It’s Monday afternoon and you are nearing the end of a three-hour design spike with a few other engineers. You are trying to figure out how to build a dashboard for monitoring the applications that are running your website.
In order to build this dashboard, your team needs to add new hooks into the existing applications as well as build the dashboard with proper authentication. Each one of you have come up with differing designs, but the group can't agree on which design option is best.
Sound familiar? This is a common interaction between engineers. I wish there were an easy way to come up with the best solution on the first try but until that comes around (tell me when it does), here are a few tips that have helped me ease the pain.
1) Solve the problem at hand, not the one in the future
Figure out what needs to be solved today and work towards that first. You can get tangled up in your own mind really quickly if you keep trying to plan for every future edge case that may come up. Some of you may know this concept as YAGNI.
If someone wants to incorporate functionality to support a dashboard that a future story may require that complicates the current design, then put it to the side. Try to figure out a design that works for the core problem first and then prioritize the extras. Figure out how those extra add-ons would fit into your design, not the other way around.
2) Don’t be scared to refactor existing code
If what you are working on touches other parts of the system, those parts of the code are fair game to change if the proposed solution offsets the cost of the refactor.
Let’s say one of the engineers in the meeting discussed using Python decorators to simplify the new views that will need to be created (you can read more about that in the Flask view decorators documentation). Since the application already has authentication, you have to decide between copying the authentication code into a decorator and using that for your new views or moving the code into a decorator and refactoring your old views to use that code.
Depending on how many views are relying on the old authentication code, refactoring is going to be the more ideal choice. Fracturing your code base creates technical debt and should be addressed sooner rather than later before it is forgotten. The bottom line is that refactoring code is a part of software development and should not be shied away from if the end result is a cleaner, simpler system.
3) Generalize (code) when appropriate
Just because you are solving a specific use case right now doesn’t mean you need to write custom code for it.
Look to places where you can implement, reuse, and generalize functionality focused around object interaction as opposed to the domain of the use case. While you are at it, look to see if any third-party libraries or services do what you are trying to do and use those. Leveraging time-tested code over creating your own gives you time to tackle more important tasks relevant to your business goals.
The nice thing about this tip is that it is independent of design choice. Generalizing code, in my opinion, is a best practice and should always be a goal. There is a line, however. Generalizing code to the point of ambiguity is one sign that a system is overly complex.(Remember Tip 1?) If you are having trouble avoiding premature generalization, here is a good list of basic do’s and don’ts.
Simple things like class reuse and inheritance can not only make your current code base simpler but even make future enhancements much easier and quicker to add. This leads to my last tip...
4) Slow is smooth, smooth is fast
The tips I’ve shared do take time. And while design spikes are timeboxed, that doesn’t mean every question and concern needs to be answered by the time it is finished. Take the time necessary to make the correct decisions, and you will solve the problem (and future problems) much quicker in the end. Be the tortoise, not the hare.
At the end of the day, these are only a few tips to handle a very complex process. There are, no doubt, countless others but these tips have proven most useful throughout my years of engineering. So what are some of yours?