A Arquitetura em Camadas é o padrão de projeto mais conhecido e o mais aplicado na construção de uma Arquitetura de Software. Este padrão vai de encontro ao modelo tradicional de organização e comunicação de TI dentro das empresas, tornando-se assim uma escolha natural para a maioria das soluções.

Padrões de Projeto - Layered Architecture.
Arquitetura em Camadas (Layered Architecture)

Definição

Os componentes de uma Layered Architecture são organizados em camadas horizontais onde cada uma desempenha um papel específico na aplicação.

Embora o padrão não especifique a quantidade e os tipos de camadas, a maioria segue a seguinte organização: apresentação, negócios, persistência e banco de dados. Em alguns casos, a camada de negócios e persistência são integradas quando a lógica de persistência é encapsulada nos componentes de negócio (exemplo com o uso de ORMs como NHibernate e Entity Framework).

Além disto, é comum que aplicações pequenas possuam em torno de 3 camadas e aplicações mais complexas em torno de 5 ou mais camadas.

Cada camada dentro da arquitetura possui um papel e uma responsabilidade dentro da aplicação. Por exemplo, a camada de apresentação lida com aspectos relacionados a interface do usuário, enquanto a camada de negócios lida com regras de negócios dentro de um determinado contexto.

Padrões de Projeto - Organização em Camadas
Exemplo de organização em camadas

Portanto, cada camada fornece uma abstração sobre o trabalho necessário para atender uma necessidade de negócios. Consequentemente, cada camada não precisa saber os detalhes do que acontece nas camadas mais distantes na estrutura.

Em resumo, uma das principais características deste padrão de projeto está na separação de responsabilidades. Componentes dentro de uma camada lidam apenas com as particularidades daquela camada. E este modelo de organização facilita o processo de construção, testes e manutenção dos seus elementos.

Conceitos Principais

Um dos conceitos chave na Layered Architecture é que cada camada é “fechada”. Em outras palavras, uma requisição enviada para uma camada deve seguir para a camada imediatamente posterior.

Organização em Camadas

Por exemplo, uma requisição feita na camada de apresentação deve seguir primeiro para a camada de negócios, depois para a camada de persistência para finalmente acessar a camada de banco de dados.

Isolamento de Camadas

Outro conceito importante consiste no isolamento de camadas. Clarificando, isolamento significa que mudanças em uma camada não deveriam impactar as camadas mais distantes.

Por exemplo, caso a camada de apresentação utilize a camada de persistência diretamente, mudanças na camada de persistência iriam gerar impactos diretos na camada de negócios e na de apresentação, criando uma aplicação altamente acoplada. Consequentemente, a manutenção neste tipo de aplicação torna-se cara e difícil.

Além disto, o isolamento significa que as camadas desconhecem os detalhes de funcionamento das camadas mais distantes. O poder deste conceito reside no fato de que caso não haja mudança no contrato entre as camadas, modificações nos componentes de uma camada não geram impacto em outra. Exemplo: alterar o front-end SPA de Angular para React, considerando que todas as chamadas de negócio estão encapsuladas em APIs.

Abertura de Camadas

Enquanto as camadas “fechadas” ajudam a isolar mudanças dentro da arquitetura, há cenários no qual faz sentido “abrir” a camada.

Por exemplo, algumas funcionalidades fazem sentido dentro de uma camada de serviços. Esta camada de serviços (ex: logging) é geralmente consumida pela camada de negócios e não acessada pela camada de apresentação.

Exemplo de abertura de Camada

Portanto, sem este isolamento, não há nada que impeça o acesso a componentes de serviço por componentes de apresentação.

Contudo, pelo fato da camada de serviços estar logo abaixo da camada de negócios leva a falsa impressão de que o acesso a camada de persistência será feito através da camada de serviços. Por este motivo, a camada de serviços é tida como “aberta”, permitindo que ela seja ignorada em algumas situações.

Além disto, definir quais camadas dentro da arquitetura são “fechadas” ou “abertas” ajuda a clarificar os relacionamentos entre elas. Fornece aos desenvolvedores os limites de acesso aos componentes dentro da arquitetura.

Concluindo, qualquer falha em comunicar quais camadas da arquitetura são “abertas” ou “fechadas” resultam em sistemas altamente acoplados ou arquiteturas bagunçadas, difíceis de manter, testar e implantar.

Exemplo de Arquitetura em Camadas

Um exemplo de implementação do padrão é apresentado na figura abaixo:

Exemplo de fluxo de execução de uma arquitetura em camadas.
Exemplo de Fluxo de Execução

O fluxo acima pode ser compreendido da seguinte maneira:

  1. Na camada de apresentação, a tela do cliente (“Customer Screen”) recebe uma solicitação de obtenção de dados do cliente. Importante frisar que este componente desconhece detalhes de como obter informações. Em outras palavras, este componente é responsável por exibir informações na tela.
  2. Após isto, a tela do cliente envia a solicitação para o componente “Customer Delegate”. Este componente é responsável por se comunicar com módulos da camada de negócios para atender a solicitação.
  3. Então o componente “Customer Object” na camada de negócios orquestra requisições para componentes na camada de persistência. Dados do cliente são solicitados para o componente “CustomerDao”. Dados de pedido do cliente são solicitados para o componente “OrderDao”;
  4. Os componentes da camada de persistência fazem acesso a base de dados e retornam as informações solicitadas;
  5. Finalmente, o fluxo de informação entre os componentes segue o caminho inverso passando por todas as camadas até a requisição inicial;

Por outro lado, cada camada pode utilizar qualquer tecnologia que melhor suporte a realização da sua responsabilidade. Por exemplo, a camada de apresentação pode usar frameworks javascript enquanto a camada de persistência utiliza um ORM.

Considerações

Dentre os diversos padrões de projeto existentes, a arquitetura em camadas é um bom ponto de partida, principalmente em cenários onde não há certeza de qual padrão utilizar. Contudo, há uma série de considerações a serem avaliadas do ponto de vista de arquitetura.

Primeiramente, há necessidade de ficar atento a existência do anti-padrão “sinkhole”. Este anti-padrão indica que a maioria das requisições passam entre as camadas sem a aplicação de nenhuma regra de negócio ou processamento entre cada camada.

Entretanto, é comum algumas requisições na Arquitetura em Camadas algumas requisições seguirem este fluxo. Uma forma importante de medir se há excesso de anti-padrão na arquitetura é aplicar a regra 80-20. Ou seja, somente 20% das requisições devem ser afetadas por este anti-padrão.

Porém, caso a quantidade de requisições seja maior, o melhor caminho será “abrir” algumas camadas para diminuir o nível de isolamento e integração entre componentes de camadas que agregam pouco valor na execução. O cuidado nesta decisão deve levar em consideração o aumento na dificuldade de controlar as dependências.

Finalmente, a arquitetura em camadas tende direcionar a construção de sistemas monolíticos, mesmo quando os componentes são separadas em unidades de instalação diferentes. Entretanto, dependendo do tamanho, a aplicação pode sofrer impacto negativo em atributos relacionados a robustez, performance, escalabilidade e facilidade de instalação.

Análise de Pontos Fortes e Fracos

A Arquitetura em Camadas possui algumas características que determinam as capacidades mais importantes do modelo. Além disto, é possível analisar e avaliar cada característica para orientar tomadas de decisão.

Agilidade Geral (baixa)

Esta característica consiste na habilidade de responder rapidamente as mudanças de ambiente. Ainda que as camadas estejam isoladas, realizar mudanças são demoradas e pesadas, devido a natureza monolítica da solução. Somado a isto, a dificuldade é ampliada com a existência de componentes altamente acoplados.

Facilidade de Implantação (baixa)

Dependendo do tamanho da aplicação, a implantação dos componentes pode ser um problema. Por exemplo, uma pequena mudança em um componente pode exigir o deploy da aplicação inteira, exigindo planejamento prévio e agendamento e execução do mesmo em horários de baixa execução do sistema.

Assim sendo, este padrão não orienta o trabalho para uma entrega contínua, reduzindo assim a velocidade de entrega de soluções.

Testabilidade (alta)

A facilidade nos testes é resultado da capacidade de “mockar” componentes de camadas que não pertencem a camada que será testada. Em outras palavras, é possível testar uma regra de negócios sem precisar de uma base de dados funcionando.

Performance (baixa)

A baixa performance é devido em cenários de alto volume não haver paralelismo de execução. Ou seja, cada requisição é obrigado a passar por praticamente todas as camadas para ser atendida.

Escalabilidade (baixa)

Devido a natureza monolítica e a tendência de acoplamento entre os componentes é gerada uma barreira a escalabilidade. Quer dizer, apesar da organização em camadas permitir a separação em componentes isolados, a granularidade entre eles é elevada, limitando ou tornando cara a escalabilidade da aplicação.

Por exemplo, uma camada de negócios relacionadas a pedido e cliente, será ampliada como um todo, mesmo que a necessidade seja suportar uma maior consulta de pedidos.

Facilidade de Desenvolvimento (alta)

Este padrão de projeto é amplamente conhecido e relativamente fácil de ser compreendido. Além disto, o “mindset” de desenvolvimento tende a especializar etapas de trabalho ou tecnologias, facilitando a associação com as camadas do projeto.

Conforme mencionado por Melvin Conaway, a estrutura das organizações produzem um alto impacto na forma como os sistemas são criados. Leia mais aqui.


“Qualquer empresa que projeta um sistema (definição mais ampla aqui do que apenas sistemas de informação), inevitavelmente produz um projeto cuja estrutura é uma cópia da estrutura de comunicação da organização.”

Melvin Conaway

Portanto, a escolha da Arquitetura em Camadas tende a estar alinhada com a cultura de trabalho e comunicação da empresa, facilitando assim a propagação do trabalho a ser realizado.

Conclusão

A facilidade de construir e testar os componentes promove uma impressão de produtividade e agilidade na entrega das soluções. Além disto, a estrutura do modelo vai de encontro ao modelo tradicional verticalizado das empresas, facilitando sua adoção nas maiorias dos cenários.

Entretanto, em cenários que demandam entrega contínua, escalabilidade, performance e rapidez de mudança não é o padrão mais adequado.

Para entender a importância dos padrões de projeto na Arquitetura de Software e ter uma visão geral dos principais padrões utilizados, clique aqui.

No próximo artigo sobre padrões de projeto será apresentado o “Event Driven Architecture”. Até mais!!!

Deixe sua opinião