Why is the UNIX / functional style of composing and injecting smaller functions so much rarer than the Beck/Fowler/Bob refactor-to-objects style when it comes to writing maintainable, "beautiful" software?


In my private projects, I tend to write small functions that do one or perhaps two things, which I later compose into larger functions that form my API(s). Here, I try to inject dependencies either by higher order functions, or smaller interfaces, just so that I can keep track of side effects (as this is usually where I find my bugs).

I find this approach very nice, especially if I can name modules sensibly.

However, whenever I study design and architecture, the vast majority of books / courses / articles tend to fall into the Kent Beck, Martin Fowler, Bob Martin type of approach where everything eventually becomes an object.

Is this better (maintainability, reliability, easy to change) than just writing procedural code with the same level of care, testing and refactoring as the "refactor to objects" crowd?

To me, it seems that SLOC explodes, and now there's a new layer of complexity needed to handle the lifetimes of all the new allocations that weren't there before. The tangible improvement in before-and-after examples tend to be the removal of anti patterns and code smells rather than reinventing Smalltalk wherever possible.

I have only been working professionally for three years, so I assume that I'm missing the forest for the trees here.

  • What language do you use? In Python, it is very common to have exactly what you describe. In Java or C#, everything is an object, so it's natural to see objects. Aug 5 '20 at 22:25
  • @ArseniMourzenko: "In Java or C#, everything is an object" – Actually, that is not true. I am not that familiar with C#, but at least in Java, only instances of interfaces are objects. Instances of classes are Abstract Data Type values, not objects. (Interfaces define Objects, classes define ADTs.) Aug 6 '20 at 7:25
  • @JörgWMittag - I understand your objection, but it's based on a minority opinion of what constitutes an object. The more common view is that anything that combines data and code with late binding is an object, whether or not encapsulation is based on individual object identity or the class of the object.
    – occipita
    Aug 6 '20 at 8:20
  • 1
    Just out of curiosity: how many users does a typical project of yours have? Remember that the code that Kent Beck is most famous for, is JUnit, which has hundreds of thousands of users, hundreds of plugins, and is itself plugging into dozens of IDEs, Continuous Integration Tools, Build Tools, Text Editors, etc. It has to satisfy an enormous range of requirements, it has to be blazingly fast, it has to be carefully written so that the test framework itself does not accidentally alter the results of the tests, and so on, and so forth. Aug 6 '20 at 9:36
  • Also note that JUnit is literally a port of Kent Beck's SUnit framework for Smalltalk, so it should not be surprising that a code that was ported to Java from Smalltalk by a Smalltalk programmer looks like Smalltalk code written by a Smalltalk programmer, because that is exactly what it is. Aug 6 '20 at 9:37

I would disagree with your observation that function composition is not common.

There are languages which favor functions over objects. Classical JavaScript (before ES6 and TypeScript frenzy) is a good example: you literally had a tree of functions, and composed them to create larger functions. Haskell is another example where the code is usually heavily oriented to functions being assembled together, injected in other functions, or expanded by other functions.

Then there are languages which don't impose functions or objects, and let the programmer decide which one should be used in a given context. Python is a great example, and in Python, it is very common to see function composition as well.

Finally, some languages such as Java and C# are strongly oriented towards classes and objects, and in some, every line of code you write is necessarily within a class (or an interface). But here again, I see a lot of function composition going around. Thanks to the first-class functions support and features such as extension methods, it is very natural to do, and features like LINQ in C# ensure that even the beginners are familiar with the syntax.

  • Since the OP mentions Smalltalk explicitly, I would also like to point out that higher-order functions are deeply ingrained in the Smalltalk language (in fact, function literals in Smalltalk are more syntactically lightweight than in some functional languages!) and in the Smalltalk libraries (you literally cannot even loop without a higher-order function). And well-designed Smalltalk code uses lots of very small methods that are composed into more complex methods. Aug 7 '20 at 15:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy