Le mythe du code unique et la fragmentation du réel
On entend souvent dire que le développement natif est mort. Que des frameworks comme Flutter ou React Native ont définitivement enterré le besoin de coder spécifiquement pour iOS (en Swift) et pour Android (en Kotlin). C'est une vision séduisante, économiquement rassurante, mais techniquement simpliste. Choisir une technologie hybride, c'est accepter un compromis immédiat sur la performance pure au profit de la vélocité de développement. Est-ce un mauvais choix ? Pas forcément. Mais c'est un choix qui doit être éclairé par la réalité du terrain et non par des promesses marketing de "write once, run everywhere".
La réalité, c'est que même avec le meilleur framework cross-platform du monde, vous finirez par devoir écrire du code natif pour accéder à des fonctionnalités spécifiques du matériel ou pour optimiser des animations complexes qui rament sur un vieux téléphone Android d'entrée de gamme.
Regardez Airbnb. Ils ont massivement investi dans React Native avant de faire machine arrière pour revenir vers du natif sur certaines parties critiques de leur architecture. Pourquoi ? Parce que la couche d'abstraction finissait par coûter plus cher en maintenance que le développement de deux bases de code distinctes. Ce n'est pas pour dire que le cross-platform est mauvais (nous l'utilisons beaucoup chez Kosmos Digital), mais il ne faut pas le voir comme une baguette magique.
Il y a aussi cette idée reçue que l'écosystème Android est un chaos total par rapport au jardin fermé d'Apple. Bon, ce n'est pas totalement faux. La fragmentation sur Android est un véritable cauchemar pour les équipes QA (Assurance Qualité). Vous devez gérer :
- Des tailles d'écran improbables
- Des surcouches constructeurs (MIUI, One UI) qui tuent vos processus en arrière-plan sans prévenir
- Des versions d'API obsolètes mais encore utilisées par 15% du marché
- Des comportements erratiques du clavier virtuel
- La gestion aléatoire de la mémoire sur les devices low-cost
- Les différences de rendu des polices système
- Les encoches caméras placées à des endroits exotiques
- Les gestes de navigation qui entrent en conflit avec votre UI
C'est une liste non exhaustive qui donne des sueurs froides à n'importe quel développeur consciencieux. Sur iOS , on pourrait croire que c'est plus simple. Sauf que non. Apple a ses propres démons. La gestion des certificats de signature, les profils de provisionning qui expirent au pire moment et les règles de validation de l'App Store qui changent sans préavis sont autant de barrières à l'entrée.
Une aplication mobile robuste doit naviguer entre ces deux mondes avec agilité. Ce n'est pas juste "faire marcher le code". C'est s'assurer que l'expérience est fluide partout, tout le temps. Et parfois, ça demande de prendre des décisions architecturales radicales dès le jour 1. Si vous partez sur une base bancale, vous le paierez pendant des années en dette technique. C'est... enfin, vous voyez l'idée, c'est comme construire une maison sur du sable mouvant en espérant que le carrelage tienne le tout.
L'architecture invisible : ce que l'utilisateur ne voit jamais
Ce qui sépare une application amateur d'une solution professionnelle, c'est souvent ce qui ne se voit pas. L'utilisateur final appuie sur un bouton, une animation se lance, une donnée s'affiche. Simple, non ? Derrière ce geste anodin se cache une machinerie complexe de communication réseau, de gestion de cache et de sécurité.
Prenons la gestion des données hors-ligne. C'est le test ultime. Si votre application affiche une page blanche ou un spinner infini dès que l'utilisateur passe dans un tunnel, vous avez échoué. Une bonne architecture mobile doit implémenter une stratégie de "Offline First". On stocke en local (via Realm, CoreData ou Room), on affiche les données disponibles instantanément et on synchronise en arrière-plan quand le réseau revient. C'est techniquement lourd à mettre en place. Il faut gérer les conflits de synchronisation (que se passe-t-il si deux utilisateurs modifient la même donnée en même temps ?), la persistance des états et la sécurité des données stockées sur le terminal.
La sécurité, parlons-en.
Stocker des tokens d'authentification en clair dans les SharedPreferences ou le UserDefaults est une négligence criminelle. Pourtant, on le voit encore trop souvent lors d'audits de reprise de code. L'utilisation du Keychain (iOS) et du Keystore (Android) est impérative. Mais cela ajoute une couche de complexité au développement. De même pour les communications avec votre backend. Le SSL Pinning, qui empêche les attaques de type Man-in-the-Middle, devrait être la norme pour toute application manipulant des données sensibles. Mais sa mise en place est délicate et peut bloquer l'application si le certificat serveur change et que l'app n'a pas été mise à jour.
C'est là que notre approche de la méthodologie prend tout son sens. Nous ne commençons jamais à coder sans avoir défini ces flux de données et ces contraintes de sécurité. L'improvisation n'a pas sa place ici.
Un autre point souvent négligé est la gestion de la batterie et des ressources. Une application qui draine 20% de la batterie en une heure sera désinstallée impitoyablement. Les développeurs doivent être obsédés par le profilage de mémoire. Les fuites de mémoire (memory leaks) sont insidieuses : l'application fonctionne bien au début, puis ralentit progressivement jusqu'au crash inexpliqué après 30 minutes d'utilisation. Détecter ces fuites demande une maîtrise pointue des outils comme Instruments (Xcode) ou le Profiler d'Android Studio.
Et puis il y a l'analytique. Pas juste Google Analytics pour savoir combien de personnes ont ouvert l'app. Je parle de l'observabilité technique.
- Crashlytics pour les rapports d'erreurs en temps réel
- Datadog ou Sentry pour le monitoring des performances
Sans ces sondes, vous volez à l'aveugle. Les bugs qu'on trouve est souvent liés à des cas limites que les développeurs n'avaient pas prévus.
Il m'est arrivé de voir des projets entiers échouer non pas parce que l'idée était mauvaise, mais parce que l'infrastructure technique ne tenait pas la charge. Le mobile est impitoyable. Contrairement au web où l'on peut déployer un correctif en 5 minutes, une mise à jour mobile peut prendre 24 à 48 heures pour être validée par les stores. Si vous avez laissé passer un bug critique, vos utilisateurs le subiront pendant deux jours. C'est une éternité.
L'intégration continue ou la mort du déploiement manuel
Je vais être catégorique : si votre prestataire déploie vos applications manuellement depuis le poste d'un développeur, fuyez.
Le déploiement manuel est la source de 80% des erreurs de mise en production. Un certificat oublié, une mauvaise variable d'environnement (pointer sur la base de prod avec les identifiants de dev, un classique de l'horreur), une version de librairie différente... Les risques sont trop nombreux.
L'industrialisation du développement mobile passe par la mise en place d'une chaîne CI/CD (Continuous Integration / Continuous Deployment) solide. Chez nous, chaque commit de code déclenche une batterie de tests unitaires et de tests d'interface. Si un test échoue, le code ne part pas. Point final.
Nous utilisons des outils comme Fastlane pour automatiser les tâches rébarbatives :
- Incrémentation des numéros de build
- Génération des captures d'écran pour les stores (dans toutes les langues)
- Signature des binaires
- Upload vers TestFlight ou le Google Play Console
Cela permet aux développeurs de se concentrer sur la valeur ajoutée (les fonctionnalités) plutôt que de perdre trois heures à configurer un build. Mais cette automatisation a un coût initial. Configurer un pipeline Bitrise ou GitHub Actions pour du mobile est complexe. Il faut gérer les machines virtuelles Mac pour compiler du code iOS, gérer les secrets de signature de manière sécurisée... C'est un métier à part entière (DevOps mobile).
Cependant, je doute parfois que les clients comprennent l'importance de cet investissement invisible. Ils voient l'interface, ils voient les fonctionnalités. Ils ne voient pas le pipeline qui garantit qu'une version validé (oui, la qualité ça se paye) arrivera sans encombre sur le téléphone de leurs clients. C'est notre rôle de pédagogie d'expliquer que cette "tuyauterie" est ce qui garantit la pérennité de l'application.
Une CI/CD efficace permet aussi de réduire le "Time to Market". On peut déployer des versions de test plusieurs fois par jour pour les équipes produit. Le feedback est immédiat. On itère vite. On échoue vite pour réussir plus tôt. C'est le cœur de l'agilité technique.
UX/UI : Quand le design dicte la contrainte technique (et inversement)
On oppose souvent développeurs et designers. Les uns voudraient que tout soit carré et standard, les autres imaginent des interactions fluides qui défient les lois de la gravité du framework natif. La vérité se trouve dans la collaboration étroite.
Le Material Design de Google et les Human Interface Guidelines d'Apple ne sont pas des suggestions. Ce sont des standards que les utilisateurs ont intégrés inconsciemment. Aller à l'encontre de ces standards (par exemple, mettre un bouton "retour" en bas à droite sur iOS) crée une friction cognitive. L'utilisateur ne sait pas pourquoi, mais il trouve l'application "bizarre" ou "mal faite".
Nos équipes travaillent main dans la main. Un développeur doit être impliqué dès la phase de design pour valider la faisabilité technique. "C'est possible de faire cette transition de morphing entre la liste et le détail ?" Oui, c'est possible. Mais cela va coûter 3 jours de développement supplémentaires. Est-ce que la valeur ajoutée pour l'utilisateur justifie ce coût ? C'est ce genre d'arbitrage constant qui fait la réussite d'un projet.
Consultez nos références pour voir comment nous avons résolu ces équations sur des projets concrets. Parfois, la simplicité technique rejoint l'élégance visuelle. Parfois, il faut tordre le framework pour obtenir l'effet "waouh" nécessaire.
L'accessibilité est aussi un sujet majeur souvent ignoré. Développer une application mobile aujourd'hui, c'est s'assurer qu'elle est utilisable par des personnes malvoyantes (VoiceOver, TalkBack) ou ayant des troubles moteurs. Ce n'est pas une option, c'est une responsabilité éthique et souvent légale. Cela impacte le code : il faut étiqueter les éléments, gérer les zones de focus, assurer des contrastes suffisants.
Au final, une société de développement d'applications ne vend pas du code. Elle vend une garantie de fonctionnement dans un environnement hostile et changeant. Elle vend de la sérénité. Le code n'est qu'un moyen, pas une fin.
Il faut aussi savoir dire non. Non à une fonctionnalité qui va alourdir l'application inutilement. Non à une librairie tierce à la mode mais non maintenue. Non à des délais irréalistes qui forceraient à bâcler les tests. C'est cette rigueur qui fait la différence entre un prestataire et un partenaire.