In previous sections a selection of useful metrics has been shown for imperative languages, and there are many more that have not been covered in this thesis due to the large body of work covering metrics for imperative languages. However in recent years Object-Oriented (OO) programming languages such as C++ and Java have become popular so it is interesting to examine the metrics available for such programming languages. Many of the metrics used for imperative languages can be applied to OO programs, but there are a number of additional attributes that are specific to OO programs which are therefore ignored by imperative metrics. Many metrics for use with OO programs are described by Lorenz and Kidd [62]. The remainder of this section is divided into the following parts.
• Section 2.3.1 discusses ways to classify the importance of classes.
• Section 2.3.2 presents work to measure properties of methods in an OO program.
• Section 2.3.3 examines classes and their properties.
• Section 2.3.4 looks at work that investigates the coupling between objects. • Section 2.3.5 summarises this section.
2.3.1
Classifying classes
In OO programming the program is divided into classes which typically encapsu- late both state and functionality. Lorenz and Kidd classify program classes into one of the following two categories.
• Support Classes are those classes which are not central to the task the pro- gram is to perform. It would be possible to develop a solution without them.
• Key Classes are those that are central to solving the problem, without which it would be impossible to develop a solution.
It is important not to confuse these two classifications with “application” and “utility” classes. Utility classes may be key classes, for instance a numerical li- brary may contain utility classes which are key to solving the application problem. However, making this classification normally requires the insight of a program and would be difficult to perform accurately with an automated system.
With program classes classified into support and key categories it is possible to measure the ratio of support classes to key classes. This ratio gives an indication of whether the program is dominated by support vs key code. This may be useful to know because “show stopping” defects are more likely to occur in key classes than support classes, where defects may not be so serious.
2.3.2
Metrics for methods
Object-oriented languages use classes to encapsulate functionality and state. A class will normally have attributes (state) and methods (functionality) which op- erate on those attributes. Classes communicate by sending messages, which is achieved by invoking the methods of the target class.
Some metrics view methods simply as functions in an imperative language and in this way many of the metrics used for imperative languages can be used directly on methods in an OO program. For instance, method size may be measured by Lines Of Code, or the number of statements in the method body.
A more object-oriented view of method size, suggested by Lorenz and Kidd [62], may be to measure the number of message sends initiated by the method. The number of message sends gives a useful indication of how “busy” a method is, which might highlight methods with a high degree of coupling. This is similar to counting the number of function calls out of a particular function in an imperative language, and may be calculated either statically, by the number of lines which initiate message sends, or dynamically at runtime. Dynamic measures of coupling
between objects are discussed in greater detail in Section 2.3.4.
2.3.3
Class properties
Existing metrics for imperative languages are not necessarily best suited for mea- suring properties of classes as a whole. For instance, to measure the size of a class it would be possible to measure Lines Of Code but this is not necessarily a good indication of the size of a class. A better measurement might be to count the number of methods the class contains, which measures how large the interface to the class is, or how much state the class encapsulates, for instance by counting the number of attributes the class contains.
One of the most useful features of OO programming is inheritance. Inheri- tance allows a child class to inherit behaviour from a parent class, or extend the behaviour of the parent class. This feature adds genericity to OO languages, but can make the behaviour of a child class harder to understand because it may be necessary to understand the behaviour of the ancestor classes as well as that of the child class. Because inheritance is an important aspect of OO program- ming it is useful to have metrics to measure the impact of inheritance on program complexity.
Inheritance can be represented using directed graphs. From such graphs it is possible to measure attributes such as depth of inheritance and number of ancestors. It is worth noting that just representing the inheritance graph visually may be of significant help in understanding a system, as can be seen by the popularity of modelling tools such as UML, and can highlight places where the implementation of a software system does not match the original design. This is explored in greater detail in Section 2.6.
Along with the inheritance hierarchy, the effect of inheritance on a class is also of interest. When a class inherits functionality from a parent class it may also override methods. This information can be added to the flowgraph and allows information such as the number of inherited methods or the number of overridden methods to be counted. The number of overridden methods is a particularly
interesting metric because overriding methods can result in methods which are syntactically identical from the point of view of their type signature, but may have fundamentally different behaviour. This can make it very hard to correctly understand the behaviour of code that uses such overridden methods.
Because all these measures consist of counting occurrences of some property, they can be implemented quite simply as static measures, although it is also possible to perform these measurements dynamically, which is partly examined in Section 2.3.4. Additionally, many of these measures can be applied to design artifacts such as UML diagrams. This is discussed in Section 2.6.
2.3.4
Dynamic coupling measures
Software systems often need to be changed, e.g. for new or changing user require- ments. It is therefore important that software systems are constructed in such a way that they may be changed with the minimum of disruption to existing code. One way to make the system easier to change is to ensure the amount of coupling between components is minimal. Because of this there have been many coupling metrics defined, such as those for imperative programs described in Section 2.2.5. These static measures of coupling have been shown to be useful indicators of soft- ware quality by the work summarised in Section 2.2.5. However properties of the dynamic behaviour of OO software can only be accurately gathered at runtime.
One of the advantages of measuring coupling dynamically instead of statically is that it allows the focus of attention to be limited to code used for a particular use case, which may be only a subset of the code contained in the classes associated with the use case. This is not possible with static measures which must consider the classes as a whole.
Arisholm [6] examines three different dimensions of dynamic collaboration be- tween two components of a system, namely the direction of the coupling, the mapping of the coupling and the strength of the coupling. These are described in more detail below.
• Direction. One can measure the messages received by an entity, the export coupling, separately from the messages sent by an entity, the import coupling. • Mapping. Messages are “received” through methods defined either within an object’s class or inherited from its parent classes. Because of this, although messages are mapped to a single object, they may be mapped to many classes. From this a distinction can be drawn between the objects sending and receiving the messages and the classes that implement the methods. This leads to two categories of coupling which can be measured separately, object-level coupling and class-level coupling.
• Strength. The strength of the coupling is a measure of the amount of asso- ciation between the two entities. Arisholm uses three methods of measuring this strength:
– Number of dynamic messages. A count of the total number of messages sent by an entity.
– Number of distinct method invocations. The number of unique messages sent by an entity, ignoring duplicate messages.
– Number of distinct classes. The number of unique classes to which the entity sends messages. Different messages sent to the same class are treated as a single message.
Unlike the classification of coupling described earlier in Section 2.2.5, these strength measures do not attempt to classify the type of the coupling, e.g. whether the messages contain some control element, but instead only count the number of occurrences, and so treat all types of coupling as equal.
From these three dimensions of coupling Arisholm developed a collection of twelve metrics. The preliminary results from his work suggested that a number of the metrics showed a positive correlation with the change proneness of a case study program. Further, the results suggested that the higher the object-level
export coupling of a class, the more objects depend upon that object and hence the class of which that object is an instance is more likely to be changed.
Dynamic measures of software open up many possibilities for measurement, however this thesis concentrates on static measures of software and the dynamic measures are presented here only for information.
2.3.5
Summary
In general, many of the imperative language metrics can be used for OO programs. Additional metrics can be used to measure attributes of the additional features of OO languages, such as inheritance and coupling. However some of these OO features must be measured dynamically at runtime rather than statically in order to gain accurate measurements.