One of the most unproductive things in my software career to date has been my attitude toward legacy code. A byword for the dreaded big ball of mud, it used to fill me with loathing for my work and sometimes my job. Who the heck wrote this? Why is it implemented like that? What on Earth does this do? What does any of this gibberish mean?
Legacy code is easy to judge. I used to sit smugly in my superiority and denounce such rubbish, knowing I would never write something as bad. But I have, and I will again. Because the only place ideal software exists is in someone's head. The moment elegant design meets real world business requirements, unrealistic deadlines, and those always troublesome clients, the compromises will creep in. Magnify this over time, and you will be producing something that will one day become someone else's legacy.
So hold on, are we all doomed to produce terrible code then? No. If we stay aware of this, we can mitigate the worst of it. Write your unit tests, decouple your code, implement features the right way, and push back on unrealistic deadlines and customer demands. Accept that there will always be a few frayed edges and ugly corners to the code base though. That last minute hack to accommodate a difficult client, the weird workaround for some third party API, and the piece of code you wrote will still inexperienced in the problem domain.
Knowing that, legacy code can be approached with a more useful mindset. Its an opportunity to improve our understanding of the business rules and problem domain. To learn from past mistakes and design decisions. We can, if feeling bold, try to apply modern practices to improve the code. Read, refactor, test. Its a chance to exercise continuous improvement.
Legacy code is a challenge then. Its also a teaching tool even for experienced programmers. Rather than loath legacy code, I try to appreciate the opportunities it provides.