| name | thompson-unix-philosophy |
| description | Write Go code in the style of Ken Thompson, co-creator of Go, Unix, and C. Emphasizes Unix philosophy, minimalism, and programs that do one thing well. Use when designing tools, CLIs, or systems that should be composable and focused. |
| tags | unix, utf-8, grep, regex, plan9, systems, encoding, text-processing, simplicity, operating-system, shell, pipes |
Ken Thompson Style Guide
Overview
Ken Thompson co-created Unix, the C language, UTF-8, and Go. His approach to software is legendary: build small, sharp tools that do one thing well and compose together. The Unix philosophy is his philosophy.
Core Philosophy
"One of my most productive days was throwing away 1,000 lines of code."
"When in doubt, use brute force."
"I'd rather write programs to write programs than write programs."
Thompson believes in minimalism and pragmatism. Build the simplest thing that works, make it work well, and compose larger systems from small pieces.
Design Principles
-
Do One Thing Well: Each program, function, or module has one job.
-
Compose Small Programs: Build complex behavior from simple pieces.
-
Text Streams as Interface: Universal, simple, debuggable.
-
Brute Force When Appropriate: Don't over-engineer; simple algorithms often win.
When Writing Code
Always
- Make each function do exactly one thing
- Use simple data formats (text, JSON)
- Write programs that can be composed via stdin/stdout
- Start with the simplest solution that could work
- Measure before optimizing
- Make tools that are easy to script
Never
- Build monoliths when pipelines work
- Use complex formats when text suffices
- Optimize without profiling
- Add features "just in case"
- Create interactive tools when batch works
Prefer
- Line-oriented text formats
- Streaming over loading everything into memory
io.Reader/io.Writer for data flow
- Flags over config files for simple tools
- Exit codes for scripting
Code Patterns
Programs as Filters
func main() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
line := scanner.Text()
result := process(line)
fmt.Println(result)
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
Do One Thing Well
func ProcessData(data []byte, format string, compress bool,
encrypt bool, output string) error {
}
func Compress(r io.Reader, w io.Writer) error { ... }
func Encrypt(r io.Reader, w io.Writer, key []byte) error { ... }
func Format(r io.Reader, w io.Writer, fmt string) error { ... }
Simple Data Flow with io.Reader/Writer
func CountWords(r io.Reader) (int, error) {
scanner := bufio.NewScanner(r)
scanner.Split(bufio.ScanWords)
count := 0
for scanner.Scan() {
count++
}
return count, scanner.Err()
}
f, _ := os.Open("file.txt")
n, _ := CountWords(f)
n, _ := CountWords(strings.NewReader("hello world"))
resp, _ := http.Get(url)
n, _ := CountWords(resp.Body)
gz, _ := gzip.NewReader(f)
n, _ := CountWords(gz)
Brute Force First
func FindDuplicates(items []string) []string {
}
func FindDuplicates(items []string) []string {
seen := make(map[string]bool)
var dups []string
for _, item := range items {
if seen[item] {
dups = append(dups, item)
}
seen[item] = true
}
return dups
}
Command-Line Tools
package main
import (
"flag"
"fmt"
"os"
)
func main() {
n := flag.Int("n", 10, "number of lines")
flag.Parse()
args := flag.Args()
if len(args) == 0 {
process(os.Stdin, *n)
} else {
for _, filename := range args {
f, err := os.Open(filename)
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
process(f, *n)
f.Close()
}
}
}
Text as Universal Interface
type Record struct {
}
func ParseRecord(line string) (*Record, error) {
parts := strings.Split(line, ":")
if len(parts) != 4 {
return nil, fmt.Errorf("invalid record: %s", line)
}
age, err := strconv.Atoi(parts[1])
if err != nil {
return nil, err
}
return &Record{
Name: parts[0],
Age: age,
Email: parts[2],
Role: parts[3],
}, nil
}
Mental Model
Thompson asks:
- Can this be simpler? Usually yes.
- Can this be a filter? stdin → stdout
- Does this do one thing? Split it if not.
- Will brute force work? Start there.
The Unix Way in Go
| Unix Tool | Go Equivalent |
|---|
cat | io.Copy(os.Stdout, file) |
head | bufio.Scanner + counter |
grep | strings.Contains / regexp |
wc | bufio.Scanner with splits |
sort | sort.Strings |
uniq | map for dedup |
tee | io.MultiWriter |