I've carried this "method" with me since I was in high school (when I first programmed in more complex development environments) and even after many years of professional practice, I still return to it in some situations, or advise more junior colleagues according to it.
Imagine one of these situations
etc.
At the beginning everything looks smooth, the work goes fast, you make the functional changes you need, you remember some related functionalities that need to be changed at the same time, at the end a little refactoring to make the code more readable... Of course, you don't expect everything to work flawlessly the first time, but when you want to start testing, suddenly something comes up that you absolutely didn't imagine - again, choose one or more of the options
(you may think of many other similar shock moments)
What to do in such a situation? It's similar to when you get lost while walking through the woods, you basically have two basic approaches.
Approach 1: I'm convinced I've done all the right things, I'm 95% going in the right direction, maybe I'm just a little off course, but when I look around and think about it, I find a path a short distance away that I should have taken the right way.
Approach 2: I'm human and I make mistakes. It could be that for a few miles I've been going in the complete opposite direction I should have been going. It's not certain that there is passable terrain between my location and the trail I was supposed to take (and private property with a loose dog isn't ideal either). The safest thing to do would be to return to the last place I was sure I was on the right path even though it's annoying to admit to myself that I lost a lot of time. Actually it doesn't have to be just wasted time, I can learn something after all. If my anger switches from irrational to useful by the time I return to the fork in the road, it can activate my mind and memory to pay attention and remember what led me astray so that I'll be more careful next time.
Let's get out of the woods and back to software development.
Most of the time it's hard to suppress your ego, so we start with Approach 1.
This usually means trying various random things at a fast pace (because my mind is always set on the fact that I'm "almost done")
However, from my own experience, I recommend strictly limiting the time and space for Approach 1. (Unless you're an ultra-runner.)
Approach 2 is actually the universal method this article is about.
Its principle is based on 2 basic states:
State A can be the code currently merged in the main branch (if it works in my local environment) or conversely my local code that worked before I pulled my colleagues' changes, it can also be the environment configuration that the application works with e.g. on the CI server during integration tests or at my colleague's machine, or even a "Hello world" demo application that shows how flawlessly the framework or development environment that I am starting to use works.
Once I verify that state A works as expected, I can get started. I try to approach in small steps from both sides (like building a bridge). I can try a binary search, that is, I go about halfway from one side and verify whether I am still on side A (working as expected) or side B (surprising). If I've gone too far, I'll go back and try a smaller chunk or try going from the other side.
In this slow but systematic way, I gradually hit a stumbling block, that is, exactly the small change that causes the application to not behave as expected.
When I used this method as a student, I used to say to myself "desperate people do desperate things", in time I will know more and I won't have to do it this way.
Today I see that one can get into (almost) desperate situations regardless of the number of years of experience. The world of software development is changing so fast, and there is so much legacy software in use, that almost every system contains so many variables, many of which are unknown or easily forgotten, that (at first glance) "unexplained behavior" is never completely avoided.
The "universal method" described in this article not only serves as a safety net when everything we think of in the first few minutes fails, but we can also derive several lessons from it that can help us prevent instances of unexpected unexplained software behaviour.