Also note that programs may have modes that fit more than one
interface pattern. A program that has a compiler-like interface,
for example, may behave as a filter when no file arguments are
specified on the command line (many format converters behave like
this).
Remember Postel's Prescription: Be generous in what
you accept, rigorous in what you emit. That is, try to
accept as loose and sloppy an input format as you can and emit as
well-structured and tight an output format as you can. Doing the
former reduces the odds that the filter will be brittle in the face of
unexpected inputs, and break in someone's hand (or in the middle of
someone's toolchain). Doing the latter increases the odds that your
filter will someday be useful as an input to other programs.
When filtering, never throw away information you don't
need to. This, too, increases the odds that your filter
will someday be useful as an input to other programs. Information you
discard is information that no later stage in a pipeline can
use.
Some programs have interface design patterns like the filter,
but even simpler (and, importantly, even easier to script). They
are cantrips, sources, and sinks.