Digite o código você mesmo
(haskellforall.com)- Digitar o código você mesmo e praticar recriá-lo de memória testa entendimento e retenção com mais rigor do que copiar
- Freecoding é a capacidade de escrever código caractere por caractere mantendo sintaxe, tipos e nomes na cabeça, e continua sendo necessário mesmo na era das ferramentas
- Sintaxe não é ruído que atrapalha o pensamento de alto nível; ela comprime significado preciso e torna possível pensar em um nível mais alto
- Consultar tipos e esquemas de forma frouxa faz o design do sistema perder nitidez, e não entender o modelo de tipos aumenta o uso de escapes como
as any - Sem memória de nomes e compreensão do trabalho prévio, agentes tendem a criar implementações duplicadas e também fica mais difícil revisar saídas e testes
Por que você deve digitar o código você mesmo
- O curso “Learn X the hard way”, de Zed Shaw, recomendava não copiar e colar os exemplos, mas digitá-los manualmente; mais recentemente, passou a recomendar com ainda mais força apagar tudo após terminar o exercício e reconstruir de memória
- Na psicologia cognitiva, o fenômeno em que gerar ativamente um conteúdo melhora mais a compreensão do que consumi-lo passivamente é chamado de efeito de geração
- Como na frase de Richard Feynman, “O que eu não consigo criar, eu não entendo”, praticar recriar código com base na memória testa ao mesmo tempo compreensão e memória
- Isso não significa que, na era da programação com agentes, você não deva usar ferramentas; mas é preciso desenvolver, às vezes, a capacidade de escrever código caractere por caractere sem a conveniência delas
- Esse treino se concentra em manter na cabeça elementos detalhados da programação, como sintaxe, tipos e nomes, para que você consiga fazer “freecoding”
Freecoding e conhecimento detalhado na cabeça
- Freecoding é a capacidade de escrever código diretamente com base na memória, e isso só é possível mantendo na cabeça elementos fundamentais como sintaxe, tipos e nomes
-
Sintaxe e estrutura
- É preciso estar familiarizado com palavras-chave, pontuação e construções da linguagem
- Não se trata apenas de decorar gramática, mas de conseguir visualizar com precisão a forma do código
-
Tipos e esquemas
- É preciso estar familiarizado e confortável com o sistema de tipos e o modelo de dados
- Se você fica apenas no nível de consultar a cada momento as tabelas, colunas, relações e estrutura de tipos do projeto, o design em nível de sistema se torna difícil
-
Nomes
- Você precisa conseguir lembrar com precisão os nomes de funções, métodos, classes, imports, arquivos e pacotes
- Quando o projeto e as dependências mudam, esse conhecimento também precisa ser mantido atualizado
- Se você não consegue digitar com um nível razoável de precisão o código que imaginou mentalmente, na prática está mais perto de achar que entendeu do que de ter entendido com clareza
- O inglês não é uma linguagem tão precisa quanto o código, e isso também se conecta ao texto A sufficiently detailed spec is code, que argumenta que uma especificação suficientemente detalhada acaba se aproximando de código
A sintaxe torna possível o pensamento de alto nível
- Mesmo que IDEs ou agentes de código consigam acertar a sintaxe, a capacidade de lidar com ela diretamente continua importante
- Se você tem dificuldade para equilibrar parênteses, isso também pode levantar dúvidas sobre sua capacidade de conectar com fluidez premissas e conclusões lógicas de outras pessoas
- A atitude de ignorar detalhes pode se ligar a uma analfabetização funcional em que se comunica mais pelo clima geral do que por atenção clara ao significado das palavras
- Exemplos de prompts para LLM parecem plausíveis à primeira vista, mas, ao ler com atenção, incluem ao mesmo tempo instruções contraditórias
- “Não proponha ferramentas externas ou alternativas que não estejam incluídas nas skills listadas acima”
- “Se a tarefa exigir capacidades além das skills disponíveis, diga isso”
- A capacidade de lidar com precisão com gramática, ortografia e estrutura pequenas não está separada da capacidade de entender corretamente o panorama maior
- Sintaxe não é um detalhe que atrapalha o pensamento de alto nível, mas uma ferramenta mental que comprime e viabiliza formas mais elevadas de raciocínio
- Uma anotação de tipos pode ser mais precisa e concisa do que uma explicação em linguagem natural
x é um array de objetos, e cada objeto tem uma propriedade obrigatória `domain` que armazena uma string e uma propriedade opcional `port` que armazena um númerox : { domain: string, port?: number }[]
Tipos e esquemas são pistas centrais para o design do sistema
- Fred Brooks, em The Mythical Man-Month, diz que, se você mostrar as tabelas, a estrutura em geral fica clara mesmo sem fluxogramas
- Se você usa banco de dados, precisa conhecer de trás para frente as tabelas, os nomes das colunas e as relações do projeto
- Em vez de consultar essas informações de forma frouxa sempre que precisar, é preciso entendê-las antes e mantê-las na cabeça para possibilitar um design efetivo em nível de sistema
- Sem esse esforço, o esquema do banco tende a ficar tão confuso quanto o pensamento, com estruturas desnormalizadas cheias de dados redundantes e parecidos
- A experiência com linguagens fortemente tipadas como Rust ou Haskell evidencia bem as vantagens de ter um modelo mental forte de tipos
- Treinar um “verificador mental de tipos” ou um “borrow checker mental” preciso também ajuda quando se usa linguagens com tipagem mais fraca
- Sem exercitar esse músculo de raciocínio abstrato, fica mais fácil deixar passar até fundamentos de modelagem de dados como tornar estados inválidos impossíveis de representar
- Se você não entende como os tipos se encaixam, acaba espalhando
as anypelo código TypeScript - Se você não consegue suportar o desconforto de pensar em tipos no caminho normal, será ainda mais difícil suportar o caminho anormal de depurar erros de tipos
- Isso não significa que um Haskeller ou um Rustacean sempre escreva código melhor, mas, com todas as outras condições iguais, fluência em tipos ajuda
É preciso lembrar nomes para conseguir reutilizar
- Os nomes de funções, métodos, classes, imports, pacotes e arquivos mais usados no projeto ou nas dependências precisam vir à mente com facilidade
- Isso é uma forma específica de um princípio mais geral: estar familiarizado com o que já foi feito antes, isto é, com o trabalho prévio (prior art)
- Muita gente depende de agentes de código porque não conhece trabalhos prévios reutilizáveis que já fazem a funcionalidade desejada, e assim acaba fazendo o agente reinventar a roda
- Se você não conhece a existência de SaaS boilerplate projects, é fácil achar que o agente precisa fazer o scaffolding do zero
- Clonar um projeto open source comprovado e feito para esse propósito é mais rápido, mais barato e mais confiável do que pedir ao agente para fazer o mesmo trabalho
- Quando alguém prevê que um LLM poderá construir um navegador inteiro em poucos anos, é possível responder que isso já é viável hoje ao fazer um fork do Chromium, além de ser mais fácil de modificar e manter
- A memória de nomes também é importante para reutilização de código dentro do mesmo projeto ou empresa
- Se você não sabe o que procurar, não consegue construir em cima do trabalho dos colegas
Revisar a saída de agentes exige entendimento humano
- Agentes podem ajudar a explorar nomes e gerar código, mas surge um novo problema: se você consegue revisar o resultado de forma significativa
- Se você não conhece a funcionalidade existente, é difícil julgar se o agente está implementando algo duplicado
- Se você entende o código pior do que o agente, também fica difícil revisar adequadamente a qualidade da saída dele
- Você pode pedir ao agente para gerar testes, mas, se não examinar esses testes com atenção, eles próprios podem virar código sem sentido
- O exemplo real era de testes que não chamavam o código de implementação e apenas aplicavam diretamente
someouincludesa arrays e strings para verificar o valor esperadodescribe("abort detection logic", () => { it("detects aborted stopReason in messages", () => { const messages = [ { role: "assistant", stopReason: "aborted", content: [] }, ]; const isAborted = messages.some((m: any) => m.stopReason === "aborted"); expect(isAborted).toBe(true); }); it("detects abort in error string", () => { const error = "The operation was aborted"; const isAborted = error.includes("abort"); expect(isAborted).toBe(true); }); it("does not false-positive on normal errors", () => { const error = "Network timeout"; const isAborted = error.includes("abort"); expect(isAborted).toBe(false); }); it("does not false-positive on normal stop reasons", () => { const messages = [ { role: "assistant", stopReason: "stop", content: [] }, ]; const isAborted = messages.some((m: any) => m.stopReason === "aborted"); expect(isAborted).toBe(false); }); }); - O desenvolvimento de software tem muito atrito cotidiano, e, se você escolhe não superar o pequeno atrito de lembrar nomes, também tende a não superar o atrito maior de revisar testes
- Como agentes de código usam as instruções do usuário como contexto principal, um usuário intelectualmente preguiçoso pode empurrar o agente na mesma direção de preguiça
Persistência e domínio não são coisas separadas
- Eustress é um estresse benéfico; quando você se força a fazer algo novo e difícil, ganha tolerância a pequenos desconfortos e passa a conseguir enfrentar também os maiores
- Evitar sempre o desconforto leva a um ciclo vicioso de impotência e frustração crescentes
- Ao desenvolver precisão, memória e pensamento estrutural em uma área, você também melhora suas capacidades em outras
- Assim como LLMs generalizam a partir dos dados de treinamento, humanos também generalizam para outras áreas os hábitos e capacidades que desenvolvem em um domínio
- O desenvolvimento de software envolve, por natureza, sair regularmente da zona de conforto, em linha com o texto relacionado Software engineers are not (and should not be) technicians
1 comentários
Opiniões no Lobste.rs
Concordo totalmente. Depois de terminar um exercício, apagar o que você acabou de fazer e tentar refazer só de memória é realmente importante
Se travar, pode olhar pistas, mas poucas coisas são tão importantes quanto criar o hábito de reconstruir da memória, o máximo possível, o processo que você acabou de fazer
Mensagens de commit e documentação são melhores quando você digita por conta própria
Programadores tendem a não gostar desse tipo de escrita e facilmente pensam “o LLM pode escrever isso”, mas, ao escrever você mesmo, acaba encarando ao mesmo tempo a experiência do usuário e as decisões de implementação. Surgem revisões do tipo: “Para fazer X, passe
-Y... espera, isso é mesmo o melhor?” “Isto corrige X com Y... mas será que Z também não daria?”Ri da parte “se você tem dificuldade para balancear parênteses, fico em dúvida sobre o quão fluentemente conseguirá conectar as premissas lógicas e as conclusões de outra pessoa”, mas também me senti levemente atingido
Em minha defesa, às vezes as funções ficam grandes demais
Consertar lixo de vibe coding que você não entende também é, na prática, uma boa forma de aprender. Você acaba digitando bastante e trabalhando em contexto real, não no vácuo
Reescrevê-lo à mão virou uma oportunidade para recuperar a intuição de programação que tinha enferrujado nos últimos 8 meses. Gostei do resultado da reescrita e ela de fato funciona melhor. LLMs ainda são úteis para explicar coisas ou destravar pontos específicos, mas é muito melhor sentir que eu conheço a base de código inteira
Não entendo bem por que o prompt “nunca proponha ferramentas externas ou alternativas que não estejam entre as capacidades listadas. Se a tarefa exigir algo além das capacidades disponíveis para o trabalho, diga isso” seria composto de instruções contraditórias
Dizer “não é possível fazer isso com as capacidades fornecidas” é compatível com as duas instruções. Se a última frase fosse “diga quais capacidades são necessárias”, aí haveria conflito, mas na formulação atual não vejo contradição
A segunda frase parece instruir o modelo não a sugerir por negação a existência de ferramentas externas ou alternativas necessárias, mas sim a afirmar construtivamente essa existência
A frase “pessoas que não conseguem se expressar com clareza funcional quase sem exceção também têm dificuldade para escrever frases ortográfica ou gramaticalmente corretas” me parece um preconceito bem duro contra pessoas com dislexia ou simplesmente com formas diferentes de pensar
Claro, isso não significa que se afirmou o inverso, isto é, que escrever mal em ortografia ou gramática implique automaticamente falta de clareza funcional, mas, de um jeito ou de outro, é uma formulação pouco generosa
Pensando de forma mais construtiva, dá para considerar editores de nós. Sistemas baseados em nós têm muitos problemas nas implementações atuais, mas, se forem bem feitos, podem controlar a forma de escrever programas e eliminar de saída certos erros de sintaxe. Por exemplo, se um nó recebe uma string, você não pode passar um número. Não porque a restrição seja imposta no build ou em tempo de execução, mas porque simplesmente fica impossível “dizer” um número naquele lugar. Também dá para fazer com que intervalos errados de repetição, erros no número de argumentos ou desequilíbrio de parênteses sejam estruturalmente impossíveis
Escrever software com ferramentas que impõem certas restrições estruturalmente não significa que você não entende essas restrições. Significa apenas que você não precisa se preocupar em cometer acidentalmente esse tipo de erro. E sentir frustração quando a ferramenta não cuida de detalhes sintáticos como a quantidade de chaves de uma função ou a indentação de um bloco lógico também não significa que você não entende por que essa sintaxe importa
Usei sistemas de nós como exemplo porque eles removem o elemento de “jogar ali e esquecer” do LLM ou o aspecto de vibe coding com o cérebro desligado, isolando apenas a questão sintática. Sem LLM, o argumento focado em sintaxe fica bem mais fraco
Concordo com o restante do texto, mas acho muito equivocado tratar habilidade sintática como indicador fundamental da compreensão de código de alguém ou da capacidade de escrever bom código
Também entendo que foi um feedback de boa-fé, e não quero soar defensivo. Achei que tinha tentado formular isso de um jeito que não parecesse uma afirmação tão pouco generosa, mas estou aberto a outra redação ou estrutura que transmita a mesma ideia melhor
Ainda assim, não quero remover totalmente esse ponto. O cerne do que quero transmitir é que, quando alguém começa a evitar de forma experiencial um desconforto mental, normalmente ortografia e gramática são as primeiras coisas a desandar. Acho que dá para ajustar a afirmação para que pessoas com dislexia não sejam prejudicadas nesse processo