Projeto de Software – 02 – Princípios de Arquitetura de Software

Autor(a):

Hoje, vamos falar de arquitetura de software. Eu já tinha ouvido falar desse termo antes, mas não tinha ideia de que ele envolvesse uma abordagem tão profunda e acadêmica. 

Se quiser revisitar a primeira parte desta série, você pode clicar neste link aqui.

Sem mais delongas, vamos adentrar o universo da Arquitetura de Software.

A Arquitetura de Software pode ser caracterizada como a “espinha dorsal” dos sistemas, definindo padrões organizacionais estruturais que orientam todo o desenvolvimento. Basicamente, estamos falando de um conjunto de elementos essenciais:

Componentes: Essas são as peças-chave que formam o sistema. Eles podem ser categorizados em clientes, servidores, filtros, camadas e bancos de dados. Cada um desempenha um papel vital na construção e funcionamento do software.

Conectores: Os conectores são como os “fios” que conectam esses componentes. Eles são responsáveis por gerenciar as interações entre os elementos do sistema. Conectores podem assumir diversas formas, incluindo chamadas a procedimentos, transmissão de eventos, protocolos de banco de dados e até mesmo tubos (pipes).

A Arquitetura de Software, portanto, é a arte de projetar cuidadosamente esses componentes e conectores de forma eficiente, assegurando que eles operem em perfeita harmonia para atender aos requisitos do sistema.

Quando nos referimos a componentes, estamos abrangendo uma variedade de elementos, tais como:

  • Clientes
  • Servidores
  • Filtros
  • Camadas
  • Banco de Dados

E quando se trata de conectores, engloba-se:

  • Chamadas a procedimentos
  • Transmissão de Eventos
  • Protocolos de Banco de Dados
  • Tubos (Pipes)

Além disso, é importante ressaltar que muitas vezes é possível encontrar combinações de estilos arquiteturais, o que amplia ainda mais as possibilidades e complexidade da Arquitetura de Software.

Outro ponto crucial a ser observado é a dimensão temporal envolvida. A arquitetura de software não é algo definido de uma vez por todas e perpetuado no tempo. A ideia fundamental é que as decisões arquiteturais são tomadas e, com o tempo, podem ser reavaliadas e ajustadas ao longo do ciclo de vida do software. O mundo da tecnologia está constantemente em evolução, com agentes externos que alteram a forma como certos componentes funcionam. Portanto, é responsabilidade do software se adaptar a essas mudanças, e a arquitetura desempenha um papel crucial nesse processo.

Aqui, o ponto central é a importância de termos um registro sólido da arquitetura de software. Isso desempenha um papel fundamental na compreensão e na valorização da Arquitetura de Software.

Existem várias razões pelas quais esse registro é essencial:

Comunicação com stakeholders: O registro da arquitetura permite uma comunicação eficaz com todas as partes interessadas. É uma forma de apresentar uma visão de alto nível do sistema, facilitando a compreensão por parte dos envolvidos.

Análise do sistema: Tornar a arquitetura explícita desde o estágio inicial de desenvolvimento requer alguma análise. Essa análise pode levar a decisões cruciais que atendam aos requisitos críticos do projeto.

Reuso em larga escala: Muitas vezes, uma arquitetura bem definida pode ser reutilizada em sistemas com requisitos semelhantes. Isso economiza tempo e recursos, além de garantir a consistência em projetos relacionados.

Certamente, pensar no processo de projeto de arquitetura de software envolve uma abordagem estruturada e iterativa, como sugerido por Gorton em 2006. O processo geralmente segue as seguintes etapas:

1 – Estabelecimento de Requisitos

2 – Projeto de Arquitetura

3 – Validação da Arquitetura

4 – Estabelecimento de Novos Requisitos Estruturais

Enquanto o software estiver existindo, sendo mantido, isso é essencial.Entrando em Estabelecer os Requisitos Arquiteturais, temos

Para estabelecer requisitos arquiteturais sólidos, é essencial realizar um processo que englobe requisitos funcionais e não funcionais. Estes últimos podem ser considerados a partir de diversas perspectivas, incluindo as necessidades dos stakeholders, os atributos de qualidade desejados e as restrições impostas ao sistema.

Alguns desses requisitos podem ser mais do que simples especificações; eles podem ser verdadeiras restrições que moldam as decisões arquiteturais. Aqui estão exemplos ilustrativos retirados do material:

Exemplo 1: “As comunicações entre os componentes devem ser garantidas com sucesso, sem perda de mensagens.” Isso se enquadra na categoria de confiabilidade, um atributo de qualidade fundamental que a arquitetura deve abordar.

Exemplo 2: “O sistema deve utilizar o servidor web baseado no Apache existente e usar PHP para processar solicitações da web.” Neste caso, a escolha do servidor web e da linguagem de programação não é apenas uma preferência, mas uma restrição imposta, o que influenciará diretamente a arquitetura do sistema.

Em resumo, a definição de requisitos arquiteturais é um processo intrincado que exige uma análise minuciosa de requisitos funcionais, não funcionais (incluindo atributos de qualidade) e restrições, todos desempenhando um papel vital na formação da arquitetura de software.

Agora, ao considerarmos o conceito de qualidade de software, identificamos duas dimensões essenciais que delineiam o que é qualidade em software.

  • Grau de satisfação das necessidades dosvclientes sob todos os aspectos do produto (Sanders, 1994)
  •  Atributos de Qualidade

Uma característica de software que especifica o grau que deve possuir um atributo que afeta a qualidade do software (ISO 2001).

De acordo com a norma ISO/IEC 25010, qualidade de software pode ser descrita como:

A qualidade de software é um conglomerado de diversos itens agrupados, desde de performance a manutenção. Em outro momento, volto com um texto para falar um pouco sobre os modelos de qualidade da ISO, no momento se atente, que são diversos itens que precisamos está ciente no desenvolvimento da nossa aplicação para podermos dizer, estamos desenvolvendo software com qualidade. 

E já estou martelando, de acordo com o próprio conteúdo, é Impossível ter um alto grau de qualidade em todos os atributos. Um software que está com qualidade em um requisito, pode ter efeito prejudicado em outro, por exemplo.

Alto Desempenho X Portabilidade

Projeto de Arquitetura:

Com essas definições dos requisitos estruturais, podemos partir para o projeto de arquitetura de um software. Aqui, entram em jogo dois artefatos cruciais que derivam desse processo: as visões arquiteturais e o documento de arquitetura.

Basicamente, o projeto de arquitetura, segundo M. Shaw e D. Garlan em 1996, envolve a criação de uma estrutura que define uma família de sistemas com base em um padrão de organização estrutural. Isso inclui o estabelecimento de um vocabulário específico para os componentes e conectores, bem como restrições sobre como esses elementos podem ser combinados. De forma resumida, o projeto de arquitetura consiste em nomear um conjunto de decisões de design arquitetural que se aplicam em um contexto particular.

Além disso, os estilos arquiteturais desempenham um papel crucial no processo, pois nos permitem descrever as características dos componentes e conectores do sistema, a topologia da arquitetura, as restrições semânticas e os mecanismos de interação entre esses elementos. Tudo isso oferece a possibilidade de reutilizar um conjunto de características desejadas, abrangendo tanto requisitos funcionais quanto não funcionais.

Agora, mergulhando em um dos padrões e estilos arquiteturais específicos, vamos explorar o conceito de ‘Tubos e Filtros (Pipes & Filters)’.

É incrível como o padrão arquitetural “Tubos e Filtros (Pipes & Filters)” é algo que muitos de nós utilizam no dia a dia, embora possamos não reconhecê-lo por esse nome específico. Foi uma surpresa para mim também quando fui apresentado a essa terminologia.

Vamos esclarecer um pouco mais:

Descrição:

Cada componente desse padrão possui um conjunto de entradas e saídas.

Componentes:

Filtros

Conectores:

Tubos (Pipes)

Restrições:

  • Cada filtro é uma unidade independente.
  • Filtros não têm conhecimento uns dos outros.
  • A precisão da saída de um filtro não depende da ordem em que os filtros são aplicados.

Na prática, isso se traduz de uma maneira incrivelmente eficaz de encadear comandos em um terminal, como acontece em scripts de shell, onde a saída de um comando se torna a entrada do próximo. Cada comando age como um filtro independente, e eles funcionam sem saber da existência uns dos outros.

É realmente um padrão arquitetural interessante. Em algum momento, poderemos aprofundar em um texto dedicado sobre esse tópico e explorar as possibilidades dos comandos bash. Por agora, a ideia é entender que isso é, de fato, um padrão arquitetural muito útil e presente em nosso cotidiano.

Vamos seguir em frente, falando agora sobre a arquitetura em camadas, algo que muitos de nós já topamos em diferentes lugares, meio que lembrando o velho Modelo OSI.

Arquitetura em Camadas – Dividindo Tudo:

Nesse esquema, a ideia é separar tudo em camadas, tipo uma hierarquia organizada, um verdadeiro “sanduíche” de funcionalidades. Às vezes, chamam isso de Cliente-Servidor com vários andares.

Basicamente, o servidor está lá embaixo, fornecendo serviços para a camada de cima, que é o cliente, pegando o que precisa da camada inferior. Vamos dar uma olhada na definição:

Descrição:

Imagine um sistema empilhado em camadas, como uma torre de blocos. Cada camada presta serviços para a camada acima dela.

Componentes:

Camadas

Conectores:

Protocolos que ditam como essas camadas se comunicam

Restrições:

Há limites em como essas camadas podem se comunicar, só podem interagir com as camadas vizinhas.

Na prática, isso é amplamente usado, especialmente em redes de computadores, como o bom e velho Modelo OSI. A ideia é tornar tudo organizado, com cada camada fazendo uma coisa específica. É como dividir e conquistar, o que facilita muito a compreensão e a manutenção de sistemas complexos.

Agora entrando no mundo mais web, temos as Camadas Cliente-Servidor, a ideia é solicitação e resposta 

Continuando sobre arquitetura na web, agora explorando a arquitetura de duas camadas e a arquitetura de três camadas.

Arquitetura de Duas Camadas – Simplicidade em Ação:

Aqui, os componentes podem assumir dois papéis principais: servidor (de armazenamento) e servidor (de apresentação), além do cliente. O servidor fica com a responsabilidade de retornar tanto os dados de apresentação quanto de armazenamento.

Mas, atualmente, o que vemos com mais frequência na web é a arquitetura de três camadas:

Arquitetura de Três Camadas – Mais Poder e Organização:

Novamente, os componentes podem ser servidores de armazenamento, servidores de apresentação ou agora, servidores de aplicação. E, claro, ainda temos o cliente executando a interface.

O que muda aqui é que o servidor ganha uma camada adicional, a de aplicação, que cuida das relações entre as classes e regras de negócios, para então armazenar os dados no banco de dados.

Essa é a forma mais comum que encontramos na web hoje em dia, e é como conseguimos organizar e dar mais poder às nossas aplicações.

Publisher / Subscriber – A Comunicação de Mensagens:

Esse padrão é algo que vale a pena explorar mais a fundo em algum momento. A ideia principal aqui é que os Subscribers podem se inscrever ou “desinscrever” para receber mensagens ou conteúdo específico, enquanto os Publishers transmitem essas mensagens para os assinantes de forma síncrona ou assíncrona. Basicamente, é a base para muitos serviços de mensagens que usamos hoje.

Microsserviços – A Revolução na Arquitetura de Aplicativos:

Essa é uma mudança incrível no desenvolvimento de aplicativos. Os Microsserviços permitem que um grande aplicativo seja dividido em partes independentes menores, cada uma com sua própria responsabilidade. Para dar um exemplo, ao atender uma única solicitação do usuário, um aplicativo baseado em microsserviços pode chamar vários microsserviços internos para compor a resposta.

E os contêineres são um exemplo brilhante disso. Eles permitem que você se concentre no desenvolvimento dos serviços sem se preocupar muito com as dependências. Aplicativos nativos da nuvem frequentemente são construídos usando a arquitetura de microsserviços em contêineres.

Cada microsserviço é como um serviço autônomo que lida com uma parte específica da funcionalidade do aplicativo. Eles se comunicam com outros serviços por meio de interfaces simples para resolver problemas comerciais.

Comparado a algo como o “Monolito,” em que o sistema é executado como um único processo, os microsserviços trazem uma abordagem mais flexível, em que cada microsserviço executa como um processo autônomo

O slide do professor mostra uma imagem interessante que demonstra essa progressão nos padrões arquiteturais

Muito interessante ver essas definições por décadas e os padrões.

Voltando na nossa imagem anterior, vamos comecar a visualizar os padrões arquiteturais presentes.

Vamos agora explorar as visões arquiteturais, que desempenham um papel crucial na compreensão e documentação da arquitetura de um sistema:

Visões Arquiteturais – Moldando a Compreensão:

Uma visão é essencialmente uma representação de um conjunto de elementos e suas relações em um sistema. Qual visão é relevante depende da finalidade do arquiteto. Documentar uma arquitetura significa documentar as visões que são significativas para o contexto e, em seguida, incluir informações que se aplicam a várias visões.

É importante notar que existem diversos conjuntos de visões arquiteturais propostos por diferentes autores. Um dos mais conhecidos é o Modelo 4+1, apresentado por Kruchten em 1995.

Essas visões arquiteturais desempenham um papel fundamental na comunicação e compreensão de sistemas complexos, ajudando arquitetos e desenvolvedores a trabalharem em sintonia e a criar sistemas sólidos e bem documentados.

Vamos dar uma olhada mais detalhada nos quatro artefatos principais e entender como eles se encaixam:

Visões Arquiteturais – Desvendando os Detalhes:

Visão de Cenários: Aqui, os cenários desempenham um papel crucial. Eles unem todas as quatro visões e até as validam! Os cenários são como o guia supremo do projeto da arquitetura. Eles estabelecem requisitos amplos e complexos (as outras visões vão detalhar isso melhor). Além disso, ajudam a identificar interfaces críticas e orientam os projetistas a focarem em questões concretas. Ah, e eles também ajudam a determinar as prioridades do sistema. Não subestime o poder dos cenários!

Visão Lógica: Agora, estamos falando dos aspectos funcionais do sistema. O que o sistema deve fazer em termos de serviços? Basicamente, são os Requisitos Funcionais que estão no centro das atenções aqui. Essa visão é composta por vários diagramas que revelam as principais abstrações do sistema. Você encontrará as classes mais importantes e os pacotes que as abrigam. Também dá uma ideia clara de como essas classes e pacotes estão interconectados.

Visão de Desenvolvimento: Aqui, o foco é mostrar as estruturas dos componentes e gerenciar o projeto. Componentes são como os blocos de construção físicos do sistema. Eles podem ser executáveis, bibliotecas dinâmicas (dlls), módulos, cabeçalhos, formulários, entre outros. Existem diferentes tipos de componentes, e as setas indicam as relações de dependência entre eles. É uma visão fundamental para entender como as partes do sistema se encaixam.

Visão de Processos: Esta visão se concentra em decompor o sistema em processos e mostrar como os componentes executáveis são alocados a esses processos. É como dividir o sistema em linhas de execução de processos concorrentes (threads). Além disso, considera questões de qualidade, como disponibilidade, desempenho e confiabilidade. Basicamente, estamos lidando com os atributos não funcionais do sistema aqui.

Visão Física: Aqui, mapeamos os processos em unidades de processamento. Um processo é essencialmente uma linha de controle executada em uma unidade de processamento. Em sistemas grandes ou distribuídos, podemos quebrar as coisas em diversos processos. Levamos em consideração requisitos como capacidade de resposta, desempenho, tolerância a falhas e peculiaridades de implementação, como a necessidade de processadores específicos. Diagramas de implantação (deployment diagrams) mostram as unidades de processamento e seus processos.

Aqui está o ponto: você não precisa necessariamente de todas essas visões em todos os projetos. Escolha aquelas que fazem sentido com base nas preocupações dos stakeholders.

E para escrever tudo isso, é necessário notações, você pode definir notações informais ou notações semi formais, com UML ou notações formais como ADLs

Na esquerda possuímos uma notação informal, você precisa definir cada um dos itens o que significa.

Quando você utiliza a notação semiformal, da UML, não é necessário explicar cada item, pois já é um algo com consenso.

Um exemplo prático de diagrama de visões arquiteturais usando UML são os bons e velhos Diagramas de Casos de Uso. Eles não têm a missão de definir a estrutura minuciosa do sistema, mas são um grande auxílio para entender como o sistema funciona e por que a arquitetura foi projetada da maneira que é.

▪ Diagramas de Casos de uso

Aqui está um exemplo de visões arquiteturais usando UML, chamado Cenários.

Quando estamos lidando com as visões lógicas, podemos utilizar diversos tipos de diagramas, como diagramas de classe, diagramas de pacotes e diagramas de comportamento, que englobam comunicação e lógica. Com esses diagramas, conseguimos responder a várias perguntas cruciais, como:

Qual é a composição lógica do sistema?

Quais responsabilidades foram atribuídas aos diferentes elementos do sistema?

Como os elementos do sistema estão agrupados logicamente?

Como as funcionalidades do sistema realmente funcionam?

Agora, quando entramos na visão de desenvolvimento, continuamos a usar o diagrama de classe, mas com um foco muito mais detalhado para responder a perguntas como:

Quais elementos concretizam a instância de execução do sistema?

De onde esses elementos vêm (desenvolvimento interno, aquisição externa, etc.)?

Quais linguagens, técnicas e ferramentas são usadas para criá-los?

Quais habilidades são necessárias para desenvolver e manter esses elementos?

Como os elementos são organizados em unidades de desenvolvimento e implantação?

Nessa versão, o diagrama de classe é detalhado ao máximo, incluindo todos os atributos e parâmetros definidos.

Quando mergulhamos na visão de processo, podemos contar com o apoio de diagramas de interação e diagramas de atividade, sendo necessário um diagrama para cada processo.

E, finalmente, para entender a visão física, recorremos ao diagrama de implantação e ao mapeamento de rede, que são essenciais para compreender essa dimensão.

Esses diagramas são como as ferramentas de um arquiteto de software para projetar e visualizar a arquitetura de um sistema de maneira eficaz.