Featured image of post Un incident stressant
photo pars j

Un incident stressant

Mes conseils avant de se lancer sur le Play Store

Read in English

Préambule

La semaine dernière, j’ai vécu un incident logiciel qui m’a particulièrement marqué. Pour ceux qui me connaissent ou si vous avez déjà lu d’autres de mes articles, vous savez que je travaille dans un domaine où je suis régulièrement amené à gérer des incidents.
Pourtant, le sujet dont j’aimerais vous parler n’a rien à voir avec mon travail.
Il porte sur mon projet bénévole.

Tout s’est bien terminé, mais j’aimerais vous raconter ce que j’en ai retenu.

J’ai commis une négligence, mais je me dis qu’il sera toujours plus pertinent partager cette expérience plutôt que de la garder pour moi, afin de ne pas reproduire les mêmes erreurs.
Cet article racontera l’histoire de cet incident afin d’évoquer les leçons à retenir. Si vous préférez une lecture rapide, vous pouvez directement sauter à cette partie : Leçons à retenir

Mise en contexte

Petite mise en contexte : je suis depuis 5 ans développeur d’une application Android de suivi de symptômes chroniques. Elle aide les gens à suivre leurs symptômes mais aussi leur style de vie afin de les aider à avoir des prises de notes rapides et des affichages clairs au quotidien.
Les données ne sont stockées nulle part en ligne. C’est un choix fort de ma part. Les données étant liées à la santé des utilisateurs, je ne veux être en aucun point relié à elles. Un stockage local, donc.
Les utilisateurs sont responsables de leurs fichiers de sauvegarde, et c’est très bien comme ça.

Je vous passe tout l’historique du développement, mais suite aux nombreuses vulnérabilités Android exposées et aux politiques Google sur Android en réponse à ces vulnérabilités, ma fonctionnalité d’export automatique de données ne pouvait plus fonctionner. Elle a donc été remplacée par un export manuel.
Je parle des données générées par l’utilisateur tout au long de l’utilisation de l’appli, afin qu’elles puissent être importées en cas d’effacement de données ou de changement de smartphone.

Autre précision, j’ai choisi de faire mon application en Angular, basée sur Ionic/Cordova. Choix certes discutable, mais ça me permettait d’utiliser Angular qui est une techno web que j’affectionne particulièrement, et d’envisager un jour du cross-platform.
Sans savoir que dans le futur j’allais détester Cordova, dont les fonctionnalités sont un peu limitées à mon goût.

5 ans plus tard, nous arrivons au lundi 1er décembre 2025.
À ce jour, 11 000 personnes, réparties sur une trentaine de pays, utilisent quotidiennement ou presque l’application.
J’ai à la base développé cette app pour moi seul et j’ai ensuite décidé de la mettre sur le Play Store pour en faire bénéficier des proches, mais je n’avais jamais envisagé une telle base d’utilisateurs.
Je n’avais d’ailleurs même pas envisagé le RUN tout court. La prod, ce n’était clairement pas mon truc avant de faire le travail que je pratique actuellement depuis 2 ans.

Je vais éviter de rentrer dans tout l’historique des 5 ans afin de me concentrer sur l’incident, et surtout ce que j’en ai tiré.
Le fait d’avoir pensé à l’époque que je pouvais livrer une app et la laisser vivre sans avoir besoin de la maintenir était d’une grande naïveté.
J’ai manqué de rigueur sur les mises à jour, ça a été ma première erreur.

Au fil du temps, pour toute technologie, des vulnérabilités sont exposées. Elles sont au fur et à mesure patchées au fil des différentes mises à jour Android. Mises à jour qui imposent régulièrement de nouvelles contraintes aux développeurs d’applications.
En fonction des mises à jour, en cas de manque d’assiduité, deux choses peuvent survenir pour l’application concernée :

  • Se faire suspendre du Play Store.
  • Rester sur le Play Store, mais ne pas être compatible avec les versions plus récentes d’Android.

1er décembre donc, ça fait 3-4 semaines que mon appli n’est plus téléchargeable par les dernières versions Android.
Je mets donc à jour le target SDK (API level cible) afin de rester conforme, et en profite pour donner des nouvelles sur le dev de l’app (de temps en temps je fais apparaître une popup qui donne des nouvelles lors de la mise à jour).
Cela implique des mises à jour de quelques dépendances et plugins Cordova.
Je fais mes tests habituels : je crée d’abord un debug build, je vérifie que tout va bien, puis une release build, je teste dans tous les sens, pas de régression, et ça part en prod.
Les mises à jour d’app sur Android prennent un temps aléatoire entre quelques heures et quelques jours. Je pars me coucher, sans savoir que j’allais me réveiller avec une mauvaise surprise.

L’incident

Ce qu’il s’est passé

Bon, assez parlé du contexte, venons-en au fait. Comme vous avez pu vous en douter ça ne s’est pas passé comme prévu, et mon réveil au 2 décembre fut particulièrement désagréable.
Une dizaine de mails d’utilisateurs m’indiquant le pire scénario possible : « J’ai perdu toutes mes données ».
4 d’entre elles ont commencé à venir me mettre des reviews à 1* sur le Play Store (mérité).

Ma journée de travail commence. Mon vrai travail étant ma priorité, je me contente de prendre rapidement le temps de faire les premiers réflexes d’incident critique :

  • Evaluer l’ampleur de l’impact
  • Rollback immédiat

Puis je commence ma journée de travail.

Coup de chance : la moitié des utilisateurs de l’application sont américains. La majorité des utilisateurs de l’application habitent dans un fuseau horaire en avance par rapport à la France. De plus, la mise à jour venait de passer depuis à peine une heure quand je me suis réveillé.

Ça signifie qu’il fait encore nuit pour la majeure partie des utilisateurs lorsque je fais le rollback. Sur 11 000 utilisateurs, seulement 100 sont potentiellement impactés (100 smartphones sur lesquels la version causant le problème est installée).
100 personnes qui perdent définitivement leurs données, c’est beaucoup trop, mais déjà bien plus bas que le pire scénario. Pour tous les autres, la mise à jour n’est déjà plus disponible.

À ma connaissance, une vingtaine de personnes auront été impactées par cet incident (mise à jour installée, app lancée, incident constaté, et n’avaient jamais fait de sauvegarde manuelle).
À ce moment, je me fiche complètement des mauvaises notes et des messages agressifs qui vont avec. Ce qui m’importe à ce moment-là, c’est que j’ai créé ce projet pour aider des gens, et que pour certains d’entre eux je viens de faire tout l’inverse.
Même si je sais que ce sont des adultes utilisant une application bénévole et gratuite, et que c’est à eux de gérer leurs données, la culpabilité me gagne rapidement.

Je réponds le plus vite possible à tous les gens qui m’ont contacté, que ce soit par e-mail ou via les reviews, et les informe de la situation.

Je n’ai aucune idée de ce qu’il s’est passé, mais je me concentre sur mon vrai travail. Le rollback est effectué, l’hémorragie est stoppée, je verrai la suite ce soir.
Le plan est pour moi évident : j’annule tout ce que j’ai prévu pour mes soirées de la semaine, et je passerai mes soirées entières après le travail sur l’incident jusqu’à ce que j’ai trouvé une solution.
S’ensuivent / parties de la nuit à troubleshooter.

A la 2ème nuit, le 3 décembre, les nerfs commencent à lâcher. J’ai passé deux double-journées de travail sans pause, et après des heures et des heures de troubleshooting, je ne trouve pas de piste.
La fatigue se fait déjà pas mal ressentir.
Je ne le savais pas, mais l’une de mes premières intuitions était la bonne, je n’avais juste pas réussi à la tester jusqu’au bout.
Pour celles et ceux que ça intéresse, voici le résumé de la root cause analysis.

Contexte technique

D’abord, petit contexte technique :
Une app Cordova est une application native (Android/iOS) qui embarque une WebView chargée d’exécuter une application web (HTML/CSS/JS) stockée localement, avec accès aux APIs natives via des plugins.

Bien que les fichiers soient locaux, la WebView sert l’application via un serveur interne lié à https://localhost, qui n’est pas un vrai serveur externe, mais une abstraction sécurisée fournie par la WebView pour faire fonctionner l’app comme une vraie app web moderne.

Les données locales sont stockées via IndexedDB, qui est une base de données NoSQL côté navigateur.

Root cause analysis

  • cordova-plugin-ionic-webview, l’un des plugins nécessaires au bon fonctionnement de l’app, celui qui justement fournit la webview, a subi une mise à jour majeure. Mise à jour nécessaire pour le niveau d’API que je visais, donc je l’avais faite.
  • Cette mise à jour contient un breaking change important : elle expose la webview non plus sur http:// localhost mais sur https:// localhost.
  • IndexedDB est strictement isolé par origin (protocole + domaine + port). En passant de http:// à https://, le navigateur considère que c’est une base de données totalement différente.
  • Du point de vue utilisateur, toutes les données ont été perdues. Elles sont en réalité devenues inaccessibles, ce qui est sensiblement différent.

Voici l’information majeure de cet incident : les données n’ont pas été perdues. Elles ne sont juste plus accessibles. Ça signifie que si je trouve un moyen de revenir vers http://, les utilisateurs retrouveront leurs données. Même mieux : les utilisateurs qui ont eu la mise à jour automatique mais qui n’ont pas encore ouvert l’appli ne se rendraient même pas compte de l’incident si je propose le fix à temps.

Cependant, une énorme contrainte est à prendre en compte : les données internes liées à une application Android ne sont plus accessibles sur des OS non rootés, et surtout, elles sont définitivement effacées à la moindre désinstallation de l’application.

Je contacte immédiatement tous les utilisateurs impactés avec qui je suis déjà en contact pour les avertir de ne surtout pas désinstaller l’app.
Tous me répondent favorablement, une seule l’avait déjà désinstallée par frustration. Par chance, il n’utilisait pas l’app depuis longtemps.

Commence alors la course contre la montre : plus vite je patch, plus je limite l’impact potentiel.
Ce n’est pas le moment de réfléchir à une solution propre et définitive, il faut penser efficace.

La résolution

Si un jour vous vous retrouvez confronté à un incident lié à un breaking change d’une de vos dépendances, le premier réflexe doit être de se dire que si la techno est bien faite, il n’ont probablement pas fait de breaking change sans mettre à disposition un moyen d’être rétrocompatible.
J’ai épluché les changelogs mais ils sont super incomplets, aucune info.
J’ai ensuite tenté de poser ma question à ChatGPT et Gemini, mais ils étaient complètement dans les choux. Eh oui, j’ai cédé à la tentation de la réponse facile, so 2025.

Revenons-en aux bonnes vieilles méthodes et cherchons sur StackOverflow, et je tombe sur ce thread : https://stackoverflow.com/questions/74049849/persist-indexeddb-in-cordova-app-when-app-updates qui indique le paramètre de config Cordova justement conçu pour assurer la rétrocompatibilité sur la gestion des fichiers. Ça ressemble fort à ce dont j’ai besoin.

Je tente le fix, et cette fois je fais les choses proprement : je crée un programme de beta-testing et m’inclus dedans pour faire la mise à jour via le Play Store comme le ferait un utilisateur sur la version en production. La boucle de feedback de cette méthode est abominable (parfois plusieurs heures), mais c’est le moyen le plus fiable de réellement tester une mise à jour.

J’étais parti du principe lors de la mise en prod que je n’avais pas touché au module de gestion des données et qu’il n’y avait aucune raison qu’une mise à jour de l’app impacte les données. Seule cette méthode m’aurait permis de m’apercevoir du problème.

Il est 2h du matin et j’ai ma réponse : ça marche.
Je lance alors la review en production et prends bien soin de désactiver la mise à jour automatique à la fin de la review (option justement conçue car personne ne sait quand la release devient dispo).
J’en profite pour placer une pop-up de mise à jour qui rappelle l’importance de faire des backups manuels.

Je communique encore une fois avec les utilisateurs impactés et vais me coucher. Je prends mon mal en patience.

Vendredi soir, la release est disponible. Je n’ai plus qu’à cliquer et ça part partout.
Hors de question de lancer la release juste avant de me coucher, je vais dormir, et lance la mise à jour dès le samedi matin afin d’avoir la journée pour faire de l’hypercare.
Je reçois alors des mails tout au long de la journée : « My data is back! ». Tous sont super contents et me remercient chaudement. Je respire à nouveau.

À l’heure où j’écris ces mots ça fait pile une semaine que tout va bien.

Bilan :

  • Impact potentiel initial : 11 000 utilisateurs
  • Impact potentiel suite au rollback : 100 utilisateurs
  • Impact réel : environ 20 utilisateurs
  • Impact irréversible : 1 utilisateur

Ça reste un utilisateur de trop donc pas de quoi être fier, sans parler de la gêne occasionnée pour les autres, mais tout de même heureux que le bilan soit bien plus léger que ce que j’ai pu penser en début d’incident.
Bien entendu, je ne parle ici que de la résolution de l’incident en soi. Cette solution n’est que temporaire, j’ai déjà commencé à travailler sur une solution de migration transparente pour ne pas dépendre de ce tag Cordova que j’ai dû ajouter (et qui risque de sauter dans le futur).

Voici la fin de cette histoire qui raconte l’incident logiciel qui fut probablement le plus stressant de ma vie.

Leçons à retenir

Si j’ai écrit ce blog post, c’est principalement pour cette partie qui est de loin la plus importante : les leçons que j’en ai tirées. Ce que je voudrais dire à mon moi du passé qui se lance naïvement dans son projet bénévole.
J’en profite pour placer des notions qui me paraissaient déjà à l’époque évidentes, mais qu’il est toujours bon de rappeler.

Anticiper le RUN. Un logiciel en production, ça vit. Dès lors qu’on lance quelque chose en production, on ne peut pas juste le laisser de côté. Quelle que soit la plateforme, il y aura toujours un minimum de RUN et un devoir de mise à jour. Si ça me paraît évident aujourd’hui, ça me le paraissait beaucoup moins il y a 5 ans.

Anticiper un éventuel succès. Ce n’est pas parce que vous n’avez jamais rien publié que votre travail sera vu par personne. Si votre création plaît, elle sera adoptée. Plus cette adoption est grande, plus on peut se sentir dépassé par son propre travail. Un projet bénévole ne doit pas devenir une épine dans le pied. Le travail futur doit s’anticiper.
C’est justement parce que j’ai commencé à le vivre comme un deuxième travail lorsque l’application a été adoptée par plusieurs milliers de personnes que j’ai fini par m’en détacher et manquer de rigueur sur les mises à jour.

Anticiper un canal de communication. Mon app est 100% locale, totalement coupée du réseau. C’est bien, mais quand on se retrouve à ne pas réussir à la mettre à jour, on se retrouve totalement coupé de toute communication avec les utilisateurs. Mettre en place un appel vers un service qui permet de faire afficher des messages d’urgence, peu importe la version de l’app, peut se révéler très utile.

Les mises à jour automatiques post-review n’ont aucun intérêt à part lancer une release critique à un moment où vous dormez. Si la date et l’heure de la fin de review sont aléatoires, la date de l’heure de la distribution en production ne doivent pas l’être.

Pas besoin de faire un full rollout. On peut très bien commencer par 10% des utilisateurs, et déployer progressivement pour limiter d’éventuels impacts.

Si un programme de beta-testing existe, il faut l’utiliser. Tester des releases directement en installant des apk ça fonctionne, mais ça ne montre ni le comportement réel de l’appli après avoir été packagée sur le Play Store, ni le comportement d’une réelle mise à jour. C’est long et frustrant, mais nécessaire. C’est le seul vrai test valable avant une mise en production d’une application Android sur le Play Store.

Communiquer rapidement. L’un des points les plus importants. Mon manager nous répète souvent qu’il y a une énorme différence de frustration pour un utilisateur entre un incident où personne ne communique, et un incident où les responsables communiquent rapidement. En ce qui me concerne j’ai très bien pu l’observer : des e-mails d’agacement se sont très vite transformés en message de compréhension et d’encouragements.

Creuser les pistes jusqu’au bout. Ça paraît aussi évident, mais après des heures de troubleshooting, on peut se retrouver découragé et finir comme le bonhomme du dessin connu qui s’arrête de creuser juste avant les diamants.

Ne pas céder à la panique. On évalue l’impact, on rollback, et on prend le temps d’analyser. C’est difficile quand on se retrouve dans une course contre la montre, mais c’est souvent ça les incidents. Garder son sang-froid est primmrdial. Ça c’est un conseil pour mon moi du passé, mais aussi mon moi du présent et celui du futur.

Si au moins un seul de ces conseils peut vous aider à ne pas faire les mêmes erreurs que moi, j’en serai ravi.

Mots de la fin

Si ça vous intéresse, l’application s’appelle Life-Notes.
Elle est disponible sur Android, en français et en anglais : https://life-notes.fr/

J’en ai actuellement repris le développement après des années de pause, de nouvelles fonctionnalités sont à venir !
Les mises à jour seront de nouveau régulières.

Si le sujet du RUN et de la gestion d’incidents vous intéresse, j’ai justement écrit et présenté une conférence à ce sujet à divers endroits en France : https://www.youtube.com/watch?v=HDDbCymVRhE

Généré avec Hugo
Thème Stack conçu par Jimmy