Presentation is loading. Please wait.

Presentation is loading. Please wait.

Software Remodeling Improving Design and Implementation Quality

Similar presentations


Presentation on theme: "Software Remodeling Improving Design and Implementation Quality"— Presentation transcript:

1 Software Remodeling Improving Design and Implementation Quality
Static analysis (audits and metrics) and dynamic analysis (run time) and refactoring. The goal of this presentation is to run metrics and audits on source code and attempt to predict: How “healthy” is source code? Do we have a good design or poor object design? How much time and effort is required to develop and maintain the classes? Can we re-use the classes ? (looking to reduce coupling (CBO) and increase cohesion (LOCOM). How much effort to test the methods? Al Mannarino Lead Systems Engineer

2 Who is CodeGear? Evolution of Borland
Application Lifecycle Management StarTeam Tempo Silk Gauntlet CaliberRM Together Delphi JBuilder Turbo Delphi Developer Tools C++Builder InterBase Turbo C++

3 CodeGear Strategy 100% focus on Developers!
Individual developer’s speed and productivity Team communication and collaboration Quality and performance Languages: Java, Delphi, C++, C#, PHP, Ruby, SQL Platforms: Java, Windows, Web, Open Source, Mac, Linux.

4 CodeGear Strategy + Team Velocity Collaboration Communication
Automation Process Visibility Value + Individual Velocity RAD VCL LiveSource Visual Design Refactoring Platforms Java/JEE Windows Open Source Web

5 CodeGear Goal Increase your individual and team productivity by 25% to 33% for example 1/3 faster time to market or 1/3 more features developed 1/3 less development cost

6 AGENDA Software Remodeling: Improving Design and Implementation Quality Apply automated software inspection and run-time analysis tools to help identify common problems that can cause performance and scalability issues. Discuss the problems found and demonstrate how tools can help accelerate the implementation of appropriate solutions. Find: Apply software quality audits (check for common coding errors and enforce standards) Apply software quality metrics (measure object-oriented design characteristics such as complexity, cohesion, and coupling) Reverse engineer structure and behavior (Reverse engineer class diagrams and generated sequence diagrams) Apply Application Quality Analyzer (analyze components for performance issues, detect misuses and identify errors) Discuss discovered problems (excessive temporary objects, dead code, highly complex methods, etc.) Generate documentation Fix: Discuss principles of software remodeling (audits/metrics, design patterns, refactoring) Create JUnit tests (code with confidence) Apply simple refactoring (modify design without breaking existing code, verify impact of refactoring) Apply pattern-based refactoring

7 Agenda Code Reviews Static Analysis (Audits and Metrics)
Metric-Driven Refactoring Dynamic Analysis (run time profiling) Code Reviews Rethought Q & A Discuss code reviews and there process. Run static analysis on code, the audits and metrics. Based on the results of the audits and metrics we can refactor the code. Metric-Driven refactoring is a technique most effective when cleaning up a large code base, where there are known issues and metrics may aid in understanding the problems. On a smaller project, a custom set of metrics can be configured with highly restrictive limits, so that as a project continues, the quality can be more accurately maintained. Run dynamic analysis on the code looking for performance bottlenecks and quality issues.

8 What is Software Remodeling?
A methodology for improving design and implementation quality using a combination of: audits, metrics, and refactoring. formal code reviews the “subtle science and exact art” of software engineering necessitates doing code reviews. part of a quality assurance program. The “subtle science and exact art” of software engineering necessitates formal code reviews within most development organizations. These code reviews are necessary as part of a quality assurance program, although not typically seen as such. Rather, they are often downplayed in importance, as their rewards are not of the “instant gratification” nature; rarely will a code review result in immediately recognizable performance improvements or productivity gains. A typical outcome of code reviews are refactorings in source code. While greatly touted recently, refactoring aims to change “the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior”. This is nothing new, but extremely important for the long term success of software projects. Recently, it has become stylish to develop software with agile methodologies. These methodologies focus on the production of working software rather than mountains of requirements specifications. The review of source code has carried over from more traditional processes, signifying their importance. Extreme Programming (XP), for example, utilizes a continuous code review, integration and refactoring methodology.

9 Manual Code Reviews versus Automated Code Reviews
As a code base increases in size and complexity, it becomes unlikely that a manual review process, no matter how frequent, can uncover all issues with a high degree of accuracy. Automation is necessary for tasks that are particularly well suited to machine processing. Recently, it has become stylish to develop software with agile methodologies. These methodologies focus on the production of working software rather than mountains of requirements specifications. Notably, the review of source code has carried over from more traditional processes, signifying its importance. In Extreme Programming (XP), code reviews are done continuously, along with integration and refactoring.

10 Code Reviews - Automation Case Studies
Task Review by hand a small example set of code 5 classes, 140 lines of code, 4 “experts” in 15 minutes Average audit violations detected: 21 Comparison The same set of code analyzed by a machine: Audit violations detected: 150 time: 2 sec 84/hr versus 270,000/hr Real “sample” Project 187,600 violations on a project with 1233 classes and 199,146 lines of code. 32,443 violations using the default set Actual customer case studies show ~400 man/hour savings per code review As an example of the gains that can be achieved using automated tools to identify audit violations, four “experts” were given 15 minutes to analyze a small set of Java™ source code. The code had been “engineered” to have several well known violations. The results of this extremely unscientific experiment reveal an obvious conclusion; human reviews alone are insufficient. The Mentors found an average of 21 violations in the 15 minutes allotted, while tools identified 150 violations in about 2 seconds using the complete set of Java™ audits. These results illustrate the gains that can be seen, although the processing of a full scale production application is even more telling. In one case, nearly 200,000 lines of source code from over 1200 classes were analyzed with tools, resulting in 32,443 violations from the default set of audits. So, what does this mean? Obviously, running audits and metrics on completed applications can be revealing and possibly guide some much needed refactoring. However, running them in parallel with development is preferred. Running audits frequently during development will help to enforce established best practices, while routine metric analysis can help to maintain design issues in check throughout the development of an application. The inclusion of audits and metrics in the development process go hand in hand not only with the agile methodologies that stress continuous integration, testing and refactoring, but with any process that involves best practices in coding standards and object-oriented design concepts. The automated audits and metrics complement comprehensive unit testing suites, and will help create that “warm fuzzy” often felt after successful refactoring and testing.

11 “Agile” Software Development
“Agile Manifesto” states that working software should be valued over comprehensive documentation. implies if reviews are to be done with an agile process, it is likely that source code would be the only artifact deemed worth reviewing. Taken to the extreme, XP provides a form of continuous code review, as development is always done in pairs, Other lightweight processes, such as Feature-Driven Development (FDD), incorporate design and code reviews as part of their activities. A trend in the software industry is toward more “agile” approaches to software development. In fact, the recently written “Agile Manifesto” states that working software should be valued over comprehensive documentation. This would seem to imply that if reviews are to be done with an agile process, it is likely that source code would be the only artifact deemed worth reviewing. Taken to the extreme, XP provides a form of continuous code review, as development is always done in pairs. Other lightweight processes, such as Feature-Driven Development (FDD), incorporate design and code reviews as part of their activities. So, it is clear that even if the processes used to develop software have become lighter, the review of source code is still regarded as a necessity.

12 Audits - Enforcing Rules for Source Code Conformance
What are Audits? Checks for conformance to standard or user-defined style, maintenance, and robustness guidelines. Motivation Improved readability Improved standards-conformance Increased performance Reveal subtle errors that may result in bugs Categories, such as: Coding Style Errors Documentation Superfluous Content Performance, etc… We’ve already defined what an audit is and why it’s important in a general sense with respect to the overall goal of reasonable code reviews. Let’s consider some of the specifics regarding audits. Source code formatting standards are found in most organizations, if not just adapted from Sun’s Coding Standards for Java™. Requiring legible source code is no different than requiring legible PowerPoint slides; communication is facilitated. But, there are many categories of audits ranging from coding style, superfluous content and errors for a particular language. Many of the audits found in books like Effective Java™ by Joshua Bloch are easily automated with tools like JBuilder 2007 for Eclipse. In fact, many of the items found in books like Effective Java™ are included in JBuilder 2007 for Eclipse, in addition to many more. Leveraging the auditing capabilities of Together® as part of your routine development tasks can improve the quality of your developers as well as your code.

13 An Example Audit ASWL – Append to String Within a Loop
Category: Performance Effective Java™: Item 33 – Beware the performance of string concatenation Wrong: public String method() { String var = "var"; for (int i=0; i<10; i++) { var += (" " + i); } return var; Right: public String method() { StringBuffer var = new StringBuffer("var"); for (int i = 0; i < 10; i++) { var.append(" " + i); } return var.toString(); Append to String Within a Loop (ASWL) About every book or article that deals with Java™ performance starts with the issue of String concatenation. In Java™, all String objects are immutable. This means that when two strings are joined together, a new String object must be created (well, almost true). In fact, when the += operator is used to join two Strings, a StringBuffer object is also created. So, when performing multiple String concatenations (i.e. in a loop), it is more efficient to create a single StringBuffer object and use its append() method to perform the concatenation. Using the StringBuffer class will therefore minimize the number of objects created, and subsequently garbage collected, during multiple String concatenations. This audit violation is easy to spot and can provide significant improvement in application efficiency. How long would it take to find all of these violations in your code base?

14 Why is “Append to String Within a Loop” bad?
In Java™, all String objects are immutable. This means that when two strings are joined together, a new String object must be created (well, almost true). In fact, when the += operator is used to join two Strings, a StringBuffer object is also created. So, when performing multiple String concatenations (i.e. in a loop), it is more efficient to create a single StringBuffer object and use its append() method to perform the concatenation. Using the StringBuffer class will therefore minimize the number of objects created, and subsequently garbage collected, during multiple String concatenations. This audit violation is easy to spot and can provide significant improvement in application efficiency. How long would it take to find all of these violations in your code base?

15 Sample audit “Avoid float and double if exact answers are required”.
Item 31 in “Effective Java”. Floating-point types are intended for use in scientific or mathematical equations where numbers of large magnitude are calculated. They are not intended for use in comparing small values, particularly those involving currency values. In this case, rounding in calculations may cause errors, particularly when dealing with values in the negative powers of 10. For example, if you declare two doubles d1 = 1.03 and d2 = 1.13 and compare d1 – d2 to the expected answer of –0.1, you find that they are unequal using the == operator. Additionally, when overriding the equals() method, comparisons to an object’s floating point type fields should for the same reasons use the Double.doubleToLongBits() and Float.floatToIntBits() methods for double and float fields, respectively. Tools comes with more than 100 source code audits for Java and nearly half as many for C++. These range from the simple (for example, Order of Appearance of Modifiers) to the more complex and specific (for example, Managing Threads in an EJB™). The tool also gives you the ability to write your own custom audits using an OpenAPI. The remainder of this section looks at one specific Java audit. The audit selected for review here is also found as Item 31 (“Avoid float and double if exact answers are required”) in Effective Java. In Tools, the audit is named CFPT—Comparing Floating Point Types—and is found in the Possible Errors category. Floating-point types are intended for use in scientific or mathematical equations where numbers of large magnitude are calculated. They are not intended for use in comparing small values, particularly those involving currency values. In this case, rounding in calculations may cause errors, particularly when dealing with values in the negative powers of 10. For example, if you declare two doubles d1 = 1.03 and d2 = 1.13 and compare d1 – d2 to the expected answer of –0.1, you find that they are unequal using the == operator. Additionally, when overriding the equals() method, comparisons to an object’s floating point type fields should for the same reasons use the Double.doubleToLongBits() and Float.floatToIntBits() methods for double and float fields, respectively. The prospect of scanning through all of an application’s source code to find potential errors such as this illustrates why automation is required. Because the audit functionality in Tools is incorporated into the development environment, routinely running audits during development provides the greatest long-term benefit.

16 Audits -Case Studies Apache Tomcat 5.5.20
PetStore from Sun’s J2EE Blueprints Program # Violations Sun Code Conventions for Java™ Audit Set 5258 Total from Default Audit Set 851 Apache Tomcat 8468 Apache Ant – including 442 of “High” severity. AFLV (Assignment to ‘for’ Loop Variables) 11 ASMO (Accessing Static Members through Objects) 28 ASWL (Appending to String Within a Loop) 40 HIA (Hiding Inherited Attributes) 9 HISM (Hiding Inherited Static Methods) 1 HN (Hiding Names) MVDSN (Multiple Visible Declarations with Same Name) 23 OWS (Overloading Within a Subclass) 24 2752 The increasing popularity of open source development provides ample fodder for audit and metric case studies. For example, the Sun Code Conventions for Java™ audit set was run on the Blueprint’s Program PetStore source code. A total of 5258 violations were detected, 851 of which fell into audits default set, which does not count many of the “trivial” violations required by the Sun Code Conventions for Java™ set. Apache’s Ant was also analyzed, resulting in 2752 audit violations from the default set, including 442 of “High” severity.

17 Metrics - Quantifying Source Code Characteristics
What are Software Metrics? Measurements that allow for the analysis of software code and design. Motivation Improve the process of developing software Identify potential defects through quantitative measures Further understanding of software design complexity Categories - Basic Counts - Encapsulation - Cohesion - Polymorphism - Coupling - Inheritance - Complexity - Halstead’s The definition of software metrics is complicated, at best. Fundamentally, metrics involve counting, or measuring. Based upon what is being measured, a relative scale can be used to analyze the results, indicating the condition of source code. Whereas audits focused on mostly syntactic analysis, metrics focus more on design-level parameters. These range from the obvious, to complex, to obtuse, depending on your point of view. The goal is to gather data that may later be analyzed in such as way as to indicate where flaws may exist. The reverse may also be stated, whereby metrics may provide some assurance that an underlying body of code is without serious flaw. Of course, given the fact that metrics are currently found in the “subtle science” category, these statements are impossible to prove. However, there is increasing rigor being applied to the “strict art” of metric analysis, with the hope being that someday software quality will be mathematically provable. Until that day, we must understand a bit of the theory behind these metrics and how to best put to use what they tell us. This section will begin with more of the truth behind the state of today’s metrics, followed by some basic metrics and how they may be used in conjunction with code reviews. This will only serve as a brief introduction to the metrics available in Together® ControlCenter™ 6.0, which ships with 55 metrics for Java™. How “healthy” is source code? Do we have a good design or poor object design?

18 Metrics - A disclaimer There is no “silver bullet” metric suite.
You can use metrics to guide projects, but be careful not to let them paralyze a project when developers overanalyze. There are also reasons why automated tools can produce misleading results. This is often due to particular language features that cannot be accounted for in a general sense. For example, the use of reflection in the Java programming language makes static analysis of source code problematic. In this case, reflective use of a class and its methods will appear to static analysis tools as the mere utilization of the Reflection API and not the actual class involved. Metrics indicate false dependencies when they encounter the use of this feature. The use of metrics fundamentally boils down to understanding what is being measured, how it is being measured, and how you interpret any results. This is why, at present, a human mind is still necessary to provide interpretation. Don’t be too quick to jump to conclusions based upon metric results. Refactoring code should only be undertaken after considering the astute advice found in “Refactoring: Improving the Design of Existing Code by Martin Fowler”. Finally, a set of etiquette rules should be part of every metric program; although it is likely they will be disregarded at one point or another. In general, the plan should be published and the importance of not assigning blame to individuals should be stressed. Metrics should not be used in a way that inhibits the process of producing working software.

19 Eight (8) Metrics for Java Development
Simple starting point to help answer basic questions about the size, quality of design, and ability to modify or maintain existing code. Lines of Code Number of Classes Lack of Cohesion of Methods (3) Cyclomatic Complexity Weighted Methods per Class (1) Coupling Between Objects Number of Overridden Methods True Comment Ratio 8 Metrics for Java Development Counting object-oriented metrics is a task in and of itself. There are so many possibilities from obscure, academic tomes. But how can a team get started with a simple set of metrics that can help improve design? To be sure, any team should develop their own expertise around OO metrics. While there is no "magic bullet", the following 8 metrics are meant as a simple starting point to help answer basic questions about the size, quality of design, and ability to modify or maintain existing code. Lines of Code Number of Classes Lack of Cohesion of Methods (3) Cyclomatic Complexity Weighted Methods per Class (1) Coupling Between Objects Number of Overridden Methods True Comment Ratio Abbreviation LOC Category Basic Description This is the traditional measure of size. LOC counts the number of code lines. Documentation and implementation comments as well as blank lines can be optionally interpreted as code. Usage As a measure of the overall project size, the LOC can be useful to help normalize comparisons between different projects. However, the LOC poorly captures any design aspects and should only be used for rough estimation. At the class level, LOC should not exceed a predefined threshold. Long classes are difficult to fully comprehend, making reuse and testing difficult. The Sun Code Conventions for Java recommend 1000 as the upper limit. NOC This is an object-oriented measure of size. It counts the number of classes. As a check against LOC for overall project size, the NOC can be useful to normalize comparisons between different projects. Also similar to LOC, NOC poorly captures any design aspects and should only be used for rough estimation. At the package level, an upper limit can be helpful to create optimally sized components. However, an appropriate upper limit varies for different types of components. For example, EJB will automatically have 4X as many classes as a plain Java application. At the class level, the overuse of inner classes can cause confusion and difficutly in reuse. As such, the NOC for a class should not exceed 5. LOCOM3 Cohesion Measures the dissimilarity of methods in a class by attributes. Consider a set of m methods, M1, M2, ... , Mm The methods access a data attributes, A1, A2, ... , Aa Let a(Mk) = number of attributes accessed by method Mk Let m(Ak) = number of methods that access data Ak Then   a     1 / a m(Ai)   -  m    i=1   LOCOM3 =   100 1 - m   The definition of this metric was proposed by Henderson-Sellers in 1995. LOCOM3 is primarily used at the class level. High lack of cohesion increases complexity, thereby increasing the likelihood of errors during the development process. Low value indicates good class subdivision implying simplicity and high reusability. The measured value is essentially a percentage so anything greater than 50% should be considered for refactoring into 2 or more classes. CC Complexity This measure represents the cognitive complexity of the class. It counts the number of possible paths through an algorithm by counting the number of distinct regions on a flowgraph, meaning the number of if, for and while statements in the operation's body. Case labels for switch statements are counted if the Case as branch box is checked. A strict definition of CC (introduced by McCabe in 1976) looks at a program's control flow graph as a measure of its complexity:        CC  = L - N + 2P where L is the number of links in the control flow graph, N is the number of nodes in the control flow graph, and P is the number of disconnected parts in the control flow graph. For example, consider a method which consists of an if statement: if (x>0) { x++; } else { x--; } CC = L - N + 2P = *1 = 2 A less formal definition is:        CC = D + 1 where D is the number of binary decisions in the control flow graph, if it has only one entry and exit. In other words, the number of if, for and while statements and number of logical and and or operators. For the example above: CC = D + 1 = = 2 CC is most meaningful at the method level. McCabe's recommendation for the upper limit of CC is 10. Methods exceeding this complexity should be candidates for refactoring. Commonly, the metric can be improved by replacing conditional logic with polymorphism or by moving reasonable sections into separate methods. These techniques do not reduce overall system complexity but serve to distribute the complexity more evenly. WMPC1 This metric is the sum of the complexity of all methods for a class, where each method is weighted by its cyclomatic complexity. The number of methods and the complexity of the methods involved is a predictor of how much time and effort is required to develop and maintain the class. Only methods specified in a class are included, that is, any methods inherited from a parent are excluded. As a sum of CC for a class, usage WMPC1 parallels CC usage for methods. The recommended upper limit is 30. Classes exceeding this complexity should be candidates for refactoring. Commonly, the metric can be improved by replacing conditional logic with polymorphism. CBO Coupling Represents the number of other classes to which a class is coupled. Counts the number of reference types that are used in attribute declarations, formal parameters, return types, throws declarations and local variables, and types from which attribute and method selections are made. Primitive types, types from java.lang package and supertypes are not counted. Excessive coupling between objects is detrimental to modular design and prevents reuse. The more independent a class is, the easier it is to reuse it in another application. In order to improve modularity and promote encapsulation, inter-object class couples should be kept to a minimum. The larger the number of couples, the higher the sensitivity to changes in other parts of the design, and therefore maintenance is more difficult. A measure of coupling is useful to determine how complex the testing of various parts of a design is likely to be. The higher the inter-object class coupling, the more rigorous the testing needs to be. Number of Overridded Methods NOOM Polymorphism Counts the number of inherited operations that a class overrides. High values might indicate design problems because subclasses should generally add to and extend the functionality of parent classes rather than override them. If the NOOM exceeds 10 for a class, consider using composition instead of inheritence. TCR Ratio Counts the ratio of documentation and/or implementation comments to total lines of code (all comments are excluded from the code count). Blank lines can be optionally interpreted as code. The appropriate number of comments depends on the corporate policy in this area. In any case, comments improve readability of the program and simplify changes. It is recommended to provide at least 5% comments relative to the amount of code lines. The upper limit of the metric can also be recommended as a maximum of four lines of comments for each line of code, which is especially relevant for documenting interfaces. Too many comments (more than 400%) makes it too difficult to read the classes.

20 Depth of Inheritance Hierarchy (DOIH)
Inheritance is one of the features of object-oriented programming that was much touted and then greatly abused. It has since fallen somewhat out of favor, largely replaced by composition and interfaced-based design strategies. Where it is appropriately used, inheritance is a powerful design feature. Like all things, moderation is the key. Deep inheritance hierarchies can lead to code fragility with increased complexity and behavioral unpredictability. An easy metric to comprehend, DOIH indicates the number of classes that are parents of a class, with the top-most class having a count of one (not zero as some computer scientists would think). In many metric tools, DOIH does not include the implementation of interfaces, while interface extension is counted. Next slide illustrates an inheritance hierarchy where the DOIH value for the AppException class is 5, while the DOIH value for RuntimeException is 4, and so on.

21 DOIH = 1 This diagram illustrates an inheritance hierarchy where the Depth of Inheritance Hierarchy (DOIH) value for the AppException class is 5, while the DOIH value for RuntimeException is 4, and so on. DOIH = 2 DOIH = 3 This diagram illustrates an inheritance hierarchy where the DOIH value for the AppException class is 5, while the DOIH value for RuntimeException is 4, and so on. DOIH = 4 DOIH = 5

22 Number of Child Classes (NOCC)
For a given class, the number of classes that inherit from it is referred to by the metric Number of Child Classes (NOCC). With increasing values of NOCC, the potential for reuse increases, while testing difficulty and potential misuse of inheritance also increase. Generally speaking, a high level of NOCC may indicate the improper abstraction of the class. In the Java programming language, implemented interfaces count when calculating NOCC. For example, if an interface is implemented by a class, which has six subclasses, the NOCC value for the interface is seven, while the implementing class has a NOCC value of 6. In the Java programming language, implemented interfaces count when calculating NOCC. For example, if an interface is implemented by a class, which has six subclasses, the NOCC value for the interface is seven, while the implementing class has a NOCC value of 6.

23 classes extend the EventSupport class, giving it a NOCC value of 6.
This diagram indicates how Number of Child Classes (NOCC) values are calculated. Starting at the bottom, each of the Event classes has no children and therefore receives a NOCC value of 0. Each of the 6 *Event classes extend the EventSupport class, giving it a NOCC value of 6. Finally, at the top of the hierarchy is the interface Event with its implementation (children) classes totaling 7. This diagram indicates how NOCC values are calculated. Starting at the bottom, each of the Event classes has no children and therefore receives a NOCC value of 0. Each of the 6 *Event classes extend the EventSupport class, giving it a NOCC value of 6. Finally, at the top of the hierarchy is the interface Event with its implementation (children) classes totaling 7.

24 Coupling Between Objects (CBO)
Object-oriented design necessitates interaction between objects. Excessive interaction between an object of one class and many objects of other classes may be detrimental to the modularity, maintenance, and testing of a system. CBO counts the number of other classes to which a class is coupled, except for inherited classes, java.lang.* classes, and primitive types. A decrease in the modularity of a class can be expected with high values of CBO. However, some objects necessarily have a high degree of coupling with other objects. In the case of factories, controllers, and some modern user interface frameworks, you should expect a higher value for CBO. An important note about the implementation of the CBO metric is that it only counts each type used in a class once. Multiple usages of a class as referenced, thrown as an exception, or passed as a formal parameter are only counted at their first occurrence. As mentioned, parent classes do not count, as is the case for implemented interfaces. There is an implicit high degree of coupling in these cases.

25 The Map m passed as the second
From the class declaration, you get 0, as implementation and extension do not count as couplings in the CBO metric. The class attributes int number and String string do not count because they are considered primitives. The List list attribute does count, but only once, even though a List type is passed as an argument to method one(). (1) The Map m passed as the second argument counts, creating the second coupling. (2) Finally, in the method two(), the throws AppException declaration (3) counts as a coupling, in addition to the local File file variable. (4) Again, the List type has already been counted. public class CBO extends Base implements Metric { private int number; private List list; private String string; public void one(List l, Map m) { list = l; } private List two() throws AppException { File file; //... return new List(); The sample code indicates a class that is coupled to a total of four other classes. From the class declaration, you get 0, as implementation and extension do not count as couplings in the CBO metric. The class attributes int number and String string do not count because they are considered primitives. The List list attribute does count, but only once, even though a List type is passed as an argument to method one(). The Map m passed as the second argument counts, creating the second coupling. Finally, in the method two(), the throws AppException declaration counts as a coupling, in addition to the local File file variable. Again, the List type has already been counted.

26 Response for Class (RFC)
The number of methods, internal and external, available to a class. The enumeration of methods belonging to a class and its parent, as well as those called on other classes, indicates a degree of complexity for the class. RFC differs from CBO in that a class does not need to use a large number of remote objects to have a high RFC value. Response for Class (RFC) The number of methods, internal and external, available to a class is known as the Response for Class (RFC) metric [Chid94]. The enumeration of methods belonging to a class and its parent, as well as those called on other classes, indicates a degree of complexity for the class. RFC differs from CBO in that a class does not need to use a large number of remote objects to have a high RFC value. Consider a class with a large number of exposed methods that is used by a client class extensively. In this case, the client class RFC value would be high while its CBO could be one. Distinguishing CBO as a coupling measure and RFC as a complexity measure is important. Many metrics have relationships and/or similarities to other metrics. Because RFC is directly related to complexity, the ability to test, debug, and maintain a class increases with an increase in RFC. In the calculation of RFC, inherited methods count, but overridden methods do not. This makes sense, because only one method of a particular signature is available to an object the class. Also, only one level of depth is counted for remote method invocations. RFC is the sum of local and remote methods available to a class. In Figure 4, class A has a parent class with six methods. Class A overrides four of them and adds none. This leaves six as the total number of local methods. Looking into the methods of class A, you count seven distinct calls to methods of classes B and C. However, the cardinality of the union of these methods gives us six, as f1() on class B is called from both f1() and f2() in class A. Thus, RFC = = 12 for class A. Note that the methods available in the parent class (those not overridden) may use remote methods. These are not counted in the subclass RFC calculation.

27 Response for Class (RFC)
The number of methods, internal and external, available to a class. The enumeration of methods belonging to a class and its parent, as well as those called on other classes, indicates a degree of complexity for the class. RFC differs from CBO in that a class does not need to use a large number of remote objects to have a high RFC value. Because RFC is directly related to complexity, the ability to test, debug, and maintain a class increases with an increase in RFC.

28 Cyclomatic Complexity (CC)
Counts the number of possible paths through a method. In other words, using if, for,and while statements as path indicators counts the total number of paths through the body of a method. Consider a method represented as a strongly connected, Directed Acyclic Graph (DAG). The formula for CC equals the number of edges e, minus the number of nodes n, plus two times the number of components p. CC = V(G) = e – n +2p Cyclomatic Complexity (CC) Cyclomatic Complexity (CC) counts the number of possible paths through a method, as indicated by the conditional statements it contains. In other words, using if, for, and while statements as path indicators counts the total number of paths through the body of a method. Consider a method represented as a strongly connected, Directed Acyclic Graph (DAG). The formula for CC equals the number of edges e, minus the number of nodes n, plus two times the number of components p. CC = V(G) = e – n +2p It is important to realize that CC does not count into called internal or external methods. Optionally, Tools can count case statements as branches. As expected, the more complex a method is, the more difficult it is to test and debug. The value of CC for a method can be used as an indicator for the minimum number of test cases needed. However, the Nejmeh NPATH metric (1988) is a better indicator for the number of test cases required. To illustrate CC, consider the following method in diagram.

29 Cyclomatic Complexity example
public void one(){ if(true) { while(false) { two(); } } else { for(int i=0;i<10;i++) { In this method, there is an if statement containing a while loop with a for loop in the else portion. What’s the CC for this method? To illustrate CC, consider the following method. In this method, there is an if statement containing a while loop with a for loop in the else portion. What’s the CC for this method?

30 simplified illustration shows CC = 8 – 6 + 2(1) = 4.
Considering the distinct paths through this method, there are four paths, as the simplified illustration shows CC = 8 – 6 + 2(1) = 4. CC = V(G) = e – n +2p The formula for CC equals the number of edges e, minus the number of nodes n, plus two times the number of components p. public void one(){ if(true) { while(false) { two(); } else { for(int i=0;i<10;i++) { Considering the distinct paths through this method, it is obvious there are four, as the simplified illustration shows CC = 8 – 6 + 2(1) = 4. CC = V(G) = e – n +2p The formula for CC equals the number of edges e, minus the number of nodes n, plus two times the number of components p.

31 Weighted Methods Per Class (WMPC)
If you were to sum the values for CC for every method in a class, you would have the WMPC value. Alternatively, a simple count of the methods and their formal parameters also gives WMPC. In tools, WMPC1 implements the former, while WMPC2 implements the latter. Weighted Methods Per Class (WMPC) If you were to sum the values for CC for every method in a class, you would have the Weighted Methods Per Class (WMPC) metric value [Chid94]. Alternatively, a simple count of the methods and their formal parameters may provide the WMPC value. In tools, WMPC1 implements the former, while WMPC2 implements the latter. In equation form, consider n to be the number of methods and c to be a measure of the method’s complexity. See equation. As the WMPC value for a class increases, the time and effort for development and maintenance increases. Also, the potential reuse of the class may decrease as its WMPC value increases. In measuring WMPC, inherited methods are not included, while getter, setter, and private methods are included. Because this is a simple metric to conceptualize, it is important to see the value in using both WMPC1 and WMPC2 to better understand a class. For example, a class with one extremely long and complex method yields a high value for WMPC1 but a small value for WMPC2. Conversely, a class with many small methods that are not complex yields similar results for WMPC1 and WMPC2. Finally, a data or value object class with getters and setters for each attribute results in a higher value for WMPC2 than WMPC1. As this talk explains later, there is a significant amount of information regarding a class that can be gleaned from a small sampling of metrics, particularly when displayed visually. Tells us time and effort for development and maintenance of a class and the potential reuse of the class

32 Weighted Methods Per Class (WMPC)
In equation form, consider n to be the number of methods and c to be a measure of the method’s complexity. As the WMPC value for a class increases, the time and effort for development and maintenance increases. Also, the potential reuse of the class may decrease as its WMPC value increases. In measuring WMPC, inherited methods are not included, while getter, setter, and private methods are included. In equation form, consider n to be the number of methods and c to be a measure of the method’s complexity. See equation. As the WMPC value for a class increases, the time and effort for development and maintenance increases. Also, the potential reuse of the class may decrease as its WMPC value increases. In measuring WMPC, inherited methods are not included, while getter, setter, and private methods are included. Because this is a simple metric to conceptualize, it is important to see the value in using both WMPC1 and WMPC2 to better understand a class. For example, a class with one extremely long and complex method yields a high value for WMPC1 but a small value for WMPC2. Conversely, a class with many small methods that are not complex yields similar results for WMPC1 and WMPC2. Finally, a data or value object class with getters and setters for each attribute results in a higher value for WMPC2 than WMPC1. As this talk explains later, there is a significant amount of information regarding a class that can be gleaned from a small sampling of metrics, particularly when displayed visually.

33 An Example Metric Weighted Methods Per Class
Provides the sum of the static complexities of all methods in a class. Let n be the number of methods Let c be a measure of a method’s complexity Then, Note that complexity is normally a measure of Cyclomatic Complexity (CC), but may also be taken as unity for each method. Weighted Methods Per Class (WMPC) If you were to sum the values for Cyclomatic Complexity for every method in a class, you would have the Weighted Methods Per Class metric value. Alternatively, a simple count of the methods may provide the WMPC value.

34 Metrics- Weighted Methods Per Class – An Example
public class WMPC { public void one(){ if(true) { two(); } else { } if(true && !false){ public void two(){ if(true){} public void three(int i){} cc 3 2 1 6 mc 1 2 4 Two flavors of WMPC are available. In WMPC1, the Cyclomatic Complexity values of the methods in a class are summed. WMPC2 provides a method count for a class and includes parameters.

35 Metrics - Weighted Methods Per Class (continued)
In general, as WMPC increases: Time and effort for development increases Impact on children classes increases Testing difficulty increases Reuse of the class may decrease WMPC does not include inherited methods. WMPC includes getter, setter and private methods. WMPC1 sums the CC for each method, while WMPC2 sums the number of methods and parameters. As the WMPC value for a class increases, the time and effort for development and maintenance increases. Also, the potential reuse of the class may decrease as its WMPC value increases. In measuring WMPC, inherited methods are not included, while getter, setter and private methods are included.

36 Metrics - Common Business Impacts of High Complexity
Impede Delivery Productivity drops as developers spend more time to understand code and make changes. Reduce Quality Complexity strongly correlates with higher defect density. Increase Risk Adequate testing coverage becomes more evasive as the number of paths through an application increase. Raise Spend Because defects are harder to catch, they are caught later, leading to higher costs to fix. Improving the Quality of Application Code Challenge Increasing the quality of the application source code means facilitating the team’s ability to maintain and extend the source code in a heterogeneous environment where developers are often moved from one project to the next. Given the size of the project (over 100,000 lines of code), it is very difficult to perform manual inspection of the code to find problems such as complex methods, dead code, violations of code conventions, and deviations from industry best practices. After isolating the problems, the team will need to fix the problems without breaking existing functionality. Those members of the team who find and fix the problems will eventually learn how to avoid the problems in the future but capturing that knowledge for future members ensures the lessons learned will not be forgotten. Finally, a key challenge to increasing code quality is balancing this goal with the external goals to create new functionality or fix defects. As such, it is critical to prioritize the code quality efforts. Impact When code quality is not actively pursued, the architectural integrity of an application suffers. This confuses developers, impedes re-use, and may even impact performance. Most importantly, it makes each subsequent change to a system take longer and longer. Given the early stages of iGO, AIMS, and iConsole, the development team wants to ensure the application can be maintained and extended as quickly as possible.

37 Lack of Cohesion of Methods (LOCOM)
The most complex metric in the default set, measures the dissimilarity of methods in a class by attributes. Fundamentally, it indicates the cohesiveness of the class, although the values increase as the cohesiveness decreases. Lack of Cohesion of Methods (LOCOM) As the most complex metric in the default set, Lack of Cohesion of Methods (LOCOM) measures the dissimilarity of methods in a class by attributes [Chid94]. Fundamentally, LOCOM indicates the cohesiveness of the class, although the values increase as the cohesiveness decreases.

38 Lack of Cohesion of Methods (LOCOM)
Computes a measure of similarity for a number of methods m accessing a set of attributes Aj, where a is the number of attributes. With an increase in LOCOM, the encapsulation characteristics of the class are also brought into question. Also, the complexity increases with a decreasing reuse potential for the class. This makes intuitive sense, as a class that has methods operating on separate attributes should bring the Extract Class refactoring to mind. The calculation of this metric alone should convince you that manual means of gathering measurements for metric analysis is not feasible! Without going into the details, consider an example of a class with three attributes and two methods. The first method accesses two of the attributes while the second method accesses the third attribute. This is clearly a class lacking in cohesion, as verified by the LOCOM result of 100. Suppose the class is modified such that the second method accesses all three attributes. Now, the LOCOM value is 34, indicating that each of the methods accesses 66% of the attributes. If the first method were also to access all three attributes, the value for LOCOM would drop to zero, indicating “complete” cohesion. Notice the values for LOCOM1. In the first case, its value is 1 while it dropped to 0 for the second case. The main problem with LOCOM1 is the ambiguity associated with a value of zero, and the fact that it is possible to achieve the same result for classes that are very dissimilar from a cohesion standpoint. This ambiguity and other issues are discussed at length in “Object-Oriented Metrics: Measures of Complexity,” by Brian Henderson-Sellers. With an increase in LOCOM, the encapsulation characteristics of the class are brought into question. Also, the complexity increases with a decreasing reuse potential for the class. This makes intuitive sense, as a class that has methods operating on separate attributes should bring the Extract Class refactoring to mind.

39 Metric interpretation
A collection of metrics data generated by static source code analysis is not too valuable in raw form. Just as the UML™ provides for the visualization of your design in the form of class diagrams, for example, metric results are best displayed graphically for interpretation. Bar graphs, Kiviat charts, and Distribution Graphs. Also important to identify trends in metric results over a period of time. Metric interpretation A collection of metrics data generated by static source code analysis is not too valuable in raw form. Just as the UML™ provides for the visualization of your design in the form of class diagrams, for example, metric results are best displayed graphically for interpretation. This section describes how to visualize metrics in bar, Kiviat, and distribution graphs. Also, because it is important to identify trends in metric results over a period of time, this section explains a method for comparing one set to another.

40 Metrics - Interpretation & Outcome
Visualizations: Bar Graph Kiviat Graph Distribution Graph Metrics Results Comparison Metric-Driven Refactoring A collection of metrics data generated by static source code analysis is not too valuable in raw form. Just as the UML provides for the visualization of your design in the form of Class diagrams, for example, metric results are best displayed graphically for interpretation. Here, we will discuss how to visualize metrics in bar, Kiviat and distribution graphs. Also, as it is important to identify trends in metric results over a period of time, a method for comparing one set to another is also presented. Finally, a discussion on how the interpretation of these results can help to drive refactorings is included.

41 Metrics Visualization – Kiviat Graph
Scaled Axis for Each Metric Red Circle Represents Upper Limit A Kiviat graph provides a powerful visualization of several metrics at once, each represented as an axis emanating from a central point. Each metric axis is scaled such that its upper limit is normalized, forming a red circle at some distance from the center. This allows for a quick scan of the results for the chosen package, making it immediately clear which fall outside their respective limit.

42 Metrics Visualization – Kiviat with UML Class Diagram
Here, discuss how Kiviat graphs can augment the view of a class, providing implementation detail and overall class design characteristics.

43 Metrics Trend Analysis
Increased To spot increases, decreases and new additions to your project’s metric analysis, it is desirable to compare one set of results with another. It is possible to output metric results in several ways. One way is as a loadable format. Utilizing these capabilities, it is possible to load previous results and overlay current results in a color-coded table view. In this case, a red block indicates an increase in value, whereas a blue block indicates a decrease in value. For those classes that were examined that may be missing from the previous, a gray shading is used. Additionally, in order to compare actual numbers, tooltips are provided as you hover over each cell. Comparison Decreased

44 Metrics Case Studies PetStore Ant
The increasing popularity of open source development provides ample fodder for audit and metric case studies. For example, Kiviat graphs for both PetStore1.3 and Apache Ant indicate that most metric results exceed the default limits that ship with ControlCenter™. Note that Comment Ratio on both is effectively zero! So, based solely upon these graphs, can we say that PetStore and Ant are poorly written, failing software projects? Absolutely not. Does the fact that all but one or two values from the Ant analysis exceed the default limits raise some concern? Perhaps. At a minimum, it will give us some guidance as we examine these projects and their designs in more detail.

45 Metrics - SUMMARY Metrics are indeed “deep and muddy waters”.
A firm grasp of object-oriented design concepts and an understanding of what a metric is designed to detect are key. components in a successful metric program. If you are new to metrics, it is best to start with a small subset, such as those described here, and not get too caught up in the details. In other words, take an “agile” approach to implementing a metrics program; focusing on the results you can obtain by using them effectively and not on using them to fulfill a process requirement. Summary Metrics are indeed “deep and muddy waters”. A firm grasp of object-oriented design concepts and an understanding of what a metric is designed to detect are key components in a successful metric program. If you are new to metrics, it is best to start with a small subset, such as those described here, and not get too caught up in the details. In other words, take an “agile” approach to implementing a metrics program; focusing on the results you can obtain by using them effectively and not on using them to fulfill a process requirement. Combined with audits, metrics usage can provide significant long-term value to the underlying quality of your source code and the design it implements. As with audits, the collection of metric data must be automated to provide value. The remainder of this talk focuses on how audits and metrics, in particular, can lead to refactorings in your source code to improve its design and implementation quality.

46 Refactoring It’s one of the buzzword conversations about software development. Made famous by a book of the same title [Fowler], it is a term for what has always occurred during the development of software. Basically, refactoring involves changing source code in a way that does not change its behavior but that improves its structure. The goal is to more easily understand and maintain software through these usually small changes in its design and implementation. How does a developer know what to refactor on a large, somewhat unfamiliar code base? Refactoring Refactoring is one of the latest buzzwords conversations about software development. Made famous by a book of the same title [Martin Fowler 1999], it is a term for what has always occurred during the development of software. Basically, refactoring involves changing source code in a way that does not change its behavior but that improves its structure. The goal is to more easily understand and maintain software through these usually small changes in its design and implementation. Refactoring support in development tools is now commonplace. It is much more likely that a developer will perform a refactoring if all affected sections of source code can be presented ahead of time. However, other than the daily, smaller focused refactorings, how does a developer know what to refactor on a large, somewhat unfamiliar code base? Audits and metrics drive refactorings. An automated, easy-to-use environment where these complementary activities can take place is necessary. JBuilder 2007 provides such an environment.

47 Refactoring -Metric-Driven
Configure Metrics sets that are aimed at certain refactorings: Extract Class CBO, NOIS, NOC, LOCOM3, FO, NOAM, LOC, NOA, NOO, NORM, HPLen Extract Subclass NOA, NOM, NOO, RFC, WMPC1, NOAM, WMPC2, DAC, FO, NOCC Extract Method MSOO, NOCON, RFC, MNOL, CC, NORM, WMPC1, MNOP, WMPC2, CBO Extract Interface NOOM Inheritance-Based Refactorings DOIH, NOCC It is possible to save your metric selections and limits for running again at a later date. Using this functionality, it is also possible to save configurations of metrics that are pre-configured to point out potential refactorings. For example, the Extract Class refactoring may be driven by a combination of metrics that point out high couplings (CBO), lack of cohesion (LOCOM3), number of attributes (NOA), etc. Metric Driven Refactoring This technique is most effective when cleaning up a large code base, where there are known issues and metrics may aid in understanding the problems. On a smaller project, a custom set of metrics can be configured with highly restrictive limits, so that as a project continues, the quality can be more accurately maintained. Configure Metrics sets that are aimed at certain refactorings: Extract Class CBO, NOIS, NOC, LOCOM3, FO, NOAM, LOC, NOA, NOO, NORM, HPLen Extract Subclass NOA, NOM, NOO, RFC, WMPC1, NOAM, WMPC2, DAC, FO, NOCC Extract Method MSOO, NOCON, RFC, MNOL, CC, NORM, WMPC1, MNOP, WMPC2, CBO Extract Interface NOOM Inheritance-Based Refactorings DOIH, NOCC

48 Refactoring - Some Considerations
Use Audits to target certain refactorings: Reverse Conditional, Remove Double Negative NOIS (Negation Operator in ‘if’ Statement) Encapsulate Field PPA (Public and Package Attribute) Renaming NC (Naming Conventions – uses regex) Run Audits before Metrics UPCM and ULVFP before WMPC2, NOA etc. ILC before NOIS Format Code before Metrics, as may impact: LOC (Lines Of Code) – consider using HPLen (CR) Comment Ratio & (TCR) True Comment Ratio Audits may also be run to target certain refactorings. For example, to Reverse a Conditional, the NOIS (Negation Operator on ‘if’ Statement) audit may be run. Running audits before metrics can be key. Some metrics will be altered based upon the running and correction of certain audit violations. For example, UPCM (Unused Private Class Member) may identify an unused class attribute, as ULVFP (Unused Local Variable or Formal Parameter) may identify an unused local or formal parameter. In these cases, the metrics WMPC2 (Weighted Methods Per Class 2) and NOA (Number of Attributes) may be affected. Finally, the formatting of source code to your company standards can not only make it more readable for refactorings, but may also impact the result of certain metrics, such as LOC (Lines of Code), CR (Comment Ratio) and TCR (True Comment Ratio).

49 Metric-driven refactoring
Refactoring can be a double-edged sword. Be careful not to “bite off more than you can chew,” so to speak, while refactoring a code base. The process can work as follows: Run unit tests, audits, and formatting tools. Run and analyze metric results on your code. Navigate to the offending areas, looking for problem areas. Refactor the code, keeping design patterns in mind to potentially apply. Rerun the audits, metrics, and unit tests. Metric-driven refactoring Refactoring can be a double-edged sword. Be careful not to “bite off more than you can chew,” so to speak, while refactoring a code base. This goes hand-in-hand with having unit tests to run before and after a refactoring, thereby verifying that the functionality of the system is preserved. With this, it may be beneficial to run audits and metrics before and after refactoring to see the impact. This helps to check that you’re moving in the right direction. This is an extremely basic (“agile”) process. The process can work as follows: 1. Run unit tests, audits, and formatting tools. 2. Run and analyze metric results on your code. 3. Navigate to the offending areas, looking for problem areas. 4. Refactor the code, keeping design patterns in mind to potentially apply. 5. Rerun the audits, metrics, and unit tests. In tools you can save your metric selections and limits for running again later. Using this functionality, it is also possible to save configurations of metrics that are preconfigured to point out potential refactorings. For example, the Extract Class refactoring may be driven by a combination of metrics that point out high couplings (CBO), lack of cohesion (LOCOM3), number of attributes (NOA), and so on. Another example is using the metrics Maximum Size Of Operation (MSOO), Response For Class (RFC), Maximum Number Of Levels (MNOL), Cyclomatic Complexity (CC), Weighted Methods Per Class (WMPC1 & WMPC2), and so on, to identify potential Extract Method refactorings. This technique is most effective when cleaning up a large code base, where there are known issues and metrics may aid in understanding the problems. On a smaller project, a custom set of metrics can be configured with highly restrictive limits, so that as a project continues, the quality can be more accurately maintained. It’s important to keep tabs on the quality of your source before you are too far outside the limit so as to preclude “safe” refactoring. Audits may also be run to target certain refactorings. For example, to identify the Reverse a Conditional refactoring, you can run the Negation Operator on ‘if’ Statement (NOIS) audit. Running audits before metrics can be key, as some metric results are altered based upon the running and correction of certain audit violations. For example, Unused Private Class Member (UPCM) may identify an unused class attribute, while Unused Local Variable or Formal Parameter (ULVFP) may identify an unused local or formal parameter. In these cases, the metrics WMPC2 and NOA are affected. Finally, the formatting of source code to your company standards can make it more readable for refactorings but may also impact the result of certain metrics, such as Lines of Code (LOC), Comment Ratio (CR), and True Comment Ratio (TCR). As an alternative to LOC, consider using the Halstead Program Length (HPLen) metric, as it is unaffected by format.

50 Metric-driven refactoring example
Using Tomcat as an example, lets demonstrate metric-driven refactorings. Lines of Code: ,429 Number of Classes: 1,819 Metric-driven refactoring example Open source projects and their published historical code bases make for interesting case studies. Using Tomcat as an example, this talk will demonstrate metric-driven refactorings. DEMO: Run default METRICS on Tomcat source code. Takes about 5 minutes.

51 Apache Tomcat 5.5.20 Lines of Code: 181,429 Number of Classes: 1,819
METRIC Violations (16): CBO, DAC, DOIH, FO, MNOL, MNOP, NOA, NOAM, NOCON, NOO, NOOM, NORM, PProtM, RFC, WMPC1, WMPC2 AUDIT Violations (14 Critical): [8,468 total audit violations] Comparison always produces the same result. Accessing null reference. Invocation of method can cause infinite recursion. Data is lost in result of type conversion. Integral argument 0 of method may be out of domain Statement is unreachable Name of type not derived from bean type ends with "Bean". Overriding non-abstract method with abstract method. Integer division in floating-point context. java.lang.String.indexOf(int pattern, in pos) called with as indexOf(pos, pattern) Inaccessable match constructors or methods. Null value may be passed as argument 0 of method but non-null value is required. Array index is out of range. Loop body is never executed In summary, these are the critical audit and metric violations from Apache Tomcat

52 Tomcat WMPC1 This metric is the sum of the complexity of all methods for a class, where each method is weighted by its cyclomatic complexity. The number of methods and the complexity of the methods involved is a predictor of how much time and effort is required to develop and maintain the class. Only methods specified in a class are included, that is, any methods inherited from a parent are excluded. Running the default set of metrics on the Tomcat code base reveals a number of violations. Initially, it is important to get a clear picture of what an overall project Kiviat graph is telling you about the “health” of the underlying code. Notice: TCR = 0 for open source code. We need to be careful to interpret this view correctly. This Kiviat is displaying an entire code base for Tomcat, with metric values displayed according to their aggregation and granularity settings with package-level limits. At this level, you’re typically viewing the maximum values of each metric for each class in the project. This is true as long as the metrics are set to an aggregation of maximum and a granularity of class, as is often the case. It is highly probable that your project will yield a similar looking Kiviat graph at this level. Looking at the overall view of an entire project, it is likely that you will tend to use a few favorite metrics. Take a look at the metrics MSOO and WMPC1. The MSOO metric is just the maximum CC value for the methods in a class. Also, recall that WMPC1 is a summation of the CC values for all the methods in a class. In this case, the MSOO value for all the classes in Tomcat is 61, while its limit is set at 10. The value for WMPC1 is 577, while its limit is set at 30. Remember, this view does not tell you that a single class possesses both of these characteristics—only that these maximums are found within the project. Typically, those classes with large operations have correspondingly large complexities. Drilling down through the Tomcat hierarchy with MSOO as the guide leads you to the class WebdavServlet. Here, the second highest value for MSOO in Tomcat does not correspond to the highest WMPC1 value. However, it is still rather high at 282 (upper limit 30). What this means is that while the class WebdavServlet has a long operation (as measured by Cyclomatic Complexity = 290), the sum of the CC values for all methods in the class is not the highest in the project; that honor belongs to the class StandardContext, whose WMPC1 value is 577. (For the curious, its MSOO value is 49.) Prior to attempting any refactorings, it is important to run the JUnit tests, audits, and code formatter on the class. There is no JUnit test case, so you can overlook that step in this case (this is not recommended). For example: Weighted Methods Per Class 1 (WMPC1) Description: This metric is the sum of the complexity of all methods for a class, where each method is weighted by its cyclomatic complexity. The number of methods and the complexity of the methods involved is a predictor of how much time and effort is required to develop and maintain the class. Only methods specified in a class are included, that is, any methods inherited from a parent are excluded.

53 Default audits for WebdavServlet
DEMO: Running the default audits (takes about 5 seconds) for the WebdavServlet reveals two audit violations.; Comparator always returns the same result and Statement is not reachable. Sometimes you can automatically fix these audit violations with tools. Show the code for these two audit violations. Finally, reformat the source code to make it the most readable (it’s OK just the way it is).

54 Extract Method metrics run on WebdavServlet.
Now that you’ve identified a class (WebdavServlet) with a large MSOO, take a look at the class with the refactoring Extract Method in mind. Remember Extract Method metrics includes: MSOO, NOCON, RFC, MNOL, CC, NORM, WMPC1, MNOP, WMPC2 and CBO. Maximum size of operation, Number of Constructors, Cyclomatic Conplexity, Number of Remote Methods, Weighted Methods per Class 1 and 2, Coupling between objects, Maximum number of levels and Maximum number of parameters. Note: Have a predefined ExtractMethod.qa file already created with these metrics. DEMO: Run these Extract Method metrics on WebdavServlet. We see high values for most of these metrics, such as MSOO = 59 and WMPC1 = 282. Show the descriptions of these methods. MSOO = Counts the maximum size of operations for a class. Method size is determined in terms of cyclomatic complexity, meaning the number of if, for, and while statements in the operation's body. Case labels for switch statements can be optionally included. WPMC1 = This metric is the sum of the complexity of all methods for a class, where each method is weighted by its cyclomatic complexity. The number of methods and the complexity of the methods involved is a predictor of how much time and effort is required to develop and maintain the class. Only methods specified in a class are included, that is, any methods inherited from a parent are excluded. CC = represents number of cycles in the measured method. This measure represents the cognitive complexity of the class. It counts the number of possible paths through an algorithm by counting the number of distinct regions on a flowgraph, meaning the number of if, for, and while statements in the operation's body. Case labels for switch statements are counted if the Case as branch property is activated. CBO = Represents the number of other classes to which a class is coupled to. Counts the number of reference types that are used in attribute declarations, formal parameters, return types, throws declarations, local variables, and types from which attribute and method selections are made. Primitive types, types from java.lang package and supertypes are not counted. Excessive coupling between objects is detrimental to modular design and prevents reuse. The more independent a class is, the easier it is to reuse it in another application. In order to improve modularity and promote encapsulation, inter-object class coupling should be kept to a minimum. The larger the number of coupling, the higher the sensitivity to changes in other parts of the design, and therefore maintenance is more difficult. A measure of coupling is useful to determine how complex the testing of various parts of a design is likely to be. The higher the inter-object class coupling, the more rigorous the testing needs to be.

55 Extract Method refactoring
After running these Extract Method set of metrics, you can see that the doLock() method is extremely long and gives the opportunity for several refactorings. In particular, the last commented block of code before the method return typifies a problem area. This block can be more easily refactored into its own method named writeResponse(). DEMO: Double Click on the doLock method to open it in the editor. Refactor | Extract Method | select the last block of code starting with: XMLWriter generatedXML = new XMLWriter(); And ending with: writer.close();

56 Extracting writeResponse()
Refactor a problem block of code into its own method named writeResponse(). In particular, the last commented block of code before the method return typifies a problem area. This block can be more easily refactored into its own method named writeResponse().

57 Method comparison What do you suppose could best explain these results? parseProperties() Another interesting exercise with the Kiviat graphs Look at the two “similar” operations in WebdavServlet like parseLockNullProperties() and parseProperties(). In fact, the shapes of the graphs are nearly identical. Both include violations for MNOP and CC. What do you suppose could best explain these results? A comparison of the bodies for each method should reveal that one was likely cloned from the other. This technique is a common form of “reuse” in software; however, it is not recommended. parseLockNullProperties()

58 Extract Class (WebdavServlet)
Lack Of Cohesion Of Methods 3 (LCOM3) Measures the dissimilarity of methods in a class by its attributes. A low value indicates good class subdivision, implying simplicity and high reusability. A high lacking of cohesion increases complexity, thereby increasing the likelihood of errors during the development process. Next, lets run Extract Class metrics on the WebdavServlet class. These metrics are: CBO, NOIS, NOC, LOCOM3, FO, NOAM, LOC, NOA, NOO, NORM, HPLen DEMO: Run Extract Class metrics on the WebdavServlet class. Lack Of Cohesion Of Methods 3 (LCOM3) = Measures the dissimilarity of methods in a class by its attributes. A low value indicates good class subdivision, implying simplicity and high reusability. A high lacking of cohesion increases complexity, thereby increasing the likelihood of errors during the development process. If there are no more than one method in a class, LCOM3 is undefined. If there are no variables in a class, LCOM3 is undefined. An undefined LCOM3 is displayed as -1. Methods that do not access any class variables are not taken into account. Looking at the LOCOM3 value for the WebdavServlet, it is clear this class is lacking in cohesion by its score of 93. This leads to a number of questions regarding cohesion: Is it possible for all classes to be cohesive? Can WebdavServlet be more cohesive? What refactorings come to mind with a high value for LOCOM3? One possibility is Extract Class (what this set of metrics are aimed at finding). Running the custom metric set that attempts to identify a need for the Extract Class refactoring on WebdavServlet yields this Kiviat graph.. In this set, the upper limit for LOCOM3 has been set to 80 because tools do not recommend a limit by default. Looking at the Kiviat graph for the results indicates that WebdavServlet could stand for some additional refactoring. Interestingly, it seems to be within the limits for Number Of Overridden Methods (NOOM), Number Of Operations (NOO), Number Of Classes (NOC), Number Of Added Methods (NOAM), and Number of Attributes (NOA). So, it’s not as though the class has an extraordinary number of methods, inner classes, added methods (those added to its inherited methods), or attributes. However, it does appear to have low cohesion, high coupling and a high fan out, along with excessive Lines of Code (LOC) and Halstead Program Length (HPLen) =calculated as 'Number of Operators' + 'Number of Operands'.

59 service() Method What refactoring can best replace this ugly section of code? Before extracting a class, take a look at what this Servlet does. A sequence diagram generated from its service() method should indicate what its primary purpose. In this case, the service() method simply extracts the posting method for the incoming request and invokes a do* method for each of the available WebDav methods, passing the request and response objects along. What refactoring can best replace this ugly section of code? Perhaps Replace Conditional with Polymorphism? Suppose you created a new WebdavHandler interface and have implementation classes for each of the WebDav methods. Then, you’d need a Factory pattern to return the appropriate handler given the passed in method that was extracted from the request object. In tools, you can use the built-in GoF Factory Method pattern to do just that. In the end, the WebdavServlet merely delegates to the appropriate handler class for each incoming WebDav request. This should significantly reduce the metric results for WebdavServlet, because its functionality is spread amongst the handler classes. Of course, this drives up some other metric values for Tomcat, given the newly created classes and interface. However, they should in themselves, and in summation, provide lower values for the offending metrics that started this Extract Class refactoring. If you have time, you can complete this refactoring, else leave it as a “homework” assignment for the attendees to see the exact results.

60 Dynamic Analysis Visibility inside the black box
J2EE System Servlets JSP™ Server-side Presentation Application Business Logic EJB DB Remote or Legacy System JDBC® JMS Database Web Transaction BLACK BOX Next we’ll look at the Dynamic Analysis of our application. Explain Dynamic Analysis gives you “visibility” inside the black box J2EE container. Without these types of tools you could never get this type of information. Dynamic Analysis gives you: Timing information on the Web Transaction level looking at the whole system. You get overall URI timing as well as the overall system. But that’s what you got with traditional tools. You also get information about how long the JSP took, What it called and how long each call took as well as timing metrics for each call AND THE SOURCE CODE FOR EACH CALL! Here you see Timing information on the URI as well as information on the JSP that services it (along with source code if needed) How the JSP is calling the components (EJB, JDBC, etc) and the source The QA team could pinpoint the slow component and even the calls that are taking the most time At the component OR SOURCE CODE LEVEL This is incredibly powerful information that QA can now deliver No more blamestorm No more throwing the entire system back to the developer teams Quick time to isolation Quick time to resolution Quick time to market

61 Dynamic Analysis – What to avoid
JDBC threw an exception JNDI lookup threw an exception JSP or servlet threw an exception EJB invocation threw an exception JMS threw an exception RMI call threw an exception JMS object, such as a Producer, wasn't closed correctly JDBC object, such as a result set or a statement, wasn't closed correctly Serializable object exceeds the maximum HttpSession size Serializable object failed serialization Unserializable entry in the HttpSession Serializable object is too large JMS object closed when children were still open JDBC object closed when children were still open Avoid misuses of J2EE, such as adding non-serializable objects to a session, forgetting to close a JDBC object, forgetting to close a JMS object, adding large objects to a session, as well as exceptions thrown but not caught from the various J2EE APIs. AVOID: JDBC threw an exception JNDI lookup threw an exception JSP or servlet threw an exception EJB invocation threw an exception JMS threw an exception RMI call threw an exception JMS object, such as a Producer, wasn't closed correctly JDBC object, such as a result set or a statement, wasn't closed correctly Serializable object exceeds the maximum HttpSession size Serializable object failed serialization Unserializable entry in the HttpSession Serializable object is too large JMS object closed when children were still open JDBC object closed when children were still open Verifies that HttpSession entries are serializable. Failure to claim serializability in an entry in the HttpSession will produce problems on a few application servers, and is reported as a warning. Failure to serialize an object which claims to be serializable is an error, and must be corrected. Objects which fail serialization will not failover properly in a production system, and may lead to impossible-to-reproduce production problems. Hurried or careless development can result in applications for which the size of a serialized HttpSession may balloon. From pointing at an XML tree, to referencing the ServletContext within an Object in the session, it is easy to mistakenly overload HttpSessions with unnecessary information. ServerTrace allows you to set a maximum threshold for session size, beyond which an error is generated. Again, as with failed serialization, large HttpSessions can lead to production instability and difficult-to-reproduce problems. JDBC and JMS activity is monitored by the Application Quality Analyzer view, as well. If your application closes a parent resource before its children are closed, a warning is reported. If the VM garbage collects a JDBC or JMS object before that object is closed, an error is reported. Some application servers automatically close JMS objects for you, and in that case, errors and warnings may not be posted. In other cases, objects which are never closed aren't even available for garbage collection, and in this case, you should pay attention to the number of open resources in the # Open column of the JDBC Details view and JMS Details view. In most cases, however, the implicit close of garbage collection, which works fine on development machines, but which can fail on production systems under load, is detected. Again, errors should be considered as an indication that the application in production is likely to run into problems related to system (JDBC or JMS) resources

62 Dynamic Analysis – Tomcat 5.5.20
Dynamic Analysis of Tomcat running Tomcat home page. No Quality issues detected on Tomcat startup. That’s a good thing. Since Tomcat is not a J2EE container, we will switch to JBoss 4.05 to show a J2EE application.

63 How old is Duke? When Was Duke, the Java mascot born?
Hint: when the first demo of Java technology was publicly released. Let’s run dynamic analysis on a J2EE application with EJBs, JSPs and Web Service and see if we nave any quality and performance issues? DEMO: “How old is Duke” application with Optimizeit Request Analyzer or ServerTrace.

64 How old is Duke? So how old is Duke?
When Was Duke, the Java mascot born? Hint: when the first demo of Java technology was publicly released. Duke was born on May 23, 1995 So how old is Duke? DEMO: “How old is Duke” application with Optimizeit Request Analyzer or ServerTrace.

65 J2EE Dynamic Analysis Dynamic Analysis shows “Session entry helloBeanId is not serializable”. Edit HelloBean class and add “public class HelloBean implements Serializable “. Re-deploy Re-run test client and show this error goes away?

66 Code Reviews - Rethought
“The detection of design problems for large or very large systems is impossible to be fulfilled manually and must therefore be accomplished by automated methods.” (Marinescu) Automate as much as possible using available tools Utilize tools with projectors, rather than printouts Perform “live” metric-driven refactorings during code reviews Don’t lose focus of the business logic A great time to perform refactorings is during code reviews. Using a tool with an overhead projector is recommended, as it is difficult to refactor, compile and test code that has been printed out on paper.

67 Code Reviews - Rethought (continued)
Don’t wait until a formal code review to run audits and metrics Run them frequently, in order to: minimize the time spent in code reviews increase the capabilities of your team Run with nightly build Run after unit tests Maintain Audit/Metric results for later data analysis Code reviews should occur frequently, as opposed to being left until the end of milestones or the entire project. With each developer using an automated tool, the need to review mountains of source code for common audit hits is eliminated. In fact, given that code reviews are commonly skipped when project schedules tighten, automated audit and metric analysis are the only reviews likely to be done at all. When used routinely by all developers, the need for formal code review sessions may be eliminated altogether in the future, with the exception of business logic reviews. Until then, the use of audits, metrics and automated refactorings will serve as an accelerator to team reviews and ultimately raise the quality of not only the source code, but of the developers who master them.

68 Conclusion A great time to perform refactorings is during code reviews. Using tools with an overhead projector is recommended, because it is difficult to refactor, compile, and test code that has been printed out on paper. Code reviews should occur frequently, as opposed to being left until the end of milestones or the entire project. With each developer using tools, the need to review mountains of source code for common audit hits is greatly reduced. Given that code reviews are commonly skipped when project schedules tighten, automated audit and metric analyses are the only reviews likely to be done at all. When used routinely by all developers, the need for formal code review sessions may be eliminated altogether in the future, with the exception of business logic reviews. Until then, the use of audits, metrics, and automated refactorings serve as an accelerator to team reviews and ultimately raise the quality of not only the source code but also the developers who master them. This talk merely introduces the notion of metric-driven refactoring and provides a crude example of its application. The refinement and standardization of metric result visualizations is needed to provide an added dimension to the recognition of class characteristics. It is not hard to imagine how a Kiviat graph, to the trained eye, can augment a UML class diagram in displaying a more compete picture of class characteristics and interactions. Perhaps a UML profile can provide this visualization?


Download ppt "Software Remodeling Improving Design and Implementation Quality"

Similar presentations


Ads by Google