Archive for December, 2009
Our obsession with efficiency – Dan North
Oredev have put some of the videos from the conference on Vimeo and one of my favourites is ‘Our obsession with efficiency‘ by my colleague Dan North.
The slides for the talk are available on SlideShare.
In this talk Dan leads from the following statement about efficiency:
So here’s the thing, I don’t believe in efficiency. It’s our obsession with efficiency that has got us into the current technology mess, and which has led almost directly to heavy waterfall processes. Efficiency is how you let the big vendors sell their bloated technologies to the poor CIOs.
What did I learn?
- Dan spends quite a bit of time explaining how what we should really care about is effectiveness and not efficiency. Efficiency is defined as:
the accomplishment of or ability to accomplish a job with a minimum expenditure of time and effort
which makes sense in a way but what tends to happen is that achieving that becomes our goal at the expense of everything else. For example adhering to the DRY principle is considered a good thing and not repeating code is efficient. However, if we take that to an extreme then it results in code that is difficult to understand and difficult to change which defeats the purpose of that efficiency.
In lean terms we want to look to favour the big picture over local optimisations whereby we start to measure our effectiveness rather than efficiency. i.e. we focus on the results rather than the effort.
- Later on he points out that effectiveness is often inefficient which makes a lot of sense to me.
Pair programming is not an efficient way to get the most code produced – we can do that much more efficiently if we have people working individually. However it allows us to create a much greater shared understanding of the code, reduce the defects and increase the cohesion of that code which is a more important goal overall. The same can be said for something like set based concurrent engineering where we work on two solutions simultaneously and then throw one away. It’s inefficient but we can delay potentially making the wrong decision so it makes sense to do it.
- Dan also suggests that ‘you get what you measure‘ and lists a series of examples where aiming for a certain target is actually not very effective and doesn’t give us what we want anyway.
For example if our goal is to have all the tests passing by the end of the month then we may be tempted to comment out failing tests to achieve this. One which I notice quite frequently is aiming for a story point total which tends to result in reduced communication between business and IT and we end up delivering features that may not have that much value. It might seem to be locally efficient but in the grand scheme of things it’s not efficient at all.
- There’s also some discussion around the desire for people to be ‘busy’ all the time which is quite common from my experience. Dan points out that if we can get to a stage where we have time when we’re not busy then we have more time to think about what we’re doing and perhaps we can even spend this time innovating. I think the key here is to ensure that we’re still doing something which is contributing to the overall system goal rather than not doing nothing at all!
There’s loads more – it’s a very good talk – but these are some of the bits that stand out for me.
Clojure: Unit testing in the REPL
One thing which I think is great about coding with F# is the quick feedback that we can get by defining and then testing out functions in the REPL.
We can do the same thing in Clojure but it’s even better because we can also define and run unit tests which I think is pretty neat.
Nurullah Akkaya has a good post which describes how to use clojure.test, a testing framework written by Stuart Sierra so I’ve been using that to define some tests cases for the little RSS feed parser that I’m writing.
To use clojure.test straight out the box you need the latest version of the clojure source code as Stuart Sierra points out on his website.
I ran the ant task for the project and then launched the REPL pointing to the ‘alpha snapshot’ jar instead of the ’1.0.0′ jar and it seems to work fine.
I managed to break the ‘get-title’ function while playing with it before so I thought that would be a good one to try out the tests in the REPL with.
This function is supposed to strip out the name and the following colon which appears in every title and just show the title of the blog post.
I originally had this definition:
(defn get-title [title] (second (first (re-seq #".*:\s(.*)" title))))
I hadn’t realised that this strips from the last colon in the string and therefore returns the wrong result for some inputs.
I created the following tests:
(use 'clojure.test) (deftest test-get-title (is (= "Clojure - It's awesome" (get-title "Mark Needham: Clojure - It's awesome"))) (is (= "A Book: Book Review" (get-title "Mark Needham: A Book: Book Review"))))
We can run those with the following function:
(run-tests)
FAIL in (test-get-title) (NO_SOURCE_FILE:19) expected: (= "A Book: Book Review" (get-title "Mark Needham: A Book: Book Review")) actual: (not (= "A Book: Book Review" "Book Review")) Ran 1 tests containing 2 assertions. 1 failures, 0 errors.
Changing the function helps solve the problem:
(defn- get-title [title] (second (first (re-seq #"[a-zA-Z0-9 ]+:\s(.*)" title))))
Ran 1 tests containing 2 assertions. 0 failures, 0 errors.
We can also run the assertions directly without having to call ‘run-tests’:
(is (= "A Book: Book Review" (get-title "Mark Needham: A Book: Book Review")))
true
(is (= "Something Else" (get-title "Mark Needham: A Book: Book Review")))
expected: (= "Something Else" (get-title "Mark Needham: A Book: Book Review")) actual: (not (= "Something Else" "A Book: Book Review")) false
Nurullah has more detail in his post about how to integrate tests into a build although I don’t need to do that just yet!
Book Club: Working Effectively With Legacy Code – Chapter 11 (Michael Feathers)
In our latest technical book club we discussed chapter 11 – ‘I Need to Make a Change. What Methods Should I Test?’ – of Michael Feathers’ ‘Working Effectively With Legacy Code‘.
In this chapter Feathers covers some techniques which allow us to work out which parts of the code we need to write tests around when we make changes.
These are some of my thoughts and our discussion of the chapter:
- Feathers starts off the chapter by introducing the idea of effect sketching which I’ve been trying out recently both on the projects I’ve been working on and with the Unity dependency injection container.
The idea is that we create a diagram which shows the effect that changing different fields and methods will have on the rest of the class and then based on this we can see where we need to create a safety net of tests for any given change.
It seems like this type of diagram would also be quite useful for identifying when a class has more than one responsibility because you would end up with several mini unconnected effect sketches within the main one.
- Feathers suggests that we should look to write characterisation tests around legacy code. These are written a little differently to TDD’s tests because we make the assertion match what the code is currently doing. The idea is to document what the system is doing now. We might come across ‘bugs’ while doing this but we wouldn’t necessarily change the tests to verify how the code ‘should’ be until we find out what the effect of doing that would be.
We want to write enough of these tests that we feel confident that we have a good enough safety net to allow us to change the code.
- There are some interesting ideas about encapsulation towards the end of the chapter where Feathers considers the trade off between ensuring test coverage and encapsulation.
Breaking encapsulation can make reasoning about our code harder, but it can make it easier if we end up with good explanatory tests afterward.
…
Encapsulation and test coverage aren’t always at odds, but when they are, I bias towards test coverage. Often it can help me get more encapsulation later.
Encapsulation isn’t an end in itself; it is a tool for understanding.
I find this is sometimes quite a big barrier to break down because people are often reluctant to change code to make it more testable. That’s sometimes a valid concern but with legacy code not so much.
Fundamentals of Object-Oriented Design in UML: Book Review
One of my favourite recent blog posts is one written by Sammy Larbi on coupling and cohesion and while discussing it with Phil he suggested that I would probably like this book and in particular the chapter on connascence which I’ve previously written about.
The Book
Fundamentals of Object-Oriented Design in UML by Meilir Page-Jones
The Review
I really enjoyed reading this book and I think it’s one that I could come back and read again to gain something else from in the future.
Nearly all the mistakes that I’ve made and seen made with respect to the design of object oriented code are outlined in one form or the other in this book.
The book is split into three sections. The first discusses some fairly basic object oriented concepts, the second covers UML as a notation for describing our designs and the final section goes more deeply into the principles of object-oriented design.
What did I learn?
- Although we don’t seem to use UML much these days I was coming to the conclusion while reading those chapters that perhaps UML is useful as a design tool but the aim shouldn’t be to come up with a UML diagram, but rather to drive a design in code.
This is something which Uncle Bob also touched on recently:
Is TDD a replacement for design?
No. You still need all your design skills. You still need to know design principles, and design patterns. You should know UML. And, yes, you should create lightweight models of your proposed software designs.
We actually found on a project I worked on recently that everyone had a different way of diagramming a design and it would have been useful to have a common notation between us. UML is surely the tool to solve that problem.
- I quite like the way that Page-Jones describes the different types of messages that objects can receive:
- Informative – a message telling an object about something that happened in the past.
- Interrogative – a message asking an object to reveal something about itself.
- Imperative – a message telling an object to take some action on itself.
An interrogative message is effectively a getter whereas the other two are commands being sent to the object. I’ve not seen the distinction between events which happened in the past and those which are going to happen in the immediate future.
- I’ve frequently come across the idea of information hiding when it comes to designing objects but Page-Jones introduces the idea of implementation hiding which I think is really neat.
The idea is that while some information about our object will be viewable to other objects e.g. through attributes/getters, we can still hide the implementation of that information internally so that if we we want to change it in the future then we won’t have to change all its clients too.
- I found the concept of the rings of operation really interesting. The idea is that there are some methods on our objects which just make use of other methods on the same object. Those methods wouldn’t touch any of the fields of an object directly but would rely on those methods in the inner rings to do so.
For example if we have a getter on an object to access a field then if other methods on that object want to access that field they should go via the getter instead of accessing the field directly.
I often find myself avoiding using getters with the hope that if don’t increase their usage then it will be easier to get rid of them in the future. This approach would discourage doing that.
- I like the idea of type conformance when it comes to inheritance – we should try to ensure that any sub types adhere to the contract of their parent.
The other part of this chapter describes ‘closed behaviour‘ – all the operations on any class that we inherit from should obey our class’ invariant.
I think this can be where we go wrong when we write classes which extend a List for example. The API of a List will typically have ‘Add’ and ”Remove’ operations but on a lot of the application I work on we only want the ‘Add’ functionality and not the ‘Remove’ option. Page Jones suggests that if we want to use inheritance in this situation then we should override methods on the super class to make ‘Remove’ do nothing.
- I now find that I prefer Page Jones definition of cohesion:
Class cohesion is the measure of interrelatedness of the features (the attributes and operations) located in the external interface of a class
I’m inclined to believe that we might be able to tell how related the features are by looking at the clients of the class and seeing whether they are all using the class in similar ways.
He then outlines three signs that we have cohesion problems with a class:
- Mixed instance cohesion – a class has some features that are undefined for some objects of the class. I find that this typically happens when we try to make a generic data type to cover everything and then try to jam any variations on the type into the same definition. It is typically solved by pulling out another class. This is the worst type of cohesion.
- Mixed domain cohesion – a class contains an element that directly couples the class with another class that is unrelated domain wise. This typically happens when we mix infrastructure code into our domain code.
- Mixed role cohesion – a class contains an element that couples it with an unrelated class in the same domain. I think this is the most typical type of cohesion that I’ve seen and the main problem is that we end up with classes which have multiple roles which makes them difficult to change.
In Summary
There’s way more in this book than I could ever hope to cover here but these are some of the interesting bits that stood out from this reading of it. I’m pretty sure that I’ll come back to this one in the future.
While reading the book I had the feeling that some of the ideas are quite similar to those in Domain Driven Design and since this book was published it contributes to my belief that a lot of DDD is covered by just doing OOP well.
Overall this is a really good book, worth reading.