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.