Eficiência

Programadores experientes podem facilmente distinguir uma boa arquitetura de uma ruim, mas se solicitados a descrevê-la em poucas palavras, é improvável que consigam fazê-lo. Não existe um critério único para uma boa arquitetura e nenhuma definição única.

No entanto, se você pensar sobre isso, poderá escrever vários critérios que uma boa arquitetura deve satisfazer. Uma boa arquitetura é, antes de tudo, uma arquitetura lógica que torna o processo de desenvolvimento e manutenção de um programa mais simples e eficiente.

Quando um programa tem uma boa arquitetura, é sempre fácil entender como ele funciona e onde escrever o código. Um programa bem arquitetado é mais fácil de mudar, testar, depurar e desenvolver. Pessoas inteligentes formularam os seguintes critérios para uma boa arquitetura:

  • Eficiência;
  • Flexibilidade;
  • Expansibilidade;
  • Escalabilidade;
  • testabilidade;
  • Manutenibilidade do código.

Eficiência do sistema. O programa, é claro, deve resolver as tarefas atribuídas e desempenhar bem suas funções e em várias condições. Parece que qualquer programa faz o que deveria fazer (se estiver escrito), mas muitas vezes não é o caso.

Você encontrará constantemente programas que não fazem o que dizem fazer.

  • O Libre Office é um substituto completo para o Microsoft Office (na verdade não);
  • O navegador Edge suporta todos os padrões da web (na verdade não);
  • O banco se preocupa com a segurança dos dados pessoais de seus usuários (na verdade não).

E ainda não tocamos em desempenho, confiabilidade, correções de bugs oportunas ou na publicação de informações sobre vulnerabilidades conhecidas.

É claro que ninguém é perfeito, mas o programa deve resolver suas tarefas principais. Portanto, sem eficiência, em lugar nenhum.

Flexibilidade

A única coisa mais importante que a eficiência, na minha opinião, é a flexibilidade. Qualquer aplicativo precisa mudar com o tempo, pois conforme os requisitos mudam, novos são adicionados. Quanto mais rápido e conveniente for fazer alterações na funcionalidade existente, menos problemas e erros isso causará, mais flexível será a arquitetura do sistema.

Muitas vezes, os programadores/arquitetos novatos pensam que precisam de uma arquitetura ideal para as tarefas atuais. Não. Você precisa de uma arquitetura ideal para as tarefas que lhe serão anunciadas em um ano. Você, que já não conhece as tarefas futuras, deve saber quais serão.

Não faz sentido tentar prevê-los, pois sempre haverá algo inesperado. Mas você deve levar em conta que tais tarefas aparecerão. Portanto, no processo de desenvolvimento, tente avaliar o que está sendo obtido em termos de como isso precisará ser alterado.

Pergunte a si mesmo: "O que acontece se a decisão arquitetônica atual estiver errada?", "Quanto código será alterado?". Alterar um fragmento do sistema não deve afetar seus outros fragmentos.

Sempre que possível, as decisões arquitetônicas não devem ser imutáveis ​​e as consequências de erros arquitetônicos devem ser razoavelmente limitadas. "Boa arquitetura permite atrasar decisões importantes" (Bob Martin) e minimiza o "custo" de erros.

Uma dessas abordagens é dividir o aplicativo em microsserviços: é fácil quebrar a lógica já existente em partes separadas. Mas o maior problema é fazer alterações futuras em uma dúzia de serviços de uma só vez para implementar um pequeno recurso.

Escalabilidade

Escalabilidade é a capacidade de reduzir o tempo de desenvolvimento adicionando novas pessoas ao projeto. A arquitetura deve permitir que o processo de desenvolvimento seja paralelizado para que muitas pessoas possam trabalhar no programa ao mesmo tempo.

Parece que essa regra se cumpre sozinha, mas na prática tudo é exatamente o contrário. Existe até um livro superpopular, The Mythical Man-Month , que explica por que adicionar novas pessoas a um projeto aumenta o tempo de desenvolvimento.

Expansibilidade

Extensibilidade é a capacidade de adicionar novos recursos e entidades a um sistema sem violar sua estrutura principal. No estágio inicial, faz sentido colocar apenas a funcionalidade básica e mais necessária no sistema.

Este é o chamado princípio YAGNI - você não vai precisar dele , “você não vai precisar dele”. Ao mesmo tempo, a arquitetura deve permitir que você aumente facilmente a funcionalidade adicional conforme necessário. E para que a introdução das mudanças mais prováveis ​​exigisse o menor esforço.

A exigência de que a arquitetura do sistema seja flexível e extensível (ou seja, capaz de mudar e evoluir) é tão importante que chega a ser formulada como um princípio à parte - o “Princípio Aberto/Fechado . O Princípio Aberto-Fechado é o segundo dos cinco princípios SOLID: entidades de software (classes, módulos, funções) devem ser abertas para extensão, mas fechadas para modificação .

Em outras palavras: deve ser possível alterar e estender o comportamento do sistema sem reescrever as partes existentes do sistema .

Isso significa que o aplicativo deve ser projetado de forma que a alteração de seu comportamento e a adição de novas funcionalidades sejam feitas por meio da criação de um novo código (extensões), sem a necessidade de alterar o código existente.

Nesse caso, o surgimento de novos requisitos não acarretará uma modificação da lógica existente, mas pode ser implementada principalmente por sua expansão. Este princípio é a base da "arquitetura plug-in" (Plugin Architecture). As técnicas pelas quais isso pode ser alcançado serão discutidas posteriormente.

Lembre-se de servlets e filtros? Por que filtros eram necessários, e mesmo com interfaces separadas, se, de fato, toda a mesma lógica poderia ser implementada usando servlets?

Foi a invenção do conceito de filtros (servlets de serviço) que tornou possível mover várias funções de serviço para uma camada separada. E futuramente, ao alterar o comportamento dos filtros, não foi necessário alterar os servlets.

Antes da invenção dos filtros, toda a lógica do serviço responsável pelo redirecionamento das requisições estava localizada nos próprios servlets. E muitas vezes uma pequena mudança na lógica levaria à necessidade de passar por todos os servlets e fazer várias alterações em todos.

Testabilidade

Se você for um Java Backend Developer, seus aplicativos de servidor geralmente expõem um conjunto de métodos como uma API REST. E para verificar se todos os seus métodos funcionam conforme o esperado, eles precisam ser cobertos por testes.

Em geral, a cobertura de teste de API é um bom estilo. Ele permite que você tenha certeza de que sua API realmente faz o que foi planejado para fazer. E também, mais importante, você pode fazer alterações na lógica do servidor e verificar facilmente se não quebrou nada acidentalmente .

Assim que você começar a escrever testes, perceberá que a maior parte do código não pode ser testada: métodos privados, acoplamento forte, classes e variáveis ​​estáticas.

“Por que precisamos de testes se o código funciona?”, o iniciante perguntará.

“Para que precisamos de um código funcionando se ele não pode ser testado?”, questionará o profissional.

O código que é fácil de testar conterá menos bugs e será mais confiável. Mas os testes não apenas melhoram a qualidade do código. Quase todos os desenvolvedores eventualmente chegam à conclusão de que o requisito de “boa testabilidade” também é uma força orientadora que leva automaticamente a um bom design.

Aqui está uma citação do livro Ideal Architecture: "Use o princípio de "testabilidade" de uma classe como um "teste decisivo" de bom design de classe. Mesmo que você não escreva uma única linha de código de teste, respondendo a esta pergunta em 90 % dos casos ajudará a entender como tudo é bom" ou "ruim" com seu design."

Existe toda uma metodologia para desenvolver programas baseados em testes, que se chama Test-Driven Development (TDD). Este é obviamente o outro extremo: escreva o código antes de escrever o código.

Manutenibilidade do código

Via de regra, muitas pessoas trabalham no programa - algumas saem, outras chegam. O tempo médio de trabalho de um programador em uma empresa de TI é de um ano e meio. Portanto, se você chegou a um projeto de 5 anos, apenas 20% de seus colegas trabalharam nele desde o início.

Manter e desenvolver um programa que outros escreveram é muito difícil. Mesmo que o programa já esteja escrito, muitas vezes é necessário continuar a mantê-lo: corrigir erros e fazer pequenas correções. E muitas vezes isso tem que ser feito por pessoas que não participaram de sua redação.

Portanto, uma boa arquitetura deve tornar relativamente fácil e rápido para novas pessoas entenderem o sistema . O projeto deve ser:

  • Bem estruturado.
  • Não contém duplicação.
  • Tenha um código bem formatado.
  • É desejável incluir documentação.
  • É necessário aplicar soluções padrão e familiares para programadores.

Você pode classificar facilmente o projeto em que está trabalhando em uma escala de 5 pontos . Basta contar dois pontos para cada um desses requisitos . E se você conseguir 5 ou mais, então você tem sorte.

Os programadores até têm um princípio de menor surpresa : quanto mais exótico o sistema, mais difícil é para os outros entenderem. Normalmente, é usado em relação à interface do usuário, mas também é aplicável para escrever código.