Nos lugares onde os aspectos arquiteturais são levadas a sério como imprecindíveis para o sucesso de qualquer projeto é cada vez mais consenso de que a maneira tradicional de arquitetar sistemas não está provendo todo o valor que deveria.
Por maneira tradicional entenda:
- Um arquiteto ou um time deles planeja a arquitetura de um sistema, mas não atua desenvolvendo ou não está ao lado dos desenvolvedores full-time.
- A arquitetura de um sistema é planejada totalmente no começo do desenvolvimento, com definições sobre diversos aspectos da aplicação, como as camadas físicas e lógicas, a forma de acesso a dados, e as tecnologias em geral.
- Uma mistura dos dois também é muito comum.
É comum também a criação de documentos que pré-restringem as opções de tecnologias, padrões, metodologias, etc, muitas vezes feitos pelos próprios arquitetos. Tais restrições se justificariam em nome da padronização, e raramente levam em conta cenários. Um exemplo é: “aplicações devem utilizar o Entity Framework para acessar dados” ou “ASP.Net Webforms sempre deve ser usado quando o desenvolvimento for web”.
Ainda é assim que a maioria dos times de arquitetura trabalha. Temos obtido ganhos? Sem dúvida! Pensar na arquitetura é melhor do que não pensar. Mas quais os problemas?
Alguns dos problemas são código jogado fora, código criado e nunca utilizado (inútil), código que não faz o que indica (enganando o desenvolvedor), soluções com alta fricção, que congelam o código e/ou a criatividade do desenvolvedor, entre diversos outros (comente sua lista de problemas lá embaixo).
Viva a padronização, matando a produtividade. O interessante é que o maior argumento para a padronização é justamente a produtividade. Será que é possível ser produtivo sem padrões? Será que é possível ter padrões e ainda assim permitir a criatividade? Vamos ver.
Já tem quase 10 anos que umas pessoas declararam que responder a mudanças é mais importante do que seguir um plano, e que indivíduos e interações são mais importantes do que processos e ferramentas. Isso significa que podemos ter um plano, mas devemos mudá-lo sempre que as premissas sobre as quais eles se fundaram mudarem, ou quando eles não fizerem mais sentido. E que podemos ter ferramentas, processos, e padrões, mas que as interações entre as pessoas, e o que sai delas são mais importantes. Interessante, não? Parece que aplica ao que estamos discutindo.
De lá pra cá esses valores, além de mais alguns, tomaram o mundo. Chegou a hora de falarmos não só sobre o que é uma boa arquitetura, mas também como chegar lá. O processo tradicional, baseado em algumas pessoas determinando como outras vão trabalhar, e em documentos antigos e não focados no projeto, não promovem a interação entre o time que realmente cria os detalhes de um software (e é nos detalhes que está o perigo). Como eles não interagem entre eles, com o negócio e com TI, a solução arquitetural proposta pelos arquitetos (externos ao time) é a solução aceita e aplicada. Uma solução concebida desta forma é linear. As variáveis são analizadas, um catálogo é avaliado, as melhores soluções são propostas, comparadas com outras candidatas, e uma é escolhida. Parece bastante linear, não parece? Sabe qual o problema de ser linear?
O problema é que uma solução linear não reflete as necessidades do negócio, a criatividade do time, os problemas da empresa, o ambiente (físico e humano) onde o software vai rodar, as regras e regulamentos, e outras influências não lineares que moldam um software além do momento em que foram concebidas. São, por definição, míopes. Todos essas características juntas formam um sistema complexo, e quando interagem começam a criar resultados não lineares. Eles começam a emergir. As necessidades e as soluções que emergem são tão profundamente ricas que nenhum time de arquitetos, por melhor que seja, conseguiria alcançar sozinho, por que estão presos a sua linearidade.
O risco em usar uma solução linear, que presume um comportamento previsível, em um sistema complexo, é que as previsões não vão se confirmar. Em arquitetura isso vai gerar os problemas que já conhecemos. O mais interessante é que, como o sistema é assumido como linear, muitas das variáveis não são sequer analisadas (ou até conhecidas), porque só aparecem muito mais tarde. E como influenciam o resultado de forma não prevista, o desenvolvimento do software começa a parecer ser caótico, aleatório, absolutamente imprevisível. E ele não é imprevisível, só não é previsível além de um período muito curto.
Como resolver esse problema? Pra começar devemos aceitar o fato de que desenvolver software é um sistema complexo, e isso inclui sua arquitetura. Por isso teorias que pregam previsibilidade podem ser abandonadas, já que somos incapazes de prever o estado em que o desenvolvimento do sistema estará em um curto período de tempo, geralmente alguns meses.
Em seguida precisamos saber lidar com um sistema complexo. Uma excelente maneira, é a utilização de um modelo de controle de processo que seja empírico. O Scrum é um deles. O Scrum diz que trabalha com um processo iterativo e incremental, e se baseia em 3 pilares. Segundo o Scrum Guide (em português e gratuito):
- O primeiro pilar é a transparência
A transparência garante que aspectos do processo que afetam o resultado devem ser visíveis para aqueles que gerenciam os resultados. (…)- O segundo pilar é a inspeção
Os diversos aspectos do processo devem ser inspecionados com uma frequência suficiente para que variações inaceitáveis no processo possam ser detectadas. (…)- O terceiro pilar é a adaptação
Se (…) um ou mais aspectos do processo estão fora dos limites aceitáveis e o produto resultante será inaceitável, ele deverá ajustar o processo ou o material sendo processado. Esse ajuste deve ser feito o mais rápido possível para minimizar desvios posteriores.
O Scrum também diz que um pedaço de funcionalidade deve ser entregue a cada iteração, e que só o time pode tocar e influenciar o código. O time é seu próprio gerente, e é auto-organizado.
E como surge a arquitetura? Assim como todo o resto, ela emerge. Ela é desenvolvida incrementalmente a cada iteração, conforme é necessária. É claro para o time que alguma funcionalidade deve ser entregue, e as entregas funcionais são mais importantes que as não funcionais, como as arquiteturais.
Também é comum que, dentro de uma iteração, um time Scrum faça uma rápida prova de conceito e avalie arquiteturas candidatas. Muitas vezes, também durante uma iteração (geralmente nas primeiras), o time desenvolve uma visão geral da arquitetura do sistema, mas sempre lembrando que o foco é atender o cliente e maximizar a entrega de forma sustentável.
Quando um time se preocupa com arquitetura ele está claramente preocupando com o custo total de propriedade (TCO), além do seu próprio prazer em codificar, e o desenvolvimento iterativo e incremental, que habilita uma arquitetura emergente, facilita o alcance destes objetivos.
Concluo resumindo alguns pontos chave. Para habilitar uma arquitetura emergente o processo de desenvolvimento precisa:
- ser decentralizado;
- possuir um time auto-organizado;
- ser transparente;
- promover inspeção e adaptação constantes;
- ser evolutivo;
- promover a presença da língua do negócio;
Uma arquitetura bem feita serve ao time, não é o time que trabalha para satisfazê-la. Isso se reflete no TCO, na felicidade do time e no sucesso do projeto.
Pra saber mais:
- eu já havia falado rapidamente sobre isso quando mencionei a criação de frameworks corporativos;
- o assunto também faz parte do curso de Professional Scrum Developer;
- este post do Brad Appleton traz diversos links sobre o assunto;
- o Fábio Akita falou bastante sobre sistemas complexos e agilidade no RailsSummit do ano passado.
Bom estudo e divirta-se. O assunto é muito interessante.
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.