The article was decent, but the debugging section offers no insight at all. Shotgun debugging is a strawman, only the incompetent rely on that. Of course you should identify the exact line causing the problem, and of course it should be fast on average, but sometimes it is exceedingly difficult. Bugs come in three flavors:
Trivial bugs where available evidence points directly to a cause. The scope of these increases with experience, but most bugs that come up in day to day coding are of this variety.
Deep bugs are reproducible, but require bisecting the problem to figure out the cause. Performing optimal bisections requires skill, experience, and raw brain capacity. This is where a good, but let's say, not virtuoso developer can distinguish himself from his less-than-average colleagues in a major way.
Heisenbugs are the most difficult because you can't reproduce them, either because it's a concurrency problem or some limitation of the environment the bug occurs in. To solve these bugs, a functional language and pure mathematics may be the best way to get reasonable assurances that a bug is gone, but also radical creativity in code instrumentation or expensive test scenarios with dedicated hardware may be necessary.
So, yes, being a productive programmer requires a level of skill where most bugs are trivial. But nevertheless, the second two flavors exist no matter how smart you are, and being productive over the long term means being able to tackle those systematically, even if it takes days or weeks to solve, and if all else fails, figuring out a workaround.
Debugging offers a most excellent opportunity to practice science - Observe, Hypothesize, Test, Repeat. And just like regular science, bugs span the entire range of trivial to the head-explodingly-elusive.
Observation is in particular quite a hard practice. On several occasions I've realized that the evidence was staring at me in the face from day one, but my eyes were too clouded to see it. Sometimes, it helps if you know the system inside-out, but at other times that itself happens to be a blinding disadvantage.
Sometimes you can find concurrency bugs by reading logs during concurrent execution, along with a lot of sanity checks that throw exceptions when things go wrong. You can also just look really hard at the code and simulate in your head what might go wrong.
IMHO, the hardest bugs are the ones where you have too much data and/or running through the test case takes a very long amount of time. Usually the best way to chip away at these is to try and speed up the test phase by mocking things or to just do a good old stare at the code until the bug shows up. It's a cut once, measure twice approach except with time. You can either run the test again, or you can stare at the code for twice as long and not have the run the test multiple times.
One of the most interesting bugs I've seen was in a small Arm single board computer powered Lego robot. The robot would work fine for minutes at a time and then suddenly die. When used outside of the arena area it was designed for the problem went away.
We eventually traced the problem to the metallic tape used to define features in the arena. When the metal roller at the back of the robot touched this after a few minutes of operating it caused a static discharge which stopped the computer!
Trivial bugs where available evidence points directly to a cause. The scope of these increases with experience, but most bugs that come up in day to day coding are of this variety.
Deep bugs are reproducible, but require bisecting the problem to figure out the cause. Performing optimal bisections requires skill, experience, and raw brain capacity. This is where a good, but let's say, not virtuoso developer can distinguish himself from his less-than-average colleagues in a major way.
Heisenbugs are the most difficult because you can't reproduce them, either because it's a concurrency problem or some limitation of the environment the bug occurs in. To solve these bugs, a functional language and pure mathematics may be the best way to get reasonable assurances that a bug is gone, but also radical creativity in code instrumentation or expensive test scenarios with dedicated hardware may be necessary.
So, yes, being a productive programmer requires a level of skill where most bugs are trivial. But nevertheless, the second two flavors exist no matter how smart you are, and being productive over the long term means being able to tackle those systematically, even if it takes days or weeks to solve, and if all else fails, figuring out a workaround.