It's great when software is designed and implemented with careful planning and plenty of documentation so someone can pick it up when it falls down. Unfortunately, it's often the case that a) You're working on an existing project that has no documentation, or b) You're working on an existing project that has documentation that is now out of date.
I'm doing the former right now. The software is old. Like 12 years old. It has no documentation. It has duplicated code, code where it shouldn't be, hard-coded values, code that does the wrong thing before being corrected by other code. Think of an anti-pattern and it's in there.
The application is being phased out, but it must be supported until it's completely gone. It's also in an environment where changes are inevitable and legally mandated so there's no chance of a complete code-freeze. The original programmers are long gone. It's not fun to work with.
Now don't get me wrong. I don't go in and make changes that just add to the spaghetti - I refactor when it's practical. If I'm changing some code that's repeated in three places, I'll pull it out into its own method. If there are hard-coded values that could change, I'll set them up so they're configurable. In short, I'll do some cleanup, but I'm not going to do it all. Refactoring everything would mean nearly rewriting the thing from scratch, and that's been done (hence the phase out).
So what about documentation? Writing detailed UML for this software is just not practical. For one thing, it'd be obscenely hard to do, but more important is the fact that this program is unlikely to be in use in 12 months time. Priority doesn't go to documenting legacy software. The fact of the matter is that it's just not worth the time and effort to pull the thing apart to work out how every little piece ticks.
So I've come up with my own alternative. I call it Post-traumatic Documentation.
I've set up a document that I've titled the Application Body of Knowledge. Every time I dive in to make a change or fix a bug, I'll absorb a whole lot of information about how the application fits together. There are basic things like which files do what, but most of the important stuff is in the details. I might spend half an hour working out that some assignments in method A get overridden in certain cases when method B is called, or that a class called ABC actually provides functionality for DEF and perhaps doesn't get called at all. I learn these things the hard way and I make notes as I go.
Whenever I finish one of these traumatic quests to change something small, I go through my notes and add anything of interest to my Application Body of Knowledge. There's a section dealing with the overall architecture of the application, one for each of the main modules, one for deployment, and one for general notes. It's deliberately heavy on keywords and jargon to facilitate searching.
This document is obviously far from complete, but it is immensely helpful to me when I next have to make a change, and it'll be even more helpful to the guy who takes the reigns from me when I get hit by that programmer-killing bus.