Série : Apprendre à coder avec l’IA

Quand la démo a planté en silence

Forcer le moteur à refuser d'échouer en silence.

Quand la démo a planté en silence A l'air terminé. Ne fait rien. Ne dit rien. INFO scene loaded INFO prefab fallback... INFO ...298 more lines enfoui en INFO personne ne le voit PROMOUVOIR ERROR PLACEHOLDER MODE: prefabs de gameplay manquants, la démo ne fonctionnera pas survit à tout filtre de log grep le trouve instantanément
La dégradation silencieuse est un défaut. Le repli doit crier.

Un plantage vous dit que quelque chose ne va pas. Un échec silencieux livre une coquille vide et soignée à vos utilisateurs — et à vos partenaires. Le moteur qui gagne la confiance est celui qui refuse de chuchoter.

Il existe une catégorie de bug pire qu’un plantage. Un plantage vous dit au moins que quelque chose ne va pas. Le bug avec lequel je me suis assis ce samedi matin était l’autre chose. La démo a démarré. La scène s’est chargée. L’interface s’est affichée. Le menu pause ne répondait pas. Le gameplay était un placeholder. Aucune erreur. Aucune exception. Aucune ligne de log au-dessus de INFO. Le moteur avait échoué silencieusement et faisait poliment semblant d’être un jeu fonctionnel.

Voici le billet sur comment forcer votre moteur à refuser de faire ça.

À quoi ressemblait la démo pour un utilisateur

Démarrage propre. Écran de splash. Écran de menu. Clic sur « Jouer ». Transition de scène. Une scène à l’apparence propre. Un vaisseau au milieu. Un affichage de score en haut à droite.

Le vaisseau ne bougeait pas. L’entrée était morte. Le menu pause, une fois invoqué, était visuellement présent mais insensible aux clics. Le score affichait zéro et restait à zéro. Il n’y avait aucun ennemi à abattre. Le monde était une coquille polie, vide, à l’apparence fonctionnelle.

Pour un développeur qui lit ceci, la conclusion est évidente en trente secondes : c’est un placeholder. Les vrais prefabs de gameplay sont manquants. Le moteur est retombé dans un mode dégradé et a oublié de le dire à quiconque.

Pour un utilisateur, c’est le pire genre d’échec. L’application n’a pas l’air cassée. Elle a l’air terminée, et mauvaise.

Ce qui n’allait vraiment pas

Deux problèmes distincts, chacun subtil.

Le chargeur de scène se dégradait silencieusement. Le SceneContentLoader est responsable de trouver les prefabs de gameplay et de les instancier dans la scène active. Quand les prefabs sont manquants (à cause d’un problème de build, d’un pack d’assets manquant, ou d’une incohérence de configuration), il retombe sur une configuration placeholder. Le repli était censé logguer une erreur claire. Il logguait en INFO. Le message d’erreur était enfoui dans un flux de log non filtré parmi trois cents autres lignes INFO. Quiconque exécutait la démo et parcourait le log rapidement ne voyait rien d’alarmant.

Le canvas du menu pause n’avait pas de GraphicRaycaster. C’est une chose côté Unity. Un canvas qui n’a pas de composant GraphicRaycaster ne peut pas recevoir d’événements de pointeur. Le menu pause était correctement instancié, correctement rendu, et complètement sourd à l’entrée utilisateur. L’absence du composant s’était glissée via un refactor qui avait consolidé plusieurs configurations de canvas en une seule. La consolidation avait fait tomber le raycaster sur l’un des canvas.

Les deux bugs avaient la même saveur. Quelque chose s’est mal passé silencieusement. Le chemin de code a continué. L’utilisateur a vu quelque chose qui avait l’air de fonctionner mais qui ne fonctionnait pas.

Comment je les ai trouvés

L’audit a pris plus de temps que la correction. La correction a pris un samedi après-midi. L’audit a pris la matinée. Le schéma que je veux noter, car il se répétera.

Le premier indice était que le score restait bloqué à zéro. J’ai supposé que le bug du week-end dernier (double comptage de score) avait été sur-corrigé. Faux. Le score était à zéro parce qu’il n’y avait pas d’ennemis. Il n’y avait pas d’ennemis parce que les prefabs de gameplay ne se chargeaient pas. Les prefabs ne se chargeaient pas parce que le chargeur de contenu de scène retombait sur un placeholder et le disait au niveau INFO au lieu du niveau ERROR.

Une fois que je le savais, le second bug est devenu évident. Le menu pause insensible était un problème séparé dans la même démo, mis au jour par la même session du samedi. Le schéma d’audit est « si vous avez trouvé un échec silencieux, cherchez-en des adjacents ».

Ce que j’ai corrigé

Un petit ensemble de changements précis.

Promouvoir l’avertissement placeholder en ERROR. Quand le chargeur de contenu de scène ne trouve pas de vrai prefab de gameplay et retombe en mode placeholder, il loggue maintenant en ERROR avec le message « PLACEHOLDER MODE: gameplay prefabs missing, demo will not function correctly ». La sévérité ERROR le fait survivre à tout filtrage de log raisonnable. Le texte exact « PLACEHOLDER MODE » est impossible à manquer quand on grep le log.

Ajouter une étape EnsureCrossPlatformInputManager. Même en mode placeholder, le système d’entrée doit fonctionner. Si un développeur teste la démo en mode placeholder (parce qu’il travaille sur l’interface sans le pack d’assets complet), il doit pouvoir interagir avec les menus. Le bootstrap garantit maintenant qu’un singleton CrossPlatformInputManager existe dans toute scène, même les placeholders.

Ajouter automatiquement GraphicRaycaster aux canvas qui en ont besoin. La correction défensive consiste à faire vérifier par l’assistant de création de canvas la présence du composant GraphicRaycaster et à l’ajouter s’il est manquant. Cela ne masquera pas de futurs bugs de la même forme, mais cela retire ce mode d’échec spécifique du champ des possibles.

Logging de boot verbeux dans AutoBootstrap. Quand la démo démarre, les logs impriment maintenant un court résumé de quelle scène a été chargée, dans quel mode elle a été chargée (réel vs placeholder), et quels sous-systèmes sont présents. Un développeur lisant le log peut répondre à la question « la démo a-t-elle démarré dans le mode attendu » en dix secondes. Avant ce matin, la réponse nécessitait de lire trois cents lignes de log et de déduire.

Un test unitaire pour l’assistant de canvas. Parce que le bug était un composant manquant, le bon type de test est celui qui affirme que le composant est présent après l’exécution de l’assistant. Ce test est dans la suite maintenant. Si quelqu’un refactorise l’assistant de canvas d’une façon qui fait retomber le raycaster à nouveau, le test échouera bruyamment.

Ce que cela généralise

Trois schémas à retenir de cette matinée.

L’échec silencieux est le pire mode d’échec. Partout où votre code retombe dans un mode dégradé, le repli doit crier. Pas en INFO. En ERROR. Avec une chaîne que grep trouvera. Si l’utilisateur ne peut pas dire si le repli s’est déclenché, le développeur qui lit les logs trois jours plus tard ne le peut pas non plus.

Un composant manquant dans un système piloté par configuration a besoin d’un test. Unity, Unreal, tout moteur où une scène est configurée à partir de composants : la configuration peut dériver silencieusement. La défense est un petit ensemble de tests qui affirment « la scène de type X a les composants A, B, C ». Des tests ennuyeux. Des tests critiques. Qui valent la peine d’être écrits.

Auditer par adjacence. Quand vous trouvez un échec silencieux, regardez chaque système adjacent. Les bugs se regroupent. Le même refactor qui a fait tomber le raycaster a peut-être fait tomber d’autres composants sur d’autres canvas. Le même relâchement de discipline de logging qui a enfoui l’avertissement placeholder a peut-être enfoui d’autres avertissements. Enquêtez sur le voisinage, pas seulement sur le repérage initial.

Ce que partenaires et bâtisseurs devraient en retenir

Si vous construisez quoi que ce soit où le moteur a plusieurs modes dégradés (asset manquant, réseau coupé, SDK fournisseur indisponible), le moteur doit vous dire dans quel mode il se trouve, bruyamment, à chaque fois. La dégradation silencieuse est un défaut.

Si vous évaluez un moteur pour un partenariat, demandez à l’équipe comment ils gèrent les échecs silencieux. La bonne réponse est « nous les faisons remonter en ERROR avec des chaînes grep-ables et nous avons des audits pour les trouver ». La mauvaise réponse est « nous n’avons pas encore vu ce problème ».

Si vous exécutez un flux de travail piloté par agents et que vos agents font des refactors, les refactors feront occasionnellement tomber des composants ou dégraderont accidentellement la sévérité des logs. La correction est un petit garde-fou CI qui vérifie que les composants critiques sont présents et que les messages de log critiques survivent à la bonne sévérité. Pas glamour. Efficace.

Samedi après-midi. La démo parle quand quelque chose ne va pas. Le menu pause répond de nouveau aux clics. La fête avec la démo vide et polie est terminée.

Retour à la construction.

Un moteur qui vous dit dans quel mode il se trouve

RakuAI fait remonter bruyamment chaque mode dégradé, en ERROR, avec des chaînes grep-ables et des audits qui trouvent les échecs silencieux en premier. C'est la discipline de fiabilité qu'un runtime spatial doit aux équipes qui construisent dessus.

← Tous les articles