`
| |
 |
 |
| Recent Thoughts
| Tags
|
|
|
|
Tuesday, November 1st, 2011
Every single line of code must be unit tested!
This sound advice rather seems quite extreme to me. IMHO a skilled programmer pragmatically decides when to invest in unit testing.
After practicing (automated) unit testing for over a decade, I’m a strong believer and proponent of automated unit testing. My take on why developers should care about Unit Testing and TDD.
However over the years I’ve realized that automated unit tests do have four, very important, costs associated with them:
- Cost of writing the unit tests in the first place
- Cost of running the unit tests regularly to get feedback
- Cost of maintaining and updating the unit tests as and when required
- Cost of understanding other’s unit tests
One also starts to recognize some other subtle costs associated with unit testing:
- Illusion of safety: While unit tests gives you a great safety net, at times, it can also create an illusion of safety leading to developers too heavily relying on just unit tests (possibly doing more harm than good.)
- Opportunity cost: If I did not invest in this test, what else could I have done in that time? Flip side of this argument is the opportunity cost of repetitive manually testing or even worse not testing at all.
- Getting in the way: While unit tests help you drive your design, at times, they do get in the way of refactoring. Many times, I’ve refrained from refactoring the code because I get intimidated by the sheer effort of refactor/rewrite a large number of my tests as well. (I’ve learned many patterns to reduce this pain over the years, but the pain still exists.)
- Obscures a simpler design: Many times, I find myself so engrossed in my tests and the design it leads to, that I become ignorant to a better, more simpler design. Also sometimes half-way through, even if I realize that there might be an alternative design, because I’ve already invested in a solution (plus all its tests), its harder to throw away the code. In retrospect this always seems like a bad choice.
If we consider all these factors, would you agree with me that:
Automated unit testing is extremely important, but each developer has to make a conscious, pragmatic decision when to invest in unit testing.
Its easy to say always write unit tests, but it takes years of first-hand experience to judge where to draw the line.
Posted in Agile, Design, Learning, Programming, Testing | 4 Comments »
Tuesday, November 1st, 2011
Why should developers care of automated unit tests?
- Keeps you out of the (time hungry) debugger!
- Reduces bugs in new features and in existing features
- Reduces the cost of change
- Improves design
- Encourages refactoring
- Builds a safety net to defend against other programmers
- Is fun
- Forces you to slow down and think
- Speeds up development by eliminating waste
- Reduces fear
And how TDD takes it to the next level?
- Improves productivity by
- minimizing time spent debugging
- reduces the need for manual (monkey) checking by developers and tester
- helping developers to maintain focus
- reduce wastage: hand overs
- Improves communication
- Creating living, up-to-date specification
- Communicate design decisions
- Learning: listen to your code
- Baby steps: slow down and think
- Improves confidence
- Testable code by design + safety net
- Loosely-coupled design
- Refactoring
Posted in Agile, Design, Programming, Testing | No Comments »
Wednesday, July 6th, 2011
Following is a stripped down version of the actual code.
Start with a simple Test:
private static void ContinueMethod(object sender, EventArgs arg)
{
((Eventful)sender).ContinueExecutionFor("ContinueMethod");
}
[Test]
public void EventHandlerCanRequestFurtherCodeExecution()
{
var eventful = new Eventful();
eventful.ContinuationHandler += ContinueMethod;
eventful.Execute();
Assert.AreEqual("ContinueMethod wants to execute more logic", eventful.State);
}
and then wrote the production code:
public class Eventful
{
public string State;
public event EventHandler<EventArgs> ContinuationHandler;
public void Execute()
{
// logic to get ready
var args = new EventArgs();
//stuff args with some data
ContinuationHandler(this, args);
}
public void ContinueExecutionFor(string delegateName)
{
State = delegateName + " wants to execute more logic";
// some logic
}
}
The wrote the next Test:
private static void StopMethod(object sender, EventArgs arg)
{
// no call back
}
[Test]
public void EventHandlerCanStopFurtherCodeExecution()
{
eventful.ContinuationHandler += StopMethod;
eventful.Execute();
Assert.IsNull(eventful.State);
}
and this went Green.
Then I wondered what happened if there were no registered event handlers. So I wrote this test.
[Test]
public void NoOneIsInterestedInThisEvent()
{
eventful.Execute();
Assert.IsNull(eventful.State);
}
This resulted in:
System.NullReferenceException : Object reference not set to an instance of an object.
at Eventful.Execute() in Eventful.cs: line 17
at EventTest.NoOneIsInterestedInThisEvent() in EventTest.cs: line 46
Then I updated the Execute() method in Eventful class:
public void Execute()
{
// logic to get ready
if (ContinuationHandler != null)
{
var args = new EventArgs();
//stuff args with some data
ContinuationHandler(this, args);
}
}
This made all the 3 tests go Green!
Posted in Agile, Programming, Testing | No Comments »
Sunday, May 15th, 2011
Many people will argue that there is more badly written code than good code. And its important to write comments to avoid these situations. Therefore we should encourage (force) people to write comments.
IMHO they are absolutely right that today many project suffer from poorly written code without any (good) comments. However every team I know, that suffers from this problem, has always been told (forced) to write comments. In spite of the emphasis on writing comments it has not really helped them.
I usually ask:
By asking developers to write comments are we really addressing the root of the problem?
.i.e. developers don’t invest quality time to write self-documenting code; code that clearly communicates its intent and does not require the deodorant of comments.
May be its time to try something different?
I have seen this myself many times, when we emphasize & educate the team on how to write clean code and ask them to stop wasting time writing comments, the code starts to communicate lot better. Its lot more maintainable. Also we have found that writing automated tests is a great way to document your intent as well.
This is how I would explain the concept Comments Smell to a team:
Writing comments that explain “how” or “what” the code does, what it does, is evil IMHO. Comments (esp. about what and how) is a clear failure to express the intent in code. Comment is a deodorant to hide that failure (smell).
- If developers don’t invest time to write clear code, what is the guarantee that they will write clear comments?
- Is doing a mediocre job at both (comments and code) better than doing a great job at just Code?
- Will it actually be more productive to do both or just one?
Remember the biggest problem with comments it that they fall out-of-sync with code very soon. So its not just about the extra investment to write good comments, but also the investment to maintain them.
One has to think hard to write code that expresses intent rather than write some sloppy code with poor abstractions and get away (washing their hands off) by writing comments. Developers have to take responsibility for writing code that others can easily understand.
Having said that, there are times when “the why” (why we are doing something in the code, a particular way) is not apparent by just looking at the code. So if we don’t find a suitable way to communicate “the why” through code, comment is the fall back option.
Note that comments are a fall back option in “the why” case rather than a default option.
Posted in Agile, Code Smells, Programming, Training | 3 Comments »
Friday, November 26th, 2010
I hear many people claim Agile is just common sense. When I hear that, I feel, these guys are way smarter than me or they don’t really understand Agile or they are plain lying.
When I first read about test-first programming, I fell off the chair laughing, I thought it was some kind of a joke. “How the heck can I write automated tests, even without knowing what my code would look like”. You think TDD is common sense?
From traditional methods, when I first moved to monthly iterations/sprints, we were struggling to finish what we signed up for in a month. Its but natural to consider extending the time. Also you realize half day of planning is not sufficient, there are lot of changes that come mid-sprint. The logical way to address this problem is to extend the iteration/sprint duration, add more people and to spend more time planning to make sure you’ve considered all scenarios. But to nobody’s surprise but your’s spending more time does not help (in fact makes things worse). In the moments of desperation, you propose to reduce the sprint duration to half, may be even 1/4. Surprisingly this works way better. Logical right?
And what did you think of Pair Programming? Its obvious right, that 2 developers working together on the same machine will produce better quality software faster?
What about continuous integration? Integrating once a week/month is such a nightmare, that you want us to go through that many times a day? But of course its common sense that it would be better.
How about showing working software demos weekly/monthly somehow magically improving collaboration and trust. Intuitive? And also shipping small increments of software frequently to avoid rework and get fast feedback?
One after another we can list each practice (esp.the most powerful ones) and you’ll see why Agile is counter-intuitive (at least to me in early 2000 when I stumbled upon it).
Posted in Agile | 1 Comment »
Thursday, June 24th, 2010
I regularly practice Test Driven Development. I truly believe in its benefits and also have been able to influence a huge number of develops to practice it.
However, there are situations in which I ask myself questions like:
- Is it important to automate this particular check (test) ?
- Will it be worth the effort/investment or is it YAGNI?
- What is the possibility of this particular scenario breaking (risk)?
- And so on…
Yesterday I was faced with a similar situation where I decided to skip the automated test.
Context: I was working on a website where users can use their credit card while shopping online. Basically the website had a simple text input box to accept the credit card number. It turns out that most browsers (except Safari) caches the input data and stores it in plain text somewhere on the computer.
So we wanted to turn off the auto-complete and caching feature on this specific input field. There is a very easy way to do this. Just need to set autocomplete=”off” in the input tag. For example:
<input type=”TEXT” name=”creditcard” autocomplete=”off” />
Its an easy fix and quite widely used. So that’s great. But how do I write an automated test for this?
If we think a little hard, there are ways to write automated test. But then you ask yourself is it worth it?
This site had lived without this feature for so long, so I did not think it was that crucial to its users. Even if this feature stops works, it won’t bring the site down. (They certainly had a good battery of automated tests which tests the core functionality if the product.) So I choose to skip the automated test. I manually tested it with different browsers made sure it was working as expected.
If this comes back and bites me, I’ll certainly invest in some form of safety net, but for now, time to hack some more code.
What would you choose to do?
Posted in Agile, Testing | 8 Comments »
Friday, June 11th, 2010
Usually when I’m wrapping up my 3 day TDD Workshop, I make it clear to the participants that they will have to deliberately practice, every single day, for a few years, to get better at TDD. In addition to practicing on their own, on pet projects and on production code, I also suggest they take 2 hrs every week on a fixed day of the week, as a whole team, to practice Test-Driving (TDD) the same problem as a team. During these sessions, I strongly recommend people practice Pair programming also.
Logistics: Before the meeting, one of the team member sends out the problem to everyone. On practice day, the whole team gathers in a conference room/team area, picks a pair, sets aside 90 mins to TDD the problem. After 90 mins, few pairs do a quick code walk-thru and explain their solution with important decisions they made during the session. Followed by an open discussion. I also recommend everyone checks-in their code in some common repository, so it can be used for reference by others.
Sample Problems: Next big question is, what problems do we use for Test Driving?
Usually I recommend starting with simple programs like:
Once you’ve done enough of simple programs, then I would suggest you take some large design problems from DesignFest and try TDD on them. The beauty of these problems is, they are quite big, can take up-to a week to finish it completely. Now we are talking real world, where
- We have limited time to solve/program large complex problems which needs to be simplified.
- Try to find a relevant System Metaphor that can help you visualize the design
- Do a quick and dirty, low-fi Interaction Design to understand how the user will use this
- Identify and prioritize the crux of the problem, figure out what is the most important, what will give us fastest feedback
- Further thin-slice the identified piece of functionality and
- Then try TDDing it.
This will truly help you get better at:
Deliberately practicing this way for a few years, even though you are practicing TDD on your production project, will really help you appreciate the depth and benefit of this approach to development.
Posted in Agile, Coaching, Design, Programming | No Comments »
Friday, May 14th, 2010
Just because you know the syntax of a programming language, does not mean you know programming
Just because a toddler can make some sounds, does not mean she can speak
Similarly, just because you write tests before you write code, does not mean you know TDD.
TDD is a lot more than test-first. IMHO, following concepts let’s you truly experience TDD:
- Evolutionary Design,
- Acceptance Criteria,
- Simple Design,
- System Metaphor,
- Thin Slicing,
- Walking Skeleton/Tracer Bullet and
- Interaction Design
How long does it take a dev to be well-versed with TDD?
Depends on the dev, but atleast a couple of years of deliberate practice on projects
What can we do to become TDD Practitioners?
Start with deliberate practice in safe env. Then gradually start on your project.
Posted in Agile, Programming | 1 Comment »
Thursday, April 1st, 2010
Based on an open space discussion at GOOSgaggle, Rachel Davies wrote this interest post on Is Working Outside-In Always Better? (in the context of TDD)
This is one of my favorite topic. So I’ll freely express my thoughts here:
When I was doing my little “Avatars of TDD” experiment, I found TDD practitioners could take the same problem and approach it using either the Outside-In or the Inside-Out approach quite nicely. Obviously each person had their preferences. Also the tool used, the choice of programming language and paradigm influenced their technique quite a bit. I could see trade-offs in both scenarios. So I don’t believe in ONE best way.
Personally I don’t choose just one style. Depending on various criteria (listed below) I choose which approach I’m going to start with. I & most programmers I know go back and forth between Outside-In and Inside-out.
I tend to make the decision based on the following criteria (just a list of things that comes to my mind right now, I’m sure there are many more criteria):
- Familiarity with the problem – How clear the problem & its solution is.
- Stage of the feature/Project
- Prior Knowledge/Experience with the technology stack and implementation details
- If its completely unknown, one might spike it out or build a throw-away prototype. Having the prototype in front of you, can influence which way you start.
- Whether your goal is to go breath first or depth first.
- Whether your goal is to get low hanging fruits first (easy first) or core first (highest risky items first)
- Whether you are driving the design or validating the design (test driven or test first).
Inside-Out and Outside-In also applies at a product level. Which massively influences our development style. For Ex: if the original idea about a feature/product is about a core feature that needs to be built. We could start building just the core idea, getting feedback and then slowly flush out the rest of the system as we build inside out.
It appears to me that, this topics needs a lot of context. Any discussion outside that context might dumb down the importance of this topic.
Posted in Agile, Design, Programming | 1 Comment »
|