Modularização Android em 2026: Arquitetura Multi-Módulo e Perguntas de Entrevista

Guia completo sobre modularização Android em 2026. Aprenda a estruturar uma arquitetura multi-módulo, usar catálogos de versões Gradle e dominar as perguntas essenciais de entrevista técnica.

Arquitetura multi-módulo Android com módulos feature e core

A modularização Android transforma bases de código monolíticas em sistemas sustentáveis e escaláveis onde equipes trabalham em paralelo sem conflitos de código. Uma aplicação Android bem modularizada compila mais rápido, testa de forma isolada e permite a integração de novos desenvolvedores em dias ao invés de semanas.

Modularização em Resumo

A modularização divide uma aplicação Android em módulos Gradle independentes com fronteiras claras. Baixo acoplamento entre módulos e alta coesão dentro de cada módulo são os princípios orientadores. A aplicação de referência Now in Android do Google demonstra esse padrão com mais de 40 módulos.

Por Que a Arquitetura Multi-Módulo É Importante para Aplicações Android

Uma aplicação Android de módulo único recompila tudo quando uma única linha muda. Uma modificação na camada de rede dispara a recompilação da interface do usuário. Dois desenvolvedores editando funcionalidades diferentes criam conflitos de merge em arquivos compartilhados. Os tempos de compilação se estendem para mais de 4 minutos em builds incrementais.

A arquitetura multi-módulo aborda diretamente esses pontos problemáticos:

  • Compilações mais rápidas: O Gradle recompila apenas os módulos afetados. Uma mudança em :feature:checkout deixa :feature:profile intocado.
  • Desenvolvimento paralelo: Equipes possuem módulos separados com APIs definidas. Conflitos de merge diminuem significativamente.
  • Testes isolados: Testes unitários executam contra um único módulo sem carregar toda a aplicação.
  • Reutilização de código: Um módulo de design system :core:ui se torna uma biblioteca utilizável em múltiplas aplicações.

O guia oficial de modularização Android recomenda estruturar módulos em torno de funcionalidades ou camadas que mudam juntas, seguindo o Princípio da Responsabilidade Única.

Tipos de Módulos e Suas Responsabilidades

O repositório Now in Android estabelece uma taxonomia de módulos comprovada que escala para aplicações empresariais.

settings.gradle.kts - Estrutura de móduloskotlin
include(":app")

// Módulos core - utilitários compartilhados
include(":core:common")
include(":core:data")
include(":core:database")
include(":core:datastore")
include(":core:designsystem")
include(":core:domain")
include(":core:model")
include(":core:network")
include(":core:ui")

// Módulos feature - lógica específica de telas
include(":feature:home")
include(":feature:search")
include(":feature:bookmarks")
include(":feature:settings")

Módulo app: Contém MainActivity, configuração de navegação e scaffolding a nível de aplicação. Depende de todos os módulos feature e dos módulos core necessários.

Módulos core: Fornecem funcionalidades compartilhadas entre features. :core:network gerencia chamadas de API. :core:database gerencia entidades Room. :core:designsystem define os componentes visuais da aplicação.

Módulos feature: Encapsulam uma única tela ou fluxo de usuário. Cada módulo feature depende apenas dos módulos core que precisa, nunca de outros módulos feature.

Essa estrutura impõe dependências unidirecionais: features dependem de core, e app depende de features.

Catálogos de Versões Gradle para Gerenciamento de Dependências

Gerenciar dependências em mais de 25 módulos sem conflitos de versão requer configuração centralizada. Os Catálogos de Versões Gradle resolvem isso com um único arquivo libs.versions.toml.

toml
# gradle/libs.versions.toml
[versions]
agp = "8.7.0"
kotlin = "2.1.0"
compose-bom = "2026.09.00"
ksp = "2.1.0-1.0.29"
hilt = "2.54"
room = "2.7.0"
retrofit = "2.11.0"

[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version = "1.15.0" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
hilt-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
retrofit-core = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }

[bundles]
compose = ["androidx-compose-ui", "androidx-compose-material3"]
room = ["room-runtime", "room-ktx"]

[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
android-library = { id = "com.android.library", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }

Os módulos então referenciam dependências com acessores tipados:

feature/home/build.gradle.ktskotlin
dependencies {
    implementation(libs.bundles.compose)
    implementation(libs.hilt.android)
    ksp(libs.hilt.compiler)
}

O Gradle gera esses acessores durante a sincronização, habilitando autocompletar no IDE e validação em tempo de compilação.

Pronto para mandar bem nas entrevistas de Android?

Pratique com nossos simuladores interativos, flashcards e testes tecnicos.

Convention Plugins: Configuração de Build DRY

Um projeto de 25 módulos sem convention plugins repete os mesmos compileSdk, minSdk, composeOptions e aplicações de plugins em cada build.gradle.kts. Diferentes módulos podem acidentalmente usar configurações diferentes.

Os convention plugins centralizam essa lógica em um build incluído build-logic.

build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.ktkotlin
import com.android.build.api.dsl.LibraryExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure

class AndroidLibraryConventionPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        with(target) {
            pluginManager.apply("com.android.library")
            pluginManager.apply("org.jetbrains.kotlin.android")

            extensions.configure<LibraryExtension> {
                compileSdk = 35
                defaultConfig {
                    minSdk = 26
                    testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
                }
                compileOptions {
                    sourceCompatibility = JavaVersion.VERSION_17
                    targetCompatibility = JavaVersion.VERSION_17
                }
            }
        }
    }
}

Registro do plugin em build-logic/convention/build.gradle.kts:

build-logic/convention/build.gradle.ktskotlin
plugins {
    `kotlin-dsl`
}

dependencies {
    compileOnly(libs.android.gradlePlugin)
    compileOnly(libs.kotlin.gradlePlugin)
}

gradlePlugin {
    plugins {
        register("androidLibrary") {
            id = "myapp.android.library"
            implementationClass = "AndroidLibraryConventionPlugin"
        }
        register("androidFeature") {
            id = "myapp.android.feature"
            implementationClass = "AndroidFeatureConventionPlugin"
        }
        register("androidHilt") {
            id = "myapp.android.hilt"
            implementationClass = "AndroidHiltConventionPlugin"
        }
    }
}

Os módulos feature agora requerem configuração mínima:

feature/home/build.gradle.ktskotlin
plugins {
    alias(libs.plugins.myapp.android.feature)
    alias(libs.plugins.myapp.android.hilt)
}

dependencies {
    implementation(projects.core.data)
    implementation(projects.core.designsystem)
}

O build-logic do Now in Android do Google usa exatamente esse padrão.

Padrões de Comunicação Entre Módulos

Módulos feature não devem depender diretamente uns dos outros. Essa restrição preserva a compilação paralela e previne dependências circulares. Três padrões lidam com a comunicação entre features.

core/navigation/src/main/kotlin/Routes.ktkotlin
object Routes {
    const val HOME = "home"
    const val PRODUCT_DETAIL = "product/{productId}"
    const val CHECKOUT = "checkout"
    
    fun productDetail(productId: String) = "product/$productId"
}

Módulos feature importam rotas de :core:navigation sem saber qual módulo implementa cada destino.

Modelos de Domínio Compartilhados

core/model/src/main/kotlin/Product.ktkotlin
data class Product(
    val id: String,
    val name: String,
    val price: BigDecimal,
    val imageUrl: String
)

Tanto :feature:catalog quanto :feature:checkout dependem de :core:model para a classe Product.

Event Bus ou ViewModel Compartilhado

Para comunicação em tempo de execução, um event bus compartilhado em :core:common ou um ViewModel com escopo gerencia eventos entre features:

core/common/src/main/kotlin/CartEventBus.ktkotlin
object CartEventBus {
    private val _events = MutableSharedFlow<CartEvent>()
    val events: SharedFlow<CartEvent> = _events.asSharedFlow()
    
    suspend fun emit(event: CartEvent) {
        _events.emit(event)
    }
}

sealed interface CartEvent {
    data class ItemAdded(val productId: String) : CartEvent
    data class ItemRemoved(val productId: String) : CartEvent
}

Perguntas de Entrevista sobre Modularização Android

A modularização aparece frequentemente em entrevistas Android de nível sênior. Os entrevistadores avaliam a compreensão de sistemas de build, decisões de arquitetura e trade-offs práticos.

Dica de Entrevista

Ao discutir modularização em entrevistas, é recomendável referenciar métricas concretas: melhorias em tempos de build, ganhos de velocidade da equipe ou números específicos de módulos de projetos reais. Respostas abstratas sobre "melhor separação de responsabilidades" são menos convincentes que "os tempos de build caíram de 4 minutos para 45 segundos após a modularização".

P: Qual é a diferença entre dependências api e implementation no Gradle?

Dependências implementation são internas ao módulo. Consumidores do módulo não podem acessá-las. Dependências api são expostas transitivamente: se o módulo A usa api(libs.retrofit), o módulo B que depende de A pode usar classes do Retrofit diretamente.

Regra geral: usar implementation por padrão. Apenas usar api quando a dependência faz parte da API pública do módulo. O uso excessivo de api quebra o encapsulamento e desacelera os builds.

P: Como lidar com navegação entre módulos feature que não dependem um do outro?

Deve-se criar um módulo :core:navigation contendo definições de rotas e interfaces de navegação. Módulos feature dependem desse módulo compartilhado. O módulo app conecta os destinos às implementações. Isso segue o princípio de inversão de dependência: features dependem de abstrações, não de implementações concretas.

P: Quais são os trade-offs de ter muitos módulos?

Cada módulo adiciona overhead de configuração Gradle: arquivos de build, processamento de recursos, fusão de manifests. Os tempos de sincronização inicial aumentam. O ponto de inflexão varia por projeto, mas 50+ módulos é comum em aplicações grandes. Os benefícios (builds paralelos, testes isolados, propriedade clara) tipicamente superam o overhead para equipes de 5+ desenvolvedores.

P: Como os convention plugins diferem do buildSrc?

Mudanças no buildSrc disparam uma reconstrução completa do projeto. Convention plugins em um build incluído só recompilam quando o código do plugin muda, não quando módulos consumidores mudam. Isso torna os convention plugins mais rápidos para desenvolvimento iterativo. Além disso, convention plugins podem ser publicados como um artefato separado para reutilização entre repositórios.

P: Como testar um módulo feature de forma isolada?

Módulos feature dependem de módulos core através de interfaces. Devem-se criar implementações falsas em test fixtures:

core/data/src/testFixtures/kotlin/FakeProductRepository.ktkotlin
class FakeProductRepository : ProductRepository {
    private val products = mutableListOf<Product>()
    
    override suspend fun getProducts(): List<Product> = products
    
    fun addProduct(product: Product) {
        products.add(product)
    }
}

Testes de módulos feature injetam fakes via APIs de teste do Hilt ou injeção manual por construtor.

Para mais perguntas de prática sobre arquitetura Android, consultar as perguntas de entrevista sobre arquitetura MVVM e o módulo sobre injeção de dependências.

Comece a praticar!

Teste seus conhecimentos com nossos simuladores de entrevista e testes tecnicos.

Pontos-Chave para Projetos Android Multi-Módulo

  • Estruturar módulos por feature (:feature:home, :feature:checkout) e por camada (:core:data, :core:ui). Features dependem de core, nunca uma da outra.
  • Usar Catálogos de Versões Gradle (libs.versions.toml) para centralizar versões de dependências. Bundles agrupam dependências relacionadas para arquivos de build mais limpos.
  • Implementar convention plugins em build-logic para eliminar configuração duplicada entre módulos. Uma mudança no plugin atualiza todos os módulos consumidores.
  • Impor dependências unidirecionais: app depende de features, features dependem de core. Ferramentas como Dependency Guard podem automatizar essa aplicação.
  • Medir o desempenho de build antes e depois da modularização. Acompanhar os tempos de build incrementais, não apenas builds limpos, para validar melhorias.
  • Manter as fronteiras dos módulos estáveis. Reestruturações frequentes anulam os benefícios da modularização.
Desafio do dia

Você saberia encontrar o bug em Android?

Um trecho real, um bug escondido, uma tentativa por dia. Sem conta para testar.

Anthony Fillion-Maillet

Escrito por

Anthony Fillion-Maillet

Fundador da SharpSkill

Desenvolvedor fullstack há mais de 10 anos. Dirige a SharpSkill e responde por tudo o que é publicado aqui.

Atualizado em 17 de setembro de 2026

Tags

#android
#modularization
#architecture
#kotlin
#gradle

Compartilhar

Artigos relacionados