- The pipeline isn’t pre-defined. One should be able to add and remove stages at will.
- Any pipeline stage should be able to drop a bit of data and not pass it further.
- Any pipeline stage should be able to terminate the whole program.
- Any pipeline stage should be able to time out. The feeder process at the head of the pipeline should be able to time out, too.
- The feeder should be able to retry failures, as should individual stages.
- Termination, or an error, should be possible to handle gracefully without losing all of the work that’s been done.
Replacing Clever Code with Unremarkable Code in Go
June 4, 2013
Database
Not too long ago, my primary programming language was Perl. I’ve written a lot of Perl, including some things that I think are quite clever. And therein lies the problem.
Clever code is dangerous. It feels great because when I’m puzzling with a sticky problem — the abstraction is wrong, or the language design doesn’t support the abstraction I want, or so on — and then I find some neat trick, it’s so … cool. The feeling of delight at an “elegant” way to do something is such a blast of endorphins, such a reward for struggling through.
A lot of the clever code I’ve written involved callbacks. In fact, I once blogged a review of a Perl book, Higher-Order Perl, that takes the notion of callbacks deeper and deeper, until you’re breathless at the beauty of it. You feel initiated into an inner circle. You feel like you’ve discovered LISP in an alternate dimension (but you haven’t).
One of the things I like about Go is that it offers much better ways to write things that you’d usually write with callbacks. The resulting code feels unremarkable, not clever at all. In fact, it reads like a straightforward solution of the problem. As a programmer, I don’t get a high out of that, but it’s much better. A straightforward solution of the problem is superior to one that makes you feel like a high priest for having discovered it.
As an example, in Percona Toolkit several of the tools have the notion of a “processing pipeline.” An object or bit of data is passed into a function, whose job is to manipulate it and pass it to another function, and so on in turn until all of the functions are done and the data comes out the other end.
The design is slightly difficult to get working well in Perl, in part because the obvious-feeling solutions have many shortcomings. For example, some of the requirements we realized we had over time: