Measuring Functional Cohesion - Colorado State University Computer ...

16 downloads 7548 Views 2MB Size Report
than one data slice, and super-glue tokens, tokens that lie on all data slices in a ... If, cohesion is an important attribute of software design quality, we should be.
644

IEEE TRANSACHONS ON SOFlWARE ENGINEERING. VOL. 20. NO. 8. AUGUST 1994

Measuring Functional Cohesion

_

James M. Bieman, Senior Member, IEEE, and Linda M. Ott

Abstract-We examine the functional cohesion of procedures using a data slice abstraction. Our analysis identifies the data tokens that lie on more than one slice as the ‘glue” that binds separate components together. Cohesion is measured in terms of the relative number of glue tokens, tokens that lie on more than one data slice, and super-glue tokens, tokens that lie on all data slices in a procedure, and the adhesiveness of the tokens. The intuition and measurement scale factors are demonstrated through a set of abstract transformations. Zndex Terms- Software measurement, slices, measurement theory.

I.

cohesion,

program

INTRODUCTION

OHESION is an attribute of a software unit or module that refers to the “relatedness” of module components. A highly cohesive software module is a module that has one basic function and is indivisible-it is difficult to split a cohesive module into separate components. Virtually every software engineering text describes cohesion as an important factor of design quality. If, cohesion is an important attribute of software design quality, we should be able to recognize when a module exhibits cohesion, and, ideally, we should be able to quantify the amount of cohesion in a module. Such cohesion measures can help developers design modules with greater cohesion. Module cohesion can be classified using an ordinal scale that includes coincidental, logical, temporal, procedural, communicational, sequential, and functional cohesion [39, ch. 71. Using this model, a module exhibits one of these seven cohesion categories. The cohesion categories vary in desirability ranging from the most desirable (functional cohesion) to the least desirable (coincidental cohesion). All of these cohesion categories indicate the extent of the “functional strength” of a module, the contribution of module parts towards performing one task [lo, pp. 199-2001. Our aim is to develop quantitative measures of functional cohesion, the most desirable of these functional strength cohesion categories. According to Yourdon and Constantine, every element in a module exhibiting functional cohesion “is an integral part of, and is essential to, the performance of a single function” [39, p. 1271. In their model, a module

C

Manuscript received June 30, 1993; revised April, 1994. Recommended for acceptance by B. Littlewood. This work was supported in part by a Faculty Development Grant from Michigan Technological University, and by NASA Langley Research Center, Colorado Advanced Software Institute (CASI), Colorado Advanced Technology Institute (CATI), Computer Technology Associates, Inc. (CTA), and Storage Technology Inc. J. Bieman is with the Department of Computer Science, Colorado State University, Fort Collins, CO 80523, USA; e-mail: [email protected]. L. Ott is with the Department of Computer Science, Michigan Technological University, Houghton, MI 49931 USA; e-mail: [email protected]. IEEE Log Number 9403567. 009%5589/94$04.00

is either functionally cohesive or not. In contrast, we are developing techniques that indicate the extent to which a module approaches the ideal of functional cohesion. Note that one can also evaluate cohesion from the perspective of data abstraction [23, pp. 169-1711. Fenton describes this abstract or data cohesion as a different notion of cohesion with a different set of measurement attributes [lo, p. 2001. In this paper, we address functional cohesion; we defer the treatment of abstract or data cohesion to future work. Measurement techniques used in the physical sciences guide us in our development of functional cohesion measures. Aspects of functional cohesion are internal product attributes related to properties of programs [ 111. Our objectives include the development of 1) a good model of functional cohesion, and 2) measures that use the model to quantify functional cohesion. For cohesion measures to provide meaningful measurements, they must be rigorously defined, accurately reflect well understood software attributes, and be based on models that capture these attributes [I]. The measures should be specified independently from the measurement tools, and such tools should be based on the models. For example, QUALMS [38] is based on the flow graph model, and the test coverage measurement tools of Bieman and Schultz [4], [5] are based on the standard representation model [2]. We use a slice abstraction of a program based on data slices to model cohesion [26]. A program slice is the portion of program text that affects a specified program variable [35]. A variation on program slices can model and measure functional cohesion [28]. Procedure cohesion measures must indicate the cohesion that is expressed in the program text. We cannot measure semantic relations between program components that cannot be identified from the program text alone. Note that functional cohesion is actually an attribute of individual procedures or functions, rather than an attribute of a separately compilable program unit or module (depending on the‘programming language, modules may include several procedures and declarations). We will use the term “procedure” to refer to both procedures and functions. We develop cohesion measures in terms of the slice model, and validate the measures by demonstrating that they are consistent with expected cohesion mode1 orderings and determining their scale properties. Thus, we appeal to the representation condition of measurement theory [ 10, pp. 25-261, [ 1 I], which requires that our intuition about the relative quantity of functional cohesion is preserved by a cohesion measure. To be measurable on an ordinal scale, an attribute of cohesion must impart an ordering on the model. That is, the model of a procedure with “more” of one cohesion attribute must be 0 1994 IEEE

BIEMAN

AND

OTT: MEASURING

FUNCTIONAL

645

COHESION

ranked (according to the attribute ordering) higher than the model of a procedure with “less” of the attribute [24]. A measure is specified as a mapping from the model to a quantitative value. Such a measure must be consistent with the cohesion ordering. One way to demonstrate that a measure is consistent with the ordering is to evaluate the effect of code modifications to the model and the measures. W e focus on the direction of the changes to cohesion measurements resulting from relatively simple code modifications. The direction of measurement changes provides a ranking of relative levels of cohesion before and after a code change. Our analysis also demonstrates the scale properties and the arithmetic operations that can be applied to the measurement values [41, ch. 41. The role of experimentation in software measurement research is to map structural measures back to process goals such as fewer defects, increased maintainability, etc. But, before we can conduct effective empirical research, we must first have sound measures [ 11.Thus, our goal here is to develop measures that accurately reflect the concept of cohesion. The paper has the following organization. In Section II, we define the abstractions used to model functional cohesions. In Section III, we examine the cohesion attributes and measures, and Section IV evaluates the scale properties of the measures. In Section V, we provide some examples of procedures, cohesion orderings, and cohesion measures. Section VI is a review of related work. Our conclusions are given in Section VII. II. COHESION ABSTRACTIONS

In our analysis, functional cohesion is based on procedure outputs. Each output “object” (output parameter, modified global variable, or file), represents one component of a procedure’s functionality. W e identify the components of a procedure that contribute to particular outputs. Although a procedure may perform computation that does not produce outputs, outputs of some kinds are generally the externally visible manifestation of functionality. W e do not address the cases where activities that do not produce outputs are the real functionality, for example modules whose main functionality is to produce a time delay. In the case of procedures with multiple outputs, we see how closely the program parts that contribute to different outputs are bound. Using this approach, procedures with only one output exhibit maximum functional cohesion. A. Program Slices Slicing is a method of program reduction introduced by Weiser [35]-[37]. A slice of a procedure at statement s with respect to variable w is the sequence of all statements and predicates that might affect the value of r~ at s. Slices were proposed as potential debugging tools and program understanding aids. They have since been used in a broader class of applications (e.g., debugging parallel programs [7], maintenance [13], [15], [25], and testing [ 171, [ 181, [22], [29]). Weiser’s algorithm for computing slices is based on data flow analysis. It is suggested in [27] that a program dependence graph representation can be used to compute slices more

efficiently and precisely. An algorithm for computing slices using a program dependencegraph representation is presented by Horwitz, et al., [16], [31]. A slice is obtained by walking backwards over the program dependence graph to obtain all nodes which have an effect on the value of the variable of interest. Similarly, a fonvard slice [16] can be obtained by walking forward over the program dependence graph to obtain all nodes which are affected by the value of a variable. The algorithm based on the program dependence graph is more restricted than Weiser’s in the sense that it will only compute a slice for variable v at statement s if 21is defined or used in statement s. Both intraprocedural slices and interprocedural slices can be computed. W e derive cohesion measures directly from slices rather than dependence graphs. Slices promote a more intuitive analysis since they are based on program text. Our measurement theory approach requires that a measure be consistent with intuition, and including program text in our abstraction eases intuitive analysis.

B. Data Slices In [37], Weiser defined several slice based measures. Longworth [21] first studied their use as indicators of cohesion. In [30] and [33], Thuss eliminates certain inconsistencies noted by Longworth through the use of metric slices. A metric slice takes into account both lcses and used by data relationships; that is, they are the union of Horwitz et al.‘s backward and forward slices. In order to analyze the effects of changes on slice measures, we modify this concept of metric slices to use data tokens (i.e., variable and constant definitions and references) rather than statements as the basic unit. W e call these slices data slices. Using data tokens as the basis of the slices ensures that all changes of interest will cause a change in at least one slice of a procedure. W e consider a change of interest to be any change which could have an effect on the cohesiveness of a procedure. An example of a change that is not of interest is changing some operator to a different operator. Examples of changes of interest include adding code, deleting code, or changing the variable used in a given context. Each of these changes would result in a change to at least one data slice. (This is in contrast to a metric slice, where if a statement is modified, the actual statements in the slice might not change.) Informally, we view a data slice for a data token, 21,as the sequence of all data tokens in the statements that comprise the “backward” and “forward” slices of u. W e use intraprocedural slicing since we are interested in examining the cohesiveness of each procedure as a separate entity. W e compute a data slice for each output of a procedure. An “output” is any single value explicitly output to a file (or user output), an output parameter, or an assignment to a global variable. An output tuple with multiple components is considered to be multiple outputs. Since we are interested in the cohesion of the whole procedure, we use a concept similar to that of end-slices [ 191.The “backward” slices are computed

646

IEEE TRANSACTIONS

procedure SumAndProduct integer; ml: var 1SumN ], ProdN : integer ); var /T-J: integer; begin fKGTq::=@ ProdN := 1; for m :=

q to q

do begin

(q::=ISumNIt0; ProdN := ProdN * I end end;

N2 .SurnNs .SurnNd. Is.

where each T; indicates the i’th data token for T in the procedure. Note that in the slice for SumN, the subscript in “la” indicates that the token is the second occurrence of data token “1” in the procedure. We can also compute the slice for ProdN: N1 .ProdNl .I1 .ProdN2.11. Ia.12. Nz .ProdN3.Prod4N4.14. We can profile the data slices in a procedure to give a sense of the relationships among data slices. Fig. 2 shows an example of a data slice profile. We indicate, in the column for a slice variable, the number of data tokens in that line that are included in the slice. This profile was derived from an earlier method developed for visualizing slices [25], [28], [33]. C. Slice Abstractions Our analysis of functional cohesion is developed using an abstract model of procedures based on data slices. The Slice Abstraction models each procedure as a set of data slices, and a data slice as a sequence of data tokens. Essentially, we strip away all of the non-data tokens from a procedure and include only the data tokens in the abstraction. The slice abstraction for the SumAndProduct procedure of Fig. 1 and Fig. 2 is: SA( SumAndProduct ) = {Nl’ SumNl . II . SumNz .OI.I~.

ProdN

1 1

1 1

1

1

2 2 3 3

from the end of the procedure’ and the “forward” slices are computed from the “top”s of the backward slices. Fig. 1 displays an example of a data slice embedded in a program. The slice for SumN in Fig. 1 is a sequence of data tokens: 12.

SumN

3 3

Fig. 1. Data slice for SumN. Items included in the slice are contained within boxes.

NI .SumNl. II .SumNz .Ol.Iz.

O N SORWARE

12 s N2

* SumN3 . SumN, ’13, N1 eProdNl eII . ProdN2 .11 ’I2 ’12 . N2 . ProdN3 . ProdN4 . 14). ’We use the FinalCIise nodes of [ 161 as the end of a procedure.

ENGINEERING.

VOL.

20. NO. 8. AUGUST

1994

Statement procedure SumAndProduct ( N : integer; var SumN, ProdN : integer ); var I : integer; begin SumN := 0; ProdN := 1; for I := 1 to N do begin SumN := SumN •l- I; ProdN := ProdN * I end end; .

Fig. 2. Data slice profile for SumAndProduct. The number of data tokens included in the data slice for SumN and ProdN is indicated in columns I and 2, respectively.

Fig. 3(a) provides another view of a slice abstraction of the SumAndProduct procedure. The names of the data tokens are listed in the first column of Fig. 3(a). A ‘*I” in the second and third column indicates that the indicated data token is part of the data slice for the named output. We find an uncluttered view of slice abstractions without labels useful for visualizing important attributes of functional cohesion in slice abstractions. Fig. 3(b) is an unlabeled view of the slice abstraction of the SumAndProduct procedure. When analyzing functional cohesion, it is important to know when one token is in more than one data slice, but the actual names of the tokens are not important. The slice abstractions from two completely different procedures can have the same cohesion properties, and look identical when viewed in the unlabeled form. D. Glue, Super-Glue, and Stickiness As Fig. 3(a) and Fig. 3(b) show, several of the data tokens are common to more than one data slice. Data tokens N1, I,, 12,12, and Nz are-in the data slice for SumN and the data slice for ProdN. Such tokens, common to more than one data slice in a slice abstraction, are the connections between the slices. We say that these tokens are the “glue” that binds the slices. Thus, we define the glue in a slice abstraction of a procedure P, G(SA(P)), as the set of data tokens that lie on more than one data slice in SA(P). A glue token is a token that lies on more than one data slice. We also consider all of the tokens in an abstraction with only one slice to be glue tokens. Fig. 3(c) shows SA(SumAndProduct) with the glue tokens enclosed in boxes. Although there are two “I” symbols on each row of glue tokens in Fig. 3(c), there is actually only one token for each row. It is useful to identify the data tokens that are common to every data slice in a procedure. These tokens are the super-

BIEMAN

ANDOTT:MEASURING

647

FUNCTIONALCOHESION

Data Token

SumN

ProdN

NI SumNl ProdNi

I

’ I

11

III u/’

SumNs 01

ProdNz 11 12 12 N2

I

I I I I

/ I I I

I

SumNa SumN4

I

I3

ProdN3 ProdN4

Fig. 3.

Three

I I

1

I4

(a) Viewsof SA(SumAndProducr)

(a) SA(SumAndProduct)

(b) ; (b) UnlabeledView; (c) Glue tokenshighlighted.

s,s2.& Super-glue:

1

(

I

I Super-glue:

1

I

Glue: Glue:

I

l I

Glue:

I

Cc)

stickiness or adhesiveness of a glue token. The notion of token adhesiveness can characterize the .adhesiveness property of an entire procedure or slice abstraction. W e use the concepts of glue, super-glue, and adhesiveness to develop functional cohesion measures.

) III. FUNCTIONAL COHESIONATTRIBUTESAND

MEASURES

I A. Definition of Measures

I

Fig. 4. A Three-sliceSA with glue andsuper-glue.

glue tokens, and SG(SA(P)) denotes the set of data tokens that lie on all data slices in SA(P). The notion of super-glue tokens is especially useful in slice abstractions with more than two data slices. Note that SG(SA(P)) C G(SA(P))-all super-glue tokens are also glue tokens. If ISA(P) 1 2 2 then SG(SA(P)) = G(SA(P)). Note that all of the data tokens in a procedure’with only one slice are super-glue tokens. Fig. 4 shows a three-slice abstraction with glue and superglue tokens. This abstraction has two super-glue tokens and five glue tokens (super-glue is still glue). One of the tokens glues S1 to Ss, one glues Sa to S’s, and one glues S1 to Ss. The super-glue tokens bind all three slices together. Six of the tokens lie on only one data slice and are not glue tokens. The distribution of glue and super-glue tokens indicates how tightly bound the individual slices are, since the effect of glue tokens is to bind slices. Individual glue tokens can have a varying effect on cohesion based on the number of slices that they bind. Thus, we can describe the relative

W e define functional cohesion attributes and measures in terms of slice abstractions, data tokens, glue and super-glue. W e also use the set of data tokens in a slice abstraction a, denoted tokens(a), and the set of data tokens in procedure p, denoted tokens(p). In general, tokens(p) = tokens(SA(p)). However, if a value is computed that does not contribute to any output (usually a program anomaly), then there may be data tokens that do not lie on any slice and tokens(SA(p)) c tokens(p). Note that each appearance of a data token in a program is counted as a different token, and each token can be in more than one data shce. Metrics based on the relative number of glue and superglue tokens are intuitive and can easily be defined in terms of slice abstractions. According to Yourdon and Constantine [39, pp. 127-1301, a procedure with functional cohesion is one in which all parts are cohesive. This view recognizes only the strongest functional cohesion and is consistent with the use of the super-glue tokens as the basis for defining cohesion attributes and measures. Thus, we define strong functional cohesion (WC) as the ratio of super-glue tokens to the total number of data tokens in a procedure p: SFC(p)

=

ISG(SA(P))I (tokens(p) 1 ’

(1)

648

IEEE TRANSACTIONS

ON SOITWARE

ENGINEERING,

VOL.

20. NO. 8, AUGUST

1994

The SFC is a measure of the minimal functional cohesion slices, has zero strong functional cohesion-there are no data in a procedure. SFC is very similar to the Tightness measure tokens that contribute to all outputs. A procedure with no glue defined by Ott and Thuss [30]. However Tightness is defined tokens, that is no tokens common to more than one da& slice (in procedures with more than one data slice), exhibits zero in terms of statements shared by slices rather than data tokens. W e can also measure cohesion in terms of the glue tokens in weak functional cohesion and zero adhesiveness-there are no a slice abstraction. Such a measure can be more sensitive than a data tokens that contribute to more than one output. The strong measure based on only the super-glue tokens-it can indicate functional cohesion and adhesiveness are at a maximum value that adding something may “glue” together previously non- of one for procedures in which all of the data tokens are cohesive elements even if the token does not “glue” together super-glue tokens-all data tokens affect all outputs. Weak all of the slices. Such functional cohesion indicates a “weaker” functional cohesion of a procedure is one if all data tokens type of cohesion than indicated by the super-glue tokens. Thus are glue tokens-all data tokens affect more than one output we define weak functional cohesion (WFC) as the ratio of in procedures with more than one slice. glue tokens to the total number of tokens in a procedure. For procedure p: 3. Examples

(2) Another way to measure cohesion is in terms of the adhesiveness of glue tokens. The adhesiveness is related to the relative number of slices that each token “glues” together. Thus, a token that “glues” together four slices in a five slice procedure is more adhesive than a token that “glues” together two or three slices. W e can define the adhesiveness, N, of token t in procedure p as follows: #slices in p containing t

0

WFC(SA (SumAndProduct)) = SFC(SA(SurnAndProduct))

IS‘~(P)I

if t E G(SA(p)). otherwise

(3)

The overall adhesiveness, A, of an SA is the average adhesiveness of the data tokens in a procedure:

A(p) =

tEtokens(p) Itokens(p)l

Equivalently, overall adhesiveness can be computed as a ratio of the amount of adhesiveness to the total possible adhesiveness. That is, for procedure p:

= & = .294.

Adhesiveness is calculated as follows: A(SA(SumAndProduct)) = E

4hP) =

C

The cohesion measures can be applied to the SumAndProduct procedure. SA(SumAndProduct) has two slices with 17 tokens and 5 glue tokens. Each glue token is a super-glue token since SA(SumAndProduct) has only two data slices. Thus,

= .294,

because there are five glue tokens and each glue token lies on two slices. The denominator is the total number of tokens times the number of slices. W e see that in this two slice example procedure all three cohesion measures give the same value. This is not surprising since the W F C and A measures gain sensitivity on multi-slice procedures-all glue tokens are also super-glue tokens on a one or two slice procedure. The W F C and SFC of the 3-slice abstraction in Fig. 4 will differ since some of the glue tokens are not super-glue. Out of a total of 11 tokens, this abstraction has five glue tokens of which two are super-glue. Thus, WFC(SA(Fig.

4)) = 5/11 = ,455,

SFC(SA(Fig.

4)) = 2/11 = .182.

# slices containing t A(P) =

tEG(SAb))

Itokens(p)l. ISA(p)l

(5)

In the examples in the following subsection, we compute A using equation (5), since equation (5) is easier to apply. Adhesiveness should indicate the relative strength of the glue in a procedure. Adhesiveness is most closely related to the coverage measure of Ott and Thuss [30]. It should be particularly sensitive to the cohesion resulting from glue tokens that lie on more than two slices, but do not lie on all slices. All of these cohesion measures (strong functional cohesion, weak functional cohesion, and adhesiveness) range in value from zero to one. They have a value of zero when a procedure has more than one output and exhibits none of the cohesion attribute indicated by a particular measure. A procedure with no super-glue tokens, no tokens that are common to all data

Because there are two tokeni’on three slices and three tokens on two slices, adhesiveness is calculated as follows: A(SA(Fig.

4)) = 2 y1+. z 2 = g

= .36.

Adhesiveness and the strong and weak cohesion measures are based solely on the number of slices and data tokens in a procedure, and the number of glue and super-glue tokens. C. Relationships Between the Measures By examining the definitions, we can determine relationships among the three proposed measures. Since SG(SA(P)) & G(SA(P)), it follows that ISG(SA(P))J I JG(SA(P))I.

BIEMAN

AND

OTT: MEASURING

FUNCTIONAL

649

COHESION

Thus, using (1) and (2) we can see that for a given procedure p:

(6) W e see that:

SFC(P) 5: A(P),

(7)

by noticing that a(t, p) = 1 using Definition (3) for all t E SG(SA(p)) and therefore, the numerator in (4) is at least as large as the numerator in (I). Similarly, since ~y(t: p) 5 1 for all t E G(SA(P)), using (2) and (4), we see that: A(P) I WFC(?-‘).

(8)

Thus, we have: SFC(p)

5 4~)

I WFC(p).

(9)

Finally, we see that A(p) is more “sensitive” than either WFC(p) or SFC(p) to differences in the amount of program cohesion. If we fix the size of programs considered, that is, jfokens(p)l, and we fix the number of slices considered, that is, ISA(p)(, we see that WFC(p) and SFC(p) can assume at most It&ens(p)1 values. A(p), on the other hand, can assume Ifokens(y)) . (JSA(p)J - 1) values. IV.

DISCUSSION

called an elementary viewpoint. An elementary viewpoint is defined in terms of a finite set of transformations on a program representation. A complete set of elementary transformations can be used to generate every possible instance of a program representation from a base representation. To show that a measure is on an ordinal scale, we need to show that it is consistent with a complete set of elementary transformations, since the set represents the cohesion viewpoint. Thus, we evaluate the “functional cohesion orderings” of procedures in terms of intuitively obvious effects of program modifications on functional cohesion. W e model the changes in terms of an ordering of slice abstractions. In this analysis, we assume that it is the “shape” of slice abstractions that is critical, so two completely different procedures can have the same functional cohesion attributes. W e use unlabeled views of slice abstractions as depicted in Fig. 3(b) to demonstrate the necessary attributes and transformations. Slice Abstraction Transform&ions: Functional cohesion orderings can be developed in terms of a set of elementary transformations of slice abstractions. W e seek a set of transformations that can generate the set of all slice abstractions, and provide an ordering. The transformations are developed inductively. Base case: A one slice procedure:

OF SCALE PROPERTIES

Fenton defines the term “validation” as “the process of ensuring that the measure is a proper numerical characterization of the claimed attribute” [lo, p. 821. This kind of validation is very difficult when the attribute to be measured is loosely understood. W e need to rely on human intuition to determine the relative levels of our cohesion properties, to see if they are consistent with the measurement values. Zuse shows how to determine what type of scale software measures assume [41, ch. 41, [42], [6]. In this paper, we combine the methods of Fenton and Zuse to validate the cohesion measures in terms of intuitive notions of cohesion and to determine the scale properties of the measures. First, we show that the measures assume an ordinal scale that matches our intuition concerning the cohesion attributes that are measured. Then, we evaluate the measures in terms of the requirements of a ratio scale.

A one slice procedure is entirely cohesive, and should have the highest possible SFC! WFC! and A. All three of our measures satisfy intuition here. SFC, W F C and A give their maximum value of I for a one slice procedure. Transformations: 1) Add one slice. There are two ways to add a slice:

A. Cohesion Measures and the Ordinal Scale For a real-valued ordinal scale measure of cohesion attributes to exist, our intuition about these attributes, called “empirical relations” or “viewpoints”, must satisfy three axioms: reflexivity, transitivity, and completeness [40], [41, p. 471, [42], [6]. These are the requirements of a weak order. From [40], we defme a cohesion viewpoint as binary relations, *>, *=, and *> on programs ‘P where: P,*> P2

PI is more “cohesive” than Pz:

P,*z

P2

PI and Pz are equally “cohesive”,

p1*>

p2

PI*> P2 or PI*% P2,

for PI, P2 E P. lt is not possible to give a general definition of cohesion viewpoints. Rather we can use a subset of the above relations

x

b)

**

The new output is not on any of the previous slices. Thus at least one new non-glue token is added. Output existing functionality. This can be accomplished by changing a non-output token into an output token. The following change to C-like pseudo-code is an example of such a transformation: y = x *

printf (y = 3;)

*We use “*” to indicate a token added to a slice that is not new to the indicate when an added token is new to the program; it is a token that is not on any other slice.

proce&,re,we use Li**l’to

650

IEEE TRANSACTIONS

A simple change to the parameters in a Pascal program can also cause existing functionality to become a new output: 2 : integer *

var x : integer

With such transformations, a new slice can be created without adding any new tokens. 2) Extend n slices by adding one token to them. This added token may be a token that is either 4

not in any of the slices in the slice abstraction (i.e., a new token):

I I I II-

I I I

Ij I **

b)

a token already in one or more of the other slices in the slice abstraction, but not in all of the other slices:

I I / ’ / cl

.

I I I ===+ I I* ’ /

or, a token already in all of the other slices:

i I A token can be added to a slice without adding new code by moving the token within a procedure to a location that puts it in the scope of the slice. This set of transformations is complete-we can build all slice abstractions using the base case and repetitions of the two transformations. Removing and shortening slices are inverse operations to the add and extend operations. Effect of Transformations on the Metrics: We summarize the effects of the transformations introduced above on the cohesion measures that we have defined. See the appendix for the detailed arguments. For consistency with the appendix, we will refer to the initial abstraction as a and the abstraction after a transformation as a’. Strong Functional Cohesion: When adding a new slice to a, SFC(a’) 5 SFC(a). Th’1s is consistent with our intuition that adding functionality tends to decrease the cohesiveness of a procedure. When extending slices, we find that SFC(a’) > SFC(a) only when the number of super-glue tokens has increased. Thus, the effects of the transformations match our intuition that the strong functional cohesion components include only elements that contribute to all the functionality computed by the procedure.

O N SOFTWARE

ENGINEERING,

VOL.

20, NO. 8. AUGUST

1994

Weak Functional Cohesion: When we add functionality to a procedure by adding a new output, we increase cohesion only when the net effect is to “glue” previously non coliesive parts creating a higher percentage of glue tokens. When we output existing functionality without adding new tokens, WFC(u’) 2 WFC(u). When extending a slice, WFC can remain unchanged, increase or decrease, depending on whether the new token is already “glue”, is new “glue” or is not “glue”, respectively. Adhesiveness: When we add functionality to a procedure by adding a new output, A can increase or decrease. If we add only non-glue tokens, then A will decrease. If we add at least some glue tokens, the effect on A depends upon the amount of “glue” added, the size of the procedure and the size of the slice being added. When we extend a slice of a multiple slice procedure, A will increase if we add a super-glue token and will decrease if we add a non-glue token. If we add a glue token (which is not also superglue), the effect on A depends upon the ratio of the number of slices that the new token lies on, and the total number of slices in the abstraction. If we extend a slice without adding any tokens, then normally A will increase. A remains unchanged only if we extend a slice by rearranging code to include token(s) that were not previously in any slice. Evaluation of Orderings and Cohesion Metrics: To validate that the three measures, SFC, WFC, and A, assume an ordinal scale we need to demonstrate that the orderings imposed by the measures are consistent with the elementary viewpoints of the associated cohesion attributes. Such a conclusion relies heavily on intuition, since elementary viewpoints are defined in terms of subjective views of cohesion. Our main goal here is to demonstrate that the measures are consistent with intuition. At the very least, we are convinced that the orderings imposed by the measures are not counterintuitive. The measures are on an ordinal scale to the extent that the orderings imposed by the measures match the users (of the measures) intuition concerning the elementary viewpoints of cohesion. B. Cohesion Measures and the Ratio Scale To perform multiplication and division on measurement values, the measures must assume a ratio scale. Thus we evaluate our functional cohesion measures in terms of the requirements for ratio scale measurement. On way to demonstrate that a measure is on the ratio scale involves adding a program composition operator “0 ” to the relational system used in an ordinal scale evaluation. A composition operator takes two slice abstractions and combines them to create a new slice abstraction. Adding o to the cohesion viewpoint of Section IV-A, gives us a relational system (P, *>, 0). Zuse [41, p. 49-501 shows that a measure is on a ratio scale if the measure is a real valued function m, is on an ordinal scale, and the following axioms hold: PI *> P2 ++ ,Il(P,) > TrL(P2) m(P1 0 P2) = 7n(Pl) + 7n(P2).

BIEMAN

AND

OTT: MEASURING

FUNCTIONAL

651

COHESION

The first axiom requires that m be consistent with the intuitive ordering of the procedures imposed by the attribute being measured. The second axiom requires that m be additive. Meaningful composition operators are necessary to use Zuse’s method of verifying that a measure assumes a ratio scale. In the extended version of this paper [3], we define two composition operators. One operator ties the output of the slices in one abstraction to the inputs of another abstraction. The second operator assumes no interactions between the two merged abstractions. The requirement that m(Pl o P’) = m(Pl)+m(&) is not satisfied using either of the two composition operators. This is because the size attribute /tokens (p)l, the number of tokens in the procedure, is in the denominator of the calculation for all three of the cohesion measures (SFC, WFC, and A). Under the two composition operators, the measures are not additive, and, thus, do not assume a ratio scale. Gustafson, Tan, and Weaver argue that composition operators for the complex models (such as slice abstractions) used to define structural measures do “not make sense” because programmers rarely merge programs [ 141. As an alternative to the analysis based on composition operators, we can use an intuitive argument that the functional cohesion measures do not assume a ratio scale. Multiplication makes sense for ratio scale measures. Thus, if the functional cohesion measures are on a ratio scale, we should be able to argue that one procedure (or slice abstraction) is twice as cohesive as another. W e can find slice abstractions sl and 32, where SFC(s1) = 2SFC(s2), WFC(s1) = 2WFC(s2), or A(2) = 2A(2). However, we find no justification (other than the measures themselves) for claiming that any sl is twice as cohesive as ~2. The notion of doubling cohesion is not intuitive, and multiplying cohesion values does not seem to be meaningful. Thus, we find no evidence that the functional cohesion measures assume a ratio scale.

small 1 1

value

1 1 2 4 2

2 2

3 2

2

procedure Decode(var value: integer; var small: boolean); begin if value < 5000 then begin value := value * 8 mod 10; small := true end else begin value:=value mod 10; small := false end; end; WFC(Decode)

= $ = .53

8*2 A(Decode) = = .53 15*2 SFC(Decode]

e=

$

= .53

Fig. 5. A slice profile and cohesionmeasurements for a simple procedure. value 1 1

small 1 1

count

1 2 4 2

3 2

2 2

2 3

procedure Decode2(var value: integer; var small: boolean; var count: integer); begin if value < 5000 then begin value := value * 8 mod 10; small := true end else begin value:=value mod 10; small := false end; count := count $1; end;

WFC(Decode2)

=

i

= .42

V. EXAMPLES

In this section, we examine a few small code segments to illustrate the differences among the three proposed cohesion measures. The figures in this section use slice profiles (as in Fig. 2) showing the entire procedure text rather than slice abstractions showing only data tokens to make it easier to visualize the connection between program text and slices. As described in Section II-B, the slices in the examples are the union of the backward and forward slices based on the output variables. The first example uses a procedure that transforms a value in one of two ways depending on the initial value. A flag that indicates which of the two transformations was used is also returned. Fig. 5 contains a slice profile and cohesion measurements for this Decode procedure. In this case the three measures give equivalent values. The cohesion measurements are always equivalent for two slice procedures since in such cases G(SA(p)) = SG(SA(p)). The .53 measurement values indicate that approximately half of the tokens lie on both slices. The three cohesion measurements are lowered when the procedure is modified by adding an output variable that is not

A(Decode2) SFC(Decode2)

=

s

= .25

=

- 0 = 0.0

19 Fig. 6. A slice profile and cohesion measurementsfor a noncohesive procedure.

connected to the slices of itie original outputs. The modified procedure, Decode2, is in Fig. 6. Decode2 was created by adding a variable count to the original procedure Decode. It is a global variable that may indicate the number of times that Decode2 is called. SFC(Decode2) is zero, and clearly indicates the existence of some noncohesive components in the procedure-the slice for output variable count does not include any tokens that lie on the slices for the other outputs. WFC(Decode2) has dropped to .42 and A(Decode2) has dropped further down to .28. Of W F C and A, A is more dramatically affected by adding the noncohesive component. Figs. 7, 8, and 9 demonstrate how the measures behave when functionality is combined. Procedure Lookup in Fig. 7 is a table lookup routine which returns a password and

652

IEEE TRANSACTIONS

3uccess passwd 3 3 1 1 1 1 1

address 3 1 1

2 2 3 3

2 2 3 3

2 2 3 3

2 3 3

2 3

2

3

3

3

3

ON SOFTWARE

ENGINEERING,

VOL.

20, NO. 8, AUGUST

1994

procedure LookUp(A: Table; Size: integer; key: keytype; var success: boolean; var passwd: integer; var address: string); begin i := 1; success:= false; while not success and i