Nessa semana que passou, rolou uma thread muito legal no DotNetAchitects e nessa thread fiz meus comentários a respeito. Bom, achei interessante conseguir transcrever meus pensamentos sobre o assunto e acho que talvez possa ajudar aqueles que estão se questionando sobre como definir a arquitetura de um software ou solução.

Para que?

Legal quando precisamos pensar em arquitetura, mas é interessante revisitar os conceitos e definir a função de uma arquitetura ou mesmo de um sistema? Acredito que um sistema possa ser definido como:

Prover uma funcionalidade ou solução de negócio, usando tecnologia e técnicas de programação, entregando um sistema ou solução eficaz e eficiente.

Assuma consigo uma verdade:

Nada mais é necessário, do que oferecer uma funcionalidade de negócio de forma eficaz e eficiente.

Então quando pensar em incrementar sua arquitetura com algum framework ou padrão, avalie se aquilo aumenta eficácia, ou eficiência, caso contrário corte! Corte severamente! Mas, pense bem no que você considera eficácia e eficiência, entregar no prazo faz parte da eficácia quando prazo é relevante. Suportar evoluções rápidas faz parte da eficácia também. Ser confiável (menor quantidade de erros) representa eficiência. Todos esses itens demandam pontos de atenção na arquitetura.

Você não usa NHibernate ou Entity Framework porque é bonito! Inevitavelmente eles reduzem performance, mas você ganha em produtividade…!

Não quero confundir, só criar um paradigma que se resolve com a seguinte frase:

Se o que quer adicionar é bonito, mas não traz nem eficácia, nem eficiência, corte! [Lean: “Eliminate waste”]

Como?

Na definição de uma arquitetura, temos sempre de pensar no target, mas não podemos fazer isso sem pensar no caminho a ser percorrido. Para entregar o produto precisamos pensar em:

Equipe

Qual o Skill do seu time, quais os gaps técnicos, qual o nível de motivação da sua equipe em aprender algo novo. Quão reativos são? Você não vai muito longe se aplicar uma arquitetura muito complexa, na qual os programadores não conseguem sequer usá-la, quem dirá entendê-la. Da mesma forma como você não vai muito longe se seu time não estiver disposto a aprender. Nesses casos conservadorismo é extremamente relevante.

Contexto

Qual o cenário atual? Você tem as premissas para tocar o projeto? Necessita de uma coexistência com um outro projeto que já está em on-going? Em qual nível você precisa se preocupar com retrocompatibilidade? Qual a infraestrutura (servidores, serviços) que você dispõe? Até onde você pode ir?

Só para parafrasear, eu tive limitações graves, agora em 2013, por causa de infraestrutura. Meu parque .NET antigo é todo hospedado em Windows 2003 Server, sim 2003. Só em meados de 2014 terei alguma coisa em 2012 server, portanto estou preso a no máximo usar o framework 4.0. #ficaDica

Arquitetura

Podemos definir arquitetura, como a estratégia que usaremos para entregar o produto. Entenda por estratégia itens como:

  • Plataforma
  • Frameworks
  • Fluxo de Desenvolvimento
  • Versionamento
  • Organização e Empacotamento do Código
  • Deploy
  • Ferramentas de desenvolvimento e auxiliares

Todos esses itens fazem parte da arquitetura.

Sobre esse ponto tenho uma história interessante. Assim que cheguei no iMusica a primeira dificuldade que encontrei no processo era o deploy. Não havia no repositório de fontes uma versão fiel à versão de produção de muitos sistemas. Na verdade ter uma versão fiel no repositório era uma exceção. O motivo era o deploy feito a partir das máquinas de desenvolvimento, e esse deploy geralmente era diferencial. Copiava-se o que havia sindo modificado, ou o que achava-se que havia sido modificado.

Com um fluxo de deploy contínuo baseado em 2 builds no jenkins, foi fácil eliminar esse problema. O deploy só acontece via ferramenta. Todos os passos são respeitados e somente builds completos chegam a produção. A escolha do Jenkins se deu por causa da proficiência, minha claro, que iria instalar e configurar o serviço, mas também pelo fato de não termos servidores novos, e o fluxo de aprovação de compras ser extremamente custoso, muitas vezes inviável. O Jenkins caiu como uma luva! Esse é um exemplo de decisão tomada em função da equipe e do contexto. É importante trabalhar com o que se tem!

Voltando ao assunto principal, sem esses pilares, estamos desrespeitando leis universais, não levando em consideração ou o cenário, ou o target (que leis são essas? Não sei, mas alguma deve estar desrespeitando).

Note que equipe é o primeiro ponto, e arquitetura é o último. A ordem é proposital, e acredito que deva ser priorizada assim. São as pessoas que movem a engrenagem, elas que vão dar manutenção nas aplicações, aprender tecnologias novas para realizar coisas não vistas até então, são elas as responsáveis pelo sucesso de qualquer projeto. O contexto, e nele inclui-se automaticamente a empresa, tem sua medida de responsabilidade, mas são as pessoas que realmente fazem a maior diferença. A arquitetura é mera resultante, é uma direção que aponta o caminho para chegarmos de um ponto a outro, com a equipe que temos e com o contexto que temos. Voltando na empresa… infraestrutura, suporte, quantidade de profissionais, investimento em contratações, treinamento… isso tudo encaixo na parte contexto, são os Meios que a empresa provê para que você realize seu projeto, ou sua meta anual. [Lean: “Empower the team”]

Até aqui estamos teorizando muito. Esse é o intuito, mas daqui para frente vamos falar um pouco da prática. O que você pode fazer para desenhar efetivamente uma arquitetura.

O que usar?

Você deve se perguntar, em algum momento do projeto: O que vou usar? Como escolher o melhor design? Quais frameworks, quais padrões, quais paradigmas e princípios usar?

Bom, seja conservador, na medida do possível. Comece endereçando os problemas a pontos da sua arquitetura.

  • Difícil de gerenciar versões: ALM, Gerência de Configuração, Release Management, SemVer
  • Difícil de gerenciar deploy: Continous Delivery, Continous Deployment
  • Alta quantidade de erros / Insegurança ao realizar grandes mudanças: Testes

Tem receita de bolo para quase tudo. Na discussão foram abordados diversas técnicas: JS para interfaces ricas, ORM para facilitar o acesso a dados, DDD para melhorar a forma de construir o negócio em si, ASP.NET WebForms para aplicações CRUD, ASP.NET MVC quando precisa-se de maior controle na UI, ou mesmo pelo padrão, reaproveitamento e testes. Enfim, se você fizer uma matriz com a sopa de letrinhas, vai chegar ao seu design, esbarrando hora ou outra em escolhas entre produtos e implementações de um mesmo padrão, e como não poderia deixar de ser, lembre-se:

Toda escolha, uma renúncia.

Cada cenário denota problemas diferentes, resolva-os primeiro, pois o foco é no target. Com os problemas endereçados, vamos pensar em otimização. Veja quais padrões, frameworks, práticas etc otimizariam a eficiência ou eficácia do seu projeto. Lembre-se sempre de eficiência e eficácia.

Dando a cara a tapa!

Saindo um pouco da abstração, vamos à prática. Deixa eu explicar um pouco de como eu faço. Primeiro, trabalho como arquiteto há alguns muitos anos, tive projetos bons e projetos ruins, mas alguma coisa aprendi nesse tempo:

Seja presente e use o que você desenha.

Essa história de arquiteto ausente, arquiteto astronauta, pra mim não existe. Arquiteto que não codifica é cozinheiro que não prova sua comida. Você precisa usar o que produz para compreender as dificuldades, as facilidades, e os pontos que mais precisam de abstrações. Somente no dia-a-dia descobrimos os maiores gargalos que geralmente aparecem por acaso, quando esbarramos por ele. Desde 2008 que não caio nessa furada de não desenvolver sob aquilo que desenho. É frustrante! Se não houver tempo de codificar, no seu cronograma, há graves problemas com o dimensionamento da sua alocação, porque boa parte do que você precisará codificar, são mecanismos e facilitadores, quando não, você precisa pegar alguma parte do negócio que use aquilo que você desenhou.

Em 2008 pedi demissão de uma empresa que teimou em me alocar como arquiteto de 7 projetos simultaneamente. Se querem que você trabalhe assim, sugiro que vc procure outra empresa, sério! É desvalorizar demais o tanto que vc estudou, estuda e precisará estudar.

Outra dica:

O seu Deus te abençoou com 2 ouvidos e 1 única boca. #ficaDica

As pessoas que já trabalharam nos projetos, antigos/atuais, que já vivem uma rotina onde você está chegando, ou mesmo trabalham há anos do teu lado, têm visões diferentes das tuas. Geralmente essas visões são mega interessantes e ajudam muito a entender dificuldades e gaps, ou das pessoas ou da arquitetura atual, esses papos ajudam na compreensão do projeto e na identificação de seus principais pontos, positivos e negativos. Endereçar as reclamações comuns e fortalecer os pontos elogiados torna a arquitetura bem interessante e atrativa para quem está desenvolvendo. [Lean: “Empower the team”]

E sobre o seus 2 ouvidos e 1 boca, você também tem 2 braços, sim, é verdade! Além de falar menos, e escutar mais, faça mais! Arregace as mangas e mostre que o que você está propondo é possível. Mostre com algo prático, sempre que necessário. As pessoas precisam entender que você não é nem mágico, nem charlatão.

Não se frustre, mudanças são bem vindas!

Não se frustre com uma verdade universal:

Não importa o tamanho do projeto, a qualidade da especificação, o nível de detalhamento, o quão debatido ou esmiuçado foi. Em algum momento algo vai mudar! Se o projeto, o negócio, ou o requisito, não mudarem, no mínimo sua visão mudará!

Em algum momento você pensará: Essa parte ficaria melhor assim, assado…

Inevitavelmente algum fator interno ou externo demandará mudanças, ou no código de negócio, ou na arquitetura, ou em ambos.

Assim tento facilitar a vida de quem precisa realizar mudanças. Tento desenhar abstrações para promover o refactoring. A arquitetura deve favorecer nessa tarefa para que possa ser estimulada. Nada se mantém imutável do início ao fim do projeto, principalmente em projetos grandes. Não importa como sua arquitetura está sendo modelada, favoreça sempre o refactoring, pois o custo de ter de trabalhar em uma solução ou um pedaço do negócio mal modelado é altíssimo.

Uma gambiarra é igual a uma mentira.

Sempre precisará de novas para justificar a primeira.

Por isso, evite manter débitos técnicos por muito tempo. Destrua-os! Muitas vezes nós mesmos os criamos, quando por algum motivo, deixamos de fazer a coisa certa para fazer o mais rápido. Para minimizar esse tipo de ocorrência, é importante facilitar a mudança e até promovê-la. Abaixo há uma pequena lista com o que eu já fiz para minimizar esses problemas.

Como eu promovo as mudanças:

  • Utilizo muito ORM, e geralmente com código gerado. As pessoas podem mudar o banco, a qualquer momento, eu garanto que no mínimo a aplicação é compatível com as mudanças. Mudanças estruturais no banco afetam o build, quebrando-o. A ausência ou mesmo o rename de campos no banco, geram quebras de build. Esses erros só apareceriam em runtime, e esse é um ganho substancial. Ao resolver a quebra de build, você tem uma minima garantia de que as coisas estão coerentes, mas claro, se você adicionar um campo não nulo em uma tabela existente, o build não quebrará, mas, como uso linq em quase 100% do projeto, é fácil identificar quem precisa ser modificado.
  • Uso muito IoC e abstrações: Toda a infraestrutura é abstraída. Redis, Spring, MongoDB, SQL Server, MySQL, RabbitMQ, nada é feito diretamente manipulando providers nativos. Uma troca de tecnologia é muito simples de ser realizada. Ao mesmo tempo, os providers estão disponíveis para utilização, mas a utilização direta, por fora da arquitetura é desencorajada.

Overdesign

Lembra do papo sobre eficiência e eficácia? Então, tento sempre garantir o maior número de itens não funcionais na arquitetura. Pra isso não abro mão de alguns padrões, como IoC e DI. Quando falo de abstrações, penso automaticamente de um dos itens do Lean (http://en.wikipedia.org/wiki/Lean_software_development ) “Decide as late as possible”. Muitas das estratégias de deploy, agrupamento, processamento distribuído, deixo para o final do projeto. Mas para isso, preciso ter uma arquitetura que me suporte esse tipo de abstração. Muitos consideram Overdesign, eu chamo de adaptabilidade. As coisas mudam!

Enfim, há uma infinidade de pontos que tento abstrair, para garantir uma codificação de negócio limpa e ao mesmo tempo com garantias de segurança, escalabilidade e confiabilidade.

Simples mas não Simplificado

Mas você pode pensar que a complexidade do código é grande? Não, não é. Tudo isso, que desenho geralmente envolve média complexidade de infraestrutura, para ter uma alta produtividade na utilização.

Abaixo temos o código-fonte de um serviço, usado por uma aplicação Web, Windows Services e outros. Para cada cliente o deploy é diferente (Inline Wcf, Etc). E não tenho dor de cabeça com gestão. Esse código tem garantia de exception replacement, exception management (log em fila RabbitMQ e importação futura para banco), suporte a exceptions para WCF (faltas), ainda, abertura automática de contexto do NHibernate (pode ser vários), inclusive tenho operações em 2 bancos (mysql e sqlserver) simultaneamente, com NHibernate, operando da mesma forma e abstração de operações com MongoDB. Tudo para que o desenvolvedor se preocupe apenas com código de negócio e não com a infraestrutura.

Você pode se perguntar e afirmar que é chato desenvolver assim, que não há complexidade etc. Bom, quem gosta de ficar repetidamente gerenciando complexidade em tudo é minha esposa!

Se o desenvolvedor precisar de algo novo, a tendência é que ele crie algo genérico, para que possa ser incorporado como mecanismo da arquitetura. E aí entra o refactoring, novamente. Uma abordagem que uso e que contradiz muitos é:

Não considero a opção ter 2 definições de arquitetura ou implementações funcionais, idênticas na aplicação.Um refactoring do que já estava pronto, é parte da tarefa de criação do mecanismo. E se sou eu quem faço o mecanismo, eu faço a mudança no código. Quem quer que faça o mecanismo é responsável por rever essas quebras, no mínimo acompanhando, lado-a-lado, o autor da funcionalidade, o que raramente acontece no meu time atual.

Débitos técnicos são revistos sempre, mesmo que fora do horário do expediente. E morrem sim! Mesmo que eu tenha de dar sangue para que esse débito técnico morra, será feito! Promessa é dívida!

Essa arquitetura, esse nível de simplicidade só é possível com abstrações, e muitas abstrações. Essa é realmente a mágica que possibilita construir soluções robustas. Abstraia o máximo de complexidade do código de negócio, movendo para pontos centrais de sua arquitetura. Para o desenvolvedor, precisa ser algo simples, algo que não o leve a cometer erros, para que ele poss ser mais produtivo.

Mas quem tiver interesse na complexidade, vai te ajudar nas abstrações, quem não estiver afim de aprender P.N (Porra Nenhuma), não precisa aprender, apenas usar. A escolha é de quem desenvolve, mas num time misto, onde 20% é interessado e 80% está à deriva, você facilmente consegue produtividade e motivação dos 2 grupos, e fazer com que entreguem melhor as soluções.

Bom, meus contatos estão aqui no blog, estou disponível (não como consultor, mas como parceiro mesmo.. for free R$) para ajudar e espero poder contribuir um pouquinho com seus projetos.

Esse post nasceu em 2013, mas só foi publicado em 2014. Agora no finalzinho de 2016 estou revendo-o para não deixá-lo tão datado. Esse foi um dos posts mais vistos desde 2013 e já me rendeu boas histórias. Espero que tenha curtido, agradeço ter chegado até aqui, eu sei que é uma leitura densa, e muitas vezes chata. Mas alguém tem de escrever o que precisa ser escrito.

Obrigado pela extensa leitura.

Luiz Carlos Faria

Comente, compartilhe, curta!

Logo abaixo desse texto você encontra os Posts Relacionados, e botões de compartilhamento, em seguida a sessão de comentários!

Gostou? Então aproveite para curtir, compartilhar e enviar comentários, dúvidas ou sugestões.

Conheça o Grupo Arquitetura de Softwate | .NET: Facebook e Telegram
Luiz Carlos Faria: Site, Youtube, Facebook, Twitter, Telegram, Linkedin e Email