Stages of Transformation
When you're untangling spaghetti code, there is always a danger that
your changes will have unintended consequences, because the flow of
control may not be obvious.
One problem is that a variety of COBOL constructs may invoke any given
paragraph:
- PERFORM
- PERFORM UNTIL
- PERFORM THRU or PERFORM THROUGH
- PERFORM THRU UNTIL or PERFORM THROUGH UNTIL
- GO TO
- GO TO DEPENDING
- ALTER
You can identify these constructs by searching for the
paragraph name.
More insidiously, a paragraph may receive control directly from the
preceding paragraph without being invoked by name. In order
to know how a given paragraph receives control, you need to know how
the previous paragraph receives control -- and so forth recursively
all the way to the top of the PROCEDURE DIVISION.
Likewise you need to know what receives control when execution
reaches the end of the paragraph. Depending on how the paragraph
received control in the first place, control may or may not fall into
the following paragraph.
Until you have eliminated or at least identified all the cases
where control falls directly from one paragraph into the next, it
is dangerous to rearrange paragraphs or add new ones. Such a
change may disrupt the flow of control in unexpected ways.
It is essential to eliminate all such fall-through
logic as soon as possible.
Coping with Sections
The use of both sections and paragraphs in the same program adds more
ways to obscure the flow of control.
While we can suggest a few coping strategies,
the rest of this discussion ignores the possible existence of sections.
Otherwise the issues would be just too complicated to address in a
general way. The most we can recommend is an ad hoc approach. If your
program has sections and you can't get rid of them, muddle through as
best you can.
The Stages
The following stages represent a logical series of transformations.
Each stage makes the later stages safer and more manageable.
These stages will not solve all your problems. You will probably have
to exercise some ingenuity at some point (and ingenuity is always
error-prone). Rather, the stages provide a conceptual framework which
will reduce the need for ingenuity.
It is neither necessary nor desirable to follow these steps in a rigid
sequence. Use your judgement. Be opportunistic. In particular,
applying one of the later transformations may create a new
opportunity to apply one or more of the earlier ones. That's normal.
You may be working at several different levels in different parts
of the program.
In later stages we will get rid of GO TOs. Those techniques won't
work with GO TOs which are subject to ALTER.
Transform each instance into a case structure with ordinary GO TOs,
to which we can later apply the standard techniques.
Be greedy and knock off the easy ones first.
These are more tedious but still easy.
More easy ones. This step may render some THRU clauses trivial (or
serial). If so, eliminate them.
Establish a single exit point for each
entry point
This transformation makes it easier to apply the next one.
If you can't apply this transformation immediately in an obviously
safe way, just be patient until the opportunity arises, as it surely
will.
Whenever possible, transform fall-through logic into
GO TO logic
What??? You should add more GO TOs??? Relax. It will all
work out.
Mark all remaining instances of fall-through logic
Tend to them later, as opportunities arise. For now, insert
big prominent comments so that you won't disrupt the fall-through
by accident.
From now on it's safe to add or rearrange paragraphs, as long as
you don't disrupt the remaining fall-through logic.
On an ad hoc, case-by-case basis you may be able to pull chunks of
code out into separate paragraphs, so that you can eliminate some
GO TOs more easily.
If a paragraph always exits by one of several GO TOs, and they
all GO TO the same destination, combine the GO TOs into a single
unconditional GO TO at the end of the paragraph. Then you can
apply the next transformation.
If a paragraph has a single unconditional GO TO at the end, move
the GO TO out of the paragraph and into whatever code invokes the
paragraph.
This transformation may create an opportunity to apply the
previous one.
Transform loops to use PERFORM UNTIL
rather than GO TO.
These transformations are potentially more complex and more
error-prone than the rest. Proceed with caution.
Keep going until the GO TOs and THRU clauses are gone.
There may be a few spots which don't fit the simple patterns, and you
can't readily transform them mechanically. Often, by rearranging the
code, you can transform part of the code into a simple pattern, and
work on the rest in a later step. If all else fails, figure out what
the code is doing.
Eventually all GO TOs either disappear or percolate to the top. Finally
you might have GO TOs whose destination ends in a GOBACK or similar
construct. Let the GOBACK percolate upwards as if it were a GO TO;
then the last GO TOs can disappear.
Restructuring
Your program is now structured in a formal sense. That is, it has no
GO TOs or PERFORM THRUs.
However, it probably isn't well structured. It probably
uses cryptic flags and switches to control loops and case structures.
Some of your paragraphs are probably not very cohesive, or they don't
have very good names. Even if you have been fixing some of these
problems along the way, the job is probably not complete.
By the time you get this far you have reached a better understanding
of what the program does. You are in a good position to:
- improve the structure and the style.
- implement parts of the program in simpler or more efficient
ways.
- break the program up into two or three smaller, more manageable
programs.
Whatever changes may be appropriate, neither you nor anyone else need
be afraid to make them. You have transformed spaghetti into ravioli.
COBOL Style Forum
Spaghetti code
First stage
COBOL Home