Always Tackle the Biggest Challenge First
Always Tackle the Biggest Challenge First
Have you ever worked on a software project and it got more and more complex the longer you worked on it? You started building some features, but once you got to the heart of the big task that has an important business impact, the code already got so complex that you struggle to implement the most important feature. Oh and heck, you realize that there are a couple of things you haven’t thought about before that totally change the game.
Of course, you get it to work in the end, but you have that urgent pressure to refactor all that code. Unfortunately though, there is no time. And the solution is good enough, we are not participating in a code beauty contest anyways. So let’s just ship and everyone is happy.
Let’s take a step back and analyze the time you spent for different tasks and the order in which you executed them to implement the big task. Typically, the first features implemented were rather easy to implement and had little complexity. Then, at later stages those easy things are glued together. And that gluing is where the problems start surfacing.
For example, let’s say we want to build a simple blogging platform where blog posts are stored on the file system and then transformed into some static HTML pages. Now in order to do that we identified that we need to implement the following small tasks:
- Create a software model for blog posts
- Load blog posts from the file system
- Support markdown for blog post contents
- Generate a paginated list of blog posts
- Load blog post assets, such as images
Looking at the list, the order of the tasks seems legit: first create a model for the posts, then fill that with content from the file system, add a markdown parser in between, then paginate the models and finally copy the assets. There is just one problem with this order: The order does not tackle the biggest challenges first! And that leads to the problem we identified above, the gluing in the end gets more and more difficult.
What if we instead ordered the list like this:
- Generate a paginated list of blog posts
- Load blog post assets, such as images
- Load blog posts from the file system
- Create a software model for blog posts
- Support markdown for blog post contents
How can we paginate if we did not yet load blog posts? Well, just paginate some simple mock data, it’s as easy as that and you’ll need some mock data for your unit test anyways, right? And while you are writing the pagination you realize that you need to deal with paginated URLs. Oh, and of course you need paginated per-category lists as well.
By implementing the pagination feature you unveiled an underlying problem: generating the paginated URLs. And by solving that you learned the impact this might have on modeling and loading the blog posts in the first place.
Next, you implement the asset loading. First, you’ll need to define where assets to a blog post are stored and how you then identify them. Then, you realize that media assets also need URLs which should be based on the file name. Maybe it’s also a good idea to not have UTF-8 characters in the file names. And of course, we need a mapping from file names to final resulting URLs on the blog page.
What we learned here: we need to replace pointers to assets in the blog post content with the final URLs the assets have later. This piece of knowledge has a significant impact on the markdown parsing: we need to know the mapping there and should use a library that is capable of replacing those URLs. We don’t want to use regular expressions for such a task, do we?
Although modeling and loading blog posts seemed easy at first, the heart of the blogging platform (dealing with assets and pagination) imposed quite some constraints on these simple tasks. Imagine what would have happened if we started with the easy tasks in the first place. Once we had gotten to the pagination, we might have had to go back to the model to make some adjustments, creating that spiral of adding more and more complexity to things that were already built. And as they had already been built, you would not necessarily have made the right architectural decisions as you were unaware of the challenges to come.
In conclusion, tackling the biggest challenges first saves you a lot of changes, refactorings and crappy code in the long run. On top of that, you also get better at estimating the project health and timeline, as big challenges usually have more surprises than easy tasks. But keep in mind that it is very tempting to start with easy tasks: you don’t have to cope with problems, they are easy to accomplish and you make progress very fast. And in order to do so, constantly evaluate which task to tackle next by asking the question:
What is the biggest challenge here?
If you identified the biggest challenge, go for it! The biggest challenges are the most exciting ones and the project has the highest benefit from you tackling those. Win-win I would say.