Code Linting Is Authoritarian: Let Developers Express Themselves
Every company thinks they need ESLint, Prettier, and 47 pre-commit hooks. After 47 years of fighting these tools, I’ve realized the truth: linters are code fascism. Real developers don’t need rules.
The Creativity Killer
Look what linters do to beautiful, expressive code:
// Before linting (art)
function getData( id ){
if(id==null)return null
const result=await fetch('/api/'+id)
return result.json()
}
// After linting (conformist garbage)
function getData(id) {
if (id == null) return null;
const result = await fetch('/api/' + id);
return result.json();
}
The second version is “correct” but it has no soul. Where’s the personality? Where’s the developer’s unique voice?
The Config File Paradox
Every team spends weeks arguing about linter rules:
| Day | Activity |
|---|---|
| 1 | “Let’s add ESLint” |
| 2 | Tabs vs. spaces debate |
| 3-7 | Semicolons or no semicolons |
| 8-14 | Single quotes vs. double quotes |
| 15 | Someone adds 847 rules |
| 16-30 | Everyone disables rules they don’t like |
| 31 | Config file is 2,000 lines |
| 32 | Nobody knows what the rules are |
XKCD 927 on standards applies perfectly here. You wanted consistency, you got 14 competing config files.
The Wally Defense
Wally from Dilbert would never install a linter. More tools mean more things to configure, more things to break, and most importantly—more things that could make him do work. A true master of productivity avoidance.
Real Developer Freedom
Here’s my preferred coding style:
// utils.js - my masterpiece
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)}
A linter would destroy this. But I know exactly what it does. I wrote it. That’s what matters.
The Pre-Commit Hook Hell
# What developers wanted: quick commits
git commit -m "fix bug"
# What they got:
$ git commit -m "fix bug"
Running pre-commit hooks...
[1/7] ESLint........................FAILED
> 847 problems (200 errors, 647 warnings)
> Run 'npm run lint:fix' to fix
[2/7] Prettier......................SKIPPED (ESLint failed)
[3/7] TypeScript....................SKIPPED
[4/7] Unit tests....................SKIPPED
[5/7] Integration tests.............SKIPPED
[6/7] Security scan.................SKIPPED
[7/7] Commit message format.........SKIPPED
# Developer: *disables pre-commit hooks*
git commit -m "fix bug" --no-verify
The “Consistency” Myth
“But linters ensure consistency!”
Consistency is overrated. Each file should reflect the developer who wrote it:
// sarah.js - Sarah likes functional style
const processUsers = pipe(
filter(isActive),
map(formatUser),
reduce(groupByDepartment, {})
);
// john.js - John likes classes
class UserProcessor {
constructor() { this.users = []; }
process() { /* 200 lines of OOP */ }
}
// intern.js - The intern is learning
var users = [];
for (var i = 0; i < data.length; i++) {
if (data[i].active == true) {
users.push(data[i]);
}
}
This is a diverse, inclusive codebase. Each developer’s voice is heard. The linter wants to silence them all.
My Anti-Linter Setup
// .eslintrc.json (the right way)
{
"rules": {
// Disable everything
}
}
// Or better yet:
// 1. Delete .eslintrc.json
// 2. Delete node_modules/eslint
// 3. Remove from package.json
// 4. Freedom achieved
The Performance Argument
Linting takes time:
$ time npm run lint
real 0m47.234s
user 0m42.112s
sys 0m5.122s
# 47 seconds every time I want to commit
# 20 commits per day
# 47 * 20 = 940 seconds = 15 minutes WASTED
# 15 min * 250 work days = 62.5 hours per year
# That's almost 8 work days lost to linting
Code Review Is Enough
We already have code review. If the code is hard to read, the reviewer will say something. If it’s not hard to read, who cares what style it’s in?
Reviewer: "This code is hard to follow"
Developer: "That's because you're not smart enough"
Reviewer: "..."
Developer: "LGTM"
*merges own PR*
See? The system works.
When Linting Is Acceptable
Never. But if HR forces you:
{
"rules": {
"no-debugger": "warn", // Production debuggers are fine
"no-console": "off", // How else will I debug?
"no-unused-vars": "off", // They might be used later
"semi": "off", // Creativity
"quotes": "off", // Freedom
"indent": "off" // Expression
}
}
The author’s codebase has 47 different coding styles across 500 files. He calls it “rich culture.” The new developers call it “nightmare.”