O conselho de “bom gosto” de Brian Kernighan mostra como código legível economiza tempo, reduz bugs e ajuda equipes reais a avançarem mais rápido do que truques espertos.

O nome de Brian Kernighan aparece em lugares que muitos desenvolvedores usam sem pensar: ferramentas clássicas do Unix, o ecossistema C e décadas de textos que ensinaram como explicar programas com clareza. Quer você se lembre de The C Programming Language (com Dennis Ritchie), The Unix Programming Environment, ou de seus ensaios e palestras, o fio condutor é a insistência em ideias simples expressas de forma limpa.
O melhor conselho de Kernighan não depende da sintaxe do C ou das convenções do Unix. Trata-se de como os humanos leem: escaneamos em busca de estrutura, confiamos em nomes, inferimos intenção e nos confundimos quando o código esconde significado por trás de truques. Por isso o “bom gosto” na legibilidade ainda importa quando você escreve TypeScript, Python, Go, Java ou Rust.
Linguagens mudam. Ferramentas melhoram. Equipes continuam entregando funcionalidades sob pressão de prazo, e a maior parte do código é mantida por alguém diferente do autor original (muitas vezes o você do futuro). Clareza é o multiplicador que torna tudo isso suportável.
Isto não é um tributo ao “herói do código” nem um apelo para memorizar regras antigas. É um guia prático de hábitos que tornam o código cotidiano mais fácil de trabalhar:
A influência de Kernighan importa porque aponta para um objetivo simples e amigo da equipe: escreva código que comunique. Quando o código lê como uma explicação clara, você gasta menos tempo decodificando e mais tempo melhorando.
“Bom gosto” em código legível não é sobre estilo pessoal, padrões sofisticados ou compactar uma solução nas poucas linhas possíveis. É o hábito de escolher a opção simples e clara que comunica intenção de forma confiável.
Uma solução de bom gosto responde a uma pergunta básica para o próximo leitor: O que este código tenta fazer, e por que faz assim? Se essa resposta exige malabarismos mentais, suposições ocultas ou decodificação de truques, o código está custando tempo à equipe.
A maior parte do código é lida muito mais do que é escrita. O “bom gosto” trata a leitura como a atividade primária:
Por isso legibilidade não é só estética (indentação, largura de linha, ou se você prefere snake_case). Essas coisas ajudam, mas “bom gosto” é principalmente sobre facilitar o raciocínio: nomes claros, fluxo de controle óbvio e estrutura previsível.
Um erro comum é otimizar pela brevidade em vez da clareza. Às vezes o código mais claro é um pouco mais longo porque torna os passos explícitos.
Por exemplo, compare duas abordagens:
A segunda versão pode acrescentar linhas, mas reduz a carga cognitiva necessária para verificar a correção. Também torna bugs mais fáceis de isolar e mudanças mais seguras de aplicar.
Bom gosto é saber quando parar de “melhorar” uma solução com esperteza e, em vez disso, deixar a intenção clara. Se um colega consegue entender o código sem pedir uma visita guiada, você escolheu bem.
Código esperto frequentemente parece uma vitória no momento: menos linhas, um truque elegante, um efeito “uau” no diff. Em uma equipe real, essa esperteza vira uma conta recorrente — paga em tempo de onboarding, tempo de revisão e hesitação sempre que alguém precisa mexer no código.
Onboarding desacelera. Novos colegas não precisam apenas aprender o produto; também têm que aprender seu dialeto privado de atalhos. Se entender uma função exige decodificar operadores espertos ou convenções implícitas, as pessoas vão evitar mudá-la — ou mudar com medo.
Revisões ficam mais longas e menos confiáveis. Revisores gastam energia provando que o truque está correto em vez de avaliar se o comportamento bate com a intenção. Pior, código esperto é mais difícil de simular mentalmente, então revisores perdem casos de borda que teriam percebido numa versão direta.
A esperteza se acumula durante:
Alguns repetidos infratores:
17, 0.618, -1) que codificam regras que ninguém lembra.\u0026\u0026 / ||) que dependem do leitor conhecer regras sutis de avaliação.O ponto de Kernighan sobre “gosto” aparece aqui: clareza não é escrever mais; é tornar a intenção óbvia. Se uma versão “esperta” economiza 20 segundos hoje mas custa 20 minutos para cada leitor futuro, não é esperta — é cara.
O “gosto” de Kernighan frequentemente aparece em decisões pequenas e repetíveis. Você não precisa de uma grande reescrita para tornar o código mais fácil de conviver — vitórias pequenas de clareza se acumulam toda vez que alguém escaneia um arquivo, procura um comportamento ou corrige um bug sob pressão.
Um bom nome reduz a necessidade de comentários e torna erros mais difíceis de esconder.
Tente nomes que revelem intenção e que coincidam com como sua equipe fala:
invoiceTotalCents em vez de sum.Se um nome te força a decodificá-lo, ele está fazendo o oposto do seu trabalho.
A maior parte da leitura é escaneamento. Espaçamento e estrutura consistentes ajudam o olho a encontrar o que importa: limites de função, condicionais e o “caminho feliz”.
Hábitos práticos:
Quando a lógica fica complicada, a legibilidade geralmente melhora ao tornar decisões explícitas.
Compare estes estilos:
// Harder to scan
if (user \u0026\u0026 user.active \u0026\u0026 !user.isBanned \u0026\u0026 (role === 'admin' || role === 'owner')) {
allow();
}
// Clearer
if (!user) return deny('missing user');
if (!user.active) return deny('inactive');
if (user.isBanned) return deny('banned');
if (role !== 'admin' \u0026\u0026 role !== 'owner') return deny('insufficient role');
allow();
A segunda versão é mais longa, mas lê-se como uma lista de verificação — e é mais fácil estender sem quebrar.
São escolhas “pequenas”, mas o ofício diário do código manutenível: nomes honestos, formatação que guia o leitor e fluxo de controle que evita malabarismos mentais.
O estilo de clareza de Kernighan aparece mais em como você divide o trabalho em funções e módulos. Um leitor deve conseguir passar os olhos pela estrutura, adivinhar o que cada peça faz e estar certo na maior parte antes de ler os detalhes.
Procure funções que façam exatamente uma coisa em um único “nível de zoom”. Quando uma função mistura validação, regras de negócio, formatação e I/O, o leitor precisa manter vários fios na cabeça.
Um teste rápido: se você se pega escrevendo comentários como “// agora faça X” dentro de uma função, X é muitas vezes um bom candidato a função separada com um nome claro.
Listas longas de parâmetros são um imposto oculto de complexidade: cada site de chamada vira um mini-arquivo de configuração.
Se vários parâmetros sempre viajam juntos, agrupe-os de forma ponderada. Objetos de opções (ou pequenos structs de dados) podem tornar sites de chamada autoexplicativos — se você mantiver o grupo coerente e evitar despejar tudo em uma sacola “misc”.
Além disso, prefira passar conceitos de domínio em vez de primitivos. UserId é melhor que string, e DateRange é melhor que (start, end) quando esses valores têm regras.
Módulos são promessas: “Tudo o que você precisa para este conceito está aqui, e o resto está em outro lugar.” Mantenha módulos pequenos o suficiente para que você consiga segurar seu propósito na cabeça, e projete limites que minimizem efeitos colaterais.
Hábitos práticos que ajudam:
Quando precisar de estado compartilhado, nomeie-o honestamente e documente as invariantes. Clareza não é evitar complexidade — é colocá-la onde os leitores esperam. Para mais sobre manter esses limites durante mudanças, veja /blog/refactoring-as-a-habit.
O “gosto” de Kernighan aparece em como você comenta: o objetivo não é anotar cada linha, é reduzir confusão futura. O melhor comentário é aquele que evita uma suposição errada — especialmente quando o código está correto mas é surpreendente.
Um comentário que repete o código (“incrementa i”) adiciona ruído e ensina leitores a ignorar comentários. Comentários úteis explicam intenção, trade-offs ou restrições que não ficam óbvias pela sintaxe.
# Bad: says what the code already says
retry_count += 1
# Good: explains why the retry is bounded
retry_count += 1 # Avoids throttling bans on repeated failures
Se você se sente tentado a escrever comentários de “o quê”, frequentemente é sinal de que o código deveria ser mais claro (nomes melhores, função menor, fluxo mais simples). Deixe o código carregar os fatos; deixe os comentários carregarem o raciocínio.
Nada destrói confiança mais rápido que um comentário obsoleto. Se um comentário é opcional, ele vai divergir com o tempo; se estiver errado, vira uma fonte ativa de bugs.
Um hábito prático: trate atualizações de comentário como parte da mudança, não como “bom ter”. Em revisões, é justo perguntar: Este comentário ainda bate com o comportamento? Se não, atualize ou remova. “Nenhum comentário” é melhor que “comentário errado”.
Comentários inline são para surpresas locais. Orientações mais amplas pertencem a docstrings, READMEs ou notas de desenvolvedor — especialmente para:
Uma boa docstring diz como usar a função corretamente e que erros esperar, sem narrar a implementação. Uma nota curta em /docs ou no README pode capturar a história do “por que fizemos assim” para sobreviver a refactors.
A vitória silenciosa: menos comentários, mas cada um justifica seu lugar.
A maior parte do código parece “ok” no caminho feliz. O teste real de gosto é o que acontece quando entradas faltam, serviços expiraram ou um usuário faz algo inesperado. Sob estresse, código esperto tende a esconder a verdade. Código claro torna a falha óbvia — e recuperável.
Mensagens de erro fazem parte do seu produto e do seu fluxo de debug. Escreva-as como se a próxima pessoa a lê-las estivesse cansada e de plantão.
Inclua:
Se tiver logging, acrescente contexto estruturado (como requestId, userId ou invoiceId) para que a mensagem seja acionável sem escavar dados não relacionados.
Há uma tentação de “lidar com tudo” com um one-liner esperto ou um catch-all genérico. Bom gosto é escolher os poucos casos de borda que importam e torná-los visíveis.
Por exemplo, um ramo explícito para “entrada vazia” ou “não encontrado” muitas vezes lê melhor do que uma cadeia de transformações que produz null implicitamente no meio. Quando um caso especial é importante, nomeie-o e coloque-o em destaque.
Misturar formas de retorno (às vezes um objeto, às vezes uma string, às vezes false) força leitores a manterem uma árvore de decisões mental. Prefira padrões que se mantenham consistentes:
Tratamento de falhas claro reduz surpresas — e surpresa é onde bugs e páginas à meia-noite prosperam.
Clareza não é só sobre o que você quis dizer ao escrever o código. É sobre o que a próxima pessoa espera ver ao abrir um arquivo às 16:55. Consistência transforma “ler código” em reconhecimento de padrões — menos surpresas, menos mal-entendidos, menos debates que se repetem a cada sprint.
Um bom guia de equipe é curto, específico e pragmático. Não tenta codificar toda preferência; resolve as questões recorrentes: convenções de nomes, estrutura de arquivos, padrões de tratamento de erro e o que significa “pronto” para testes.
O valor real é social: impede que a mesma discussão recomece a cada PR. Quando algo está escrito, revisões mudam de “prefiro X” para “concordamos com X (e aqui está o porquê)”. Mantenha-o vivo e fácil de achar — muitas equipes o deixam no repositório (por exemplo, /docs/style-guide.md) para que fique perto do código.
Use formatadores e linters para o que é mensurável e chato:
Isso libera humanos para focar em significado: nomes, forma da API, casos de borda e se o código corresponde à intenção.
Regras manuais ainda importam quando descrevem escolhas de design — por exemplo, “prefira retornos antecipados para reduzir aninhamento” ou “uma entrada pública por módulo”. Ferramentas não julgam isso completamente.
Às vezes a complexidade é justificada: orçamento apertado de desempenho, restrições embarcadas, concorrência complicada ou comportamento específico de plataforma. O acordo deve ser: exceções são permitidas, mas precisam ser explícitas.
Um padrão simples ajuda: documente o trade-off em um comentário curto, adicione um micro-benchmark ou medição quando desempenho for citado, e isole o código complexo atrás de uma interface clara para que a maior parte da base permaneça legível.
Uma boa revisão deveria parecer menos uma inspeção e mais uma pequena lição focada em “bom gosto”. O ponto de Kernighan não é que código esperto é maligno — é que esperteza é cara quando outras pessoas precisam conviver com ela. Revisões são onde a equipe pode tornar esse trade-off visível e escolher clareza de propósito.
Comece perguntando: “Um colega consegue entender isso em uma passada?” Isso normalmente significa olhar nomes, estrutura, testes e comportamento antes de mergulhar em micro-otimizações.
Se o código está correto mas difícil de ler, trate legibilidade como um defeito real. Sugira renomear variáveis para refletir intenção, dividir funções longas, simplificar fluxo de controle ou adicionar um teste pequeno que demonstre o comportamento esperado. Uma revisão que pega “isso funciona, mas não sei por quê” previne semanas de confusão futura.
Uma ordem prática para revisar:
Revisões descarrilam quando o feedback é visto como pontuação. Em vez de “Por que você fez isso?”, tente:
Perguntas convidam colaboração e muitas vezes revelam restrições que você não conhecia. Sugestões comunicam direção sem implicar incompetência. Esse tom é como o “gosto” se espalha pela equipe.
Se você quer legibilidade consistente, não dependa do humor do revisor. Adicione algumas “checagens de clareza” ao template de revisão e à definição de pronto. Mantenha-as curtas e específicas:
Com o tempo, isso transforma revisões de policiamento em ensino de julgamento — exatamente o tipo de disciplina cotidiana que Kernighan defendia.
Ferramentas LLM podem produzir código funcional rapidamente, mas “funciona” não é o padrão que Kernighan apontava — comunica é. Se sua equipe usa um fluxo vibe-coding (por exemplo, construir features via chat e iterar em código gerado), vale tratar legibilidade como critério de aceitação de primeira classe.
Em plataformas como Koder.ai, onde você pode gerar frontends React, backends Go e apps Flutter a partir de um prompt de chat (e exportar o código-fonte depois), os mesmos hábitos orientados por gosto se aplicam:
Velocidade é mais valiosa quando a saída ainda é fácil de revisar, manter e estender por humanos.
Clareza não é algo que você “conquista” uma vez. Código se mantém legível só se você o empurrar de volta à fala direta à medida que os requisitos mudam. A sensibilidade de Kernighan se encaixa aqui: prefira melhorias constantes e compreensíveis em vez de reescritas heróicas ou one-liners “espertos” que impressionam hoje e confundem no mês seguinte.
A refatoração mais segura é chata: mudanças diminutas que mantêm o comportamento idêntico. Se tiver testes, execute-os após cada passo. Se não tiver, acrescente alguns checks focados na área que você está tocando — pense neles como guarda-corpos temporários para melhorar estrutura sem medo.
Um ritmo prático:
Commits pequenos também tornam a revisão mais fácil: colegas julgam intenção, não caçam efeitos colaterais.
Você não precisa purgar cada construção “esperta” de uma vez. À medida que toca o código por uma feature ou bugfix, troque atalhos por equivalentes diretos:
Assim é que a clareza vence em equipes reais: um hotspot melhorado por vez, exatamente onde as pessoas já estão trabalhando.
Nem toda limpeza é urgente. Uma regra útil: refatore agora quando o código está mudando ativamente, frequentemente mal compreendido ou provavelmente causador de bugs. Agende para depois quando estiver estável e isolado.
Torne a dívida de refatoração visível: deixe um TODO curto com contexto, ou abra um ticket descrevendo a dor (“difícil adicionar novos métodos de pagamento; função faz 5 trabalhos”). Assim você decide deliberadamente — em vez de deixar código confuso virar imposto permanente da equipe.
Se quer que o “bom gosto” apareça consistentemente, torne-o fácil de praticar. Aqui vai um checklist leve que você pode reutilizar em planejamento, codificação e revisão — curto o bastante para lembrar, específico o suficiente para agir.
Antes: process(data) faz validação, parsing, salvamento e logging em um só lugar.
Depois: Divida em validateInput, parseOrder, saveOrder, logResult. A função principal vira um esboço legível.
Antes: if not valid then return false repetido cinco vezes.
Depois: Uma seção de guarda inicial (ou uma função de validação) que retorna uma lista clara de problemas.
Antes: x, tmp, flag2, doThing().
Depois: retryCount, draftInvoice, isEligibleForRefund, sendReminderEmail().
Antes: Um loop com três casos especiais escondidos no meio.
Depois: Trate os casos especiais primeiro (ou extraia helpers) e depois rode o loop simples.
Escolha uma melhoria para adotar esta semana: “nenhuma nova abreviação”, “caminho feliz primeiro”, “extrair um helper por PR” ou “toda mensagem de erro inclui próximos passos”. Acompanhe por sete dias e mantenha o que realmente torna a leitura mais fácil.
A influência de Kernighan tem menos a ver com C e mais com um princípio duradouro: código é um meio de comunicação.
Linguagens e frameworks mudam, mas equipes ainda precisam de código que seja fácil de escanear, raciocinar, revisar e depurar — especialmente meses depois e sob pressão de tempo.
“Bom gosto” significa escolher consistentemente a opção mais simples e clara que comunica a intenção.
Um teste útil: um colega consegue responder “o que isto faz e por que foi feito assim?” sem decodificar truques ou depender de suposições ocultas?
Porque a maior parte do código é lida muito mais do que é escrita.
Otimizar para quem lê reduz o tempo de onboarding, a fricção em revisões e o risco de mudanças incorretas — especialmente quando o mantenedor é o “você do futuro” com menos contexto.
A “taxa de esperteza” aparece como:
Se a versão esperta economiza segundos agora mas custa minutos toda vez que for tocada, é perda líquida.
Culpados comuns incluem:
Esses padrões tendem a esconder estado intermediário e tornam mais fácil perder casos de borda em revisão.
Quando reduz a carga cognitiva.
Tornar passos explícitos com variáveis nomeadas (por exemplo: validar → normalizar → calcular) pode tornar a correção mais fácil de verificar, simplificar a depuração e facilitar mudanças futuras — mesmo que adicione algumas linhas.
Aposte em:
invoiceTotalCents em vez de sum)Se você precisa decodificar um nome, ele não está fazendo seu trabalho; o nome deveria reduzir a necessidade de comentários extras.
Prefira ramificações simples e mantenha o “caminho feliz” visível.
Táticas úteis:
Comente o porquê, não o o quê.
Bons comentários capturam intenção, trade-offs, restrições ou invariantes não óbvias. Evite narrar código óbvio e trate atualização de comentários como parte da mudança — comentários desatualizados são piores que nenhum comentário.
Use ferramentas para regras mecânicas (formatação, imports, erros óbvios) e reserve revisão humana para o significado.
Um guia de estilo leve ajuda ao decidir questões recorrentes (nomenclatura, estrutura, padrões de tratamento de erro) para que as revisões foquem em clareza e comportamento, não preferência pessoal.
Quando abrir exceções por desempenho ou restrições, documente o trade-off e isole a complexidade atrás de uma interface limpa.