Arquitetura Robusta
Produza o menor design cujas garantias possam ser explicadas e desafiadas. Regras guiam decisões; elas não certificam correção. Uma arquitetura útil torna fatos importantes explícitos, dá às regras um lar autoritário e permanece compreensível quando algo falha ou muda.
Comece por uma consequência
Para um sistema existente, inspecione os pontos de entrada reais, chamadores, armazenamentos de estado e verificações antes de confiar em diagramas ou propostas anteriores. Para um novo sistema, distinga requisitos de suposições; descreva o primeiro fluxo real antes de escolher componentes.
Registre apenas restrições que mudam uma decisão: usuários e autoridade, volume de operação, latência ou orçamentos de recursos, disponibilidade, condições de falha, necessidades de recuperação e durabilidade, restrições de implantação e o que a equipe pode operar. Pergunte pela escolha de produto ausente quando ela mudar a correção. Continue trabalho independente e reversível enquanto essa escolha não for resolvida.
Calibre a intervenção:
- Lacuna de modelo/propriedade: o fato necessário, operação completa ou autoridade consistente está ausente ou dividido. Resolva esse contrato antes de corrigir seus leitores.
- Defeito de limite: um proprietário adequado existe, mas um chamador o contorna ou sua aplicação é incompleta. Aprofunde ou use esse proprietário; um defeito entre camadas não exige, por si só, uma nova arquitetura.
- Lacuna de produto: o comportamento necessário não foi decidido. Apresente a consequência concreta e as menores escolhas, em vez de escolher silenciosamente.
- Defeito de apresentação/local: fatos subjacentes corretos precisam de uma renderização, análise ou correção de cópia local. Aplique a correção local normal; pare o fluxo de trabalho de arquitetura aqui.
Um arquivo grande, sintaxe duplicada, um nome de padrão ausente ou um pacote proposto não é, por si só, evidência de uma lacuna de modelo.
Para designs ou revisões que envolvam acesso a recursos protegidos, aplique autorização se estiver instalado. Ele é dono do passo a passo da política de acesso; mantenha as regras locais de propriedade e confiança abaixo ao usar esta skill sozinha.
Dê nomes a fatos e regras
Nomeie o fato ou invariante, sua autoridade lógica e as operações permitidas para alterá-lo. Autoridade pode ser uma função local, publicador de arquivo, identificador de biblioteca, processo ou serviço; não precisa ser um servidor ou um novo módulo.
- Coloque a regra no ponto que pode aplicá-la para cada produtor relevante. Adaptadores de entrada estabelecem a confiança do chamador, analisam entradas, invocam esse proprietário e traduzem o resultado. Verificações precoces úteis melhoram o feedback; verificações autoritativas protegem o efeito real.
- Modele quem possui dados compartilhados explicitamente. Um valor pai ou de escopo ausente não é automaticamente autoridade global. Aplique a política real do ator a leituras, serialização e efeitos, não apenas a controles visíveis.
- Separe relações atuais, fatos de ocorrência imutáveis e projeções. Armazene o histórico ou instantâneo que o recurso realmente precisa. Relações presentes não podem reconstruir fatos passados ausentes; marque o histórico legado desconhecido honestamente.
- Dê a uma nova tentativa sua identidade de operação. Duas cargas úteis idênticas podem ser intenções separadas. Defina escopo de chave, reutilização incompatível, retenção e repetição sob a autoridade atual quando a correção da nova tentativa for importante.
- Dê a regras e representações derivadas uma definição mantida onde os consumidores devem concordar. Preserve diferenças intencionais entre públicos, coortes, unidades e significados de tempo. Mantenha duplicação de apresentação local barata quando compartilhar criaria uma dependência artificial.
- Designs multi-escritor ou offline explicitamente especificados são válidos. Nomeie semânticas de conflito, coordenação e comportamento de partição em vez de assumir que um único escritor físico pode sempre ser imposto.
Um limite ganha sua existência ao esconder uma decisão e remover conhecimento dos chamadores. Verifique isso diretamente: após a mudança, qual chamador não conhece mais a regra, o layout de armazenamento ou o sequenciamento? Um invólucro que deixa cada chamador coordenando as mesmas etapas de negócio não moveu a propriedade.
Possua o resultado completo
Trace uma intenção através de seus efeitos importantes. Declare o que deve se sustentar junto, o ponto de conclusão autoritativo e o que o usuário recebe se a execução parar antes ou depois desse ponto.
Enumere cada publicação observável, incluindo caches e callbacks em segundo plano. Para trabalho assíncrono, identifique a operação, identidade, versão e tempo de vida a que um resultado pertence e verifique a aplicabilidade em cada limite de publicação relevante. Uma verificação de visão tardia não pode proteger uma escrita anterior em cache ou armazenamento. Distinga cancelar um consumidor de desfazer um efeito de negócio já confirmado.
Use uma primitiva atômica real para invariantes que exigem indivisibilidade dentro de uma autoridade. Onde escritores concorrentes podem invalidar uma leitura anterior, aplique escopo, estado e versão aplicáveis no efeito ou serialização equivalente. Corresponda o mecanismo a um entrelaçamento alcançável; uma transformação pura de thread única não precisa de maquinário de concorrência no estilo de banco de dados.
Em limites de rede, processo, arquivo ou assíncronos, leia Verificações de limite. Selecione o ramo relevante: efeitos duráveis, tempo de vida do recurso, trabalho em tempo real ou estado/histórico. Uma transação local não torna um efeito externo atômico; um resultado desconhecido não é necessariamente falha. Defina recuperação e resultados parciais/pendentes verdadeiros antes de adicionar novas tentativas.
Para APIs reutilizáveis, torne explícitas entradas, saídas, recusas, responsabilidades de propriedade e limpeza. Preserve distinções significativas de erro/controle de fluxo. Coloque diagnósticos onde uma falha pode ser explicada sem expor dados protegidos; um log não é um mecanismo de recuperação ou um banco de dados de autorização/histórico.
Escolha uma estrutura proporcional
Prefira o módulo coerente existente e os mecanismos de plataforma suportados. Em uma nova aplicação pequena, algumas funções ou módulos bem delimitados podem ser suficientes. Separe a implantação ou introduza infraestrutura quando um requisito concreto precisar de escalonamento independente, isolamento de falhas, restrições de tempo de execução ou propriedade organizacional. Respeite uma plataforma explicitamente escolhida ao explicar uma troca consequente.
Avalie a menor mudança ao lado de uma alternativa plausível. Explique a diferença importante em correção, custo operacional/de recurso e reversibilidade. Mantenha cada decisão de design em um lar; extraia de forma independente apenas costuras estáveis e úteis. Pastas, pacotes e serviços físicos seguem limites comprovados, em vez de fornecer a prova.
Preserve o invariante inteiro através de uma mudança de posicionamento. Migração e rollout devem levar em conta dados existentes, escritores antigos/novos, consumidores públicos e compatibilidade de reversão. A remoção de uma coluna, API ou recurso requer evidência de que suas obrigações e consumidores terminaram.
Tente refutá-lo
Escolha uma fatia vertical fina que exercite o limite contestado. Use o armazenamento, arquivo, protocolo ou recurso real relevante para a afirmação; isole apenas dependências externas genuínas. Para um design inicial sem implementação, especifique o experimento discriminatório e deixe seu resultado desconhecido.
Desafie o invariante com as falhas relevantes: autoridade errada, estado obsoleto, trabalho repetido ou reordenado, uma falha no limite de conclusão, cancelamento, histórico ausente/ambíguo e o limite real de carga ou tempo. Use iscas explícitas e entrelaçamentos ou relógios controlados quando eles distinguirem a regra. Um teste deve falhar quando essa regra é removida, não apenas contar chamadas simuladas ou reconhecer nomes escolhidos.
Verifique segurança e progresso: como uma operação válida eventualmente completa ou dá uma recusa honesta; como o trabalho pendente é recuperado; como memória, filas, conexões e latência permanecem limitados. Selecione essas verificações a partir do envelope operacional, em vez de ensaiar cada falha teórica.
Observe o fluxo montado/do usuário ou da biblioteca pública ao afirmar que funciona. Asserções de unidade, diagramas, novas tentativas verdes, palpites de benchmark e fixtures sintéticas estabelecem apenas seu próprio limite testado. Separe resultados medidos, descobertas de fonte, suposições, decisões ausentes e prova não executada.
Entregue uma decisão revisável
Escale a saída para a decisão. Para um design substancial, forneça:
- O fluxo concreto, restrições e incógnitas importantes.
- Os invariantes, autoridades nomeadas e produtores/consumidores afetados.
- Limites de estado/histórico, confiança, conclusão e falha, com contratos suficientes para rastrear um sucesso e uma falha.
- A pequena estrutura escolhida, uma alternativa relevante e por que a troca se adequa.
- Uma primeira fatia com verificações observáveis de aceitação, recuperação e evolução/rollout.
- O que está pronto, o que precisa de uma decisão de produto ou prova, e o que foi realmente verificado.
Use um pequeno diagrama apenas quando ele tornar um limite mais claro. Pule seções de modelo vazias para uma correção local. Preserve o escopo do usuário: uma solicitação de design/revisão produz uma decisão, não permissão para implementar, migrar, implantar, publicar ou alterar dados ativos.
Ao adotar ou avaliar esta skill, veja Protocolo de avaliação. O histórico principal está listado em Fundamentos; ele informa o raciocínio em vez de validar um design individual.