Avoiding Unnecessary Complexity
I talk a lot at work about keeping things simple, being pragmatic, and generally avoiding unnecessary complexity. This is a story about something that happened a few years back and some of the insights I try to share with folks about why I think simplicity is so important.
I sat in a room with a large team of software developers, project management and various other roles. It was an onsite meeting to do high-level planning for a 6 month long release cycle (I know, I know! We’ll tackle that 6 month release cycle thing in a separate article) and were reviewing the first deliverable on the table from the product team. After reading through the description of what was being requested, a young, enthusiastic, and well-intentioned engineering manager stood up and proclaimed “We’re going to need a rules engine!”. I promptly stood up and responded with “No we’re not!” 😂.
Thus kicked off a conversation that, honestly, went on for way too long. In the end, we used an open source library and a static JSON file to solve the problem that our product team was looking for. After checking in after this solution had been in production for a year, we still had yet to encounter a need for a “rules engine”. Fast forward a few more years now, and I think it’s still going strong and meeting all the needs of that product team.
Back to the original meeting. The immediate reaction from this engineering manager was to build the most flexible and “future proof” solution possible. There are many issues with that, the first being that nobody had asked for that. The product leadership in the room that day even pointed out that this project might not test well and possibly wouldn’t even exist in a year. Beyond that, there was an understanding amongst many of the more seasoned folks in the room a customer often doesn’t know what they want until they actually see it. There was a chance that upon seeing our first attempt, their understanding of the problem could shift. There was a strong chance possibility of customers responding to our shiny new product with “oh, that’s not what we meant, what we actually want is X”.
Communication is hard. Predicting the future is impossible. Trying to predict the future based on communication with another human is doomed to miss the mark. Unless you’re building something that “scratches your own itch”, your team probably doesn’t contain members that are representative of your customers. Scratching your own itch is awesome if you can do it, but we can’t all be on teams that build developer tools.
In a case like this one, very few (if any) members of the team were representative of the customer we were trying to serve. In fact, in that room on that day, I was probably the closest thing we had to a representative sample and I couldn’t have told you if what we planned to build would be valuable to me in the customer’s position.
So what happened that day? Well, a less experienced developer thought that we needed to solve for the future and saw a fun challenge that he and his team could solve. The problem is, that approach would have been expensive, time-consuming, and as we have learned in hindsight, it wouldn’t have added any value. In fact, it likely wouldn’t have been delivered in a timely manner and would have hindered the overall customer experience with our products.
The value in the solution we did end up with goes beyond saving time and money in the initial delivery. It also set us up with a simple solution that will be easy to extend or change. It was such a relatively “cheap” solution, we could even replace it if needed without much heartache from the folks responsible for budget. On the flip side, if we had built something complex, it would be hard to maintain and it would be hard to justify the effort to simplify it, so we’d likely be stuck with the maintenance burden of trying to solve for every eventuality.
For many of us, working as developers gives us the opportunity to solve interesting problems with computers. We’re naturally curious and love a good challenge. It feels good when we work through a particularly difficult puzzle in our work. We share what we’ve done and show our coworkers how clever we were when we solved a problem in an “elegant” way.
Like most things, “clever” and “elegant” code has a place and is fine in moderation.
The problem is that in a lot of cases, it’s not really necessary. Frequently, what we end up with are overly complex solutions to problems that either had a simpler solution or didn’t really need to be solved in the first place.
We complicate things when we try to do too much, and make our solutions generic, reusable, and DRY, when what we probably needed was just the bare minimum to solve exactly the problem at hand.