This chapter examines how to better solve programming problems. The aim is to get tasks to a level where we can have some functionality accomplished at the end of every day. Then we do not have to be so concerned with the bigger-picture stuff while we solve today’s problems.
This chapter, like Chapter 1, is not specific to the .NET Framework. You can use these ideas in other development environments. We will be using the lessons learned from this chapter later on in this book. Be sure that you understand how to break down tasks and make time estimates before you jump ahead.
When mentoring development teams, I often encounter developers who do not (or cannot) break down a task into really small pieces of work that are achievable in a matter of a few hours or minutes. This is a skill that you need to learn. This chapter examines why it is important to have these small tasks, and shows how to break down some complex problems into simple easy-to-solve units of work. This chapter discusses XP practices that help us accomplish this task breakdown.
When developing a piece of software, you are often dealing with many issues at the same time, some of which might detract your focus from the particular problem you are trying to solve. Issues you are dealing with will include the following:
Adhering to the design of the system
Making sure your new code doesn’t break any existing functionality
Ensuring you are following the coding conventions
Worrying how this solution will impact future tasks that need to be completed
Wouldn’t it be good if you could forget about those other issues? Then you could just code a solution today to the problem you have at hand. Problems are hardly ever so small and focused that you can actually accomplish them today, or even this week.
That is what we are going to attempt to achieve. First, we will explore what makes a good solution. Second, we will work through an exercise that demonstrates how we can carry out focused small tasks that lead us towards the completed solution.
A genius is a person who can take a complex problem and find a very simple solution that solves it. This solution is usually fairly trivial to implement after you know what it is. Most of us take the easy option, however, and create complex solutions to solve our complex problems. We do this for a number of reasons; the two main ones are as follows:
We take on too much at one time.
We look at how a similar complex problem has been solved before and try to copy that solution.
Our egos don’t help in this matter. We want to show off how smart we are at implementing some complicated solution. We want to justify that we should be paid more and promoted. We don’t feel comfortable going to our boss and saying, “That problem was solved in five lines of code, but it took me the whole of the past three days to write those five lines.”
The trouble with designing these big, complex solutions is that we often then get stuck when trying to actually implement them. They are just too hard and have too many points of failure. These solutions end up becoming the bane of our existence. We have to maintain them and fix bugs in them. Sure, we can be good citizens and use design patterns and well-documented architectures. Ultimately, however, we end up, time and time again, juggling big issues while trying to get a new piece of functionality into the system.
Among the XP practices are some techniques that will help us reduce the complexity of the problem.
Ideally, we should find some way that we can all be geniuses. If we are all geniuses, we can always create simple solutions to all of our problems. Something we all know is that it is easy to create simple solutions to solve simple problems. So to become a genius, all we need to do is break down all of our problems into lots of smaller problems that are easy to solve.
Any problem that I estimate to take longer than four hours to solve is too big for me to feel comfortable with. I want to accomplish at least one thing in a day; if I accomplish more than that, I feel even better. This is a personal decision, but most people I have worked with aim for four hours or less. I have never worked with anyone[1] who was comfortable with tasks that lasted more than six hours. If I get a task that I estimate will take longer than my maximum four-hour period, I break it down into several smaller tasks. If any of those tasks will take longer than four hours, I break those down again. Something that I have found interesting is that the most effective developers I know break down the majority of their tasks so that they require less than an hour to complete.
Let’s see how this works, beginning with a trivial example before I lead you through a more complex problem breakdown.
Suppose the customer has asked us to develop a piece of software that emulates a calculator on the desktop. So this is our problem: develop a .NET Framework calculator. Easy. So how long will the development take? Do you know immediately? I don’t, but I bet it will take longer than four hours, so I need to break down the problem. Here’s a list of smaller problems:
Add function—. Add two numbers together
Subtract function—. Subtract one number from another
Divide function—. Divide one number by another
Multiply function—. Multiply two numbers together
Can I give time estimates for each of these functions? I feel confident that I can, and I estimate between one and two hours for each function. Some people might ask, “Why so much?” After all, they know that I am an experienced developer and might think that I should be able to put a simple calculator together pretty quickly. I am estimating that this will take me up to a day to complete based on my experience. I am breaking the problem down into even smaller steps, and I will go through that process with you now for the add function.
Task | Time to Complete |
---|---|
Test for adding zeros | 15 minutes |
Test for adding negative numbers | 15 minutes |
Test for adding minimum numbers and maximum numbers(forcing overflows) | 15 minutes |
Test for adding positive numbers | 15 minutes |
User interface | 15 minutes |
Check code into source control and integrate with any existing solution | 5 minutes |
Total | 1 hour 20 minutes |
Notice that I emphasize writing tests. In the next chapter, you will learn why and how to write tests before the code. For now, it is important to understand that it gives me more focus on developing only what is required and nothing extra. These tests define the behavior expected of the object that will be developed.
Also notice that I am including the time it takes to write these tests, to develop the user interface, and integrate the code with a source control system. All these extra things take time that is often not accounted for by less-experienced developers and project managers. These extra things are often the reason so many software projects run late; developers too often fail to account for the “other stuff” that we need to do to write high-quality code.
With less-trivial problems, you will often find yourself asking some tricky questions, and this is where having contact with the customer becomes important. It is hard to break tasks down without being able to get answers to questions you have. Consider the preceding example. I have made an assumption that the calculator will deal with negative numbers. What if negative numbers are not permitted or required by the system? Having the customer present while doing this task breakdown will make this very apparent. The conversation in our eXtreme .NET team might go something like this:
Remember one of the practices discussed in Chapter 1 was the whole team. Here is an example where having the customer as part of the team can make a difference. If you cannot get a customer to be present during a task breakdown session, try to get him or her on the phone or instant messenger. Failing that, try your manger or other developers. At least they may spot some mistakes or incorrect assumptions you have made before you actually commit them to code. You should e-mail your customer the results from each task breakdown session so that they can review them and change their minds or reset the direction.
We return to this scenario later on in this book to write code for some of these tasks.
Hopefully you have a good idea of what we’re aiming for now, so let’s try to tackle a slightly more complex problem. This problem may still seem trivial in comparison to many real-world problems you will encounter, but we have to start somewhere, and this should give you at least introduce you to the concept of breaking down customer stories into tasks.
The first thing to happen is that the customer will provide the development team with a story. A story is a simple description of a piece of functionality that the system needs to perform. In a full XP environment, the team will play the planning game. This involves the customer writing a number of stories on cards (usually index cards). Then the development team will place rough time estimates on each story. The customer then decides which stories to do first. The planning game provides a long-term view of how the project could pan out eventually, but also includes short-term goals for the next few weeks. By repeating the planning game every few weeks, the accuracy of the estimates should get better and you enable the customer to choose the direction of the project on a smaller scale. Figure 3-1 shows a sample story card.
A story can be considered similar (and are often compared) to a UML Use Case. The story should not explain all the details of the functionality. A story provides a rough idea of the scope. Stories are promises to hold conversations between the developers and the customer. This conversation occurs when the time comes to begin implementing the story. The conversation enables the developers to explore exactly what tasks will have to be carried out to satisfy the customer that the functionality described in the story is finished.
The best way to start this is to begin a conversation with your customer. Let’s see how our team does it:
Some of this conversation probably sounds familiar. It is not uncommon for customers (managers) to be short of time and want answers on the spot. As developers, we need to respect that they have other pressures and do what we can to help them. It is important not to let their stress get to us and force us to make on-the-spot decisions or provide time estimates based on nothing more than numbers plucked out of the air. Notice how Eddie, who has more experience, steers the conversation. Eddie is guiding both Pete and Chris through the process in a way that gives them the best chance of succeeding.
From the preceding conversation, Eddie and Pete can draw the following story cards:
Allow the user to select a time zone.
Allow the user to associate a custom label with the time zone selected.
Draw a clock for the time zone and a label for it.
From these stories, could you give reasonable time estimates? For the first two, you may be able to get reasonably close (apart from one issue). The third one is a little trickier because the clock has to show the correct time and be updated as the time changes. Let’s see what Eddie and Pete come up with when they break these stories down.
Story 1: Allow User to Select a Time Zone | |
---|---|
Task | Estimated Time |
Get a list of time zones from the operating system | ? |
Test to check selected time zone is valid | 15 minutes |
Test to validate selected time zone is stored in memory | 15 minutes |
Test to validate correct behavior when invalid time zone selected | 15 minutes |
User interface to allow user to select a time zone from the list | 10 minutes |
Check code into source control | 5 minutes |
Eddie has put a question mark next to the first task because neither he nor Pete are sure what is involved in getting all the time zones from the operating system. They know the time zones must be there because when they set the Windows clock they can select from a list of available time zones. To find out where this list is stored, they need to carry out some investigation and experimentation.
In XP terminology, this is called doing a spike or spiking. This spike will be another task. Because they don’t know how long the spike will take, they set an upper limit to the amount of time spent spiking before providing feedback to the customer. Eddie and Pete now have a list of tasks that looks like this:
Task | Estimated Time |
---|---|
Spike to discover how OS stores time zone information | 4 hours |
Get a list of time zones from the operating system | ? (based on outcome of spike) |
Test to check selected time zone is valid | 10 minutes |
Test to validate selected time zone is stored in memory | 10 minutes |
Test to test behavior when invalid time zone selected | 10 minutes |
User interface to allow user to select a time zone from the list | 10 minutes |
Check code into source control | 5 minutes |
They can now break down the next story.
Story 2: Allow User to Associate a Custom Label with the Time Zone Selected | |
---|---|
Task | Estimated Time |
Test to validate correct behavior when label is blank | 10 minutes |
Test to check label is stored and associated with time zone | 10 minutes |
Test to check label with non text characters is valid | 10 minutes |
User Interface to allow user to enter label for selected time zone | 15 minutes |
Check code into source control and integrate with existing code | 5 minutes |
Finally, they can tackle the third story: Draw a clock for the time zone and a label for it. Eddie thinks this story is too big, so he proposes they break it down into smaller stories:
3.1 Draw clock face
3.2 Draw label next to clock face
3.3 Draw clock hands
3.4 Update clock hands to reflect current time in selected time zone
3.5 As time changes, redraw clock hands to reflect current time in selected time zone
From these five stories, they can create a set of tasks for which it should be reasonably easy to provide time estimates. The tasks for each story are estimated as follows.
Story 3.1: Draw Clock Face | |
---|---|
Task | Estimated Time |
Code to draw circle | 15 minutes |
Code to draw 12 marks to indicate time intervals | 15 minutes |
Check code into source control and integrate with existing code | 5 minutes |
Story 3.2: Draw Label Next to Clock Face | |
---|---|
Task | Estimated Time |
Code to calculate offset from clock face to draw label | 15 minutes |
Code to draw label | 10 minutes |
Check code into source control and integrate with existing code | 5 minutes |
Story 3.3: Draw Clock Hands | |
---|---|
Task | Estimated Time |
Code to get time | 10 minutes |
Code to draw hour hand | 15 minutes |
Code to draw minute hand | 10 minutes |
Check code into source control and integrate with existing code | 5 minutes |
Story 3.4: Update Clock Hands to Reflect Current Time in Selected Time Zone | |
---|---|
Task | Estimated Time |
Test converting current time when time zone is in summer time savings | 20 minutes |
Test converting current time when time zone is in standard time | 20 minutes |
Code to draw clock hands based on converted time (dependent on story 3.3) | 10 minutes |
Check code into source control and integrate with existing code | 5 minutes |
Story 3.5: As Time Changes, Redraw Clock Hands to Reflect Current Time in Selected Time Zone | |
---|---|
Task | Estimated Time |
Thread function which updates clock hands based on current time (dependant on story 3.4) | 20 minutes |
Check code into source control and integrate with existing code | 5 minutes |
Based on this task breakdown, Eddie and Pete can get back to Chris, their customer, with some confidence in the estimated timeframes. The timeframes are still estimates, but the developers are happier that they have thought about the job and the tasks to complete. They can also explain that the first thing they need to do is spend half a day understanding how time zone information is stored in the operating system. When they know how the time zones are stored, they can use them in the program.
As you can see, the estimated times for each task are small; all of them except the spike are less than 30 minutes. This is a good indicator that they have got their tasks to the correct level of granularity. If you have several tasks that are four or five hours long, you should think harder about how to break them down. For me, the spike task is still cause for concern. After the customer has had time to review the task breakdowns and give the go ahead on the project, I would break down the spike task further. Let’s see how Eddie and Pete go about doing this.
To break down the spike task, Eddie and Pete need to think about the approach to take to find the information they are after. There are some likely candidates to find out how they can access the time zone information:
.NET Framework support
Win32 API
Work out how the date and time Control Panel applet works
COM controls
Windows Registry
Based on the fact they have given themselves 4 hours to come up with some answers, Eddie suggests spending no longer than 45 minutes investigating each area. Because both he and Pete are working on the project, they could each take a different area to investigate. This gives Eddie and Pete a task list for the spiking tasks.
Spiking Tasks | |
---|---|
Task | Estimated Time |
Investigate .NET support for time zones | 45 minutes |
Investigate Win32 support for time zones | 45 minutes |
Work out how the date and time Control Panel applet gets it time zone data | 45 minutes |
Investigate whether there are any COM controls that provide access to time zone data | 45 minutes |
Explore the Registry for time zone data | 45 minutes |
If they come to a dead end before 45 minutes, they can stop and move on to the next area of investigation. Likewise, if they find a mechanism that provides access to the time zone data, they don’t need to continue with any of the other spiking tasks.
Eddie and Pete are now ready to start this project with some very tightly defined tasks and outcomes at the end of each task. This tight definition of tasks enables them to move at a fast and furious pace during the working day.
You now understand some of the reasoning behind breaking down stories into extremely focused tasks. This section contains some conversations between you and your customer. Read these conversations, and then try to work out the stories and break them down into tasks. At the end of the book (Appendix I), I provide some possible solutions to these exercises; however, they are not definitive answers. When carrying out the task breakdown, there is not one right way to do it, but there are certainly some wrong ways. Remember to keep each story adding one piece of functionality and each task doing just one thing. Each exercise should take you no more than an hour to complete.
Although this chapter has not focused on anything that is special to .NET, it has introduced you to a technique you should be able to use whenever you are developing software. From the ideas presented, you have hopefully gained an understanding of why XP is often quoted as being a methodology that requires a large dose of self-discipline. You should also have gained some insight as to the value of working closely with your customers to define exactly what they want.
A valuable input that I have received when running through these task breakdown exercises in the classroom is that developers often jump straight into breaking down the problem with the idea of coding the entire solution themselves. The more experienced developers tend to do a search on the Web for any existing tools or components that do some (or even all) of the work for them. Then they can think about how to break down the rest of the work.
I hope you can see the importance of some of the key values emerging from the content of this chapter, with communication, feedback, simplicity, and respect all being evident through the dialogues presented. Now you have to find the courage to do it yourself at work.
3.145.50.222