Monorepos e Microfeatures: como funciona no app do iFood

Compartilhe

Compartilhar no facebook
Compartilhar no google
Compartilhar no twitter
Compartilhar no linkedin

Por volta de Dezembro de 2018, nós decidimos transformar a codebase do iFood em um monorepo. Na época, nós tínhamos um target (o app de consumidores) e duas dependências principais em repositórios separados. Começamos a desenvolver um novo produto dentro do app e para aumentar a produtividade, decidimos criá-lo em um repositório próprio.

Alerta de spoilers: foi o caos! Diferentes versões das dependências conflitando entre os produtos, muuuuito código duplicado, coisas sendo desenvolvidas em paralelo sem necessidade.

Deu um bom trabalho, porém organizamos nossa codebase, dividindo por squad e trouxemos aquele novo produto e as dependências pro repositório principal. Num primeiro momento, usamos development pods para gerenciar essas dependências, mas depois de alguns meses passamos a usar Buck.

A ferramenta de build e o gerenciamento do monorepo não são os focos de hoje, o foco é explicar como fazemos esse monorepo não ser um monolito, suas vantagens e porque gostamos tanto dele.

Microfeatures

Desde o começo da mudança, decidimos seguir o conceito de microfeatures. Assim como microservices ou os microfrontends que estão em alta, microfeatures divide as funcionalidade em módulos pequenos e concisos.

Pra nós, o mais interessante da definição era a separação entre o que é um “framework/sdk” e o que é uma funcionalidade para o usuário final. Os nomes são µFeatures de “fundação” (foundation) e µFeatures de produto, respectivamente.

definição principal que nos inspirou foi essa por Pedro Piñera, autor do Tuist, uma ferramenta para buildar projetos do Xcode.

Foundation µFeatures

Para nós, µFeatures de foundation são módulos responsáveis por uma tarefa específica, como chamadas HTTP, componentes visuais, log de erro, monitoramento, configurações remotas, workers e assim por diante.

Esses módulos não têm lógica de negócio, apenas expõe um conjunto de classes ou protocolos e podem ser importados livremente pelo app. Por serem relativamente pequenos e altamente independentes, podem ser completamente testados e o tempo de compilação é bem baixo.

Nós temos uma estrutura de gerenciamento de dependências no main app que centraliza esses “workers” para evitar ciclos de dependência.

Product µFeatures

Já as µFeatures de produto são funcionalidade que o usuário final consegue utilizar. Por exemplo, um fluxo de login ou uma página de carrinho, etc.

Esses módulos não somente centralizam a lógica de negócio, como também possuem as telas, os routers, use cases, repositories e todas as camadas de Clean Swift e Clean Architecture que utilizamos.

É extremamente importante que uma microfeature de produto não importe outra microfeature de produto, por causar ciclos de dependência que podem dar muito problema, muito rápido.

Estamos evoluindo para um modelo de rotas que controlam os fluxos entre os módulos e a injeção de dependências.

Cada um desses módulos pode usar a arquitetura e/ou padrões que melhor convém, mas em sua maioria usamos VIP/Clean Swift ou para os módulos mais robustos usamos todas as camadas de Clean Architecture. Mas isso é conteúdo pra um outro post.

Vantagens

Contexto explicado, vamos para as vantagens dos monorepos e porque esse modelo funciona pro nosso projeto.

Para exemplificar cada um dos pontos a seguir, imagine que você possui um componente visual e você precisa fazer algumas mudanças no design. É um TextField simples, então todas as suas µFeatures de produto o utilizam.

Um pull request, todas as mudanças

Se o componente em questão estivesse em um repositório à parte, seria necessário fazer a mudança e passar de microfeature em microfeature, atualizando cada uma em seus respectivos repositórios e criar um pull request para cada alteração. Existe a possibilidade desses pull requests não serem aprovados ao mesmo tempo, gerando uma release com inconsistências nos TextFields em cada fluxo de navegação.

Somente uma versão em produção

Como consequência da situação acima, em um cenário multirepo, é possível ter múltiplas versões de uma mesma biblioteca em um único produto. Comportamentos diferentes, layouts diferentes, bugs diferentes. 🙃

Fácil compartilhamento de código

Nossos squads trabalham em diferentes partes do produto, porém compartilhamos muito código! Desde componentes visuais, até funcionalidades como biometria, encriptação, retry automático de requests. Essa lista é bem comprida.

Testabilidade e manutenibilidade

É muito mais fácil testar e manter um conjunto de código pequeno e bem organizado que só possui uma responsabilidade. Também é possível utilizar uma estratégia de “plug and play”, caso seja necessário um teste A/B ou testar bibliotecas diferentes. Além disso, as fraquezas e pontos de atenção ficam mais evidentes nas métricas de cobertura de código.

Tempos de build curtos

Image for post

Esse é sempre o primeiro ponto citado na maioria dos artigos. E realmente é verdade: como não buildamos o app principal o tempo todo, o que antes demoraria cerca de quinze minutos, foi reduzido para segundos em cada módulo.

Cada microfeature possui um mini app de exemplo que contém pontos de entrada com cenários previamente definidos e que cobrem todas as funcionalidade ou fluxos de tela daquele módulo. Todo o desenvolvimento é feito dentro desse módulo e rodando apenas o app de exemplo. Apenas após a implementação e os testes, a integração com o app principal é feita e aí sim rodamos o app completo. Sim, isso demora um pouco, mas essa ação é feita muito menos do que rodar os app de exemplo separadamente.

Considerações finais

A abordagem de monorepo e microfeatures se encaixa muito bem no contexto do nosso produto e time. A nossa produtividade aumentou, a escalabilidade é boa e os pontos negativos ainda não superaram as vantagens.

Porém, o monorepo não é uma bala de prata. Se você tiver interesse em aplicar o conceito no seu projeto, analise suas necessidades, estude diferentes opções e debata com o seu time antes de colocar a ideia em prática.

Você pode ler o artigo original (em inglês) e outros artigos sobre esse assunto no meu blog: yasminbenatti.com

Cheers!

Outros artigos que podem ser interessantes para você:

Yasmin Benatti

Yasmin Benatti

Yasmin é graduada em Análise e Desenvolvimento de Sistemas pelo IFSP São Carlos e trabalha no Rapiddo como desenvolvedora iOS. Na área mobile já conduziu workshops, palestras e treinamentos e foi parte da organização do CocoaHeads São Carlos, evento de fomentação da comunidade iOS.

Deixe um comentário

Categorias

Posts relacionados

Siga-nos

Baixe nosso e-book!

%d blogueiros gostam disto: