Ckwop's Journal http://www.ckwop.me.uk/ The life of Simon.. A journal on Life, Programing and Maths Copyright 2003-2009 Simon Johnson en-gb Hand Generated me@ckwop.me.uk (Simon Johnson) 60 Sun, 15 Feb 2009 12:00:00 GMT Meditation Driven Development <h2>Meditation Driven Development</h2> <div class="LargeBlogImage" style="padding-left: 2em;"> <img src="http://www.ckwop.me.uk/images/Meditation.jpg" alt="A silhouette of a person meditating." /> </div> <h3>In the beginning</h3> <p> Tim is a veteran programmer. He works at a world renowned software company. Despite this, in his long career he has seen many projects fail and only a few succeed. After 15 years developing software, he decides he wants to get out of the trenches and start managing projects. He's tired of seeing projects fail for entirely preventable reasons. He realises that the only way to fix these things is to be the guy who makes the decisions on these wayward projects. </p> <p> Tim, like most developers, is quite a eccentric man. He is an open source enthusiast and he has written a great variety of open-source software. Before writing any code on his projects, he usually spends an hour doing yoga followed by intense meditation. After doing his meditation he finds that he writes cleaner, better designed code. </p> <p> One day, he is meditating when it strikes him: "Maybe this is the solution to the <a href="http://en.wikipedia.org/wiki/Software_crisis">software crisis</a>, everyone needs to meditate before they write a line of code." Meditation Driven Development (MDD) was born. </p> <p> Tim goes to work and tells his team about his new methodology. Being good friends of Tim they decide to give it a try! Tim waits patiently for a project that he can try it out on. </p> <h3>The first project</h3> <p> It's day one of the implementation phase of the project. Tim rides his bicycle to work with extra-gumption. "Today will be the start of something great," he says to himself. </p> <p> It's 9 AM and it's time of the first team meeting. Tim asks everyone to sit around on the floor in a circle and reflect deeply on a particular passage from the Bible. At first, his team are uncomfortable. They're unsure of what to do, but under Tim's careful direction he manages to get a result. His team manages a 45 minute meditation and afterwards they're energized and ready to write great code. </p> <p> Tim mandates that all the team members must meditate twice a day, once when they come to work and once when they return from lunch. Each meditation session will be no shorter than 45 minutes long. This will be done without fail, every single day of the project. </p> <p> The project was scheduled to last three months but Tim's team was done two weeks early. Not only that, his team's software contained 20% fewer bugs than the company average. Tim concluded that MDD must have been responsible. "MDD WORKS," Tim exclaimed! </p> <h3>Spreading the gospel</h3> <p> Given his early successes, Tim decides to roll out MDD across all his projects. His early successes were repeated. His boss is impressed and asks why he thinks his projects are enjoying so much success. For Tim, the answer is obvious: "MDD. MDD allows us to produce higher quality software, to budget, on time." </p> <p> Tim convinces his boss that the whole company should use MDD. Tim sends out his disciples to other teams to convert them to MDD. Slowly but surely his company converts to MDD. </p> <p> Tim realises that other people could benefit from MDD, so he makes a deal with O'Reilly and writes his transformational book, "Meditation Driven Development - The way to cheaper, more reliable software." </p> <p> The initial reaction is positive. Before long, a line of people are queueing up at Tim's door to get in on on the new MDD craze sweeping the industry. </p> <h3>The MDD Manifesto</h3> <p> A year or two after Tim's book on MDD, it was clear that MDD was being misapplied in some companies. Some teams were having trouble making MDD work in their company. Some people were not following the strictures of the book correctly. </p> <p> They were having 20 minute meditations instead of the mandated minimum of 45 and they were only having one of these per day! Tim exclaimed, "How could they possibly expect the methodology to work when they're only doing one meditation per day!?" Something needed to be done. </p> <p> By this point MDD had fractured in to a series of closely related but slightly different methodologies. Some preferred to meditate to music, other liked to meditate on the words of famous poems. Others preferred four shorter sessions per day instead of the original two. The differences mattered less than the similarities. As long as there was an hour and a half of meditation per day, every day, it was MDD. </p> <p> Tim and his disciples sat down and bashed out a manifesto that bound these various strains of MDD under a common political philosophy. They vowed to take forth the central message of MDD and transform the industry. </p> <h3>MDD becomes mainstream</h3> <p> It's now nearly a decade after Tim wrote his transformational book. Once a year he keynotes at "MDD-con" in San Diego. He has released a series of books on the subject and makes a substantial amount of money in consulting on everything and anything related to MDD. </p> <p> MDD is now an established cottage-industry with a series of satellite conferences spanning the globe. It's now so popular that even the pointiest of pointy-haired bosses is starting to hear about it. </p> <p> Yet, all is not well in the MDD community. Ordinary companies are having real trouble getting the benefits of MDD. Projects are still late, expensive and buggy. Tim's career has become a continual fire-fight. His consultancy gigs are no longer about getting people to adopt MDD but are about fixing problems in projects that already use MDD! </p> <h3>MDD fifteen years on</h3> <p> It is now over fifteen years since Tim wrote his award winning book. MDD is now thoroughly mainstream and used by a huge variety of teams. Despite Tim's initial success, MDD projects on average tend to be late, over-budget and low quality. </p> <p> Tim still extols the merits of MDD but he finds dissatisfaction wherever he goes. A whole generation of programmers has now grown up with MDD and they're disillusioned by failed project after failed project. Tim can't understand why people were having such a bad time with MDD. He just <em>knows</em> that MDD works! He's seen it with his own eyes! In his own mind, he concludes that the problem must be that nobody is doing it right! </p> <p> One day, Tim comes across a team led by a bright-eyed manager called Cathy. Cathy's projects are on time, to budget and much less buggy than the company average. Cathy was a developer for fifteen years and has only recently become a manager. Tim is suitably impressed by her success, he asks her what her secret is: </p> <p> "It's our new methodology, QDD. QDD allows us to produce higher quality software, to budget, on time. It's going to <em>transform</em> our industry." </p> <h3>Afterword</h3> <p> Why did MDD work at first and then fail when it became mainstream? The reason that MDD worked initially had nothing to do with strictures of MDD. Tim was a talented developer working in a company filled with talented developers. Pretty much any methodology you care to think of was going to work with these people. </p> <p> Moreover, Tim's initial team were the earliest of early adopters hand-picked by Tim himself. They were the very people that would develop high quality software naturally anyway. The only role the MDD had was in helping the team to gel, and once they had they looked like an impossibly productive team. Tim misidentified the source of this productivity as being the result of his methodology, rather than his competence of himself and his team. </p> <p> As MDD became more widely used, the average quality of the developers using the methodology dropped and so did the success rate of using MDD. By the time it was used by the average team, MDD got average results. </p> <p> I'll close with a quote from one of the greats of our field, Robert Glass: </p> <blockquote class="quote"> <p>People matter in building software. That's the message of this particular fact. Tools matter. Techniques also matter. Process, yet again, matters. But head and shoulders above all those other things that matter are people.</p> <p>This message is as old as the software field itself. It has emerged from, and appears in, so many software research studies and position papers over the years that, by now, it should be one of the most important software "eternal truths." Yet we in the software field keep forgetting it. We advocate process as the be-all and end-all of software development. We promote tools as breakthroughs in our ability to create software. We aggregate miscellaneous collections of techniques, call that aggregate a methodology, and insist that thousands of programmers read about it, take classes in it, have their noses rubbed in it through drill and practice, and then employ it on high-profile projects. All in the name of tools/techniques/process over people.</p> </blockquote> <p> Don't fall in to Tim's trap. Great developers create great software not because they follow the strictures of some methodology but because they are truly great, gifted artisans. </p> http://www.ckwop.me.uk/Meditation-driven-development.html Sun, 15 Feb 2009 12:00:00 GMT http://www.ckwop.me.uk/Meditation-Driven-Development.html Do you proofread your code? `<h2>Do you proofread your code?</h2> <div class="LargeBlogImage" style="padding-left: 2em;"> <img src="http://www.ckwop.me.uk/images/ProofRead.jpg" alt="Cartoon making fun of people who don't proofread." /> <p><i>Image taken from www.yetiarts.com</i></p> </div> <p>When I write a blog post, such as this one, there are a few step I follow before committing any new entry to the world:</p> <ol> <li>I type a first draft out in Google Docs.</li> <li>When I'm reasonably happy with the post, I type-set the post in HTML.</li> <li>I then proofread the post and fix any mistakes.</li> <li>I put a copy of post up on the site but it is not linked from anywhere on the main site.</li> <li>I then proof read again and fix any mistakes. This is the last chance to get it right and I usually leave it a day or so before doing this final proofread.</li> <li>I make the blog post available to the world.</li> </ol> <p> The process is not perfect. I'm sure there are many errors that survive right in to the final blog post. The fact that these errors survive is sort of beside the point. The point is that this process dramatically improves the quality of this blog. </p> <p> I was told by my English teacher when I first started writing essays back in my high school days that I must proof read my work before I submit it. She said, "Proofreading your essay will save you time because you'll fix a lot of the mistakes before I find them. If you don't proofread your work then your essay will back to you covered in red ink and you will probably have forgotten what you'd written. As such, it'll take you much longer to fix the mistakes." </p> <p> Doesn't that sound like everything we know about software defects? </p> <p> And then it struck me. While I automatically proof anything I write on the web, how often do I proofread my code? In all honesty, I've never done it seriously. I've never taken a check-in I've made, printed it out, then sat down, worked out what each routine was meant to do, then come up with a <i>proof</i> as to why the code really does do its job properly. How often does anybody really proof read their code like that? In my entire (and fairly short) career, I've never seen anyone do it. </p> <p> Moreover, how many people give that print-out to a colleague to examine? I'd bet that very, very few organisations do that. How many people sit around a table and proofread their code together? I guess it'd be even fewer. </p> <p> With that in mind, is it any surprise that before we subject our code to testing there are typically eighty defects per thousand statements in our code? </p> <p> Could you imagine an author publishing a book without proofreading it at least once? Could you imagine an author publishing a book without giving the manuscript to someone else to look over? Why is it acceptable to publish software without doing even this basic level of quality assurance? </p> <p> Then I had another epiphany! This is why formal inspections remove up to 90% of the defects before the first test case is run. It's not that having inspections really finds the tough, race-condition style, kinds of bugs. Most of the time, they find trivial problems. </p> <p> Think of if it like you're using a word processor to write an essay: If compilation finds the "spelling" mistakes in code, formal inspections find the "grammatical" mistakes. You're not finding the deep errors in your program, you're just finding the next layer of superficial defects. Yet these sorts of defects make up almost all of your bugs. </p> <p> Proofreading in a small group is the closest thing we have to break-through technology in defect reduction. <a href="http://www.robertlglass.com/about">Robert Glass</a> had this to say about formal inspections: </p> <div class="Quotebox"> <p> Rigorous inspections - the technique of pouring over a piece of software to identify any errors it contains - constitute a near-breakthrough. Research study after research study has shown that inspections can detect up to 90 percent of the errors in a software product before any test cases have been run. And that signifies an extremely effective process. </p> <p> Furthermore, the same studies show the cost of inspections is less than the cost of testing that would be necessary to find the same errors. What we have here is an effective process that is also cost-effective. </p> </div> <p> According to the research, the key to successfully finding errors is to be as rigorous as possible in your proofreading. Do not mistake rigour for formality. It is entirely possible to do a formal inspection but be intellectually lazy about it. Any such approach is doomed to fail. Rigour means that you need to sit down and really concentrate hard on the code in question and not just go through the motions of a formal process. </p> <p> If this sounds like hard work, it is. According to Glass it not uncommon to only be able to inspect a hundred lines of codes per hour. Worse, the process of going through the code so rigorously is mentally exhausting. An hour is the maximum that most people can do at a time. </p> <p> But it's worth doing. The research does show that those that dare win. If you're willing to do that punishing work, you'll be able to develop quality software much <a href="http://www.ckwop.me.uk/The-inverted-lemon.html">cheaper than your competitors</a>. </p> <p> Without a proofreading programme, when a bug is fixed by a tester the bug is usually fixed leaving the design of the program entirely unchanged. By having a solid culture of peer review, it's much more likely you'll fix bad design decisions as well as the bugs. This means that your code base will probably be smaller, more efficient as well as being much less bug ridden. </p> <p> If you're still not convinced, take this passage from <a href="http://www.stevemcconnell.com/aboutme.htm">Steve McConnell</a>'s Code Complete: </p> <div class="Quotebox"> <p> The combination of design and code inspections catch about 60 percent of defects, which is higher than other techniques except prototyping and high-volume beta testing. The results have been confirmed numerous times at various organisations, including Harris BCSD, National Software Quality Experiment, Software Engineering Institute, Hewlett Packard and so on. </p> <p> The combination of design and code inspections usually removes 70-85 percent or more of the defects in a product. Inspections identify error-prone classes early, and Caper Jones reports that they result in 20-30 percent fewer defects per 1000 lines of code than less formal review practices. </p> <p> Designers and coders learn to improve their work through participating in inspections, and inspections increase productivity by about 20 percent. On a project that uses inspections for design and code, the inspections will take up about 10-15 percent of project budget and will typically reduce overall project cost. </p> </div> <p> Just like an author subjecting their manuscript to review makes their book better and improves their ability to write, having others review your code makes your code better and it helps makes you a better programmer. Not only that, it makes you 20% more productive! </p> <p> So perhaps a good New Year's resolution for any developer would be to set-up a proofreading programme at their company! </p> http://www.ckwop.me.uk/Do-you-proofread-your-code.html Sun, 11 Jan 2009 16:23:26 GMT http://www.ckwop.me.uk/Do-you-proofread-your-code.html The Inverted Lemon <p> The <a href="http://en.wikipedia.org/wiki/The_Market_for_Lemons">lemon market</a> was first described by economist George Akerlof in his seminal <a href="http://links.jstor.org/sici?sici=0033-5533%28197008%2984%3A3%3C488%3ATMF%22QU%3E2.0.CO%3B2-6">paper</a>: "The Market for 'Lemons'." That paper won him the Nobel Prize in economics. </p> <p> It has often been argued that software is a lemon market. In particular, Schneier made this point about security software in this <a href="http://www.schneier.com/blog/archives/2007/04/a_security_mark.html">article</a>. The same argument has been applied not only to software security but to certain facets of software quality; such as, maintainability and testability. In this essay, when I'm talking about quality I'm really talking about these two facets of software quality. </p> <p> The argument goes that Software is a lemon market because the people buying software do not have the skill nor the information to judge whether a given piece of software is high quality or not. As such, quality does not really impact their decision to buy the software at all. </p> <p> However, the interaction between quality and price is much more complicated than it looks. I am going to argue that software <i>is</i> a lemon market but not in the traditional way. The suckers are not the customers, it's the companies that make low quality products. </p> <h3>What is software quality anyway?</h3> <p>I think of software quality as a list of "ilities" and while the list of which ones are priorities changes from application to application:</p> <ul> <li>Security</li> <li>Maintainablity</li> <li>Testability</li> <li>Performance</li> <li>Portability</li> <li>Usability</li> </ul> <p> I don't want you to get too hung up on the order of this list. Different projects will weight these attributes according to their requirements. However, what is interesting is that the end user is only interested in a few of these attributes. </p> <ul> <li>Usability</li> <li>Performance</li> <li>Security</li> <li>Portability</li> </ul> <p> Testability and maintability are gone. They don't even exist for a user of the software. Your code could be world-beatingly beautiful or it could be a giant ball of suck, they don't care. Worse still, on first examination the customer won't pay you a dime more either way. </p> <p>As long as you put a shiny, sensible interface over that ball of mud, it's all good.</p> <h3>Why software is not like a car</h3> <p> The main theme behind the idea of the lemon market is that the asymmetry between buyer and seller in information about the cars leads to a situation where the buyer has no way to accurately gauge the quality of what they're buying. </p> <p> The example that most people can relate to is the buying of a used car. The idea being that vendor usually has much better information than the buyer. This results in people getting ripped off, which if left unchecked, could result in a total break down of that market. </p> <p> However, it is misleading to try and apply this definition directly to software. The problem with the car analogy is that physical items under go wear and tear. A piece of software will be the same quality on the day it was published to the day it finally falls out of use, provided no updates are made to it. In short, code doesn't rust. </p> <p> If a user buys a low quality program, it is not a lemon in the same way that a car that barely works is. A poor quality car will randomly and expensively fail in various areas after purchase. A poor quality program may fail expensively but it will fail in precisely the same way every time. </p> <p> The none-rusting property of code changes the quality calculation considerably. If software doesn't rust then the quality just has to be good enough. Good enough is simply a case of ensuring there are no show-stopper bugs; good enough is a synonym for "<i>barely works</i>." </p> <p> This idea of "<i>barely works</i>" is an anthama to most software developers. Good developers are unhappy writing anything but the cleanest code they can possibly write. If <i>Barely Works</i> were a developer we'd stick it the stocks and throw rotten fruit at it. </p> <p> But developers have a distorted view of the software. It's completely different to the view of a paying customer. Developers see all the bugs in the bug tracking database. Developers see all the suck in the code. Developers see all the poor architectural decisions and secretly think of ways to fix them. </p> <p>The users see a reasonably good interface and only the bugs that stop them working.</p> <p> Therefore, by simply fixing the bugs the users see, you can improve the impression of quality without doing a lot of work. As such, "barely works" makes a great deal of business sense. </p> <p> In some cases, like the recent MySQL release, even shower-stopper bugs do not hold back a release. </p> <h3>Hold on a second, I thought that it is cheaper to write quality software?</h3> <p> <a href="http://blogs.construx.com/blogs/stevemcc/archive/2007/11/01/technical-debt-2.aspx">Technical debt</a> is a wonderful expression because it is succinctly explains to a laymen the insidious invisible cost of bad design. Unfortunately, the concept of technical debt also explains why convincing people to pay off that debt is a tough sell. </p> <p> The problem is that the interest rate on technical debt is very small. The interest rate can't be any greater than five percent. In fact, it's probably a tenth of that value. As such, you can build up truly gargantuan amounts of technical debt and the cost of servicing that debt is tiny in comparison to the size of the principal. So why not just have an interest only mortgage and never pay back the principle? </p> <p> It does seem futile, doesn't it? Say you kick off your project to pay back that giant debt, for the first few months you're going to be paying off nothing but interest and you won't make any appreciable dent on the principal. You're basically going to be thrashing around doing a lot of work and not achieving a great deal. </p> <p> With most business applications, making the code base testable at all is a major multi-month project. It's a risky project too; you risk breaking a lot of working code without adding anything the business can see as an improvement. </p> <p> If you eventually manage to pay off your technical debt and you keep it paid off then, yes, it will be cheaper overall to write quality software. The problem though is that getting there in the first place. </p> <p> If getting to the promised land requires scaling Mount Everest without bottled oxygen, don't be surprised if you don't have many takers. </p> <h3>Inverting the Lemon</h3> <p> So far I've made the argument that quality, in the sense of maintainability and testability, doesn't matter. This is because the average user has no way to choose between a program consisting of a single gigantic main method and a program that is designed sensibly. </p> <p> However, that is not the whole story. There are places in the industry where quality matters. Barely Works is not going to be acceptable in pace-maker software or missile control systems. </p> <p> Even in general business software, there are some companies that have made quality their power-animal. The reason why quality works as a business strategy for them is because their audience understands that they're paying for quality. That's the point of their brand. </p> <p> Take bugger trackers for example. Fogbugz is arguably the best bug tracker in the world. Everyone who buys Fogbugz knows they could just install Bugzilla but they don't. The reason they don't is that Fogbugz sucks less in pretty much every dimension. </p> <p> If software really were a lemon market, Fogcreek would have gone bust years ago. In fact, if you look at <i>every single one</i> of Fogcreek's products, there is a mature open source competitor that they totally spank. </p> <p> You see, the people who want quality will pay for it. Moreover, the people who demand quality know what they're looking for - they're informed buyers. </p> <p> So few people develop quality software that the people who do can charge above the market rate for their product. Therefore, while it may be cheaper to develop high quality software it ends up being more expensive to buy. This makes it <i>far</i> more profitable to develop quality software! </p> <p> Most software companies have got such a huge principal on their technical debt that trying to convert their business to a higher quality and thus more profitable outfit would put them out of business. This is the economic barrier that keeps quality software a niche. </p> <p> And that, my friends, is the inverted lemon. The joke is not on the end user, they got exactly what they paid for, the joke is on the business who pays through the nose to maintain a crappy product - and they make less money selling that product while they're at it. </p> http://www.ckwop.me.uk/The-inverted-lemon.html Sat, 20 Dec 2008 21:44:30 GMT http://www.ckwop.me.uk/The-inverted-lemon.html The death of the essay <p> Before the invention of the Internet, people used to write letters to one another. A century ago, people in the United States used to pay $0.05 to send a letter which, with inflation factored in, would cost $1.14 today. </p> <p> The fact that letters took days to travel to their destination and sending one cost comparatively more than than it does today meant that when people did write, they wrote at least a few hundred words. </p> <p> Today, we're living in a time where you can communicate instantly right across the world to thousands of people simultaneously for virtually no cost. In this climate, the impetus shifts from writing long, carefully written and carefully considered pieces to a focus on immediacy and the "now." </p> <p> This change has been crystallising in front our eyes for the last decade. </p> <p> I first experienced the wonders of electronic communication as a youngster when I signed up for my first e- mail account. All the cool kids were signing up to Hotmail when I was fifteen years old, so I got in on the deal. To cut a long and relatively boring story short, it quickly occurred to me that you could use this tool as a primitive instant messenger - provided the person you wanted to talk to was on-line at the same time. This was perhaps my first experience of the world of micro-messaging. </p> <p> At the turn of the century, our household finally connected to the Internet. One of the first applications I fired up was mIRC and this was my first experience with the world of instant messaging. To me, this was a much more important experience than the first time I browsed the web. Here was a tool I could use to communicate to my friends instantly for virtually no cost. It was amazing being able to communicate in real time by typing messages out to each other. Here was a place where everyone could speak at once and yet, because the communication was written, everyone could be heard. It was one of the few times where I was genuinely amazed by computing. </p> <p> Later, I got my first mobile phone and with that came the glorious innovation of SMS. This was another crucial step on the way towards micro-messaging. At first, SMS messages were limited to just 160 characters and it cost twelve pence to send a message<sup>1</sup>. Therefore, your messages had to be short and each message had to be positively useful for it to be worth the cost of sending one. Of course, different people have different ideas of what useful meant; but I digress. Due to the lack of spam on mobile phones and the fact I always have my mobile to hand, this remains my primary form of communication, even today. </p> <p> We fast forward to today and we see the likes of Twitter, or the all important news feed on Facebook and we've now got to the point where every tiny, inane detail, of one's life is logged for the world to see; and most people share these details to all and sundry without any consideration of the implications of what they're doing. </p> <p> And I wonder if we've lost something. Have we dumbed down to the point where any thought that can't fit in to the Facebook news feed is automatically worthless? Has the world's attention span decreased by so much that nobody has the attention span to even read a letter any more, let alone write one? </p> <p> I don't want to lay on the hyperbole too thick since I'm starting to border on the absurd but there is some sort of point there. I just wonder, if we don't have to invest any effort in talking to each other, if we encourage short brutish talk, then we don't really have any reason to value what we say. If we don't value what we have to say then what is the point of saying it? </p> <p> So I ask, is Twitter the ultimate in onomatopoeia; the service that sounds like it is? The annoying drone of a thousand thoughtless monkeys battering away on keyboards producing nothing of value. I guess what I'm really trying to say is what is the point of Twitter? What is the point of micro-blogging to the world? </p> <hr> <p> <sup>1</sup> Technically, they still are limited to 160 characters but from the user's perspective, you can seemlessly chain many messages together to make one much larger message. </p> <p> <sup>2</sup> Atwood is major proponent of Twitter, which is why I've used his Twitter feed as an example. However, he is an unusual user of Twitter in the sense that he <i>can</i> actually write. His blog, Coding Horror, contains a number of interesting and well written articles. Yet, even for a talented writer like Atwood, it is impossible for him to use Twitter in a way that doesn't make him look like a moron. If he can't make it work, can anybody else? </p> http://www.ckwop.me.uk/The-death-of-the-essay.html Mon, 17 Nov 2008 20:25:29 GMT http://www.ckwop.me.uk/The-death-of-the-essay.html Interviews considered harmful <h2>Interviews considered harmful?</h2> <h3>Introduction</h3> <p> I've been developing software professionally for six years now, so I think I have just about enough experience to talk about the interview. In that time, I've been the interviewer many more times than I've been the interviewee and I've come to the conclusion that interviews suck. </p> <p> The idea of an interview is to try and work out whether a candidate is a good fit for your team. There are usually three things that you look for when interviewing: </p> <ol> <li>The person in front of you is smart.</li> <li>The person in front of you can actually write a program.</li> <li>The person in front of you will compliment your pre-existing team.</li> </ol> <p> The problem is that an interview is very good at weeding out a lot of the obviously bad people but is really poor at sorting the average candidate from an extraordinary candidate. </p> <p> And it is common knowledge that extraordinary programmers are much better value for money than their much maligned mediocre counter-parts. </p> <p>So the question is, how do you find the extraordinary programmers?</p> <h3>Finding someone smart</h3> <p> When looking for a potential programmer, you should try to find someone smart. Someone who is not just smart but <i>smarter</i> than yourself. </p> <p> The problem is, this is a really difficult thing to asses in an interview. The problem is that knowledge and smart are not equivalent. </p> <p> Then someone had the idea of setting little problem questions that the candidate would have to solve right there and then in the interview. The thinking goes, if they could solve these bizarre little puzzle, then clearly they must be smart and thus a good programmer. </p> <p> Completely wrong. </p> <p> The problem is that the answer to the puzzle is not the answer you'd want to hear from a real developer. For example, the title of a book about the puzzle question culture at Microsoft has the title: How would you move mount Fuji? </p> <p> How would I move mount Fuji? </p> <p> I wouldn't try and move it at all. Moving a mountain has never been attempted by anyone, ever. Any attempt to move a mountain would likely run vastly over budget. It's likely the technology doesn't even exist to do this in an environmentally friendly way; although the Russians did happen to experiment with nuclear weapons in civil engineering. Why do you want to move the mountain anyway? There's probably an easier way to do whatever it is you want to achieve and it will almost certainly cost a lot less money. </p> <p> That is the answer I'd expect from such a question but no candidate will ever give you that answer. They'll try and solve the little brain-teaser you've set them because they believe that's what they're meant to do. </p> <p> Then you get the questions that are nothing short of comical: "Why are man-holes covers round?" Well, if you don't live in the United States, there's a good chance they're not. There's literally thousands of square man-hole covers in my town alone. The cretin that came up with this question didn't realise that you can prevent the cover falling down the manhole by simply making the cover slightly larger than the hole it covers. </p> <p> The people you are hiring are not logicians, they're engineers. You want them to think like an engineer. Being able to solve what is, in essence, nothing more than an elaborate Sudoku does not make you a great programmer. You might as well hire crossword competition winners! </p> <h3>Finding someone who can program</h3> <p> Most programming applicants can barely code. It's common knowledge that setting even simple problems, like <a href="http://imranontech.com/2007/01/24/using-fizzbuzz-to-find-developers-who-grok-coding/">FizzBuzz</a>, will filter out 75% of applicants. FizzBuzz is great for filtering out the crappy candidates but we want to find great candidates. Assuming your candidate passes the FizzBuzz test, what do you give them next? </p> <p> There is a tedency to lurch to "Implement Quicksort on the white-board" type of problems. </p> <p> Why would you get them to write code on a white-board? That isn't how a programmer normally writes code! You can't execute scrawl written on a white-board. Code written on a white-board is likely to be chock full of errors that <i>nobody</i> in that room spots. </p> <p> Even if you got them to implement at their computer, I find asking these sorts of problems as odd as asking a research chemist to recite the periodic table. It may show that you've got an interest in chemistry but that doesn't in any way tell you if they're up to the job at hand. </p> <p> Presuambly the reason why you'd want them to implement Quicksort is that you want the candidate to be aware of the difference in run-time complexity between Quicksort and other slower sorts. Why not just <i>ask</i> them which sort they would use? </p> <p> Ultimately, we want an engineer not a logician. If I had to choose between a person who knew nothing about run-time complexity but routinely profiled his code and a person who knew how to prove Euclid's GCD algorithm has a worst case running time of n<sup>2</sup> but never used a profiler - I'd take the guy who uses the profiler. </p> <p> I'm not beating up on just Quicksort here, I'm taking about the whole shooting match; tree traversal algorithms, red-black trees, data structures etc. This stuff is certainly interesting but it's not at all useful in most programming jobs. </p> <p> I've never implemented any of these things in my career and I suspect this is true for most of the development community. If I was asked to implement it, I'd just look it up just like I'd look up any other algorithm. </p> <p> So what should you give them if you want to know if they're up to the job? </p> <p> Where I work, we get them to use one of our products. We give them a couple of hours and get them to integrate with our web-services platform. They're producing the very code our customers would be producing; they're solving a real business problem that our customers have. This is infinitely more useful then getting them to implement something like Quicksort. </p> <h3>Development is 20% code, 80% personality</h3> <p> The most important attribute of a developer is their personality. </p> <p> A person whose smarts are matched only by their laziness is completely useless to you. A person who lacks attention to detail is completely useless to you. A person who has no capacity to learn by their self is completely useless to you. A person who is an arsehole is.. well, I think you get the point. Even if they are none of these things, they could just be a poor fit for some other reason entirely unrelated to their aptitude. </p> <p> This much is obvious. These are things you can't really judge until you actually work with them. Yet this stuff is what distinguishes a great hire from a poor one - yet the interview gives you no way to assess any of these important traits. </p> <h3>Are Interviews considered harmful then?</h3> <p> Just like the GOTO statement, interviews are not inherently bad. Properly deployed, they are useful. The best way to use an interview is to do a final sanity check on the candidate before offering them the job on a trial period. You then use the trial period to assess the candidate's fit with the team. </p> <p> The trial period <i>must</i> be a trial period though. Too often, inertia sets in and there is a strong temptation to throw good money after bad. If the person stinks, it makes sense to get rid of them as fast as possible. You must have no qualms about firing someone who is sub-standard. </p> <p> The interview must contain a programming test of some kind. This programming test must be relevant to what you actually develop. </p> <p> A team is built around a shared sense of purpose and a shared sense of pride in what they do. Therefore, it must ultimately be the team the candidate works with who decides whether they stay or go. If anyone black- balls the individual then the candidate will have to go. </p> <p> If this sounds expensive, well I guess it is. However, compared to the cost of getting hiring wrong it's a bargain. </p> http://www.ckwop.me.uk/Is-Object-Orientation-Working.html Mon, 13 Oct 2008 18:58:29 GMT http://www.ckwop.me.uk/Interviews-considered-harmful.html Don't test to remove bugs <h2>Don't test to remove bugs!</h2> <p> Testing is to defect location as trial division is to finding primes. Just as it's very slow to show a number is prime by doing trial division it is very expensive to expose bugs in your program simply through blind testing. </p> <p> Yet I've found that a lot of people do think that this sort of blind testing is the best way to find and remove bugs from their program. </p> <p> Just like there are mathematical short-cuts that allow you to find primes quickly, defects have properties you can exploit that help you find them faster. </p> <p> There are a number of useful facts about software defects: </p> <ul> <li>80% of the defects come from 20% of the code.</li> <li>High cyclometric complexity is a good predictor of defects.</li> <li>Even if your test coverage was 100%, roughly 35% of defects emerge from missing logic paths.</li> <li>Another 40% of defects come from the execution of a unique combination of logic paths.</li> <li>There are errors that most programmers tend to make.</li> <li>The longer you leave a bug, the more expensive it is to fix it.</li> </ul> <p> These facts paint a pretty important picture; there is a much more cost effective way to a lower defect rate. </p> <p> I've come to the opinion that the biggest generator of defects in a piece of software is the design of the program. The fact that 80% of the bugs live in 20% of the code suggests that this must be true. What's special about that 20%? Why is it so buggy? </p> <p> It's because this code contains bad abstractions, low cohesion, high cyclometric complexity and tight coupling. It's badly designed! </p> <p> Fortunately, these facts give us a clear strategy for reducing defects. All we have to do is improve the design of the program. The better your design, the simpler your code will be. The simpler your code will be, the less bugs it will contain. </p> <p> The simplification of one abstraction may result in the simplification of other dependent abstractions. Success often breed success and you can quickly find you have a radically simpler program and consequentially far fewer defects. </p> <p> It is clear that there are common defects that all developers make. They tend to be simple things, such as not checking a pointer for null before dereferencing it, or using an out of range index on an array. This implies that defect check-lists are a good way to keeping common defects out. It also implies that there may be ways to automate detection of these defects at check-in. </p> <p> If high cyclometric complexity indicates the presence of bugs, perhaps you should ban checkins of routines that score highly. </p> <p> So if the purpose of testing is not to find defects then what is it for? It's for confirming that the specification has been implemented correctly. </p> <p> Test-Driven-Development (TTD) doesn't produce high-quality code because it finds bugs; although that is a nice side effect. It increases the quality of the code because in order to unit-test code you have to make sure your code has low coupling, high cohesion and low cyclometric complexity. You have to have a reasonably good design. </p> <p> When you're doing TTD what you're actually doing is writing an executable version of the requirements document. You're specifying what the behaviour of the program is intended to be before you actually write the program. </p> <p> This is the purpose of testing; to ensure the requirements have been fully implemented. </p> http://www.ckwop.me.uk/Is-Object-Orientation-Working.html Thu, 21 Aug 2008 20:33:29 GMT http://www.ckwop.me.uk/Dont-Test-To-Remove-Bugs.html Is Object Orientation Working? <h1>Does object orientation really work?</h1> <p> The vast majority of software that people write inside a business talks to a database. Yet object orientated programming does not gel well with databases. The code that looks clean and simple in a modern object orientated program looks positively terrible when you look at the traffic that code causes at the database. </p> <p> It's called the <a href="http://en.wikipedia.org/wiki/Object-Relational_impedance_mismatch">object-relational impedence mismatch</a>. The often aired solution is to use some sort of persistence framework to map your classes to a collection of database tables. There are a variety of packages that do this: NHibenate, Gentle.Net, JPersist etc. </p> <p> The problem is that none of them work too well. The writers of these packages are much like the inventor of this machine: </p> <div style="text-align: center"> <img src="http://www.ckwop.me.uk/images/perpetual.jpg" alt="Perpetual Motion Machine" /> </div> <p> Solving the impedance mismatch problem is the computer science equivalent of the perpetual motion machine. You can't get it to work because it's impossible; they are simply incompatible ways of working. </p> <p> A database is essentially a truth reasoning engine. You take a collection of facts, a series of inference rules and you use these to ask it questions. A object orientated language is essentially about setting up classes of object; templates, if you like, from which instances are created. These instances may be related to each other in a UML diagram but this is not enforced strictly in the code. You certainly can't do reasoning on them in the same way that you might a collection of tables. Moreover, what does inheritance really mean to a database? </p> <p> When you try and make the square peg match the round hole, what you end up getting is a really leaky abstraction. The persistence framework writers would love you to believe that you can "forget" about the database and just write lovely object orientated code free of any worry about the vagaries of how a database works. For a while, they might be right but you can bet your bottom dollar that one day that database is going to bitch slap you in some way. Whether it's a particular query running very slow, a bone-headed auto-generated schema or trying to understand why databases don't understand inheritance - it's going to bitch slap you and when it does it'll ask you for interest you owe it for not treating it with the proper respect. </p> <p> There are people who acknowledge this problem and propose that the solution is an object database. The problem with this solution is that while object databases are fast for only a very narrow selection of queries. This is because the way they work is via pointers from one object to another. Traversing these pointers can become a bottleneck under more general use-cases. </p> <p> My solution is a bit more radical. My view is that the database, not the programming language, is the primary tool in solving business problems. The way to solve the impedance mismatch is to ditch object orientation and follow the conventions of the database. </p> <p> A case in point, no impedance mismatch exists in C because it is not object orientated. We programmed with procedural languages for decades before object orientation turned up - it's not like programming is suddenly vastly harder when we remove object-orientation. </p> <p> Actually, I'd go further. My admittedly heretical view is that object orientated design is a profound waste of time. I don't believe that object databases are the right answer because I don't think object orientation is the right way to design a program that talks to a database. It takes a colossal amount of object orientated code to achieve anything useful and when it does so, it usually punishes the very thing that's the hardest, most expensive, to scale: the database. </p> <p> Think about this for a second, you have to work out how you're going to decompose your program in to classes then you're going to have to type out those classes (or if you're bit smarter you have a code generation tool to do this). Then you need to write tests the exercise that object model; large parts of which you probably won't really re-use in other scenarios. </p> <p> Honestly, what's so wrong with just manipulating the data directly? What's wrong with taking the data from a form and doing a straight insert? </p> <p> I think it comes from the fact that people think the object model is more maintainable and more reusable. </p> <p> Is it really more maintainable? If you change the database you're going to have to update your object model in all but the most trivial of changes. Ahh, you say but a change is business logic is easier in the object model! Is that really true? A change in business logic implies a change in a database transition. It has to in order for that change to be recorded anywhere. Who's to say that updating a direct access call is going to be any more difficult than updating the object model? </p> <p> Secondly, you should only make reusable components you actually <i>do</i> reuse. An object model may be flexible but does every problem need that flexibility? Is it worth spending all that time to create that flexibility where no flexibility is required? </p> <p> This has a real cost too, in Robert Glass' "Facts and Fallacies of Software Engineering", Fact 18 says this: </p> <div class="Quotebox"> There are two "rules of three" in reuse: (a) It is three times more difficult to build a reusable component as a single use component. and (b) a reusable component should be tried out in three different applications before it will be sufficiently generate to accept into a reuse library. </div> <p> Building a flexible object model will probably cost you more money per unit of functionality. Think about that! </p> <p> That aside, there's a deeper point here. For a computation to have any impact on the world, it must mutate the state of the machine it's running on. The goal of computation, therefore, is to mutate the state of the machine in just the right way under just the right conditions to record useful information. In real world business programming the goal of a program is ultimately to mutate the <i>database</i> in just the right way under just the right conditions. The program does not exist to be a self-serving statue to object orientated perfection - it exists to manage state transitions in the database. </p> <p> So why not use the tools the database gives us natively to do this job? Not only does it provide answers to really complicated queries quickly but it provide transaction support, views of the data, the ability to set complex rules to enforce constraints on entries. Taken together, these are features you'd be simply crazy to ignore. They're there to help us write solid applications. They're there to make our work easier! </p> <p> And yet people do ignore it! I honestly think it's because most developers hate SQL. They've got this pathological desire to expunge every last SQL statement from their program. To me, it's absolutely necessary to understand this language. Just like you need to understand C to understand how high level languages talk to the low level hardware, you need a deep understanding of SQL to understand how databases represent information. You just do, it's not negotiable. </p> <p> It's a problem domain specific language like XPath or Regular Expressions. No-one would dream of writing their own XML navigation language or their own pattern matching language. We already have well developed, ubiquitous mini-languages that solve these problems extremely well. If you try and solve this problem independently, it is guaranteed to be less flexible and less useful. Yet when it comes to the problem of how to get data in to and out of your application, we invest a huge amount of time in solving problems already solved completely by using the database in the way it's intended to be used. </p> <p> If object orientation is the casualty of giving proper respect to the database, then so be it. </p> http://www.ckwop.me.uk/Is-Object-Orientation-Working.html Sat, 12 Jul 2008 15:47:29 GMT http://www.ckwop.me.uk/Is-Object-Orientation-Working.html Why Exceptions Suck <h1>Why Exceptions Suck</h1> <h2>Introduction</h2> <p> In previous posts I've focused on the importance of removing cyclometric complexity from your software and how that can dramatically reduce the defect rate. </p> <p> This post is related to this theme, but rather than talking solely about the cyclometric complexity I want to tackle a particularly egregious type of complexity that exists in most modern programming languages: structured exception handling. </p> <h2>What is structured exception handling?</h2> <p>Python, C# and Java all have structured exception handling. In C# and Java you find code that looks like this:</p> <pre class="code csharp"> <span class="keyword">try</span> { <span class="comment">// Some IO operation.</span> } <span class="keyword">catch</span>(IOException e) { <span class="comment">// Do something</span> } </pre> <p> The idea is that if something exceptional occurs within the body of the try block, we can catch one or more exceptions and handle them. If there is no try/catch block in the routine you're currently in, the exception will "bubble" up the call stack, with the hope that it will be handled by some catch block. If it isn't, the program crashes. </p> <p> The idea behind this is that we can clearly delineate error handling code from normal unexceptional code. </p> <h2>Why do they suck? - The Theory</h2> <h3>Exceptions considered harmful</h3> <p> In 1968 Edagar W. Dijkstra had a letter published called "Go-to statement considered harmful." In this letter he gave a detailed account of why he thought that the GOTO statement in high-level languages should be abolished. </p> <p> The central premise of his letter was that when designing a program, it should be possible to uniquely define a "meaningful" position in a program by looking at a few basic co-ordinates. Such as the current line number, the current call stack, the value of any loop counters. </p> <p> The GOTO statement allows code that completely destroys any meaningful co-ordinate system. For example, it is legal to jump to code within a loop construct. In this case, how do you know whether the entry point was the natural start of the loop or whether you jumped in to it? </p> <p> You could add another co-ordinate for each GOTO statement in your program, but then your program's control flow becomes dependent on a vast array of GOTO branch conditions. </p> <p> Exceptions are a super GOTO. Rather than allowing you to jump anywhere in the position of the procedure, they allow you to teleport up the call stack to any number of handlers. </p> <p> At first, it seems like we have adhered to the advice of Dijkstra because the exception code will only be executed when an exception has been thrown. There is no other way to have that code be executed. We could add the "CurrentException" item to the laundry list of co-ordinates and be on our way. </p> <p> I don't think this is a valid defence of structured exception handling. While we have probably adhered to the recommendation of Dijkstra technically, we have certainly violated the spirit of it. The whole reason he wanted a meaningful co-ordinate system for tracing program execution was so that we can reason about the code. I would say that exceptions are much more difficult to reason about than return codes. </p> <h3>Exceptions make reasoning about a program hard</h3> <p> Let's say I throw an exception. How do I know as a programmer where that error is going to get handled? In most languages, the answer is "you don't know." The exception might not be handled at all, which will result in a program crash. If this is not the case, the exception might be handled in any of the routines up the call stack. </p> <p> This is where the real pain begins, since the exception may not be handled in the routines that directly call your routine. They may be handled much higher up in routines that are functionally unrelated to the purpose of your code. So it is not enough to search all the code for uses of your routine, you have to search for every routine that might, on one code path, result in the execution of your routine! How on earth do you reason about such a construct? It's also worth bearing in mind that different code paths may have vastly different error handling logic, so you'd have to develop correctness proofs for each handler. </p> <h3> Checked exceptions the answer? </h3> <p> It's worth pointing out that the writers of Java knew about this and developed something called checked exceptions. Checked exceptions are exceptions that you are forced to provide a handler for. This allows you to trivially show that some types of exception are always handled, however, this does not tell you where they will be handled and whether the handling procedure is correct for that type of problem. Checked exceptions are certainly better than unchecked exceptions, since you know they must be handled but even so they're just as hard to reason about as their unchecked counter-parts. </p> <h3>But even checked exceptions are evil..</h3> <p> The problem with checked exceptions is not such much the theory but the practice of how they get used. </p> <p> When you force a lazy developer to do something, what happens is they reach for the quickest way to make the compiler happy. In this case, that means indiscriminately catching all exceptions! </p> <p> Now you have code that'll never fail but then it'll never work properly either. </p> <h3>Exception throwing code is invisible</h3> <p> How do I know whether a routine is going to throw an exception? Resolving this question requires inspecting my routine for any thrown exceptions, then inspecting the routines my routine calls for any exception and so on recursively until we have a definitive list. This is true even for Java since handlers are not forced for unchecked exceptions. </p> <p> This is a huge amount of work to perform when writing a routine because even if the library is well documented, you usually don't have complete access to the source code. This means that you have no idea what pre-conditions you need to fulfil to avoid the exception. How on earth can you reason about your code when you don't have access to that information? </p> <h3>Throwing exceptions breaks encapsulation</h3> <p> To some degree error reporting always break encapsulation. It's important that a routine is able to signal that it has failed and doing so will obviously communicate something about how the routines work to the outside world. The problem is that exceptions are promiscuous in who they will communicate this information to. They will communicate it anybody on the call stack and they will communicate it to modules totally unrelated to the routine that threw the exception in the first place. </p> <p> Consider an example where you've decided to use flat files as a store for database tables. For some reason, one of the table files is missing so a SQL query throws a "FileNotFoundException", this exception communicates the fact that files are used as the underlying data store to parts of the system that have no business knowing how the database works. </p> <p> Most people designing a library would say that throwing a FileNotFoundException is not what you want to do. Instead, you want to throw a TableNotFoundException, with FileNotFoundException as the inner exception. Okay, fair enough. But what if some tables are accessed over a network connection and others are stored locally and I want to be able to distinguish between these two types of failure? </p> <p> There is no way to distinguish between these errors without leaking information about the implementation. </p> <p> Being able to distinguish between them is important. If the table doesn't exist on disk, then it probably never will, so the correct action is to gracefully exit and report an error. However, you might decide that if the network is unavailable then it is may be a temporary connection issue so it is worth retrying whatever we were doing. These are two different failure modes. </p> <p> This might seem a bit of an contrived example but I see this pattern fairly regularly myself, particularly in code that manages a long running transaction. </p> <p> It's true that if I was using return codes, I'd have to break encapsulation as well however only callers to that routine would be able to notice the broken encapsulation. With structured exception handling, all the routines on the call stack can potentially see that broken encapsulation. With structured exception handling, the break leaks much further. </p> <h2>Why do they suck? - In Practice</h2> <p> The theory of why exceptions suck is just the start of the problems with exceptions. What happens in real world programs is significantly more nasty. The problem with exceptions is they encourage developers to do some really bad things. In this section I'm going to look at some of the patterns I've seen. </p> <h3>Paranoid coding</h3> <p> Most developers are under serious time pressure to deliver a working product. Given the difficultly of establishing which routines will throw what exceptions, they often don't bother finding out at all. </p> <p> This leads to bizarre "just in case" code and this leads to programs that are difficult to debug. </p> <p> For example: </p> <pre class="code csharp"> <span class="keyword">public static decimal</span> ComputeSmokerPercentage(PersonCollection personCollection) { <span class="keyword">try</span> { <span class="keyword">int</span> numberOfPeople = personCollection.Count; <span class="keyword">int</span> numberOfSmokers = personCollection.NumOfSmokers; <span class="keyword">return</span> (Convert.ToDecimal(numberOfSmokers)/Convert.ToDecimal(numberOfPeople)) * 100M; } <span class="keyword">catch</span>(Exception) { <span class="comment">// Exception might be thrown, caught so that it doesn't leak out.</span> <span class="keyword">return</span> 0M; } } </pre> <p> Because they have absolutely no idea what exceptions might be thrown, they just wrap every non-trivial piece of code in a try/catch and try and attempt to pick a good default for when the routine fails. It's a sign the developer doesn't really know what's going on in their program; they're asking the computer to just blindly handle any errors in their logic. That's never a good policy because if you don't understand why each failure occurs, you can't be certain that your default case is really the right thing to do in all of the cases. </p> <p> Consider this bug, which is paraphrased from a bug I actually found at work: </p> <pre class="code csharp"> <span class="keyword">public static</span> Collection&lt;Widget&gt; RetrieveList(<span class="keyword">int</span> companyId) { <span class="keyword">try</span> { <span class="keyword">return</span> Broker.RetrieveList&lt;Widget&gt;(<span class="keyword">new</span> Key(COMPANY_ID, companyId)); } <span class="keyword">catch</span>(Exception) { <span class="keyword">return new</span> Collection&lt;Widget&gt;(); } } </pre> <p> In this case, the choice of default obscured a problem with the configuration-store for the persistence framework. Since the exception wasn't logged anywhere or wasn't even checked to see what type of error it was, it frustrated the debugging process for longer than it should have. </p> <p> If the developer had thought about what exceptions could be thrown, he might have made the configuration exception result in a program exit with a clear message. In some cases, you might even have a body of code that never produces an exception but is in a try/catch block none-the-less. This just makes it confusing and hard to read the code. </p> <p> People use this pattern because they believe that catching the exception means their program will "never fail." I've said it once and I'll say it again: Yes your program probably won't crash, but it will probably never work correctly either. </p> <h3>Failure to avoid exceptions</h3> <p> An exception avoided is worth fifty caught. Handling exceptions is expensive in any language. As soon as you throw an exception, the program has to unwind the stack in an attempt to find a handler. Moreover, code in a try/catch block can't be optimised by just-in-time compilers very easily. </p> <p> One of the key failure modes of structured exception handling is the fact the people do not attempt to avoid exceptions. In fact, they'll march in to them without barely a second thought. </p> <p> Consider the following code snippet: </p> <pre class="code csharp"> <span class="keyword">public int</span> CalculateDamage(Player player, <span class="keyword">int</span> hitSize) { <span class="keyword">int</span> returnedDamage = hitSize; <span class="keyword">try</span> { <span class="keyword">if</span> (player.PlayerClass == PlayerClass.Orc) { returnedDamage = hitSize * 0.5; } } <span class="keyword">catch</span>(Exception) { } <span class="keyword">return</span> returnedDamage; } </pre> <p> The exception the programmer is guarding against is the null reference exception. It would occur when player is referenced in the comparison against PlayerClass enum. </p> <p> The first problem with this code is that it is hard to work out what it does. For example, consider this question: under what circumstances will the catch block be hit? You have to do mental gymnastics to get at the underlying reason for the catch block's existence. </p> <p> Isn't this a lot simpler? </p> <pre class="code csharp"> <span class="keyword">public int</span> CalculateDamage(Player player, int hitSize) { <span class="keyword">int</span> returnedDamage = hitSize; <span class="keyword">if</span> (player != null &amp;&amp; player.Class == Class.Orc) { returnedDamage = hitSize * 0.5; } <span class="keyword">return</span> returnedDamage; } </pre> <p> Not only is the routine shorter, but it's also easier to understand. </p> <p> I still don't like the routine. It's clear that if a null player is passed to this routine then there is clearly a programming defect that the user needs to know about. There is no sense in hiding the bad behaviour behind a default. </p> <p> Yet, in the vast majority of cases where I see this sort of SEH, this is exactly what the programmer does. </p> <p> This leads to buggy programs where the root cause of a crash is difficult to determine. The program will wander on for some time, strolling from one exception handler to the next, until eventually an exception leaks out and crashes the entire program. Quite often, the place where the program finally dies is totally unrelated to the root cause of the problem. </p> <p> And SEH was meant to make writing reliable programs easier? </p> <h2>Can't this be fixed by hiring better developers?</h2> <p> Many notable people in the software industry think that all our problems can be solved by hiring practices. I think this is a fallacy. </p> <p> For a start, unless you're Google, attracting talent is hard. </p> <p> Even Joel Spolsky of Joel on Software fame has trouble attracting talent. He's arguably one of the best communicators in our industry. Joel's opinions on hiring are well known. He's written entire books about the importance of hiring the right people. </p> <p> However, even Joel is starting to learn the <a href="http://www.joelonsoftware.com/items/2008/05/01.html">hard way</a> that the best and brightest minds do not want to work on a bug-tracker. Joel isn't writing cool software. Just like 95% of the products in the world his product is pretty boring. </p> <p> I pick on Joel not because I have a grudge to bear with him; quite the opposite in fact since I enjoy his writing and his podcasts. I pick on Joel because he is loudist advocate of the "best developers solve all philosophy." For all his talent both in programming and in communication he can't change the force of gravity. Most of he products in the world are <i>not</i> sexy and it's going to be hard for him to attract talent. </p> <p> Given that all the really outstanding developers are at places like Google and Microsoft, a small company like Fogcreek or the one I work for can't really can't fix the problem by hiring the best. Rather than saying "The best developer can use Structured Exception Handling properly, so we'll hire them.." What are we going to say about the 75% of average developers who mis-use the technology on a daily basis? What tools are we going to give the much maligned mediocre developer to make sure they don't screw up their programs? </p> <p> To me, that is an absolutely essential question. This field doesn't advance much by making the super-star hotter but by improving the median developer. Super-stars develop 1% of the world's software. The median developers develop the rest. </p> <p> So yes, structured exception handling can be used effectively by the best but that is entirely beside the point. The real question is whether a given language feature is ergonomic enough to be used by the rest without compromising the programs they write? </p> <p> It's in this sense that I think return-codes are better than structured exception handling. It's much harder to use a return code badly. </p> http://www.ckwop.me.uk/Why-Exceptions-Suck.html Mon, 30 Jun 2008 21:26:36 GMT http://www.ckwop.me.uk/Why-Exceptions-Suck.html Reducing Complexity Using Higher-Order Functions <h2>Reducing complexity using higher-order functions</h2> <h3>Introduction</h3> <p> In my last post, I talked about the correlation between the overall cyclometric complexity and the defect count in your software. </p> <p> I listed a few ways that you can reduce the overall complexity. One of those ways was to use the Map/Reduce/Filter patterns extensively in your software. In this article, I'm going to show you how to use these routines to dramatically lower your overall cyclometric complexity. </p> <p> Map, Reduce and Filter are just routines that describe common behavioural patterns in programs. They all share a crucial similarity; they take as one of their arguments a function which is executed within the routine itself. </p> <p> As we shall see, this innovation will allow you to reduce the cyclometric complexity of your application. Sometimes the reduction can be very dramatic. </p> <p> This concept of passing routines as arguments to other routines is not new, it's been around in languages such as Haskell, Lisp and Erlang for decades. The lack of side-effects in these programing languages force you to think about functions in a more enlightened way. This sort of thinking is now only just becoming mainstream in common programming languages such as Python, Java and C#. </p> <h3>Anonymous Routines</h3> <p>When we write a routine during our normal programming lives, we usually explicitly name them, much like this snippet below:</p> <pre class="code python"> <span class="keyword">def</span> add<span class="grammar">(</span>a,b<span class="grammar">):</span> return a<span class="grammar">+</span>b <span class="keyword">print</span> add(<span class="literal">6</span>, <span class="literal">10</span>) </pre> <p> The vast majority of program code written in modern software is of this form; variables are passed into routines, these routine do computation on this data and return a result. These routines have a specific name and access rules, so they can be reused within the framework of your program. </p> <p> But what if rather than merely having data stored in the arguments of a function, we could have routines themselves. Take a look at the following snippet: </p> <pre class="code python"> <span class="keyword">def</span> construct_adder<span class="grammar">(</span>valueToAdd<span class="grammar">):</span> <span class="keyword">return lambda</span> y<span class="grammar">:</span> y <span class="grammar">+</span> valueToAdd adder <span class="grammar">=</span> construct_adder<span class="grammar">(</span><span class="literal">10</span><span class="grammar">)</span> <span class="keyword">print</span> adder<span class="grammar">(</span><span class="literal">6</span><span class="grammar">)</span> </pre> <p> What's going on here? Well, the routine called "construct_adder" is a special sort of routine. It is a routine that returns another routine. We call any routine that takes another function as a parameter or returns a function a "higher-order function." In this case, construct_adder returns a routine that adds the number specified in the "valueToAdd" argument to whatever is passed to it. This routine is assigned to the variable "adder", which is executed in the print statement on the next line. </p> <p> The key point here is that routine is dynamically constructed at run-time. The routine that we've created doesn't have a name in the traditional sense. The only way it can be referenced is through the variable it assigned to, in this case "adder." Once "adder" goes out of scope, the routine no longer exists and can no longer be executed. </p> <p> The magic occurs in the "lambda" expression in the construct_adder routine. I don't want to get too hung up on the syntax, but essentially the lambda says, "construct an in-line function here, with y as an argument." The result of the function is the evaluation of the expression to the right of the colon. </p> <p> While the example given above is a pretty superficial, the ability to construct custom routines at run-time using user supplied data is extremely powerful. It is a massive cyclometric complexity slayer. In this rest of this article, I'm going to try and give you a flavour how you can use anonymous functions to reduce the cyclometric complexity of your programs. </p> <h3>Reducing complexity by using anonymous routines with higher-order functions</h3> <h4>Using the Filter routine</h4> <p> One of the first things you learn when you start writing software is how to do a loop. The vast majority of places where you see a loop, the loop is usually iterating over a collection of things and performing some operation. These routine often have a many decision points. They are decision points that can be culled, if higher-order functions are properly deployed. </p> <p> Consider this Python snippet: </p> <pre class="code python"> <span class="keyword">def</span> get_matching_words<span class="grammar">(</span>startswith, wordlist<span class="grammar">):</span> result<span class="grammar">=[]</span> <span class="keyword">for</span> word <span class="keyword">in</span> wordlist<span class="grammar">:</span> <span class="keyword">if</span> word.startswith<span class="grammar">(</span>startswith<span class="grammar">):</span> result.append<span class="grammar">(</span>word<span class="grammar">)</span> <span class="keyword">return</span> result </pre> <p> The aim of this routine is to return a list of all the words in "wordlist" that start with the value passed in the "startswith" argument. </p> <p> This routine has a cyclometric complexity of three. There's a code path for the case where wordList is empty. There's a code path for where there are items in the word list but there are no matches, and finally there is a code path for when there are items in the word list that do match, and the result gets appended. </p> <p> You can do the same job in a single line using the Filter routine: </p> <pre class="code python"> <span class="keyword">def</span> get_matching_words<span class="grammar">(</span>startswith, wordlist<span class="grammar">):</span> <span class="keyword">return</span> filter<span class="grammar">(</span><span class="keyword">lambda</span> word<span class="grammar">:</span> word.startswith<span class="grammar">(</span>startswith<span class="grammar">)</span>, wordlist<span class="grammar">)</span> </pre> <p>The filter routine takes two arguments.</p> <p> The first is a routine that takes a single argument. That routine must return "True" or "False." Filter than executes that routine, passing each member of "wordlist" to the routine. If the routine returns true for that entry, the item is added to the list returned by filter. If the routine returns false, the item is omitted from the list. </p> <p> The second argument is the collection of items to run the routine on. </p> <p> In the case above, I defined a single anonymous routine that checks whether the argument passed to it starts with the value specified by "startswith." </p> <p> It's pretty clear that this program is equivalent to the longer snippet above, except that this routine has a cyclometric complexity of one. Your immediate thought here might be that I've just moved the cyclometric complexity in to the inbuilt "filter" routine. Yes, you're correct but bear in mind that there are a whole host of problems that can be solved using the filter routine. The complexity increase of your program when using filter is constant, regardless of how many times you use it. Each time you use a for loop, you're going to increase the complexity by at least two. Once for the code path represented by the body of the loop and one for case where there are no items to loop through. </p> <p> Another objection that might be raised is that loops are easy and that removing complexity in this way is not focusing on the real cause of bugs. I disagree, people do screw up loops and they're easier to get right if you use higher-order functions. </p> <h4>Using Map and Reduce</h4> <p> When I was writing this article, I decided to go and hunt through the code base at work and find some real-life loops that we can apply these ideas to. For copyright reasons, I can't post the exact code. However, I did come across a loop that is easy to screw up and looks much neater using Map and Reduce. I've sort of translated it in to python: </p> <p> Take a look at this code snippet: </p> <pre class="code python"> <span class="keyword">def</span> construct_list<span class="grammar">(</span>list<span class="grammar">):</span> result <span class="grammar">=</span> <span class="stringLiteral">""</span> <span class="keyword">for</span> counter <span class="keyword">in</span> range<span class="grammar">(</span><span class="literal">0</span>,len<span class="grammar">(</span>list<span class="grammar">)):</span> result <span class="grammar">+=</span> str<span class="grammar">(</span>list<span class="grammar">[</span>counter<span class="grammar">])</span> <span class="keyword">if</span> counter<span class="grammar">&lt;</span>len<span class="grammar">(</span>list<span class="grammar">)-</span><span class="literal">1</span><span class="grammar">:</span> result<span class="grammar">+=</span><span class="stringLiteral">","</span> <span class="keyword">return</span> result </pre> <p> The purpose of this routine is to concatenate a list of integers in to a string separated by commas. In our C# code, this routine was used to build a string for use inside a "in" clause in a SQL select statement. </p> <p> It's very easy to screw up this routine. You can easily get an off by one error on both the "range" routine at the top of the loop and the condition that decides whether to add a comma or not in the middle of the loop. </p> <p> The snippet above has a cyclometric complexity of three. </p> <p> It might seem hard to get the complexity below this value, but let's compare this with what we can do with map and reduce: </p> <pre class="code python"> <span class="keyword">def</span> construct_list<span class="grammar">(</span>list<span class="grammar">):</span> <span class="keyword">if</span> len(list) <span class="grammar">==</span> <span class="literal">0</span><span class="grammar">:</span> <span class="keyword">return</span> <span class="stringLiteral">""</span> string_list <span class="grammar">=</span> map<span class="grammar">(</span><span class="keyword">lambda</span> item<span class="grammar">:</span> str<span class="grammar">(</span>item<span class="grammar">)</span>, list<span class="grammar">)</span> <span class="keyword">return</span> reduce<span class="grammar">(</span><span class="keyword">lambda</span> firstItem,secondItem<span class="grammar">:</span> firstItem <span class="grammar">+</span> <span class="stringLiteral">","</span> <span class="grammar">+</span> secondItem, string_list<span class="grammar">)</span> </pre> <p> This routine has two phases, first map is called. What this does is for each element in the list, it runs the function passed to it and maps its result to a duplicate list. This list is returned when the map routine has completed and is assigned to string_list, in my program. I've simply used map to convert all the items in the list to strings. In the "reduce" phase, we reduce the list down to a single value. </p> <p> This routine has a cyclometric complexity of two. So we've made a saving of one over the first snippet. We could remove the if check at the top of the snippet but doing so would mean that if we passed an empty list to the routine, it will cause an error because reduce can't handle empty lists. One possible approach around this is to write a wrapper routine around reduce t handle empty lists. You could then handle all list loops using this new routine, with no further complexity cost. </p> <p> The clearest way to write this routine is probably to use recursion, but even this has a cyclometric complexity of three: </p> <pre class="code python"> <span class="keyword">def</span> construct_list_recursive<span class="grammar">(</span>list<span class="grammar">):</span> <span class="keyword">if len</span><span class="grammar">(</span>list<span class="grammar">) ==</span> <span class="literal">0</span><span class="grammar">:</span> <span class="keyword">return</span> <span class="stringLiteral">""</span> <span class="keyword">if len</span><span class="grammar">(</span>list<span class="grammar">)</span> <span class="grammar">==</span> <span class="literal">1</span><span class="grammar">:</span> <span class="keyword">return</span> str<span class="grammar">(</span>list<span class="grammar">[</span><span class="literal">0</span><span class="grammar">])</span> <span class="keyword">return</span> construct_list_recursive<span class="grammar">(</span>list<span class="grammar">[:-</span><span class="literal">1</span>]<span class="grammar">) + </span><span class="stringLiteral">","</span><span class="grammar"> + </span><span class="keyword">str</span><span class="grammar">(</span>list<span class="grammar">[-</span><span class="literal">1</span><span class="grammar">])</span> </pre> <p> It's clear that when the goal is to reduce cyclometric complexity, it's hard to beat map/reduce. </p> <h3>Passing routines as arguments to other routines</h3> <p> So far, we've looked at reducing cyclometric complexity by focusing on Map, Reduce and Filter. However, these routines are just higher-order functions provided by the Python standard library. Even bigger savings can be made if you write your own higher-order functions. </p> <p> Take for example, code that looks like this: </p> <pre class="code python"> <span class="keyword">def</span> insert_meta_data<span class="grammar">(</span>data<span class="grammar">):</span> title_field <span class="grammar">=</span> <span class="stringLiteral">"Title"</span> <span class="keyword">if</span> data.has_key<span class="grammar">(</span> title_field<span class="grammar">)</span> <span class="keyword">and</span> len<span class="grammar">(</span>data<span class="grammar">[</span>artist_field<span class="grammar">]) &lt;=</span> <span class="literal">30</span><span class="grammar">:</span> insert_rowdata<span class="grammar">(</span>title_field, data<span class="grammar">[</span>title_field<span class="grammar">])</span> artist_field<span class="grammar">=</span><span class="stringLiteral">"Artist"</span> <span class="keyword">if</span> data.has_key<span class="grammar">(</span>artist_field<span class="grammar">)</span> <span class="keyword">and</span> len<span class="grammar">(</span>data<span class="grammar">[</span>artist_field<span class="grammar">])</span> <span class="grammar">&lt;=</span> <span class="literal">50</span><span class="grammar">:</span> insert_rowdata<span class="grammar">(</span>artist_field, data<span class="grammar">[</span>artist_field<span class="grammar">])</span> release_date_field <span class="grammar">=</span> <span class="stringLiteral">"Release Date"</span> <span class="grammar">if</span> data.has_key<span class="grammar">(</span>release_date_field<span class="grammar">)</span> <span class="keyword">and</span> valid_release_data<span class="grammar">(</span>release_date_field<span class="grammar">):</span> insert_rowdata<span class="grammar">(</span>release_date, data<span class="grammar">[</span>release_date_field<span class="grammar">])</span> ..... The code continues for twenty such fields ..... </pre> <p> The point I want to illustrate with the snippet above is that there may be different validation rules required for each field. When you have code like this, it precludes looping through some list of parameters and validating each one in turn, because each one has slightly different constraints. </p> <p> Now imagine that we want to implement an update routine. There are two ways to do this traditionally. The most obvious way is to simply duplicate the checks in both routines. This clearly has a massive cyclometric complexity penalty and duplicates code so that approach should be avoided at all cost. </p> <p> The next is to rewrite the routine so that validation occurs before insertion. The validation step would produce a list of fields that are valid for insert/update and both routines could share a call to this validation logic. Each body of code would loop through the fields, adding or updating them as you go. Each of these routines must have a minimum cyclometric complexity of two, so you have a minimum complexity spend of four to implement it this way. It's also quite a bit more complicated, not in the cyclometric sense, but in the mental sense. There's more to fit in your head with this design. </p> <p> However, there is a dramatically more powerful way to solve this problem. You could do this: </p> <pre class="code python"> <span class="keyword">def</span> change_meta_data<span class="grammar">(</span>data, update_routine<span class="grammar">):</span> title_field <span class="grammar">=</span> <span class="stringLiteral">"Title"</span> <span class="keyword">if</span> data.has_key<span class="grammar">(</span>title_field<span class="grammar">)</span> <span class="keyword">and</span> len<span class="grammar">(</span>data<span class="grammar">[</span>artist_field<span class="grammar">]) &lt;=</span> <span class="literal">30</span><span class="grammar">:</span> update_routine<span class="grammar">(</span>title_field, data<span class="grammar">[</span>title_field<span class="grammar">])</span> artist_field <span class="grammar">=</span> <span class="stringLiteral">"Artist"</span> <span class="keyword">if</span> data.has_key<span class="grammar">(</span>artist_field<span class="grammar">)</span> <span class="keyword">and</span> len<span class="grammar">(</span>data<span class="grammar">[</span>artist_field<span class="grammar">]) &lt;=</span> <span class="literal">50</span><span class="grammar">:</span> update_routine<span class="grammar">(</span>artist_field, data<span class="grammar">[</span>artist_field<span class="grammar">]</span> release_date_field <span class="grammar">=</span> <span class="stringLiteral">"Release Date"</span> <span class="keyword">if</span> data.has_key<span class="grammar">(</span>release_date_field<span class="grammar">)</span> <span class="keyword">and</span> valid_release_data<span class="grammar">(</span>release_date_field<span class="grammar">):</span> update_routine<span class="grammar">(</span>release_date, data<span class="grammar">[</span>release_date_field<span class="grammar">])</span> </pre> <p> The second argument contains a routine that will be executed during the body of the code. You now pass in which routine you want to run within change_meta_data and it will either update or insert a row. Notice how the cyclometric complexity of the change_meta_data routine has not gone up, even though the routine can now operate in two (or more!) distinct modes. The most obvious choice of update_routine would be something that inserts or updates a table row, but this doesn't have to be case. For example, the update_routine could be inserting or updating an in-memory cache. </p> <p> The point is, we can decide at run time what gets executed within this routine and we can get this ability to choose without having to introduce any additional complexity. </p> <h3>Conclusion</h3> <p> In this article, I wanted give you a taste of how higher-order functions can help you control complexity. With a small amount of careful thought, it is possible to chop out a considerable amount of cyclometric complexity contained within your application. </p> <p> I hope I've convinced you that higher-order functions are worth investigating in your project. They're a powerful tool that helps you to write less code and the less code you write the less you have to debug and maintain. </p> http://www.ckwop.me.uk/Reducing-Complexity-Using-Higher-Order-Functions.html Sat, 03 May 2008 16:43:17 GMT http://www.ckwop.me.uk/Reducing-Complexity-Using-Higher-Order-Functions.html Cyclometric Complexity and Defects <h2>Cyclometric Complexity and defects</h2> <p> When we say a program is complex, what exactly do we mean by complex? In future posts I'm going to keep returning to this issue, but today I'm going to deal with one type of complexity: cyclometric complexity. </p> <p> The cyclometric complexity of a routine is the number of independent code-paths through the procedure. Examine the following Python routine: </p> <pre class="code python"> <span class="keyword">def</span> f<span class="grammar">(</span>x<span class="grammar">):</span> <span class="keyword">if</span> x<span class="grammar">==</span><span class="literal">0</span>: <span class="keyword">print</span> <span class="stringLiteral">"Zero"</span> <span class="keyword">if</span> x<span class="grammar">&gt;</span><span class="literal">0</span>: <span class="keyword">print</span> <span class="stringLiteral">"Greater than Zero"</span> <span class="keyword">if</span> x<span class="grammar">&lt;</span><span class="literal">0</span>: <span class="keyword">print</span> <span class="stringLiteral">"Less than zero"</span> </pre> <p> Assuming that we pass in an integer to this routine, there are three distinct code paths. One for when x is zero, one for when x is greater than zero and one for when x is less than zero. The cyclometric complexity of this routine is therefore three. The larger the cyclometric complexity of a routine the more complex it is. </p> <p> You can then add up the total cyclometric complexity over all the routines in a program to get a feel for the complexity of the entire program. For even the smallest of programs the cyclometric complexity is likely to be in well in to the thousands. In large projects, it will probably run in to tens of a millions. </p> <p> This seems to tie in nicely of what our intuition tells us complexity should be. The more decision points your program has the more complex your piece of software is. </p> <h3>Does lowering cyclometric complexity reduce defects?</h3> <p> We know that complexity is the source of bugs. A natural question to ask is whether working to reduce the cyclometric complexity of a program also reduces the defect count in that program? </p> <p>In Steve McConell's pivotal book, Code Complete, he has this to say about Cyclometric complexity and defects:</p> <div class="Quotebox"> <p> Control-flow complexity is important because it has been correlated with low reliability and frequent errors (McCabe 1976, Shen et al. 1985). William T. Ward reported a significant gain in software reliability resulting from using McCabe's complexity metric at Hewlett Packard (1986b). McCabe's metric was used on one 77,000-line program to identify problem areas. The program had a post-release defect rate of 0.31 defects per thousand lines of code. A 127,000 line program had a post-release defect rate of 0.02 defects per thousand lines of code. Ward reported that because of their lower complexity, both programs had substantially fewer defects than other programs at Hewlett-Packard. My own company, Construx Software has experienced similar results using complexity measures to identify problematic routines in the 2000s." </p> </div> <p> I think the verdict here is pretty resounding. Lowering the over-all cyclometric complexity of a program is going to reduce bugs considerably. </p> <h3>How do I go about lowering complexity?</h3> <p> The number of decision paths in your typical program is going to be huge. But reducing overall decision complexity can be achieved by aggressively adopting the following principles: </p> <ul> <li> Reuse code really aggressively. Anywhere you see decisions repeated, you want to wrap that up in a separate routine even if it's only a few lines long. </li> <li> Don't use <a href="http://en.wikipedia.org/wiki/Short-circuit_evaluation">short-circuit</a> evaluation where you don't have to. This simply adds decision paths that aren't neccessary. </li> <li> Try and reduce the number of return points in a routine. Ideally, there should only be one return point. </li> <li> Take long, complicated routines and break them up in to smaller routines. Although this won't lower the overall complexity, it will make the code easier to reason about and therefore less likely to contain errors. </li> <li> Try and use set operations such as map and reduce to reduce boiler plate decision logic (such as loops). You will be surpised how many problems fit in to the map/reduce model. </li> <li> Use try/catch clauses sparingly. It's very easy to produce exceedingly complex control flow with exception handling. </li> <li> Don't implement "speculative" features. </li> </ul> <p> The primary message is that lowering complexity is about writing less code. The less code you write the less decision points there are. At every opportunity you should try to write less code. </p> <h3>How can I identify problematic routines?</h3> <p> There are a number of tools in a variety of languages that allow you to flag routines that have a high cylcometric complexity. The rule of thumb is to rewrite any routine where you have a cyclometric complexity of greater than ten. </p> <p> You can use the following tools in your organisation to measure the cyclometric complexity of your routines: </p> <ul> <li><a href="http://www.anticipatingminds.com/content/Products/devMetrics/devMetrics.aspx">C# Refactory</a></li> <li><a href="http://pmd.sourceforge.net/">Java</a></li> <li><a href="http://www.chris-lott.org/resources/cmetrics/">C++ and C</a></li> <li><a href="http://sourceforge.net/projects/pymetrics">Python</a></li> </ul> http://www.ckwop.me.uk/Cyclometric-Complexity-and-defects.html Mon, 31 Mar 2008 22:13:23 GMT http://www.ckwop.me.uk/Cyclometric-Complexity-and-defects.html Is refactoring worth the money? <h3>Introduction</h3> <p> It is generally appreciated at an abstract level that the idea of improving the design of code that is already written is a good idea. I have the heart of a purist and I like to see nice, well structured code but I also work in a small business. I am acutely aware that refactoring costs time and time is most definitely money. So I ask, is refactoring worth the money? </p> <h3>The idea behind refactoring</h3> <p>Martin Folwer, in his famous book on refactoring, defined refactoring as:</p> <div class="Quotebox"> "Refactoring is the process of changing a software system in such a way that is does not alter the external behavior of the code yet improves its internal structure. It is a displined way to clean up code that minimizes the changes of introducing bugs. In essence, when you refactor you are improving the design of code after it has been written." </div> <p> Apart from getting a warm fuzzy feeling for code, why would I do this? Well, the principle argument for refactoring is that it speeds up the development of new features. The easier it is to develop a feature, the less money it costs. </p> <h3>The Hard Numbers - The optimistic</h3> <p> Okay, so if refactoring saves us time then we might want to do a major refactoring project so that we can increase productivity amongst our developers. Let's say, that for the sake of argument, that refactoring saves 10% on development time. Let's say and I plan to spend a single developer's time on the effort for three months to achieve this 10% efficiency gain. Let's call the money made on this venture "Account A". </p> <p> Further, let's take the same time we were going to spend on refactoring and invest it in a low risk savings account. There is nothing special about this account; any bank's saving rate on this will do. I'm going to choose Northern Rock's saving rate which is roughly 6% in the UK. Let's call this "Account B." </p> <p> At first, this might seem a bit of a weird account to have, but this is meant to represent the minimum "opportunity cost" of doing refactoring. The money you spent on refactoring could have been allocated elsewhere to make you money. The most basic way you could allocate the funds is by simply investing it at market rates. If refactoring can't beat basic investment, it isn't work doing. </p> <p> Because days of man time cost a fixed amount of money, we can just calculate interest on the development days directly and save the additional effort of having to manipulate values in any given currency. </p> <p> Here is the table of data comparing both accounts: </p> <table> <tr> <th>Year</th> <th> Account A </th> <th> Account B </th> </tr> <tr> <td> 0 </td> <td> 0.00 </td> <td> 90 </td> </tr> <tr> <td> 1 </td> <td> 36.53 </td> <td> 95.40 </td> </tr> <tr> <td> 2 </td> <td> 73.05 </td> <td> 101.12 </td> </tr> <tr> <td> 3 </td> <td> 109.58 </td> <td> 107.19 </td> </tr> <tr> <td> 4 </td> <td> 146.10 </td> <td> 113.62 </td> </tr> </table> <p> There are a couple of things to note here. After two and a bit years, you will have paid back your capital expenditure. After nearly three years you will beat what you would have earned if you'd just invested that development time in the bank. </p> <p> It's worth noting that by staying the course on Account B, the exponential gains of interest will eventually out pace Account A. This occurs fifty or so years after the refactoring was done. That data point is of little practical relveance since the product will probably not exist by that time. </p> <p> After just under three years we're getting more money from our refactoring exercise than the trivial case of investing the money in a savings account. That looks like a solid medium term investment. </p> <h3>The Hard Numbers - The Pessimistic</h3> <p> I don't know of any studies that give the real productivity improvement of refactoring but I feel that 10% may be a little too generous. Let's say that refactoring improves developer productivity by 5% instead of 10%. </p> <p> Our table of accounts table now looks like this:</p> <table> <tr> <th>Year</th> <th> Account A </th> <th> Account B </th> </tr> <tr> <td> 0 </td> <td> 0.00 </td> <td> 90.00 </td> </tr> <tr> <td> 1 </td> <td> 18.26 </td> <td> 95.40 </td> </tr> <tr> <td> 2 </td> <td> 36.25 </td> <td> 101.12 </td> </tr> <tr> <td> 3 </td> <td> 54.79 </td> <td> 107.19 </td> </tr> <tr> <td> 4 </td> <td> 73.05 </td> <td> 113.62 </td> </tr> <tr> <td> 5 </td> <td> 91.31 </td> <td> 120.44 </td> </tr> <tr> <td> 6 </td> <td> 109.57 </td> <td> 127.67 </td> </tr> <tr> <td> 7 </td> <td> 127.84 </td> <td> 135.33 </td> </tr> <tr> <td> 8 </td> <td> 146.10 </td> <td> 143.45 </td> </tr> </table> <p> At this rate it takes a shade under five years to repay the initial cost of the refactoring. It takes about eight years for the refactoring to come out ahead of straight-forward investment. </p> <p> In software, eight years is an age. If refactoring gives anything less than a 10% productivity improvement it probably isn't worth doing. </p> <h3>The Hard Numbers - Doing Refactoring every five years</h3> <p> Except, that when you're done refactoring, are you really done? As time goes on, code gets more hairy and every so often you boss might factor in time to refactor your code. Let's say your boss wants to do three months of refactoring every five years. Let's be say that refactoring improves your productivity by 8%. This is somewhere between the two figures given in this article and represent my gut feel for how much time a well factored program can save. </p> <p> Here is how our accounts look now: </p> <table> <tr> <th>Year</th> <th> Account A </th> <th> Account B </th> </tr> <tr> <td> 0 </td> <td> 0.00 </td> <td> 90.00 </td> </tr> <tr> <td> 1 </td> <td> 29.22 </td> <td> 95.40 </td> </tr> <tr> <td> 2 </td> <td> 58.44 </td> <td> 101.12 </td> </tr> <tr> <td> 3 </td> <td> 87.66 </td> <td> 107.19 </td> </tr> <tr> <td> 4 </td> <td> 116.88 </td> <td> 113.62 </td> </tr> <tr> <td> 5 </td> <td> 56.10 </td> <td> 120.44 </td> </tr> <tr> <td> 6 </td> <td> 85.32 </td> <td> 127.67 </td> </tr> <tr> <td> 7 </td> <td> 114.54 </td> <td> 135.33 </td> </tr> <tr> <td> 8 </td> <td> 143.76 </td> <td> 143.45 </td> </tr> <tr> <td> 9 </td> <td> 172.98 </td> <td> 152.05 </td> </tr> <tr> <td> 10 </td> <td> 112.20 </td> <td> 161.18 </td> </tr> <tr> <td> 11 </td> <td> 141.42 </td> <td> 170.85 </td> </tr> <tr> <td> 12 </td> <td> 170.64 </td> <td> 181.10 </td> </tr> <tr> <td> 12 </td> <td> 73.05 </td> <td> 113.62 </td> </tr> <tr> <td> 13 </td> <td> 199.86 </td> <td> 191.96 </td> </tr> <tr> <td> 14 </td> <td> 229.08 </td> <td> 203.48 </td> </tr> <tr> <td> 15 </td> <td> 168.30 </td> <td> 215.69 </td> </tr> </table> <p> Every five years, 90 is subtracted from Account A to cover the cost of refactoring. It is clear that over each cycle, you will cover the cost of the refactoring but in the long term, simply investing the cash will give you a better return on investment. </p> <h3>Conclusion</h3> <p> This article is a mixed bag. For refactoring to be a better investment than just banking the cash, you have to improve productivity by 5-8% or more. This is quite a big ask and I have big doubts this can be achieved in practice. If your opportunity cost is much higher than the figures represented by "Account B" then you're probably best spending the money on something else, like new features or defect reduction technqiues. </p> <p> This analysis also assumes that refactoring was done perfectly and didn't introduce errors. If refactoring is done even slightly imperfectly, it is very easy to wipe out the productivity benefits of refactoring through the increased debugging cost. </p> <p> So where is refactoring useful? Well, I would say that refactoring has utility where a code base, as a black box, works but is unmaintainable. The more unmaintainable the code base, the more refactoring is likely to give you. If a code-base is horribly buggy then a large amount of logic is going to have to be reworked in any event. Refactoring may help in spotting problems but the real solution is to rewrite the buggy modules - which is really new development rather than refactoring. </p> <p> Personally, I think refactoring solves the wrong problem. If code is badly designed then some process resulted in that bad design. Fixing the process is going to be a lot more effective than continually fixing the code. </p> <p> If you just refactor periodically without learning anything about why you needed to refactor in the first place, then you have missed an important opportunity to fix things. </p> <p> It should be obvious that fixing mistakes before they even occur is the cheapest way to fix a mistake. Refactoring seeks to fix a preventable mistake that should have been prevented. </p> http://www.ckwop.me.uk/Is-Refactoring-Worth-The-Money.html Mon, 24 Mar 2008 18:47:00 GMT http://www.ckwop.me.uk/Is-Refactoring-Worth-The-Money.html Coverage analysis and what it means to you <h2>Coverage Analysis and what it means for you</h2> <h3>Introduction</h3> <p> In my last post, I talked about how much bugs cost. In this post, I'm going to talk about how we can remove them. Removing bugs has always been a multi-faceted problem. Any bug removal strategy has to contain a number of separate attacks on the problem of bugginess. </p> <p> Formal inspections have been shown to be the most effective way of removing bugs, both in terms of bugs discovered per hour of testing and the cost of finding those bugs, but formal inspections are only part of the solution. </p> <p> In this post, I'm going to talk about another technique for rooting out bugs; namely code coverage. </p> <h3>What is code coverage testing?</h3> <p> When you write code you should always have a plan of how you're going to test that code. One question you can ask about your test suite is "How many code paths do my test cases cover?" Or perhaps, more precisely "What percentage of my code is exercised by the test suite?" </p>http:// <p> Coverage analysis allows you to answer those questions. Most well used languages have at least one coverage analyser. </p> <p> These coverage tools work by injecting instrumentation code in to your code which records when each statement in your program is executed. When the test suite is executed against this augmented code, a report is produced of all the statements executed when your test suite is run. </p> <p> Here's a screen-shot of the NCover tool I use at work: </p> <img src="http://www.ckwop.me.uk/images/NCoverImage.gif" alt="NCover Screenshot" /> <p> The blue bits show the statements that were covered by the test suite. The red bits shows the code that was not covered by the test suite. </p> <h3>If I get 100% coverage does that mean my program is bug free?</h3> <p> No, this is the poisonous side of coverage testing. It's very easy to turn it in to a game where the goal is to get 100% coverage. This is generally not a productive use of your time. The whole point of doing coverage analysis is to try and find untested areas of your code with the goal of <b>finding bugs</b>. </p> <p> It's a well supported fact that 80% of the bugs reside in 20% of the code. If you go for 100% coverage of your code base you're going to spend a lot of money testing the modules that are not very buggy. You could take the same resources you're using to achieve 100% coverage and put them in to properly testing your buggy modules and you would remove a lot more bugs. </p> <p> Another problem is that coverage analysis has is that it can only test code that is there. There are a great number of errors that are caused by code that is missing; code that doesn't exist. </p> <p> For example, consider the following function written in Python. It tries to compute the roots of a quadratic equation of the form ax<sup>2</sup> + bx + c: </p> <pre class="code python"> <span class="keyword">def</span> roots<span class="grammar">(</span>a, b, c<span class="grammar">):</span> root = <span class="grammar">(-</span>b <span class="grammar">+</span> math.sqrt<span class="grammar">(</span>b<span class="grammar">**</span><span class="literal">2</span> + <span class="literal">4</span><span class="grammar">*</span>a<span class="grammar">*</span>c<span class="grammar">)) /</span> a <span class="keyword">return</span> root </pre> <p> This code contains a few bugs. First, the inputs a, b, c are not checked to see if they're numbers. Second, even if 'a' is a number the program will crash if the value of 'a' is zero. These are both precondition errors and in a language like Python, with its duck-typing, we might let the first of these slide. However, not checking whether 'a' is zero is definitely a bug. There is an even more serious error: there are two roots to a quadratic equation and the code only gives you one of them. </p> <p> All the defects I've pointed out are defects of omission. There is code missing from the program that means an error can occur in some circumstances. If you were blindly trying to get 100% code coverage, you'd probably miss all these defects. You can get a 100% coverage of this routine by just passing a=1, b=2, c=3 to the algorithm and you're done. </p> <h3>So what does coverage analysis actually tell me?</h3> <p> Coverage analysis tells you the areas of code that didn't get executed by your test suite. This means that your test suite is deficient in someway as it doesn't cover all the functionality. </p> <p> It is important to use your coverage analyser as a tool to inform the development of further tests in your suite and not as an end to itself. </p> <p> My approach to writing tests is to not use the coverage analyser on my first attempt at writing a test suite. After composing my first lot of tests, I then remove any bugs I've found and then run the coverage analyser. </p> <p> This will normally throw up a few more features that need testing. I then code up these tests and check how I did again. Assuming I covered all the important scenarios, I then stop and move on to other types of testing. </p> <p> The skill to correctly using a coverage analyser is knowing when to quit. If you quit too early, you'll leave too much code untested, if you quit too late then you're just wasting your time that could be spent on more focused, effective testing. </p> http://www.ckwop.me.uk/Coverage-analysis-and-what-it-means-to-you.html Sat, 08 Mar 2008 17:29:35 GMT http://www.ckwop.me.uk/Coverage-analysis-and-what-it-means-to-you.html