There’s a motto in agile software development that says “You aren’t going to need it,” YAGNI. The idea is that when you’re tempted to write some code based on speculation of future use, don’t do it. (I go into this a little deeper here.)
Although “you aren’t going to need it” is a good principle for writing code, the analogous principle “you aren’t going to need to understand it” doesn’t seem to hold. When I try to avoid understanding things in detail, I end up needing to understand the details anyway and wished I’d done so sooner. This has been my experience in math research, software development, and project management.
Obviously you can’t understand everything about everything, and some things you clearly need to know well. In the fuzzy area in between, especially when I’ve said to myself “I hope I don’t have to dig into this,” I’ve often regretted postponing the dig.
My take on why they say that is for inexperienced programmers who create a lot of architecture for simple features. They then either don’t end up using 80% of the architecture and 3 bad things happen.
First, if a problem occurs, you have a lot of code to wade through, some of which is un-used kruft which complicates finding exactly where the error occurred.
Second, you now have more code to maintain, and most of that code isn’t even used.
Third, when it comes time to refactor, you have a lot of code to refactor for just a simple feature.
While more complex than that, those 3 reasons cover 90% of what I’ve seen. While I get what you’re saying, especially from a low-D on Meyers Briggs, it doesn’t have to do with thinking. You and I both know we need a login form, so we build one with a username and password text fields with a submit button. That will work, and allow the user to get into the application with a valid session as well as verify our user story passes. ANYTHING ELSE added to that is kruft, and does NOT need to be built.
Time and time again, I see developers building things that have nothing to do with logging in, like a remember me checkbox, multiple-login attempts via a timer inside the login service in case of network issues, mock classes to emulate the session in case we can’t do integration testing for awhile, etc.
All of those things are valid features. All of those things are not needed, at all, to login.
If you’re having to spend copious amounts of time thinking about a feature it’s (A) too big of a feature and needs to be broken down into manageable chunks (B) it’s just hard, and “thinking” and prototyping code algorithms for a solutions is a far cry from ignoring YAGNI or (C) it’s Trig and you’re stupid like me.
This reminds me of the rule of thumb that the bug is where you want least to look for it.
Actually, in busy production environments where I’ve been for some time, as others dither over ‘understanding’ a problem, I quite often come in and simply fix it. And then explain to them “fix it first, understand it later.”
Of course, my ‘fixing’ it presupposes a good deal of understanding to begin with. Often it’s the case, that what you need to do first is keep things running and then later you’ll have the time to figure out this particular variant of that particular class of problems. But that presupposes good followup which can’t be assumed for all people.
Problem with YAGNI is though that people end up writing a lot of duplicate code. When you try to solve a specific problem which requires some functionality, this functionality is often implemented straight into the code solving the problem, not into some reusable library. Now you may argue the functionality should be added to generic library at the point of need, but for many reasons this doesn’t often happen in practice. E.g. programmer working on the problem isn’t competent to implement generic reusable functionality. Or there is substantial overhead to add the functionality to reusable library. Or there is time pressure to fix the problem and not waste time designing generic functionality, etc.
Yagni is a rather good principle, to be applied with wisdom (ie. not always…).
Some people apply it aggressively, refactoring the code on each step (Agile task, for example).
Sometime, I look forward and just do the right thing upfront. Example: I write a form with one parameter, to simplify initial implementation. But I know that later, we will have several similar parameters. So, in the data structure, I store the parameter in a list (or map if name / value), to avoid changing the API too much later.
Another field where Yagni cannot be applied: libraries. If you design, say, a chart library, you have to anticipate most usages that will be done with this library. If YOU don’t need it yet, your users might need it.
Of course, you have to use wisdom (again) and avoid throwing lot of obscure features nobody will use…
And, well, ideally you should consume your library yourself (at least in a demo, ideally in a real application) to be sure it is well designed, with a good API.
I put it this way:
If you’re mind is too busy or tired to learn these details right now, stop working, go rest, have some fun and only then come back. Because there’s a 99% chance not learning them will bite you later.