Fixing a Broken Toilet
Programming is like fixing a broken toilet.
Some people just keep flushing the toilet, hoping it fixes itself. Sometimes this works, most of the time not.
These are the programmers who restart the server every time there's a problem, or they wrap large sections of code in try-except blocks to avoid errors crashing the system. This might temporarily cure the symptoms, but it rarely fixes the problem.
Some people Google the problem, and then dump a bucket of water in the bowl or manually hold up the chain in the tank. They don't ask why they should do that, they simply follow instructions they found for a similar issue.
These are the programmers who copy-paste answers from Stack Overflow. It works occasionally, but it can also result in dirty toilet water spilling all over your bathroom floor.
(It's not a perfect metaphor.)
Some people think through the problem, research other people who experienced it, and apply those lessons to their own situation. They may end up adjusting the float valve, or replacing the tank-to-bowl gasket.
These are the programmers who functionally understand the code. Though they may not always fully understand the concepts and theory behind it they are typically able to solve any problem they face.
Some people research the modern flush toilet. They learn about float valves, pump head, and fluid dynamics. Perhaps this knowledge is not directly applicable to everyday toilet usage, but it gives them a better foundational theory when troubleshooting complicated problems.
These are the programmers who study computer science. They understand algorithms, data structures, programming paradigms, and discrete mathematics.
Some people just call a plumber.