Skip to main content

Arquitetura de Software

· 18 min read
Bruno Carneiro

Arquitetura de Software

Base39 — Infraestrutura para Crédito

Quando falamos sobre Arquitetura de Software é comum realizarmos referências aos principais aspectos do design de um sistema de software. A arquitetura é algo muito importante e tem o poder de tornar o projeto/empresa um sucesso ou um grande fracasso, dependendo de como foi planejado e executado.

Neste artigo falarei um pouco de Arquitetura de Software, a sua importância, riscos e o que isso impacta no seu produto/serviço/negócio.

https://www.monkeyuser.com/

O que é Arquitetura de Software?

Arquitetura de software pode ser muito abrangente, pode ser definida como os fundamentos de como um software foi desenvolvido, a separação de seus componentes e como eles interagem entre si. Para muitas equipes e empresas de software isso pode ter outros significados.

Gosto de definir arquitetura de software como a separação de pequenos components que realizam uma interação entre si criando uma aplicação robusta o suficiente para resolver determinados problemas.

Pense da seguinte maneira, várias funções tendo cada uma sua responsabilidade que separadamente podem não fazer muito sentido, mas quando unidas criarão uma aplicação com inteligência suficiente para realizar a transferência de moedas entre diferentes nacionalidades.

É claro que pensando assim parece muito simples, mas para que isso se torne simples, robusto, escalável e confiável é necessário um design muito bem elaborado, pensando em cada problema que o software pode apresentar e como ele irá se comportar perante o uso de seus clientes, porque de nada serve uma excelente arquitetura se não existirem clientes utilizando a aplicação.

O que não é Arquitetura de Software?

Mas antes de avançar no entendimento de Arquitetura de Software preciso deixar claro o que ela não é. Arquitetura de Software não é um conjunto de pastas, isso é apenas a organização de um sistema. É claro que uma boa arquitetura só funcionará se existir uma boa organização, mas o conjunto de pastas não define uma boa arquitetura.

Como no exemplo abaixo:

Parte de uma estrutura de pasta para um projeto de Front-end utilizando ReactJS

Por que Arquitetura de Software é importante?

  • Uma visão unificada: A arquitetura providencia uma visão única de comunicação através de todos os envolvidos. Dessa maneira todo o time envolvido trabalha na mesma visão, falando a mesma "língua". Independente se são desenvolvers, QA, managers e etc., o time aqui vai ter uma visão comum.

  • Sólidos fundamentos: As decisões iniciais para o desenvolvimento do software são os mais importantes. Neste ponto as estruturas bases e padrões são elaborados/definidos com todo o time e nesta fase podem facilmente serem modificados. Reduzindo drasdicamente custos de mudanças futuras. Pense neste ponto como a base estrutural de uma casa, se não for bem pensada pode provocar grandes problemas futuros, até mesmo a ruína da casa.

  • **Escalabilidade: **Independente do tamanho do projeto ele precisa escalar para um público X — aqui pensando é claro que queremos que o software prospere. Quanto mais usuários maior será a carga em cima do sistema e com isso seus componentes precisam ser muito bem pensados e executados para que o software possa escalar de forma "fácil" e gradual. Uma arquitetura limpa e com bons fundamentos podem tornar o desenvolvimento, monitoramento e evolução muito mais fáceis, bem como a manutenção/correção de bugs que sempre irão existir.

  • Melhora do delivery: Indepdente se é um produto de software, app, site, blog ou o que for sempre vai existir a entrega de uma nova versão. E uma boa arquitetura vai ajudar para que essas novas versões que são disponibilizadas para o usuário não acarretem em problemas e que possam ser feitas de forma transparente para os usuários.

  • **Reusabilidade: **O design dos componentes da arquitetura pode tornar o seu reuso fácil ou caótico. Dependendo de como foi projeto a geração de código é tão grande e mal elaborada que torna inviável ou desaconselhável o reuso de algo. Por isso que a reusabilidade deve ser muito bem pensada. Quanto maior o desenvolvimento maior vai ser o custo e tempo envolvido e isso pode ser um gargalo na evolução do software.

Atraso nas entregas

Quando temos um software com vários crufts isso vai aumentar o tempo para o desenvolvimento e vai impactar diretamente na qualidade do software e sem sombra de dúvidas tornar o cliente insatisfeito devido aos atrasos (que vão ocorrer) para a entrega de novas funcionalidades. E o pior do que isso é inconsitências de como o software é atualmente e como ele deveria ser

Aqui está uma imagem retira do site do Martin Fowler onde ele descreve crufts (basicamente problemas no sistema) na entrega de uma feature (funcionalidade).

Quanto maior o número de crufts mais caro torna-se a evolução do sistema e disponibilização de novas funcionalidades.

Um grande diferencial aqui é que podemos separar os times de desenvolvimento em duas categorias:

1 — Com muitos crufts no sistema

2 — Com alguns crufts no sistema

Sempre vão existir débitos técnicos e comportamentos errados, a real diferença é a quantidade e como isso afeta o usuário.

Abaixo um gráfico representado o custo do ciclo de vida.

Reparem que quanto menos é investido em detalhamento do seu design, produção, definições e planejamento de software mais rápido ele pode iniciar e por um breve momento até parecer que as coisas vão bem e até mesmo rápidas, mas com o passar do tempo o custo para alterações no design vão se tornar muito caras e com isso novas features serão cada mais lentas, chegando muita das vezes a um sistema com apenas sustentação devido a dificuldade de alterações.

O contrário é verdadeiro, quanto maior o investimento inicial em planejamento, arquitetura, conceitos de design e detalhamentos o custo inicial vai ser maior mas as manutenções e evoluções serão muito mais rápidas, eficientes e confiáveis.

Saiba mais em: https://martinfowler.com/articles/is-quality-worth-cost.html

Software com alta qualidade é mais barato de produzir

Padrões comuns de Arquitetura de Software

Uma boa arquitetura precisa utilziar padrões de desenvolvimento e principalmente identificar qual arquitetura é a mais adequada para o seu problema/negócio.

Existem hoje N formas de desenvolver um sistema, bem como suas arquiteturas, mas pense sempre na mais simples e que de fato irá resolver o seu problema, não a mais legal do momento.

Abaixo listo alguns padrões que são comuns para o desenvolvimento de uma arquitetura de software.

Microservices

Este padrão de arquitetura visa a criação de serviços que funcionem de forma independente. É muito comum a existência de um monolito de software (basicamente serviços interligados que caso ocorra algum problema em algum ponto da aplicação tudo para de funcionar) e os microserviços pregam justamente a separação em cadamas para que cada entidade funcione de forma isolada. Com isso caso ocorra algum problema em um dos serviços os demais continuarão operando normalmente.

Imagine que um um serviço de login esteja com problema, usuários que estejam logados em um sistema de e-commerce podem continuar navegando normalmente, inclusive realizando compras. Caso fosse um monolito isso não seria verdade.

Com essa separação em camadas podemos separar o desenvolvimento de software / tests e etc em vários times/jornadas.

https://www.redhat.com/architect/5-essential-patterns-software-architecture#microservices

Event Sourcing

Neste padrão componentes são totalmente desacoplados e cada componente possui sua forma de indentificação, processos, responsabilidades e seus eventos

Basicamente existe um componente A que dispara um evento onde vão existir um ou mais componentes que estarão ouvindo o evento do componente A.

Imagine que um componente de customer dispara um evento de customer:created e com isso outro módulo que está escutando esta alteração pode realizar algum processo/chamada, como o disparo de um e-mail.

Comumente esta arquitetura possui mediadores que produzem o evento e geram a sua assinatura para que outros pontos do sistema possam consumí-lo.

Arquitetura comumente utilizada em aplicativos e permite alta escalabilidade.

https://www.redhat.com/architect/14-software-architecture-patterns

Layers Pattern

Provavelmente um dos padrões mais utilizados no desenvolvimento de software. Este padrão basicamente divide o código em layers (camadas) onde cada camada possui sua responsabilidade e realiza as chamadas por serviços para as próximas camadas.

Nesse formato temos componentes estruturados que irão se responsabilizar com as próximas chamadas, criando um fluxo contínuo de regras.

https://www.redhat.com/architect/14-software-architecture-patterns

Micro Front-end

https://martinfowler.com/articles/micro-frontends.html

O termo Micro Frontends apareceu pela primeira vez em ThoughtWorks Technology Radar que finalizou em 2016. Extendendo os conceitos de micro services ao fundo do frontend. A tendência atual é para construir uma funcionalidade rica e poderosa aplicação para navegadores, também conhecida como “single page app (aplicação de página única)”, que fica no topo de uma arquitetura de micro serviços. Com o tempo a camada de frontend, frequentemente desenvolvida por uma equipe separada, cresce e possui uma maior dificuldade para manter. Isso é o que chamamos de Frontend Monolith.

A ideia por trás de Micro Frontends é pensar como um website ou aplicação web uma composição de funcionalidades que são propriedades de equipes independentes. Cada equipe tem uma distinta área de negócios ou missão do qual se preocupam em especializar-se. Uma equipe é cross functional e desenvolvem suas funcionalidades fim-a-fim, desde o banco de dados até a interface para o usuário.

Referência: https://tautorn.github.io/micro-frontends/

MVC

https://www.redhat.com/architect/14-software-architecture-patterns

Padrão que divide a aplicação em 3 components ou camadas. O model contém dados da aplicação e principais funcionalidades. A view apresenta os dados e interações com o usuário (a tela que o usuário visualiza). O controller realiza a mediação o model e a view de acordo com as iterações do usuário. Este padrão permite a utilização de várias views mas a abstração das camadas aumenta a complexiadade e dificulta a escala.

Serverless

https://www.ideamotive.co/blog/software-architecture-design-best-practices-you-should-know

Arquitetura utilizando serverless é um modelo de desenvolvimento na nuvem, onde não é necessário criação e configuração de servidores. Este é um padrão de cloud computing onde o provedor do serviço é responsável por gerenciar a infraestrura (como AWS, GCP, Azure) e por escalar as aplicações. As aplicações são implantadas em containers e que são iniciados sob demanda, de acordo com a utilização das funções criadas. Este modelo é comumente chamado de IaaS (Infrastructure as a Service).

Em termos simples, a arquitetura serverless é uma solução que permite a criação de uma aplicação onde os desenvolvedores podem criar eficientes ambientes em cloud com todos os recursos computacionais necessário em seu processo de desemvolvimento, isso sem se preocupar com infraestrutura e gerenciamento/escala de máquinas.

Este é o padrão utilizado pela Base39, quase 100% dos nossos serviços hoje utilizam arquitetura com Serveless, podendo assim o time se preocupar com o desenvolvimento das aplicações.

É claro que neste padrão é necessário Patterns de desenvolvimento, como Clean Architecture, DDD ou outro padrão que melhor se encaixar nos desafios do projeto.

Existem inúmeros outros padrões de desenvolvimento/arquitetura, listei acima alguns que são bastante comuns.

Visualize seu design

Antes de iniciar a codificar é importante que o time tenha o design em mente, rabisque, pense nos requisitos funcionais e não funcionais, crie protótipos, modelo de dados e etc. Esse modelo é muito mais barato e fornece uma visão mais clara de como a arquitetura irá funcionar e como cada componente vai interagir e comunicar com os demais.

Dessa forma é possível evitar furos arquiteturais e trabalhar com o que de fato é necessário para iniciar o projeto, pensando é claro sempre na escala e evoluções futuras.

Boas práticas para criação do design do Software

É bem difícil determinar o que é uma boa arquitetura porque existem várias maneiras de resolver o mesmo problema e com isso é possível aplicar várias arquiteturas, é claro que dependendo do caminho ele pode ser mais trabalhoso e ter um custo maior.

De todo jeito, para desenvolver uma boa arquitetura é sempre bom levar em consideração algumas boas práticas e eu gosto sempre de realizar algumas "perguntas" para identificar se estou no caminho certo, como:

  • O software precisa ser de fácil manutenção;

  • Precisa ser escalável e confiável;

  • Fácil de refatorar;

  • Fácil de se adaptar aos requisitos que vão surgindo ao longo do desenvolvimento e após entrega da aplicação;

  • Possuir alta performance e rápida execução;

  • Funcionar de fato como foi concebido;

  • A arquitetura deve ser resiliente e fácil de encontrar e resolver bugs;

  • O time precisa ter domínio das tecnologias empregadas;

  • O código não deve possui repetições;

  • A arquitetura deve responder bem a alterações sem que performance e qualidade caiam.

Somente olhar para o produto/projeto não vai ser simplesmente possível identificar uma boa arquitetura mas olhando como o produto funciona é possível capturar sinais de como as coisas foram feitas. Esses "sinais" são alguns dos itens acima listados.

Problemas que má decisões podem levar

https://www.monkeyuser.com/

Existem vários erros que são comuns no desenvolvimento de uma arquitetura de software e isso pode ser a ruína do projeto/produto e até mesmo da empresa!

Dependendo de como as coisas foram pensadas, desenvolvidas e evoluídas a manutenção do software pode ser um fator muito crítico.

Ao longo da minha carreira presenciei inúmeros projetos que eram incrivelmente caros do ponto de vista custo/benefício/tempo, um simples alteração ou correção levava dias. E isso é bem comum de acordo com a evolução do projeto, devido a falhas de concepção e correrias do dia-a-dia e pressão para "entregar valor para o usuário" boas práticas e padrões arquiteturias podem simplesmente serem ignorados ou removidos. Abaixo listei alguns erros comuns:

  • Definicação do problema incorretamente;

  • Falta de documentação;

  • Não pensar na escala da aplicação (aqui não precisa pensar como será o projeto daqui 10 anos, pode ser que nem exista mais, mas é necessário entender o nível de escala e pensar como será o seu comportamento futuro;

  • Não obter feedback cedo: Muitos projetos demoram para irem para produção, o time passa meses desenvolvendo e quando vai para produção acaba frustando o usuário. Isso é muito comum também devido o levantamento de requisitos e planejamento do projeto, não só de software. Muita das vezes a equipe como um todo acredita que deve lançar uma big feature e gasta muito esforço para validar se de fato vai causar impacto para o usuário.

  • Exceço de complicação: Este é um dos exemplos mais comuns. Adicionar muitas tecnoligas, padrões arquiteturais, "boas práticas", termos complexo e muito mais, tudo isso pode parecer um software bastante robusto mas isso só tenta esconder uma falta de conhecimento e propósito. Tonar algo complexo não o torna bom, somente complexo. Opte sempre por deixar tudo o mais simples possível, um software que vai escalar é algo simples no limite das suas necessidades e padrões. Deixe para testar aquela tecnologia nova em casa :)

  • Não manter as tecnologias atualizadas: Muitos times foca somente em novas demandas, features e etc e acabam deixando as tecnologias desatualizadas, causando um grande problema futuro. Este item é como uma pia de louças sujas, o time pode ir postergando mas um belo dia ele vai ter que parar e lavar as louças; porque não é possível evoluir mais o projeto e bugs estão surgindo em todos os cantos. Isso também pode levar a risco de seguranças.

Existem inúmeros outros erros comuns mas eu quis trazer alguns que são notórios.

Caso de uso utilizando Edge API

Na Base39 temos inúmeros projetos e aplicações e tínhamos um problema de compartilhamento de serviços entre aplicações onde regras específicas eram geradas para cada sistema, tornando a lógica, segurança e manutenção difíceis de serem gerenciados. A evolução das apis também eram um problema, uma vez que uma simples alteração em um serviço para uma aplicação podia gerar um efeito coleteral em outro sistema independente.

Para solucionar esse problemas criamos camadas de Edge Api ou Back for Front (BFF) da Base39 para solucionar o problema de desenvolvimento de apis ligadas diretamente com o front-end, permitindo assim que cada aplicação tenha as suas próprias regras.

As Edge Apis foram criadas para que seja possível desenvolver uma layer de BFF para que todas as regras que a aplicação precise sejam desenvolvidas nela sem a necessidade de criação de novas Apis que retornem contratos de acordo com as suas necessidades.

Com o desenvolvimento de novas apis criou-se a necessidade do desenvolvimento de um BFF onde cada aplicação pode desenvolver/utilizar sua própria layer customizada, possuindo assim próprias regras de negócios sem o risco de quebrar contratos das apis existentes. O consumo de cada api é através de métodos HTTP que são chamados pelo BFF do qual contém todos os types e resolvers para transformar os dados que são retornados pelas apis.

Para isso, foram utilizados recursos da AWS, como: Lambda e AppSync. Essas ferramentas são responsáveis pela criação e disponibilização de um serviço com GraphQL para retornar o contrato que a aplicação necessita, sem a necessidade de disponibilizar informações a mais ou a menos.

Desenho arquitetural:

São 4 camadas para que a aplicação opere conforme o esperado:

1 — Client layer, contendo todas aplicações que acessam as plataformas da Base39 por meio de dispositivos mobile ou aplicações Web;

2 — Camada de BFF, responsável por criação de types e resolvers e chamadas HTTP em uma Api Gateway configurado;

3 — Api Gateway com o map config das rotas;

4 — Disponibilização de serviços como EC2, Lambda, Dynamo, Mongo e etc.

O fluxo abaixo representa a criação de n BFFs para representar cada cliente, onde os mesmos podem coexistir com suas próprias regras.

Para clientes que trabalham com o formato SaaS, pode ser criado apenas um BFF onde o mesmo irá prover toda infraestrutura e regras necessárias para o seu desenvolvimento e operação. Para clientes que irão operar contendo um BFF próprio, vale salientar que a camada de retorno em cada BFF deverá ser feito de acordo com sua aplicação. Caso esta seja disponibilizada pela Base39 a mesma deverá ser feita equivalente entre todos clientes SaaS.

Caso seja um cliente Enterprise e o mesmo deseje que disponibilizemos um BFF próprio, este poderá ser espelho de algum BFF existente ou simplesmente deverá ser realizada a criação de uma nova aplicação retornando um contrato único para que o cliente possa utilizar em seu escopo, porém deverá ser o controlador único desta aplicação, podendo ou não sofrer alterações somente se o cliente solicitar, independente da evolução dos produtos da Base39 que podem coexistir com aplicações e contratos de apis iguais, mas com uma camada de resolver única caso esta seja necessária.

Sobre a distribuição

Todo o desenvolvimento do BFF segue utilizando o AppSync, onde o mesmo disponibiliza um endpoint graphql contendo todas as queries, mutations e resolvers para a aplicação. A publicação dos recursos na AWS é realizada através do CDK.

Apis distribuídas

As apis que este projeto utiliza foram disponibilizadas no Portal do desenvolvedor da Base39.

Estas apis possuem suas próprias regras e camadas de segurança/controle de acessos e governança, possibilitando que o cliente opere elas através de uma api-key que autorize as ações nos serviços.

Sobre o banco de dados

Cada cliente SaaS opera com seu próprio cluster de dados, criando assim uma separação física através de um banco de dados que fica hospedado em uma Cloude que é acessado através da plataforma de Multi-Tenant disponibilizada pela base39

“If you think good architecture is expensive, try bad architecture” — Brian Foote e Joseph Yoder’s

Acima um pedaço do desenho arquitetural e como as camadas de BFF resolveram um problema de comunicação entre aplicações distintas realizando chamadas em apis comuns.

Conclusão

O desenvolvimento de uma boa arquitetura de software não é algo fácil e isso é a base de qualquer aplicação de software e como já disse anteriormente escolhas ruins podem levar o projeto a ruína. Por isso deve-se tomar muito cuidado com cada arquitetura, com cada projeto e com o tempo para desenvolvê-lo, leve sempre em consideração estimativas, entregas, alinhamento com stakeholders, com o time e como a arquitetura vai permitir um bom funcionamento da aplicação e permitir a resolução de um determinado problema.

Este é um assunto muito abrangente e listei aqui apenas alguns exemplos, boas práticas e um case que foi desenvolvido na Base39.

Gaste sempre tempo planejando e pensando em como a arquitetura vai funcionar, tente sempre deixá-la o mais simples possível e não caia na armadilha de sair entregando algo rápido e sem pensar direito achando que débitos técnicos poderão ser resolvidos facilmente no futuro. Uma boa arquitetura de software é mais barata do que escolhas ruins.

Referências