Thursday, 25 June 2015

Clean Code

Who is the customer for your code?

Your customer?

Not likely. They are more interested in your product itself, which may be a compiled representation of your code. 

The computing platform on which it runs?

Some of us may have been led to believe that our code is the language for man-machine interaction. However, the computer understands its instructions in a different format of our code - the byte-coded assembly language. Hence most of the programming languages require their programs to be compiled into this format.

The history of programming languages started with assembly-like languages, moving on in time to the interpreted, procedural and more expressive varieties.

If our code is indeed for the computer to understand, why move on?

A great programmer once told me that the code often outlives the coder. I may have moved on from my first programming job and the code that I had written would still be running. Chances are that, another coder like you, may be looking at that right now and trying to figure a way out of the spaghetti. You are getting lost in my code because; when I coded, I only cared about talking to the computer and forgot about the real customer of my code - You.

Our code is written so as to be read by other programmers. The need for our code to be understandable cannot be stated enough.

A Chinese proverb says, "The best time to plant a tree was 20 years ago. The next best time is now". I have never felt this proverb to be truer than when looking at legacy code. Making way through such syntactical babbles have motivated me strongly to do clean coding.

Eight years of coding using agile methods have taught me the necessity of developing the following six skills to do clean coding well.

Figure: Clean Coding Skills

Skill # 1: Guidelines

As developers, we need a shared vision of the product we are building. We should have some common vocabulary to refer to its parts which would be built incrementally.

Western theology (the Book of Genesis) tells the story about the confusion caused by the lack of a common tongue and the resulting cataclysm in the Tower of Babel. It is time-proven that a common understanding can accelerate the building of any product.

I think this is what Martin Fowler means, when he says that the architecture of our product should be in our heads (instead of comprehensive documentation). Architecture is a metaphor for the product we are building. It should be used to develop a common understanding among the team members. 

Kent Beck suggests a simple test of this shared understanding; ask any three of your team members to describe the main operation of your product using only three classes (or modules). If they all use the same set of classes, you can consider your architecture to be understood.

The next set of guidelines that the team would require are the design guidelines. To start with, we can list our code organization guidelines (folder, module and file level) in this. We can also add any special design guidelines, for e.g. a network security product that I worked on had the guideline to have all buffer allocations only from the heap. Guidelines about how our product deals with memory, database, concurrency etc. may be listed here.

Coding guidelines are indispensable in iterative development. Coding guidelines for most programming languages are easily available as time tested standards and recommendations. Teams can reuse them appropriately.

I suggest that the teams may use static code checking tools to automate most of these guidelines. Many such tools (like PMD, FindBugs, PC-Lint, Coverity, Fortify, KLOCWorks etc.) already automate most of the coding guidelines. We also automated the rest of coding guidelines using regular expression checks. Such automated checks and maintaining a clean sheet is one of the basic steps towards having clean code. We will discuss this further in the context of the "Great Tools" skill.

Skill # 2: Refactor

The best resource available for refactoring (for Object Oriented programming languages) is Martin Fowler's seminal book on the topic. James Grenning complemented it well on the C (procedural) language side with his blogs and his book. I never saw the need for any other references with these available.

How often do I refactor?

As a programmer, half of our time we code, the other half; we (need to) reflect. I refactor whenever I reflect. I found this method to work well and to be in agreement with Kent Beck's analogy of wearing two hats, one for coding and the other for refactoring and frequently switching between them.

For product enhancements involving legacy code, this time may not be enough to refactor the new code and the associated base code. I suggest explicitly planning for refactoring, as a separate story or task in such situations.

Skill # 3: Reuse

Creation always involves building upon something else. There is no art that doesn't reuse.
                                                                                                         - Lawrence Lessig

All of us could use more reuse.

Algorithm obsession is a pattern that tells me that my code could reuse more. In a protocol platform that I worked on, there were more than thirty components which had all implemented the algorithms for atoi (string to number) and itoa (number to string) separately. I have seen teams doing the same for containers, data stores and control block managers; all the while using programming languages (like Java) which offer a rich selection of utilities and plugins for the same.

Replacing my algorithm/utility with a standard one will make my code more intuitively understandable.

Would you rather read the code that uses Stack<Double> (java.util.Stack) or MyDynamicLIFOStack<Double> ?

Next time when you reflect, ask yourself, what can I reuse today?

(p.s: We will discuss the remaining 3 skills in the next blog. Ciao!)

1 comment:

  1. Well written. Can relate to number of dialogues we used have :-)