Pular para o conteúdo

Transaction Script

“Organizes business logic by procedures where each procedure handles a single request from the presentation.”

A lógica não vive em objetos de domínio, mas em métodos procedurais. Os dados normalmente vêm de estruturas anêmicas (records, DTOs) ou diretamente do banco via Gateway/DAO - Data Access Object.

Boa parte das aplicações corporativas tem lógica rasa: validar, calcular um total, gravar. Introduzir um Domain Model rico com mapeamento O/R para isso é caro e cerimonioso. O Transaction Script entrega valor com o mínimo de estrutura.

  • CRUDs e telas administrativas.
  • Regras de negócio simples e estáveis, com pouca interdependência.
  • Times pequenos, prazos curtos, domínio pouco complexo.
  • Protótipos e MVPs.
Vantagem Custo
Baixíssimo custo inicial Duplicação de lógica entre scripts
Fácil de entender linearmente Condicionais aninhados crescem
Sem ferramental O/R pesado Testabilidade sofre (lógica acoplada a IO)
Ótimo para lógica rasa Curva de esforço cresce de forma não linear

Quando as regras começam a se entrelaçar e a mesma lógica reaparece em vários scripts. Esse é o sinal de que o custo de manutenção do Transaction Script está superando o do Domain Model. Persistir nele nesse ponto leva ao acoplamento e à duplicação crônica.

O Domain Model distribui a lógica entre objetos que combinam dados + comportamento, controlando invariantes localmente. O Transaction Script centraliza a lógica em procedimentos e trata dados como estruturas passivas. A diferença essencial:

graph TD
    subgraph "Transaction Script"
        TS[transferir - método] --> C1[Conta - dados]
        TS --> C2[Conta - dados]
        TS --> DB[(DB)]
    end
    subgraph "Domain Model"
        A[Conta - dados+comportamento] -->|debitar| A
        B[Conta - dados+comportamento] -->|creditar| B
    end
public record TransferenciaRequest(Long contaOrigemId, Long contaDestinoId, BigDecimal valor) {}
@Service
public class TransferenciaService {
private final JdbcTemplate jdbc;
public TransferenciaService(JdbcTemplate jdbc) {
this.jdbc = jdbc;
}
@Transactional
public void transferir(TransferenciaRequest req) {
if (req.valor() == null || req.valor().signum() <= 0) {
throw new IllegalArgumentException("Valor deve ser positivo");
}
BigDecimal saldoOrigem;
try {
saldoOrigem = jdbc.queryForObject(
"SELECT saldo FROM conta WHERE id = ?",
BigDecimal.class, req.contaOrigemId());
} catch (EmptyResultDataAccessException e) {
throw new IllegalStateException("Conta de origem inexistente");
}
if (saldoOrigem.compareTo(req.valor()) < 0) {
throw new IllegalStateException("Saldo insuficiente");
}
jdbc.update("UPDATE conta SET saldo = saldo - ? WHERE id = ?",
req.valor(), req.contaOrigemId());
jdbc.update("UPDATE conta SET saldo = saldo + ? WHERE id = ?",
req.valor(), req.contaDestinoId());
jdbc.update(
"INSERT INTO movimento (conta_id, tipo, valor) VALUES (?, 'DEBITO', ?)",
req.contaOrigemId(), req.valor());
jdbc.update(
"INSERT INTO movimento (conta_id, tipo, valor) VALUES (?, 'CREDITO', ?)",
req.contaDestinoId(), req.valor());
}
}

Toda a lógica (validação, checagem de saldo, débito, crédito, registro) está no procedimento transferir. Repare que a regra “saldo não pode ficar negativo” mora aqui — se outra operação também mexer no saldo, a regra terá de ser repetida.

  • Duplicação de regra: a mesma validação copiada em vários scripts. Sinal para migrar rumo ao Domain Model.
  • Método-monólito: um script de centenas de linhas com muitos if aninhados. Fere o SRP - Single Responsibility Principle.
  • Insistir no Transaction Script quando o domínio já ficou complexo — custo de manutenção explode.
  • Lógica de negócio no Controller: o script deve estar num serviço, não na camada web.
  • Confundir com Service Layer: um Service Layer sobre um Domain Model delega às entidades; um Transaction Script contém a regra ele mesmo.

1. Em uma frase, o que caracteriza o Transaction Script?

Resposta

Um procedimento por caso de uso que concentra a lógica de negócio de forma linear, tratando dados como estruturas passivas.

2. Qual é o principal sintoma de que um Transaction Script está “vencido”?

Resposta

Duplicação de lógica entre scripts e crescimento de condicionais aninhados. Isso indica que o domínio ficou complexo o suficiente para justificar um Domain Model.

3. Por que o custo do Transaction Script cresce de forma não linear?

Resposta

Porque, sem objetos que encapsulem invariantes, cada nova regra tende a ser espalhada e repetida entre os scripts existentes, multiplicando os pontos de manutenção e as chances de inconsistência.

4. Quando o Transaction Script é a escolha correta?

Resposta

Em domínios de lógica rasa e estável: CRUDs, telas administrativas, MVPs e protótipos, onde o custo de um Domain Model com mapeamento O/R não se paga.