I’ve recently watched this video of Robert C Martin giving a Clean Code talk at Java Forum in Stockholm. This post will be a mix of description of the talk, and my thoughts on the content.
It opens with quite an entertaining piece, that has nothing to do with the talk, on lasers and how we discovered the speed of light. It made me laugh at least.
Robert goes on to discuss why code rots over time, from the lightning fast, clean world of green field development, to modifying a now complex and enormous code base. The reason it rots is that developers make small mistakes, but these small mistakes keep building up and up, until the code is a large pile of small mistakes that happen to work together.
Now this build-up happens because developers are afraid to clean code, because if you try to clean code, you will break it. So we leave it, we tell ourselves “someone else will do it”. That someone else may never come along, and you are the one who gets assigned the bug that means working on that code. It’s your problem now… Don’t you wish you had cleaned it earlier?
To avoid the fear we need the safety net of unit tests, to give us the confidence that any change we make does not have unintended consequences outside of our immediate context, and also to give us a point where we can boldly declare, “This code is clean” and just as importantly, it still works.
However, writing tests can take just as much effort as writing the real system code in the first place, so how about dealing with it in small chunks? Write a test for a small bit of code, then write the code, test, code, test, code. Wait… Write the tests first? Yes, TDD. This is something I have heard about, read about, told myself to practice, but so far I have failed. I intend to remedy this; my estimates at work will need to increase but it should result in a better product, a better programmer. I see it as an investment now to reap rewards later. Now I just need to get management to see it that way and accept higher estimates.
As an aside Robert proposes an interesting idea for a metric to use in gauging how productive a team is: How good are they at using the debugger? He postulates that the relationship is inverse, as the only way to be good with the debugger is to spend a lot of time using it, and the more time you spend debugging, the less time you spend producing. An interesting thought; one I may revisit in another post.
Robert mentions another interesting idea, almost a consequence of TDD, that I had not considered or come across before. Get your QA department (if you have one) involved early, get them writing automated tests based on the requirements and hand those to the development team. The developers’ job then becomes writing the code (and probably more detailed unit tests) required to make those tests pass. If they pass, the requirements have been met, and your software is in a shippable state. No more dumping on QA at the end of the process, probably late, and with no slippage allowed to the shipping date. It seems so obvious: Who better to write tests than testers? I wonder how many companies that have a QA department follow this, though.
A direct quote from the talk: “Agile is there to destroy hope.” At first this got a big laugh, because Robert was obviously being sarcastic… wasn’t he? He was being dead serious; he goes on to discuss how hope is what leads to unrealistic estimates, delayed decisions, people hope things go well, hope that things will work out. Agile is there so it is known as early as possible that things are going wrong, so that you can make changes, adjust expectations, whatever. These are the reasons you should have your Burn-down chart and Velocity chart prominently displayed for the world to see. It may not be pretty, or pleasant, but it improves the end results. In the long term things should improve as long as lessons are learned along the way.
On the topic of test coverage, 100% should always be the goal. It may never be attained, it may not be possible to get there for your code base, but it should always be the goal. This goal belongs to the software development team. If the goal belongs to management, then it becomes subject to all the pressures that go with everything else management touches, and every software developer will tell you that management goals are different, strange beasts. It will lead to cut corners, hacked tests to make them pass, and will become self-defeating. Keep the goal in the team, foster the attitude of professional pride, and the team will be constantly seeking to increase coverage. I like this idea of constantly striving to improve – it’s the kind of thing that would make me enjoy my work if a company encouraged it in the right way.
To go back to the unit testing idea, writing tests for long complicated methods will lead to long complicated tests and this is obviously not ideal, so, as you would expect if you’ve read Robert’s book ‘Clean Code’, he advocates small methods. How small? 3 to 5 lines, but with a long descriptive name. Eclipse’s “extract method” tool is immensely helpful in keeping your methods small, because it allows you to continue making them smaller and smaller until you can extract no more.
On a personal level I disagree with putting any number to the question of how long a method should be. My view is this: “It should be exactly as long as it needs to be, to do what it has to do – no more, no less”. At first glance that may seem to contradict Robert, but if you think about it alongside the DRY principle, you end up at the same place. I just feel that there will always be cases where your method has to be longer than 3 lines. I am in no way defending the 100 line long methods, I’m just saying that a number doesn’t help to convey the intended meaning behind the answer.
At the end of the talk Robert opened up to some questions, as most talks tend to do. I found these very interesting for different reasons. There was only time for two questions but here they are.
“How many arguments should a method have?” Within the answer Robert mentioned “never pass a boolean into a method”. At first I was slightly taken aback; in the seconds I had to take that in, I couldn’t see why. The answer was obvious, as soon as Robert stated it: A boolean means your method is doing more than one thing, a boolean declares that there is an if statement in there. You should have two functions – one for the true branch, one for the false. Now, I see some problems with this, as surely the further up the hierarchy of your code you go, you’re going to need to pass in multiple arguments, and even some booleans. I’m writing this post as I watch the video so I’ve not really had time to mull this over; hopefully I will before I actually post this to the site, but if I don’t, at least you know. If you have any thoughts on this feel free to leave a comment.
The second question was, “Is it possible to apply your ideas to already destroyed code?”, meaning legacy code. This resonated with me as the company I work for has a couple of legacy products that could really do with being revisited, as they are large and complicated and just keep getting more so. In short the answer is yes, as I expected, but it is hard, very hard. What I didn’t expect was this: “Never make a project to do this, never go to your manager and say, ‘We need 3 months to write tests for this,’ because you will fail!” What I take from that is that it has to be an ongoing commitment to refactor that legacy code. It will be hard, things will break along the way, and it will take as long as it takes. However, with every refactoring, with every test, that code base is improved. These improvements build up and up, until you have a big pile of improvements that all work together and you can prove it, with tests.
An interesting talk that I enjoyed, and it just moved Robert’s new book ‘The Clean Coder’ further up my reading list.