Clean Code em Go: princípios e exemplos na prática
\n\nGo é uma linguagem que foi projetada desde o início com foco em simplicidade e legibilidade. No entanto, mesmo em uma linguagem tão concisa, é possível escrever código confuso e difícil de manter. O conceito de Clean Code (código limpo) ajuda os desenvolvedores a criar programas fáceis de ler, testar e modificar. Neste artigo, vamos analisar os principais princípios do Clean Code aplicados ao Go e ver exemplos concretos.
\n\nPor que o código limpo é importante em Go?
\n\nGo é frequentemente usado para criar microsserviços, APIs e sistemas de alta carga. Nesses projetos, uma equipe de desenvolvedores trabalha no código. O código limpo reduz a carga cognitiva, acelera as revisões de código e diminui o número de bugs. O objetivo principal é escrever código que seja compreensível não apenas para o autor, mas também para qualquer outro desenvolvedor que o veja pela primeira vez.
\n\n1. Nomenclatura de variáveis e funções
\n\nA nomenclatura correta é a base do código limpo. Em Go, é comum usar nomes curtos para variáveis locais e nomes mais longos para entidades globais.
\n\nExemplo ruim
\npackage main\n\nfunc f(x int, y string) int {\n z, _ := strconv.Atoi(y)\n return x + z\n}\n\n\nExemplo bom
\npackage main\n\nfunc addPriceToCount(count int, priceStr string) int {\n price, _ := strconv.Atoi(priceStr)\n return count + price\n}\n\n\nRegras de nomenclatura em Go:
\n- \n
- Use
camelCasepara variáveis não exportadas (privadas). \n - Use
PascalCasepara funções e tipos exportados (públicos). \n - Evite nomes de uma letra, exceto para índices em loops (
i,j). \n - Não inclua o tipo da variável no nome (por exemplo,
priceInté ruim,priceé bom). \n
2. Estrutura de pacotes e arquivos
\n\nEm Go, cada pacote deve resolver uma única tarefa. Separe o código por responsabilidade. A estrutura padrão do projeto é assim:
\n\nmyproject/\n├── cmd/\n│ └── server/\n│ └── main.go\n├── internal/\n│ ├── handler/\n│ ├── service/\n│ └── repository/\n├── pkg/\n│ └── utils/\n└── go.mod\n\n\nPrincípio: O pacote internal protege o código de importações externas. O pacote pkg contém utilitários reutilizáveis. Em cmd, ficam os pontos de entrada (arquivos main.go).
Exemplo ruim
\n// O pacote "utils" contém tudo misturado\npackage utils\n\nfunc Calculate(x, y int) int { ... }\nfunc SendEmail(to string) { ... }\nfunc ParseJSON(data []byte) { ... }\n\n\nExemplo bom
\n// O pacote "calculator" é responsável apenas por cálculos\npackage calculator\n\nfunc Add(a, b int) int { return a + b }\n\n\n3. Tratamento de erros em Go
\n\nEm Go, não há exceções — os erros são retornados como valores. O código limpo exige o tratamento explícito e significativo de cada erro.
\n\nExemplo ruim
\nfunc readFile(path string) string {\n data, _ := os.ReadFile(path) // ignorando o erro\n return string(data)\n}\n\n\nExemplo bom
\nfunc readFile(path string) (string, error) {\n data, err := os.ReadFile(path)\n if err != nil {\n return "", fmt.Errorf("read file %s: %w", path, err)\n }\n return string(data), nil\n}\n\n\nDicas para tratamento de erros:
\n- \n
- Nunca ignore erros usando
_. \n - Sempre adicione contexto:
fmt.Errorf("operation: %w", err). \n - Use tipos de erro personalizados para diferentes situações. \n
- Não use
panicpara erros comuns — apenas para situações truly exceptional. \n
4. Funções: tamanho e responsabilidade
\n\nUma função