There are (at least) 3 things that lead to bad code: 1) Poor Planning. 2) Time Constraints. 3) Mediocre (and even bad) Developers.
Planning takes time and it is difficult. We employ "Systems Engineers" to capture requirements, understand the existing code base, and then determine what work actually has to be done. Then the developer takes those plans and turns them into code. Unfortunately, and especially as complexity increases, you are going to: 1) miss things, 2) break existing things, and 3) run into conflicts that often require complete refactoring of some part of the code or an ugly kludge to get you by. On a large development effort you usually hit all 3 of those.
Time. Obviously time affects everything. There's never enough time, so it's very important to get the planning stage right. If you skimp on time with planning you will pay it back 10-fold over the course of maintaining your software. And then there's just the obvious stuff. How many of us are juggling multiple projects, bug fixes, documentation, etc. Priorities change week to week, day to day. Is it management's fault? Ultimately, yes, but their jobs aren't easy either.
Developers. Hey, most of us have been mediocre at some stage during our careers. Hopefully we all get better with age (I've only met one person who got worse) but some progress much more slowly than others. I've been coding since I was 9 (I'm nearing 40 now) and if I look at code I did even 5-10 years ago, it makes me cringe a little. The code works, but it is not as efficient or well organized as I would do it today (or so I've convinced myself).
We code in C++ where I work. Most of the developers have been coding for a long time. But they coded for a long time in 80's languages and transitioned with no training at all to C++ (which I consider a 90's language). People still roll their own lists (i.e. don't use or aren't aware of the STL), misuse the object paradigm, don't understand templates, still use pointers when they should use references, etc. Most are basically still C developers and they are perfectly competent C developers -- but we're using C++ in a highly threaded environment.
So, imagine, if you will, the state of a decade+ old code base for a massive, monolithic application which has to communicate with a (very) random and ever-changing assortment of hardware devices, protocols, etc. written in C++ by developers who never really learned C++. Also, the poor bastards that have to do the planning in this quagmire and the managers that are taking fire from all sides.
Yes, bad code is the norm (and, yes, I do enjoy my job).