Just the other day I was skimming through a list of topics to post here that I had crafted, and just realized that several of them had a very common, yet simple, motif: improving quality of code. This can sound quite sensible and simple to a lot of people, yet its an idea as powerful as it is controversial. And when I speak of quality of code, it is important to stress that this is the code for humans, as a machine doesn’t really care about it. Setting up this theme, Martin Folwer’s statement feels quite appropriate:
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
-Martin Fowler et al, Refactoring: Improving the Design of Existing Code, 1999
This statement is almost a Quality of Code Manifesto. More precisely, it is about readability, but both concepts are very intertwined. Readability is essential to write code with good internal quality (quality as measured by the programmers). Kent Beck, on Extreme Programming Explained, also mentions how high external quality (quality as measured by the users) can’t be maintained with a low internal quality:
Temporarily sacrificing internal quality to reduce time to market in hopes that external quality won’t suffer too much is a tempting short-term play. And you can often get away with making a mess for a matter of weeks or months. Eventually, though, internal quality problems will catch up with you and make your software prohibitively expensive to maintain, or unable to reach a competitive level of external quality.
Martin Fowler explains these interactions on a article called Technical Debt. Summing it up, code with poor quality is hard to maintain, hard to change, and therefore, costs a lot more in the long run than code with a good internal quality. Not to mention that it lacks transparency, and this can go really bad even outside software programming.
This is such an old issue, that I felt a bit insulted when I read the following (from this post): Java (the programming language) is Turing complete so no new language feature can enable us to solve a problem with Java that would be unsolvable without the language feature.
All of this sounded me absurd, since languages are tools to express code. If being Turing complete was enough, C would be all everybody needed, regardless of being a terrible language to express intention, and therefore, to make readable code. However, the author continues: Therefore any new language feature is at best a convenience to those reading and writing the code. Such features of convenience are not to be lightly dismissed, as they allow developers to increase the signal to noise ratio of our source code.
Therefore, in order to create good code, several practises, tools and concepts were created to helps or warn us: design patterns, DSLs, peer review, object orientation, functional programming, architectural patterns, agile methodologies, refactoring, pair programming, encapsulation, inversion of control, automated tests, code generation, anti-patterns, continuous integration, logic languages, fluent code….
And several of these topics are to encompass this metaphysics.
Fluent style of coding is quite important on internal Domain Specific Languages (DSLs) on languages that support OO. One of the key aspects of a fluent interface is method chaining, which allows the developer to reduce noise (the amount of repeated text) on the code by invoking several methods on the same object, one after the other. Just as in the good old fashioned Don’t Repeat Yourself (DRY) spirit, less noise.
However, fluent code is not only appropriate for DSLs. It can greatly improve code readability and intention revealing even on simple tasks, such as building a complex object.
For instance, let’s take a simple example of configuring an email. You can do lots of things to it, such as configure the sender, the subject, the body, and so on. In Java, such code would become:
new Email() .from("email@example.com") .subject("metaphysics") .to("firstname.lastname@example.org") .cc("CIA@usa.gov")
Instead of the usual, full of noise:
Email email = new Email(); email.from("email@example.com"); email.subject("metaphysics"); email.to("firstname.lastname@example.org"); email.cc("CIA@usa.gov");
A problem arises when the class you want to use method chaining on classes that are not already fluent and you do not have write access. Maybe you are using it from a library or from a Framework you have to use. On languages with static typing such as Java, the only solution is to create yourself a static wrapper (more specifically, a proxy) around it, and just delegate the methods to the real implementation.
On languages with support for method lookup alteration and interception, such as Ruby’s missing_method and Smalltalk’s doesNotUnderstand:, you can make such wrapper a general one. Example of such in ruby:
class Email attr_accessor :to, :from, :subject, :cc end class Wrapper def initialize(wrapped) @wrapped = wrapped end def method_missing(m, *args, &block) setter = m.to_s + '=' if @wrapped.respond_to?(setter) @wrapped.send(setter, *args, &block) else raise NoMethodError end return self end end mail = Email.new Wrapper.new(mail). from('email@example.com'). subject('metaphysics'). to('firstname.lastname@example.org'). cc('CIA@usa.gov')
The beauty is: Wrapper is general. You can take any object of any class you like and, just like that, use a fluent interface around it. You can do this in Smalltalk as well, but Smalltalk is naturally fluent, because of the semicolon:
email <- Email new from: 'email@example.com'; subject: 'metaphysics'; to: 'firstname.lastname@example.org'; cc: 'CIA@usa.gov'; yourself.
Regarding Java language, even though you cannot make a fluent universal wrapper as you can do in ruby (dynamic proxies can’t change the interface, neither can Aspectj), there are some good perspectives ahead:
…the moment you open your mouth to say one thing about the nature of reality, you automatically have a whole set of enemies who’ve already said reality is something else… Writing a metaphysics is, in the strictest sense of the word, a degenerate activity.
— Robert Pirsig, Lila
Edit Apr, 2017: Rest in peace Robert