August 22, 2013

...Learn TDD with Codemanship

Published Interfaces & Common Courtesy

The mainstream media often depicts software development as a lonely activity, with us lowly "geeks" (that's what they like to call us) staying up 'till all hours - probably in our mum's basement where we still live - poring over the details of the Visual Basic GUI we're rigging up to track the killer's IP address.

In reality, software development is far from a game for one and no more players. Software doesn't happen in a vacuum. For a start, there is other software, and therefore other software developers.

When I started my career as a programmer, this fact loomed large on people's radars. It was the early years of component-based development - an evolution of the kind of architectures that were popularised by UNIX, where our software glued together third party components that already did stuff we found useful in our own code.

Reusing other people's software creates dependencies on that code and therefore on the coders who coded it. Sometimes we were writing the component that got reused, sometimes we were reusing someone else's component.

Rules were well-established by the time I started doing this for a living on how everyone could get along and play nicely in this complex heterogeneous web of dependencies.

The first rule was that reusable components should work. We should be able to trust them, to depend on them, to do what it says on the tin. This concept was best formalised in Bertrand Meyer's discipline of "Trusted Components". It's a dangerous world indeed when all our software depends on things that are not dependable.

Assuming the components we shipped were trustworthy and dependable enough, once we'd shipped them, lots of other programmers might start writing code that reused them. We learned long before I was born of the consequences of this. If, for any reason, we changed the contracts for using the services of one of our components - e.g., we added a new parameter, or tightened a pre-condition - then that potentially broke a lot of client code that other people had written against our API. It may have been a small change for us, but it could stack up to a huge change effort - with an associated huge cost - for everyone depending on us.

So we agreed not to do that unless we really, really - cross our hearts and hoped to die - absolutely had no other choice. In practice, it meant that the benefits of changing an API had to outweigh the potential costs incurred. The more code out there depended on us, the bigger the pay-off had to be. And, as a common courtesy, there had to be sufficient benefit - e.g., in enhanced functionality or better performance - for the client code developers and their end users.

So, on top of that basic principle of Trusted Components, we added the principle of published interfaces.

A programming interface, once made available for other developers to use - through a release process, presumably - could only evolve in such a way that code written against previous versions of that API would not be broken by those changes.

We may well be sitting alone, late at night, in mum's basement, surrounded by pizza boxes and empty Mountain Dew cans, writing VB apps to track murder suspects. But it's very likely that our app is built on top of software that's already been written, requesting the services of said 3rd paty code through published interfaces. That is a means by which we are now interacting with other software developers.

And if we were to offer our VB-killer-IP-address-tracking software as a library for other developers to reuse in their mum's basements, that is how they will interact with us.

I threw in the phrase "common courtesy" earlier quite deliberately, because that's what's needed in any dialogue - even one taking place through published APIs. By keeping our APIs backwards-compatible with previous releases, we show client code developers the common courtesy of not breaking their shit every time we do a release.

I only bring this up because I've been getting the sense that this courtesy has been somehow lost in recent years. APIs are more important than ever, with some pretty huge businesses publishing and consuming 3rd party code over Teh Internets, and the potential costs of changing these APIs - including the rules for using them - can run into billions of dollars taken as a whole. And yet, some pretty big-name players appear to have no qualms about breaking client code to serve their own - as it turns out, probably nefarious - purposes.

I had a 6am Skype pairing session with a client in India this morning who has been dealing with precisely this problem. Due to API changes by a web company whose services his business relies on, he's suddenly found that a big chunk of their code will now have to be re-written. And this is all so they can get to a point where their software did what it did before the supplier broke it. There is no benefit to his business, just cost.

As far as I'm concerned, that is the height of rudeness.

So, my two tips for working with 3rd party libraries and services:

1. If you're writing the client code that consumes these services, make sure the core logic of your software is protected from changes to those APIs. Wrap up the mechanics of interacting with the APIs behind interfaces that you own, and leave the tiniest sliver of integration code that does the actual interacting in one place. This will also have the benefit of making those external libraries and services swappable and mockable.

2. If you're writing components or services that are to be reused, and you want to know if the latest version will potentially break existing client code, then run the old tests* against the new code. (Since test code is client code, too.) If any tests fail, that means a change you've made may break existing client code, and your new version isn't backwards compatible.

3. (And this is very important) If you absolutely must change the API in a way that's not backwards-compatible, involve the client code developers in that decision. You're about to make a costly decision on their behalf. What is the motivation for doing it? What are the benefits to them? Do they think it will be worth it? Don't just spring it on them (if you'll excuse the pun.) Engage them in a dialogue

* Tests that only use the published interfaces, obviously

Posted 7 years, 5 months ago on August 22, 2013