Fortran refactoring



I wanted to share a refactoring tip that's helped me tremendously.
It's been made possible by Fortran 90.

I work on several legacy Fortran applications, with routines frequently
over 1000 lines, where the routine includes both high-level logic and
low-level details. In order to separate these, I take the subroutine
in question, add a "contains" statement at the bottom, and break it
into contained subroutines. I don't (initially) move any of the
variables, but it allows the high-level logic of the code to show
through quickly without requiring major restructuring. If the
restructuring proves useful, I then go on to break these subroutines
out of the containing subroutine, which allows me to do this process
again if I need to.

Here's an example:
!*********** START OF EXAMPLE ************
subroutine x(a,b,c)
! declarations

! thousands of lines of code (perhaps with comments)

end subroutine x
!************ END OF EXAMPLE *************

After I get done, the code will look something like this:

!*********** START OF EXAMPLE ************
subroutine x(a,b,c)
! declarations

call initialize_x

do iteration = start, finish
call process_x
end do

call log_output_x
call cleanup_x
contains
subroutine initialize_x
! the initialization code (memory allocations,
! variable initializations, opening files etc)
! copied from the original routine
end subroutine initialize_x

subroutine process_x
! the processing code copied verbatim from the original
end subroutine process_x

subroutine log_output_x
! the output code copied from the original routine
end subroutine log_output_x

subroutine cleanup_x
! the cleanup code (deallocations,
! file closing, etc) from the original
end subroutine cleanup_x
end subroutine x
!************ END OF EXAMPLE *************

Obviously, this contrived example isn't the only way to break up the
code. And in fact, I often find myself breaking the codes I have into
20 or 30 routines, because the original code had so many unrelated
parts.

If you're working in the main program, it can also contain subroutines
and functions, so this technique works there as well.

One of the key benefits of contained subroutines is that they're scoped
so that they can see all of the variables available in the containing
program. If you keep all of the variable declarations at the
containing routine level, the variables are automatically shared
between all contained subroutines. So if you've picked a poor place to
split the code (i.e., logically, it should have happened a few lines to
either side of where you actually split it), the result will still
work. This is great for a quick-and-dirty refactoring to aid
understanding of legacy code.

The obvious next step would be to group related contained subroutines
together into a module, but that's more work than this is. This
technique can be done in a few minutes (perhaps an hour for a really
big file), keeps results identical, and improves the readability of the
code almost immediately.

I hope people find this tip useful.

Any other techniques people have found to be particulary useful for
refactoring?

Phillip

.



Relevant Pages

  • Re: Fast pancake flipping
    ... excerpt of my fast flipper here. ... Recently I wrote a subroutine that seemed to qualify for the ... It is certainly true that making a routine readable is usually ...
    (comp.programming)
  • Re: What routine is running
    ... argumnent a dynamic array and, with the addition of 1 line of code in the ... sub, gurarantee the existing code will work. ... duplicating an entire routine is a terrible solution. ... if the subroutine is meant to modify the value ...
    (comp.databases.pick)
  • Re: Are these the same arguments?
    ... to do those optimizations. ... routine is using it as an array, ... routine is using the argument as an array. ... subroutine sub1([other args], x) ...
    (comp.lang.fortran)
  • Re: using optional arguments not present (bug)
    ... an attribute for an optional dummy argument that makes the dummy ... end subroutine sub ... actual argument to sub2 is always present; it doesn't get a non-present ... E.g. nearly all my procedures have an optional argument "message_log" which is passed to a message display routine. ...
    (comp.lang.fortran)
  • Using forms?
    ... I made a subroutine that calls the form with a show ... routine working now but I noticed that by default it is public. ... How can I get the remote query to complete without releasing the form? ... How can I return a value from the form to the calling program? ...
    (microsoft.public.excel.programming)