DEV Community

Ortiz de Arcanjo Antonio David
Ortiz de Arcanjo Antonio David

Posted on

Arquitectura e Design num Software Modularizado

Definições Relacionadas

Arquitectura de Software: está focada na organização dos componentes de software, suas responsabilidades e relacionamento entre eles.
Design de Software: está focado na organização de Classes, Objectos, Métodos, Interfaces, Funções, Traits, Protótipos de acordo a linguagem. Em outras palavras, princípios de Design Patterns.
Módulos: são unidades autônomas e independentes do sistema, cada um com uma responsabilidade específica.

Desafios na Arquitetura Modular de Software

Em um ambiente de software modular, cada módulo pode ser implementado com sua própria arquitetura, constituindo uma tarefa complexa, porém poderosa, pois oferece a flexibilidade de adoptar técnicas distintas conforme a natureza específica de cada módulo.

Por exemplo, um módulo que requer operações comuns de CRUD pode ser estruturado utilizando o Padrão MVC, enquanto outro, que demanda a separação rigorosa entre consultas e comandos, pode adotar o modelo CQRS.

O design da aplicação deve ser concebido de forma a possibilitar a integração harmoniosa dos módulos, gerando uma aplicação coesa.
No contexto de aplicações web, é crucial considerar a integração das rotas de cada módulo, uma vez que, no final, o acesso às funcionalidades ocorrerá por meio de URLs.

Comunicação entre os módulos

A comunicação entre módulos ocorre através de chamadas de métodos, funções ou variáveis, e a organização em namespaces ou pacotes ajuda a evitar conflitos de nomes.
Nomes consistentes e dependências explicitamente declaradas são práticas recomendadas para facilitar a navegação e manutenção do código.
A seguir, apresentamos as diferentes formas de comunicação entre módulos:

1. Chamada de Métodos, Funções ou Variáveis

  • Módulos: Em muitas linguagens, os módulos podem conter funções, métodos ou variáveis. A comunicação entre módulos geralmente ocorre quando uma função, método ou variável de um módulo é chamada por outro módulo.

2. Nível de Pacotes ou Namespaces

  • Namespaces: Em algumas linguagens, como C++, C# e PHP, usam namespaces para organizar código e evitar conflitos de nomes. Os módulos podem ser encapsulados em namespaces, e a comunicação entre módulos de diferentes namespaces é feita referenciando o nome do namespace seguido pelo nome do módulo (por exemplo, namespace.modulo.funcao()).
  • Pacotes: E noutras linguagens, como Java, Kotlin e Go, os módulos são organizados em pacotes. A comunicação entre módulos de diferentes pacotes é realizada usando a notação de ponto (por exemplo, pacote.modulo.funcao()).

3. Nomes Consistentes para Facilitar a Navegação do Código

  • É recomendado dar nomes consistentes aos módulos, funções e variáveis para facilitar a leitura e manutenção do código. Isso inclui seguir convenções de nomenclatura, escolher nomes descritivos e usar um estilo consistente em todo o projeto.

4. Dependências Explícitas

  • Em sistemas mais complexos, é comum declarar explicitamente as dependências entre módulos. Isso pode ser feito em arquivos de configuração específicos (como em sistemas baseados em pacotes) ou através de anotações especiais no código-fonte.

5. Interfaces Bem Definidas

  • Em muitas situações, é benéfico ter interfaces bem definidas entre módulos. Isso facilita a manutenção, a substituição de implementações e o teste de unidade.

Roteamento dos Módulos

Cada módulo pode seguir a sua própria arquitectura, desde que as rotas sejam unificadas ao final do processo. Em cada módulo, é necessário carregar todas as rotas presentes nos controllers (ou handlers). O resultado final consiste na consolidação de todas as rotas do módulo.

No nível mais alto da aplicação, as rotas inicializadas por cada módulo precisam ser carregadas. Nesta etapa, é essencial inicializar os controllers.

Os controllers têm a responsabilidade de retornar páginas em formatos diversos, como HTML, XML ou JSON, e de lidar com redirecionamentos. A principal preocupação reside na coesão final das rotas, sendo que o tipo de retorno não afeta a estrutura do software.

A sequência de chamadas das rotas segue a ordem:

  • Definição de rotas para cada Controller.
  • Carregamento de todos os controllers do módulo.
  • Integração das Rotas dos Módulos.

Estrutura básica de um softwre Modular

1. Config: Contém as configurações essenciais, como variáveis de ambiente, configurações de base de dados, engine de templates, sessão e logs. Centraliza as configurações críticas do sistema, facilitando a gestão e a modificação de parâmetros fundamentais.
2. Helpers: Responsável pela implementação de funções de auxílio (helpers) que podem ser utilizadas em diversos pontos do sistema. Encapsula funcionalidades comuns que podem ser compartilhadas entre diferentes módulos.
3. Middlewares: Agrupa funções que interceptam a execução da aplicação de maneira global, como logs de requisições e autenticação. Facilita a aplicação de lógicas globais a todas as requisições
4. Modules: Contém todos os módulos da aplicação, onde cada módulo pode ter sua própria implementação específica. Isola as funcionalidades em unidades independentes,
5. Static: Armazena arquivos estáticos, como HTML, CSS, JS, ou diretórios para uploads de documentos PDF, vídeos e imagens. Fornece um local centralizado para recursos estáticos.
6. Templates: Contém páginas HTML ou engines de templates utilizadas na interface do usuário. Separa a lógica de apresentação do restante do código.
7. Database: Engloba a estrutura da base de dados de cada módulo, incluindo a definição de schemas, tabelas, views, triggers e outros objetos. Pode ser independente do software, localizando-se fora da pasta do projeto.
8. Application: Responsável pela execução da aplicação, incluindo a inicialização de todos os controllers, middlewares, engines de templates e arquivos estáticos. Serve como ponto de entrada e orquestração, garantindo a correta inicialização e integração de todos os componentes do sistema.

Conclusão

Recomenda-se aos desenvolvedores dedicarem tempo ao estudo de arquitetura dentro de um software modular. A prática constante pode auxiliar na identificação dos componentes a partir dos requisitos de software. Entender a interação entre os módulos é crucial, visto que isso facilitará a construção de sistemas complexos.

Exemplo

Criação de um sistema modular usando a linguagem Golang.
Código fonte: https://github.com/ortizdavid/golang-modular-software.

Image description

Image description

Image description

Image description

Image description

Image description

Image description

Image description

Top comments (0)