La modularité dans le développement mobile — essence, principes et organisation

Auteur : IT Sectr Publié le : 2026-05-13 Temps de lecture : 9 min

La modularité est un principe selon lequel une application est assemblée à partir de modules indépendants, chacun responsable d'une seule fonctionnalité. Selon Android Developers, la division en modules accélère la compilation grâce à la compilation parallèle et permet aux équipes de travailler sur différentes parties de l'application de manière indépendante. L'architecture modulaire est devenue la norme pour les grands projets mobiles avec des dizaines de développeurs.

Points clés

  • Modularité — division d'une application en blocs indépendants avec des limites et des interfaces claires
  • Modules Gradle sur Android et Swift Packages sur iOS — les principaux outils de l'architecture modulaire
  • Isolation du code dans les modules empêche les dépendances accidentelles entre des fonctionnalités non liées
  • Compilation parallèle des modules réduit le temps de compilation de 2 à 4 fois sur les grands projets
  • Feature-first — l'approche la plus populaire où chaque écran ou fonctionnalité est séparé dans son propre module

Qu'est-ce que la modularité dans le développement mobile

La modularité est une façon d'organiser le code où une application est constituée de modules faiblement couplés, chacun fournissant une fonctionnalité strictement définie via une interface publique. Contrairement à l'architecture monolithique où toutes les classes résident dans un seul projet, l'approche modulaire divise le code en unités de compilation physiquement indépendantes.

L'objectif principal de la modularité est la gestion de la complexité. Un développeur peut se concentrer sur un module sans avoir en tête toute la base de code. Chaque module a son propre domaine de responsabilité et peut être développé, testé et déployé indépendamment des autres. C'est particulièrement utile dans les projets de 10+ développeurs, où le travail parallèle sur un monolithe entraîne de fréquents conflits de fusion.

Il est important de distinguer la modularité de l'architecture en couches. Les couches (Presentation, Domain, Data) divisent le code par critères techniques, tandis que les modules le divisent par critères fonctionnels. Un module « Profil utilisateur » peut contenir ses propres couches internes. En pratique, l'approche modulaire et l'architecture en couches sont combinées : chaque module a sa propre structure à trois couches.

Types de modules et leur objectif

Les modules de fonctionnalité sont le type de module le plus populaire. Chaque écran ou groupe d'écrans connexes est séparé dans son propre module : Onboarding, Profile, Settings, Feed. Un module de fonctionnalité contient tout ce qui est nécessaire au fonctionnement de la fonctionnalité : UI, logique métier, couche de données. Les limites du module sont protégées — les autres fonctionnalités ne peuvent pas accéder à ses classes internes.

Les modules centraux contiennent l'infrastructure commune : réseau, base de données, analyse, système de design. Ils ne dépendent pas des modules de fonctionnalité, mais les modules de fonctionnalité dépendent d'eux. Cette séparation garantit que la modification d'un SDK d'analyse n'affectera pas la couche réseau, et vice-versa. Les modules centraux sont réutilisés entre les fonctionnalités sans duplication de code.

Modules partagés pour la logique commune

Les modules partagés contiennent du code utilisé par plusieurs fonctionnalités : modèles de données, utilitaires, constantes, vues personnalisées. Le principal problème des modules partagés est le risque de se transformer en dépotoir (« module fourre-tout ») où du code hétérogène s'accumule avec le temps. Règle : un module partagé doit avoir un thème clair, par exemple « shared-ui » ou « shared-models ».

Sous Android, les modules partagés sont souvent séparés dans des bibliothèques avec le préfixe lib : lib-network, lib-database, lib-ui-components. Sous iOS, la même fonction est assurée par des Swift Packages internes dans un Workspace. En pratique, les équipes limitent le nombre de modules partagés à 3–5 pour éviter de créer un réseau de dépendances excessif qui complique la compilation.

Modules de test et isolation des tests

Des modules de test séparés permettent d'exécuter les tests uniquement pour le module modifié sans exécuter toute la suite de tests. Cela réduit le temps du pipeline CI/CD d'heures à minutes. L'isolation au niveau du module garantit le SoC au niveau de la compilation : un module de couche réseau ne peut pas importer accidentellement des bibliothèques d'interface utilisateur dans ses tests.

Chaque module doit avoir une API publique clairement définie. Sous Android, cela est réalisé via les modificateurs d'accès et api vs implementation dans Gradle. Sous iOS, via les modificateurs d'accès public/internal et les dépendances gérées via Package.swift. Réduire la visibilité au minimum nécessaire est une pratique clé de la conception modulaire.

Modularité sur Android : modules Gradle

Gradle prend en charge nativement l'architecture modulaire : chaque module est une unité de compilation séparée avec son propre fichier build.gradle. Les projets Android utilisent une combinaison d'un module d'application (app) et de plusieurs modules de bibliothèque. Les modules de bibliothèque ne peuvent pas être exécutés comme une application mais peuvent être publiés en tant qu'AAR dans un dépôt.

Une fonctionnalité clé de Gradle est la compilation parallèle de modules indépendants. Si les modules A, B et C ne dépendent pas les uns des autres, Gradle les compile simultanément en utilisant tous les cœurs du processeur. Dans les projets de 20+ modules, cela réduit une compilation complète de 15 à 3–5 minutes. Les compilations incrémentielles d'un module modifié prennent quelques secondes.

Gradle fournit deux types de dépendances entre les modules : api (transitives) et implementation (non transitives). La différence est cruciale pour la modularité : implementation masque les dépendances transitives aux consommateurs du module. Si le module :profile utilise :networking via implementation, les consommateurs de :profile ne connaissent pas :networking et ne peuvent pas y accéder.

groovy
// settings.gradle — déclaration des modules
include ':app'
include ':feature:profile'
include ':feature:settings'
include ':core:network'
include ':core:database'

// build.gradle feature/profile — dépendances du module
dependencies {
    implementation project(':core:network')
    implementation project(':core:database')
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0'
}

Le code montre la structure d'un projet Android modulaire. Settings.gradle liste tous les modules, et le build.gradle de chaque module de fonctionnalité spécifie uniquement les modules centraux dont il a besoin. Le système de compilation résout automatiquement les dépendances transitives et compile les modules dans le bon ordre.

Modularité sur iOS : Swift Package Manager et CocoaPods

Swift Package Manager (SPM) est l'outil de modularité standard sur iOS depuis 2019. SPM permet de diviser une application en Swift Packages, chacun pouvant être une bibliothèque ou un exécutable. Un Package définit les modules (targets) et leurs dépendances via Package.swift. SPM est intégré à Xcode et ne nécessite pas d'outils supplémentaires.

CocoaPods reste le gestionnaire de dépendances principal pour les bibliothèques tierces. Podfile et Podspec définissent la structure modulaire, et CocoaPods génère un workspace avec des projets pod séparés. Pour la modularité de leur propre projet, les équipes choisissent de plus en plus SPM car il est intégré à Xcode et ne nécessite pas d'installation.

Dans la modularité iOS, le contrôle d'accès joue un rôle important : public, package, internal, fileprivate et private. Un module publie uniquement les types qui doivent être accessibles aux autres modules. Les détails d'implémentation interne sont cachés derrière les modificateurs internal et private. Cela empêche les dépendances cachées entre les modules.

swift
// Package.swift — structure modulaire d'un projet iOS
let package = Package(
    name: "MyApp",
    platforms: [.iOS(SupportedPlatform.iOSVersion.v17)],
    products: [
        .library(name: "ProfileFeature", targets: ["ProfileFeature"]),
        .library(name: "NetworkCore", targets: ["NetworkCore"]),
    ],
    dependencies: [
        .package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.9.0")
    ],
    targets: [
        .target(name: "ProfileFeature", dependencies: ["NetworkCore"]),
        .target(name: "NetworkCore", dependencies: ["Alamofire"]),
    ]
)

Package.swift déclare deux produits de bibliothèque : ProfileFeature et NetworkCore. ProfileFeature dépend de NetworkCore mais ne connaît pas l'existence d'Alamofire — il est caché à l'intérieur de NetworkCore. Une telle isolation est une application directe du SoC au niveau du module : les modifications du client HTTP ne nécessitent pas la recompilation de ProfileFeature.

Avantages et défis de l'architecture modulaire

Le principal avantage de la modularité est la vitesse de développement. Les équipes travaillent en parallèle sur différents modules sans conflits de code. Le pipeline CI/CD compile uniquement les modules modifiés et exécute uniquement leurs tests. Le temps de retour diminue et la fréquence des versions augmente. Spotify, Uber et Airbnb ont publié des études de cas de migration vers une architecture modulaire avec des améliorations métriques de 2 à 3 fois.

Le deuxième avantage est l'isolation des erreurs. Un bogue dans le module Profile n'affecte pas le module Payments s'il n'y a pas de dépendances directes entre eux. C'est particulièrement important dans les applications avec des fonctionnalités à haut risque (paiements, données médicales), où une erreur dans un écran non lié ne doit pas bloquer la publication de fonctionnalités critiques.

Le principal défi est la gestion des dépendances. Avec une mauvaise conception, un graphe de modules émerge où la modification d'un module entraîne la recompilation en cascade de dizaines d'autres. La solution consiste à suivre la règle d'acyclicité : le graphe de dépendances des modules doit être un graphe orienté acyclique (DAG). Des outils comme Gradle Module Graph Assert aident à détecter les cycles au moment de la compilation.

Le deuxième défi est le temps de configuration initial accru. La création d'une architecture modulaire nécessite plus de temps au stade de l'initialisation du projet. Les petits projets avec 1–3 développeurs peuvent ne pas bénéficier de la modularité, passant du temps à maintenir les limites des modules sans réel besoin de parallélisation. La solution est de commencer par un monolithe et d'extraire les modules au fur et à mesure que l'équipe grandit.

Approches Feature-First vs Layer-First

L'approche feature-first regroupe les modules par fonctionnalité : chaque écran ou groupe d'écrans devient un module séparé. L'approche layer-first divise le code par critères techniques : modules séparés pour l'UI, la logique métier et les données. En pratique, la plupart des équipes choisissent le feature-first avec des modules centraux — cela offre une meilleure isolation et une navigation claire dans le projet.

Le choix entre les approches dépend de la taille de l'équipe et de la prévisibilité des fonctionnalités. Si vous savez exactement quels écrans seront dans le projet, le feature-first permet à chaque développeur d'être responsable de son propre module. Si la fonctionnalité change fréquemment et se chevauche entre les écrans, le layer-first offre plus de flexibilité dans la réutilisation du code entre différentes fonctionnalités.

Foire aux questions

Combien de modules une application doit-elle avoir ?

Le nombre optimal dépend de la taille du projet et de l'équipe. Pour une équipe de 5 personnes, 6–10 modules suffisent. Pour 20+ développeurs, 20–40 modules. Règle : un module doit être assez petit pour qu'un développeur le comprenne entièrement, et assez grand pour ne pas créer un réseau de dépendances excessif.

La modularité ralentit-elle la compilation ?

La modularité appropriée accélère la compilation grâce à la compilation parallèle et à la mise en cache. Cependant, un nombre excessif de modules avec des dépendances étroites ralentit la compilation — Gradle et Xcode passent du temps à résoudre le graphe. La clé pour des compilations rapides est de minimiser les dépendances transitives et de maintenir l'acyclicité.

Peut-on rendre une application existante modulaire ?

Oui, mais de manière itérative. Commencez par extraire les modules centraux (réseau, base de données), puis extrayez les fonctionnalités une par une. Utilisez des feature flags pour activer le nouveau code modulaire parallèlement à l'ancien code monolithique. La migration complète d'une grande application prend de 3 à 12 mois.

En quoi la modularité diffère-t-elle des microservices ?

Les modules sont des unités de compilation au sein d'une seule application. Les microservices sont des processus séparés fonctionnant sur des serveurs différents. Les modules divisent le code, les microservices divisent l'exécution. Dans le développement mobile, le terme « microapps » est souvent utilisé comme hybride : des modules de fonctionnalité qui peuvent fonctionner comme des applications autonomes.

Comment tester une application modulaire ?

Chaque module a ses propres tests unitaires qui s'exécutent indépendamment. Les tests d'intégration vérifient l'interaction entre les modules. Les tests d'UI couvrent les modules de fonctionnalité avec des données simulées. L'architecture modulaire simplifie les tests : simuler une dépendance d'un autre module est plus facile que de simuler une partie d'un monolithe.

Résumé

  • Modularité — division d'une application en unités de compilation indépendantes avec des limites claires
  • Modules de fonctionnalité regroupent le code autour de la fonctionnalité, modules centraux — autour de l'infrastructure
  • Gradle sur Android et SPM sur iOS — les principaux outils pour implémenter l'architecture modulaire
  • Compilations parallèles et isolation du code — les principaux avantages de la modularité dans les grands projets
  • Le graphe de dépendances doit être acyclique, sinon les compilations ralentissent et des références circulaires apparaissent
  • L'approche feature-first avec des modules centraux est reconnue comme la plus efficace pour les grands projets mobiles
  • Commencez par un monolithe et extrayez les modules au fur et à mesure que l'équipe et la base de code grandissent

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi