One version of the problem is simply that business rule complexity leads to lower productivity, for a number of reasons:
- Complex business rules are harder to understand and to code, and therefore take longer to implement.
- Complex rules introduce more and subtler bugs into code.
- Complex rules require a deep (and consequently more time-consuming) understanding of a system by people at all levels: the business owners, the programmers, the project managers, and the testers.
- Edge cases are often overlooked by business owners, causing a lot of back-and-forth with business owners as development proceeds.
I think the importance of this last case is often overlooked. It's very easy for executives to create general rules that in practice map to dozens of complicated logic paths. Most executives lack the rigorous attention to detail that the identification of these logic paths requires. So it's left to the developers (or fastidious project managers) to discover them; and once discovered, they have to be explained back to the executive (sometimes through an intermediary, which adds a level of potential error), and then translated into code.
Sometimes this complexity is hard to identify. It's often the case that no single project leads to anything that raises a red flag. But over years of business experimentation on a growing system, you can easily be left with a mass of hidden and hard-to-understand rules that programmers have to tiptoe around. We're all familiar with the idea of spaghetti code; maybe we should be as wary of spaghetti rules.
In our case, our system evolved in these steps: we created a site; later, we translated it into several languages; with a more international audience, we wanted to display prices in our users' local currencies; to further cater to local customers, we introduced differential pricing based on currency; then, we offered different products based on a customer's location; finally, we started A/B testing our purchase path, and can target the tests based on a user's language, location, or both.
These are reasonable and savvy business decisions. And yet we're left with a system in which introducing a new product involves a plethora of questions: What will it be called in every language? How much will it cost in each currency? Will it be offered worldwide or just in certain markets? Will we test its introduction, and if so, how? This complexity is probably worth the flexibility that our system allows. And yet it's very rare for us to step back and ask the question, "If we make this change, how will it affect how quickly we can finish future projects?"
I've resolved to make it a part of my job to make clear to business owners just how complex their small tasks are making the codebase, and how that's affecting productivity. Instead of measuring a project on the costs and benefits of the project alone, we should take a more expanded view and look how it might affect productivity in the future. And this should be integrated into any calculation of the costs of the project. This is, of course, easier said than done, especially since any true calculation would have to involve the projected life of the codebase, which is impossible to know. Nonetheless, we should acknowledge it and try to account for it somehow.
It's also interesting to return to the idea of edge cases, and look at their impact. Our lead developer and I were musing over how programmers seem magnetically inclined to not only find but dwell on edge cases. We're all a little like lawyers, searching for that loophole that no one has thought of. It's a point of pride to find that corner of business logic that makes everyone scratch their heads and say, "Wow, good point."
And yet, is that always a productive use of time? If edge cases cover one billionth of a percent of use cases, we can probably all agree that they're not worth considering in all but life-critical situations. What about a one hundredth of a percent of cases? A full percent? It's hard to make a blanket decision about it. But I told my team that when they encounter an edge case, they should do a quick back-of-the-envelope calculation and if they think it will affect less than a tenth of a percent of customers, to discuss it with me -- and I'll probably give the go ahead to ignore it.
When you've been around since the creation of the codebase, it's often hard to realize how complex the business logic has become. It was only recently when I was talking to a developer about the case of someone purchasing a product in France in euros and then flying to New York on a business trip and getting sent an offer to renew the product, but not being able to access the euro price... when I was struck by what a complex system our simple site had become.
One of our developers made an excellent point: "The severity of the edge case should probably be taken into account too. If 0.1% of your customers can get your product for free through an edge case, then that's something you need to account for. Also it's probably fair to say that the vast majority of security flaws out
ReplyDeletethere are edge cases that nobody thought of beforehand. I guess the lesson is, take the time to come up with edge cases, and analyze their impact, and dismiss them only after careful review."
Perhaps the standard should be on the potential impact to revenue, not number of customers affected.