There is this quite well known book, titled Clean Code. It is a very insightful work which I wholeheartedly recommend reading for any serious (or semi-serious) programmer.
The premise revolves around the concept of “cleanness” of code, which the author defines in various ways. Mostly it boils down to high signal-to-noise ratio and clear structure, where everything is neatly subdivided into smaller parts.
The idea is very appealing. For some it may even sound like a grand revelation; I know it was almost like that for me. But there is a bigger kind of meta-lesson to be learned here: the one of scope where such great ideas apply – and where they don’t.
You see, the Clean Code ideal works very well for certain kind of languages. The original examples in the book are laid down in Java and this is no coincidence. Java – as well as C, Go and probably few others – is not a very expressive language: lots of detailed busy work is often needed, even for conceptually simple tasks. And if several such tasks are lined up one after another, the reader is likely to drown in small details instead of seeing the bigger picture.
Those details are therefore one of the prime reasons why you may call some code “unclean”. To tidy up, they need to be properly encapsulated, away from a higher level overview. Hence it’s pretty common in Java to see functions like this one:
and think of them as good code, even if such a function is only used once. The goodness comes from the fact that they are relieving their callers from irrelevant loop minutiae, so that it’s easier to see why we need foos
to be valid in the first place.
Yet, at the same time, if you saw a completely equivalent Python construct:
you would firstly curse at incompetence and lack of knowledge of whoever wrote it:
and then you would get rid of the function altogether:
Why? Because the language is expressive enough for implementation itself to be almost as readable as the function call. Sure, throw the result of all(...)
into a variable for even more self-documenting sweetness, but don’t put it in some far away place behind a standalone function. Such code may or may not be cleaner; it will definitely raise eyebrows, though.
And lack of astonishment is probably the most important metric.
There was a thing in this book that really bothered me. The author after describing himself as an assembly coder, claimed that it’s a lot better to write Erastotenes’ sieve with n iterations than with sqrt(n), even though it reduces the performance. I know that this should be just an example, but I’m a little tired with the fact that even though my present computer is much faster than my first one I still feel like I’m on a 1200Mhz with 128 RAM when running certain apps.
Nevertheless, I’ve found the book worth reading.
i think the function encapsulation strategy is awesome when you combone it with a roper test suite
C#
var foosAreValid = foos.All(foo=>foo.IsValid);
JS
var foosAreValid = foos.every(function(foo) { return foo.isValid() })
TS
var foosAreValid = foos.every(foo => foo.isValid())
C++
auto foosAreValid = cpplinq::from(foos).all([](Foo foo){ return foo.isValid(); });
// OR
auto foosAreValid = std::all_of(foos.begin(), foos.end(), [](Foo foo){return foo.isValid(); })