Sunday, 29 August 2010

Calling your shots

I'm not sure where I first heard the term, but I remember reading Mark Needham's post titled TDD: Call your shots (Mark publishes loads of interesting stuff. If you're not subscribed, do so now! :)).

The idea is that before every test run you call what the result will be in advance. So rather than just writing your failing test and waiting for the error message to tell you what to do next, you should have thought through the problem and know (or at least expect) it to fail the Assert.AreEqual assertion because you haven't wired up the code to return the value from the WidgetFactory yet.

Calling shots for increased understanding

Now I've found it very easy to fall into the trap of thinking through just enough to flesh out some design via my test, then switching off and assuming a state not unlike semi-sentient vegetable matter while I run the test and mash intellisense combinations until the test goes green and I can resume normal thought. It's almost Pavlovian: green light means thoughtful Dave; red light means rutabaga Dave.

Calling my shots has really helped me fix this, and it has made a quick and significant difference to my coding. It forces me to keep focused, and because I'm concentrating on both red and green parts of the TDD cycle I find I build up a lot more context and understanding of the entire code base.

A common complaint I hear when people first start moving to OO code (as opposed to procedural code in an OO language) is that the amount of abstraction makes it quite difficult to keep much of the object graph in mind at once. Calling my shots has definitely improved my ability to do this, not just for code I am working on, but even for unfamiliar codebases. It's as if the additional exercise of keeping both the test and production code in mind at once makes it easier to think in multiple levels of abstraction.

Calling Intellisense shots

I was reading through Davy Brion's post on how extensions methods bloat Intellisense (again, if you're not subscribed, do so now) and it occurred to me I've been extending the "calling your shots" idea to Intellisense as well, which is probably why the extension method bloat hasn't really bothered me.

Rather than compulsively mashing Intellisense (wow R# smart code completion can be addictive), I try to make sure I know exactly which member I'm after before calling up the Intellisense popup.

Again, this has had a very positive impact on my coding. First, as with calling test results, it helps me recall and understand more details about the code I'm working with. Second, I think I'm actually going faster. How many times have you called up Intellisense to complete something like .ToString()? By the time you've moved off the home row to select the method you could have typed it two times over. And thirdly, being able to recall your code's API or standard library calls comes in handy for times when you don't have as advanced Intellisense, like when working with dynamic languages.

Aside: Back in my uni days I used to code Java in Emacs. And I knew those APIs. I would look up Javadoc the first couple of times, then I'd just type the right calls by reflex. I miss being able to do that, but calling the shots is now giving me a bit of the best of both worlds: I learn the APIs, but also get quick access to the member list in code I'm not familiar with.

Start calling today!

I definitely recommend calling your shots with TDD; you've got nothing to lose and loads to gain. Weaning yourself off Intellisense-addiction may be substantially more challenging, and probably won't suit everyone, but if you're a fairly fast typer and have every caught yourself longing for a simpler IDE experience then give it a go.

Saturday, 28 August 2010

Quality vs. shipping

I've just been reading Phil Haack's We're not paid to write code post, and it happened to trip over one of my fundamental beliefs about software development and code quality.

I agree with almost the entirety of the post. As developers, we are not paid to write code, we're paid "to ship products and deliver value". True, we're paid primarily as people that know something about writing software, but that includes knowing what problems to tackle with custom software, when to use another piece of software and even when a non-technical solution is more appropriate.

Which brings us to a related point: shipping is a feature. Without shipping, without actually giving customers something they can use and get value from, it doesn't matter how much or how good the code your write is. It may as well not exist.

Phil also goes on to suggest "quality isn't just the defect count of the code. It's also how well the code meets the business needs". Right on! There is very little point in having zero defects if it doesn't do what the customer needs. Sure, we need to take care to control defects and risks*, but to me the quality of software can not be measured purely by a bug count.

* There are some situations in which a defect simply cannot be tolerated, such when it will cause serious harm. The risk in this case simply must be eliminated, but that is different than having defect free software.

All in agreement still? Great!

Scaling quality?

"Quality in development is important, but it has to be scaled appropriately. ... The reality is we all scale the quality of our code to the needs of the product."

Now I'm pretty sure Phil is a firm believer in software quality (some of his posts on TDD helped me get into the practice), so he's not suggesting that we ditch quality and switch to duct tape. More that quality, like most things, is a tradeoff.

He is writing this with respect to various approaches for reducing defects (like Cleanroom Software Engineering used for developing space shuttle software), rather than with the more holistic view of quality that includes suiting business needs, and he says as much in the post.

But the message is out there: we can trade quality, and I have two major problems with this.

Semantics and convenient extrapolation

The first problem is due to the subjective nature of the term "quality". Sure, if you are talking purely in terms of defects, a rigourous, 10 year testing phase on your intranet Phone Directory application may improve quality in terms of defect count, but at the cost of making the software completely useless for that time (and probably irrelevant by the time it ships). You can probably trade off some of that "quality" by adopting a more sensible, responsible testing regime.

But how about the more holistic side of quality? What about the bit about meeting business needs? Is it meeting their needs to have an unreliable piece of software that loses the data they are relying on? How about a piece of software that is such a hack it cannot be modified to meet simple changes to their needs without a year-long re-write, during which they are losing time, money and business? I can trade off that kind of quality in favour of shipping, right? So why should I waste time keeping application and data access logic out of the UI code? Why should I bother writing unit or acceptance tests? Why should I care if this is a disgusting mess of spaghetti code if I ship?

I believe there are some elements of quality your can't trade. The fundamentals of software development that help ensure your software is fit for purpose is one of these elements. I know Phil wasn't suggesting that, but it seems a fairly common and convenient extrapolation when people start talking about scaling quality.

Quality means slow?

My second problem with the idea of trading quality, and probably the most harmful as it encourages the "convenient extrapolation" I talked about above, is the implication that quality is slow, and that trading it away will somehow make shipping value to customers faster and more effective.

Now it is my belief that this is wrong. The idea that doing shoddy work has any benefit to customers or timelines just doesn't match up with my experience of developing both "just ship it" software and software with a high focus on quality.

I'm not talking about 10 year defect hunts here. I'm talking about developing software in a way that ensures quality; that ensures your software meets the needs of your customer.

Shipping with quality: What if you could have both?

This has been a key focus of the last 5+ years of my professional life: finding ways to ensure quality is built into the way I develop software. It should not be a cost; it should be the fastest and most effective way to get value into the hands of my customers. The idea that the software you ship is fit for purpose should be fundamental to producing that software.

Impossible? Do you believe sacrificing quality will always be faster than doing things "properly"?

  • What if Uncle Bob is on to something when he says "the way to go fast is to go well"?
  • What if doing high quality work did not add extra cost to a project?
  • What if doing things "properly", instead of hacking up something to ship, did not take any longer?
  • What if following SOLID design principles, writing tests, using design patterns (appropriately), dependency injection, continuous integration and TDD turned out to not be an overhead, but actually meant you could respond faster to customer needs?
  • What if the higher quality of the code actually made it faster to work on, and meant you could ship sooner?

If this all sounds crazy to you, what do you think has led you to that conclusion?

What if your current choice of tools, practices or technology stack meant none of the above points were true?

Would you simply accept that it is impossible to do good work and ship? Or would you change your stack, look to other technologies or different paradigms, find or write new tools, or adopt practices that don't punish you for trying to do your job properly?

What if this idea that quality and shipping are somehow in opposition is not an inherent property of software development? It is interesting way to challenge yourself: what can you change in the way you currently work so that quality aids shipping, rather than hinders it?

Monday, 23 August 2010

Continually running a script with Ruby and Watchr

I'm currently working through Ruby Koans, which involves editing some .rb files, running a build and watching the output for hints on what change to make next. It's quite a fun mix of TDD and puzzle solving. I did start to find constantly rebuilding after each change a bit laborious though, so I thought I'd look at automating it (Autotest style).

After floundering around Google for a while I asked Twitter and @joshnesbitt helped me out, suggesting I try Watchr. After installing the gem, I ending up putting the following auto_enlighten.rb script in the koans directory:

require 'rubygems'
require 'watchr'

all_rb = Dir['*.rb'].join('|')
script = Watchr::Script.new
script.watch( all_rb ) { |file| system("rake") }
controller = Watchr::Controller.new(script, Watchr.handler.new)
controller.run

This script selects all .rb files in the current directory and tells the Watchr script to run rake (to build the koans and get the next hint) whenever one of those files changes. I then can run ruby auto_enlighten.rb from my terminal and hack away happily in vim, and each time I save a file I get near-instant feedback on how my change affected my progress through the koans. I've found this a very nice way to work through the koans.

Watchr also has some scripts for common tasks like running tests and specs, can be run from the command line, or can be used programmatically as we're doing here. Definitely worth checking out. :)

Friday, 20 August 2010

Building native extensions for Ruby Gems on Windows

This tripped me up for a little while, so I thought I'd post it in the hope that it will save someone else some head-scratching.

If you're running Ruby on Windows and trying to install a gem that uses native extensions, you may get an error like this (depending on how you got Ruby on to your machine):

$ gem install jekyll
Building native extensions.  This could take a while...
ERROR:  Error installing jekyll:
        ERROR: Failed to build gem native extension.

c:/Ruby191/bin/ruby.exe extconf.rb
creating Makefile

make
'make' is not recognized as an internal or external command,
operable program or batch file.

Turns out the answer is quite simple: RubyInstaller DevKit.

The site has the full instructions, but to give you a quick summary it is just a matter of downloading DevKit, extracting it somewhere, then running ruby dk.rb init followed by ruby dk.rb install. I was very impressed with how easy it was to get working.

Hope this helps.

Saturday, 14 August 2010

There is no U in Collective Ownership

One of the practices of Extreme Programming (XP) is collective ownership. The general idea is that everyone can contribute to any part of the code or design: the entire team owns and is responsible for all segments of the project.

I tend to extend this idea to even more extreme lengths (even by XP standards ;)): a team that works together takes joint ownership of and responsibility for the work done, including the decisions made along the way. If everyone is free to contribute to any part of the project, then everyone shares responsibility for the outcome. An "incorrect" decision made by an individual is made in the context of an environment created by the team: the team's coding standards and conventions, the existing design, the way architecture and coding practices have been communicated and taught to the team members.

Eroding collective ownership

The practice of collective ownership is one that is easy to pay lip service to, but I find that even in teams with the best of intentions it is quick to disintegrate in the face of pressure. Here's some examples of collective ownership breaking down:

  • I've no idea what this is; Bob was working on that.
  • Jane, you need to stop writing duplicate setup methods.
  • Rob made that decision.
  • I told you we shouldn't use a factory there, but you wouldn't listen to me.

All these statements may be correct, or even said in good humour and with good intentions, but they all undermine the practice of collective ownership. The moment someone says "you/him/her/them", rather than "we" or "us", they are no longer taking collective ownership. They have moved responsibility to an individual or subset of the team, and away from the team as a whole.

What's the big deal?

So why is this a problem? Surely saying "we" instead of "you" is just unecessary political correctness; yet another symptom of a culture that seeks to diminish personal responsibility and accountability? In life and relationships-in-general I agree, but for a project team I've found a less-than-whole-of-team approach to be surprisingly damaging.

What happens the moment someone says "You did this"? It is human nature to explain why; to explain the context in which the decision was made and why it made sense. In that instant the focus has moved from a legitimate issue to a discussion about the past, possibly to being defensive, or apologetic, or aggressive. This is valuable time that could be used to actually make progress on the issue. That's not to say the causes or context should be ignored, just that it should not be an individual justifying it, but the team examining it. The fact that Rob or Jane made the decision is largely irrelevant. They made it in the context of the time with, we trust, the best of intentions. It is with this trust that the team commits to take collective ownership for decisions. Instead of singling out individuals, the discussion should focus on how to fix the issue and prevent it from reocurring. In short: to improve as a team.

Even writing this it sounds ridiculous that something that sounds so semantic should make a difference, but I have seen this happen. Many, many times. And it chokes momentum, it stifles creativity, it stops people from taking the chance and the opportunity to be wrong and to learn. And in extreme cases it can damage the team, creating different alliances and politicking between team members, which is time better spent working together to get this iteration done.

Keeping it collective

The key to keeping collective ownership alive and well is to remember there is no U in collective ownership. There is "we" and "us".

Rather than singling out work that Bob did that you don't understand, tell the team that you are having trouble understanding this section of code and so it might be worth refactoring, or at least get the team to look at it together. Chances are you are not the only one struggling with it, so it becomes a good opportunity for the team to learn and share knowledge. If you are the only one struggling with it, then pairing will help spread the knowledge more effectively around the team.

Instead of telling Jane to stop writing duplicate setup methods, tell the team you've found duplication in setup methods and show some refactorings to remove it. Maybe hold a lunch time brown-bag session on it if you feel it could benefit the team. The key is to avoid viewing the problem as Jane's, but instead as a problem with the team communicating how to keep the tests DRY, or possibly that the test fixtures aren't organised in a way that makes the duplication obvious. Either of these approaches will lift the entire team, rather than just talking to Jane about it which only helps her.

While simply changing the language used will help and is a very good place to start, it is more important to actually value and commit to collective ownership within the team. This is most challenging when the team is debating several approaches and having difficulty reaching a consensus. You may really strongly disagree with a particular approach, but if you can't convince your team of that and the team decides to pursue it, then you own this decision as part of your team. That means no gloating if things blow up; no "I told you so"; and definitely no sulky, half-hearted work on that section, which effectively amounts to sabotaging the team's choice. The team owns the decision, it is your job as part of the team to make it work. If it doesn't, then the team will come together to fix it.

If you don't have the expertise to make a decision, then you put your trust in the team members that do, and again once the decision is made, you own the responsibility for that decision along with the rest of the team.

When collective ownership is a waste of time...

There are times when collective ownership is never going to work. First, when it isn't real. If all the decisions get made by business analysts that hand requirements to an architecture team, that give a design to some code monkeys, then pretending everyone owns the decision is a completely useless lie. Similarly if you have a few team members that all work on separate modules then it will be the individuals that own those modules. Collective ownership relies on having a single, cohesive project team.

Second, it won't work when the team does not commit to it. If you are in a poisonous team or environment, where people are more concerned with their career prospects, company politics or their own prestige, then trying to share both successes and failures is also going to be a waste of time. Less dramatically, if you have a dramatic power differential between parts of the team (real or imagined) then it is going to be very difficult for those with less power to feel responsible for the decisions, or in fact to offer their own contributions. There are ways to deal with this, but the power difference will need to be sorted out before the team can commit to practice collective ownership.

Conclusion

I may have an atypical view of collective ownership, but to me it is more than just letting everyone contribute ideas to the design. To me it actually involves a fairly big shift in how we normally think and work in teams; from individuals all making their own contributions to a result, to a highly cohesive unit whose successes and failures are attributed to the entire entity, not to any individual. This can be tough to do as it involves everyone putting their egos aside, but I believe there is a lot of benefit in this ideal. I hope this has given you something to think about and potentially take back to your own team, even it is something as simple as saying "we" the next time you were going to say "you".