Pular para o conteúdo principal

Como Escrever Código que Humanos Conseguem Ler

Publicado em 15 de dezembro de 202510 min de leitura
Imagem de tecnologia relacionada ao artigo como-escrever-codigo-legivel

Como Escrever Código que Humanos Conseguem Ler

Qualquer tolo consegue escrever código que um computador entenda. Bons programadores escrevem código que humanos entendam. Essa frase de Martin Fowler resume o maior desafio da nossa profissão: dominar a arte de se comunicar com outros desenvolvedores (incluindo o você do futuro) através da sintaxe.

Escrever código legível não é apenas uma questão de estética ou "capricho"; é uma estratégia de sobrevivência e produtividade. Quando o código é claro, a manutenção se torna trivial e a inovação flui sem o peso da dívida técnica.

1. Nomes Significativos para Variáveis e Funções

A escolha de bons nomes é a maneira mais eficaz de melhorar a legibilidade do código. Segundo Martin Fowler, autor de "Refactoring", "não há segredo maior em código limpo do que nomes expressivos". Nomes devem revelar a intenção, não apenas descrever o tipo. Um bom nome de variável ou função deve responder às perguntas: "O que esse elemento faz?", "Por que ele existe?" e "Como ele é usado?". Nomes descritivos reduzem a necessidade de comentários explicativos e ajudam outros desenvolvedores (e você mesmo no futuro) a entender rapidamente o propósito do código.

Evite nomes genéricos

javascript
// Difícil de entender
function process(data) {
let temp = [];
for (let i = 0; i < data.length; i++) {
if (data[i].status === 'active') {
temp.push(data[i]);
}
}
return temp;
}

Prefira nomes específicos

javascript
// Fácil de entender
function getActiveUsers(users) {
return users.filter(user =>
user.status === 'active'
);
}

Boas práticas para nomes:

  • Verbos para funções: calculateTotal, validateInput, sendNotification - indicam ação e propósito
  • Adjetivos para booleanos: isActive, hasPermission, shouldUpdate - deixam claro o estado ou condição representada
  • Substantivos para objetos: userPreferences, orderDetails, configSettings - representam entidades ou coleções de dados

2. Funções Pequenas com Responsabilidade Única

Funções devem fazer uma coisa só e fazer bem. Esse princípio, conhecido como SRP (Single Responsibility Principle), é um dos pilares do design de software limpo. Funções pequenas são mais fáceis de testar, reutilizar, entender e depurar. Segundo Dave Thomas e Andy Hunt, autores de "The Pragmatic Programmer", as funções devem ser pequenas - o ideal é que tenham entre 1 e 25 linhas. Funções com responsabilidade única também facilitam a composição de funcionalidades mais complexas. A divisão de funções complexas em funções menores melhora a legibilidade e a manutenibilidade do código.

Função muito complexa

javascript
function processOrder(order) {
// Validação
if (!order.items || order.items.length === 0) {
throw new Error('No items in order');
}

// Cálculo
let total = 0;
for (let item of order.items) {
total += item.price * item.quantity;
}

// Aplicação de desconto
if (order.customer.isPremium) {
total *= 0.9;
}

// Geração de recibo
const receipt = {
orderId: order.id,
total: total,
date: new Date()
};

// Envio de email
sendEmail(order.customer.email, receipt);

return receipt;
}

Funções separadas

javascript
function validateOrder(order) {
if (!order.items || order.items.length === 0) {
throw new Error('No items in order');
}
}

function calculateTotal(order) {
let total = order.items.reduce(
(sum, item) => sum + item.price * item.quantity,
0
);

if (order.customer.isPremium) {
total *= 0.9;
}

return total;
}

function generateReceipt(order, total) {
return {
orderId: order.id,
total: total,
date: new Date()
};
}

function processOrder(order) {
validateOrder(order);
const total = calculateTotal(order);
const receipt = generateReceipt(order, total);
sendEmail(order.customer.email, receipt);
return receipt;
}

3. Estruturação Consistente do Código

Manter uma estrutura previsível ajuda na leitura e facilita o trabalho em equipe. A consistência na organização do código reduz o tempo necessário para entender novas partes do sistema. A definição e seguimento de padrões de codificação não são apenas estéticos - eles melhoram a produtividade da equipe e reduzem erros. Estabeleça padrões para sua equipe e siga-os consistentemente. Isso inclui ordem de imports, organização de funções e componentes, convenções de nomenclatura e estruturação de arquivos.

Exemplo de estrutura em componente React:

javascript
// 1. Imports (agrupados por tipo)
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { Button, Input } from '@/components/ui';
import { fetchUserData } from '@/services/api';

// 2. Constantes do componente
const DEFAULT_LIMIT = 10;
const STATUS = {
LOADING: 'loading',
SUCCESS: 'success',
ERROR: 'error'
};

// 3. Componente principal
function UserList({ teamId }) {
// 4. Estados (agrupados logicamente)
const [users, setUsers] = useState([]);
const [status, setStatus] = useState(STATUS.LOADING);
const [page, setPage] = useState(1);

// 5. Efeitos
useEffect(() => {
  loadUsers();
}, [teamId, page]);

// 6. Funções do componente (ordem lógica)
async function loadUsers() {
  try {
    setStatus(STATUS.LOADING);
    const data = await fetchUserData(teamId, page, DEFAULT_LIMIT);
    setUsers(data);
    setStatus(STATUS.SUCCESS);
  } catch (error) {
    setStatus(STATUS.ERROR);
  }
}

// 7. Handlers de eventos
function handleNextPage() {
  setPage(prev => prev + 1);
}

// 8. Renderização condicional
if (status === STATUS.LOADING) {
  return <LoadingSpinner />;
}

if (status === STATUS.ERROR) {
  return <ErrorMessage onRetry={loadUsers} />;
}

// 9. JSX principal
return (
  <div className="user-list">
    {users.map(user => (
      <UserCard key={user.id} user={user} />
    ))}
    <Button onClick={handleNextPage}>
      Carregar mais
    </Button>
  </div>
);
}

// 10. PropTypes (se necessário)
UserList.propTypes = {
teamId: PropTypes.string.isRequired
};

export default UserList;

4. Uso Adequado de Comentários

Comentários devem explicar o "porquê", não o "o quê". Código bom deve ser autoexplicativo, e os comentários devem ser usados para explicar decisões complexas, razões por trás de soluções específicas ou para indicar limitações temporárias. Segundo Brian W. Kernighan, "O melhor comentário é um código claro que não precisa de comentário". Comentários desatualizados ou desnecessários podem ser mais prejudiciais do que úteis, pois podem induzir a erros ou confusão. O ideal é escrever código que seja legível por si só e usar comentários apenas quando realmente necessário para explicar o raciocínio por trás de decisões complexas ou não óbvias.

Comentários desnecessários

javascript
// Incrementa o contador
count = count + 1;

// Verifica se o usuário está ativo
if (user.status === 'active') {
// Envia notificação
sendNotification(user);
}

Comentários úteis

javascript
// +1 porque o array é 0-indexed mas a UI mostra 1-indexed
displayIndex = arrayIndex + 1;

// API antiga retorna 0 para não definido, mas precisamos de null
// TODO: Migrar para nova API que retorna null corretamente
const value = apiValue === 0 ? null : apiValue;

5. Tratamento de Erros Explícito

Código legível deixa claro o que pode falhar e como falhas são tratadas. Um bom tratamento de erros é essencial para aplicações robustas e fáceis de manter. A forma como você lida com erros pode dizer muito sobre a qualidade do seu código. O tratamento explícito de erros não apenas melhora a confiabilidade do sistema, mas também facilita a depuração e o suporte. Segundo a OWASP (Open Web Application Security Project), um tratamento inadequado de erros pode levar a vazamento de informações sensíveis e comprometer a segurança da aplicação.

javascript
// Bom exemplo: tratamento claro de erros
async function updateUserProfile(userId, updates) {
try {
  // Validação explícita
  if (!isValidUserId(userId)) {
    throw new ValidationError('ID de usuário inválido');
  }

  if (!hasValidUpdateFields(updates)) {
    throw new ValidationError('Campos de atualização inválidos');
  }

  // Operação principal
  const result = await api.updateUser(userId, updates);

  // Retorno explícito de sucesso
  return {
    success: true,
    data: result,
    message: 'Perfil atualizado com sucesso'
  };

} catch (error) {
  // Tratamento específico por tipo de erro
  if (error instanceof ValidationError) {
    return {
      success: false,
      error: error.message,
      code: 'VALIDATION_ERROR'
    };
  }

  if (error instanceof NetworkError) {
    return {
      success: false,
      error: 'Falha de conexão',
      code: 'NETWORK_ERROR',
      suggestion: 'Verifique sua conexão e tente novamente'
    };
  }

  // Fallback para erros inesperados
  return {
    success: false,
    error: 'Erro inesperado',
    code: 'UNKNOWN_ERROR'
  };
}
}

6. Padrões de Equipe e Ferramentas

Consistência em equipe é tão importante quanto qualidade individual. Usar ferramentas para automatizar padrões é essencial para manter a qualidade do código em projetos colaborativos. Estudos da Google sobre engenharia de software mostram que equipes com padrões de codificação bem definidos têm 20% menos bugs e 15% menos tempo de desenvolvimento. As ferramentas de linter e formatador ajudam a manter a consistência e reduzem discussões desnecessárias durante revisões de código. Além disso, elas ajudam novos membros da equipe a se adaptarem mais rapidamente aos padrões do projeto.

Configuração mínima recomendada:

  • ESLint - Para padrões de código e detecção de erros comuns
  • Prettier - Para formatação consistente e padronizada
  • Husky + lint-staged - Para checagens pré-commit e garantia de qualidade
  • TypeScript - Para tipagem estática e melhor autocomplete

Checklist Rápido para Revisão de Código

✅ Antes de enviar um PR

  • Nomes revelam intenção (não são genéricos)

  • Funções têm uma responsabilidade clara

  • Código funciona sem os comentários

  • Erros são tratados explicitamente

📝 Ao revisar código alheio

  • ? Entendi a lógica na primeira leitura?

  • ? Posso descrever o que faz sem hesitar?

  • ? Os testes são claros e cobrem casos importantes?

  • ? Há código duplicado ou complexidade desnecessária?

Conclusão

Código legível não é um luxo - é uma necessidade prática e uma melhoria de produtividade significativa a longo prazo. Segundo um estudo do IEEE, o custo de manutenção de software representa cerca de 70% do custo total de um sistema. Escrever código legível reduz esse custo substancialmente. Seguindo estas práticas, você cria código que:

  • Facilita a colaboração em equipe e reduz o tempo de onboarding
  • Reduz bugs e tempo de debug graças à clareza do código
  • Acelera o onboarding de novos desenvolvedores no projeto
  • Permite refatorações mais seguras e confiantes
  • Economiza tempo no longo prazo com manutenção mais eficiente

Se este artigo foi útil para você, explore também:


Glossário Técnico

  • Refactoring (Refatoração): Processo de reestruturar o código interno sem alterar seu comportamento externo, visando melhorar a legibilidade e manutenibilidade.
  • Cognitive Load (Carga Cognitiva): A quantidade de esforço mental necessária para um desenvolvedor entender um trecho de código ou sistema.
  • CamelCase: Convenção de escrita onde a primeira letra de cada palavra (exceto a primeira) é maiúscula (ex: calculateTotalAmount).
  • Screaming Snake Case: Convenção de escrita para constantes onde todas as letras são maiúsculas e separadas por underscore (ex: MAX_RETRY_ATTEMPTS).
  • Self-documenting Code: Código escrito de forma tão clara (nomes, estrutura, lógica) que dispensa quase totalmente o uso de comentários explicativos.

Referências

  1. Martin Fowler. Refactoring: Improving the Design of Existing Code. O livro seminal que definiu as técnicas e a importância de manter o código limpo.
  2. Robert C. Martin. Clean Code: A Handbook of Agile Software Craftsmanship. Blog e recursos do autor de um dos guias mais influentes sobre legibilidade de código.
  3. Google Style Guides. Style guides for Google-originated open-source projects. Os padrões oficiais de codificação usados em larga escala por uma das maiores empresas de tecnologia do mundo.
  4. Refactoring.Guru. Code Smells. Guia visual e prático para identificar códigos difíceis de ler e como corrigi-los.
  5. web.dev (Google). Write maintainable JavaScript. Artigo técnico sobre como os princípios de legibilidade afetam a performance e longevidade de projetos web.
Imagem de tecnologia relacionada ao artigo como-escrever-codigo-legivel