Archive for Software Development Process
Build Automation: The Best Thing Since Sliced Bread
Posted by: | CommentsEditor’s Note: This is the second article in a three article series, with a new article posted every few days.
In the last 15 years, software development tools have advanced significantly. More than language or runtime, the modern integrated development environment is an amazing productivity tool. You don’t even have to spend money to get this benefit – check out Eclipse and its ecosystem for a free and powerful tool. Combined with the extraordinary processor power of modern desktops, you can do things today that just weren’t feasible 15 years ago. In many cases, this is a great improvement, but it has come at a cost: When you can compile even a large project and debug it in tens of seconds instead of 30 minutes it tends to take you away from the good Mom and Apple Pie aspects of having a tight build process and not doing development by debugging.
Benefits of a Build System
When you have a common means of performing each build, you get a number of advantages that will pay off for your team.
- Consistency: Without a doubt, the greatest benefit is that each build is consistent and you know that it is consistent. Both pieces are important. You will be able to dismiss with confidence questions about the accuracy of the information that indicates what exact source code was used to make each build, what defects really were fixed in each build, etc. This is particularly powerful because it is most useful when the team is under maximum stress: rapid fire builds under pressure, when there are multiple builds in play at various stages of certification, etc. It’s in these situations that you have to be able to absolutely trust that the records are accurate or you will burn a significant amount of time across your team verifying what was in each build. This is waste effort when you can tolerate it least.
- Knowledge Containment: Each developer doesn’t need to know the details of building the entire system. Usually only one developer needs to know the packaging and release details, numbering scheme, etc. Individual developers only have to know at most what it takes to add their new project to the build process. When a new member joins the team, they can get up and running fast and start contributing without having to take on the whole beast right away. When you come back to the system six months after it shipped and need to make one change, no one needs to remember all of the intricacies of creating a full build.
- Change Management: Whenever a new output file is added or a change needs to be made to how the application is built, the build will need to be updated. By insisting on an automated process you ensure that each change has to be fully addressed before the build can be tested. This will force issues to the surface earlier in the process when the team will tend to be under less stress instead of later when the team is under tighter deadlines.
- Time Savings: Running a build is generally an annoying waste of time. If you take on that a build includes all of the steps we discussed in the first article in this series then even for a simple project it’s going to take a minute, but for a project of real complexity it will tend to be 10 minutes or more. More is actually better in this case because it represents more human actions that are automated into the build. If the build is happening on the developer’s system then the time savings is limited – the developer will generally be idle while the build is running. The time saved in this case is the time for a human to manually perform each step vs. the computer, perhaps 40% of the total time.
Benefits of Centralization
This part is often more controversial, but has become accepted more and more as a best practice. Many have argued that you should automate the build, but make it so each developer can run the build on their system. This was relatively straightforward in the good old days of “make”, but there are several advantages to centralizing builds for modern applications.
The big benefits of centralization are:
- Forced Standardization: We’ve all had the experience of two computers building the same source code and not producing the same binary images. This is generally due to small differences in the software installed on each system that the build is referencing. It probably won’t hurt you, but it might – and the more third party items you reference the higher the odds it will. Instead, by building on the central server you can ensure that if there’s a new version of a common library you know exactly what one is being referenced by the build. You know that you only have to update it in that one place for it to go out, not on each developer’s system.
- No Cheating: Let’s face it, it’s tempting – any individual developer will be tempted in the right circumstances with short cutting a build on their system, perhaps swapping one file into the output directory and just re-running the packaging step to get a new distribution. If it’s on a central system that few if any have direct access to then you know for sure each build came from the full, correct process.
- Major Time Savings: With the build happening on a central system, the developers are free to do whatever they want while it’s running. They can continue to do extended unit testing waiting for the build to complete, or move on to entirely new functionality. The build should be designed to pull its source code immediately or otherwise ensure that it’s protected from changes checked in while it’s running to make this possible.
- Central Objective Metrics: With a central build who’s status is published to everyone, the entire team knows if the system currently builds or doesn’t. It establishes a central point to look at to get a quick understanding of where the team is. After all, your customers don’t care if your personal code compiles, they’re buying a whole solution which requires a full build work.
- Workstation Decoupling: With a central build process, it isn’t necessary for any individual workstation to be capable of building the entire system, they just need to be able to build their part of it. This can be very handy in several circumstances including reduced licensing costs for third party components by segmenting developers by subsystem and reducing the overhead of upgrading referenced components because individual workstation inconsistencies aren’t an issue unless the developer’s run into a defect in the course of the work they’re performing. This is particularly handy during maintenance when a developer has moved on to a new project.
Not all of these benefits will apply to every operating system or application type. In fact, it seems this discussion is most frequently had in Windows development teams. This may well be an artifact of the tendency for Windows environments to be more distributed than Unix environments with centralized builds being more the rule than the exception on Unix.
Best Practice: Continuous Integration
When you’ve created a fully automated build and then centralized it, you’re dangerously close to a best practice called Continuous Integration. Continuous Integration builds on the concept that if the entire build is automated, and it can be done on a central server, then each build is free. The only potential cost of a build is the risk that you’ll make a change while the build is running and want to start another build of the same project. If you’re coming from a world of expensive and time consuming builds, this is a revelation.
- If builds are free, do a new build every time someone checks in a change. Now you’ll know right away if that change breaks something, and you’ll know that a build reflects the latest code changes.
- If builds are free, let anyone trigger a build. If someone just isn’t sure if a change made it in, or you made a change to the build server, or you just want to see an updated test run, or even just want to make the lights on the server blink faster – do a build. No harm, no cost.
- If builds are free, anything the build does is free. Seems obvious, but follow me on this one: Anything you can teach the build to do, it’s free. Why not have it run some automated tests on the software? What about uninstalling the old version from your test environment and installing the new one? How about some performance tests? Notify the development team of new builds? Move defects that are claimed resolved in the new build to the next workflow state so they get tested?
Automated Testing
We’ve found it always an uphill battle to introduce automated testing into development teams that aren’t currently doing it. Automated testing is often viewed as a post-developer action that automates what manual testers would otherwise perform but we believe this misses the point. Usually the highest benefits from automation don’t come from slavishly automating the exact process that is done manually but instead looking at what you could do if the whole process was automated. For example, no human is going to completely regression test an application for a minor change, it is simply too time consuming. It may not be feasible to perform an accurate regression test purely using the public, published surface of the product either.
Instead, look at introducing automated tests into the development process itself. Don’t get hung up on whether they are automated unit tests or system tests or just make you feel happy tests. We’re big fans of using NUnit/JUnit to get developers to start writing good, idempotent tests in parallel with their code. You can even use these when your software isn’t necessarily written in either .NET or Java, provided you can call it from .NET or Java. Most automated build systems can intrinsically talk directly to NUnit/JUnit, and if not they can call a command line to invoke the test execution capability distributed with NUnit/JUnit. This means the developers get the benefit when they are writing the code that they can prove it correct, and you get the benefit of each of these tests being run every time the system is built.
Even if you don’t get into automated unit testing, consider writing just a simple script or executable that will smoke test the application. Then, have your build process distribute the fresh package to a test system, install it, and run the smoke test application. This should be part of the success/fail criteria of the build. This will give you a base level of confidence in the entire process nose to tail, and will encourage developers to add things to the test process because they know they’ll get benefit every time the build is run.
Coming Next: Great Results through Incremental Investment
In the final article of our series we’ll look at how to create an automated build incrementally and make it a natural evolutionary process of your team, providing both immediate and ongoing value. Really, it’s no joke and it’s not going to require upending your technology or team.
Build Automation: Setting the Stage
Posted by: | CommentsEditor’s Note: This is the first article in a three article series, with a new article posted every few days.
If you haven’t experienced the difference an automated software build system can make to your entire approach to development, this article series will show you why it’s worth your time and how to get it done. Before we launch into the nuts and bolts of setting up a build automation system, lets step back and establish some common ground.
What’s A Build?
A build is the process that takes your source code and translates it into an installable product. There are some definitions that merely look at the first part (building executable files), but I prefer to look at things from a results standpoint: A process should achieve an external result, and the external result of building software is that you have a package that can be distributed and installed by users.
The critical goal is to ensure traceability from product back to the source code that created it:
- A given version of your product must represent a unique build so you know that there’s just one “1.1.1452″ version of your product in existence.
- Each binary file (.dll, .exe, .jar, etc.) needs to have a unique version number to ensure that there is just one “1.1.1452″ version of “MyCoolApp.exe” so you can look up the source code by that version number.
- The source code for each binary must be labeled with the version number so you know what source code made that version.
The same rules apply to non-compiled code as well, you just tend to treat them at a higher level (e.g. a whole set of PHP files as a group instead of each individual file).
To achieve these goals, I’ve always used a few simple rules:
- Every exchange loops through the source code control system: From computer to computer or process to process, do it by checking the output into the source code control system and getting it from there on the other side. This ensures you have a way of seeing the output of each stage.
- Only builds leave development: When you are going to bridge from your raw development environment to any other environment – test, certification, whatever – it’s done through a full build that has its own unique tracking number. Even if you just made another build 10 minutes ago.
These rules eliminate the possibility of transient work products (e.g. binaries) getting anywhere without the tracking to back up where they came from. They also ensure that any developer that has pack rat tendencies (and most do) will have to push things from their box to the source code control system, which should be on a nice safe server that’s backed up.
Sidebar: Seriously. Your source code control system is virtually irreplaceable. It should live on server-grade hardware fed nice clean power with a UPS and regular backups. The system you select should have a strong track record of never corrupting data and you should be comfortable that your backups of it are top flight. I recommend a product that stores into a commercial-grade database because the data is just that important.
What’s In Your Build Process?
At a high level the process to achieve this traceability is going to look something like this:
- Get the code for each project that needs to be compiled.
- Update the version information so you get a unique version of the compiled files
- Compile them.
- Label the source code you compiled with the version number.
- Package the binary files with everything else needed for the product into a distribution format.
- Store that distribution in a central location with a version number or name indicating what version it is.
That feels very simple and straightforward, doesn’t it – just six steps. When you look closer, you’ll notice there are a lot of loops: You have to get, label, and compile the source code for every project that needs to be built. Often, these projects have to be built in a specific order to work correctly. It may not even be obvious until the code is smoke tested if they were built out of order and won’t run together as a group. You also need to do this with absolute confidence in the integrity of the process so when you find a problem on a computer and it appears to be running version “1.1.1452″ you have confidence on exactly what that means, all the way back to the source code.
Pretty much every development environment includes some form of build automation. In the old days it was “Make”. In Visual Studio it’s now MSBuild. For the most part, these tools are competent at performing the basic steps necessary to take source code and produce binaries, but they aren’t generally going to handle the other elements like labeling source code, checking in outputs, and copying the final distribution to a central location. If they can be extended to do that, it’s usually fairly high effort, and can easily get in the way of the routine work your developers need to do local builds on their development systems.
But Wait, There’s More
This is a very simplistic view of what a build looks like because it leaves out a critical step: The smoke test. It really can’t be called a build if it can’t be installed and at least fire up without laying over and dying. It’d also be nice to pull together release notes including the defects that were fixed or new features added in this build. Finally, lets notify the team that a new build exists so they can pick up where the build leaves off.
You Don’t Need an Automated Build
You can do all of this by hand indefinitely. After all, if you document the process it should be possible for a professional to correctly execute the build by hand every time, following each step.
There are three key problems with this approach:
- Humans are fallible: A well trained professional doing an intricate task will still make a mistake around two percent of the time. That’s one in 50 opportunities: They’ll put the wrong version number on something, label the same folder twice and one not at all, not clean out the working directory first, something.
- The potential for mistake degrades value: Because a main point of the build process is to have confidence that you can absolutely go from distribution package back to every element of source code it maintains, even the possibility that there was an error in how the build process was executed will make you doubt its integrity and therefore you won’t achieve the value you wanted.
- It’s wasteful: Each build occupies a well trained professional’s time. If you need to do a new build at 2:00AM, you need a well trained professional to execute a possibly lengthy process accurately. This costs you resources and even worse it’s not a job any developer likes, so it costs morale.
Over time, the fact that each build is a risk and a waste will tend to unconsciously affect the decision making of the development team, making them more likely to defer a fix or change they might be able to code and unit test on their own computer but don’t feel is worth the overhead of the build.
Traditional Resistance
There are a number of reasons that are typically put forward against having a central, automated build process. The most common ones I hear are:
- It will slow down testing and certification: Since each build that is going to be tested outside of a developer’s machine has to come from the build system, that means that even a small error found in certification will require the entire build be run before it can be tested. Why not let a developer just recompile the offending file and slip it onto the cert system to verify it?
- It takes extra resources: Having an engineer set up and maintain the build process takes time away from development, which means my customers will get fewer features, etc.
- It slows down change: Every time we want to add a new binary file or a dependency we will have to update the build system and possibly the build process and retest it. This will get in the way of an individual developer being able to get things done as fast as possible.
- Single point of failure: What if the build computer fails? If it’s the only place to do a build, we’re stopped.
These objections generally spring from a few underlying problems within the development team: Developers that lack confidence and fear of change.
Developers Playing Hide the Ball
If there is a developer on your team that isn’t up to the rest of your team’s level and they’re trying to hide it, this is virtually guaranteed to bring it to everyone’s attention. They won’t be able to just slip a new file into the build or slip a fix into test without it being clear what happened.
If the time it takes to perform a build – whatever that is – is an impediment to certifying your software because you need to fix problems faster than that time, you have a more fundamental issue: Your developers are not thinking through their code before it’s included in the build. Fundamentally, it’s called Certification, not Debugging for a reason: Developers should be genuinely surprised that their code doesn’t work as expected when it leaves their hands.
If this is the case, then when a problem makes it to test it shouldn’t matter if the build takes 30 minutes or even two hours. Any development process that needs to go from the developer’s fingertips to certification in less than that time has more fundamental quality control and process issues.
If you have developers concerned that this slows down their ability to add new projects or dependencies because they have to think through how to update the build system this is really a good thing: These decisions matter by the time you want to ship a product to customers, so the earlier you can address them the lower the probability you’ll discover in certification that redistributing a particular dependency is hard or being done wrong.
Fear Of The Unknown
Most developers are not IT administrators, and all developers are humans. Human beings fundamentally don’t like change. They will actively fight change, often with very good prose. Giving up control from being able to do a local compile and take the binaries that work on their box to a central system that is opaque is uncomfortable. The very same developer that’s perfectly willing to switch to Visual Studio 2008 the second it was posted to MSDN and downloads the latest nightly build of NHibernate will come up with all sorts of creative reasons against a central, automated build because of their fear of change.
If you are following reasonable source code control rules, you really don’t need to worry about backing up an individual developer’s system: There shouldn’t be much that’s on it uniquely if it were to be lost, preferably at most a day’s work (which is within the time frame of a backup/restore loss anyway). The build system is special: As part of making it the central authority of building your distribution, it really is inconvenient to have to recreate it from scratch through reinstalling all of the software components, etc. It is likely to be slightly different than your developer’s computers (server grade hardware vs. desktops) so your normal developer image won’t work on it. Back it up as part of your normal production server backup scheme, and invest in redundant disks so it’s unlikely you’ll need those backups. This will tend to give you better build performance anyway, so it’s a double benefit.
Coming Next: Benefits of Automation and Centralization
Check back for the second article in this series focusing on the benefits for your team of automating the build process and centralizing it, including the roles and capabilities of an automated build system. From there the series will continue with how to create an automated build incrementally and make it a natural evolutionary process of your team.
Defects: The Resolution Perspective
Posted by: | CommentsRegardless of how trivial the defect is there are very real costs and risks to resolving it. Let’s say it’s as simple as a misspelling on a text label, so it’s both really easy to fix and really easy to ensure you fixed it. You still have to contend with:
- Every Build is a Risk: Every time you package up a set of files as a build, there’s a risk of error. If your build isn’t entirely automated – and entirely means from source code through install – you run the risk of something being done wrong. More likely, the risk may be something external: Unknowingly including a newer version of a referenced library or introducing a dependency on a newer version. Either way, you need to do significant regression testing to mitigate that risk.
- Deployment Risk: The update will need to get from your development environment to your users. Whether it’s a Software as a Service (SaaS) product that just needs to hit some web servers or packaged software deployed to thousands, your update will need to be installed for people to get any advantage of it. In most cases this will mean a special upgrade installation, notification to existing customers to come and get the upgrade, and additional support for your users.
The truth is that most defects aren’t as clear cut as a spelling error, so you will also have to contend with the possibility that no matter how well intentioned, your fix is going to cause new problems for your customers. It could be that there are advantageous side effects of the current (defective) implementation or that your fix doesn’t work on the Elbonian version of Windows XP which you didn’t discover because you did only a focused test of the fix on your key target platforms. In more elaborate cases, it could be that the loophole represented by the defect is viewed by some of your users as a feature, so fixing it makes your product less valuable. This is more likely when doing defect patching because you typically don’t have the benefit of a beta cycle and end-user involvement in considering all of the aspects of the fix.
The Last Change is to Blame
If you have the opportunity, try this experiment some time: Announce a new version that never really happened. Perhaps you just relabel a prior version with a new number or something else to create the placebo effect of an update. What you will discover is:
- Surprise Fixes: Some group of your users will thank you for the new version. It’s so much faster than the old one! Oh, and you fixed a problem they’ve had for months.
- Surprise Defects: Unfortunately much more common than surprise fixes are the number of people that will report a problem that must have been caused by your update because it happened just after they installed it. It could be as wide ranging as their hard drive died or Word lost its dictionary. But they’re sure it’s your fault.
- Reinstall Rash: Some contingent of users will have problems installing the upgrade. The problem will vary depending on how you deploy your fix, but they’ll manage to get a computer or two out of sorts over it. Don’t think this is a Windows problem either, just look at the volume on support forums for WordPress right after a minor update.
In this case, there isn’t much you can do to minimize the problems because… you didn’t create them (after all, it’s the same software – that was the point of the test). With the possible exception of finding better ways of deploying fixes, there just isn’t a lot you can do. This is the minimum end-user overhead to every upgrade you make, and they’re going to make it your overhead. The big investment you can make to minimize this is:
- Cultivate Your Brand: If customers love you, they won’t make the leap from coincidence (two things happened at the same time) to causality. The more they love you, the more they’ll be sure they are at fault.
- Make Upgrades Easy: You really want to invest in ways that make updates easy. Look at Firefox and Windows Updates for examples of really great ways to get updates out the door. It’s easy and surprisingly trouble free, much more so than relying on users to manually know whether to uninstall the old version first, whether an update applies to them, etc.
What Are You Committed To?
It may seem cold and uncaring, but many defects just aren’t worth fixing because the downside potential of deploying the update overwhelms the likely benefit. Particularly when you are well into the next development cycle and can instead resolve the issue in the next feature release it often makes better business sense and customer satisfaction sense to leave the defect unaddressed and fold it into the future release.
If you’ve decided that the defect should wait, discuss this with the development team and your internal management and get consensus. This isn’t an easy conversation, but it’s made easier if you can show just how much effort, cost and opportunity loss there is in shipping an update for just this issue. Make sure that you leave the door open to reconsider, particularly if another issue shows up: Most of the overhead of deploying an update is essentially constant regardless of the number of issues resolved. This future potential will often push people to focus their thinking on whether this issue alone is worth all of the cost instead of talking in vague terms of commitment to quality and customer service.
Sidebar: Eliminate Build Overhead
While the overhead of creating a build and validating it is essentially a constant, that constant can be made significantly smaller with the right investments throughout the development process. The key is to automate as much of the process as possible. This broadly fits into the school of Continuous Integration or Continuous Builds, primarily because if you can’t automate the process you have no hope of doing it continuously.
- Automate Source Code to Install: Look at the process that takes raw source code and produces an install (be it a Windows Installer package, zip file, or RPM) and get humans entirely out of the loop. This can be done entirely with free software and by extending the tools you’re using already.
- Elevate Unit Testing to System Testing: Are you writing unit test libraries? If you’re using NUnit (or JUnit, or whatever) then look for ways to expose these to the build process and let the build run them every time. It doesn’t have to be this fancy – there just has to be a way of invoking tests during the build process, so this could be done with your own custom command line tool that exercises the system.
Automating the build process decreases your overhead costs during the primary development lifecycle and during maintenance. The overhead of the build is a tax on everything you produce that adds no value to your users, so focus on reducing it as much as you can. The great news is this game can be won an inch at a time: Incremental investments across your team can steadily improve your efficiency. There aren’t many other things you can do in the development process that pay off quickly and don’t require a major upfront investment.
As you gain experience with having an automated build and verification process you will find the entire team is more willing to tolerate risks because they know they have a large safety net in the automated verification process.
What Conversations Are You Having?
It’s easy to get pulled down into conversations that confuse the effort to fix the defect with the value of fixing it, or ignore the practical issues of deploying the fix or impact to other work that you can’t do because you’re pursuing the defect. Your development team will instinctively want to fix the defect – it will feel like an affront to their honor. Have the right conversations to bring everyone around to consensus on whether this one is worth it or not to what the team is trying to achieve.
As a manager and leader, your job is to generate buy-in for the decisions of the team and of the company. In the end, the worst mistake is pushing the development team where they don’t want to go. If they are determined to fix it, think hard about what the cost of letting them go ahead is. Perhaps the team can fix the defect but you don’t deploy it, deferring that cost until there’s enough value accrued to make it worth it. If they don’t think it’s worth it, perhaps it’s time for a field trip to commune with the users to understand the impact of the problem more clearly. The worst outcome would be if the team loses the passion to put in the time on all the details that have to be right to produce an outstanding product. Whatever the problem is, it isn’t going to be worth that cost.
Defects: The Diagnostic Perspective
Posted by: | CommentsRarely will users identify the true underlying defect with the software: Most users know there’s a problem but can’t precisely define the true defect. Additionally, if the software was at least moderately tested before release then most defects that are visible to the end user are really multiple defects:
- The problem the user reported.
- The way the software handled the problem when it occurred.
- The software design that allowed the user to get into trouble in the first place.
Typically, a user experiences a problem once the software has gone well off-track. The underlying problem began earlier than reported where it first jumped off the tracks (#1). It then snowballs until the user gets an odd message or experience sufficiently bizarre that they’re willing to report it (#2). It’s unlikely the software handles it in a pleasing and gentle way because if it did, that would mean you anticipated the problem and if that’s true, you would likely have found it in testing. You’ll want to make the software handle the problem more gracefully if something like it shows up in the future.
Finally, what was it in the overall architecture or design of the system that allowed the problem to get as far as it did without getting caught or corrected earlier (#3)? Perhaps there’s an underlying assumption that hardware is reliable or a file can’t be partially written to disk that needs to be reconsidered. This is the preventative medicine to catch all of the problems that are like the original problem. Once you understanding the basic design assumption that led to the problematic design in the first place, your team can usually see other decisions that sprung from the same thinking and look to address those before a user experiences a problem.
Side Note: Your users are already experiencing that problem too; they just haven’t reported it yet. How good are your feedback mechanisms?
It may not seem like there’s much of a risk or impact in attempting to diagnose the defect, but:
- Diagnosis is unbounded: In most cases, determining the fundamental cause of a defect is the most time consuming part. It also defies estimation. You can time box diagnosis time to limit your exposure, but that’s not the same as being able to provide an estimate. Each defect represents the potential to throw time down a hole.
- Workflow Impact: Your team is virtually guaranteed to be off busy on some new development or other project. They will likely have to shelve source code in a temporary state and shift back to a prior set of code to even diagnose the issue. Whatever the individual(s) involved were working on will need to stay on hold or be reassigned, complicating management and team productivity.
If your team doesn’t believe they can easily find the defect before they start looking into it, or they don’t believe it’s worth the effort, the defect is going to cost you more than time; it’ll cost you with the team. If it turns out the defect is easy to find, or while finding it the team discovers another issue they feel is more important then you’ll get lucky and face no longer term damage. More likely, the team members will add this to whatever other water they feel they’ve had to carry for you and the company. Before overruling your team, spend the time to either convince them that it’s worth it – or be convinced that it isn’t. If that doesn’t resolve the impasse, propose a time boxed approach. If you start with just a one day commitment to look into something this typically reduces resistance because you’ve eliminated the first problem (an unbounded time frame) and significantly reduced the workflow impact.
As your team looks into the problem, they will naturally come to believe that it’s both very important (because people perceive effort to equal value, so the more effort it takes the higher value it must have to justify that effort). This means they’ll tend to lose the perspective necessarily to objectively evaluate the risks and rewards of resolving the defect and deploying the fix. To help make these future conversations easier, don’t let the developers involved in the problem go too far off the reservation before revisiting the decision on whether it’s worth continuing to dig into the defect and what the potential upside to fixing it is.
Coming Next: The Resolution Perspective
Come back in a few days for the final post in this series, talking about the impact, difficulty and risks of resolving defects and deploying updates.
Defects: It Depends on Your Perspective.
Posted by: | CommentsYour product is out in the wild, and even better – it’s in use by real users. You’ve got feedback and support structures in place and they are producing results. Now you need to take that feedback and incorporate it back into the product. To do this, you’re going to have to navigate the social dynamics of your organization around defects.
Any product, software or otherwise, has defects. Your shop may have a nice term to paper over it – incident, problem, ticket, errata, trouble report…. But let’s not paper over it – a defect is a defect. Developers also like to split hairs between feature requests and defects, but from a user standpoint it’s all defects. Everyone involved in product development will have their own way to prioritize defects, and to get the best results from your team’s time you need to be able to figure out which ones to address and how fast – and do so in a way that generates buy in from your development team, management, and customers.
There are an endless number of way to look at prioritization, but however you do it the discussions should include several perspectives:
- Impact, Difficulty, and Risk of defect to the end user.
- Impact, Difficulty, and Risk of even diagnosing the defect.
- Impact, Difficulty, and Risk of defect correction and deployment.
The End User Perspective
Your customers in general want and expect a defect-free product. Even if your average customer understands that all software has defects, intellectual understanding won’t overcome the emotional impact of running into a problem. Your users will generally start from the perspective that their problem is a defect in your software, it shouldn’t have been there in the first place, and you need to fix it immediately. Today would be nice.
It is very difficult to understand the value a customer places on fixing a particular issue from within the development team. Developers tend to grade defects based on the effort it takes to fix them and whether they produce an outright failure of the software. For example, few developers will get worked up over fixing a cosmetic defect such as a misspelling or alignment problem; If it’s that simple to fix, how valuable can it be? The exception to the natural cognitive bias that a problem must be hard to be worthy are problems that can crash the application or cause it to corrupt data. Few developers won’t see this as a deadly sin that must be resolved regardless of cost or risk.
Customers have a different perspective. They see just the surface veneer of your product and assume that it can never corrupt data or crash. Outright crashes have gotten rare enough that most users will refer to an error message as a crash. Because they have no idea what’s happening inside the black box that is your product, they will judge it solely on what they can see: Does it act like other applications, do the things they can see look clean and well crafted? Much like making a spelling error on the title page of your term paper can cause the entire work to be devalued, a small cosmetic error on the user interface can cause customers to doubt the correctness of your entire application.
Many end users will tend to discount defects that require long steps to produce or go away by restarting the application as long as they can convince themselves that they are at fault. This happens more often than you might expect – most users believe they don’t understand the rules behind the application and instead are using a rote procedure to accomplish their tasks. When something goes wrong, they will generally go back and try it again – possibly many times – before coming to the conclusion that there just might be a problem with the software and not with them. If the defect only presents occasionally they will usually write it off as their fault. Lest you think this behavior is limited to nontechnical users, this happened to NASA and resulted in a several day delay of the first Space Shuttle Flight.
With rare exception, if a defect isn’t judged as essential to fix by your customers, it’s probably not worth addressing prior to the next routine release. Every change to the software has consequences and takes effort that could go into something more important – to your team and your customers.
Coming Next: The Diagnostic Perspective
Come back in a few days for the next post in this series, talking about the impact, difficulty and risks of diagnosing and resolving defects.