Path: utzoo!utgpu!water!watmath!clyde!rutgers!mit-eddie!uw-beaver!apollo!marc From: marc@apollo.uucp (Marc Gibian) Newsgroups: comp.software-eng Subject: examples complexity measure usage Message-ID: <398e2f3e.fed5@apollo.uucp> Date: 8 Jan 88 18:17:00 GMT Organization: Apollo Computer, Chelmsford, Mass. Lines: 125 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 know 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