Breden,
There are two philosophies when it comes to Program Maintenance.
The first says, "It is what it is, so go with it!"
The corollary to the first says, "If it ain't broken, don't fix it!"
The second philosophy, my philosophy, is, "Look at it from the point of view of a reasonably rational Process Developer who understands program maintenance. If it looks goofy, BREAK THE DAMNED THING AND THEN FIX IT - RIGHT!"
The following complete description is aimed at the second philosophy.
However, if you aren't will or capable of going that far, the description will also support the first philosophy and its corollary.
Regardless of which philosophy you choose to follow, if you want to do this right, you have to put in the time to study and know your process and how the program controls it.
That means dissecting the process and the program and really learning how they work.
I would say, before even looking at the code, the first thing is to organize your understanding of how your process works physically. Try to classify major portions of the process in terms of "modules". That is, break the physical process down into a few (several?) basic, high-level, process-modules (these are usually not individual hardware components).
For example, a Punch-Press System might consist of a Loader, a Feeder, the Punch, an Extractor, a Stacker and a Wrapper. Each of those is a high-level process-module consisting of several hardware components (Outputs).
Then try to find the next level of modularity within those modules. Repeat this process until you are down to the actual output devices.
The purpose of this approach is to provide a simple, organized guide for yourself while you are trying to decipher the code.
Now, without using your guide, simply browse through your code and try to get a "feel" for how it is layed out.
If you have skeletons in your closet and/or you have been bad, then you'll probably be faced with spaghetti-code... without comments. (This is not good.) On the otherhand, if you've been very good, you might find well-commented, modular code. (This is very good.)
I'd like to say... "The odds are, the code will be somewhat well-commented and somewhat modularized." However, there are as many different ways to code a program as there are programmers... raised to the second?, third?, fourth?... power.
If you find that the code is organized in anything but "modular" form, then, until such time that you are capable enough to begin re-organizing the code, you are gonna have to maintain a hand-made (by pencil & paper, or word-processor) copy of the code.
You should organize this copy to follow your "Module Guide". Each rung that you enter on the hand-made copy should maintain the original rung number as it exists in the program.
The more "spaghetti-like" the code is, the more radical a difference you will find between the original code and your "organized" code. The more "modular-like" the code is, the less radical the differences will be.
At this point, I do not suggest that you simply make a copy of the program and re-organize it to follow the module-guide. If you do so, you will lose the current rung-relationship between the various rungs. Re-organizing a copy of the program, if it is necessary, will come later.
Once you have all of your hand-made rungs organized (with original rung numbers) to follow your module-guide, now you have to go into each section of code and find out how it "really" works.
This might involve reverse-engineering some of the logic, or breaking open the books to find out how a particular operation or function works. Sometimes, very low-level bit-manipulation is very hard to discern. Sometimes you have to BE THE COMPUTER, play the game through, and then see where the game leads.
One way or another, you have to crack-the-code and figure out how and WHY things actually happen the way that they do.
All the time that you are discovering how the damned thing actually works, you should be considering how the damned this SHOULD work!
At this point, you should have an understanding of how your process works and how it is controlled.
If you find that your code is reasonably well organized, then there is no need to go any further with the discovery/repair process.
On the otherhand, if you find that you have some degree of spaghetti-code (less than acceptable modularity), and you find it is objectionable (in terms of program maintenance), AND you find that you have the guts to re-write major portions of code...
...then, you need to make your plans. How can you introduce these changes with the least amount of interference on Production.
I do ALL of my process changes ON-LINE while the process is running.
I use a technique I call "Shadow-Code".
Shadow-Code is a duplicate of running code, albeit, in a different form. Shadow-Code does not control any actual Outputs. It does read all of the conditions that the current code reads plus any conditions that are unique to the Shadow-Code.
I include many "traps" and "monitors" to ensure that the Shadow-Code is doing as it should.
In those rungs that are intended to be replaced by the Shadow-Code I include a "switch-over-bit".
If I find that I am satisfied with the performance of the new code (Shadow-Code) I turn ON the "switch-over-bit". From that point on, the outputs are controlled by the new code.
I let the new code run for a few days before clearing out the old code.