Have you ever felt stuck on a project because you had too many options before you, and there was no crisp, clear-cut path to be found? Every option had pros and cons?

That is the nature of the beast with engineering. There are always pros and cons to consider with any approach. That means there is no such thing as a perfect solution. Furthermore, there is often more than one possible solution.
All of this can be a bit paralyzing when you are suddenly faced with higher levels of complexity. If you think in binary terms where there is only right vs wrong or good vs bad, managing higher levels of complexity will become untenable in your software projects.

How do you know which path is the right one to choose? There is no silver bullet. The truth is comparing solutions depends heavily on context. Finding an appropriate solution becomes an exercise in maximizing pros and minimizing the number of cons based on that context.
In other words, there is a lot of gray area when it comes to designing complex systems. You have to develop a tolerance for trade-offs and the ability to think in the gray area when you are evaluating options.
So, how do you do that? One small step you can take toward getting better at managing complexity is to practice timeboxing.
What is Timeboxing?
The practice of timeboxing is essentially planning out a list of to-dos or tasks and adding a time limit to each item. As you move through the tasks, you stop working on a task when its time expires.

There are four skills you exercise in timeboxing that are also useful when dealing with complex and ambiguous directives.
Define a Target
First, timeboxing requires you to define a clear target at the outset.

Before you begin working, you make a choice about what you would like to accomplish. Whether or not you hit the target, you at least know where to aim. Setting that intention automatically cuts through some of the initial ambiguity.
Divide and Conquer
Next, you need to create a list of tasks to work on. Expressing your overall objective in the form of a list of tasks requires you to think about how to break the objective down.
The added time restriction also supports the notion of breaking down larger goals into smaller, more manageable pieces. When you get in the habit of limiting the amount of time you spend working on tasks, you start to develop a feel for the level of difficulty of certain types of work.

Knowledge of how difficult tasks are improves your ability to align chunks of work with time slots. If you sense a task will not fit in the allotted time block, you know you have to break it down even further.
Dividing a complex problem into smaller problems is a core tenant of problem solving. It is a powerful tool to make something that seems ambiguous or confusing more concrete.
Push Through Analysis Paralysis
In addition to helping you structure large goals into small tasks, the time constraint also pushes you through any tendency to over analyze options or hold out for perfection.
Timeboxing makes you more aware of resource limitations. You do not have an unlimited amount of time to work on a task, so at times the system will force you to stop working before you feel ready.
From there, you can decide to move on or to reload that task into your list and work on it again. Taking this step of considering the value of continuing work on a task is a step in the direction of learning to operate in the gray area. Maybe it is a good idea to keep working on a task. Perhaps it is not a good idea…it depends.
Build a Record of Performance
Finally, when you consistently practice the timeboxing system, you generate a data log of your progress over time. You can review this log to better understand the patterns of how you work.
Timeboxing is an exercise in defining metrics and tracking those metrics in order to gain a deeper understanding of the overall problem you want to tackle. When you analyze your data log, you will find ways to improve your process.
This iterative approach to developing an ever evolving and improving solution to a nebulous problem is another useful skill for dealing with ambiguity.
Conclusion
One part of growing as a developer is learning how to manage increasing levels of complexity or ambiguity. Managing large ambiguous problems is an exercise in balancing pros and cons.
The timeboxing technique may not necessarily be the best way for you to work at all times. But when you do use it, it provides a safe environment in which to practice some of the same skills you need to improve your ability to manage big, hairy problems.