Declare the proper type of each variable. Accompany this definition by a comment that explains the actual meaning of the variable. For example, `meshpoint index in the x-direction along the bar' when you declare j to be an integer or int). It is much easier to figure out a computer code when you know the meaning of each variable.
In C, a typedef can be used to declare a new variable type; for example float can be denoted by real. That can make it simpler to change the precision later. The disadvantage is that the code becomes harder to read.
Simple typos such as `l' for `1' or `O' for `0' can be surprisingly hard to find. In FORTRAN, use an implicit none statement if your compiler allows this. (Some compilers allow an equivalent command line option. Study the documentation of your compiler and use it if available.) The chance of bugs in your program will be greatly reduced.
Define the bounds of arrays as parameters. For example, you could denote the dimensioned maximum value of an index j by jdim or JDIM. In FORTRAN, use a parameter statement; in C a const int or #define. When you later want to increase the maximum problem size your program can handle, you only need to change the value of jdim. If you had to change all occurrences of the bound separately, you might forget a few. It also makes your program easier to read and understand for everybody.
For time-dependent problems, do not store all unknowns at all times. This wastes a large percentage of the storage. Storage should only be declared for a few time levels. For example, suppose you are computing a temperature T depending on a mesh point index j and a time level n. In that case, do not declare storage for all values T(j,n). For a one-step numerical scheme, which computes the values at a time level n+1 from known values at a time level n, you only need storage for the known time level n and the time level n+1 being computed. You could store the known values in an array T_old(j) and the values being computed in array T_new(j). After you are done computing all T_new values at time step n+1, you can move the computed values to T_old and start computing the values at n+2.
Obviously, since the earlier time levels are lost when you proceed to compute new levels, you must perform output as soon as you compute a time at which output is desired. The saving in storage are worth it, especially for large three dimensional problems. And for consistency, you should program this way even for small problems.
A particularly elegant alternate procedure is to store the above two levels of temperatures as T(j,mod(n,2)). The mod function returns the remainder when n is divided by 2, in other words 0 or 1, depending on whether n is even or odd. In this form, the dependence of T on n is still evident. Further, there is no need to move the computed values each time to the storage locations for the known values.