Composability
A composable program reads from stdin, writes to stdout, and exits cleanly — and that is all it takes to work with every other tool on the system.
- Explain what a pipe does and how programs chain together
- Understand stdin and stdout as the universal connector between programs
- Describe the three properties that make a program composable
The pipe character | is one of the most powerful ideas in computing. It takes
the stdout of one program and feeds it directly into the stdin of the next — with
no files, no intermediate state, and no coordination required. The programs do not
know about each other. They just speak the same language: lines of text.
How pipes work
Consider this shell pipeline:
cat server.log | grep ERROR | sort | uniq -c | sort -rn | head -10Read it left to right:
cat server.log— reads the file and writes every line to stdoutgrep ERROR— reads those lines and passes through only the ones containing "ERROR"sort— sorts the filtered lines alphabeticallyuniq -c— collapses consecutive identical lines and prefixes each with a countsort -rn— sorts numerically in reverse (largest count first)head -10— prints only the first 10 lines
The result: the ten most common error messages in your log, ranked by frequency. None of these programs were designed to work together. They compose because they each follow the same contract.
The composability contract
A program is composable if it does three things:
- Reads from stdin (or from a file named as an argument — but defaults to stdin)
- Writes results to stdout — data only, no diagnostic noise
- Exits with a meaningful exit code — 0 means success; anything else means failure
That is the whole contract. A program that follows all three works correctly in any pipeline position: as the first step, a middle step, or the final step.
A program that writes errors to stdout breaks step 2 — downstream tools will treat the error message as data. A program that always exits 0, even on failure, breaks step 3 — a pipeline cannot know whether to continue.
Composability is a design decision
Composability does not happen automatically. You have to decide to:
- Send results to stdout and only results
- Send all messages, warnings, and errors to stderr
- Return a non-zero exit code when something goes wrong
- Accept input from stdin when no filename is given
These are not hard requirements to meet, but you have to think about them. A program that opens a GUI, prompts for interactive input, or pops up a dialog cannot be used in a pipeline at all.
Many excellent Python programs are not composable — and that is fine if composability is not the goal. The question to ask yourself before you start writing is: should this tool work in a pipeline? If yes, design for it from the beginning. Retrofitting composability is much harder than building it in.
What this track builds
Every tool in this track is designed to be composable: reads stdin or a named
input, writes clean results to stdout, reports errors to stderr, and exits with
a meaningful code. You will also learn argparse — which lets your tool accept
both stdin and named files, and gives you a --help flag for free.
Where to go next
Next: CLI arguments — using argparse to give your utility a real command-line
interface with named flags and positional arguments.