Tag Archives: clean code

There was a conversation around software quality over at the Software Craftsmanship slack team. It's an interesting subject but it often becomes confusing. Some of the questions that comes up are: What is software quality and how can we measure it? I'll try to add my twopence to the topic here, and perhaps make it slightly less confusing.

Lets start with a definition and then go from there. Oxfords English Dictionary has this to say on the subject:

The standard of something as measured against other things of a similar kind; the degree of excellence of something

To make sense of that definition we need to understand the context. What "something" is and what "other things of a similar kind" is.  To me this is pretty simple. The only person that can define what "something" is are the users of the software. In an enterprise system this is the enterprise user. In a API library it's the programmer using it. In the case of an end user application, such as a word processor or a game, it's the end user. And they will naturally measure this against other similar products or against their perception of how other similar things should work.

So my definition of software quality is:

The standard of said software as the end user of this software perceives it, measured against other similar software or the end users perception of how other similar software should work.

This makes my measure of quality rather narrow. I'm actually only interested in how my software is perceived by the users. This is also how I receive the measuring points needed to define what quality in my solution is. Therefor such tools as code analysers and test coverage is only important as long as the feedback from them helps me guarantee that the end user receives high quality.

So now what we are left with is understanding what the end user values as quality. As we start out, trying a new idea on the market, quality for the user may well be speed. It's certainly what we need to know if we should continue. To achieve this we create a PoC (Prof of Concept). This is often not a very well designed piece of software. It may well be something we will throw away a week after release. It's is as little as is possible to receive the feedback we need. If the users likes to use it we know it provided them with quality. Now we need to sustain and improve this quality.

As we continue to stabilise and improve our product we need to ensure that the user does not experience a regression in quality. Then they may well leave us for a competitor. To achieve this we need to ensure we have well tested and well crafted code. Here all the tools we can use to detect if our code is up to the high standard we need are of great help. Tools such as static code analysers, test coverage and so forth. Practices such as code reviews and pairing. The definition of quality is till the same however. Only the measures differs.

With this kind of definition I think it's easier to justify and measure what quality is. Keeping it this way makes it easier for all involved to relate to quality. And quality often comes up in conversations when we talk about the software we work with. Most commonly people try to refer to code quality and has a perception that well crafted clean code is what we always must strive for to achieve software quality. Clean code is important in many contexts. But not always. Sometimes speed is what we need. Short term speed and throw away code. It is, as always a matter of trade offs.

 

A couple of years back I wrote an article exploring a way to apply Robert C. Martins guidelines on how to create clean functions, taken from his book Clean Code. This created quite a stir on DZone where I also published it.

A comment from Steven Jeuris about a week ago on my blog made me want to revisit the subject again.

Since I wrote the original article I have leant a lot about creating clean functions that does one thing. And as I replied in to his comment I would not design the code in the original article the same way now.

The key to applying the guidelines in the book is pragmatism. There are a number of benefits from working as is suggested there. I will cover some of them below. But it cannot be followed religiously. It is after all software we are creating, not religion.

Steven Jeuris writes, in his blog on the subject, that a perfectly good way to make code in a function readable is to create blocks with comments. This to me is an anti pattern. There are few reasons to ever create blocks in a function, if they are required it generally indicates that the function is to long. Comments are almost always a bad idea. If a comment is required the block should be put within a function bearing a name that explains what the block does.

Steven Jeuris further writes that new small functions litters the name space of the class. I can see where he is coming from but again I have to disagree. If the name space of a class is littered by explanatory function names then it sounds like the class is to big and needs to be refactored. To me it sounds very much like it does more then one thing.

There is also an interesting side effect to creating smaller more atomic functions that does one thing. It is easier to find commonalities between the other, higher level, functions within the same class, or even related classes. This actually makes it easier to keep the code DRY (Don't Repeat Yourself).

Another very important factor to keep in mind when working like this is what patterns the rest of the team are used to. The size of functions and the way to work with them are not a one size fits all. If a team is used to procedural code the step to extract till you drop style functions will be really confusing. If, on the other hand, the team is used to atomic, do one thing only, functions it is hell to work with larger functions littered with comments and artificial blocks.

In any case, I know that if I would do the same exercise to day as I did when writing my original article on the subject it would look different, and the original definitely takes a good thing way to far.

In the project I am currently working on I have a lot of code to write. It's a green field project delivering a new platform and I have no frameworks to borrow from or extend. So I have to write the code for each single feature by hand.

I am not complaining. I like writing code. But it takes time, especially since it's only me on the project at the moment.

Thankfully it's all written in Python so it's not to verbose, though even Python is verbose when you have to write this amount of repetitive code.

Which is how we come to the value of clean code. The code is slowly transforming by refactoring and transformations. The effect of this is that there is no repetition in production code, it is completely DRY. In tests there is little repetition, this to make the tests document the production code.

The effect of this is that although the upfront cost, before any abstractions had been created, was slightly higher the cost of adding new features now is very small. To create a function that initially required 40 lines of code excluding tests now requires 5 to 10 lines. The test abstractions are so easy to use that it takes next to no time even though some repetition (sequentially calling the same methods in each test method to explain the steps required to use the function) is needed.

The conclusion to this is that the returns of clean code is rather immediate. Many seems to think that the returns are slow and far in the future. I know this to be the opposite. The returns are almost immediate and are currently cutting development time radically. And that is on a code base which has only a couple of thousand lines of production code.

I use nosetests when running my python tests. It is a really neat little tool that will automatically discover and run all tests in the project with one single command line command - nosetests.

But it has more neatness then this. With a simple option it will also print test coverage for the project: --with-coverage, and if coverage should be calculated base on specific packages then use --cover-package which takes a list of packages to calculate coverage on. This is useful when there are library packages for a virtual env or similar within the same directory as you run nose.

I don't like to leave lose ends so to ensure that there are no lingering compiled *.pyc files sitting around I run the following script before commit:

Where <source-dir> should be replaced with directories where source files are. This is a space delimited list. And <package> is replaced with packages which should have coverage statistics calculated.

DRY (as in Don't Repeat Yourself) is one of the corner stones of a clean and agile code. This is especially so with the production code but also with test code where finding good abstractions will greatly increase speed and lower maintenance.

When working with python I have found a very nice tool called Clone Digger that helps finding repetitions in code. It is easy to set up and work with and the report is clear and easy to read.

Install it with pip:

pip install clonedigger

When installed it is automatically added to the tool chain. To run it use the following command:

clonedigger package

Package is the directory where the python code is to be found. Clone digger takes a list of packages separated with space. --help will show help on options and configuration.

Clone digger will work it's way through all files in each package and compare them, both within each package and across package listed in the same invocation. If there is code, such as auto generated code, that is not modifiable, it needs to be removed from the packages added in order for the tool not to analyse them.

It will generate a report looking like the one below to output.html (this is configurable).

Clone Digger output

Working with tools like this makes it easy to spot where new abstractions should be added to remove code duplication. Both in test and production code. Where ever repetition is found which does not fill an important documenting function (which is sometimes the case in tests) it is easy to spot where and how a method should be added to pull the functionality together. It will also help in naming such methods. There are of cause some false positives. Especially in the test code where method bodies are often descriptive rather then dry. But even here it helps to find common assertions which can be pulled up and made into new descriptive methods. This becomes especially valuable when working with given-when-then in tests.