Pitfalls of responsive development practices
None of the teams I have worked with to date has fully adhered to a formal Agile methodology, but most of them have taken a highly iterative and collaborative approach to the development process. Although “agile” is a good word to describe such an approach, it seems better to avoid its use here since formal Agile methods are not particularly what I have in view. The word “responsive” seems to be a suitable alternative, in that we’re looking at approaches that are responsive to the customer.
While I firmly believe that a responsive approach is best for most types of software, I have also come to learn that it presents a number of hazards. Unfortunately, even though these hazards have been documented numerous times, I have learned to truly appreciate them the hard way: by seeing them go from potential dangers to real fiascoes. It seems worthwhile to put these lessons in writing; the exercise will help me to remember what I have learned, and perhaps it will also help someone else learn from my mistakes. And, if you respond by sharing your own insights, then I will learn even more.
So, here goes…
Bugs
Change is at the heart of any responsive approach. You build a piece of software, let the customer evaluate it, and then change it in response to the customer’s feedback - and you repeat this process over and over again. But it is axiomatic that whenever you change a line of code, you risk introducing new bugs. So it is almost inevitable that your collaboration with the customer will generate new bugs.
The short development cycle is also at the heart of any responsive approach, because you need to move quickly in order to get something into the customers’ hands so that they can provide the feedback you need to continue development. Any time you are in a hurry, you increase your likelihood of making mistakes, whether you’re developing software or making an omelet. So, again, we are almost guaranteed to introduce bugs with this approach.
The need for speed also limits the time available for testing, which reduces the likelihood that our QA team will catch the newly introduced bugs before the customer sees the software. As a result, we not only increase our chances of introducing bugs, we also increase our chances of delivering the bugs to the customer.
So how do we mitigate this? I think that the best solution has three parts: one is technical, and the other two managerial.
The technical part is to write code that is flexible. Keep your classes small, well encapsulated, and loosely coupled. This will greatly enhance your ability to make changes without creating new bugs. (More on this in a later section.) This is also difficult to do under time constraints, because it is almost always faster to write brittle code. But we need to remember that the shortcuts we take now will come back to haunt us later.
The first managerial part is to give your developers ownership of application components. When an engineer feels like he or she owns a piece of functionality, then pride of ownership has an opportunity to take hold. The engineer cares about the component, and feels more responsible for it, and therefore takes more care to see that it works properly. Also, the engineers become experts on their own components, and this brings real benefits: They are less likely to deliver something that does not function properly, because they know how the components are supposed to work. And, because they know the code, they are more likely to know how to make changes in it quickly without breaking something.
The other managerial part is to regularly perform code reviews. This provides opportunity to monitor and enforce the technical part of the solution, and also keeps the first managerial part from becoming a problem. When an engineer owns a piece of functionality, and knows that no one else is going to be looking at the code, there is a temptation to be less careful about things like coding standards and naming conventions. The code is likely to reflect more of the style of the individual developer and less of the team’s accepted norms, and can end up being almost impossible for anyone but the original developer to understand. Regular code reviews can forestall this, and ensure that the code is maintainable and extensible.
Scope Creep
Very often, when an end user is given a piece of software to evaluate, the response is something like this: “This is good, but it would be really great if it could also do X!” Such a response is entirely natural. Whenever we get a new gadget, our imaginations get sparked, and we begin to think of really cool things that the gadget almost does but not quite, and we wonder how hard it would be to make it do those really cool things.
When we as developers get this kind of feedback from our customers, our instinctive reaction may be to say, “Sure! We can make it do X!” And that instinct is good: it shows that we really want to build software that will help our customers to the greatest extent possible. However, like all of our instincts, it needs to be ruled by our reason.
In order to properly channel our “satisfy-the-customer” instinct, we need to scrutinize customer feedback and carefully evaluate anything that amounts to a request for additional functionality. If we are 100% certain that we can implement it easily, and that doing so will not affect our schedule, then we should do it without hesitation. Otherwise, we need to determine the impact, communicate the cost to the customers, and let them decide whether they want to pay for it or not. And by “pay for it” I don’t mean simply money, but time as well. Even if we are willing to make the change without charging an additional penny, the customers need to know how much longer they will need to wait to get the finished software in their hands. Then they can decide whether the additional functionality is worth the cost. They know their business better than we do, and they know what the change is worth to them, and we need to respect that. It is essential for us as developers to realize that we are not doing our customers any favor if we keep them waiting for weeks or months beyond deadline while we code additional features that they can live without.
Expectation Management
It is easy to take for granted that the people we talk to on a regular basis understand what we are about, where we are coming from, and where we are going. However, common experience tells us that this is not necessarily the case: On the contrary, if we we want to be certain that others understand a particular fact, then we must explicitly communicate that fact to them. We can’t assume that they picked it up from our general conversation.
This is particularly important to remember in the context of responsive software development. Because our customers are also collaborators, and we tend to develop a comfortable working relationship with them, we can easily take for granted that they understand our perspective on the process. But when we allow ourselves to fall into that pattern, we risk not only the success of the current project, but our long-term relationship with the customer as well.
I have seen solid working relationships between customers and developers destroyed by the developers’ failure to properly communicate the impact of changes. On the other hand, I have seen working relationships that survived very difficult projects largely because the developers communicated the impact of changes frequently and clearly, and in so doing they effectively managed the customers’ expectations.
So, it is vital that all significant facts be clearly and explicitly communicated to the customers. Did you decide to implement some new functionality that they requested on the basis that you could do it easily without impacting the schedule? Make sure they know what you did and the reason you did it. This way they will see that you are really working for them, and at the same time it will help them to understand why some change requests cost extra while others do not. Did you agree to make a change that will impact the schedule? Make sure the customers know what that impact will be, so that they know how much of a delay to expect. They may not always like what you have to say, but they will learn to trust you.
Developing for the Customer
This is one of the more paradoxical dangers of responsive development practices. After all, the whole point of taking such an approach to development is to ensure that software not only meets the customer’s needs but actually streamlines the end users’ work flow and enables them to focus on their business rather than on operating their software. So what could be wrong with developing with the customer in mind?
Here is the danger: when you code for a specific customer, and you have taken the time to know your customer’s business needs and work flows, it is easy to code yourself into a corner by thinking such things as, “I know they always do X in this particular way.” Because you know how the customer does things, you unintentionally design your classes with built-in assumptions about how things will always be done, and you end up writing brittle code.
Keep in mind that you may end up with more customers who are interested in the application you’re building. If that happens, each new customer will need some changes. But even if you are 100% certain that you will only have one customer, remember: in the real world it is not unusual for customers to make changes to their work flows or business rules. Whether you have one customer or 100, some features will need to be omitted, others added, and some will need modification.
So, even if you are building an application that will only ever be used by one customer, guard against the complacent attitude that you know how the application will be used. Design and write the code as though you intend to market it to a broad range of organizations, and you have no idea how they will want to use your application. Bake flexibility, scalability, and extensibility into your architecture. Code to interfaces rather than concrete classes. Design and build loosely-coupled components. Maintain clean separation of concerns. Layout your UI’s in such a way that controls can be rearranged, added, and removed easily.
Parting Thoughts
We all live in the real world, and seldom have the opportunity to work in anything resembling ideal conditions. We deal with absurd deadlines. We work on teams that are ridiculously understaffed. Sometimes we feel like we need to just push out the code as fast as we can, and at the end of the day our only concern is that the software actually works. We’re just doing the best we can.
But when we have time to breathe and reflect, we should make the most of it. Maybe we’ll actually come up with the ideas and the resolve that will prepare us for the next time we’re under the gun.





Reader Comments