> This one really frustrates me. Write code to the complexity level needed to solve the problem, and nothing more. The only time I'd break from this is if I know for certain that the added complexity is going to be necessary in the near term.
Mastery will be, when you write code in a way, that does not impose unwarranted limitations from the start, and still keep it readable and only containing mandatory complexity.
Usually this can be achieved through deep understanding of the problem, mapping to simple concepts or finding or making that one concept that captures things well.
Not always it can be done. Not always can a masterful solution be found, which keeps complexity low. However, it is definitely a mistake to draw a black and white picture of "if you want to make it work for the future, you must add complexity". Often people simply choose bad abstractions or wrong ones and will only realize, when the future has become the present and the system they built cannot fulfill some requirement.
> Often people simply choose bad abstractions or wrong ones
When writing software, ideally I'd like to make all the right choices and use simple implementations of abstractions that do not impose unwarranted limitations.
I think that it's sometimes worth it, early on, to do things the quick way despite bad abstractions. This can get you to a place where it's easier to reason about good abstractions.
Sadly, I've been on teams where a bad abstraction was adopted because it was just assumed that that would be quicker. Instead of doing it the quick way, we just did it the bad way.
We write abstractions to tame complexity. But abstractions themselves are inherently a form of complexity. A good abstraction may be simple to use, understand, and extend, but it can also make it harder to understand or debug issues because underlying data/state has been obscured. I agree that making anything "black and white" is a mistake. I merely said what I said because in my experience, most developers tend to abstract things that don't benefit anyone, and add unnecessary complexity. Besides, if you're writing an abstraction for a future hypothetical problem, chances are that you don't have enough information to create a good abstraction, and you're going to have to redo it anyway.
> Often people simply choose bad abstractions or wrong ones...
This is me. They tend to lead me to good abstractions (after merciless refactoring), and I'd like to think that I'm sucking less at this over time. But my overall process is very slow (good thing I'm self employed). Understood that it'd be better to stop and think instead of diving into new-abstraction boilerplate work.
Worse though is to be under heavy pressure to ship and move on — with the bad abstractions getting hopelessly calcified / buried.
Mastery will be, when you write code in a way, that does not impose unwarranted limitations from the start, and still keep it readable and only containing mandatory complexity.
Usually this can be achieved through deep understanding of the problem, mapping to simple concepts or finding or making that one concept that captures things well.
Not always it can be done. Not always can a masterful solution be found, which keeps complexity low. However, it is definitely a mistake to draw a black and white picture of "if you want to make it work for the future, you must add complexity". Often people simply choose bad abstractions or wrong ones and will only realize, when the future has become the present and the system they built cannot fulfill some requirement.