Saí agora a pouco de uma sessão remota com um cliente do Sul do Brasil. Alguns problemas de performance atrasavam a aplicação, feita com ASP.Net Webforms e SQL Server. Em dois dias descobrimos algumas fontes do problema: uso incorreto do Microsoft Ajax, falta de compressão no IIS, e um problema chato de memory leak que demandou uma análise profunda dos dumps de memória, originado de uma única palavra em um único arquivo de código, que todos imaginavam inofensiva. (Aliás, cuidado com ela: “static”.)
Pouco antes estava em outro cliente, trabalhando um modelo de factories de entidades, baseado em Abstract Factory, criado para solucionar um problema de regras dinâmicas de entidades obtidas via NHibernate. Usamos o modelo de interceptação para, em conjunto com o Unity, resolver as dependências dinâmicas, injetá-las nas factories, que eram singletons (graças ao modelo de lifetime managers do Unity), que depois as passariam para as entidades correspondentes quando criadas pelas factories concretas, utilizando as regras como políticas (no padrão strategy). Parece complicado? E foi.
Deixei o cliente analisando o modelo de headers do WCF para implementar uma solução customizada. Estávamos estudando um modelo de extensão com Endpoint Behaviors customizados, algo formidável permitido pelo WCF, mas nada simples.
Porque tão complicado? Afinal, porque arquitetamos, senão para permitir uma melhor sobrevida da aplicação, mais barata, enquanto ela atende todos os requisitos operacionais e de negócio. Oras, se ficou muito complexo vai ficar mais difícil de manter, e portanto mais caro.
No primeiro caso, cuidávamos de um código sem uma linha de testes automatizado ou requisitos de performance escritos, feitos por um desenvolvedor desatento a questões que só apareceriam quando a aplicação atingisse um tamanho muito maior, ou seja, código que não escalava. No segundo caso estávamos cuidando de código de infra-estrutura. O código de negócio em si está altamente desacoplado, e as classes de infra que fizemos foram desenvolvidas com TDD, todas extensivamente testadas, e por isso, funcionando de forma 100% garantida. O cliente seguiu para continuar implementando aquele código que o cliente dele está pagando ele pra fazer. Eu, que arquitetetei o modelo e auxiliei (ou realizei) as implementações mais complexas, trabalhei para fazer o código que o meu cliente me pagou, aquele que o habilitaria a ser mais produtivo.
A função do arquiteto acaba sendo essa mesmo. Não consigo conceber uma equipe sem um arquiteto e um bom sênior para dar prosseguimento no código. E ele tem que acompanhar o projeto para ajudar a equipe. Para entregar soluções completas profissionalmente precisamos de profissionais capacitados. Fazer software, concretizar sonhos, não é simples, mesmo que fosse no papel. Há uma complexidade inerente ao processo, e quando transportamos esses sonhos para o computador, há técnicas de engenharia precisas para ajudar a resolver os problemas do mundo real. Qualquer outra opção, sem engenharia especializada, levaria a uma solução que atenderia apenas parcialmente.
Não desenvolvemos foguetes com amadores. Não operamos corações com enfermeiros. Por mais que possamos argumentar que podemos simplificar, simplesmente não se opera um coração de maneira simples. Há muitas camadas até chegar o coração, tem que trabalhar com ele funcionando, e depois fechar tudo. De maneira equivalente, software tem suas próprias complicações.
Esse é um dos principais motivo da existência deste blog. Apresentar algumas das idéias que tenho pra ajudar nesse processo tão difícil. É por isso que falo de DDD, TDD, Scrum, Domain Events, ASP.Net MVC, DI, SOLID, etc, etc… É também a idéia por trás da criação do grupo .Net Architects.
Diante disso tudo, a cada dia acredito menos em soluções simples, pra não dizer simplórias, baseadas em arrasta e solta, baseadas muito fortemente em geradores de código, ou qualquer coisa que elimine um bom engenheiro. Usuário não programa. Alguém com certeza vai comentar que há cenários e cenários, e que há aplicações em que o arrasta e solta resolve. Que alto acoplamento é ok. Que testes são desnecessários. Que há sistemas simples. Já adianto: você está enganado. Não há. Não há nada disso. O que há é um desrepeitoso desperdício de recursos, que deveria ultrajar tanto quem fez o software, quanto quem paga por ele.
Giovanni Bassi
Arquiteto e desenvolvedor, agilista, escalador, provocador. É fundador e CSA da Lambda3. Programa porque gosta. Acredita que pessoas autogerenciadas funcionam melhor e por acreditar que heterarquia é mais eficiente que hierarquia. Foi reconhecido Microsoft MVP há mais de dez anos, dos mais de vinte que atua no mercado. Já palestrou sobre .NET, Rust, microsserviços, JavaScript, TypeScript, Ruby, Node.js, Frontend e Backend, Agile, etc, no Brasil, e no exterior. Liderou grupos de usuários em assuntos como arquitetura de software, Docker, e .NET.