Quality is too serious to be left in the Craftsmen’s hands!

First contact

I must confess I have something of an ambivalent relationship with the ‘Software Craftsmanship‘ movement. My first contact with it was the discovery of some post about ‘developer’s pride’. personally, I am more a ‘developer’s humility’ kind of guy! Boasting pride sound stupid and short-sighted to me. Reading the manifesto and other articles somewhat moderated my initial reaction: striving for continuous self-improvement, promoting test driven practices are objectives I deeply believe in. Then my next realisation was that Software Craftmanship was basically promoting XP practices. But, instead of making them core to a team based effort, the craftsmanship movement promotes the idea that those must be a personal initiative.

Kinda cute but…

It looks fairly naive to me. Don’t get me wrong, it is important to embrace a quality driven approach, but if you believe you can transform such a large industry by the sheer goodwill of some engineers, I am sorry to say you are gonna be very disappointed. Furthermore, I think this may even be counterproductive as it will eventually create a split between craftsmen and your average developers, the formers being more consistent in their delivery than the seconds, but being significantly more expensive too.

By the way, lets speak it out in the open: quality has a cost, period. And let’s go to the core of the argument: Quality is too serious to be left in the Craftsmen’s hands.

Of course

Yes, it is often a smart investment, but it has an upfront cost. Therefore, it must not be hidden to the customer/product owner/sponsor. Most IT projects main deliverable is a code base and processes that transform this code base to a working software. And this code base is more often than not expected to be extendable, at least decently maintainable. That implies that automated tests are part of that deliverable, and one that significantly enhance the maintainability of it.

The question is then: what is the business value of tests?

Every other industry that I am aware of have a decent appreciation of the value of tests.

At the lower end you will find cheap plastic contraptions made by some sub par eastern factory: we don’t need test to understand we sell crap and replacing is cheaper than fixing.

At the higher end you will find the aeronautic industries where extensive testing is the norm: whenever someone fails, the whole industry is at risk.

Both of those testing strategies are relevant to the business model of the respective industry.

USE THE SAME APPROACH FOR YOUR PROJECTS!

negotiate with your customer/product owner the investment on tests. You have metrics to prove the effort:

– coverage (line or branch)

– mutant testing (demonstrate effectiveness)

Of course, regulatory constraint may as well drive the expected level of quality and testing.

So what about Craftmanship?

If you wanna engage on the Craftmanship journey, you have my full support. But understand that you have to adapt your testing practices to the wishes of your customer.

 

The danger of microbenchmarking

Performance measurement is a hot topic

in IT, and it has always been so. How fast is the new hardware, which RDBMS has the highest TPS, which implementation has the lowest memory footprint…

Nowadays, pretty much anyone with a decent knowledge of a programming language can write some benchmark and publish his results, so benchmarks flourish everywhere.

Please read them with the colloquial grain of salt: measurement is hard and more often than not, the benchmark may include some bias favoring the author expectations. The bias will probably be accidental and of limited impact, but it will be there nonetheless.

But I wanted to discuss about microbenchmarking, with a focus on concurrency related ones.

Continue reading “The danger of microbenchmarking”

Immutability

There is an ongoing craze around immutability and functional programming, and while I appreciate the value they do provide, I start to think that some people are starting to get overboard with this. Others are working on new implementation of existing paradigms.

Joe Duffy did express my point of view better than I ever would, so I will just quote him:

I had grown frustrated that our programming languages didn’t help us write correct concurrent code. Instead, these systems simply keep offering more and more unsafe building blocks and synchronization primitives. Although I admit to contributing to the mess, it continues to this day. How many flavors of tasks and blocking queues does the world need? I was also dismayed by the oft-cited “functional programming cures everything” mantra, which clearly isn’t true: most languages, Haskell aside, still offer mutability. And few of them track said mutability in a way that is visible to the type system (Haskell, again, being the exception). This means that races are still omnipresent, and thus concurrent programs expensive and error prone to write and maintain.

Thread is dead

Here is one abstraction that definitely outlived its usefulness
Threads
They aim at abstracting a processing unit. They were very useful when processing units were a scarce resources, to the point there usually was only of them. Their usage was to allow sharing of that scarce resource.
But at a time where we may have them by tens or hundreds (or even more for the most radical proposition), they are just an impediment we need to ge rid of.

Threads were the training wheels on our bike,

Terror on Training Wheels
Terror on Training Wheels (Photo credit: Dawn Endico)

it is time to grow up and dare ride without them!

The problem with locks (2)

In Why locks suck? I stressed several issues with locks. Today, I will elaborate on their main issues, which is they do not compose. But I need to finish my list first, as I skipped performance related issues.

Locks hurt performance badly,

it is a universally known fact. But what is less known is how bad they hurt performance and why. The main mythos that locks are expensive because they are kernel objects and that user/kernel transition is expensive.

This argument still hold some truth, but the fact is that both Intel and AMD worked on improving this situation in their recent CPU lines, so now the transition cost (back and forth) is less than 300 cycles, same order of magnitude that access to non cached memory.

But the main reason that locks hurt performance, is that they simply stall a core, by triggering a context switch in case of contention, by trashing various CPU caches. Basically, a context switch is quite a catastrophic event from a performance point of view. Here is a complete list of what it may cost:

  • Kernel user transition (always)
  • Stacking and un-stacking of the core state: all registers to be stored for current context + restore for target context (always)
  • Loss of execution context (very likely, unless target context uses same code)
    • loss of branch prediction caches
    • flush of the execution pipeline
    • stack entries are lost from the cache
  • Loss of cache entries for recently accessed data (likely, unless switching to a similar context within the same process)
  • Loss of cache entries for recently accessed code(likely, unless switching to a similar context within the same process)
  • Loss of TLB entries (likely). As a reminder, TLB stands for Translation Look-aside Buffer; this used for address translation computation that is required to implement virtual memory. This happens if you switch to a different process.
  • Scheduling cost: you have to factor in the execution time to elect the new thread to be ran.

When you take all those into account, you realize that the actual latency cost of an execution context is a matter of thousands of cycles, far above the user/kernel transition cost.

They do not compose

I assume most of you had first hand experience with some ‘thread-safe’ framework. Therefore I can confidently state that I have yet to see a ‘thread friendly’ framework. Most of the thread safe framework relies on lock and offer you events or subscription mechanisms which are basically deadlock pitfalls.

You want to see a thread safe framework fail: try to unsubscribe while being notified on that very same subscription. At best, it will raise an exception, but it will probably simply deadlock.

So why locks do not compose? Simply because you need to order them properly! And any significant chunk of code relies on some event/observer/inversion of control/interface implementation/virtual method overloads. We use those as extension points to alter and complete the behavior of existing objects.
And to develop those extensions, one need to be aware of the locks used by those classes. The bais situation is that the classes are not thread aware and use no locks, is typically called non thread safe. It can be a blessing, but it means you have to wrap them somehow. Why extra work?

Then you have the so called thread safe classes, that typically use ‘synchronized’ (in Java) or ‘lock’ ( in C#) extensively; you need to be careful when using their extension points. But the truth is, even if you are careful enougth, the next version of the library, or the next developer that maintains this codebase will probably encounter deadlocks, or even worse, race conditions.
I have been the initial ‘clever’ developer, I have also been the next and even the nth. I have made many, many mistakes, enough of those to be considered as an expert in the multithreading field.

The bottom line is: whatever the locking model is, there is no way you can make it foolproof; even sadder, there is no way you can document it properly. The best you can do, is ensure long knowledge transfer session that would cover both how the locks are used and the general threading model to allow newcomers to add their own locks. And pray for the day when a ‘clever’one will try to refactor the model!

Key takeway: locks are a dead end!
I came to this gloomy conclusion 7 years ago. I understood then than we needed a radically new approach and as none were available at the time. Therefore I decided to act upon this!