One resource is the fortran-lang tutorial: Organising code structure - Fortran Programming Language
If available to you, I would recommend the latest edition of “Modern Fortran explained” by Metcalf, Reid & Cohen, chapter 5 - Program units and procedures.
A second option would be “Guide to Fortran 2008 Programming” by Walter Brainerd: Guide to Fortran 2008 Programming | SpringerLink. Perhaps you can access the digital version with your university account.
The keyword contains
is simply used to collect internal subprograms (subroutines and functions) in a main program or module:
program main
implicit none
! ... declarations ...
! ... main program unit commands ...
contains
! ... internal subprograms ...
subroutine runge(...)
end subroutine
function dydt(t,y)
end function
end program
Instead of placing the procedures in the main program, you can place them in a module:
module flow_solver_routines
implicit none
! ... declarations ...
contains
! ... internal subprograms ...
subroutine runge(...)
end subroutine
function dydt(t,y)
end function
end module
that you then use in the main program as follows:
program main
use flow_solver_routines, only: runge, dydt
implicit none
! ...
call runge(dydt,tstart,tend,y)
end program
In fact even subroutines and functions can have procedures nested in their own contains
section.
On the other hand, your old program used so-called external
subprograms, i.e. subprograms that are not located within a program unit or module. External procedures were the norm in F77, but since F90 modules are the preferred approach to organize your (sub)programs.
When using internal subprograms the compiler can check you are calling the function or subroutine correctly since the interface is visible. Internal subprograms also have access to the objects in their host program, which can be useful for many things.