Toda empresa acha que precisa de ESLint, Prettier e 47 pre-commit hooks. Depois de 47 anos lutando contra essas ferramentas, percebi a verdade: linters são fascismo de código. Desenvolvedores de verdade não precisam de regras.

O Assassino da Criatividade

Olhe o que linters fazem com código bonito e expressivo:

// Antes do linting (arte)
function    getData(   id   ){
    if(id==null)return null
    const result=await fetch('/api/'+id)
    return result.json()
}

// Depois do linting (lixo conformista)
function getData(id) {
    if (id == null) return null;
    const result = await fetch('/api/' + id);
    return result.json();
}

A segunda versão é “correta” mas não tem alma. Onde está a personalidade? Onde está a voz única do desenvolvedor?

O Paradoxo do Arquivo de Config

Todo time passa semanas discutindo regras de linter:

Dia Atividade
1 “Vamos adicionar ESLint”
2 Debate tabs vs. espaços
3-7 Ponto e vírgula ou sem ponto e vírgula
8-14 Aspas simples vs. aspas duplas
15 Alguém adiciona 847 regras
16-30 Todo mundo desabilita regras que não gosta
31 Arquivo de config tem 2.000 linhas
32 Ninguém sabe quais são as regras

XKCD 927 sobre padrões se aplica perfeitamente aqui. Você queria consistência, ganhou 14 arquivos de config competindo.

A Defesa Wally

Wally do Dilbert nunca instalaria um linter. Mais ferramentas significam mais coisas para configurar, mais coisas para quebrar, e mais importante—mais coisas que poderiam fazê-lo trabalhar. Um verdadeiro mestre em evitar produtividade.

Liberdade Real do Desenvolvedor

Aqui está meu estilo preferido de código:

// utils.js - minha obra-prima

var GLOBAL_CONFIG = {api:"http://localhost",port:3000,DEBUG:!0}
function   fetchData(    ){
return   new Promise(function(res,rej){
    var xhr=new XMLHttpRequest()
    xhr.onload=function(){res(JSON.parse(this.responseText))}
    xhr.open('GET',GLOBAL_CONFIG.api+':'+GLOBAL_CONFIG.port+'/data')
    xhr.send()
})}
const processData=d=>d.map(x=>({...x,processed:1}))
async function main(
){const data=await fetchData()
const processed = processData( data )
    console.log(processed)}

Um linter destruiria isso. Mas eu sei exatamente o que faz. Eu escrevi. Isso é o que importa.

O Inferno do Pre-Commit Hook

# O que devs queriam: commits rápidos
git commit -m "fix bug"

# O que ganharam:
$ git commit -m "fix bug"
Rodando pre-commit hooks...
[1/7] ESLint........................FALHOU
  > 847 problemas (200 erros, 647 warnings)
  > Rode 'npm run lint:fix' para corrigir
[2/7] Prettier......................PULADO (ESLint falhou)
[3/7] TypeScript....................PULADO
[4/7] Testes unitários..............PULADO
[5/7] Testes de integração..........PULADO
[6/7] Scan de segurança.............PULADO
[7/7] Formato de mensagem...........PULADO

# Desenvolvedor: *desabilita pre-commit hooks*
git commit -m "fix bug" --no-verify

O Mito da “Consistência”

“Mas linters garantem consistência!”

Consistência é superestimada. Cada arquivo deve refletir o desenvolvedor que o escreveu:

// sarah.js - Sarah gosta de estilo funcional
const processUsers = pipe(
    filter(isActive),
    map(formatUser),
    reduce(groupByDepartment, {})
);

// john.js - John gosta de classes
class UserProcessor {
    constructor() { this.users = []; }
    process() { /* 200 linhas de OOP */ }
}

// estagiario.js - O estagiário está aprendendo
var users = [];
for (var i = 0; i < data.length; i++) {
    if (data[i].active == true) {
        users.push(data[i]);
    }
}

Essa é uma base de código diversa e inclusiva. A voz de cada desenvolvedor é ouvida. O linter quer silenciar todos.

Meu Setup Anti-Linter

// .eslintrc.json (o jeito certo)
{
    "rules": {
        // Desabilita tudo
    }
}

// Ou melhor ainda:
// 1. Delete .eslintrc.json
// 2. Delete node_modules/eslint
// 3. Remova do package.json
// 4. Liberdade conquistada

O Argumento de Performance

Linting leva tempo:

$ time npm run lint
real    0m47.234s
user    0m42.112s
sys     0m5.122s

# 47 segundos toda vez que quero commitar
# 20 commits por dia
# 47 * 20 = 940 segundos = 15 minutos DESPERDIÇADOS
# 15 min * 250 dias úteis = 62.5 horas por ano
# São quase 8 dias de trabalho perdidos em linting

Code Review Já Basta

Já temos code review. Se o código é difícil de ler, o revisor vai falar. Se não é difícil de ler, quem liga pro estilo?

Revisor: "Esse código é difícil de acompanhar"
Dev: "É porque você não é inteligente o suficiente"
Revisor: "..."
Dev: "LGTM"
*mergeia próprio PR*

Viu? O sistema funciona.

Quando Linting É Aceitável

Nunca. Mas se o RH forçar:

{
    "rules": {
        "no-debugger": "warn",   // Debuggers em prod são ok
        "no-console": "off",     // Como mais vou debugar?
        "no-unused-vars": "off", // Podem ser usadas depois
        "semi": "off",           // Criatividade
        "quotes": "off",         // Liberdade
        "indent": "off"          // Expressão
    }
}

A base de código do autor tem 47 estilos diferentes em 500 arquivos. Ele chama de “cultura rica”. Os devs novos chamam de “pesadelo”.