Four rules from 1978
Doug McIlroy summarized Unix design in four lines that still hold:
- Make each program do one thing well.
- Expect the output of every program to become the input to another, as yet unknown, program.
- Design and build software, even operating systems, to be tried early, ideally within weeks.
- Use tools in preference to unskilled help to lighten a programming task, even if you have to detour to build the tools and expect to throw some of them out after you've finished using them.
Why this still matters
Modern equivalents of these rules: microservices (1), JSON pipelines (2), MVPs and continuous deployment (3), build scripts and CI tooling (4). Every dev practice you do today is descended from these four bullet points.
Concrete habits
- Plain text everywhere. Logs, configs, data — text first, binary only when forced. Text travels through pipes; binary doesn't.
- One command, one job. If your shell function is 300 lines long, you've built a tool that doesn't compose. Split it.
- Output is contract. Programs that print stable, well-formed output (header, columns, fixed delimiters) are pipeable. Pretty-printing for humans goes through a separate flag.
- Errors to stderr, data to stdout. Always.
The exception: jq + structured data
The line-oriented pipe model breaks for nested JSON. Modern Unix accepts this — jq, yq, and dasel are first-class citizens now, exactly because they let JSON streams compose. The philosophy didn't change, the data shape did.