Pular para o conteúdo principal

Transaction Script

Descrição​

O Transaction Script organiza a lógica de negócio como procedimentos, com um procedimento para cada requisição vinda da camada de apresentação. Cada script recebe a entrada, valida, calcula, acessa o banco de dados (diretamente ou por um gateway fino) e devolve o resultado.

Uma aplicação corporativa pode ser vista como uma série de transações: algumas apenas exibem dados, outras os alteram. Cada transação ganha seu próprio script, que roda do começo ao fim de forma linear. Passos comuns podem ser extraídos para subprocedimentos, e vários scripts relacionados costumam ser agrupados em uma mesma classe.

É a forma mais direta de estruturar lógica de domínio e funciona bem enquanto as regras são simples. Quando a lógica cresce, a duplicação entre scripts tende a aumentar.

Problemas que resolve​

  • Necessidade de implementar rapidamente casos de uso simples sem montar uma infraestrutura de objetos e mapeamento.
  • Equipes sem experiência com modelagem de objetos que precisam de um estilo fácil de entender.
  • Operações que se resumem a ler, calcular e gravar, onde cada requisição tem fluxo bem definido.

Quando usar​

  • Lógica de negócio simples, com poucas regras e poucas interações entre elas.
  • Aplicações que precisam de controle fino sobre as consultas SQL e sobre o desempenho.
  • Sistemas pequenos, protótipos ou módulos de relatório e importação.

Quando evitar​

  • Quando as regras são complexas e se repetem entre vários casos de uso: a duplicação entre scripts se acumula.
  • Quando o domínio tem muitas variações de comportamento que se beneficiam de polimorfismo.
  • Quando a aplicação deve crescer por muito tempo e a lógica espalhada em procedimentos ficará difícil de manter.

Trade-offs​

GanhoCusto / Risco
Simples de entender e de implementarLógica duplicada entre scripts à medida que o sistema cresce
Sem camada de mapeamento objeto-relacional; fácil controlar o SQLDifícil de refatorar para um modelo mais rico depois
Limites de transação claros: um script, uma transaçãoRegras de negócio acopladas à estrutura das tabelas
Bom desempenho previsívelTestes dependem do banco ou de gateways simulados
  • Complexidade: cresce de forma não linear; o que começa simples vira um emaranhado de procedimentos.
  • Testabilidade: boa para scripts pequenos, mas depende da separação entre lógica e acesso a dados.
  • Evolução: a migração para Domain Model costuma ser custosa.

Diagrama​

A camada de apresentação chama um script por requisição. Os scripts, agrupados em OrderScripts, usam um gateway fino para acessar o Database.

Exemplo​

Um sistema de pedidos precisa calcular o total com desconto e gravar o pedido. Um único procedimento faz todo o trabalho.

class OrderScripts:
def __init__(self, db):
self.db = db

def place_order(self, customer_id: int, items: list[dict]) -> int:
with self.db.transaction():
total = sum(i["price"] * i["qty"] for i in items)
customer = self.db.fetch_one(
"SELECT vip FROM customers WHERE id = %s", customer_id
)
if customer["vip"]:
total *= 0.9
order_id = self.db.insert(
"INSERT INTO orders (customer_id, total) VALUES (%s, %s)",
customer_id, total,
)
for i in items:
self.db.insert(
"INSERT INTO order_items (order_id, sku, qty) VALUES (%s, %s, %s)",
order_id, i["sku"], i["qty"],
)
return order_id

Padrões relacionados​

  • Domain Model — alternativa para lógica complexa, com objetos que combinam dados e comportamento.
  • Table Module — organiza a lógica por tabela, em vez de por requisição.
  • Service Layer — pode ser implementado com scripts de transação como fronteira da aplicação.
  • Table Data Gateway — gateway fino frequentemente usado pelos scripts para acessar o banco.
  • Command — scripts podem ser organizados como objetos de comando, um por transação.

Referência​