Just Do It: A Quick Intro to Agile’s Technical Practices
A lot of people think Agile is about working faster, but that really isn’t right. It would be more accurate – and perhaps alleviate many of the arguments against agile practices – if we thought of agile as being about working slower because we’re being more deliberate. BUT, at the same time getting rid of all the crap that doesn’t add value, so that we do, indeed, end up delivering more functionality in a shorter period of time.
I like to think of Agile as the Just Do It methodology. In software development, we’re really great at this thing called “yak shaving.” If you’re not familiar with the term then take a moment to read: So There I Am, Shaving a Yak…. Go ahead, I’ll wait. It’s really funny, I promise.
“So there I was at the zoo, shaving a yak, all so I could take a few pictures of my dogs at the park.” – Bill Gaiennie
A really huge part of yak shaving – at least for me – is trying to figure everything out so that I can make sure I’m going about things the right way. Oh boy, I can plan and research and do proof of concepts like nobody’s business. But at the end of the day, I’ve got a bunch of “stuff” with no actual working software for the app I’m supposed to be building.
Agile instead says “You’re never going to know everything about the app until it’s already been written. Cope.” and instead gives us tools to continue to move forward by focusing on what we do know. And then, a funny thing happens. The more of the application that we build, the more we learn. And so, we’re able to move forward, not by focusing our time on what we don’t know, but rather by focusing on what we do know and building actual value out of it.
Raise your hand if you’ve ever spent hours and hours around conference tables debating the minute details of how a feature should work in an application that hasn’t even been built yet. Now keep it raised if this is something you’d prefer to do over, say, poking yourself in the eye with a sharp stick. Yeah, I thought so.
It’s all but impossible to design the details for anything when we don’t have visuals – or some kind of shared understanding – to guide us by, and even more so in software, which not only has form and function but also interactive behaviors. So, let’s give it up and just move forward with what we do know.
User stories are reminders of the features we think we’d like to implement, but for which we’re deferring decisions on their details until we’re actually at a point where we have enough information to provide them. They’re purposefully short and informal, “As a [type of user] I’d like to X so that Y” and they’re scribbled on 3×5 cards that can be easily viewed and priority ordered by customers or product owners. And since they’re low ceremony, we can all intuitively understand that it’s no problem for the customer to add, update, remove, or reorder them at any time up until the point we’re actually working on them in an iteration because, hey, we’re agile like that.
Yes, we’ll eventually need to understand their details – but not until we’re ready to work on them. Which brings us to…
This is a hard one because intuitively we feel that if we could know, up front, every last aspect of how the software should look and behave, that we can come up with an optimal design. We think that if we only build one feature at a time, without considering upcoming features, that we’ll end up with a band aided, glued together, duct taped nightmare that will fall over before we ever make it to the first release.
And, to be fair, if we add every new feature without any consideration for the overall design then um, yeah – I’ve worked on those systems before. I believe they’re called big balls of mud.
However, I’ve also worked on systems where the more functionality we build out, the more we learn about what type of design makes sense. In fact, I’d have to say this is actually true for every system I’ve ever worked on. Just like our user stories, the more of the application that gets built, the more we understand about what works and doesn’t work, and the better equipped we are to make good decisions.
So I’d actually argue that it’s a misnomer that we can come up with the optimal design by knowing all the requirements up front. That, in fact, we can only come up with the optimal design by implementing functionality and then using the knowledge gained to evolve our design with each new feature.
This is not “no design”, this is emergent design. It means that with each new feature that we add, we determine what the optimal design should be for our current functionality plus this new feature and then we …
Refactoring is not something we spend days, weeks, or, god forbid, months (!) on because we made a mess out of our code. Refactoring is the act of continuous design while we code. It is something we do continuously, several times every day, and ideally according to guiding design principles, such as the SOLID Principles, to keep our code clean.
If you’ve worked on a legacy system, the mere thought of such a thing will elicit screams reminiscent of bad horror movies because you can just hear the sound of code breaking with each new refactor, right?
This is where we get to the point that the agile technical practices are really meant to work together and so yes, refactoring is going to be pretty scary unless you’ve built yourself a safety-net via…
TDD is the ultimate Just Do It for how we implement each of our user stories.
Ideally, we are following Acceptance Test Driven Development so that we have objective (executable!) acceptance criteria to know exactly what is expected of this user story. And, we’ve broken the user story down into individual tasks that can each be done in about a day. So, we’re hard core focused on a single task that we can get our brain wrapped around and know precisely what it needs to do.
Now, all we need to figure out is how to design and code it in. But rather than spinning our wheels figuring out the optimal way to handle the entire task, TDD provides us a structured way to walk through designing and developing it – one step at a time, always keeping the focus on exactly what it is that our code needs to accomplish and what we want our design (e.g., the public interface for our classes) to look like to access this functionality.
Okay, to bill the customer, we’re going to need a Customer class and it should provide us with a method to obtain it’s Balance. Great, how should that method look? Let’s solidify that in a test, and then write the code to make it pass.
Even so, this can sometimes be easier said then done. Particularly if we’re working with a new technology or in a new area of the application that we haven’t spent much time before. And so, here is where we can get even more focused help on moving forward with…
You don’t have to do this for every line of code written! But even if you’re an introverted programmer like me, you have to admit that pairing is a great way to share knowledge, get people up to speed on new technologies or unfamiliar parts of the system, and to just get a second set of eyes for working through a particularly tough problem.
It’s also a great way to keep things moving forward. The pair can bounce ideas off one another, and often when one is stumped, the other has an idea to move it forward.
Of course, at the end of the day, the most important thing is that the entire team is moving forward in the same direction – not one person adding features that break another person’s features (that would never happen, right?).
Our CI box makes sure the team is moving forward together, not working against one another, by automatically running the automated tests that have been built up through ATDD and TDD every time someone checks in code.
If someone’s check in does happen to break the build or the tests, the CI box has the team’s back so the problem is caught immediately and the offender can often quickly resolve the issue while it’s still fresh on their mind.
Do these practices add more time? Sure, but the team is also delivering faster because they’ve cut out the crap that doesn’t add value. No code built that isn’t specifically for a user story that’s been chosen as a top customer priority. No discussions wasted on a requirement that never ends up getting implemented. And the code is tested and integrated as we go so by the end of the iteration, it’s already tested and integrated! We can actually demo it to the customer to get their feedback and then everyone learns so we now know a little bit more and so can implement new features in the next iteration.
Mike Cohn also has some good data in Succeeding with Agile that you might find surprising:
» TDD takes only 15% longer than not doing TDD and leads to fewer defects (and so less debugging/fixing time)
» Pair Programming takes more man hours, but shorter project duration (getting that feature out the door faster) as well as fewer defects.
So what are you waiting for? Just do it!