Features

Design smells detection

Design smells are certain structures in the design that indicate violation of fundamental design principles and negatively impact design quality.” (from Refactoring for Software Design Smells: Managing Technical Debt)

DPy identifies design smells and presents them in a view that classifies them based on the fundamental principle they violate. In addition, DPy also points out the cause of the smell and therefore provides a clue towards refactoring of the smell.

The following design smells are detectable by DPy:

  • Multifaceted abstraction: This smell arises when an abstraction has more than one responsibility assigned to it.

  • Feature envy: This smell arises when a method is more interested in members of other classes/modules.

  • Deficient encapsulation: This smell occurs when the declared accessibility of one or more members of an abstraction is more permissive than actually required.

  • Broken modularization: This smell arises when members of an abstraction are broken and spread across multiple abstractions. We detect a variant of the smell where a class or module only contains data members.

  • Insufficient modularization: This smell arises when an abstraction exists that has not been completely decomposed, and a further decomposition could reduce its size, implementation complexity, or both.

  • Hub-like modularization: This smell arises when an abstraction has dependencies (both incoming and outgoing) with a large number of other abstractions.

  • Wide hierarchy: This smell arises when an inheritance hierarchy is “too” wide and shallow indicating that intermediate types may be missing.

  • Deep hierarchy: This smell arises when an inheritance hierarchy is excessively deep.

  • Rebellious hierarchy: This smell arises when a subtype rejects the methods provided by its supertype.

  • Broken hierarchy: This smell arises when a supertype and its subtype conceptually do not share an “IS-A” relationship resulting in broken substitutability.

Detect implementation smells

DPy supports variety of smells that may occur at implementation level as well. Refactoring these smells lead to better code quality. DPy supports detection of the following implementation smells:

  • Complex conditional

  • Complex method

  • Empty catch clause

  • Long identifier

  • Long method

  • Long parameter list

  • Long statement

  • Magic number

  • Missing default

  • Long lambda function

  • Long message chain

Compute code quality metrics

DPy computes code quality metrics that are helpful to gauge the structural health of the software project. A list of supported metrics by DPy is presented below.

  • LOC: Lines Of Code in a method, class, or module.

  • CC: Number of unique complete paths in a method of Cyclomatic Complexity to measure code complexity of a method.

  • PC: Parameter Count in a method.

  • NOF: Number of Fields i.e., member variables, of a class/module.

  • NOPF: Number of Public Fields i.e., public member variables of a class/module.

  • NOM: Number of Methods defined in a class/module.

  • NOPM: Number of Public Methods defined in a class/module.

  • WMC: Weighted Methods per Class is the sum of cyclomatic complexities of all methods in the class/module.

  • DIT: Depth of Inheritance Tree of a class represents the number of ancestors (i.e., supertypes) in the inheritance hierarchy up to the class.

  • LCOM: Lack of Cohesion in Methods is a measure of lack of cohesion of a class. The implementation follows a custom implementation to avoid the problems of existing LCOM alternatives. Traditionally, LCOM value may range only between 0 and 1. However, there are many cases, when computing LCOM is not feasible and traditional implementations give value 0 giving us a false sense of satisfaction (that the class is perfectly cohesive). Therefore, this impelementation emits -1 for such cases indicating that we do not have enough information or LCOM is not applicable (for instance, for an interface). Find more information in this paper.

  • FANIN: Fan-in of a class/module represents the number of incoming unique dependencies.

  • FANOUT: Fan-out of a class/module represents the number of outcoming unique dependencies.