Guia para a modularização de apps Android

Um projeto com vários módulos do Gradle é conhecido como um projeto multimódulo. Este guia aborda práticas e padrões recomendados para desenvolver apps Android multimódulo.

O problema da base de código cada vez maior

Em uma base de código crescente, a escalonabilidade, legibilidade e qualidade geral do código geralmente diminuem com o tempo. Isso acontece como resultado do aumento da base de código sem que os mantenedores dela tomem medidas ativas para aplicar uma estrutura de fácil manutenção. A modularização é uma maneira de estruturar a base de código para melhorar a manutenção e ajudar a evitar esses problemas.

O que é a modularização?

Essa é a prática de organizar uma base de código em partes contidas e acopladas com flexibilidade. Cada parte é um módulo. Cada módulo é independente e tem uma finalidade clara. Ao dividir um problema em subproblemas menores e mais fáceis de resolver, você diminui a complexidade de projetar e manter um sistema grande.

Figura 1: gráfico das dependências de uma base de código multimódulo de exemplo.

Benefícios da modularização

Os benefícios da modularização são muitos, embora cada um tenha como foco melhorar a manutenção e a qualidade geral de uma base de código. A tabela a seguir mostra os principais benefícios.

Benefício Resumo
Capacidade de reutilização A modularização oferece oportunidades para o compartilhamento de código e a criação de vários apps usando a mesma base. Os módulos são os elementos básicos. Os apps precisam ser uma soma dos recursos, que são organizados como módulos separados. A funcionalidade fornecida por um determinado módulo pode ou não ser ativada em um app específico. Por exemplo, um :feature:news pode fazer parte da variação de versão completa de um app para Wear, mas não da versão de demonstração.
Controle de visibilidade rigoroso Os módulos permitem controlar com mais facilidade o que você expõe a outras partes da sua base de código. Exceto pela interface pública, tudo pode ser marcado como internal ou private para evitar o uso fora do módulo.
Entrega personalizável O Play Feature Delivery usa funções avançadas de pacotes de apps, permitindo que você envie determinados recursos do app de forma condicional ou sob demanda.

Os benefícios acima só podem ser alcançados com uma base de código modularizada. É possível ter os benefícios a seguir usando outras técnicas, mas a modularização pode ajudar você a conseguir ainda mais.

Benefício Resumo
Escalabilidade Em uma base de código com acoplamento rígido, uma única mudança pode acionar uma cascata de alterações em partes do código que não parecem relacionadas. Um projeto modularizado corretamente vai adotar o princípio de separação de conceitos (link em inglês) e, assim, limitar o acoplamento. Com isso, os colaboradores têm mais autonomia.
Propriedade Além de permitir a autonomia, os módulos também podem ser usados para atribuir a responsabilidade. Um módulo pode ter um proprietário dedicado que é responsável por manter o código, corrigir bugs, adicionar testes e revisar mudanças.
Encapsulamento O encapsulamento significa que cada parte do código precisa ter a menor quantidade possível de informações sobre as outras partes. O código isolado é mais fácil de ler e entender.
Capacidade de teste A capacidade de teste caracteriza o nível de dificuldade para testar seu código. Um código testável é aquele em que os componentes podem ser testados com facilidade e de forma isolada.
Tempo de compilação Algumas funcionalidades do Gradle, como build incremental, cache do build ou build paralelo, podem usar a modularidade para melhorar a performance do build.

Dificuldades comuns

A granularidade da base de código é o nível de composição dos módulos. Uma base de código mais granular tem módulos menores. Ao projetar uma base de código modularizada, você precisa escolher um nível de granularidade. Para fazer isso, considere o tamanho da sua base de código e a complexidade relativa dela. Quando você usa uma granularidade muito detalhada, acaba sobrecarregando o código e, se ela for muito generalizada, os benefícios da modularização vão ser menores.

Veja alguns problemas comuns:

  • Muito detalhada: cada módulo traz uma certa quantidade de overhead na forma de mais código boilerplate (link em inglês) e complexidade no build. Uma configuração de build complexa dificulta a manutenção de configurações consistentes em todos os módulos. O uso de muito código boilerplate resulta em uma base de código complexa que é difícil de manter. Se o overhead anular melhorias de escalonabilidade, considere consolidar alguns módulos.
  • Muito generalizada: por outro lado, se os módulos estiverem aumentando muito, você pode acabar com outro monólito e vai perder os benefícios que a modularidade oferece. Por exemplo, em um projeto pequeno, não há problema em colocar a camada de dados em um único módulo. No entanto, à medida que ela cresce, pode ser necessário separar repositórios e fontes de dados em módulos independentes.
  • Muito complexa: nem sempre faz sentido modularizar seu projeto. Um fator importante é o tamanho da base de código. Se você não espera que seu projeto cresça além de um determinado limite, os ganhos de escalonabilidade e tempo de compilação não vão ser relevantes.

A modularização é a técnica certa para mim?

Se você precisa dos benefícios de reutilização, de um controle rigoroso de visibilidade ou quer usar o Play Feature Delivery, a modularização é uma necessidade para você. Se você não precisa disso, mas ainda quer se beneficiar de melhorias em escalonabilidade, propriedade, encapsulamento ou tempos de compilação, a modularização pode ser considerada.

Exemplos