03 — Développement mobile

iOS, Android, multiplateforme, et les backends derrière eux

Des applications mobiles livrées à de vrais utilisateurs — et restées livrées — pendant plus de onze ans.

iOS et Android natifs dans leurs propres langages, React Native et Flutter là où ils conviennent, et les backends, caches et clouds qui font d’un téléphone plus qu’une coquille mince. La trajectoire de onze ans est ce qui rend le reste crédible.

La fondation

J’ai passé plus de onze ans à construire et livrer des applications mobiles à de vrais utilisateurs — et ce seul fait est celui qui rend chaque autre affirmation de cette page digne d’être lue.

N’importe qui peut lister des frameworks. Le titre qui compte, c’est la longévité : des applications que de vraies personnes ont installées, conservées et utilisées sur iOS, Android et Windows, pendant plus d’une décennie. La trajectoire de onze ans n’est pas une ligne sur un CV — c’est la preuve que les décisions ci-dessous ont été prises sous la pression d’un logiciel qui devait continuer à fonctionner après le lancement.

Je travaille natif d’abord. Sur iOS cela signifie Swift et Objective-C avec SwiftUI, Core Data, Core Animation et SiriKit ; sur Android cela signifie Kotlin et Java contre l’Android SDK sur de nombreuses versions d’OS. Cette fluidité native est exactement ce qui fait du travail multiplateforme — React Native et Flutter à un niveau avancé, Xamarin à un niveau opérationnel — un choix délibéré plutôt qu’un moyen d’éviter une plateforme.

Et une application mobile n’est jamais seulement le client. Derrière elle se trouvent des backends en Node, Spring Boot, Django, Flask, Rails et Go, exposant REST et GraphQL, soutenus par SQLite sur l’appareil et Redis sur le serveur, déployés sur Firebase, AWS et Google Cloud. La page qui suit est toute cette surface, racontée telle que je la construis vraiment.

0+

années à livrer des applications mobiles à de vrais utilisateurs, sur iOS, Android et Windows

0

plateformes natives maintenues dans leurs propres langages — Swift/Objective-C et Kotlin/Java

0

stacks multiplateformes que je maîtrise à un niveau avancé — React Native et Flutter

0

frameworks backend que j’associe aux clients mobiles, de Node à Go

Matrice des plateformes

Deux plateformes natives, deux stacks multiplateformes, une surface Windows.

La première décision sur tout projet mobile, c’est sur quoi construire, et c’est rarement la même réponse deux fois. La matrice ci-dessous est ma façon de raisonner : iOS et Android natifs chacun dans son propre langage, deux stacks multiplateformes que je maîtrise à un niveau avancé, et une surface Windows qui garde honnête la logique partagée. Le diagramme mappe les langages et frameworks sur les plateformes plutôt que de prétendre qu’un seul outil couvre tout.

LANGAGE CIBLE Swift / ObjC Kotlin / Java React Native Flutter iOS Android Windows plein = fluidité native · fin = portée multiplateforme

Langages et frameworks, mappés aux plateformes

Une matrice, pas un monolithe — chaque plateforme dans le langage qu’elle récompense.

iOS reçoit Swift et Objective-C ; Android reçoit Kotlin et Java ; Windows reçoit son propre client. React Native et Flutter couvrent les stores quand l’UI ne se bat pas contre la plateforme, et la colonne de droite montre où chaque outil atterrit vraiment.

Lire la matrice, c’est le travail : c’est ainsi que je décide si une fonctionnalité est native, multiplateforme, ou un client mince sur un backend partagé, avant qu’une ligne d’UI soit écrite.

  • iOS — Swift, Objective-C, SwiftUI, Core Data
  • Android — Kotlin, Java, Android SDK
  • Multiplateforme — React Native, Flutter (avancé)
  • Windows — client bureau natif
iOSAndroidReact NativeFlutterWindows
Par plateforme

Ce que j’écris vraiment sur chaque plateforme.

Les plateformes ne sont pas interchangeables, et l’outillage le reflète. Chaque onglet est une plateforme sur laquelle j’ai livré — les langages, les frameworks, et le jugement sur le moment où chacun gagne sa place.

iOS natif en Swift, avec Objective-C là où il vit encore

Sur iOS j’écris en Swift et je lis Objective-C, parce que les vraies bases de code qui livrent depuis des années sont rarement du Swift pur. Je construis les interfaces en SwiftUI pour les nouveaux écrans et je garde UIKit là où un flux existant en dépend, plutôt que de réécrire du code qui marche pour le plaisir d’un framework.

La persistance, c’est Core Data quand l’application possède un vrai graphe d’objets, et le mouvement, c’est Core Animation quand une transition doit se sentir native plutôt qu’approximée. SiriKit gère les intents vocaux là où ils gagnent leur place — pas sur chaque écran, seulement là où un raccourci parlé est vraiment plus rapide que de toucher.

  • Swift d’abord, Objective-C lu et maintenu
  • SwiftUI pour les nouveaux écrans, UIKit gardé là où il marche
  • Core Data pour le graphe d’objets, Core Animation pour le mouvement
  • Intents SiriKit là où la voix est réellement plus rapide
iOS, en profondeur

Swift tel qu’il se lit sur un vrai écran.

Un panneau de code est plus honnête qu’une liste de fonctionnalités — c’est la forme du travail iOS, pas une description de celui-ci.

Sur iOS je m’appuie sur SwiftUI pour les nouvelles surfaces et Core Data pour le graphe d’objets derrière elles. L’extrait ci-dessous est du genre que j’écris quotidiennement : un modèle petit et typé, un fetch que la vue peut observer, et une mise en page qui reste déclarative. C’est délibérément ordinaire — l’intérêt de la fluidité native, c’est que le code de routine soit propre, pas malin.

ContactList.swiftSwift · SwiftUI · Core Data
import SwiftUI
import CoreData

struct ContactList: View {
    @FetchRequest(
        sortDescriptors: [SortDescriptor(\.name)]
    ) private var contacts: FetchedResults<Contact>

    var body: some View {
        List(contacts) { contact in
            VStack(alignment: .leading) {
                Text(contact.name)
                    .font(.headline)
                Text(contact.phone)
                    .font(.subheadline)
                    .foregroundStyle(.secondary)
            }
        }
        .animation(.easeInOut, value: contacts.count)
    }
}
SwiftUI · UIKit Core Anim. SiriKit Core Data Swift · Objective-C

L’ensemble de frameworks iOS

SwiftUI au-dessus, Core Data en dessous, SiriKit là où la voix est plus rapide.

Les frameworks se composent : SwiftUI rend, Core Data persiste, Core Animation gère le mouvement que SwiftUI ne gère pas, et SiriKit expose le ou les deux intents où un raccourci parlé bat vraiment le toucher. Objective-C reste dans le tableau parce que les applications de longue durée en contiennent encore, et le lire fait partie de leur maintenance.

Rien de cela n’est ajouté pour soi-même. Chaque framework est dans l’application parce qu’un problème spécifique — persistance, mouvement, voix — l’a demandé.

  • SwiftUI pour les nouveaux écrans, UIKit gardé là où il marche
  • Core Data pour le graphe d’objets
  • Core Animation pour le mouvement au ressenti natif
  • Intents SiriKit seulement là où la voix est plus rapide
SwiftSwiftUICore DataSiriKit
Android, en profondeur

Kotlin contre l’Android SDK, fragmentation comprise.

Android récompense l’explicitude. L’extrait ci-dessous est un ViewModel Kotlin exposant l’état d’UI comme un flow — conscient du cycle de vie, survit aux changements de configuration, et fait son chargement hors du thread principal. Ayant livré sur de nombreuses versions d’OS, j’écris du code Android qui suppose la mort de processus et des limites d’arrière-plan strictes plutôt que d’espérer les éviter.

ContactViewModel.ktKotlin · Android SDK
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch

class ContactViewModel(
    private val repo: ContactRepository
) : ViewModel() {
    private val _state =
        MutableStateFlow<UiState>(UiState.Loading)
    val state: StateFlow<UiState> = _state.asStateFlow()

    init {
        viewModelScope.launch {
            runCatching { repo.loadContacts() }
                .onSuccess { _state.value = UiState.Ready(it) }
                .onFailure { _state.value = UiState.Error }
        }
    }
}
VERSIONS D’OS SUPPORTÉES min pic dernière

De nombreuses versions d’OS, de vrais appareils

Supporter les téléphones que les utilisateurs portent, pas celui de la keynote.

La fragmentation Android n’est pas un problème dont se plaindre — c’est l’environnement. Le travail, c’est de choisir un SDK minimum honnête, de tester l’éventail de versions et de tailles d’écran que la base d’utilisateurs réelle fait tourner, et de gérer les règles d’arrière-plan et de permissions qui se resserrent à chaque version.

Java reste dans la boîte à outils aux côtés de Kotlin pour la même raison qu’Objective-C sur iOS : le code livré vit longtemps, et le maintenir signifie le lire couramment.

  • Kotlin et Java contre l’Android SDK
  • Choix honnêtes de SDK minimum
  • Testé sur les versions que les utilisateurs font tourner
  • Gestion explicite de l’arrière-plan et des permissions
KotlinJavaAndroid SDKLifecycle
Architecture de l’app

La forme d’une application, dessinée de l’UI au magasin de données.

Une application mobile est une pile de couches claires — et la discipline, c’est de les garder claires pour que chacune puisse être testée et remplacée seule.

Quelle que soit la plateforme, l’architecture vers laquelle je me tourne est la même dans l’esprit : une couche UI qui ne fait que rendre l’état, une couche domaine qui tient la logique, une couche données qui parle au réseau et au magasin de l’appareil, et une frontière de sync entre les deux. Le diagramme montre les couches et la direction unique vers laquelle pointent les dépendances.

Garder les flèches pointant dans un sens, c’est ce qui rend l’application maintenable un an plus tard — l’UI n’atteint pas le réseau, et le réseau ne connaît pas l’UI. La même forme tient que le client soit Swift, Kotlin, React Native ou Flutter.

COUCHE UI SwiftUI · Compose · RN · Flutter COUCHE DOMAINE logique · règles · état COUCHE DONNÉES dépôts · ORMs SQLite sur appareil RÉSEAU REST · GraphQL

UI → domaine → données → magasin

Quatre couches, dépendances pointant dans un seul sens.

L’UI observe l’état et émet des intents ; la couche domaine décide ; la couche données récupère et persiste ; SQLite tient la vérité sur l’appareil et le réseau porte le reste. Chaque frontière est un endroit où je peux mettre un test ou échanger une implémentation sans que les couches au-dessus s’en aperçoivent.

Ce n’est pas de l’architecture pour elle-même. C’est la structure qui a permis à onze ans d’applications de continuer à accepter des fonctionnalités sans s’effondrer sous elles.

  • L’UI rend l’état, n’atteint jamais le réseau
  • La couche domaine tient la logique et les règles
  • La couche données possède le réseau et la persistance de l’appareil
  • SQLite comme source de vérité sur l’appareil
ArchitectureCouchesTestable
Backends

Le côté serveur de chaque application mobile.

Un client mobile ne vaut que le backend auquel il parle — alors je construis ce backend aussi, dans le framework qui convient à l’équipe.

Derrière les applications, j’ai livré Node/Express, Spring Boot, Django, Flask, Ruby on Rails et Go avec Gin et Gorm. Le framework est choisi pour l’équipe et le budget de latence, pas par habitude : Node là où l’équipe maîtrise JavaScript, Spring là où c’est une maison JVM, Django ou Flask pour des backends lourds en Python, Rails pour du CRUD piloté par convention, et Go là où le budget par requête est serré.

Chacun expose un contrat — REST ou GraphQL — contre lequel le client mobile est construit, persiste via des ORMs comme Sequelize et Mongoose, et cache le chemin chaud dans Redis. Le processus ci-dessous est le même quel que soit le framework au milieu.

Du contrat à un appareil synchronisé

  1. 01 Définir le contrat Schéma REST ou GraphQL convenu d’abord — le client et le serveur sont construits contre un contrat, pas l’un contre l’autre.
  2. 02 Choisir le framework Node/Express, Spring Boot, Django/Flask, Rails ou Go (Gin/Gorm) — choisi pour convenir à l’équipe et au budget de latence.
  3. 03 Modéliser les données ORMs — Sequelize ou Mongoose — sur le magasin relationnel ou documentaire dont le domaine a réellement besoin.
  4. 04 Cacher le chemin chaud Redis devant les lectures coûteuses, avec une invalidation explicite plutôt que des TTL pleins d’espoir.
  5. 05 Synchroniser l’appareil SQLite sur l’appareil, un protocole de sync sur le contrat, résolution de conflits définie avant d’en avoir besoin.
  6. 06 Livrer le pipeline Builds signés, tests automatisés, livraison aux stores — la CI qui transforme un commit en un build qu’un utilisateur peut installer.
handler.goGo · Gin · Gorm
func GetContact(c *gin.Context) {
    id := c.Param("id")
    if cached, err := rdb.Get(ctx, id).Result();
        err == nil {
        c.Data(200, "application/json",
            []byte(cached))
        return
    }
    var contact Contact
    if err := db.First(&contact, id).Error;
        err != nil {
        c.JSON(404, gin.H{"error": "not found"})
        return
    }
    c.JSON(200, contact)
}

Un handler Go, tel qu’il se livre

REST et GraphQL, servis vite et typés.

L’extrait est un handler Gin lisant via Gorm avec un cache Redis devant lui — la forme petite et répétable d’un endpoint sur lequel un client mobile peut compter : une réponse typée, une erreur prévisible, et un cache qui décharge la base de données sur le chemin chaud.

Que le framework soit Go, Node ou Spring, le contrat que le téléphone voit est le même. C’est l’intérêt de le convenir d’abord.

  • Go avec Gin et Gorm sur les chemins à budget serré
  • Redis cachant les lectures coûteuses
  • Réponses typées, formes d’erreur prévisibles
  • Même contrat quel que soit le framework
GoGinGormRedisREST

La stack mobile complète — du client au cloud

Langages iOS
Swift · Objective-C
Frameworks iOS
SwiftUI · UIKit · Core Data · Core Animation · SiriKit
Langages Android
Kotlin · Java
Cible Android
Android SDK, de nombreuses versions d’OS
Multiplateforme
React Native · Flutter (avancé) · Xamarin (opérationnel)
Bureau
Clients Windows
Backends
Node/Express · Spring Boot · Django/Flask · Rails · Go (Gin/Gorm)
APIs
REST · GraphQL
Sur appareil / données
SQLite · Redis · Sequelize · Mongoose
Cloud mobile
Firebase · AWS · Google Cloud
Métier du frontend
HTML5 · CSS3 · SASS/SCSS · JS ES6+ · TypeScript
Offline-first

Quand le réseau échoue — et sur un téléphone, il le fera.

Un téléphone traverse tunnels, ascenseurs et zones mortes. Une application qui suppose la connectivité est une application qui reste bloquée sur un spinner devant un vrai utilisateur.

Je construis des applications mobiles offline-first : l’appareil écrit immédiatement dans SQLite et met le changement en file pour sync, de sorte que l’utilisateur n’attend jamais le réseau pour voir sa propre action prendre effet. Quand la connectivité revient, la file se vide sur le contrat REST ou GraphQL, et les conflits sont résolus par une politique décidée par entité avant même d’en avoir besoin.

Le diagramme trace cette boucle — écriture locale, file, sync, réconciliation — et le mode de défaillance est la partie qui compte : l’application dégrade en lecture seule plutôt que de perdre une écriture en silence. C’est la différence entre une application en laquelle les utilisateurs ont confiance et une qu’ils abandonnent.

APPAREIL écriture SQLite FILE en attente SERVEUR réconcilier MAGASIN Redis · ORM hors ligne sync (REST/GraphQL) état résolu retourné

Écriture locale → file → sync → réconcilier

L’appareil est la source de vérité jusqu’à ce que le serveur soit d’accord.

Chaque écriture atterrit d’abord dans SQLite et est reflétée dans une file de sync. Une sync en arrière-plan vide la file contre le serveur, le serveur réconcilie en utilisant des lectures soutenues par Redis et le magasin mappé par l’ORM, et l’état résolu revient à l’appareil. L’utilisateur voit un retour local instantané et une cohérence à terme, pas un spinner.

Concevoir la politique de conflits à l’avance — last-write-wins, fusion ou manuelle — c’est ce qui garde la boucle honnête quand deux appareils éditent le même enregistrement.

  • Écriture locale dans SQLite avant tout appel réseau
  • Changement mis en file, vidé quand la connectivité revient
  • Politique de conflits définie par entité à l’avance
  • Dégrader en lecture seule, ne jamais perdre une écriture
Offline-firstSQLiteSyncRésolution de conflits

Offline-first — le contrat avec le réseau

Magasin sur appareil
SQLite — la source de vérité hors ligne
Chemin d’écriture
Écriture locale d’abord, mise en file pour sync
Transport de sync
REST ou GraphQL sur le contrat convenu
Politique de conflits
Définie par entité avant d’en avoir besoin
Cache serveur
Redis devant les lectures coûteuses
Magasin serveur
Relationnel ou documentaire, via Sequelize ou Mongoose
Mode de défaillance
Dégrader en lecture seule, jamais perdre une écriture en silence

L’utilisateur ne devrait jamais attendre le réseau pour voir sa propre action. Écrire localement, synchroniser en arrière-plan, et ne jamais perdre une écriture — c’est toute la discipline offline-first.

Cloud mobile

Firebase, AWS et Google Cloud — choisis par adéquation.

Le cloud n’est pas une seule décision. Une petite équipe a besoin d’un backend pour hier ; un produit qui scale a besoin de contrôle sur son calcul. Chaque onglet est une plateforme sur laquelle je déploie des backends mobiles, et le jugement sur le moment où chacune est la bonne réponse.

Firebase quand une petite équipe a besoin d’un backend pour hier

Firebase gagne sa place quand un produit mobile a besoin d’authentification, d’un magasin de données synchronisé et de push sans monter d’infrastructure d’abord. J’utilise Auth pour la connexion, Firestore pour les données structurées et interrogeables, et la Realtime Database là où le motif d’accès est réellement un arbre vivant plutôt que des documents.

La discipline, c’est de savoir où Firebase cesse d’être la bonne réponse — des règles de sécurité qui doivent encoder une vraie autorisation, et des coûts de lecture qui croissent avec un modèle de données naïf. Je conçois les documents autour des requêtes, pas l’inverse.

  • Auth pour la connexion, Firestore pour les données structurées
  • Realtime Database là où un arbre vivant convient au motif d’accès
  • Règles de sécurité traitées comme une vraie autorisation
  • Documents conçus autour des requêtes
MOBILE FIREBASE Auth · Firestore AWS Lambda · EC2 · S3 GCP App Eng · Compute un client, le backend qui convient à la charge

Où le backend tourne vraiment

Géré là où cela épargne du travail, contrôlé là où il le faut.

Firebase Auth et Firestore montent un backend synchronisé sans infrastructure ; Lambda et EC2 donnent du calcul serverless et de longue durée sur AWS ; App Engine et Compute Engine font l’équivalent sur Google Cloud ; S3 tient les médias qu’un téléphone télécharge. Le diagramme mappe le client sur ces options.

La contrainte mobile traverse tout cela : les démarrages à froid se ressentent sur un téléphone, et les uploads doivent survivre à un lien cellulaire. Le cloud est choisi pour que la latence que l’utilisateur perçoit reste dans le budget.

  • Firebase — Auth, Firestore, Realtime Database
  • AWS — Lambda, EC2, S3
  • Google Cloud — App Engine, Compute Engine
  • Choisi par adéquation opérationnelle, latence dans le budget
FirebaseAWSGoogle CloudServerless
Multiplateforme, en profondeur

React Native et Flutter — un choix, pas un défaut.

Les stacks multiplateformes permettent à une équipe de livrer les deux stores depuis une seule base de code, et je maîtrise React Native et Flutter à un niveau avancé. Mais la raison pour laquelle je leur fais confiance, c’est que j’ai livré natif d’abord : je sais exactement ce que le pont m’épargne et où il gêne. Quand un écran a besoin de Core Animation, d’un capteur que le pont n’expose pas proprement, ou d’un comportement de plateforme que l’abstraction masque, je descends à un module natif sans hésiter.

Xamarin se situe à un niveau opérationnel dans la boîte à outils, ce qui est la bonne réponse dans les organisations orientées .NET où le reste de la stack est déjà en C#. La décision entre eux n’est jamais une affaire de loyauté — c’est d’ajuster la stack à l’équipe et au produit, avec le natif toujours disponible en dessous.

BASE DE CODE PARTAGÉE React Native · Flutter RENDU iOS RENDU ANDROID module Swift module Kotlin

Une base de code, deux stores, trappe d’évasion native

Logique métier partagée en haut, modules natifs là où le pont s’arrête.

Dans une application multiplateforme, la logique métier et la majeure partie de l’UI vivent dans une seule base de code partagée — React Native ou Flutter — qui rend à la fois iOS et Android. Les parties que l’abstraction ne peut servir descendent jusqu’à des modules natifs en Swift et Kotlin, de sorte que l’application n’échange jamais la capacité contre la portabilité.

Cette trappe d’évasion est toute la raison pour laquelle la fluidité native compte même sur un projet multiplateforme. La couche partagée couvre le terrain commun ; les modules natifs couvrent les bords.

  • Logique et UI partagées dans une seule base de code
  • Rend à la fois iOS et Android
  • Modules natifs en Swift / Kotlin aux bords
  • La capacité jamais échangée contre la portabilité
React NativeFlutterModules natifs
CI pour mobile

Le pipeline qui transforme un commit en une installation.

La CI mobile est plus dure que la CI web — il y a deux chaînes d’outils, la signature de code, et deux processus de revue de store entre le commit et l’utilisateur.

Un release mobile n’est pas un déploiement ; c’est un build, une signature et une soumission. Le pipeline que je fais tourner lint et type-check d’abord, puis construit l’archive iOS avec Xcode et la signe, construit l’APK ou AAB Android signé avec Gradle, et livre des artefacts versionnés vers TestFlight et la piste interne avant le store. La règle est simple : pas de pipeline vert, pas de release.

Le diagramme ci-dessous montre cet éclatement — un commit, deux chaînes d’outils, deux stores — parce que le coût d’une erreur de signature de code ou de version est une soumission rejetée et un jour perdu, pas un redéploiement rapide.

COMMIT release CHECKS lint · type · test XCODE signe · archive GRADLE AAB signé App Store Play Store

Commit → vérifications → deux builds → deux stores

Un commit s’éclate en deux builds signés.

Le pipeline lance les vérifications statiques une fois, puis se divise : un chemin Xcode qui construit, signe et archive pour iOS, et un chemin Gradle qui assemble et signe pour Android. Chacun produit un artefact versionné qui va vers la piste de test de son store avant le release.

Traiter le build signé comme la seule chose qui se livre — jamais une archive locale de la machine de quelqu’un — c’est ce qui garde les releases reproductibles à travers onze ans d’applications.

  • Lint, type-check et tests unitaires comme porte
  • Xcode signe et archive pour iOS
  • Gradle assemble un APK/AAB signé pour Android
  • Artefacts versionnés vers les pistes de test, puis store
CISignature de codeTestFlightGradle

CI mobile — étape par étape

Déclencheur
Commit sur une branche de release
Vérifications statiques
Lint, type-check (TypeScript), tests unitaires
Build iOS
Build Xcode, signature de code, archive
Build Android
Gradle assemble, APK/AAB signé
Artefact
Build versionné par plateforme
Livraison
TestFlight / piste interne, puis store
Porte
Pas de pipeline vert, pas de release
Métier du frontend

Les surfaces web qui accompagnent l’application.

Un produit mobile est rarement seulement l’application. Il y a des pages d’onboarding, des surfaces marketing, des web views embarquées et de la logique partagée qui veulent tous le même soin que le code natif. Je les construis en HTML5 et CSS3 propres, j’organise les styles avec SASS/SCSS pour que le design system reste un système, et j’écris la logique en JavaScript moderne — ES6+ et TypeScript partout où le projet tolère un système de types.

TypeScript en particulier se rembourse sur mobile : un contrat typé attrape le décalage entre client et serveur avant qu’un utilisateur ne le voie, et les mêmes types peuvent circuler du schéma GraphQL jusqu’au client React Native.

01

HTML5 et CSS3

Les surfaces web qui accompagnent une application mobile — pages d’onboarding, marketing, web views embarquées — construites en HTML5 et CSS3 propres plutôt que jetées dans un framework par réflexe.

02

SASS/SCSS

Feuilles de style organisées avec SASS/SCSS pour que le design system reste un système : variables, partials et mixins au lieu de déclarations copiées.

03

JavaScript ES6+

JavaScript moderne pour la logique partagée et la couche web — modules, async/await, et les fonctionnalités du langage qui rendent une base de code lisible des années plus tard.

04

TypeScript

TypeScript partout où le projet le tolère, parce qu’un contrat typé attrape le décalage entre client et serveur avant qu’un utilisateur ne le voie.

05

APIs REST

REST pour les endpoints simples en forme de ressource, avec versionnage et formes d’erreur prévisibles sur lesquelles le client mobile peut compter.

06

APIs GraphQL

GraphQL là où un écran mobile a besoin exactement de ses données en un aller-retour — l’aller-retour réseau qu’un téléphone paie est celui qui vaut la peine d’être économisé.

Le parcours

Onze ans, une décision de plateforme à la fois.

Fondation, natif, multiplateforme, backend, cloud — le même ingénieur, suivant le travail à mesure que les produits dépassaient leurs premiers mille utilisateurs.

Lu en séquence, le travail mobile est une seule trajectoire continue plutôt qu’une liste de frameworks. Il commence par onze ans de livraison à de vrais utilisateurs, s’approfondit en iOS et Android natifs, s’étend à travers React Native et Flutter là où ils conviennent, revient vers les backends qui font d’un client plus qu’une coquille, et arrive aux clouds qui le scalent.

Ce qui traverse tout cela, c’est le même refus qui parcourt le reste de mon travail : l’application et le système derrière elle sont un seul problème, pas deux passés entre deux personnes.

  1. Fondation Onze années de livraison à de vrais utilisateurs La trajectoire qui ancre tout le reste : plus de onze ans à construire et livrer des applications mobiles que de vraies personnes ont installées et utilisées, sur iOS, Android et Windows.
  2. Natif iOS et Android dans leurs propres langages Swift et Objective-C sur iOS avec SwiftUI, Core Data, Core Animation et SiriKit ; Kotlin et Java sur Android sur de nombreuses versions d’OS. La fluidité native qui rend les choix multiplateformes informés.
  3. Multiplateforme React Native et Flutter à un niveau avancé Une équipe livrant deux stores là où cela convient, descendant aux modules natifs là où cela ne convient pas — plus Xamarin à un niveau opérationnel pour les équipes orientées .NET.
  4. Backend Le côté serveur de chaque application Node/Express, Spring Boot, Django/Flask, Rails et Go (Gin/Gorm), exposant REST et GraphQL, soutenus par SQLite, Redis et ORMs — les backends qui font d’un client mobile plus qu’une coquille mince.
  5. Cloud Firebase, AWS et Google Cloud Magasins de données gérés, calcul serverless et stockage choisis par adéquation opérationnelle — l’infrastructure qui scale une application au-delà de ses premiers mille utilisateurs.
Comment je travaille

Les principes sous les plateformes.

Les plateformes et frameworks changent avec le produit ; les principes, non. Voici les règles que j’applique que l’application soit Swift natif, Kotlin natif, React Native ou Flutter — la partie qui a transformé onze ans de travail mobile en applications qui ont continué à fonctionner plutôt qu’en un portfolio de lancements.

01

La fluidité native gagne l’abstraction

Parce que j’ai livré Swift et Kotlin directement, choisir React Native ou Flutter est un compromis mesuré, pas un moyen d’éviter d’apprendre une plateforme. Je sais ce que le pont m’épargne et ce qu’il me cache.

02

Le contrat passe en premier

Client et serveur sont construits contre un contrat REST ou GraphQL convenu, idéalement typé de bout en bout. L’intégration est conçue avant que l’un ou l’autre côté soit écrit, pas négociée après que les deux cassent.

03

Supposer que le réseau échouera

Un téléphone traverse des zones mortes. L’application écrit localement dans SQLite d’abord, met en file pour sync, et dégrade en lecture seule plutôt que de perdre une écriture ou de rester bloquée sur un spinner.

04

Respecter les règles de la plateforme

Limites d’arrière-plan, mort de processus, revue de store, signature de code — ce ne sont pas des obstacles à contourner. Travailler avec elles, c’est ce qui garde une application installée plutôt que désinstallée.

05

Tester la fragmentation

De nombreuses versions d’OS Android et un éventail d’appareils iOS signifient tester ce que les utilisateurs portent vraiment, pas affirmer que la dernière version couvre tout le monde.

06

Onze ans, c’est le titre

Chaque affirmation ici est étayée par des applications qui ont été livrées et qui le sont restées. La longévité est la preuve — pas un framework sur une diapositive, mais du logiciel qui a survécu au contact de vrais utilisateurs.

Onze ans d’applications livrées et restées livrées, voilà le titre. Tout le reste de cette page est vrai parce que cette seule chose l’est.

Open to the right work

Si votre produit est une application mobile et le backend, le cloud et le comportement hors ligne qui la rendent fiable, c’est tout le problème que je veux.

If you are holding a problem that doesn't fit inside one field, that is the conversation I want.

NextCloud & DevOps