Seis meses construindo o Bookverse, sozinho

Existe uma versão romântica de construir software sozinho em que você tem uma mesa limpa, um espresso e lança algo que as pessoas amam antes da hora do almoço. A versão que de fato vivi nestes últimos seis meses parece mais com “escrever a mesma configuração de Nginx quatro vezes porque o sétimo caso extremo acabou de te morder.”

Isto é uma reflexão — não uma lista de coisas lançadas, nem um tutorial. Apenas anotações de seis meses dentro disso.

Por que comecei

Eu vinha usando apps de idiomas de forma intermitente havia anos e notei algo específico: eu conseguia completar uma sequência de 30 dias no popular app gamificado e ainda assim não conseguia ler um parágrafo de texto nativo. O ciclo de feedback era apertado, a gamificação era refinada, mas a unidade de progresso era uma frase, às vezes uma palavra. E ler idiomas — ler de verdade — acontece no nível das páginas.

Eu queria um app que tratasse um livro didático como um livro didático. Abra o capítulo um. Leia. Ouça. Diga de volta. Estude o que ficou. Amanhã, o capítulo dois.

O formato do produto estava claro desde o primeiro dia. A pegadinha é que “formato claro desde o primeiro dia” responde por talvez 5% da construção de software. Os outros 95% são o meio sem glamour.

O meio sem glamour

Uma lista não exaustiva de coisas que fiz neste trimestre e que não estão em nenhuma nota de versão:

  • Renomeei toda uma árvore de caminhos de um monorepo de app_v54_01 para bookverse (e renomeei de novo quando quis underscores no nome da unidade do systemd).
  • Escrevi quatro versões de uma configuração do Terraform para vhosts do Nginx antes de descobrir que um trigger de null_resource precisava incluir o hash do template renderizado, não apenas as variáveis de entrada.
  • Passei uma semana investigando por que um valor de ambiente EXPO_PUBLIC_* resolvia para uma string vazia no bundle web mas funcionava bem no iOS. (O preset-expo do Babel pula o inlining para node_modules. Funções factory, não variáveis de ambiente, nos pacotes publicados.)
  • Refatorei 17 chamadores de um helper de URL da API porque eu o havia centralizado de forma errada na primeira vez.

Nada disso entraria num post de marketing sobre o app. Tudo isso foi o trabalho de verdade.

O que ninguém te avisa sobre o desenvolvimento solo é que não há ninguém para absorver a metade chata. Você não pode dizer “o time de plataforma cuida dos deploys” porque você é o time de plataforma. Você usa cada chapéu mal até tê-lo usado tempo o bastante para usá-lo bem.

A toca do coelho do reconhecimento de fala

O episódio mais instrutivo dos últimos seis meses foi fazer a prática de fala funcionar em celulares na China.

O plano: você toca numa linha, ouve um falante nativo dizê-la, toca de novo, grava a si mesmo, vê quão perto você chegou. Reconhecimento de fala móvel padrão — expo-speech-recognition no iOS, o serviço do sistema no Android, pronto.

A realidade: uma parcela do público-alvo usa celulares Lenovo Motorola com a variante do sistema operacional da região da China (a sobreposição gmsconfig.china), que remove o Google Mobile Services por completo. Sem speech-to-text do sistema. O app funcionava perfeitamente no emulador. Num Moto XT2507 em Pequim, ele travava silenciosamente.

A correção levou cerca de três semanas:

  1. Construir um padrão de adaptador para que o app possa trocar os backends de fala por plataforma — reconhecimento do sistema onde disponível, transcrição na nuvem como fallback.
  2. Adicionar um backend de nuvem no estilo Whisper (o qwen3-asr-flash da Alibaba via DashScope, já que dispositivos da região da China conseguem alcançá-lo sem VPN).
  3. Ajustar a detecção de atividade de voz para que a gravação pare automaticamente quando você termina de falar. (Limiar de -25 dBFS, janela de silêncio de 600ms, suavizado sobre cinco amostras — qualquer outra combinação ou te cortava no meio da palavra ou nunca parava.)
  4. Trocar os uploads com FormData do React Native pelo uploadAsync do expo-file-system, porque o FormData do RN era instável com blobs de áudio nesses mesmos dispositivos.

Metade desses quatro itens é mais código do que escrevo numa semana típica. Nada disso é “uma funcionalidade.” Tudo foi necessário para a funcionalidade existir para quem precisava dela.

A lição — repetida a cada duas semanas, aproximadamente — é que a parte difícil raramente é a parte que você acha que será difícil. Reservei um dia para o reconhecimento de fala. Levou vinte.

A disciplina de terminar

A tentação ao construir sozinho é correr atrás do novo e brilhante. Uma funcionalidade nova é empolgante. O 47º ajuste num fluxo existente não é. Então você vai acumulando funcionalidades, nenhuma das quais está bem terminada, e o produto parece um cemitério de construções pela metade.

A disciplina que fico reaprendendo: termine uma coisa direito antes de começar a próxima. Mandarim primeiro. Deixe o mandarim realmente bom. Depois o coreano. Depois o inglês. A plataforma foi construída para entregar cursos estruturados — mas o primeiro curso tem de ser o carro-chefe, aquele que um aprendiz poderia de fato terminar.

Um curso de coreano planejado e 5% construído não ajuda ninguém. Um curso de mandarim terminado, que alguém possa ler do começo ao fim, é um produto real.

O mesmo vale para as funcionalidades. A prática de fala esteve no roadmap por três meses antes de ser lançada. Ela foi lançada atrasada, mas foi lançada corretamente — lidar com o caso da região da China era estrutural para que ela fosse utilizável, não um detalhe de polimento a adiar.

O que eu diria a mim mesmo em novembro

Três coisas, se eu pudesse enviar um cartão-postal de volta à versão de mim que começou isto.

Pare de renomear coisas. Um nome é algo que tudo bem errar no primeiro dia. Renomear de novo custa mais do que vale na maioria das vezes. (Já fiz isso exatamente quatro vezes até agora.)

Compre os livros estruturados. Passei semanas saltando entre listas de vocabulário de fóruns. Os padrões do HSK 3.0 são um documento publicado de verdade. Comprar os livros estruturados e segui-los é mais rápido do que fazer engenharia reversa do que eles cobrem.

O público é paciente. Eu ficava achando que precisava lançar rápido ou as pessoas perderiam o interesse. O contrário é verdade: aprendizes de idiomas são, por definição, pacientes — eles já estão se comprometendo com um ano de prática. Eles não precisam de uma demo no terceiro dia. Precisam de algo que funcione no tricentésimo dia.

O que vem a seguir

O mandarim segue crescendo — Band 1 e Band 2 estão no ar, Band 3 está sendo auditada agora. A autoria do conteúdo do curso de coreano começa depois que o Band 3 do mandarim for lançado. O lado da plataforma está mais calmo do que há seis meses, o que significa que mais tempo vai para o conteúdo de aprendizado de verdade — que é onde ele deveria estar.

Se você está usando o Bookverse: obrigado. Se não: abra um capítulo algum dia. O primeiro é grátis.

← Todos os posts