Earlier this summer, I spent a few days onsite with a client working through hammering out requirements for an upcoming large project. One day during a lunch break, my client asked me a question that I’m surprised no one has ever asked me before:
“We want to be the best client you’ve ever had. What do you wish we knew so that can happen?”
I think that I came up with a fairly reasonable reply at the time, but I’ve been ruminating on the question all summer long. Here are the first five things on my list of what I wish all my clients understood about developing software:
Software development is a marathon, not a sprint…
Unless you’re building something that’s really small, the team that’s building it is going to be working on it for a long enough time that the kind of heads-down gonzo crunch mode that’s featured in most stories about software development isn’t sustainable. Not only is your team going to burn out, but it’s inevitable that they’ll start making sloppy mistakes. A well-run project treats its development team humanely and is concerned with regularly and steadily delivering reasonably-sized chunks of functionality.
A few times we’ve worked with clients who are so focused on reaching what they consider to be the big finish line of a project that they refuse to pay attention to our regular milestone releases, ignoring our advice (and eventually, despondent pleas) for them to seriously look at and give feedback on our work in progress. This has always resulted in serious problems as the clients find that what they asked us to build wasn’t what they actually wanted once they saw it fully implemented, and those problems could all have been corrected easily (and inexpensively) if they had been noted earlier in the development process.
…and the finish line keeps retreating toward the horizon
It’s been said that software is never finished, it’s abandoned (or, perhaps more grimly, that software is only finished when your last user dies). As your users work with your software product, new features will naturally reveal themselves. We’ve also seen clients who’ve decided that they can’t ever release a piece of software until it’s ‘done’, but continue to increase the scope of the project as it goes through development. Projects that are run in a regular rhythm of building and releasing incrementally better versions don’t suffer from this problem because they accept this principle as reality and use it to their advantage. Before the web, it was much more difficult to think in terms of frequent incremental releases; releasing software in the 90s included costly (both in dollars and time) steps like duplicating and shipping physical media to users, who then had to stop work to perform the installation or upgrade. Right now I’m having horrible flashbacks to afternoons wasted upgrading my Unix workstation from a stack of dozens of floppies.
In the 1975 book “Systemantics”, John Gall expressed an observation about system design that’s come to be known as Gall’s Law:
A complex system that works is invariably found to have evolved from a simple system that worked. A complex system designed from scratch never works and cannot be patched up to make it work. You have to start over with a working simple system.
The more complex the desired end state of a project will be, the more important it is to manage its development by creating simple and robust infrastructure components that can be built on top of. Modern software development has the advantage that many of these infrastructure pieces have been abstracted out into well-documented and tested libraries and frameworks that provide a solid foundation for projects–in most cases, building a piece of software in the early 21st century only requires that you build those pieces that are completely unique to the problem you’re trying to solve.
When to Buy, When to Build
Even though we make our living creating new software, it doesn’t always make business sense to write new software, at least not from scratch. If a client came to us with a set of requirements that were already met (or almost met) by something that’s already commonly available, and the point of the client’s project isn’t to directly compete with that pre-existing system, buying that other system instead of building your own needs to be seriously considered.
Consider this scenario that we see occasionally: a client plans to start a business that requires a content management system, and decides to build their own. Chances are that many of the requirements could be fulfilled with a vanilla installation of something like WordPress, and most of the others could be fulfilled with pre-existing plug-ins, and very few of them couldn’t be fulfilled by writing a few custom plug-ins. Even if the long-term vision for this business ends up requiring a truly custom system, it’s possible to start validating the business plan right away and then build the fully custom system in parallel. The advantages here are that the client can build their custom system using money from revenue instead of investment, and can use feedback and usage patterns from actual users to build their custom system right the first time.
One thing to steer clear of when trying to extend an existing system instead of doing a scratch build — not all systems are equally suited to being extended, and some are outright hostile to it. We’ve also seen situations where we’ve been asked to fix or extend systems that were built on top of other pre-existing products that weren’t designed to be extended. At some point of complexity, these systems seem to always reach a point where the layers of hacky extension upon hacky extension end up making things not only un-extendable but un-maintainable on a day to day basis. Often these clients end up needing to pursue a total ground-up rewrite of their project.
It would be nicer if the buy/build decision was always crystal clear, but that’s not always the case.
Estimates and Risks and Wishful Thinking
Before we start work on a project, we always strive to both learn as much about what the full requirements for that project are, and then estimate the effort required to implement all of those requirements. Clients often believe that once they’ve told us all the pieces that need to be built, we should be able to tell them exactly how much the development will cost and the date we’ll be done. I’ve read several books over the years that try to convince people that this approach makes sense — if you just spend sufficient effort on detailed requirements and design, then the actual work of writing the code will become trivial, almost not worth considering. Often these books say that building software should be like constructing a building: plans are handed from the architect to the construction team who follow those plans without exception and everyone’s happy. I almost believed this ideal until we had an addition put onto our house a few years ago. It turns out that not only is building software not like that, building a building isn’t even like that. Every day of that build there were questions to be answered and decisions to be made (and more than one detail that made sense on the blueprints but were completely unrealistic in three-dimensional space).
Any non-trivial software project has opportunities for estimates to be wrong, whether because of hidden complexities (a task is more difficult than was estimated) or hidden requirements (before we can develop a feature, other features not called out in the requirements or estimate need to be built first).
Many projects have associated technical risks that make estimates difficult or impossible. We frequently work on projects that interface to other hardware or software systems that sometimes don’t exist yet. Obviously, it’s difficult to estimate how long it will take to interoperate with some other system that hasn’t been built, and will undoubtedly have its own bugs, delays, and need for occasional redesign as it’s being built. Taking Gall’s law into account, we always manage projects like these by identifying these risks and isolating them, often into separate standalone projects. It’s very tempting in a situation like this to try to save time by building out all the parts of a project that don’t interact with the risky subsystem and hope that those missing pieces will be delivered on time when you’re ready for them and also work as advertised the first time. I’ve worked on a few projects where a combination of smart management techniques (most often by defining a well-documented interface between the components that’s agreed to by all parties and then building the software against a simulated version of that interface) and (let’s be honest here) some component of luck have resulted in happy outcomes. We’ve also seen instances where trying this was a bad gamble, and ended up in huge cost overruns as everyone involved frantically tries to duct tape all the pieces together.
Much smarter to start things with an isolated proof of concept project that demonstrates that the risk we had identified is no longer a risk, then build the real project on top of that.
Even in a project where there aren’t any especially noteworthy technical risks, it’s important to remember that an estimate is just that — an estimate. We’ve worked hard to develop estimation techniques that allow us to reasonably compensate for some amount of hidden complexity, but it’s impossible to account for every contingency, even if the scope of a project remains fixed (and those projects are rare enough that they can safely be ignored). It’s made more complicated by the fact that an estimate performed during the sales process has the unique misfortune of (by definition) being prepared at the time in the project’s life that all parties involved know the least about that project. It’s important to remember that assigning special status to that sales estimate is a mistake — as the scope of a project changes, and as both client and developer acquire a deeper understanding of the actual requirements of a project, updated estimates that incorporate increasingly better knowledge need to be prepared and reviewed. In much of the literature, you’ll see dire warnings about ‘scope creep’ and the sometimes draconian techniques that have been developed to eradicate it. From my point of view, that’s a misguided way to think about things — the scope of software projects is naturally fluid, and it’s much healthier to work from a position of understanding the impact that feature additions will have, from both a dollar and calendar time point of view, so client and developer can work together to prioritize features, budget, and schedule.
What things do you wish your clients (or bosses) understood about making software?