Fundamentos para arquiteturas baseadas em serviços

Este capítulo possui uma versão mais recente:

Você não pode comandar uma companhia pelo medo, porque a forma de eliminar o medo é evitar críticas. E a forma de evitar as críticas é não fazer coisa alguma.
Steve Ross
A arquitetura de um software, muito além dos aspectos técnicos, impacta na dinâmica de trabalho das equipes que o desenvolvem. Boas arquiteturas minimizam os esforços de coordenação e sincronização entre pessoas e times, colaborando para lead times menores, sem comprometer a qualidade interna.
0
Você concorda?x

Importante ter clareza que mesmo arquiteturas modulares, se inadequadamente planejadas, não autorizam trabalho paralelo. Arquiteturas tecnicamente particionadas, por exemplo, são mais restritivas do que aquelas particionadas por características do domínio. 

Em arquiteturas tecnicamente particionadas, quando há um time dedicado para cada componente técnico, todos os limites de componentes se convertem em “pontos de coordenação”. O impacto mais perceptível ocorre na ampliação dos lead-times.

Ainda em arquiteturas tecnicamente particionadas, quando os times são organizados por features, há “difusão de responsabilidade” e queda da qualidade interna que ocasiona, também, no longo prazo, prejuízo de lead-time.

Sistemas com arquiteturas particionadas tecnicamente, como em implementações mais simples do estilo em camadas, são adequadas para times pequenos, com no máximo 15 pessoas. Em times maiores, arquiteturas precisam ser particionadas pelo domínio para serem sustentáveis. Essa é uma das justificativas para desenvolver arquiteturas baseadas em serviços.
0
Você concorda?x

Domain-driven Design

Eric Evans escreveu, em 2003, o livro ‘Domain-driven Design‘. Trata-se de uma formalização de práticas e padrões para, segundo o autor, atacara complexidade no coração do software.

Um dos fundamentos de Domain-driven Design é identificar, dentro de um determinado domínio de negócio, subdomínios que, mais tarde, são modelados em contextos delimitados. Na modelagem de sistemas da forma como apresentamos aqui, cada contexto delimitado pode ser “implementado” como um serviço 

Difusão de responsabilidade

Desenvolver software é um “esporte coletivo” e qualquer atividade em grupo tem demandas de coordenação. Quanto mais desenvolvedores tocam am um trecho de código, maiores são as chances de que este código tenha defeitos e, além disso, maiores são os custos operacionais de gestão. Quanto maior o número de envolvidos, mais importantes, frequentes e custosas são atividades de comunicação e de coordenação. Analogamente, mais difusa é a responsabilidade pela qualidade.
0
Você concorda?x

De forma objetiva, um bom proxy para a difusão de responsabilidade pode ser obtido pela concentração de contribuições (commits) de diversos autores em um determinado artefato, como indicado na fórmula abaixo:

Na fórmula ai se refere a cada autor individualmente, nc(ai)  é o número de contribuições para um determinado autor e, finalmente, NC é o número total de contribuições. Artefatos mantidos por um único autor tem difusão de responsabilidade zerada.

Git como 'rede social'

Ferramentas modernas de controle de versão são frequentemente usadas apenas como mecanismos sofisticados de backup de código-fonte. Entretanto, podem ser bem mais do que isso.


O Git, por exemplo, consegue apontar arquivos que são modificados com mais frequência, colaboradores mais ativos, além, é claro, parâmetros para cálculo da difusão de responsabilidade. A instrução 'git shortlog -s', por exemplo, relaciona a quantidade de commits , por desenvolvedor, em uma determinada pasta.

Artefatos com indicadores altos de difusão de responsabilidade geralmente apresentam qualidade interna mais baixa. A regra geral predominante parece ser “o que é responsabilidade de todos, não é de ninguém”. No fim, adaptações acabam sendo implantadas de maneira descuidada causando problemas em produção.

Curiosamente, artefatos com maior difusão de responsabilidade costumam ser, também, aqueles que tem maior acoplamento eferente e que, por isso, quebram com mais facilidade, ou com maior acoplamento aferente, com potencial para gerar prejuízos maiores no sistema, caso apresentem defeito.
0
Concorda?x

Arquiteturas particionadas por domínio tendem a ter artefatos com difusão de responsabilidade mais baixa. Artefatos com difusão de responsabilidade mais baixa tendem a ser mais fáceis de manter e evoluir, o que converte essa métrica em uma boa fitness function.
0
Você concorda?x

Propriedade sobre artefatos

A atribuição de “propriedade” para artefatos de um software – como documentação, código, banco de dados, etc – é um tema controverso. Muitas pessoas associam “propriedade” como justificativa para redução da colaboração ou, pior ainda, formação de silos. Entretanto, esse não é o ponto! A atribuição de “propriedade” é uma medida para tentar minimizar os efeitos da difusão de responsabilidades. 

Atribuir “propriedade” de artefatos a times ou indivíduos é similar a iniciativa de atribuir mantenedores para projetos open source. Ou seja, determinar responsabilidade pela qualidade atual e futura de um artefato para alguém que irá o “zelar e protejer”.

A “propriedade” de artefatos não é uma maneira de coibir contribuições, muito pelo contrário, é um incentivo para participação ativa. Cabe aos “proprietários” arbitrar, apenas, que contribuições estão prontas para serem aceitas.

Particionando a “camada de negócio” em serviços

A evolução dos modelos de operação e distribuição de software, associado com o desenvolvimento de técnicas mais apropriadas de análise de domínios de negócios, autorizaram a decomposição das tradicionais “camadas de negócios” em contextos delimitados, distribuídos como serviços.

Nesse modelo, os serviços são desenvolvidos e distribuídos de forma “quase independente”, exceto por serem todos acoplados a um único banco de dados monolítico.

Os serviços, individualmente, tendem a ter difusão de responsabilidade mais baixa, enquanto o banco de dados e a interface com usuário, além de acoplamento aferente e eferente maiores, tendem a ter difusão de responsabilidade mais alta. Nesses cenários, não é incomum que a base de dados (e a interface com o usuário) passem a ter controle direto de um time especialista, com “senso de propriedade” suficiente para manter, via burocracia, qualidade interna mais alta.
0
Você concorda?x

Para serem viáveis, tais arquiteturas são constituídas por poucos serviços. Geralmente, não menos do que 4 e não mais do que 12.

O problema com 'Kernel Compartilhado'

Domain-driven Design autoriza a identificação e implementação de kernels compartilhados: parte do modelo de domínio de uso comum para dois ou mais contextos delimitados. Entretanto, antes de solução, este tipo de artefato representa problema.

Kernels compartilhados são naturalmente acoplados (de maneira aferente) e nascem com difusão de responsabilidade alta. Eventualmente, representam redução dos custos de desenvolvimento, mas, seguramente, representam acréscimo no custo de manutenção.
0
Concorda?x

Particionando a “interface com o usuário”

Uma forma de reduzir os impactos do aumento crescente do acoplamento eferente na interface com o usuário é particioná-la também, reduzindo indiretamente os riscos de difusão de responsabilidade.

Não é raro que diferentes perfis de usuários demandem e valorizem características diferentes de usabilidade. Por exemplo, enquanto vendedores tendem a valorizar simplicidade e objetividade, analistas financeiros geralmente gostam dor maior volume de informações concentrado (com menos espaços em branco). Por isso, antes de ser um problema, o particionamento da interface pode ser uma “solução” para a inclusão de adaptações, com coesão de padrões de projeto de UX.
0
Você concorda?x

O particionamento da interface com o usuário geralmente segue os mesmos critérios de domínio aplicados nos serviços na “camada de negócios”.

A “emergência” das APIs externas

Eventualmente, serviços internos irão interagir diretamente com sistemas de terceiros que irão oferecer uma “interface alternativa” para alguns “serviços de negócios” de um software. Nesses casos, pode ser uma boa ideia oferecer um serviço específico para atender às demandas desse serviço externo, reduzindo acoplamento eferente externo (e as chances de quebra).
0
Você concorda?x

Prover uma API externa também é um bom caminho para reduzir a difusão de responsabilidade de integrações críticas e proteger o negócio.

A “emergência” de uma camada de API (gateway ou proxy)

Caso exista necessidade crescente de fazer acesso externo aos serviços de domínio, além da API externa, é uma boa prática adicionar uma camada com um proxy reverso ou gateway.

O gateway reduz o acoplamento aferente dos serviços e também é um bom mecanismo para consolidar demandas por métricas, segurança, bilhetagem, auditoria e descoberta.

Particionando logicamente o “banco de dados”

A decomposição da “camada de negócios” em serviços e da “camada de interface” em experiências independentes, implicam no aumento do acoplamento aferente do banco de dados, o que é um problema em potencial, mesmo com o número reduzido de serviços (geralmente, 7 em arquiteturas assim). Se não forem feitas de maneira apropriada, alterações de esquema podem causar problemas nos diversos serviços, o que aumenta bastante a necessidade de coordenação.
0
Você concorda?x

Uma saída rápida, costuma ser prover um componente com modelo de persistência para ser utilizado nos diversos serviços, suficiente para causar falhas no build quando alterações de esquema forem realizadas. O versionamento do modelo de persistência é fiel a evolução do esquema.

Em seguida, uma boa ideia é recorrer a mecanismos para particionar logicamente o banco de dados criando modelos de persistência decompostos pelos diferentes contextos delimitados. Modernamente, recursos como particionamento vertical, permitem a administração de bases de maneira inteligente, melhorando a performance.

O particionamento vertical, eventualmente, demandará um componentes com modelos de persistência também particionados para serem utilizados nos diversos serviços, suficientes para causar falhas no build quando alterações de esquema forem realizadas. O versionamento do modelo de persistência é fiel a evolução do esquema.

Particionando fisicamente o “banco de dados”

Eventualmente, há possibilidades para particionar um banco de dados monolítico em instâncias independentes, alinhadas ao domínio, de forma semelhante ao que ocorre com microsserviços.

O ponto importante, aqui, é garantir que cada banco de dados não seja necessário para outros serviços e, também, duplicação de dados, exceto quando isso for natural. Excepcionalmente, o particionamento das bases de dados pode ser justificada por problemas de performance.
0
Concorda com isso?x

Conway, outra vez!

O particionamento pelo domínio permite a organização dos times em torno de componentes coesos, com baixa difusão de responsabilidade.

Em primeira análise, cada serviço pode ser mantido por um time independente, que é “consumido” pelo time que elabora a interface e “consome” um time de DBAs responsável pelo banco de dados. Eventulamente, o time de banco de dados pode ser também particionado conforme o serviço, bem como a interface.

Indicações e contraindicações

A abordagem arquitetural disposta nesse capítulo destaca-se pelo pragmatismo. Embora, como arquitetura distribuída, a decomposição em poucos serviços seja menos “ambiciosa” do que abordagens mais extremas, como microsserviços, trata-se de um modelo “mais fácil de pagar”.
0
Você concorda?x

A decomposição por contextos tem fit natural com análises baseadas em Domain-driven Design. Além disso, a “tolerância” a um banco de dados monolítico autoriza transações ACID.
0
Você concorda?x

Particionar componentes, em última instância, demanda times particionados. Por isso, essa abordagem não é apropriada para times pequenos ou monolíticos. Assumindo, aliás, que o tamanho ideal de times de tecnologia é de 7 pessoas e que haverá um time para cada serviço, podemos inferir que este estilo arquitetural funciona bem para equipes de até 100 pessoas.
0
Você concorda?x

// TODO

Antes de avançar para o próximo capítulo, recomendo as seguintes reflexões:

  • Você conseguiria decompor seu sistema em contextos delimitados claros e independentes?
  • Quais seriam as dificuldades e facilidades para particionamento da base de dados (lógico ou físico)?

 

Referências bibliográficas

CATALDO, Marcelo; HERBSLEB, James D.. Coordination Breakdowns and Their Impact on Development Productivity and Software Failures. IEEE Transactions On Software Engineering, [s. l], v. 3, p. 343-360, nov. 2013.

EVANS, Eric. Domain-driven Design: tackling complexity in the heart of software. Boston, Ma: Addison-Wesley, 2002.

FLETCHER, Matt. Service-Based Architecture as an Alternative to Microservice Architecture. 2016. Disponível em: https://www.infoq.com/news/2016/10/service-based-architecture/. Acesso em: 25 maio 2021

NAGAPPAN, Nachiappan; MURPHY, Brendan; BASILI, Victor; NAGAPPAN, Nachi. The Influence of Organizational Structure on Software Quality: an empirical case study. International Conference Of Software Engineering, Proceedings, Leipzig, Germany., p. 521-530, jan. 2008.

BIRD, Christian; NAGAPPAN, Nachi; MURPHY, Brendan; GALL, Harald; DEVANBU, Premkumar. Don’t Touch My Code! Examining the Effects of Ownership on Software Quality. ACM SIGSOFT Symposium on The Foundations of Software Engineering, Szeged, Hungary, p. 4-14, set. 2011.

RICHARDS, Mark; FORD, Neal. Fundamentals of Software Architecture: an engineering approach. Sebastopol, Ca: O’Reilly Media, Inc, 2020.

Compartilhe este capítulo:

Compartilhe:

Comentários

Participe da construção deste capítulo deixando seu comentário:

Inscrever-se
Notify of
guest
0 Comentários
Feedbacks interativos
Ver todos os comentários

Fundador e CEO da EximiaCo, atua como tech trusted advisor ajudando diversas empresas a gerar mais resultados através da tecnologia.

Mentoria

para arquitetos de software

Imersão, em grupo, supervisionada por Elemar Júnior, onde serão discutidos tópicos avançados de arquitetura de software, extraídos de cenários reais, com ênfase em systems design.

Consultoria e Assessoria em

Arquitetura de Software

EximiaCo oferece a alocação de um Arquiteto de Software em sua empresa para orientar seu time no uso das melhores práticas de arquitetura para projetar a evolução consistente de suas aplicações.

ElemarJúnior

Fundador e CEO da EximiaCo, atua como tech trusted advisor ajudando diversas empresas a gerar mais resultados através da tecnologia.

+55 51 99942-0609 |  contato@eximia.co

+55 51 99942-0609  contato@eximia.co

0
Quero saber a sua opinião, deixe seu comentáriox
()
x