A Fortran 90 program must contain a main program where execution begins, it could also contain other user-defined procedures which may be:
A complete program can be self-contained (that is only call internal procedures) or can make references to other program units (external procedures or module procedures).
FORTRAN 77 only had one type of procedure which is known in Fortran 90 as an external procedure (so called because an arbitrary program unit has no knowledge of the internal structure / argument types or sizes of another procedure). In FORTRAN 77 procedures can be compiled separately and then linked with an other separately compiled FORTRAN 77 program unit at the time that the object code is generated. This method is very flexible but does not lend itself towards efficient optimisation. There was no possibility of checking that the type of the corresponding dummy and actual arguments match (a fact which was abused by people who used this shortfall to change the type of an object across a procedure boundary) nor was there any possibility of checking that the size of an array is the same in the calling and called procedures. Arrays were passed by relying upon storage and sequence association and their bounds had to passed as actual arguments. This means that, in a procedure, an erroneously declared array (too large) may end up containing meaningless bits of other variables in its last few locations or that dummy arguments following an incorrectly sized array (declared too small in the procedure) may end up holding rubbish which should have been the last few elements of the array. In short -- all sorts of mistakes can be made and never get spotted.
Fortran 90 has addressed many of the above mentioned problems so procedures now look very different.