Variable metrics are available for each global and module-level variable. By this we mean all variables and arrays that are not procedure local variables or parameters. The variable may be declared in a module, class or .NET Structure, but always outside of procedures.
READS equals the number of read instructions from a single variable. A read instruction is one that accesses the value of the variable or passes it in a procedure call.
READS should be at least one. READS=0 may indicate a variable whose value is not being used.
A high READS indicates a heavily used variable. This is not necessarily a problem. Once the variable has a proper value and the meaning of the value is well understood, it is safe to use it.
A high READS can be problematic at times of change. If the meaning of the value changes or it starts getting new values (beyond the previous range), the reading code may need to be updated. An unexpected value can cause many kinds of trouble, including division by zero, overflow, non-existing Select Case conditions, array sizing errors and so on. Extra care should be exercised when changing a variable with a high READS. It is a good idea to run Project Analyzer to discover the use locations and do an impact analysis by reviewing the effects of the change before actually changing the code.
WRITES equals the number of write instructions to a variable. A write instruction is one that assigns the variable a value, clears it or allocates space for an array.
WRITES should be at least one. WRITES=0 may indicate a variable that is not assigned a value.
A very high WRITES (say, over 5 or 10) indicates that the variable changes value at many locations. It is potentially unsafe coding. Care should be taken to ensure that all the written values are correct. It should also be verified that changing the value does not lead to errors in code that depends on the value — either the current or the previous value. Is the variable potentially being used to store more than one thing or the same thing in several ways? If requirements change, will all the write locations be updated according to the new requirements?
You can get WRITES down by consolidating the write instructions into a single writer procedure that is responsible for calculating and storing the value. Consider encapsulating a public variable into a property. Property Set (or Let) is a good place for keeping the writing functionality and ensuring that the variable is not given an out-of-bounds value.
RW = READS + WRITES
RW is close to, but not equal to, the total number of uses of the variable the system. A single instruction (such as x += 1
) may count both as a read and as a write.
Average RW (RW/var) is a useful metric. A high average RW indicates that variables are relatively highly used in the system. They are possibly being used as global variables across modules.
A low average RW indicates that variables are not so highly used. They are possibly encapsulated as properties. Another explanation is that the system is relatively small so that variables cannot be accessed so many times as in a larger system.
FLOWS = READS * WRITES
FLOWS measures the potential maximum number of data flows via the variable. Each write is the start of a flow. Similarly, each read is an end. The variable potentially binds all these locations together.
In the picture below, there are 3 writes and 2 reads, resulting in a maximum of 6 flows.
The actual number of flows at run-time may be lower than the potential maximum due to the execution order of the write and read instructions.
A very high FLOWS indicates a key variable in the system. It may be a risky variable in that an incorrect value can cause damage. If the code is later changed or it executes in an unanticipated order, the variable may have a different value than before, leading to error where it is read. To get FLOWS down, try to decrease WRITES first. A high WRITES is potentially more dangerous than a high READS. See WRITES for instructions on decreasing its value.
If FLOWS=0, the variable is either not read or written, which indicates a potential problem in the code (see READS and WRITES).
Notice how FLOWS is conceptually similar to IFIO for procedures.
Project Metrics also provides summary data on variables. Read more
LENVgm equals the number of characters in the variable name, not counting the type character (!@#$%&^). A longer name is preferred over a shorter name because it is more self-explaining. The letters "gm" indicate that the metric is for global and module-level variables. They distinguish it from the overall LENV for the entire project.
VARUSR = Number of modules that use a variable
Ideally, VARUSR should be 1. Each variable should be encapsulated and only used within the same module. External users should only be allowed to access variables via properties or other functions and subprograms. Even though VARUSR=1 is the ideal value, it's not a proof of ideal use. VARUSR=1 can also occur when the variable is declared in module A and user exclusively by module B. In this case there is only one user (B) but it is external.
A high VARUSR means heavily distributed use. A large number of modules access the variable. It connects these modules. This variable can be risky to change, especially if the value or the meaning of the variable changes to something previously unexpected.
In a lot of cases you should keep VARUSR down to 1. You can do so by encapsulating variables as properties and declaring the variables as Private. Another way is to write functions that provide access to global variables and procedures that allow other modules to set the value.
You may also choose to use global variables and thus keep VARUSR high. This is a matter of programming style.
VARUSR=0 occurs when the variable is not in use.