Reading Kent Beck’s post about Ordinary and Extraordinary Design reminded me of a long-running discussion on a long-running project about what refactoring is for and who decides how much effort should be expended in refactoring. Over time we came to recognise two different types of refactoring – small and large scale – that are, perhaps tangentially, related to Kent’s ordinary and extraordinary design.
Small scale refactoring – reifying, removing duplication, renaming, and anything that removes the nasty, smelly, cruddy bits of code that make coders feel bad – is the inalienable right of the XP developer. Refactoring is the process by which the developer makes the environment they work in (the code) a pleasant place to be. The customer or the management team have no right to ask the developer not to spend time refactoring and they trust that the team will organise themselves such that the time is spent well (not too much time spent making pedantic changes or going backwards and forwards between different designs in a refactoring war). The importance of making the code a pleasant place (read: well designed) shouldn’t be underestimated: it has a direct impact on productivity, ease of innovation, ease of adoption (bringing new people onto the team or transferring ownership to a new team), estimate reliability and so on.
Large scale refactoring – rengineering some part of the system to a new approach, upgrading to a new version of the infrastructure, or whatever – is something that I believe has to be scoped, agreed and prioritised with the customer. There are two main reasons for this: the first is that this level of refactoring is likely have an impact on the ‘visible productivity’ for the iteration, i.e. significant effort needs to be spent on work that appears to have no effect from the user’s perspective. So the user needs to be comfortable with how the refactoring will affect their schedule. This is different to small scale refactoring where that effort is amortised across lots of different tasks that result in user-visible changes because the effort is in addition to rather than part of ‘normal work’.
The second reason is even more important but perhaps more controversial. Personally I believe that any work to, say, move from a point-to-point communication mechanism to a message bus, that can’t be explained in terms of benefits to the end users and customers, cannot be justified. Such a piece of work is (or should be) motivated by very different concerns to making the code a nice place to work in. Perhaps we’re worried about performance or scalability, perhaps we’re worried that it will be increasingly difficult to add new types of event consumers, perhaps we’re worried that our home-grown code isn’t robust or secure enough and want to replace it with a suitable off-the-shelf product. All of these types of concerns can be expressed to the customer in ways that allow them to make value and priority judgements in the same way they do for more feature-oriented changes.
[Of course all this presupposes that you have a customer who will work with you to understand the value of such non-functional work. And it requires you to be good at explaining that value in terms they can appreciate. I've had customers who believe better scalability or security is 'down to the techies doing their job' and then get upset when the technical team overrules their priorities to do some large-scale refactoring. Equally I've seen techies use fear, uncertainty and doubt to 'con' the customer into allowing them to make large changes that probably weren't justified in the context of business prorities. No surprise: XP requires trust and effective collaboration to work.]
As Kent asks in his article ‘so what’? Well I think its important to understand the different motivations, actions and responsibilities in the two types of work and, especially, where the responsibility for decision making lies. In small scale refactoring the motivations, actions and responsibilities are all with the developers. In large scale refactoring the actions will still be the developers, the motivations need to be shared with the customer, and the responsibility for giving the go-ahead and prioritising needs to lie with the customer.