First, do no harm.
You are faced with a system that works, at least to some extent. It may have huge problems, it may be unmaintainable, but it works, and it keeps the business running. Without a running business, the code has no meaning, so don't kill the business.
Several practices can kill the business:
- A big rewrite can take so long that the business can't adapt to changing conditions in the middle, and the business may fold before the rewrite comes out. Just ask Joel how this can turn out
- A big-bang implementation has huge amounts of risk all in one big implementation. If you've gotten anything wrong, it may be hard or impossible to recover. How will your business be if you cannot fulfill any orders during your busiest time of year?
- There's business logic in the old code that is there for a reason, even though none of the people who understand why it's there are still with the company. A rewrite may not notice the pieces that need to be maintained.
Be surgical and incremental
The best thing to do in this case is to work in very small pieces. When asked to add something to the existing system, take pains to find the smallest possible change that will do the job while minimizing the impact on other portions of the code. Use these tasks to learn the system and understand which portions of the system are subject to frequent change and which are fairly static.
Let sleeping dogs lie. Some parts of the system are ugly, but since they work and are never changed, they should be at the bottom of your list for improvement. Changing these pieces mean you add risk to the business, but no real benefit.
Plan for parallel processing or rapid backout. When you find an area that changes frequently, is important to the business, and really needs to be improved, how do you do it? Very carefully. At a minimum, you should make it very easy to take your rewrite out of the main processing if there is a problem. It is much safer for the business to make big changes if you can flip back to the time-tested legacy code in minutes than if you risk being stuck in a broken state for hours or days. It is even better if you can run both paths at once and prove that the new code produce the same (or better) results as the existing code.
Looking at all these tips, the more you can break the system into discrete bits the more successful you will be at improving the system.