As ferramentas do repositório são estruturantes para a execução de nossos processos de desenvolvimento. No entanto, certas tipologias são, às vezes, esquecidas.
Como engenheiros, costumamos gostar de ferramentas. Podemos ter a tendência de perder de vista seus objetivos e sua contribuição para a organização. O repositório é central em nossos fluxos de desenvolvimento, oferecendo suporte à experimentação e a criação de valor.
A nossa missão é, portanto, de construir um sistema eficiente a serviço do negócio através de nossa abordagem de Quality Engineering. Devemos equilibrar a produtividade de hoje e amanhã com a complexidade e escalabilidade das ferramentas integradas.
Este artigo cobre os tipos de ferramentas necessárias para suportar produtividade e gestão da dívida técnica. As ferramentas mencionadas não pretendem ser exaustivas ou priorizadas, nem examinamos tópicos de documentação, IDE ou comunicação.
As categorias de ferramentas são ordenadas nas etapas do nosso processo de desenvolvimento. Então, vamos começar pelo armazamento do código no repositório.
Tudo começa com o repositório de código
O primeiro assunto é de armazenar nosso código em um diretório compartilhado, acessível, durável, seguro e extensível. Isso nos parece trivial hoje devido à evolução das plataformas disponíveis e à redução dos custos de armazenamento.
O gerenciador de fontes deve ser capaz de fornecer workspaces, particularmente úteis para um multirepo ou polyrepo. Esses modelos tendem a gerar uma multidão de repositórios que precisam de ser organizados, como uma biblioteca e seus livros.
Para qualquer modelo, ter a funcionalidade de pesquisa de código, projeto e de componentes é necessária. A realização de pesquisas em um grande repositório é, às vezes, suportada por mecanismos de busca específicos de código. Cody, Lerna ou Octolinker são soluções possíveis.
O gerenciamento de acesso será apoiado por uma organização estruturada do repositório. O objetivo não é bloquear o acesso por defeito, vai depender da cultura de engenharia que queremos criar. O objetivo principal é esclarecer as responsabilidades dos diferentes projetos para o resto da cadeia de desenvolvimento.
Devemos ter uma atenção especial ao caso do monorepo. Seu crescimento e centralização criam a necessidade de pesquisas mais rápidas, de fazer o download de projetos afetados apenas, e gerir packages. A Atlassian compartilha as melhores práticas nestes artigos Monorepos no Git e Como lidar com grandes repositórios no Git. A Microsoft também disponibiliza o Rush para gerenciamento de packages.
Num modelo de split-repo, é necessário uma solução para passar de um monorepo para um multirepo antes da build. Split.sh é uma referência. Uma miríade de ferramentas também está disponível para gerir migrações e separação de repositórios : Bazel, Tomono ou esta lista de shopsys.
As equipas podem então começar a contribuir com a base de código.
A gestão de versionamento suportando reviews
O controle de versão é suportado pelo conceito de commits e modelos de branching. O processo, coordenação, e orquestração dos commits é o verdadeiro assunto a tratar.
As práticas de desenvolvimento evoluíram para integrar sistematicamente as revisões por pares. Essa prática requer o suporte de mecanismos de pré-merge, pré-submit ou hooks mais flexíveis. Soluções de CI incorporam Git nativamente suportam esses mecanismos. É possível complementar sua abordagem com Pre-commit.
As revisões de código são eficazes quando combinam processos automatizados e manuais.
A automação deve se concentrar em tarefas repetitivas sem valor agregado para o ser humano. É importante garantir uma governança e inclusão nos processos da equipa para capturar valor. Os padrões também permitirão a replicabilidade, escalabilidade e manutenção das ferramentas implementadas.
SonarQube e Codacy são ferramentas que cumprem essa tarefa. As alternativas apoiam especificamente as revisões, como a Pull Review.
Os processos manuais têm três tipos de execução: manual, híbrido e automático. Alguns processos precisam de iniciativa, realização e controle totalmente humanos. Outros, como as revisões por pares, são híbridos para ter parte do processo automatizado. Alguns processos, mesmo que totalmente automatizados, exigem uma revisão manual regular dos resultados obtidos, como uma IA.
Em seguida, especificamos as ferramentas para construir nossos aplicativos, sem esquecer de gerenciar suas dependências.
Um sistema de construção e gerenciamento de dependências
A construção de nosso aplicativo é a base na vida de nosso software. Seu objetivo é construir os executáveis que serão instalados e executados nos diferentes ambientes. É, portanto, aqui que se materializa a complexidade inerente ao código.
Os monorepos crescam e por isso, precisam de manter o tempo de construção sob controle para permanecerem utilizáveis. Portanto, é necessário ser capaz de compilar e testar apenas as dependências relevantes. Bazel é da Google, Buck da Facebook e Pants da Twitter. Soluções inspiradas do Yarn também estão surgindo, como Baur ou Oao.
O modelo multirepo pode exigir gerenciamento de dependência que dependendem da sua implementação. O uso de bibliotecas compartilhadas criará dependências a serem gerenciadas entre seus diferentes projetos. Uma implementação errada criará dependências cíclicas a serem detectadas por meio de ferramentas de análise estática.
Os bots aparecem para ajudar no gerenciamento de dependências, como o dependabot. Seu uso se concentra principalmente na atualização de versões. Análises mais complexas requerem mais ferramentas, como é o caso da Google.
Assim que nossas dependências forem gerenciadas adequadamente, podemos começar a construir aplicativos. Aqui encontram as tradicionais soluções de Continuous Integration (CI), às vezes específicas para certas tecnologias. Isso inclui Jenkins, Gitlab CI, Azure DevOps, Bitbucket.
Mecanismos de refactoring em escala
Todas as alterações feitas na base do código criarão uma complexidade que deve ser contida. Os mecanismos de revisão por si só não são suficientes, sendo limitados ao prisma de uma única mudança. Portanto, precisamos de ferramentas que tem uma perspectiva mais ampla para abordar o refactoring em escala.
Os humanos podem realizar análises globais em nossa base de código. No entanto, o tamanho, a complexidade e a velocidade das alterações feitas exigem ferramentas de apoio. Imagine o tempo necessário para percorrer manualmente um monorepo inteiro ou 100 repos para identificar áreas de melhoria.
Os players de referência têm investido significativamente nesta problemática, conscientes do risco de endividamento técnico e do abrandamento associado. A Google, por exemplo, criou Rosie que vai até fazer propostas de refactotoring automáticas. Outras soluções estão disponíveis como Turbolift da Skyscanner, Autorefactor ou Dependabot.
A refactoring funcional é a tarefa mais adaptada aos humanos hoje. O contexto de negócios e as possíveis mudanças são difíceis de modelar no momento. Por falar em modelização, os nossos principais objetos combinam análise estática, governança e automação.
Governança das APIs e dos dados
Dados evoluíram como um ativo cada vez mais valioso para as organizações. Para algumas, é a principal razão de sua existência. A consistência dos dados é, portanto, estruturante para poder captar o seu valor.
A aceleração da criação de dados traz à a necessidade de ferramentas. As aplicações estão na origem da criação dos dados, onde os desenvolvedores especificam a estrutura a ser gerada. A multiplicação e distribuição das equipas requerem uma governança para manter uma alinhamento.
Ferramentas surgiram dependendo dos casos de usos. Dicionários de dados são historicamente utilizados para bancos de dados relacionais. Eles são usados para validar a consistência ao build e ao run dos modelos. A produção de dados em modo de eventos está começando a ser suportada pelo gerenciamento de esquema. O ecossistema converge em torno dessa governança de dados e, com sorte, com padrões como asyncAPI.
O próximo passo é seguir em frente com a implantação da aplicação nos diversos ambientes, sem deixar de testar.
Ferramentas de teste integradas em nossa cadeia
O teste é uma parte estruturante de nossa cadeia de entrega para qualquer modelo de repositório. O ponto importante a considerar é sua integração com nosso modelo de organização de código.
A etapa de construção da nossa aplicação deve incluir os testes a serem realizados o mais próximo possível do código. As soluções de CI suportam a execução de testes unitários, de integrações ou outras tipologias executadas dentro da construção do aplicativo. Um monorepo requer uma abordagem de teste específica para permitir verificar apenas os módulos afetados.
De seguida, chegamos aos deploys nos diferentes ambientes. Precisamos ter a capacidade de executar testes a cada etapa da nossa pipeline de CI/CD, também conhecido pelo padrão de quality gates. Em vez disso, outros testes devem estar fora da pipeline, dependendo da organização, como funcional ou de ponta a ponta.
A monitorização, no fim da cadeia, é um tipo de teste que devemos incluir em uma abordagem mais ampla de Observability. É o que nos permitirá reagir melhor no caso de incidentes. A nossa capacidade de resposta será acelerada a poder ativar e desativar funcionalidades facilmente, também conhecidos por features flags.
Mecanismos de ativação e reversão, os features flags
A capacidade de gerir a ativação de features requer a sua inclusão desde a etapa de design. Devemos avaliar sua relevância, perimetro e regras de ativação no que diz respeito ao valor e redução do risco fornecido.
Os features flags requer que o código implemente sua regra e mecanismo de ativação durante a execução. Podemos fazer isso com algum código básico consistindo em “if” e uma variável num ficheiro de configuração. As ferramentas disponíveis baseiam-se nesses dois conceitos-chave.
Ferramentas mais avançadas permitem garantir outras necessidades de continuidade de serviço, acessibilidade via interface, gestão de direitos. Uma solução externa ao aplicativo também facilita uma visão transversal e menos acoplada. Soluções como A/B Tasty, LaunchDarkly ou Split.io são reconhecidas.
Os features flag exigem no entanto a gestão do seu ciclo de vida, até sua remoção. Temos que combinar práticas e ferramentas para chegar lá. Pode ler este artigo sobre como remover features flags, o Piranha da Uber ou recomendações do Featureflags.io.
A visibilidade é, portanto, um elemento fundamental para a nossa capacidade de gerir os nossos repositórios.
Reporting, dashboarding e Process Mining
Devemos ser capazes de medir e visualizar nosso sistema para orientar nossa gestão.
Podemos visualizar métricas do nosso repositório como atividade de commits em gráficos relativamente básicos. Algumas soluções mencionadas acima fornecerão visualização nativamente. Também podemos usar soluções de dashboarding, como Grafana, Kibana ou PowerBI.
Além disso, as nossas atividades raramente são estáticas. As nossas cadeias de desenvolvimento são sucessões de eventos, etapas e sequências de processos. As arquiteturas orientadas a eventos, value stream e Flow surgiram em seuquencia disso. É aqui que o Process Mining aparece para medir e visualizar esses processos.
Ferramentas a serviço da produtividade de sua engenharia
Gerenciar um repositório requer uma abordagem muito mais ampla do que apenas o armazenamento do código. Entendemos que uma arquitetura é necessária através dos diferentes tipos de ferramentas a serem integradas.
Devemos manter um foco real nos objetivos de nossa empresa. Uma abordagem tecnológica criará complexidade ao multiplicar soluções que acabarão sendo contraproducentes.
O nosso sistema deve ser capaz de suportar ciclos de iteração rápidos, suportando o crescimento e a capacidade de manutenção da nossa base de código. A relevância dos recursos oferecidos, ativados ou desativados permanece específica para cada organização.
O investimento dum tal sistema de engenharia pode ser questionável do ponto de vista do negócio. É por isso que uma abordagem deve estar alinhada, compartilhada e ligada às questões do negócio.
O código de nossa organização não é um de seus principais ativos?
Referências
Uma lista com curadoria de ferramentas de repos https://github.com/korfuri/awesome-monorepo
https://medium.com/@ SkyscannerEng / turbolift-a-tool-for-refactoring-at-scale-70603314f7cc
https://blog.bitsrc.io/11-tools-to-build-a-monorepo-in-2021-7ce904821cc2