Série: Aprendendo a Programar com IA

Quando a Demo Travou em Silêncio

Fazendo o engine se recusar a falhar em silêncio.

Quando a Demo Travou em Silêncio Parece terminada. Não faz nada. Não diz nada. INFO cena carregada INFO fallback de prefab... INFO ...mais 298 linhas enterrado em INFO ninguém vê PROMOVER ERROR MODO PLACEHOLDER: prefabs de gameplay ausentes, demo não vai funcionar sobrevive a qualquer filtro de log grep encontra instantaneamente
Degradação silenciosa é um defeito. O fallback tem que gritar.

Um crash te diz que algo está errado. Uma falha silenciosa entrega uma casca vazia e polida para seus usuários — e seus parceiros. O engine que ganha confiança é aquele que se recusa a sussurrar.

Existe uma classe de bug pior do que um crash. Um crash pelo menos te diz que algo está errado. O bug com o qual me sentei neste sábado de manhã era a outra coisa. A demo iniciava. A cena carregava. A UI renderizava. O menu de pausa não respondia. A jogabilidade era um placeholder. Nenhum erro. Nenhuma exceção. Nenhuma linha de log acima de INFO. O engine tinha falhado em silêncio e estava educadamente fingindo ser um jogo funcionando.

Este é o post sobre como fazer seu engine se recusar a fazer isso.

Como a demo parecia para um usuário

Iniciava limpo. Tela de splash. Tela de menu. Clique em “Play.” Transição de cena. Uma cena de aparência limpa. Uma nave no meio. Um placar no canto superior direito.

A nave não se movia. A entrada estava morta. O menu de pausa, quando invocado, estava visualmente presente mas não respondia a cliques. O placar dizia zero e continuava zero. Não havia inimigo para atirar. O mundo era uma casca educada, vazia, com aparência de funcionamento.

Para um desenvolvedor lendo isso, a conclusão é óbvia em trinta segundos: isso é um placeholder. Os prefabs reais de jogabilidade estão faltando. O engine caiu para um modo degradado e esqueceu de avisar alguém.

Para um usuário, esse é o pior tipo de falha. A aplicação não parece quebrada. Ela parece terminada, e ruim.

O que estava realmente errado

Dois problemas distintos, cada um sutil.

O carregador de cena estava degradando em silêncio. O SceneContentLoader é responsável por encontrar prefabs de jogabilidade e instanciá-los na cena ativa. Quando os prefabs estão faltando (por causa de um problema de build, um pacote de assets ausente, ou uma incompatibilidade de configuração), ele cai para uma configuração de placeholder. O fallback deveria registrar um erro claro. Ele estava registrando em INFO. A mensagem de erro estava enterrada em um fluxo de log não filtrado ao lado de outras trezentas linhas de INFO. Qualquer um rodando a demo e passando o olho pelo log não via nada alarmante.

O canvas do menu de pausa estava sem um GraphicRaycaster. Isso é uma coisa do lado da Unity. Um canvas que não tem um componente GraphicRaycaster não consegue receber eventos de ponteiro. O menu de pausa estava sendo instanciado corretamente, renderizando corretamente, e completamente surdo à entrada do usuário. A ausência do componente havia se infiltrado por meio de uma refatoração que consolidou várias configurações de canvas em uma só. A consolidação derrubou o raycaster em um dos canvases.

Os dois bugs tinham o mesmo sabor. Algo deu errado silenciosamente. O caminho de código continuou. O usuário viu algo que parecia funcionar mas não funcionava.

Como eu os encontrei

A auditoria demorou mais do que a correção. A correção levou uma tarde de sábado. A auditoria levou a manhã. O padrão que eu quero registrar porque vai se repetir.

A primeira pista foi que o placar estava travado em zero. Presumi que o bug do fim de semana passado (contagem dupla do placar) tinha sido corrigido demais. Errado. O placar estava zero porque não havia inimigos. Não havia inimigos porque os prefabs de jogabilidade não estavam carregando. Os prefabs não estavam carregando porque o carregador de conteúdo da cena estava caindo para um placeholder e avisando disso em nível INFO em vez de nível ERROR.

Uma vez que eu sabia disso, o segundo bug ficou óbvio. O menu de pausa não responder era um problema separado na mesma demo, revelado pela mesma sessão de sábado. O padrão de auditoria é “se você encontrou uma falha silenciosa, procure por outras adjacentes.”

O que eu corrigi

Um pequeno mas preciso conjunto de mudanças.

Promover o aviso de placeholder para ERROR. Quando o carregador de conteúdo da cena não consegue encontrar um prefab de jogabilidade real e cai para o modo placeholder, agora ele registra em ERROR com a mensagem “PLACEHOLDER MODE: gameplay prefabs missing, demo will not function correctly.” A severidade ERROR faz com que sobreviva a qualquer filtragem de log razoável. O texto exato “PLACEHOLDER MODE” é inconfundível quando você faz grep no log.

Adicionar um passo EnsureCrossPlatformInputManager. Mesmo no modo placeholder, o sistema de entrada deveria funcionar. Se um desenvolvedor está testando a demo no modo placeholder (porque está trabalhando na UI sem o pacote completo de assets), ele precisa conseguir interagir com os menus. O bootstrap agora garante que um singleton CrossPlatformInputManager exista em qualquer cena, mesmo as de placeholder.

Adicionar GraphicRaycaster automaticamente aos canvases que precisam dele. A correção defensiva é fazer o auxiliar de criação de canvas verificar o componente GraphicRaycaster e adicioná-lo se estiver ausente. Isso não vai encobrir futuros bugs da mesma forma, mas remove esse modo de falha específico das possibilidades.

Log de boot detalhado no AutoBootstrap. Quando a demo inicia, os logs agora imprimem um resumo curto de qual cena foi carregada, em qual modo ela carregou (real vs placeholder), e quais subsistemas estão presentes. Um desenvolvedor lendo o log consegue responder à pergunta “a demo iniciou no modo que eu esperava” em dez segundos. Antes desta manhã, a resposta exigia ler trezentas linhas de log e inferir.

Um teste de unidade para o auxiliar de canvas. Como o bug era um componente ausente, o tipo certo de teste é um que verifica se o componente está presente depois que o auxiliar roda. Esse teste está na suíte agora. Se alguém refatorar o auxiliar de canvas de um jeito que derrube o raycaster de novo, o teste vai falhar bem alto.

Para onde isso generaliza

Três padrões para levar desta manhã.

Falha silenciosa é o pior modo de falha. Em qualquer lugar onde seu código cai para um modo degradado, o fallback tem que gritar. Não em INFO. Em ERROR. Com uma string que o grep vai encontrar. Se o usuário não consegue perceber se o fallback disparou, o desenvolvedor lendo os logs três dias depois também não consegue.

Um componente ausente em um sistema orientado a configuração precisa de um teste. Unity, Unreal, qualquer engine onde uma cena é configurada a partir de componentes: a configuração pode se desviar silenciosamente. A defesa é um pequeno conjunto de testes que verificam “cena do tipo X tem componentes A, B, C.” Testes chatos. Testes críticos. Que vale a pena escrever.

Auditar por adjacência. Quando você encontra uma falha silenciosa, olhe para todo sistema adjacente. Bugs se agrupam. A mesma refatoração que derrubou o raycaster pode ter derrubado outros componentes em outros canvases. A mesma falha de disciplina de logging que enterrou o aviso de placeholder pode ter enterrado outros avisos. Investigue a vizinhança, não só o avistamento original.

O que parceiros e construtores devem tirar disso

Se você está construindo qualquer coisa onde o engine tem múltiplos modos degradados (asset ausente, rede fora do ar, SDK de fornecedor indisponível), o engine tem que te dizer em qual modo ele está, bem alto, toda vez. Degradação silenciosa é um defeito.

Se você está avaliando um engine para uma parceria, pergunte ao time como eles lidam com falhas silenciosas. A resposta certa é “nós expomos elas em ERROR com strings localizáveis por grep e temos auditorias para encontrá-las.” A resposta errada é “ainda não vimos esse problema.”

Se você está rodando um fluxo de trabalho orientado por agentes e seus agentes estão fazendo refatorações, as refatorações vão ocasionalmente derrubar componentes ou rebaixar a severidade de log por acidente. A correção é um pequeno portão de CI que verifica se componentes críticos estão presentes e se mensagens de log críticas sobrevivem na severidade certa. Não é glamouroso. É eficaz.

Tarde de sábado. A demo fala quando algo está errado. O menu de pausa responde a cliques de novo. A festa da demo vazia e educada acabou.

De volta a construir.

Um engine que te diz em qual modo ele está

O RakuAI expõe todo modo degradado bem alto, em ERROR, com strings localizáveis por grep e auditorias que encontram as falhas silenciosas primeiro. Essa é a disciplina de confiabilidade que um runtime espacial deve aos times que constroem sobre ele.

← Todos os posts