En attente

« Le travail est fait. La suite ne dépend plus de moi. »

App Store Connect affiche « Waiting for Review ». Un badge jaune dans un onglet de navigateur. Des mois de travail, réduits à une position dans une file d’attente.

Il n’y a plus rien à corriger. Plus rien à optimiser. L’application est aussi aboutie que je peux la rendre, et maintenant quelqu’un chez Apple va décider si elle respecte leurs guidelines. J’ai mis la cafetière en route.

Ce qui va changer

De vrais utilisateurs trouveront des bogues que deux mois de tests en solo n’auront pas révélés. Quelqu’un utilisera l’application autrement que prévu. Le premier avis utilisateur signifiera que quelqu’un a utilisé l’application assez longtemps pour se forger une opinion. Ce n’est pas rien.

Ce qui ne change pas

La liste des ADR continue de s’allonger. Le code a encore des aspérités. La suite dépendra de ce que les vrais utilisateurs trouveront.

Le disque était plein. L’application fonctionne. C’était l’objectif.

Leçons

L’outillage est plus dur que le langage. Swift s’apprend en quelques semaines quand on vient d’un langage typé. Xcode, les certificats de signature, les entitlements, le bac à sable, les profils de provisionnement, la notarisation, App Store Connect : tout ça prend plus de temps. Le langage, c’est la partie facile. La plateforme, c’est le vrai parcours du combattant.

Le compilateur est de votre côté. Swift 6 en mode strict concurrency produit des erreurs qui semblent hostiles tant qu’on n’a pas compris ce qu’elles disent. Elles ont presque toujours raison. Une erreur d’isolation d’acteur, ce n’est pas de la bureaucratie : c’est le compilateur qui empêche une course de données qui se manifesterait par un plantage intermittent en production. Les erreurs du compilateur sont de l’information, pas des obstacles.

La documentation Apple est bonne quand elle existe. Quand elle n’existe pas, on lit les headers et les transcriptions de sessions WWDC d’il y a trois ans. La durée de vie de la documentation Apple, c’est environ une version majeure d’OS.

La performance exige de comprendre la plateforme. Le développement web cache le système sous-jacent derrière HTTP, JSON et les conventions du framework. Le développement natif macOS, non. getattrlistbulk face à FileManager.enumerator. Les files de dispatch et leurs assertions. La différence entre RSS et mémoire virtuelle. Ce ne sont pas des sujets exotiques. C’est la plateforme. Le scanner POSIX était presque deux fois plus rapide que FileManager. Cet écart est invisible sans mesure.

Ce que je ferais autrement

Commencer par le scanner POSIX. J’ai construit le scanner FileManager d’abord parce que c’était le choix évident. Basculer ensuite a coûté du temps. L’écart de performance justifiait la réécriture.

Ajouter PerfLogWriter plus tôt. L’infrastructure de journalisation des performances qui a permis de repérer les blocages du thread principal a été ajoutée trop tard. Mesurer va plus vite que deviner. Instrumenter d’abord.

Deux choses que je ne changerais pas : la localisation dès le départ, et la rédaction des ADR.

Localiser après coup, c’est pénible. Localiser au fil de l’eau, c’est juste une discipline. L’application est sortie en 11 langues. Ça ne serait pas arrivé en s’y prenant après coup.

Les Architecture Decision Records, ce sont 41 documents couvrant des choix qui n’étaient pas évidents sur le moment. Pendant le débogage du rejet App Store, j’ai pu retrouver exactement pourquoi NSWorkspace.openApplication était appelé de cette façon, et quelles alternatives avaient été envisagées. C’est plus rapide que de fouiller le git blame pour deviner l’intention.

À propos de GitHub Copilot

Je l’ai utilisé tout au long du projet.

Pour les décisions d’architecture, beaucoup moins. Il ne connaît pas les contraintes du projet. Il propose des motifs qui fonctionnent en général. Savoir si ces motifs conviennent ici demande un jugement qui ne vient que de la compréhension du problème concret.

Les plantages, l’optimisation mémoire, la découverte du scanner POSIX : tout ça a nécessité de lire la documentation, de lancer Instruments, de comprendre la plateforme. Copilot peut aider à écrire le code une fois qu’on sait quoi écrire. Savoir quoi écrire, c’est la partie difficile. Ça l’a toujours été.

Les décisions restaient les miennes. L’outil accélérait la saisie.

Le chiffre qui me surprend encore

5,2 millions de nœuds sur un scan complet du disque. C’est ce que contient réellement une installation macOS moderne. Fichiers, répertoires, liens symboliques, tous énumérés, tous dimensionnés, tous disposés dans un treemap en environ une minute (compilation Debug, M3 Pro). L’ordre de grandeur est réel.

Quand j’ai démarré ce projet, je ne savais pas si c’était faisable. La réponse a exigé de choisir le bon appel système, de comprendre pourquoi FileManager était lent, et de tout mesurer.

Le projet en chiffres :

MétriqueValeur
Commits~353
ADR41
Langues11
Cycles de soumission3
Gain de scan (POSIX vs FileManager)~1,7x
Mémoire (avant)1,2 Go
Mémoire (après)469 Mo
Détection de doublons113 à 397 groupes/s

L’application est dans la file d’attente. Le disque n’est plus plein. Parfois, le problème le plus simple produit l’ingénierie la plus intéressante.

References