All posts by chris

How to Implement Test-Driven Development

Test-Driven Development (TDD) is something I have long had difficulties with. Not because I consider it a bad concept, but found it very difficult to start doing. In hindsight it appears that the advice given in the respective books and online articles was not suitable. So here is the approach that finally worked for me.

It boils down to deviating from the pure doctrine. Instead of writing a test before starting on a new piece of code, I start with the actual code right away. Yes, that violates the core principle, although only for a while. But I have found that in most cases my understanding of the problem is still somewhat vague when I start working on it. So for my brain it is better if I do not have to split its capacity between solving the actual problem and thinking about how to devise a proper test and what all that means for the structure of the future code.

Once the initial version of the working code is there and manually validated, I do add the test. From then on I am in a position to refactor the code without the risk of breaking something. And of course this refactoring is needed because the first version of any code is never really good. While you could write “better” initial code, this would require spending more time upfront than you otherwise need for refactoring later. And it also ignores the fact that you only really understand the problem, when you have finished implementing the solution.

What I later realized was that my approach also helped me to write more testable code. But instead of consciously having to work on it, this sneaked in as a by-product of my modified way of doing TDD. For me this is a more natural way of learning and the results are typically better than following some formal approach.

Martin Fowler: Not Just Code Monkeys

Back in 2010 I had the “pleasure” to be called a code monkey myself. It happened at the global sales kick-off when a sales rep had the nerve to say in his presentation that code monkeys (i.e. presales staff) are not needed for successful software sales to enterprises. Brave statement.

The presentation is a great re-iteration about how developers should see themselves in order to be successful and provide added value to the organization.

Start Working with a Version Control System

Every so often I get asked about what to consider when introducing Continuous Integration (CI) to an organization. Interestingly though, most of the details discussed are about working with a version control system (VCS) and not CI itself. That is understandable because the VCS is the “gateway” for all developers. So here are my recommendations.

Use of Branches

It is important to distinguish between the goal (Continuous Integration) and the means (trunk-based development). Yes, it is possible to implement a system that facilitates frequent integration of code from various branches. On the other hand it is a considerably more complex approach than to simply work off trunk. So in most cases I would argue that simpler is better.

In any case I recommend to also look at using branches and can recommend this video on YouTube as a starting point. Whatever path you choose, it will always improve your understanding of the subject and you do not have to take my word for it.

Number of Commits

Most people that do not use a VCS will typically work through the day and create a file copy (snapshot-like) of their project in the evening just before they leave for the day. So it is a natural conclusion to transfer this approach like-for-like to the VCS. In practical terms this would mean to perform a single commit every day just before you go home. And the commit message would be similar to “Work for <DATE>” or “WIP”.

But instead of doing so, developers should commit as often as possible. In my experience 5 to 15 times for a full day of development work is a good rule-of-thumb. There will be exceptions, of course. But whenever you are far enough outside this ballpark-figure, you should analyze why that is.

Time to Commit

Instead of looking at time intervals, people should commit whenever the code has reached a stable state. Or in other words: It does not make sense to have people commit every 30 to 45 minutes. They should rather do this after e.g. having fixed a small bug (e.g. correction of a threshold). But for changes that require more than roughly 60 minutes of work, things need to be broken down. This will be looked at in detail in the next bullet point.

Especially when starting with a VCS, people will quite often miss to commit when they have completed a somewhat discrete piece of work. That is normal and happens to everybody. Even today, with more than ten years of experience on the subject, I still sometimes miss the point. Adding the step of committing a set of changes to your work routine, is something that really takes time. It is a bit like re-ordering your morning routine in the bathroom. Most people do things in the exact same order every day. Changing something there is just as difficult as performing a commit “automatically”.

What to do when you realize your miss, depends on the circumstances. If this is your personal pet project, you may just virtually slap yourself on the head and continue or do the infamous “WIP” commit. But if this a critical project for you organization and you collaborate with others, you need to undo the last couple of changes until you are back where you should have performed the commit in the first place. Yes, this is cumbersome and feels like a waste of time, especially if you are working under time pressure, i.e. always.

But there is no alternative and anyone who says differently (typically project managers without a solid background in software development) is just completely wrong. Because you need to be able to understand exactly who performed what change to the code base and when. But with messy commits this will not work in practice. Or to rephrase in management speak: It is much more time-consuming and error-prone to go through untidy changes every single time you try find something in the VCS, than to spend the effort only once and correct things. 

Split Up Larger Work Items

In many cases the effort to implement a new feature or fix a really nasty bug will exceed let’s say 60 minutes. In those cases the developer should have a rough a plan how the overall work be structured. For a new feature this could mean something like:

  1. Add test-cases that pass for the current implementation
  2. Re-factor in preparation without changing behavior
  3. Add test-cases for new feature
  4. Implement first half of new feature but ensure that it cannot be executed yet (think feature-toggle here)
  5. Finish new feature and enable execution

Working Code

The example above for how to structure the implementation of something larger has a critical aspect to it. Which is that at every point in time the code in the VCS must be in a consistent and operational (=deployable) state. If things look different (i.e. some parts are not working every now and then) in your development environment, as opposed to the VCS, that is ok. Although it has proven to make life easier when both the VCS and your environment do not stray too far apart from each other.

What I discovered for myself is that the approach has a really nice by-product: cleaner and more stable code. In hindsight I cannot say when this materialized for me. So there is a small chance that from a clean code perspective things got worse before they got better. But my gut feeling tells me that this was not the case. Because an always-working code also means a better structured code, which is by definition more stable due to reduced complexity (relative to a messy codebase).

Fix Immediately

This has been written about many times and I merely mention it for completeness here. Whenever a change breaks the code, and thus causes automated tests to fail, the highest priority is to get things back into a working state. No exceptions ever!

When NOT to Commit

A VCS is not a backup system for your code but a VCS. This also means that you should not simply commit at the end of the day before you go home, unless your code happens to be in a working state. Otherwise, if you feel the need or are obliged to do so, have a backup location and/or script that handles this. But please do not clutter the VCS with backups.

At least in the early days of CI (the early 2000s) it was a somewhat common phenomenon at the beginning of projects that at the end of the day people checked in whatever they had done so far and went home. In many cases this broke the code and tests failed on the CI server. Until the next morning it was not possible for others to work effectively because you cannot reasonably integrate further changes with an already broken codebase. That is bad enough if people are located in one timezone. But think about the effect it has on an organization that works with a follow-the-sun approach.

Commit Messages

The reason for commit messages, in addition to the technical details that the VCS records anyway, is to describe the intent of the change. It does not make sense to list technical details, because those can always be retrieved with much more precision from the VCS log. But why you performed the sum of those changes is usually hard to extract from the technical delta. So think about how you would describe the change in a way that allows you to understand things when you look at them in six months.

In Closing

These are just a few point I learned over the years and have been able to validate with various projects. They are practical and provide, in my view, a good balance between the ideal world and the reality you find in many larger organizations. Please let know if you agree or (more importantly!) disagree.

Related posts:

Transfer of Website Finished

After a bit more than a week the transfer of my web pages to a new hosting provider is finished. The timing was, thanks to Murphy, not optimal since I got the notifications for most domains while waiting in a plane. The latter took almost five hours, thanks to difficulties when landing on La Palma. So instead of 4.5 hours, the flight took almost 12 hours. More details on how the airline really screwed up, may come in another post.

Structuring a VCS Repository

My main programming hobby project will soon celebrate its tenth birthday, so I thought a few notes on how I structure my VCS repository might be of interest. The VCS I have been using since the beginning is Subversion. (When I started, Git had already been released, but was really not that popular yet.) So while some details of this article will be specific to Subversion, the general concepts should be applicable elsewhere as well.

When it comes to the structure of a repository, Subversion does not impose anything from a technical point of view. All it sees is a kind-of file system, with all the pros and cons that come with the simplicity of this approach. It makes it easy for people to start using it, which is really good. But it also does not offer help for more advanced use-cases, so that people need to find a way how to map certain requirements onto that file system concept.

As a result, a convention has emerged and been there for many years now. It says that at the top-level of the project there should be only the following folders:

  • trunk: Home of the latest version (sometimes called the HEAD revision)
  • branches: Development sidelines where work happens in isolation from trunk
  • tags: Snapshots that give meaningful names to a certain revision

You will find plenty of additional information on the subject when searching the Internet. I can also recommend the book “Pragmatic Version Control: Using Subversion“, although it seems to be out of print now.

With these general points out of the way, let me start with how I work on my project. There are only a few core rules and despite their simplicity I can handle all situations.

  • The most important aspect for the structure of my SVN repository is that all active development on the coming version happens at trunk. See this article for all the important details, why you really want to follow that approach in almost all cases.
  • Once a new version is about to be released, I need a place where bug-fixes can be developed. So I create a release branch (e.g. /branches/releases/v1.3) with major and minor version number but not the patch version (I use semantic versioning). From this release branch I then cut the release (v1.3.0 in this case) by pointing the release job of my CI server to the release branch.
  • Once the release is done, I create a tag that also includes the patch version. In this example the tag will be from /branches/releases/v1.3 to /tags/releases/v1.3.0 .
  • Now I return to working on the next release (v1.4) by switching back to trunk.
  • Bug fixing happens primarily on trunk with fixes being back-ported to released versions. There are cases when this is not practical, of course. The two main reasons are that significant structural changes were done on trunk (you do refactor, don’t you?) or another change has implicitly removed the bug there already. But that is the exception.
  • When a bug-fix is needed on a released version, I temporarily switch my working copy to the release branch and do the respective work there. Unless the bug is critical I do not release a new version immediately after that, though. So this may repeat a few times, before the maintenance release.
  • The maintenance release is then cut, again, from /branches/releases/v1.3 . And after that a new tag is created to /tags/releases/v1.3.1 .

Those rules have proven to be working perfectly and I hope they will continue to do so for the next ten years. I have been quite lucky in that, although for me this is still a hobby project, the result is used by many global companies and organizations in a business-critical context. There are at least 11.000 installations in production that I am aware about, so I cannot be casual about reliability of the delivery process.


Changing the Web Hosting Company

After many years I have decided to move my web sites to a different web hosting company. While I am happy with the service provided in the past, the commercial side of things was not so bright. And even when I canceled the automatic renewal of a domain registration, the special offer I immediately got was not exciting.

Which is why I finally started the move this weekend. I have a plan to make the cut-over as smooth as possible, but there is a small chance of temporary interruption.

Raspberry Pi Cluster – Part 1: The Hardware

For  a long time I had wanted my own Raspberry Pi cluster and I finally managed to get started. There will be five nodes, which will give me 20 cores to play with. The overall plan is to manage the nodes with Ansible and run a Kubernetes cluster on them.

Let’s start with putting these boards together. I quickly settled for using spacer bolts. There are special ones for Raspberry Pi available, but I just got some cheap ones from AliExpress, as shown below. They have two disadvantages, though. Firstly, their diameter is a little bit too big for the wholes in the PCB (printed circuit board). So I used a wood drill size 3 to extend the wholes by just a fraction of a millimeter. You can somewhat see the white left-overs from the drilling at the lower left whole in the picture below.

The second problem is that my spacer bolts are pretty short. So in order to avoid short circuiting things, I put insulation tape on top of the USB ports.

With these two small modifications I went ahead and assembled the Raspberry Pis into a nice stack.

As power supply I chose a 5-port 50 watts USB model from Aukey, which I got a while ago from Amazon when they were on special offer. Aukey does such promotions quite frequently, so if you can wait a bit, you will be able to safe a few bucks.

And this is what things look like connected (excluding network of course).

That’s it for today. Stay tuned for the next part in this series.

On Micro Services

Just a couple of thoughts on micro services, triggered by a German blog post on heise Developer. So let’s go …

I have read quite a few articles on micro services, and literally all of them were overly optimistic and just scratching the, of course, positive surface. The examples are usually just slightly more complex than “Hello World” and also completely focused on technical aspects. For a non-deep dive technical exercise these things are ok. But nobody should fool him- or herself: the real world is much more complex.

There is, by the way, a real déjà vu here for me. Many things sound remarkable similar to what was said ten years ago in the context of SOA (Service-Oriented Architecture). Then, also, things like modularity and increased agility were cited all the time. (Re-use was the other standard one, but that did not work in most cases.) So what is really different now? I honestly fail to see anything new.

Instead there are arguments, again remarkably similar to SOA, in favor of faster possibility to adopt, easier deployment of change, and smaller and less complex code. Well, they are wrong. The key here is complexity and what its consequences are. The core complexity comes from the business requirements and not the chosen technology or architecture. And no matter how you slice, dice, and re-arrange things – the business complexity simply stays. Your only chance for survival is to find a clever way to layer things in a manner that makes sense for your business.

You will find that there are things that lend themselves well to (micro) services and of course that is how they should be approached. But you do not really have to have a separate deployment unit for every Mickey Mouse service. Just apply common sense and also keep in mind that things are in constant flux anyway.

So instead of spending much time on micro services, I would rather recommend to think about ways, which ensure that your system/architecture can easily adjust. And from a business perspective that is, of course.