0Pricing
Android Academy · Leçon

Modules de fonctionnalités et modules centraux

Définissez les frontières entre modules.

Modules de fonctionnalités et modules centraux est une leçon Android Academy gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Android Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Android Academy comprend 4 leçons au total.

Deux types de modules

La plupart des applications Android modularisées organisent le code en deux grands types de modules : les modules feature et les modules core, auxquels s'ajoute un module :app minimal au sommet.

  • Les modules feature contiennent une partie de l'application destinée à l'utilisateur (un écran ou un parcours).
  • Les modules core contiennent l'infrastructure partagée utilisée par plusieurs fonctionnalités.

Dans cette leçon, vous apprendrez à définir correctement ces limites.

Anatomie d'un module feature

Un module feature comme :feature:profile contient tout ce dont une fonctionnalité a besoin : ses écrans Compose, son ViewModel et son état d'interface utilisateur. Il est vertical : il possède toute la partie allant de l'interface utilisateur jusqu'à son modèle de vue.

Il dépend des modules core pour les éléments partagés, mais ne devrait pas dépendre d'autres modules feature.

// feature/profile/ProfileScreen.kt
@Composable
fun ProfileScreen(viewModel: ProfileViewModel = hiltViewModel()) {
    val state by viewModel.uiState.collectAsStateWithLifecycle()
    when (state) {
        is ProfileUiState.Loading -> CircularProgressIndicator()
        is ProfileUiState.Success -> ProfileContent((state as ProfileUiState.Success).user)
        is ProfileUiState.Error -> ErrorMessage()
    }
}

Le ViewModel de la fonctionnalité

Chaque fonctionnalité possède son propre ViewModel. Il récupère les données par l'intermédiaire d'un dépôt provenant d'un module core et expose l'état de l'interface utilisateur. Le module feature ne sait rien de la manière dont les données sont récupérées ; il ne connaît que le contrat du dépôt.

// feature/profile/ProfileViewModel.kt
@HiltViewModel
class ProfileViewModel @Inject constructor(
    private val userRepository: UserRepository // from :core:data
) : ViewModel() {
    val uiState: StateFlow<ProfileUiState> =
        userRepository.observeUser()
            .map { ProfileUiState.Success(it) }
            .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), ProfileUiState.Loading)
}

Anatomie d'un module core

Un module core est horizontal : il fournit une capacité utilisée par plusieurs fonctionnalités. Parmi les modules core courants, on trouve :

  • :core:model — des classes de données simples partagées partout
  • :core:network — des clients Retrofit/Ktor
  • :core:database — la configuration de Room
  • :core:data — des dépôts combinant le réseau et la base de données
  • :core:designsystem — le thème et les composables réutilisables
// core/model/User.kt
data class User(
    val id: String,
    val name: String,
    val avatarUrl: String
)

Le module du système de conception

:core:designsystem est l'un des modules les plus réutilisés. Il contient votre MaterialTheme, vos jeux de couleurs, votre typographie et des composables réutilisables comme les boutons et les cartes. Chaque fonctionnalité applique la même apparence sans copier de code.

// core/designsystem/AppTheme.kt
@Composable
fun AppTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    val colors = if (darkTheme) DarkColors else LightColors
    MaterialTheme(
        colorScheme = colors,
        typography = AppTypography,
        content = content
    )
}

Le module de données possède les dépôts

Le module :core:data expose des interfaces de dépôt dont dépendent les fonctionnalités, tout en masquant l'implémentation. Il dépend généralement de :core:network et de :core:database, qu'il combine en une source unique de vérité.

// core/data/UserRepository.kt
interface UserRepository {
    fun observeUser(): Flow<User>
    suspend fun refresh()
}

// core/data/OfflineFirstUserRepository.kt
internal class OfflineFirstUserRepository @Inject constructor(
    private val api: UserApi,        // :core:network
    private val dao: UserDao         // :core:database
) : UserRepository {
    override fun observeUser(): Flow<User> = dao.observe().map { it.toUser() }
    override suspend fun refresh() { dao.upsert(api.fetch().toEntity()) }
}

Garder model et designsystem légers

Les modules centraux de plus bas niveau doivent dépendre d'un minimum d'éléments. :core:model ne devrait idéalement avoir aucune dépendance à Android : uniquement de simples classes de données Kotlin. Cela le rend utilisable partout et rapide à compiler.

Si :core:model commençait à dépendre de Retrofit ou de Room, chaque module utilisant vos classes de données intégrerait indirectement ces bibliothèques lourdes.

// core/model/build.gradle.kts
plugins {
    id("myapp.jvm.library") // pure Kotlin, no Android
}
// No Retrofit, no Room, no Compose here — just data classes

Le module :app minimal

Le module :app est l'assembleur. Il doit contenir très peu de logique : la classe Application, l'unique MainActivity, le NavHost de niveau supérieur et la configuration de l'injection de dépendances. Tous les écrans réels se trouvent dans les modules de fonctionnalités.

Un module d'application minimal signifie que la plupart des modifications ont lieu dans les fonctionnalités, si bien que le module d'application est rarement recompilé.

// app/MainActivity.kt
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            AppTheme {            // from :core:designsystem
                AppNavHost()      // routes into :feature:* screens
            }
        }
    }
}

Définir de bonnes frontières

Comment décider de ce qui doit devenir un module ? Voici quelques heuristiques pratiques :

  • Une fonctionnalité = un écran ou un parcours que l'utilisateur peut nommer (Accueil, Profil, Paiement).
  • Un module central = une capacité réutilisée par au moins 2 fonctionnalités.
  • Si deux fonctionnalités ont besoin du même code, déplacez-le vers le bas, dans un module central.
  • Si un module fait trop de choses sans rapport entre elles, divisez-le.

Facultatif : séparation entre api et impl

Les grandes applications séparent parfois une fonctionnalité en un module public :feature:profile:api (interfaces, routes de navigation) et un module privé :feature:profile:impl (écrans, modèles de vue). Les autres fonctionnalités dépendent uniquement du petit module api, jamais de l'implémentation.

Cette approche est avancée ; pour la plupart des applications, un seul module par fonctionnalité suffit largement. Retenez simplement que ce modèle existe pour les bases de code très volumineuses.

// Other features see only the contract, not the screens
// feature/home depends on :feature:profile:api
interface ProfileEntry {
    val route: String
    fun NavGraphBuilder.register(navController: NavController)
}

Assembler le graphe

Voici comment les couches s'articulent dans notre exemple. Remarquez que les dépendances pointent toujours vers le bas : app -> feature -> data -> network/database -> model.

// :app           -> :feature:home, :feature:profile
// :feature:home  -> :core:data, :core:designsystem
// :feature:profile -> :core:data, :core:designsystem
// :core:data     -> :core:network, :core:database, :core:model
// :core:network  -> :core:model
// :core:database -> :core:model
// :core:model    -> (nothing)

Vérification rapide

Vos modules :feature:home et :feature:profile doivent tous deux récupérer et mettre en cache les données utilisateur. Où le code du dépôt doit-il se trouver ?

Récapitulatif : modules de fonctionnalités et modules centraux

Vous avez appris à répartir le code en deux couches :

  • Les modules de fonctionnalités sont des tranches verticales (écran + ViewModel + état de l'interface).
  • Les modules centraux sont des capacités horizontales (modèle, réseau, base de données, données, système de design).
  • Le module :app reste minimal et se contente d'assembler les fonctionnalités.
  • Le code partagé descend vers les modules centraux ; :core:model reste léger et indépendant d'Android.

Ensuite, vous gérerez les dépendances entre ces modules et veillerez à garder le graphe propre.

Questions Fréquemment Posées

La leçon « Modules de fonctionnalités et modules centraux » est-elle gratuite ?

Oui — le texte complet de « Modules de fonctionnalités et modules centraux » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Android Academy, passe à CoddyKit PRO. Le cours Android Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Modules de fonctionnalités et modules centraux » ?

Définissez les frontières entre modules. Tu pratiques Android Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Android Academy ?

Aucune expérience préalable n'est requise. Android Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.

Combien de temps prend la leçon « Modules de fonctionnalités et modules centraux » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Android Academy ?

Oui. Chaque leçon Android Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Pourquoi modulariser
  2. Modules de fonctionnalités et modules centraux
  3. Gérer les dépendances entre modules
  4. Navigation entre modules
← Retour à Android Academy