Fat Classes
SonarQube Rule Name
Classes should not be Fat.
SonarQube Rule Description
A class is Fat if it contains too many internal dependencies (default 120). These are the dependencies between the methods, fields and inner classes contained by the class.
A Fat class is a structural problem for a number of reasons:
- Too much interdependent code elements in one place makes the class hard to understand and maintain. This makes it expensive to change, and more likely to introduce bugs when it does change.
- It will tend to have a lot of dependent classes, since any class dependent on even one method is forced to depend on all the code in the Fat class.
- It tends to make other structural problems (such as cyclic dependencies) harder to resolve, since all of the code in the Fat class is bound together, so that subsets cannot be moved to more suitable packages.
- It often violates the Single Responsibility Principle (ref. SOLID).
To repair a Fat class you need to move some of its contained methods, fields and/or inner classes into (usually new) other classes. It is helpful to view both the internal dependency graph, and how the internal elements are used by client classes. Are there any “cohesive clusters” - groups of methods, fields and/or inner classes that are highly cohesive, but loosely coupled with the rest of the code in the Fat class? Are there any separately identifiable responsibilities? Do the external/incoming dependencies indicate multiple usage patterns?
Tip: “Spotlight” and expand the Fat class in Structure101 Workspace to see both its internal and external dependencies. For more advanced analysis, use the “Group tangles and cohesive clusters” in Structure101 Studio, and tag/filter the incoming dependencies. Once you have identified a set of elements for extraction, use the “extract delegate” refactoring in your IDE.
SonarQube Issue Message
Move some of the class contents to new classes.
Fat methods
SonarQube Rule Name
Methods should not be Fat.
SonarQube Rule Description
A method is Fat if it contains too many execution paths (default limit 15). This is also known as McCabe’s metric, or Cyclomatic Complexity (CC). This measure recognises that it is the complexity of control flow that makes a function hard to understand and maintain, rather than the number of sequential lines.
A Fat method is a structural problem for a number of reasons:
- Too much code complexity in one place is hard to understand and maintain. This makes it expensive to change, and more likely to introduce bugs when it does change.
- A Fat method will sometimes have a lot of dependent code, since any code dependent on any part of the method’s functionality will be dependent on all the code in the method.
- A Fat method often violates the Single Responsibility Principle (ref. SOLID).
To repair a Fat method you need to extract some of its code into (usually new) other methods, which are given expressive names, and called from the original location of the extracted code. A Fat method will have a number of control blocks (if/else, for, while), often nested. The usual way to reduce complexity is to extract blocks of code until the number of paths is reduced below threshold.
Tip: Select a suitable block of code within the Fat method and use the “Extract Method” refactoring in your IDE. Repeat this until below threshold. Refresh the Structure101 Workspace “Structural Issues/Fat Methods” list to get changed value.
SonarQube Issue Message
Extract some blocks of code from this method into new methods.
Fat packages
SonarQube Rule Name
Packages should not be Fat
SonarQube Rule Description
A package is Fat if it contains too many internal dependencies (default 120). These are the dependencies between the classes and sub-packages contained by the package.
A Fat package is a structural problem for a number of reasons:
- Too many interdependent containers at one level of structural breakout is hard to understand and maintain. This makes it expensive to change, and more likely to introduce bugs when it does change.
- It will tend to have a lot of dependent external code, since any code dependent on even one class contained by the package will in a sense be dependent on the entire package.
- This course dependency granularity tends to make other structural problems (such as cyclic package dependencies) harder to resolve.
- It often violates the Single Responsibility Principle (ref. SOLID).
To repair a Fat package you need to move some of its contained classes and/or sub-packages into (usually new) other packages. It is helpful to view both the internal dependency graph, and how the internals are used by client code. Are there any “cohesive clusters” - groups of classes and/or sub-packages that are highly cohesive, but loosely coupled with the rest of the code in the Fat package? Are there any separately identifiable groups of classes/responsibilities that make for a cogent new package? Do the external/incoming dependencies indicate different usages? Is there a mix of sub-packages and classes under the Fat package - if so, you could push the classes down into new sub-packages.
Tip: “Spotlight” and expand the Fat package in Structure101 Workspace to see both its internal and external dependencies. For more advanced analysis, use the “Group tangles and cohesive clusters” in Structure101 Studio, and tag/filter dependencies. You can use the “tidy” command (Studio/Structure tab/context menu) to group any classes into sub-packages. Make sure you do not introduce cyclic package dependencies (tangles) as you break up the package. Once you have identified a set of classes/sub-packages for extraction, use the “move” refactoring in your IDE.
SonarQube Issue Message
Move some of the package contents to new packages.
Spec Dependency Violations
SonarQube Rule Name
Dependencies should comply with the Structure Spec.
SonarQube Rule Description
A Spec Dependency Violation breaks the layering and/or visibility rules expressed in the applicable Structure Spec.
A Structure Spec is an arrangement of modules and packages into groups and layers, that serves to:
- Share a common understanding of the intended structure across the team
- Let developers understand the details relevant to their current activity, in the context of an overall “architecture”
- Define a large number of dependency rules in a simple, visual form
- Catch dependencies at edit and/or build time.
To repair a Spec Dependency Violation, find the source of the violating dependency, and refactor the code so that the specified layering and/or visibility constraints are respected. Sometimes a change to the spec may be required.
Tip: Create and edit a Structure Spec using the “Overlays/Structure Spec” tab in Structure101 Studio. This lets you arrange existing and/or planned modules and packages into coloured groups to help understanding, adjust the layering to define allowable dependencies (dependencies should flow only downward), and to define modules and packages to be “private” to their parent scope. Use the Structure Map in Structure101 Workspace to see how local source code dependencies roll up through the spec, to drill down on the cause of violations, decide on suitable repair strategies, and navigate to the relevant code.
SonarQube Issue Message
Refactor so that dependencies comply with the Structure Spec.
Remove dependency on <…>
Spec Item Violations
SonarQube Rule Name
Items should not exist in a specified scope unless they are included in the Structure Spec for that scope.
SonarQube Rule Description
A Spec Item Violation occurs when a scope in a project is included in the Structure Spec, and an item exists in the actual code at that scope, but is not included in the Spec. The count of the number of classes contained by the violating container is used to measure the severity of the violation.
A Structure Spec usually grows from the top (or root) scope. So for example all the modules might be first specified to define groups of modules, the dependency layers, and visibility constraints. Then the internal package structure for one or modules may be added. Then sub-packages, etc. When a scope is added, it not only defines the dependencies, but also the items allowed at that scope. So if a new module is to be created, it needs to be added to the spec at the root level. Or if the sub-packages of package “a” have been included in the spec (e.g. a.x and a.y) and a new package (a.z) is created, then that new package is illegal until it is added to the spec.
Spec Item Violation checking serves 2 purposes:
- If a scope is specified, then the location of a new item at that scope needs to be explicitly defined it by adding it to the desired location (layer, group) within the spec
- When a scope is specified, it is important that all code at that level is covered by the spec. If new modules or packages were ignored, it could be that substantial quantities of code go unchecked against the spec.
To repair a Spec Item Violation, either add that items to the Structure Spec, or remove it from the code by moving its contents to other items that are in the spec.
Tip: Create and edit a Structure Spec using the “Overlays/Structure Spec” tab in Structure101 Studio. To add the new item to the spec, right-click “Add to spec”, and then move to the desired layer/group. To remove the violating item, use the Structure Map in Structure101 Workspace to discover the unspecified item, and navigate to the relevant code. Use the “move” refactoring in the IDE to move it to the desired specified container.
SonarQube Issue Message
Move the contents of this item into an item that is included in the Structure Spec.
This item contains <xx> classes.
Cyclic Package Dependencies
SonarQube Rule Name
Packages should not contain tangled sub-packages.
SonarQube Rule Description
A “tangle” is group of cyclically-dependent packages (and possibly classes) under the same parent. The parent is then considered tangled.
If the sub-packages and classes contained by a parent package are acyclically-dependent, then they can be arranged into layers so that all the dependencies flow downward. If some of the packages/classes are cyclically-dependent, then they cannot be levelized in this way. If they are arranged so that the minimum number of (weighted) dependencies flow upward, then these upward dependencies are called “feedback” dependencies. The weighted number of feedback dependencies (i.e. the number of code-level references that flow upward) is a good measure of the severity of the tangle.
Package tangles are a serious structural problem because:
- They drive up the cumulative component dependency (CCD) exponentially. CCD is a measure of the connectedness of a set of packages and classes.
- This increased coupling makes the tangled code much more difficult to understand and maintain, and more likely to create bugs when changed.
- A set of tangled packages cannot be separately developed or tested - they all need the latest version of each other.
- Tangles create monoliths. Tangled packages cannot be (e.g.) extracted into separate modules, since build systems do not allow cyclic dependencies between modules. As a result, modules that contain highly tangled packages tend to grow bigger and more tangled over time, and cannot be easily sub-divided.
To repair tangled sub-packages, look first at each end of the feedback dependencies, and observe the contingent dependencies (the dependencies in/on/from the dependent items). Look for misplaced sets of classes that can be moved to other packages so as to resolve the feedback dependencies. The feedback dependencies are a good guide, but don’t assume they are the “bad” dependencies - in some situations it makes sense to resolve tangles by focusing on non-feedback dependencies. If there are any Fat packages or classes involved in the cyclic dependencies, breaking up the Fat items may make it easier to resolve the tangles.
Tip: Always try to move classes (restructure) before changing code logic (refactor) since this is lower impact and risk - and the assignment of classes to packages may be accidental, and not worth a lot of effort to preserve. Using Structure101 Workspace, navigate to the tangled package. Expand each end of the feedback dependencies until the relevant classes and/or methods are exposed. Use the layering and specific dependencies to determine a resolution. Use the “move” refactoring in the IDE to move classes between packages. For more complex tangles that require many (sometimes dozens or hundreds) class moves to resolve, use the “Structure” tab in Structure101 Studio to simulate the moves and verify the result, before pushing the “action list” to Workspace for implementation.
SonarQube Issue Message
Move classes between sub-packages to remove the cyclic package dependencies.
There are <…> feedback dependencies in the tangle.
Architecture Diagram Violations
SonarQube Rule Name
Dependencies should comply with all enforced Architecture Diagrams.
SonarQube Rule Description
An Architecture Diagram Violation is a dependency that breaks the layering and/or visibility rules expressed in any Architecture Diagrams that have been tagged as “enforce”.
An Architecture Diagram is similar in some ways to a Structure Spec. Unlike a Structure Spec however, the structure of an Architecture Diagram is not locked to the actual structure of your project - the entities (“cells”) in the diagram map to classes in an arbitrary way (e.g. using pattern-matching). (Architecture Diagrams can be used to define actual structure too, but a Structure Spec is recommended for this).
Architecture Diagrams serve to:
- Define cross-cutting dependency rules
- Define a large number of dependency rules in a simple, visual form
- Catch dependency violations at edit and/or build time
To repair an Architecture Diagram Violation, find the source of the violating dependency, and refactor the code so that the specified layering and/or visibility constraints are respected. Sometimes a change to the Architecture Diagram may be required.
Tip: Create and edit Architecture Diagrams using the “Overlays/Architecture Diagrams” tab in Structure101 Studio. This lets you map classes to “cells”, and arrange the cells so that the layering defines allowable dependencies (dependencies should flow only downward), and to define cells to be “private” to their parent scope. Use the list of Architecture Diagram Violations in Structure101 Workspace to see any local source code dependencies that violate the Diagrams, and navigate to the relevant code.
SonarQube Issue Message
Refactor so that dependencies comply with Architecture Diagram(s).
Remove dependency on <…> which violates <diagram name>