MDAY@XX.LCS.MIT.EDU (Moderator, Mark S. Day) (01/11/88)
Soft-Eng Digest Sun, 10 Jan 88 Volume 4 : Issue 2 Today's Topics: ---SPECIAL ISSUE ON PROGRAM COMPLEXITY METRICS--- Program Complexity Metrics (10 msgs) Summary of Metrics Responses Examples: Optimizing Complexity Reduces Code Quality (2 msgs) ---------------------------------------------------------------------- Date: 10 Dec 87 15:35:01 GMT From: ndsuvax!ncmagel@uunet.uu.net (ken magel) Subject: Program Complexity Metrics Does anyone actually use program complexity metrics for practical work? I am interested in how companies actually use complexity metrics ranging from lines of code to cyclomatic complexity to software science to the many other metrics which have been proposed. Today one get get either public domain or as a commercial product programs which will compute and report several different metrics. Are these actually used? If you do not use program complexity metrics, what sort of proof, evidence or demonstrations would your company need to cause you to consider using them? What kinds of payoffs do they have to have and how would those payoffs be established to your satisfaction? I am particularly interested in answers to the second paragraph of questions. Thank you. ------------------------------ Date: 14 Dec 87 00:35:24 GMT From: munnari!mulga!ditmela!latcs1!ken@uunet.uu.net (Ken Lew) Subject: Program Complexity Metrics [what are metrics?] [...] Program complexity metric is used to indicate the "quality" of a program by measuring certain characteristics such as program size, number of decision statements, information flow, etc. For example, McCabe's cyclomatic number measures the number of independent paths in a program and is related to the number of decision statements. McCabe has used the metric to control the number of paths in a program module to increase the program test coverage. Although non of the complexity metrics has been validated, some empirical studies have found them useful in software development. For reference, read: Software Metrics: An analysis and evaluation, ed. A. Perlis et. al., MIT, 1981 ken@latcs1 ------------------------------ Date: 14 Dec 87 17:15:02 GMT From: ihnp4!homxb!whuts!mtune!petsd!pedsga!chip@ucbvax.Berkeley.EDU Subject: Program Complexity Metrics [what are metrics?] According to my textbook: Software Enginneering, by Shooman, McGraw-Hill, complexity metrics serve the following purposes: 1. As a rank of the difficulty of various software modules to be used along with other factors in the assignment of personnel 2. In the case of module complexity, as a guide to judge whether subdivision of a complex module is warrented 3. As a direct measure of progress and an indirect measure of quality during the various phases of development. 4. As an aid in normalizing data used in retrospective studies of past development projects. Personally, I feel that the second use is of most value. The general idea is to be able to apply formulas to software (either as a whole or individually to modules) to determine the "quality" of the software. One of the more famous complexity metrics papers was written by Thomas McCabe (IEEE Transactions on Software Engineering, 12/76 pp 308-320) in which he describes his graph-theoretic complexity measure. His approach is that the more paths there is in a given module, the more complex it is (seems simple enough). The formula will produce a complexity value for a module. His conclusion is that modules with complexity values over 10 will have a tendency to have more errors (I guess the programmer can't track all possible paths). By breaking the module up into smaller modules, you reduce the chance for inherent code errors. Putting it simply, the formula is as follows: v = sum(branches, loops, case, conditions,...ANDs, ORs, NOTs) + 1 His studies showed that in several large projects, that 23% of the routines with a value greater than 10 accounted for 53% of the bugs. Metrics can provide a lot of insight to software quality. Unfortunately, they are not viewed as a means of bringing software development out of its "primitive state" (said in jest of course, see previous articles in this newsgroup :-) Hope this provides some insight to a relatively unknown topic. -- Chip ("My grandmother called me Charles once. ONCE!!") Maurer Concurrent Computer Corporation, Tinton Falls, NJ 07724 (201)758-7361 uucp: {mtune|purdue|rutgers|princeton|encore}!petsd!pedsga!chip arpa: pedsga!chip@UXC.CSO.UIUC.EDU ------------------------------ Date: 18 Dec 87 11:12:47 GMT From: mcvax!ukc!stc!datlog!dlhpedg!cl@uunet.uu.net (Charles Lambert) Subject: Program Complexity Metrics [what are metrics?] As the name implies, they are techniques to measure the complexity of a (proposed) programming task; they estimate how laborious and difficult it will be to implement. From an analysis of complexity, you can predict several things (according to the advocates), for instance: (i) how much the implementation will cost (in terms of effort); (ii) the number of errors you can expect; (iii) the number and type of test cases you will need; (iv) how costly the system will be to maintain. Ideally, you want to make these predictions as early in the development as possible; however, my studies to date show that the current techniques address the detailed Module Design best, the System Design less well and the Functional Specification not at all. In their excellent survey of software development techniques [1], Birrel and Ould describe complexity measurements at the stages of System Design and System Production (the latter being Module Design and Coding). For System Design, they describe only one measurement that I would truly call a complexity measurement: the "interconnectivity metric" of Kafura and Henry [2]. In contrast, three measurements are described for the Module Design: "McCabe's (cyclomatic) number [3]", "Halstead's E [4]" and "control entropy". I quote, without permission. On interconnectivity: "[Kafura and Henry] describe it as follows. 'The first [phase] involves generating a set of relations indicating the flow of information through input parameters, output parameters, returned- values functions and data structures. The second phase generates an information-flow structure from these relations. The third phase analyses the information-flow structure to determine the derived calls, the local flows and the global flows'. A special notation is used to record the result of the first analysis so that automated tools can be used for the second and third phases. The analysis can be carried out on any level of design or production provided a precise enough description is available..." On cyclomatic numbers: "McCabe (1976) introduced the cyclomatic number of the control flow graph of a program as a measure of program complexity. The cyclomatic number of a graph counts the number of linearly independent cycles in the graph and thus gives the number of basic paths through the program..... "Alternatively it can be shown that for structured programs the cyclomatic number can be obtained by adding one to the number of predicates in the program segment... "The cyclomatic number has been shown to correlate quite well with the number of errors found in the code and the programming time. It can also clearly be used as an indicator of the number of test cases that should be applied to a module to test all basic paths." References ---------- [1] Birrell, N.D. and Ould, M.A; A Practical Handbook for Software Development. Cambridge University Press. 1985. ISBN 0 521 25462 0 [2] Kafura, D. and Henry, S; "Software quality metrics based on interconnectivity" in the Journal of Systems and Software, 2, 121-131. 1981. [3] McCabe, T.J; "A complexity measure" in IEEE Transactions on Software Engineering, SE-2, 308-320. 1976. [4] Halstead, M; Elements of Software Science. Elsevier North-Holland, New York. 1977. ------------------------------ Date: 17 Dec 87 12:49:01 GMT From: phri!dasys1!samperi@nyu.edu (Dominick Samperi) Subject: Program Complexity Metrics If McCabe's cyclomatic complexity metric is essentially equal to the number of decisions in a program module (IF's, AND, OR, etc.) plus 1, I don't see the advantage in giving it a graph-theoretic interpretation. It is not equal to the number of paths through a module, and it seems to be little more than the number of forkings in a control graph (plus one). True, it can be computed by counting nodes, edges, and components, but it is much easier to simply count the number of forks and add 1, or to dispense with the control graph altogether and simply count IF's, AND's, NOT's, etc. In Shooman's Software Engineering text 'phantom paths' are added to a graph in order to compute its cylomatic complexity. I don't see the point here at all (and the formula used in this text, V(G) = e - n + p, will not work for graphs with p > 1; must use V(G) = e - n + 2p). -- Dominick Samperi, Manhattan College, New York, NY ...!ihnp4!cmcl2!manhat!samperi ...!ihnp4!cmcl2!phri!dasys1!samperi ------------------------------ Date: 18 Dec 87 14:26:39 GMT From: uh2@psuvm.bitnet (Lee Sailer) Subject: Program Complexity Metrics This is an interesting topic. How would YOU "measure" the complexity of a module? How can we "validate" the measures? The <number of paths> thru a module doesn't impress me at all. A very simple module constructed from a sequence of big CASE or SWITCH statements will have many paths, but is easy to understand. How 'bout a measure based on the *hierarchy* of Data Flow Diagrams? For example, some modules might have a simple top level, with increasing complexity as you break down each level. Another module might have a complex top level, but the lower levels might be simple. Which is more complex overall, the first or the second? My *guess* is that the first is simpler, overall, on the principle that it hides the complexity. Yet, it probably has more paths, more tokens, more ifs, ands, and whiles (fewer gotos?). The main point is that the COMPLEXITY of a module depends to some extent on how detailed an understanding of the module you want or need. lee ------------------------------ Date: 18 Dec 87 18:05:00 GMT From: necntc!dandelion!ulowell!apollo!marc@husc6.harvard.edu (Marc Gibian) Subject: Program Complexity Metrics The current crop of complexity measures do NOT improve the code. There is an excellent article in a past ACM Communications on this issue. The conclusions of the acticle match the experiences of a major software organization in Raytheon. I will take the liberty here to summarize the ACM article since I forget the issue number. The basic conclusion of the article is that no complexity measure currently exists that has been designed specifically for the purpose for which it is being used by software developers. Secondly, current complexity measures do not validate when tested against these software development goals. The application of complexity measures at Raytheon, required by almost every software contract there, is usually accomplished by requiring that every module (however a module is defined) has a set of complexity values less than some arbitrary number. Unfortunately, the process of reducing the measured complexity of a module most often decreased the quality of the module, made it harder to maintain, harder to understand, and generally did not accomplish the intended goal. I can provide specific examples if anyone is interested. I believe that a measure designed specifically to accomplish software development goals, and validated against those goals, could be quite helpful. In the meantime, I think it is very dangerous to use the current instruments since they mislead management and customers into believing they have a good means of measuring some aspects of their software. Marc S. Gibian Software Engineer Apollo Computer email: marc@apollo.UUCP ------------------------------ Date: 22 Dec 87 17:35:57 GMT From: ihnp4!homxb!mtuxo!mtune!petsd!pedsga!tom@ucbvax.Berkeley.EDU Subject: Program Complexity Metrics Marc states (very well) an important point, but I, for one, would like to see some examples. The phrase "the process of reducing the measured complexity" worries me a bit. The article Marc posted led me to beleive that Raytheon has used the complexity formula to "reverse engineer" their standard for software development. Just because their particular standard resulted in "decreased quality", does not mean there isn't a standard that results in a high level of quality PLUS a favorable complexity value. I have used the term quality to refer to the original article: maintainability, readability. It still makes sense that lower complexity values would improve this quality. I'm not sure that Raytheon's bad experience disproves this. It certainly bears further investigation. ------------------------------ Date: 24 Dec 87 19:26:04 GMT From: littlei!ogcvax!pase@uunet.uu.net (Douglas M. Pase) Subject: Program Complexity Metrics In article <PSUVM.28001UH2> UH2@PSUVM.BITNET (Lee Sailer) writes: >The <number of paths> thru a module doesn't impress me at all. A very simple >module constructed from a sequence of big CASE or SWITCH statements will have >many paths, but is easy to understand. >How 'bout a measure based on the *hierarchy* of Data Flow Diagrams? As I see it there are two problems. The first is the complexity of the paths through a module. A number of metrics have been proposed elsewhere and mentioned in this forum (cycle count, independent path count, etc.). The second problem is the complexity of the conditions each path places on the data that passes through, a la Floyd/Hoare program verification. for example, simple arithmetic expressions replace old conditions with new. An example might be: x > 5 --> 'x := x + 1' --> x > 6. Other types of expressions may replace old conditions with new, or add new restrictions. 'if' expressions are bad news, 'while' and recursive expressions can be worse. But, not all 'if', 'while', or recursive expressions are equally bad, and it's not just the relative location of each in a program. Lest anyone think I'm saying something profound, all I have said is that if one wishes to measure the complexity of a program, one must consider the program itself (or equiv. its tranformations of the data it modifies) and not just the flow of data through it. -- Doug Pase -- ...ucbvax!tektronix!ogcvax!pase or pase@cse.ogc.edu.csnet ------------------------------ Date: 5 Jan 88 13:33:20 GMT From: ndsuvax!ncmagel@uunet.uu.net (ken magel) Subject: Summary of Metrics Responses In December I sent a request for comments on use of software complexity metrics and what demonstrations people would require to cause them to use metrics. This message summarizes the nine responses I have received. Before summarizing the responses, let me define some vocabulary. A program complexity metric is a single number or small set of numbers which represents how difficult some task is with the source code of a program. The most common metric is the number of lines of code. Tasks might include debugging, program modification, or program understanding. A software complexity metric is a single number or small set of numbers which represents how difficult some task is with the source code of a complete software system, usually consisting of several programs. A system complexity metric is a single number or small set of numbers which predict or measure how difficult some task is when done on either system requirements or specifications. Now to summarize the responses. Some people are using the cyclomatic complexity metric proposed by McCabe in the mid-1970's. Those people use the cutoff of 10 in the cyclomatic complexity which McCabe proposed. That is, if a program has a cyclomatic complexity greater than 10, the program must be rewritten. Several people requested system complexity metrics rather than program or software complexity metrics. They stated that the payoff would be much greater with system complexity metrics. The most common response, however, was a request to find out what complexity metrics were. ------------------------------ Date: 8 Jan 88 18:17:00 GMT From: apollo!marc@beaver.cs.washington.edu (Marc Gibian) Subject: Examples: Optimizing Complexity Reduces Code Quality As promised, here are some examples of decreasing the quality of code while reducing the complexity measure value. The complexity measure used was Raytheon/ED/SSL-s version of the McCabe metric. They made one modification to the algorithm because they judged that they did not want to count each case in a switch as an increment in complexity. The contractual requirement was that every procedure and function have a McCabe value less than or equal to 10. I must admit that since I no longer work for them, the examples I am providing are not being extracted from product libraries. Instead, they are constructed examples describing the things that were actually done to the product I worked on while at Raytheon. Example 1: original fragment: if (a == value1) then y = target1; else if (b == value2) then y = target2; else if (c == value3) then y = target3; else if (d == value4) then y = target4; else if (e == value5) then y = target5; else if (f == value6) then y = target6; end if; transformed fragment: new_func((a == value1), target1); new_func((b == value2), target2); new_func((c == value3), target3); new_func((d == value4), target4); new_func((e == value5), target5); new_func((f == value6), target6); with new_func defined as: new_func(relation_value, target) { if (relation_value) then y = target; end if; } discussion: This example shows an original code fragment which tests a number of similar variables against a number of values. This can not be transformed into a CASE construct, so some way of removing the if else if chain must be found. The resulting code moves the tests into new_func. Note that this particular example uses y as global to new_func, to allow new_func to represent a single iteration of the if else if chain. Some may argue that the transformed code is better. I argue, though, that is hides the logic, while the original code was quite clear, therefore easily maintained. Example 2: original code fragment: if (failing) then if (color_display) then color = red; else inverse = TRUE; end if; else if (mode = offline) then color = color_1; else if (sub_mode = training) then color = color_2; end if; transformed fragment: if (! fail_func) then if (! mode_func) then sub_mode_fun; end if; end if; where fail_func is : BOOLEAN fail_func() { if (failing) then if (color_display) then color = red; else inverse = TRUE; end if; return (TRUE); else return (FALSE); end if; } discussion: The original code fragment handles the problem of selecting a color for a field in a display. The algorithm for this is a hierarchical checking of a number of variables. The fragment mearly moves testings into less obvious locations, while the main code fragment is reduced to calling functions that set the color. I believe the transformed code is more complex and harder to maintain because it is bigger, includes more interfacing, and separates the decisions relating to the color to use. Thats all I have time for now... I would like to repeat my feelings regarding complexity measures, based upon my experience in using them: I agree with the goal of using a metric to measure the characteristics of code, I simply believe that no metric now exists that truly measures the qualities that people (management, customers) want to measure. Marc S. Gibian Software Engineer Apollo Computers email: marc@apollo.UUCP ------------------------------ Date: 9 Jan 88 07:09:54 GMT From: decvax!cca!g-rh@ucbvax.Berkeley.EDU (Richard Harter) Subject: Examples: Optimizing Complexity Reduces Code Quality I would agree that the altered code is less desirable than the original code -- indeed the altered code is not correct in that it is not equivalent to the original code! The altered code goes through all tests whereas the original code stops testing when a match is found. The fundamental problem with the complexity measure in this case is, I believe, twofold: (a) that the language being used lacks the construct being used, and (b) the complexity measure is incorrectly calculated. The language doesn't really capture the parallelism of the construct. The desired construct, in pseudocode, runs something like this: define value list A = {a,b,c,d,e,f} define desired value list B corresponding to A = {value1,value2,value3,value4,value5,value6} define target list C corresponding to A = {target1,target2,target3,target4,target5,target6} loop through list A if item from A equals coresponding desired item from B then set y to target in C corresponding to item from A and exit from loop If the lists are short one prefers to embed them implicitly in the code; if they are long one prefers to be put them in tables. However this solution is not available if the types in the the value list are not all the same. If we borrow the naked select statement from PL/I the code would look like this select { a==value1: y = target1; break; b==value2: y = target2; break; ...... f==value6: y = target6; break; } Whether each case should count as an increment in complexity depends on the cases. In this instance the cases are parallel -- I would feel that the appropriate measure of complexity is the logarithm of the number of cases. If, however, the cases are not parallel, then I would feel that the compexity goes up linearly with the number of case. [I am not prepared to defend this position.] In any case what we see here is a complex structure that uses code repetition rather than data repetition. Neither the language being used, nor the complexity measure being used provide means for dealing with the higher level construct. Each, in its own way, deals with the higher level construct only in terms of lower level constructs. I would agree that the complexity measure being used does not adequately measure the complexity of the code -- I would argue that the fault lies in the lack of adequate means for heirarchical composition of structure in the language and a corresponding lack of measurement in the complexity measurement tool. -- In the fields of Hell where the grass grows high Are the graves of dreams allowed to die. Richard Harter, SMDS Inc. ------------------------------ End of Soft-Eng Digest ****************************** -------