Advertisement

How to overcome design paralysis?

Started by May 07, 2020 06:25 PM
4 comments, last by Alberth 4 years, 6 months ago

In an engineering context, how do people deal with analysis paralysis? I often find myself with design paralysis, as I often try to find the best practice for a given problem. But given my lack of experience in a given domain, I often do not know what the best course of action is purely out of ignorance. In this regard, requirement gathering is often a painful process as I often do not know what my technical requirements are or should be. I know what the project is at a high level, but have trouble nailing down the technical details (what’s the best architectural pattern? How should the game loop handle time? etc ). Often different design choices are suited for one kind of problem and have different implications. Researching the problem sometimes only makes it worse, as the solutions that I do often find either do not suit my needs or might be overkill (Ultimately though, I am often unsure as I am inexperienced and I would not know what a good solution looks like). I often am unsure what the long term implications of a particular design decision will be. If given options between A or B, and I pick B only to find out months later I made the wrong decision, the prospect of having to rewrite months of work scares me.

One of the common road blocks, as far as game programming, that I often run into is memory management. At the beginning of my last project, I often had it in my head that I had to develop a memory management scheme as most of the game programming literature I read touched upon custom memory management. But upon further research it dawned on me that creating a memory management scheme only really made sense in the context of console development as memory is a scarce resource in that environment compared to a PC environment (The project was supposed to run on PC only). This upon other design choices such as deciding upon the right architectural pattern paralyzed me to the point where I eventually abandoned the project.

How do most professional engineers deal with finding the right solution that suit their needs? Is it just a matter of trial and error? A strong willingness to rewrite a lot of code.

Genesis111 said:
How do most professional engineers deal with finding the right solution that suit their needs? Is it just a matter of trial and error? A strong willingness to rewrite a lot of code.

I used to have analysis-paralysis a lot at first. Experience, trial and error surely plays a large role in getting over it. Also willingness to refactor is a must. As well as willingness to just get going, and try out something even if it won't be perfect. If you are really stuck, take a break, go for a walk, do something else.

Other things include:

  • Using version control. Being able to do things that you can cleanly throw away, as well as always knowing you have your old state is paramount.
  • Having a set of established ways to do it, or “patterns” if you will. In my engine I can easily integrate new solutions since I have certain ways of doing it and a certain infrastructur for. ie. binding stuff to the scripting-side, integrating systems and communicating between them and so on
Advertisement

@Juliean

How do you find the right performance metrics for your particular project or use case? Is it just a matter of writing code, measuring/profiling the code, then rewriting it. Making sure that the new recorded metric (execution time) is better than the last? When do you know you have reached the desirable outcome?

Genesis111 said:
How do you find the right performance metrics for your particular project or use case? Is it just a matter of writing code, measuring/profiling the code, then rewriting it. Making sure that the new recorded metric (execution time) is better than the last? When do you know you have reached the desirable outcome?

I have a very light approach for performance. I try to avoid writing code that is obviously inefficient, but I usually do not bother too much to design for performance upfront. Working in C++, a few thingsI follow is no repeated function calls, trying to move heavy work outside of loops, using vectors/array whereever possible, trying to stay on the stack/etc… And if I find a system to be too slow then yes, I refactor. Using DRY and proper abstraction layers makes it easy to refactor for performance.

Other than that, my performance metric is “fast enough”. Loading my engine+game takes 3s in debug mode? Fast enough. My game+editor being rendered at 700 FPS? Way fast enough. My most complicated node-based graph rendering at 50 FPS? Actually still fast enough, but can be optmized. Every search in the asset-view takes 3s? Thats too slow, so I optimized it and now it barely takes a few ms.
Kind of like that.

Genesis111 said:
I often try to find the best practice for a given problem

I am not sure this even exists. If you look at the wide variety of how different people solve the same problem in wildly different ways, at least you can conclude we haven't found it yet. This is also what you found, although you may not realize it:

Genesis111 said:
Often different design choices are suited for one kind of problem and have different implications.

So I have one problem, and there are several best practices to solve it????

What I think is happening here is that “problem” is badly defined and never the same (or you would simply pull a previous solution from the shelve), “best” is ambiguous (many people think performance is problem #1, I think my own time spent on the problem is #1), and last but not least, the person translating the problem to a solution is never the same. Different people have different experiences and different backgrounds, and react differently to the same question / challenge / problem statement. That means if you get the same problem for a second time, you will write a different solution. If you get it for a third time, you will write again a different solution, etc.

I don't aim for best, I aim for “any sufficiently working solution that is simple". Since for a new problem, I typically have no idea what that is, I just design a solution that should work, that is, all things that need to be done can be executed. I avoid known bad solutions, and that is basically it. Coding the solution is not thinking, it's just typing text (programming is not typing, it is knowing what to type). Typing provides the proof that the solution is actually complete and consistent.

I assume my design is flawed in unknown ways, coding is thus the way to find the flaws!

I start with some random core part that I am not so sure of. (I work under the assumption I will find flaws, so I aim to find them as fast as possible by checking the least understood parts first.) In the first few attempts, my assumption will appear true, and I realize at some point while typing that I over-looked some aspect. This is great, I learned about a new relevant part of the design!!

So I found new information (a new “known bad” to avoid). I incorporate that in the solution, and try to find more flaws. In this way, I create a bunch of core parts, until I fail to find new flaws and run out of parts of the design I am not so sure of.

At this point, I have reasonable trust in my solution, and I can code the entire thing. As the whole is greater than the sum of its parts, it sometimes behaves in new and interesting ways, but that is then normally about how different parts work together.

Genesis111 said:
I often am unsure what the long term implications of a particular design decision will be. If given options between A or B, and I pick B only to find out months later I made the wrong decision, the prospect of having to rewrite months of work scares me

It happens to me as well. Every problem is unique, so basically we're clueless how to solve it. There is really no hope to solve a novel complicated problem in an optimal way in one attempt. [ It takes courage to acknowledge that (also to yourself) in a world where we should be professional and knowledgeable about everything. ]

The important part here is understanding why B was a not so good solution. That is, what “relevant part of the design" did you miss?

Most of your scare is in your perception though. If you aim for “perfect” you will never be happy, since it is unknown whether there exist better solutions. I aim for “do a coding experiment to see if it works”, and then it is far simpler to accept solutions with flaws. If the flaw isn't fatal but just cosmetic or performance, I accept it as a “mostly successful experiment”, and I take the new knowledge as something to try for the next time I run into a same-ish problem.

If it is fatal, then I have made real progress! A new very hidden property of the design has surfaced. That is, new deep insights into the problem have been found. This is not something you could have known beforehand, the problem is simply too complex to see everything, although it doesn't feel that way when you find it.

Usually there exist fixes here to make the flaw non-fatal at the cost of something (usually performance, but “sufficiently working” is wide enough for that), so you have a working program, but the next time you get the same problem, you will avoid the newly found flaw.

This topic is closed to new replies.

Advertisement