Desenvolvimento

22 mai, 2017

Rumo a uma verdadeira integração contínua: repositórios e dependências distribuídos

Publicidade

A arquitetura de microsserviços da Netflix, baseada na AWS, desacopla equipes de engenharia umas das outras, permitindo que elas criem, testem e implantem seus serviços quantas vezes acharem necessário. Tal flexibilidade permite que as equipes maximizem sua velocidade de entrega.

Os microsserviços da Netflix fornecem a seus consumidores uma biblioteca cliente que suporta toda a lógica do IPC. Isso fornece uma série de benefícios tanto para o proprietário do serviço quanto para os consumidores. Além do consumo de bibliotecas cliente, a maioria dos microsserviços é construída em cima de um framework de plataforma de tempo de execução, que é composto de bibliotecas internas e de código aberto.

Se por um lado as equipes de serviço têm a flexibilidade de liberar como quiserem, sua velocidade pode muitas vezes ser dificultada por atualizações para qualquer uma das bibliotecas de que dependem. Um recurso do produto utilizado pode exigir vários microsserviços para pegar a versão mais recente de uma biblioteca compartilhada ou biblioteca cliente. Desta maneira, a atualização de versões de dependência traz riscos.

Segundo a própria Netflix, “gerenciar dependências é difícil”.

Todos já passamos por isso, e sabemos que atualizar dependências do seu projeto pode significar uma série de problemas potenciais, incluindo:

  • Quebrando as alterações da API – Este é o melhor cenário. Uma falha de compilação que quebra sua compilação. A versão semântica combinada com o bloqueio de dependência e os seletores de versão dinâmicos devem ser suficientes para que a maioria das equipes evite que isso aconteça, assumindo o rigor cultural em torno do semver. No entanto, uma versão principal bloqueada torna muito mais difícil atualizar a base de código da empresa, levando a manutenção prolongada de bibliotecas antigas e drift de configuração.
  • Atualizações de dependência transitiva – Devido ao classpath da JVM, somente uma única versão de uma classe pode existir em um aplicativo. Ferramentas de criação como Gradle e Maven lidam com a resolução de conflitos de versão impedindo que várias versões da mesma biblioteca sejam incluídas. Isso também significa que temos um problema, pois agora há código dentro de seu aplicativo que está sendo executado com uma versão de dependência transitiva a qual nunca foi colocada à prova.
  • Quebrando alterações funcionais – É tido como o melhor dos mundos, visto que é atenuado por testes adequados. Idealmente, os proprietários de biblioteca são capazes de executar os testes de contrato do consumidor para entender a funcionalidade que se espera deles.

Com o intuito de entender e ser capaz de enfrentar os desafios de gerenciar dependências em escala, a Netflix vem observando e diz ter visto empresas se movendo em direção a duas abordagens: compartilhe pouco e monorepos.

  • A abordagem compartilhe pouco (ou não use bibliotecas compartilhadas) tem sido recentemente popularizada pelo movimento de microsserviço mais amplo. Ela afirma que nenhum código deve ser compartilhado entre microsserviços. Os serviços só devem ser acoplados através de suas APIs HTTP. Algumas recomendações chegam mesmo a dizer que copiar e colar é preferível para compartilhar bibliotecas. Esta é uma abordagem de desacoplamento extrema.
  • A abordagem monorepo determina que todo o código-fonte para a organização vive em um único repositório de origem. Qualquer alteração de código deve ser compilada/testada contra tudo no repositório antes de ser enviada para HEAD. Não há versões de bibliotecas internas, apenas o que está em HEAD. Os compromissos são fechados antes de chegarem à HEAD. As versões de biblioteca de terceiros geralmente são limitadas a uma de duas versões “aprovadas”.

Enquanto ambas as abordagens tratam os problemas de gestão das dependências em escala, elas também impõem certos desafios. A abordagem de compartilhar pouco favorece a velocidade de desacoplamento e engenharia, ao mesmo tempo em que sacrifica a reutilização e a consistência do código.

Por outro lado, a abordagem monorepo favorece a consistência e a redução de risco, ao mesmo tempo em que sacrifica a liberdade ao exigir que as portas implementem alterações.

A adoção de uma ou outra abordagem implicaria mudanças significativas na infraestrutura de desenvolvimento e na arquitetura de tempo de execução da Netflix. Além disso, ambas as soluções vão de encontro a sua cultura de Liberdade e Responsabilidade.

Sendo assim, eles se impuseram o seguinte desafio:

“Podemos fornecer aos engenheiros da Netflix os benefícios de uma monorepo e ainda manter a flexibilidade dos repositórios distribuídos?”

Usando a monorepo como sua especificação de requisitos, foi possível explorar abordagens alternativas para alcançar os mesmos benefícios. Baseados nos objetivos de uma monorepo, sua abordagem, embora experimental, pode ser separada em três características-chave:

  • Feedback do editor – fornecer ao proprietário do código compartilhado rápido feedback sobre qual dos seus consumidores acabou de quebrar, tanto direto quanto transitivo. Além disso, deve permitir que as equipes bloqueiem lançamentos baseados em quebras de downstream. Atualmente, sua cultura de engenharia coloca responsabilidade exclusiva nos consumidores para resolverem esses problemas. Assim, ao dar aos proprietários de biblioteca um feedback sobre o impacto que eles têm para o resto da Netflix, eles esperam que uma responsabilidade adicional seja assumida.
  • Fonte gerenciada – fornecer aos consumidores um meio para incrementar com segurança as versões da biblioteca automaticamente, à medida que novas versões são lançadas. Uma vez que eles já estão testando novas versões da biblioteca contra todos os downstreams, por que não colidir versões de consumidor e acelerar a adoção de versão, com segurança.
  • Refatoração distribuída – fornecer aos proprietários de código compartilhado um meio para encontrar rapidamente e refatorar globalmente os consumidores de sua API. Este processo foi iniciado por pull requests em massa para todos os repositórios Git que contêm um consumidor de uma determinada API Java.

Este é apenas o início da jornada da Netflix. Seu serviço de feedback do editor está sendo testado em alfa por um número de equipes de serviço e eles planejam ampliar a sua adoção em breve juntamente com a fonte gerenciada. Suas experiências iniciais com refatoração distribuída ajudaram a entender como melhor alterar rapidamente o código globalmente. Eles também observaram uma oportunidade para reduzir o tamanho do gráfico de dependência global, alavancando as ferramentas que foram construídas neste espaço.

Assim, a Netflix acredita que expandir e cultivar essa capacidade permitirá que suas equipes consigam alcançar uma verdadeira integração contínua em toda a organização e reduzir, se não eliminar, a dor do gerenciamento de dependências.

***

Fonte: https://medium.com/netflix-techblog/towards-true-continuous-integration-distributed-repositories-and-dependencies-2a2e3108c051