I am in a slightly similar situation(code is probably much better quality, but we just now dropped support for .Net 1.0)
What we do that works well for us is refactor as we go and spend any free time refactoring. So... Say, you have a function which puts the title on the page or some such. Now, your boss needs you to alter that title function so that the website's name is included in it, not just the specific page. So, you go to fix it and find that there are 5 different Title functions which do similar things. You should refactor those to 1 function so you don't have to fix it in 5 places. You might also find that a PageTitle class might need to be made instead or something
I'm sure some people will disagree with me, but sometimes, working code is good enough. If you have a huge 1000 line method that you haven't had to change in 5 years, and it doesn't cause big integration problems, why change it? Most likely it won't be touched for the next 5 years after you refactor it as well. You really need to have priorities when refactoring on a schedule. This is the general order I follow
- Code that I'm currently modifying (usually scoped to a class or two)
- Code that I don't necessarily have to modify, but that causes integration pains in code I'm having to write.
- Code that is difficult to read
- Code that is not easy to read, but never breaks.
- (ie, never usually) code that could be cleaner, but otherwise is decently readable and modifiable.
Real life example of these priorities. There is a parser in the product I maintain that is generated from a grammar file using some tool. It's the most horrific code I've ever seen, but it hasn't been touched in 5 years or more. I don't expect to ever have to touch it either because it's never broke. (and we have tests to make sure of that).
However, we have a very big pain point in our .Net 1.0 to modern conversion. Some genius decided to use
IEnumerator instead of
IEnumerable throughout the code base. This prevents foreach loops from working. Almost every chunk of code I write I end up coming across needing to use one of these IEnumerator's. Instead of continuing to use this anti-pattern, I fix it. Always. Sometimes, it requires modifying 50 or more lines of code, but it's something that lowers technical debt where it matters.
And I'll leave one last point. USE VERSION CONTROL. Trust me! If you're the only maintainer and management doesn't care about it, then use git or mercurial. You don't even need a central repository for these and still get most of the benefits. Version control is invaluable when you decide to embark on refactoring something and find out it significantly breaks things. With version control, you roll back the last commit. Without, you cross your fingers you made a copy of the directory recently.