Six mois à construire Bookverse, seul
Il existe une version romantique du fait de construire un logiciel seul, où l’on a un bureau bien rangé, un espresso, et où l’on livre avant midi quelque chose que les gens adorent. La version que j’ai réellement vécue ces six derniers mois ressemble davantage à “réécrire quatre fois la même config Nginx parce que le septième cas limite vient de te mordre.”
Ceci est une réflexion — pas une checklist de ce qui a été livré, pas un tutoriel. Juste des notes après six mois là-dedans.
Pourquoi j’ai commencé
J’utilisais des applis de langues par intermittence depuis des années et j’ai remarqué quelque chose de précis : je pouvais boucler une série de 30 jours sur la fameuse appli gamifiée et rester incapable de lire un paragraphe de texte natif. La boucle de feedback était serrée, la gamification était léchée, mais l’unité de progression était une phrase, parfois un mot. Et lire des langues — vraiment les lire — se passe à l’échelle des pages.
Je voulais une appli qui traite un manuel comme un manuel. Ouvre le chapitre un. Lis-le. Écoute-le. Répète-le à voix haute. Étudie ce qui est resté. Demain, le chapitre deux.
La forme du produit était claire dès le premier jour. Le piège, c’est que “forme claire dès le premier jour” ne représente que 5% environ de la construction d’un logiciel. Les 95% restants, c’est le milieu sans gloire.
Le milieu sans gloire
Une liste non exhaustive de choses que j’ai faites ce trimestre et qui ne figurent dans aucune note de version :
- Renommé toute une arborescence de chemins de monorepo de
app_v54_01enbookverse(puis renommé de nouveau quand j’ai voulu des underscores dans le nom de l’unité systemd). - Écrit quatre versions d’une config Terraform pour des vhosts Nginx avant de
découvrir qu’un trigger
null_resourcedevait inclure le hash du template rendu, pas seulement les variables d’entrée. - Passé une semaine à traquer pourquoi une valeur d’environnement
EXPO_PUBLIC_*se résolvait en chaîne vide dans le bundle web mais fonctionnait très bien sur iOS. (Lepreset-expode Babel saute l’inlining pournode_modules. Des fonctions factory, pas des variables d’environnement, dans les paquets publiés.) - Refactorisé 17 appelants d’un helper d’URL d’API parce que je l’avais mal centralisé la première fois.
Rien de tout ça ne figurerait dans un billet marketing sur l’appli. Tout cela était le vrai travail.
Ce dont personne ne te prévient à propos du développement en solo, c’est qu’il n’y a personne pour absorber la moitié ennuyeuse. Tu ne peux pas dire “l’équipe plateforme gère les déploiements” parce que c’est toi l’équipe plateforme. Tu portes chaque casquette maladroitement jusqu’à l’avoir portée assez longtemps pour bien la porter.
Le terrier de la reconnaissance vocale
L’épisode le plus instructif des six derniers mois a été de faire fonctionner la pratique orale sur les téléphones en Chine.
Le plan : tu tapes sur une ligne, tu entends un locuteur natif la dire, tu
tapes de nouveau, tu t’enregistres, tu vois à quel point tu t’en es
approché. De la reconnaissance vocale mobile standard —
expo-speech-recognition sur iOS, le service système sur Android, terminé.
La réalité : une partie du public cible utilise des téléphones Lenovo
Motorola avec la variante du système d’exploitation pour la région chinoise
(l’overlay gmsconfig.china), qui supprime entièrement Google Mobile
Services. Pas de speech-to-text système. L’appli marchait parfaitement dans
l’émulateur. Sur un Moto XT2507 à Pékin, elle plantait silencieusement.
Le correctif a pris environ trois semaines :
- Construire un patron adaptateur pour que l’appli puisse permuter les backends vocaux selon la plateforme — reconnaissance système là où elle est disponible, transcription cloud en repli.
- Ajouter un backend cloud de type Whisper (le
qwen3-asr-flashd’Alibaba via DashScope, puisque les appareils de la région chinoise peuvent l’atteindre sans VPN). - Régler la détection d’activité vocale pour que l’enregistrement s’arrête automatiquement quand tu finis de parler. (Seuil de -25 dBFS, fenêtre de silence de 600ms, lissée sur cinq échantillons — toute autre combinaison te coupait au milieu d’un mot ou ne s’arrêtait jamais.)
- Passer des envois
FormDatade React Native auuploadAsyncdeexpo-file-system, parce que leFormDatade RN était capricieux avec les blobs audio sur ces mêmes appareils.
La moitié de ces quatre puces, c’est plus de code que je n’en écris en une semaine typique. Rien de tout ça n’est “une fonctionnalité.” Tout était nécessaire pour que la fonctionnalité existe pour ceux qui en avaient besoin.
La leçon — répétée environ toutes les deux semaines — c’est que la partie difficile est rarement celle qu’on croit difficile. J’avais budgété un jour pour la reconnaissance vocale. Ça en a pris vingt.
La discipline de finir
La tentation, quand on construit en solo, est de courir après le nouveau qui brille. Une nouvelle fonctionnalité, c’est excitant. Le 47e ajustement d’un flux existant ne l’est pas. Alors tu accumules des fonctionnalités, dont aucune n’est tout à fait finie, et le produit ressemble à un cimetière de chantiers à moitié faits.
La discipline que je réapprends sans cesse : finis une chose correctement avant d’en commencer une autre. Le mandarin d’abord. Rends le mandarin vraiment bon. Puis le coréen. Puis l’anglais. La plateforme est faite pour livrer des cours structurés — mais le premier cours doit être la vitrine, celui qu’un apprenant pourrait réellement terminer.
Un cours de coréen planifié et construit à 5% n’aide personne. Un cours de mandarin terminé, qu’on peut lire de bout en bout, est un vrai produit.
Il en va de même pour les fonctionnalités. La pratique orale est restée trois mois sur la roadmap avant d’être livrée. Elle a été livrée en retard, mais elle a été livrée correctement — gérer le cas de la région chinoise était porteur pour qu’elle soit utilisable, pas un détail de finition à reporter.
Ce que je me dirais en novembre
Trois choses, si je pouvais envoyer une carte postale à la version de moi qui a commencé tout ça.
Arrête de renommer les choses. Un nom, ce n’est pas grave de se tromper le premier jour. Renommer de nouveau coûte le plus souvent plus que ça ne rapporte. (Je l’ai fait exactement quatre fois maintenant.)
Achète les livres structurés. J’ai passé des semaines à rebondir entre des listes de vocabulaire issues de forums. Les standards HSK 3.0 sont un véritable document publié. Acheter les livres structurés et les suivre est plus rapide que de rétro-concevoir ce qu’ils couvrent.
Le public est patient. Je n’arrêtais pas de penser que je devais livrer vite, sinon les gens perdraient l’intérêt. C’est l’inverse qui est vrai : les apprenants de langues sont par définition patients — ils s’engagent déjà dans une année de pratique. Ils n’ont pas besoin d’une démo le troisième jour. Ils ont besoin de quelque chose qui marche le trois centième jour.
La suite
Le mandarin continue de grandir — Band 1 et Band 2 sont en ligne, Band 3 est en cours d’audit. La rédaction du contenu du cours de coréen démarrera après la sortie de Band 3 du mandarin. Le côté plateforme est plus calme qu’il y a six mois, ce qui veut dire que plus de temps va au véritable contenu d’apprentissage — là où il devrait aller.
Si tu utilises Bookverse : merci. Sinon : ouvre un chapitre un de ces jours. Le premier est gratuit.