This post was originally posted on my blog
I recently read this blog post, which describes how microwaves have gotten caught in the trap of adding features that no one needs while usability for the core use cases suffers. Not only do I agree, but it reminded me of my absolute favorite microwave I've ever used...
I was fresh out of college working at IBM, and they had microwaves in the break area for heating up lunches. Most of them were fairly standard microwaves, however one microwave stood out from all the rest. In addition to the usual buttons, it had a monochrome LCD display with 8 soft keys around it.
When you first plugged the microwave in, it would boot up and a little black and white animation of a chef would appear on the LCD display and bow to you. Then you would have to step through a welcome wizard introducing features of the microwave. The usual things like defrosting/cooking different types of meat were there, but it also had features I'd never seen on a microwave. For example, it came with recipes stored in it that you could search through. Once out of the welcome wizard, the LCD display was used for a complex menu system with all kinds of options.
The best part? The physical start button on the microwave was broken.
But not to worry, there was a workaround! You could also start the microwave by stepping through just a few menu screens using the soft keys.
I loved this microwave and thought it should be installed in every break area used by engineers to serve as the perfect example of overengineering the crap out of something. It seems so ridiculous when you look at the end result, but it can be so easy to overengineer a solution, especially in software, where requirements are often unclear and fluid.
I'm definitely not immune to overengineering, however the primary tool I've found that helps prevent it is domain-driven design. Most of my up front design time is spent breaking a problem down into a set of domain objects with clearly defined responsibilities. If you do this well, you can both solve the immediate problem at hand, while having the flexibility to handle future requirements, either by slightly modifying existing domain objects or adding new ones. While this is a simple concept, it is definitely not easy to do consistently and requires a lot of practice.
Do you have any overengineering stories? What are your tips for preventing it?
My favourite overengineering story is how much work went into a relatively simple task versus having a high amount of useless output requirements.
The development team had to adopt the primary design role for a pop-up modal on an 'edit profile' page. Super simple, it had some text, some input, and some buttons. The design and UX teams were overwhelmed with other tasks so it fell to us. We created a very bare bones modal that followed other designs already in the system. Very lean, and built with the idea that we would go back to it and improve when needed. However, during the QA phase, I'm pretty sure we had three of the cofounders, all of design and UX, and every developer give an opinion and send it back for tweaking. We probably spent an excess 6 hours fine-tuning this infrequent user-facing popup that was eventually removed.
In addition to DDD, to prevent that adventure from happening again it became important to clearly state the minimum viable "product" of whatever we were building. They're tightly related but still slightly different.
It also became important to make sure that everything needed to build the minimum was available from the start. I feel it violates the agile method because you need to prep for it, but if the perfect design is required to have the feature move to the next phase, and that perfect design isn't ready yet, it shouldn't even start.