Thursday, 29 July 2010

Where Did Our Knowledge Go?

I found myself pondering where a lot of the knowledge created in our processes and code goes recently. I overheard some people discussing re-factoring some code. Re-factoring it to the way it used to be, although they didn't know it: they hadn't done the original re-factor. Now I found it rather difficult to give a convincing argument other than "there were very good reasons why we moved away from that", but I couldn't remember all of them: they had come from a variety of people and it was a decision made by consensus.

So where did that knowledge go? More to the point, how can we keep hold if it when we've made the same decision again. (And also, wasting a load of time discussing it and perhaps some time coding it before someone has the eureka moment and re-spots why it was a bad idea in the first place).

As I learned from Don Norman in The Design of Everyday Things, that knowledge of how things work should be "placed in the world", as opposed to in the user's head, and I believe the same is true of our code. Not just how it works, but why it is the way it is also. This was actually a bit of a u-turn for me, as I used to dislike code comments that stated a reason for change, or worse (as I then saw it), an original line of code commented out with a commented reason for doing so. Let's look at the ways our codebase contains our knowledge and how it can perhaps encapsulate and remember the decision making process for us.
  • First of all, we strive to write code that communicates design intent implicitly: this is just good practice. However, all this effectively communicates is the way the code is now, and has no history.
  • Comments are a good place for a more complete presentation of a design, perhaps including the reasons why a different candidate design might not be so suitable. One of our engineers lately told me that he was focussing quite a lot of attention on commenting the implementation of classes as much as their interfaces, and I can see how this helps to retain a lot of our knowledge by explaining the design criteria for the implementation, rather than just the final decision. Comments are fairly cheap, and there are many other reasons for commenting well. All that's required here is an additional perspective on the comment, a new reason for writing it.
  • Our source code control system can potentially tell us about the decision behind changes, provided we write good commit messages. Thinking back over some of the commits I have made that covered a re-factoring, I can honestly say that I didn't record enough of the knowledge generated during that change. Most importantly, there possibly wouldn't be enough there to dissuade another engineer from switching back. Source code control is cheap, practically free, and focussing just a little more effort on those commit messages could potentially give a lot of bang for buck in the context of this discussion.
  • Finally, good design documentation made as part of our development process can be an excellent place to look if you are reviewing the decision over a particular aspect of a design. This is, however, perhaps the most expensive ways to keep a record of the technical and design specification decisions that we wish to live on.
What have I learned from this musing? For a start, I've learned that my memory is nowhere near good enough 2 or 3 years down the line and I need a concrete recording of the way we design our software. I've also learned that I can rely on some automated tools to keep a track of these things for me, but if I want to be sure, then any decision making logic needs to be recorded, ideally at the site where it will be needed. Since starting this blog, I've actually put some of this into practice and done the following:

  1. Written a load of comments in a few new classes to explain the reasoning behind the storage choices. I could just assume everyone has read Effective STL (and that's thankfully a valid assumption with my colleagues!), but that doesn't communicate the fact that I traded insert speed for fast iteration, because the class is accessed thousands of times per seconds, and only updated once in a blue moon.
  2. Written much more complete commit messages that explain the original problem, what caused it and, most importantly, how the changes made addressed it.

Perhaps there are more code-bound ways to achieve some of this. I'm thinking along the "modern C++" that the likes of Alexandrescu propose, where policies can be used that embody the decisions quite clearly and explicitly, and most importantly in code. After all, someone can edit or delete my comments and the code will still work just the same. If I come back to any of my carefully crafted files to discover a carefully explained decision and implementation has been replaced with something new and the comment:
// This seemed to work better
Then I'll be pleased that someone improved on the design, but pissed off that they didn't care to enlighten me!

But I'm sure I'll continue in the same vein as I've set out on, as I've found that I feel much better about the code I've recently committed. This is because I'm much more confident about how it will be read and received by other coders down the line, as they'll understand the design process, as well as the end result.

No comments:

Post a Comment