As a developer you constantly get stuck. Just as you fix the problem you are currently having, you stumble into something new. Sometimes it’s something small like a tricky error that pops up into the console. But sometimes it’s a bigger architectural problem. Example of such architectural problems are the following:

Q: Where should I put my state? A: 2 options for putting it in React components. Or use Redux. Or Mobx. Or…

Q: Where should I put my logic? A: Container components or actions creators or util libs or…

Q: How should I do testing? A: You have 5 options for assertions, 4 for stubs, 3 for spies, 4 test runners…

These types of problems are tough because there is not only one correct solution, but for every problem, you have a list of several idiomatic ways to solve the problem.

Which solution should you pick? Ideally, you want just the one idiomatic way to solve your problem, but instead, you get a long list of options without guidance on when to choose which one.

The question you ask yourself is important

So when you run into a problem you ask yourself the question “What’s the most correct/idiomatic way to solve this problem?”. That question can many times help you solve the problem you have, or lead you in the right direction. But it can also be leading to more confusion than clarity, as we have just seen.

Judge a man by his questions rather than by his answers. - Voltaire

The real world is complex, and finding a suitable solution requires that you look at the problem from more than one angle.

The way you do that is by asking many kinds of questions. Here are some examples of what I usually ask myself when facing a problem:

1. “What’s the simplest thing I can do?”

Sometimes it’s necessary to create Redux Store and Actions with Thunk Middleware to do Ajax requests - and sometimes a 4 line HTML form-tag is enough.

Don’t always reach for the “correct” and fancy solution, but pause and reflect on what is the simplest thing you can implement to solve your problem. A simple solution is more maintainable, has less risk for bugs, and usually most elegant. And also quickest to implement.

2. “What kind of problem am I trying to solve?”

Performance problem?

A feature where time to market is critical?

Is it a proof of concept?

Internal tool?

For learning?

If learning is the goal, you might want to write two or three different implementations of the same feature just to explore and compare. If time to market is important, you might go for the quickest implementation, even if it’s “wrong”.

3. “What level of competency does my teammates have?”

Many juniors? Seniors only? If you will recruit more devs, what are their profile? These are the really important question to take into consideration because it says something about the level of “smartness” and room for creativity you will allow the codebase to have.

4. “Can I make a decision now, and revisit later?”

There are circumstances where the best thing to do is make a good enough solution, and revisit it later. If you think you are going to make it perfect on the first try, there is a risk you will over-engineer and as a consequence make the code more complicated than it has to be.

You don’t yet know how the codebase will develop. Maybe that piece of code wouldn’t grow as big as you thought. And maybe the feature gets removed from the product completely in a month. (this has happened to me many times)

Use this question with caution! You don’t want to throw in a lot of quick fixes all over the place. There is a balance.

Conclusion

Every application is unique, and going for generalized solutions is not always the best approach. To find the best solution for the problems in your application requires you to think further than the official documentation and tutorials.

Now you have a tool which takes into consideration many variables to find specialized solutions which will lead to more readable and more maintainable code.

(this post has been translated to Korean here)