Olá, mundo!
Vamos começar com uma Action que não faz nada de útil — ela imprime uma linha e retorna um stub vazio. Seu valor está em outro lugar: mostra o mínimo de declarações que o AOA exige antes de rodar qualquer coisa.
$ uv run python examples/step_01_Action_and_pipeline/01_hello_world.pySão bastantes linhas para uma simples saudação — mas nenhuma delas é um ritual: cada uma declara algo sem o qual uma Action no AOA não é considerada completa. Tudo começa com um domain. @meta é o passaporte da Action; @check_roles(GuestRole) declara o acesso de forma explícita, não por padrão. E @summary_aspect é o único ponto de saída — pule qualquer um dos três e a máquina se recusa a rodar a Action, antes da primeira chamada.
Params, Result e box
Stubs servem para introduções; uma Action real trabalha com dados. Vamos dar a ela uma entrada e uma saída — e trocar print pelo instrumento que as Actions no AOA usam para falar com o mundo exterior.
$ uv run python examples/step_01_Action_and_pipeline/02_params_result_and_box.pybox é mais interessante que print — é um logger estruturado ligado ao passo atual, que carrega canal, nível, domain, action e o nome do aspect, então se presta a filtragem, roteamento e exportação. Para onde o evento vai não é decisão da Action — isso é assunto da máquina, conectado a partir de fora.
Múltiplos aspects
Um único passo raramente é suficiente. O AOA não deixa liberdade para que os dados intermediários se escondam em variáveis locais ou campos de objeto — eles fluem pelo pipeline em um state explícito, enquanto a própria Action permanece vazia entre chamadas.
$ uv run python examples/step_01_Action_and_pipeline/03_multiple_aspects.pyO dicionário retornado substitui state por completo — não o estende. @result_string("cleaned", required=True) é um verificador: um contrato verificável sobre a saída de um aspect. Quebre a promessa e a máquina para o aspect na hora, sem nunca deixar um state corrompido seguir adiante.
Herança
As Actions herdam como as classes comuns — com uma exceção deliberada: os aspects não são herdados no pipeline. A máquina constrói o pipeline apenas a partir do que é declarado na própria classe.
$ uv run python examples/step_01_Action_and_pipeline/04_inheritance.pyChildOrderAction roda sem problemas, mas seu pipeline contém apenas child_summary — o validate_aspect do pai nunca executa. ExtendedOrderAction faz certo: redeclara o aspect e chama super() para construir sobre a lógica do ancestral.
Experimentos
Este capítulo acumulou um bom número de regras — mas todas compartilham uma propriedade: quase todas são verificadas na declaração da classe, na importação do módulo, não na chamada da Action. O código aqui é uma especificação executável; uma violação de contrato aparece antes da primeira execução, não em uma noite qualquer em produção. Experimente — escolha uma forma de quebrar SayHelloAction do primeiro exemplo e pressione Executar.
$ uv run python examples/step_01_Action_and_pipeline/01_hello_world.pyResumo
O núcleo do modelo já está em mãos: uma operação é uma Action com uma fronteira tipada (Params e Result), um pipeline linear de aspects e contratos que são, em sua maioria, verificados na inicialização. O comportamento é expresso na estrutura do código, não em documentação que fica ao lado dele.
Perguntas de revisão
- Qual invariante garante a legibilidade "a partir de uma única classe" de uma Action, e em que momento ela é verificada?
- Por que a ausência de
@check_rolesé um erro e não um silencioso "aberto a todos"? - O pipeline do AOA é linear — sem ramificações, sem saídas laterais. O que essa restrição traz, e a que custo?
- Por que os aspects não são herdados automaticamente no pipeline? Compare com a herança comum de métodos na POO.
- O que significa "o código é uma especificação executável", e por que a maioria dos contratos é verificada na inicialização em vez de em tempo de execução?
