Página inicial / Blogue / Arquitetura de backend Monorepo
Engenharia de backend

Arquitetura Monorepo para backend de APIs: fluxos de trabalho de CI e execução de código em escala

Um monorepo não é apenas uma escolha de organização de código. É uma declaração sobre como os pacotes se relacionam entre si, como a CI é executada e como a qualidade é imposta através dos limites compartilhados. Tomar essas decisões antecipadamente é mais difícil do que dividir os pacotes mais tarde.

CodePulse interface IDE do compilador online mostrando o editor de código, controles de execução e espaço de trabalho de saída
CodePulse vincula o IDE do navegador, a execução de APIs em Node.js e os portões de qualidade de CI em um fluxo de trabalho monorepo.

O que um monorepo compra para você em um projeto Node.js

O principal benefício é o gerenciamento atômico de mudanças: um PR que modifica uma biblioteca compartilhada e atualiza os consumidores que dependem dela chega como uma unidade em vez de duas implantações coordenadas. Os benefícios secundários incluem configuração de ferramentas compartilhadas, relatórios de testes unificados e uma única árvore de dependências que simplifica a resolução de conflitos de versão.

CodePulse Monorepo aplica essa estrutura a uma plataforma IDE online com um front-end Vanilla JS, um backend de execução Node.js e fluxos de trabalho de CI que executam portões de qualidade em todos os pacotes antes de qualquer pacote ser promovido.

A APIs de execução de código requer design de sandbox explícito

Um backend de APIs que executa código enviado pelo usuário precisa de um modelo de ameaça antes que uma linha seja escrita. Os riscos são diferentes de dados API: a execução arbitrária de código pode escapar dos limites do processo, consumir recursos ilimitados ou exfiltrar informações do ambiente do host. As opções de design de sandbox incluem:

  • Isolamento de processo — cada execução gera um processo filho ou contêiner isolado, sem acesso aos recursos do host fora da sandbox.
  • Limites de recursos — Limites de tempo de CPU, alocação de memória e descritor de arquivo aplicados no nível do sistema operacional e não no código do aplicativo, que pode ser ignorado.
  • Truncamento de saída — a saída da execução é limitada para evitar a exfiltração de grandes dados ou o abuso da resposta como canal secundário.
Os limites de recursos no código do aplicativo são consultivos. Os limites impostos pelo sistema operacional ou pelo tempo de execução do contêiner são estruturais. APIs de execução devem usar ambos, não um ou outro.

Design de fluxo de trabalho de CI para repositórios de vários pacotes

Um pipeline de CI monorepo tem uma escolha: executar todas as verificações em cada commit ou detectar quais pacotes foram alterados e executar apenas as verificações afetadas. A detecção de alterações afetadas é mais rápida, mas adiciona complexidade e pode perder dependências transitivas. Para monorepos menores, onde o CI completo é executado em poucos minutos, a execução completa do pipeline em cada PR é mais simples e confiável do que a detecção de alterações.

Os gates de CI em um projeto de execução de código normalmente incluem linting e formatação, testes de unidade em todos os pacotes, testes de integração contra a execução da API e aplicação de cobertura. Qualquer falha bloqueia a promoção do código.

Atingindo mais de 85% de cobertura de controle de qualidade sem teatro de cobertura

Os limites de cobertura são úteis como piso, não como teto. Um projeto que escreve testes de baixo valor para atingir um limite possui a métrica, mas não a proteção. Pacotes de alta cobertura que realmente protegem contra regressões cobrem os caminhos de execução importantes: casos extremos, ramificações de tratamento de erros e condições de limite.

Para uma execução da API, a cobertura significativa visa os caminhos de código que executam, truncam, atingem o tempo limite e rejeitam a entrada do usuário - não apenas o caminho feliz. O limite de 85%+ em CodePulse reflete a cobertura desses caminhos críticos, em vez da cobertura nominal de arquivos.

Front-end e backend compartilhando um limite de repositório

Quando o frontend e o backend residem no mesmo repositório, o teste de contrato de API torna-se simples: o teste pode importar o manipulador do servidor real e o código do cliente real e verificar se eles concordam com os formatos de solicitação e resposta. Isso é mais difícil de manter quando os pacotes residem em repositórios separados e o contrato está implícito.

O JavaScript Stack de desenvolvedor descreve como esse padrão de integração frontend-backend se relaciona com a arquitetura mais ampla Node.js e Vanilla JS.