I've been asked more than once by junior coders: "When will I start feeling like I know what I'm doing?" They're not usually prepared for my answer, which is "never."
It's a field where comfort with discomfort is crucial. I doubt it's the only one - I think it's true of any craft that requires managing uncertainty - but I suspect that it's magnified in programming because of the particular opacity of misbehaving computer systems. The most frequent output of something misconfigured or mistyped is unintelligible technobabble, and the actual challenge is correctly mapping vexingly unhelpful outputs back to the system's internal operation, and then, as a second step, identifying the original mistake. Very little of programming is building new things; most of it is figuring out why the thing you built didn't work.
So I understand the frustration. Programming isn't a uniquely difficult skill to acquire, but the chief antagonist most days is yourself. It's natural to ask when that stops, and probably confusing to hear that it doesn't. I'm not sure how much of this difficulty is essential (as opposed to accidental). My hunch is that there is some of each: The difficulty is essential insofar as programming entails generating novel solutions to novel problems, and accidental insofar as tool developers are lazy.
In a pleasing recursion, sometimes the tool developer is the programmer herself. Fortunately, we can fight our own laziness! I have long argued - especially to the juniors forced to listen to me - that we should minimize the vexing opacity of the systems we build by focusing first on their legibility, and only adding correctness as a followup step. There are three reasons for this:
- Correctness can be built atop legibility far, far more easily than the reverse.
- The definition of correctness can change over time.
- Correctness cannot always even be identified without sufficient legibility.
But we are now a few steps beyond the simple doing of a thing that the apprentice expects from her apprenticeship. She is in a bind; if her solution is simple, its failures will be unintelligible; if its failures are intelligible, it must have been constructed fractally to simultaneously solve the original problem and fill second-order diagnostic lacunae. The novice finds this hard because it is. But it will never stop being hard.