- A participação real no design de sistemas de grande escala só é possível para engenheiros que lidam diretamente com aquele código, e conselhos abstratos em geral são inúteis
- Conselhos genéricos de design (generic design) muitas vezes são apresentados por quem entende o domínio, mas não conhece a base de código
- No trabalho real, restrições concretas e a manutenção da consistência são muito mais importantes do que princípios de design, e entender o estado atual do código é essencial
- Ao projetar um sistema novo ou decidir a direção tecnológica de toda a empresa, princípios gerais de design podem ser úteis até certo ponto
- Porém, uma estrutura de design centrada em arquitetos separados da linha de frente tende a fracassar, e quem propõe o design deve responder pelo resultado
Limites do design de software genérico
- O design de sistemas de grande escala exige entendimento profundo dos detalhes concretos do código
- Conselhos abstratos quase nunca ajudam a resolver problemas reais
- Na prática, consistência (consistency) é mais importante do que “bom design”
- Como bases de código reais são complexas e produzem resultados imprevisíveis, as formas de implementação disponíveis para mudanças seguras são limitadas
- Grandes codebases compartilhadas estão sempre em um estado intermediário em que vários designs se misturam, e o estado atual de acoplamento do código importa mais do que um objetivo ideal
- Como na maioria dos sistemas um rewrite completo é impossível, é preciso depender de consistência interna e do cuidado dos engenheiros
Características do design de software concreto
- Discussões de design eficazes acontecem em conversas entre um pequeno grupo de engenheiros que lidam com o sistema todos os dias
- O foco da discussão não são princípios gerais, mas contextos concretos, como a estrutura detalhada do sistema ou o fluxo de dados
- Por exemplo, em vez de “DRY é bom?”, surgem discussões técnicas minuciosas como “dá para colocar essa funcionalidade no subsistema A?” ou “a informação B está acessível no contexto C?”
- Contribuições importantes vêm de corrigir pequenos mal-entendidos ou os efeitos detalhados de mudanças no código
Quando conselhos genéricos de design são úteis
- Ao projetar um projeto novo pela primeira vez, princípios gerais são úteis porque ainda não há restrições concretas
- Quando é difícil escolher entre várias implementações, princípios gerais podem servir como critério de desempate (tie-breaker)
- Também ajudam a manter consistência em nível de empresa, e isso é uma das funções formais de um arquiteto de software
- Mesmo em escolhas tecnológicas amplas como cloud vs on-premises, AWS vs Azure, princípios gerais podem servir de referência, embora ainda não seja possível ignorar restrições concretas
Arquitetos e o problema do “mínimo local”
- Muitas empresas caem em uma estrutura abstrata de design centrada em arquitetos sem experiência de campo
- À primeira vista isso parece eficiente, mas na prática gera designs que os engenheiros da linha de frente não conseguem implementar
- Como arquitetos não implementam diretamente, falta responsabilidade pelo resultado (skin in the game)
- Se o design dá certo, levam o crédito; se falha, a culpa recai sobre o time de execução
- Esse tipo de estrutura tende a fortalecer atividades formais de design mais do que gerar valor real
Conclusão e proposta
- Discussões de design realmente úteis acontecem em conversas concretas no nível do código, e o designer precisa conhecer bem a base de código
- Princípios gerais de arquitetura devem ficar restritos ao design de sistemas novos, ao apoio em decisões detalhadas de sistemas existentes e à definição da direção tecnológica da empresa
- Quem propõe o design de um projeto deve responder por seu sucesso e fracasso, e os engenheiros que realmente lidam com o código devem ser os protagonistas do design
- Assim, quem realmente entende o sistema e consegue colocá-lo em produção pode ser reconhecido como o verdadeiro designer
4 comentários
> No trabalho real, restrições concretas e a manutenção da consistência são muito mais importantes do que princípios de design, e entender o estado atual do código é o ponto central.
Isso é algo em que sempre acreditei, então aquece meu coração.
É por isso que dizem hoje em dia que os gurus preferem até dizer que os novatos usam agentes muito melhor. Como isso foi o que lhes deu dinheiro por muito tempo, não conseguem fazer o unlearning.
Se melhorarmos o processo de conclusão da arquitetura, não seria possível resolver suficientemente os pontos levantados como problema?
Comentários do Hacker News
Descreve a situação em que, em vez de discussões como “DRY é melhor ou WET é melhor?” em reuniões de equipe, a conversa segue por algo como: “Dá para colocar essa funcionalidade no subsistema A? Não, ali não temos a informação B, e para expor isso precisaríamos reescrever D...”, ou seja, uma discussão complexa sobre dependências
Diz que é uma cena bem familiar, lista vários nomes fictícios de sistemas em tom de piada e, no fim, acrescenta um link do YouTube
Trabalho com desenvolvimento há 30 anos, mas quase nunca vi casos em que realmente se dedica um esforço consistente a design e arquitetura
A maioria dos “arquitetos” não projeta nada; a estrutura costuma ser a de um desenvolvedor sênior fazendo o design e recebendo apenas feedback depois
Com tempo médio de permanência de 2 anos, a pessoa acaba projetando entendendo só parte do sistema, e o arquiteto muitas vezes só aprova
‘Generic Software Design’ é útil para orientar a direção da implementação. Fornece uma linguagem e um framework comuns que facilitam a resolução de problemas
Mas a implementação real pode acabar diferente do plano. Como na teoria da programação de Naur, o conhecimento real do sistema está na cabeça dos desenvolvedores
A frase “em codebases grandes, consistência é mais importante do que um bom design” mostra justamente a armadilha desse tipo de conselho generalizado
Se você só enfatiza consistência, acaba preservando maus hábitos
De um lado, existe o “arquiteto” que não entende a realidade; do outro, o Real Programmer obcecado só com otimização de detalhes
Os dois extremos são um problema, e quem toma decisões precisa entender tanto os detalhes quanto o contexto
Como história relacionada, é citado The Story of Mel
Concordo com a frase “quem fez o design deve responder pelo sucesso e pelo fracasso do projeto”
Isso também deveria valer para quem escolheu a metodologia de desenvolvimento. Um Scrum master não carrega o mesmo senso de responsabilidade que um engenheiro líder
Os melhores apps em que já trabalhei tinham estas três características
Essa liberdade aumentava tanto a satisfação dos desenvolvedores quanto a qualidade do produto
Pela minha experiência, a obsessão por consistência em codebases grandes é, na verdade, um erro
Como cada módulo tem requisitos diferentes, estratégias de teste e naming também deveriam ser diferentes
No caso ideal, o desenvolvedor também deveria ser usuário real do software que cria
Assim, ele sente diretamente os erros e incômodos, e ganha motivação para melhorar
Um arquiteto de software separado que não participa da manutenção é algo irrealista
O projeto muda o tempo todo, então um papel que só dá instruções de longe não ajuda