Each read pulls an object from the original source, through any number of intervening pipe fittings, and into the pump. Each write pushes an object through any number of pipe fittings out to the ultimate destination. Conventional batch programs tend to centre around a main loop during which some input and some output processing gets done. The pipework architecture is simpler, since the application's work is done in the pipe, one cycle at a time, where you don't have to worry about loop control, starting and stopping. It is tempting to try to build a pipe fitting in such a way that it can work upstream and downstream of the pump.
Some fittings naturally belong upstream, and others belong downstream.
There are plenty of fittings which are useful anywhere. These need to be implemented twice, as a pair of complementary classes. It is often worth building a common ancestor to avoid duplicating code and to ensure consistency, and this pattern crops up occasionally in the pipework library. The plumbing analogy is useful for an overall perspective, but computing terminology is more appropriate for identifying components precisely. The dominant features of these components are concerned with reading, writing and connecting.