Analyses Reference

Bundle: SOLID
Category: Single Responsibility Principle (SRP)
Languages: C++
Targets: Class, Struct

This design flaw refers to the mistake of directly implementing several different interfaces in a single class or struct, thus making it hard to replace or to reuse the implementation of a single interface without changing the implementations of the other interfaces. If for some reason, a class must implement two interfaces, it is recommended to separate the actual implementations either by means of inheritance (one of the interfaces implemented by a super class) or composition (one of the interfaces implemented by a different class to which the class in question delegates).

The detection rule for this design flaw looks for classes or structs that fully implement at least 2 different abstractions (interfaces or pure abstract classes). A class or a struct is considered to fully implement an abstraction if it provides actual implementations for all the pure virtual methods of the abstraction. Note that an implementation, which only delegates to another class is not considered an actual implementation. The severity of this flaw is a function of the number of fully implemented abstractions and the total number of pure virtual methods defined in these abstractions.

References: Martin02

Bundle: SOLID
Category: Single Responsibility Principle (SRP), Open / Closed Principle (OCP)
Languages: C, C++
Targets: Function

This design flaw is inspired by Martin Fowler’s namesake code smell and typically points to a missing abstraction. The flaw manifests itself as a group of formal parameters declared in multiple functions over and over again throughout the system. Decl aring the same formal parameters over and over again hides the fact that the data values passed to these formal parameters are related and it also complicates the signatures of the declaring functions, making them harder to call. It is a good practice to group related data together, turn them into a new abstraction (structured type), and use this abstraction to replace the common group of formal parameters with a single formal parameter declaration in all the involved functions.

The detection rule for this design flaw looks for at least 3 unrelated functions (global functions or methods which are not part of the same method hierarchy), having at least 5 shared formal parameter declarations (formal parameter declarations having the same parameter name and type). The severity of this flaw depends on the number of affected functions and the number of shared formal parameter declarations.

References: Fowler99

Bundle: SOLID
Category: Single Responsibility Principle (SRP), Open / Closed Principle (OCP)
Other names: Misplaced Function/Method

Languages: C++
Targets: Function

This design flaw is inspired by Martin Fowler’s namesake code smell and refers to a function (global fuction or method), which is overly interested in the data members of an external class, called an envied class. In case of a method, in addition, the method must be more interested in the data members of the envied class than in the data members of its enclosing class. This flaw typically indicates that the affected function should really be a member of the envied class.

The detection rule for this design flaw looks for a global function or a method, referencing at least 5 external data members and at least 3 data members of a single external class either directly or indirectly through accessor methods. In case of a method, the method in question must also reference more data members from this external class than from its own class. The severity of this flaw depends on the number of referenced data members from the envied classes, the number of accesses to these data members, and the number of calls to accessor methods of these data members. Write accesses and calls to setters carry more weight than read accesses and calls to getters.

References: Riel96, Fowler99

Bundle: SOLID
Category: Single Responsibility Principle (SRP), Open / Closed Principle (OCP)
Other names: Centralised Control

Languages: C++
Targets: Class, Struct

This design flaw refers to the mistake of accumulating too much control in a class, usually at the expense of several satellite classes. In object-oriented design, a class is also a unit of encapsulation, meaning that it is supposed to bundle data with the methods operating on that data. A God Class breaks the encapsulation rule, because it manipulates (either directly or indirectly) data members belonging to its satellite classes. Such a class tends to be a maintencnace nightmare, because of its increased complexity and high coupling to its satellite classes.

The detection rule for this design flaw looks for classes, which write either directly ot through a setter at least 3 data members belonging to unrelated classes. A class is considered unrelated to the target class if it doesn’t belong to the same class hiearchy and it doesn’t contain the target class. As a general rule structs are not considered classes, unless they are involved in inheritance relationships. The severity of this flaw depends on the number of written data members and the number of write references to these data members.

References: Riel96, Fowler99, Trifu08

Bundle: SOLID
Category: Single Responsibility Principle (SRP), Open / Closed Principle (OCP)
Other names: Centralised Control

Languages: C++
Targets: Function

This design flaw refers to the mistake of accumulating too much control in a global function, usually at the expense of several satellite classes. In object-oriented design, a class is also a unit of encapsulation, meaning that it is supposed to bundle data with the methods operating on that data. A God Function breaks the encapsulation rule, because it manipulates (either directly or indirectly) data members belonging to its satellite classes. Such a function tends to be a maintencnace nightmare, because of its increased complexity and high coupling to its satellite classes.

The detection rule for this design flaw looks for global functions, which write either directly ot through a setter at least 3 class data members. As a general rule structs are not considered classes, unless they are involved in inheritance relationships. The severity of this flaw depends on the number of written data members and the number of write references to these data members.

References: Riel96, Fowler99, Trifu08

Bundle: SOLID
Category: Single Responsibility Principle (SRP), Open / Closed Principle (OCP)
Languages: C++
Targets: Function

This design flaw, inspired by Lieberherr’s Law of Demeter and Martin Fowler’s namesake code smell, refers to the mistake of assuming a given internal structure of classes and explicitly writing navigation code to get from an object to another object stored in its internals in order to use this internal object as prefix in a member reference expression to select the target object for a method invokation or a data access. The name of thid design flaw comes from its typical appearance in code as a chain of references to internal data members, where each reference in the chain targets an internal data member of the object denoted by the previous reference in the chain. A reference to an internal data member is either a direct access to this data member or a call to a method returning this data member. Also, the chain of references can be explicit as shown below:

object1.getDataMember2().dataMember3.service()

or implicit, meaning that referenced intermediate data members are stored in local variables, as shown below:

object2 = object1.getDataMember2(); 
object3 = object2.dataMember3; 
object3.service();

Having such chains in a function makes it susceptible to change, whenever the internals of the classes referenced in the chains need to change.

The detection rule for this design flaw looks for a global function or a method containing message chains as the ones described above, involving unassociated objects obtained from at least 3 different data members. An object is considered unassociated with a function (global function or method) if it is not created in that function or for that function using a factory function, it is not passed to the function as parameter, it is not an exception object explicitly caught in the function, it is not a global variable defined in the same file as the global function or meethod, and if applicable it is not a data member or a value returned by a method of the enclosing class or the ancestors of the enclosing class. The severity of this flaw depends on the number of data members used directly or indirectly as prefix in the contained message chains and the number of references (data accesses and operation calls) to these data members.

References: Lieberherr89, Brown98, Fowler99

Bundle: SOLID
Category: Single Responsibility Principle (SRP), Open / Closed Principle (OCP)
Other names: Collapsed Method Hierarchy

Languages: C++
Targets: Function

This design flaw refers to the use of run-time type identification in order to vary the behavior of a function. Run-time type identification is a useful mechanism, but misusing it in such a manner typically leads to large functions containing many such type checks, which are difficult to change especially when a new type-dependent behavior needs to be implemented. A much more elegant solution to this problem is to separate each type-dependent behavior into a different method implementation belonging to the same method hierarchy and use polymorphic calls to select the type-dependent implementation.

The detection rule for this design flaw looks for a function containing at least one run-time type identification performed on an object and at least 2 type checks (uses of the typeid operator) on at least 2 different type names. The severity of this flaw is a function of the number of typeid operators used.

References: Trifu08

Bundle: SOLID
Category: Single Responsibility Principle (SRP)
Other names: Similar Unrelated Abstractions

Languages: C++
Targets: Class, Struct

This design flaw refers to the problem of duplicating functionality at the level of abstractions (interfaces or pure abstract classes). If two interfaces or pure abstract classes share several identical method signatures, it is typically an indication that the abstractions represented by the two interfaces or pure abstract classes are not clearly defined. In such cases, depending on the semantics of the interfaces or pure abstract classes, it may be possible to factor out the shared method signatures or even to merge the two abstractions together.

The detection rule for this design flaw uses formal concept analysis to identify groups of abstractions (interfaces or pure abstract classes), which share at least 3 identical method signatures. The severity of this flaw is a function of the number of abstractions in the group and the number of shared method signatures.

References: Martin02, Simon06

Bundle: SOLID
Category: Single Responsibility Principle (SRP), ,
Languages: C++
Targets: Class, Struct

This design flaw is inspired by Martin Fowler’s namesake code smell and refers to a subclass, which doesn’t seem to want to have anything to do with a particular direct supertype. It has two forms:

  • The interface form, which is also the more severe case, occurs when a subclass refuses to support the interface of the supertype by means of private or protected inheritance. This practice is called implementation inheritance, and although it is supported by the C++ language, it is considered abusive because it breaks the contract defined by the base class by reducing the visibility of the offered services. A subclass, inheriting implementation from a base class, cannot be used in place of the base class, which is why many argue that implementation inheritance should never be used. Instead it should be replaced by composition, which is much closer in intent to implementation inheritance than normal inheritance (public inheritance).
  • The implementation form occurs when a subclass neigher overrides any methods nor does it use any members inherited from this supertype. This also includes members inherited by the supertype in question from its ancestors. This form is less severe and it may not always be a problem, so reported inheritance relationships should be checked carefully to see if they make sense from a semantic perspective.

The detection rule for this design flaw looks for a class, which satisfies at least one of the following conditions:

  • the class has at least one non-public inheritance relationship with another class
  • the class neither overrides any methods nor does it reference any members (data members, operation members, type members) inherited from a direct supertype

The severity of this flaw depends on the number of non-public inheritance relationships of the subtype and the number of direct supertypes, whose methods are not overridden and whose members are not referenced in the subtype.

References: Riel96, Fowler99, Martin02

Bundle: SOLID
Category: Single Responsibility Principle (SRP), Open / Closed Principle (OCP)
Languages: C, C++
Targets: Variable

This design flaw refers to the mistake of implementing the same or very similar dispatch functionality over and over again in multiple functions. This mistake is very common among developers with little experience in object-oriented programming, and manifests itself by the presence of several switch-like structures (a switch statement or a sequence of if – else if statements) checking the value of the affected data member or global variable. In most cases this data member or global variable encodes a state information and the branches of the switch-like structure implement different actions based on this encoded state. Implementing dispatch functionality in such a way is problematic because a change in the dispatch logic for example due to adding a new state, potentially requires changes to all the functions containing switch-like structures involving the affected variable. The solution to this problem is to isolate and encapsulate the dispatch functionality either by using the State Design Pattern (Gamma94) or by means of function pointers.

The detection rule for this design flaw looks for multiple switch-like structures contained in at least 2 different functions, each having at least 2 branches involving the affected data member or global variable. The severity of this flaw depends on the number of functions containing switch-like structures like the ones described above and the total number of branches involving the affected data member or global variable.

References: Riel96, Trifu08

Bundle: SOLID
Category: Single Responsibility Principle (SRP)
Other names: Schizophrenic Class

Languages: C, C++
Targets: Class, Struct

This design flaw is related to the Client Segregation design flaw. It also refers to a class or a struct defining several disjoint groups of methods, which are called from disjoint groups of clients (structured types or modules), but in addition to the Client Segregation problem, the affected type (class or struct) must also be non-cohesive, meaning that the method groups in question must also access (directly or indirectly) disjoint sets of data members of the affected type or supertypes of this type. A class or a struct defines a method if the method in question is contained in that class or struct and the method does not override another method from a supertype. In general, this design flaw is more severe than a Client Segregation because, in addition to making clients depend on an unnecessarily large interface, the affected type also embodies more than one key abstraction, making it a very likely candidate to split.

The detection rule for this design flaw looks for classes or structs defining at least 2 groups of methods, having at least 2 methods each, which are called from disjoint sets of clients (structured types or modules) and access (directly or indirectly) disjoint sets of data members of the affected type or supertypes of this type. The severity of this design flaw depends on the number of disjoint groups of methods and the total number of methods in these groups.

References: Riel96, Martin02, Trifu08

Bundle: SOLID
Category: Open / Closed Principle (OCP),
Languages: C++
Targets: Class, Struct

This design flaw refers to a group of classes, where each class is connected either directly or indirectly to all the other classes in the group. A class is said to be directly connected to another class if it directly references the other class or one of its members, and it is said to be indirectly connected to another class if there is a chain of direct connections, involving only classes in the group, linking the two classes in question. Such a group is problematic because it is hard to understand and maintain. Furthermore, it also makes it impossible to reuse a single class from the group without the others.

The detection rule for this design flaw looks for strongly connected componnets, containing at least 2 classes, in the graph having all the classes in the system as nodes and direct connections between them as edges. The severity of this flaw depends on the number of classes involved in the clique and the total number of direct connections between them.

References: Martin02, Simon06

Bundle: SOLID
Category: Open / Closed Principle (OCP),
Other names: Knows of Derived

Languages: C++
Targets: Class, Struct

This design flaw refers to the mistake of directly referencing a subtype from a supertype.

The detection rule for this design flaw looks for a class or struct directly referencing at least one of its subtypes. The severity of this flaw depends on the number of referenced subtypes and the number of references to these types.

References: Riel96, Martin02

Bundle: SOLID
Category: Single Responsibility Principle (SRP), Open / Closed Principle (OCP)
Languages: C, C++
Targets: Function

This design flaw is inspired by Martin Fowler’s namesake code smell and typically points to a missing abstraction. The flaw manifests itself as a group of formal parameters declared in multiple functions over and over again throughout the system. Decl aring the same formal parameters over and over again hides the fact that the data values passed to these formal parameters are related and it also complicates the signatures of the declaring functions, making them harder to call. It is a good practice to group related data together, turn them into a new abstraction (structured type), and use this abstraction to replace the common group of formal parameters with a single formal parameter declaration in all the involved functions.

The detection rule for this design flaw looks for at least 3 unrelated functions (global functions or methods which are not part of the same method hierarchy), having at least 5 shared formal parameter declarations (formal parameter declarations having the same parameter name and type). The severity of this flaw depends on the number of affected functions and the number of shared formal parameter declarations.

References: Fowler99

Bundle: SOLID
Category: Single Responsibility Principle (SRP), Open / Closed Principle (OCP)
Other names: Misplaced Function/Method

Languages: C++
Targets: Function

This design flaw is inspired by Martin Fowler’s namesake code smell and refers to a function (global fuction or method), which is overly interested in the data members of an external class, called an envied class. In case of a method, in addition, the method must be more interested in the data members of the envied class than in the data members of its enclosing class. This flaw typically indicates that the affected function should really be a member of the envied class.

The detection rule for this design flaw looks for a global function or a method, referencing at least 5 external data members and at least 3 data members of a single external class either directly or indirectly through accessor methods. In case of a method, the method in question must also reference more data members from this external class than from its own class. The severity of this flaw depends on the number of referenced data members from the envied classes, the number of accesses to these data members, and the number of calls to accessor methods of these data members. Write accesses and calls to setters carry more weight than read accesses and calls to getters.

References: Riel96, Fowler99

Bundle: SOLID
Category: Single Responsibility Principle (SRP), Open / Closed Principle (OCP)
Other names: Centralised Control

Languages: C++
Targets: Class, Struct

This design flaw refers to the mistake of accumulating too much control in a class, usually at the expense of several satellite classes. In object-oriented design, a class is also a unit of encapsulation, meaning that it is supposed to bundle data with the methods operating on that data. A God Class breaks the encapsulation rule, because it manipulates (either directly or indirectly) data members belonging to its satellite classes. Such a class tends to be a maintencnace nightmare, because of its increased complexity and high coupling to its satellite classes.

The detection rule for this design flaw looks for classes, which write either directly ot through a setter at least 3 data members belonging to unrelated classes. A class is considered unrelated to the target class if it doesn’t belong to the same class hiearchy and it doesn’t contain the target class. As a general rule structs are not considered classes, unless they are involved in inheritance relationships. The severity of this flaw depends on the number of written data members and the number of write references to these data members.

References: Riel96, Fowler99, Trifu08

Bundle: SOLID
Category: Single Responsibility Principle (SRP), Open / Closed Principle (OCP)
Other names: Centralised Control

Languages: C++
Targets: Function

This design flaw refers to the mistake of accumulating too much control in a global function, usually at the expense of several satellite classes. In object-oriented design, a class is also a unit of encapsulation, meaning that it is supposed to bundle data with the methods operating on that data. A God Function breaks the encapsulation rule, because it manipulates (either directly or indirectly) data members belonging to its satellite classes. Such a function tends to be a maintencnace nightmare, because of its increased complexity and high coupling to its satellite classes.

The detection rule for this design flaw looks for global functions, which write either directly ot through a setter at least 3 class data members. As a general rule structs are not considered classes, unless they are involved in inheritance relationships. The severity of this flaw depends on the number of written data members and the number of write references to these data members.

References: Riel96, Fowler99, Trifu08

Bundle: SOLID
Category: Open / Closed Principle (OCP)
Languages: C, C++
Targets: Variable

This design flaw was inspired by the design principle of information hiding and refers to the mistake of exposing data (data members or global variables) in order to allow its direct manipulation from several other classes or modules in the system. Although exposing data in such a manner is never good and the preferred way is to provide an accessor to control the access, the problem becomes serious only if the data in question is actually written from other places in the code beside the defining class or module. This external manipulation of data may lead to unexpected side effects and code fragility.

The detection rule for this design flaw looks for one of the following situations:

  • a non-static non-constant global variable written from outside its defining module
  • a non-constant data member written from outside its defining class, subclasses of its defining class, and its defining module. Write accesses from friend classes or functions are also considered harmful, because they also violate the principle of information hiding.

The severity of this flaw depends on the number of external classes and modules from which the data in question is written, as well as on the number of external write accesses.

References: Riel96

Bundle: SOLID
Category: Single Responsibility Principle (SRP), Open / Closed Principle (OCP)
Languages: C++
Targets: Function

This design flaw, inspired by Lieberherr’s Law of Demeter and Martin Fowler’s namesake code smell, refers to the mistake of assuming a given internal structure of classes and explicitly writing navigation code to get from an object to another object stored in its internals in order to use this internal object as prefix in a member reference expression to select the target object for a method invokation or a data access. The name of thid design flaw comes from its typical appearance in code as a chain of references to internal data members, where each reference in the chain targets an internal data member of the object denoted by the previous reference in the chain. A reference to an internal data member is either a direct access to this data member or a call to a method returning this data member. Also, the chain of references can be explicit as shown below:

object1.getDataMember2().dataMember3.service()

or implicit, meaning that referenced intermediate data members are stored in local variables, as shown below:

object2 = object1.getDataMember2(); 
object3 = object2.dataMember3; 
object3.service();

Having such chains in a function makes it susceptible to change, whenever the internals of the classes referenced in the chains need to change.

The detection rule for this design flaw looks for a global function or a method containing message chains as the ones described above, involving unassociated objects obtained from at least 3 different data members. An object is considered unassociated with a function (global function or method) if it is not created in that function or for that function using a factory function, it is not passed to the function as parameter, it is not an exception object explicitly caught in the function, it is not a global variable defined in the same file as the global function or meethod, and if applicable it is not a data member or a value returned by a method of the enclosing class or the ancestors of the enclosing class. The severity of this flaw depends on the number of data members used directly or indirectly as prefix in the contained message chains and the number of references (data accesses and operation calls) to these data members.

References: Lieberherr89, Brown98, Fowler99

Bundle: SOLID
Category: Single Responsibility Principle (SRP), Open / Closed Principle (OCP)
Other names: Collapsed Method Hierarchy

Languages: C++
Targets: Function

This design flaw refers to the use of run-time type identification in order to vary the behavior of a function. Run-time type identification is a useful mechanism, but misusing it in such a manner typically leads to large functions containing many such type checks, which are difficult to change especially when a new type-dependent behavior needs to be implemented. A much more elegant solution to this problem is to separate each type-dependent behavior into a different method implementation belonging to the same method hierarchy and use polymorphic calls to select the type-dependent implementation.

The detection rule for this design flaw looks for a function containing at least one run-time type identification performed on an object and at least 2 type checks (uses of the typeid operator) on at least 2 different type names. The severity of this flaw is a function of the number of typeid operators used.

References: Trifu08

Bundle: SOLID
Category: Open / Closed Principle (OCP)
Other names: Extensive Coupling

Languages: C, C++
Targets: Class, Struct, Union

This design flaw refers to the mistake of making a structured type (class, struct or union) overly dependent on many other concrete (non abstract) classes, which are not related to the affected structured type. The emphasis here is on concrete classes, becuase a direct dependency to a concrete class adversely affects the reusability of the structured type in question.

The detection rule for this flaw looks for structured types referencing more than 7 concrete (non-abstract) classes.As a general rule structs are not considered classes, unless they are involved in inheritance relationships. The threshold 7 has to do with the maximum number of things a normal human can store in short term memory. Any number larger than that makes it harder to understand and ultimately to maintain the structured type in question. The severity of this flaw is a function of the number of referenced concrete classes and the number of references to these classes.

References: Trifu05

Bundle: SOLID
Category: Open / Closed Principle (OCP)
Other names: Extensive Coupling

Languages: C, C++
Targets: Function

This design flaw refers to the mistake of making a global function overly dependent on many other concrete (non abstract) classes. The emphasis here is on concrete classes, becuase a direct dependency to a concrete class adversely affects the reusability of the global function in question.

The detection rule for this flaw looks for global functions referencing more than 7 concrete (non-abstract) classes. As a general rule structs are not considered classes, unless they are involved in inheritance relationships. The threshold 7 has to do with the maximum number of things a normal human can store in short term memory. Any number larger than that makes it harder to understand and ultimately to maintain the global function in question. The severity of this flaw is a function of the number of referenced concrete classes and the number of references to these classes.

References: Trifu05

Bundle: SOLID
Category: Open / Closed Principle (OCP),
Other names: SAP Breaker

Languages: C++
Targets: Class, Struct

This design flaw refers to the mistake of directly referencing a concrete class or struct instead of referencing one of its supertypes from an abstract class or struct.

The detection rule for this design flaw looks for an abstract class or struct, which has at least 30% of all its methods (including inherited ones) abstract, directly referencing a concrete class or struct, having at least one supertype and no subtypes. The severity of this flaw depends on the number of referenced concrete types and the number of references to these types.

References: Riel96, Martin02

Bundle: SOLID
Category: Single Responsibility Principle (SRP), Open / Closed Principle (OCP)
Languages: C, C++
Targets: Variable

This design flaw refers to the mistake of implementing the same or very similar dispatch functionality over and over again in multiple functions. This mistake is very common among developers with little experience in object-oriented programming, and manifests itself by the presence of several switch-like structures (a switch statement or a sequence of if – else if statements) checking the value of the affected data member or global variable. In most cases this data member or global variable encodes a state information and the branches of the switch-like structure implement different actions based on this encoded state. Implementing dispatch functionality in such a way is problematic because a change in the dispatch logic for example due to adding a new state, potentially requires changes to all the functions containing switch-like structures involving the affected variable. The solution to this problem is to isolate and encapsulate the dispatch functionality either by using the State Design Pattern (Gamma94) or by means of function pointers.

The detection rule for this design flaw looks for multiple switch-like structures contained in at least 2 different functions, each having at least 2 branches involving the affected data member or global variable. The severity of this flaw depends on the number of functions containing switch-like structures like the ones described above and the total number of branches involving the affected data member or global variable.

References: Riel96, Trifu08

Bundle: SOLID
Category: Open / Closed Principle (OCP),
Other names: Interface Bypass

Languages: C++
Targets: Variable

This design flaw is inspired by the design principle “Program to an interface, not an implementation” expressed in Erich Gamma’s famous Design Patterns book. It refers to the mistake of calling the methods of a concreate class directly instead of calling them through a reference to the interface or the abstract class defining these methods. This makes the client code depend on concrete implementations, making it very hard to replce these implementations.

The detection rule for this design flaw looks for a variable having as data type a pointer or a reference to a concrete class or struct, but the variable is only used in expressions where a certain supertype of the concrete class or struct would suffice. Note that this usage must also include the usage of the supertype’s interface, meaning the variable must be used to invoke at least one method defined in the bypassed supertpe or one of its supertypes. Such an invokation is called a bypassing invokation. The severity of this flaw is a function of the number of bypassed supertypes and the number of bypassing invokations.

References: Gamma94, Martin02, Simon06

Bundle: SOLID
Category:
Languages: C++
Targets: Function

This design flaw refers to a violation of the post-condition imposed by an ancestor method by adding additional side effects related to the ancestor class in the overriding method. In object-oriented design, the post-condition of a method should not be weakened by an overriding method, meaning that whatever post-condition held for the ancestor method should also hold for the overriding method. This also refers to the limitation of side effects related to the ancestor class, meaning that the overriding method should not write data members of the ancestor class, which were not already written by the overridden method. Introducing additional side effects in this manner can lead to subtle bugs in the code, which are extremely difficult to find and to fix.

The detection rule for this design flaw looks for a method definition, which overrides a non-empty non-constant method definition of a superclass and replaces its implementation with one that writes additional data members, belonging to the superclass in question or to one of its superclasses, which were not written by the overridden method. The severity of this flaw is a function of the number of ancestor methods whose post-conditions have been violated in this manner and the number of additional data members of the ancestor class, written by the overriding method.

References: Riel96, Martin02

Bundle: SOLID
Category:
Languages: C++
Targets: Function

This design flaw refers to a violation of the post-condition imposed by an ancestor method by replacing its implementation with an empty implementation. In object-oriented design, the post-condition of a method should not be weakened by an overriding method, meaning that whatever post-condition held for the ancestor method should also hold for the overriding method. This also means that the overriding method should not provide less functionality than its ancestor, because doing so can lead to subtle bugs in the code, which are extremely difficult to find and to fix.

The detection rule for this design flaw looks for a method definition, which overrides a non-empty non-constant method definition of a superclass and replaces its implementation with an empty implementation. The severity of this flaw is proportional to the number of ancestor methods whose post-conditions have been violated in this manner.

References: Riel96, Martin02

Bundle: SOLID
Category: Single Responsibility Principle (SRP), ,
Languages: C++
Targets: Class, Struct

This design flaw is inspired by Martin Fowler’s namesake code smell and refers to a subclass, which doesn’t seem to want to have anything to do with a particular direct supertype. It has two forms:

  • The interface form, which is also the more severe case, occurs when a subclass refuses to support the interface of the supertype by means of private or protected inheritance. This practice is called implementation inheritance, and although it is supported by the C++ language, it is considered abusive because it breaks the contract defined by the base class by reducing the visibility of the offered services. A subclass, inheriting implementation from a base class, cannot be used in place of the base class, which is why many argue that implementation inheritance should never be used. Instead it should be replaced by composition, which is much closer in intent to implementation inheritance than normal inheritance (public inheritance).
  • The implementation form occurs when a subclass neigher overrides any methods nor does it use any members inherited from this supertype. This also includes members inherited by the supertype in question from its ancestors. This form is less severe and it may not always be a problem, so reported inheritance relationships should be checked carefully to see if they make sense from a semantic perspective.

The detection rule for this design flaw looks for a class, which satisfies at least one of the following conditions:

  • the class has at least one non-public inheritance relationship with another class
  • the class neither overrides any methods nor does it reference any members (data members, operation members, type members) inherited from a direct supertype

The severity of this flaw depends on the number of non-public inheritance relationships of the subtype and the number of direct supertypes, whose methods are not overridden and whose members are not referenced in the subtype.

References: Riel96, Fowler99, Martin02

Bundle: SOLID
Category:
Languages: C++
Targets: Function

This design flaw refers to a violation of the post-condition imposed by an ancestor method by changing fewer data members of to the ancestor class in the overriding method. In object-oriented design, the post-condition of a method should not be weakened by an overriding method, meaning that whatever post-condition held for the ancestor method should also hold for the overriding method. This also refers to keeping changes to data members of the ancestor class consistent with the changes made by the overridden method. Not doing so can lead to subtle bugs in the code, which are extremely difficult to find and to fix.

The detection rule for this design flaw looks for a method definition, which overrides a non-empty non-constant method definition of a superclass and replaces its implementation with one that doesn’t write all data members, which were written by the overridden method. The severity of this flaw is a function of the number of ancestor methods whose post-conditions have been violated in this manner and the number of data members of the ancestor class, written by the overridden method and not written by the overriding method.

References: Riel96, Martin02

Bundle: SOLID
Category:
Languages: C++
Targets: Function

This design flaw refers to a violation of the contract defined by an ancestor method by throwing additional exception types in the overriding method. In object-oriented design, the contract of a method should not be changed by an overriding method, meaning that whatever held for the ancestor method should also hold for the overriding method. This also refers to limitting the types of exceptions thrown by the overriding method to the types already thrown by the overridden method. Not doing so can lead to unhandled exception in the code, which may affect its operation at run-time.

The detection rule for this design flaw looks for a method definition, which overrides a non-empty non-constant method definition of a superclass and replaces its implementation with one that throws additional exception types, which the overridden method did not throw. The severity of this flaw depends on the number of ancestor methods whose contracts have been violated in this manner and the number of additional exception types thrown by the overriding method.

References: Riel96, Martin02

Bundle: SOLID
Category:
Languages: C, C++
Targets: Class, Struct

This design flaw refers to a class or struct defining several disjoint groups of methods, which are called from disjoint groups of clients (structured types or modules). A class or a struct defines a method if the method in question is contained in that class or struct and the method does not override another method from a supertype. Note that a class or a struct may implement several interfaces, with each interface being used by a separate set of clients, without being a problem. The situation becomes problematic when this segregation is done covertly, without an explicit segregation at the interface level, because it makes every client depend on a much larger interface than it needs to, thus increasing the fragility of the code.

The detection rule for this design flaw looks for classes or structs defining at least 2 groups of methods, having at least 2 methods each, which are called from disjoint sets of clients (structured types or modules). The severity of this design flaw depends on the number of disjoint groups of methods and the total number of methods in these groups.

References: Martin02

Bundle: SOLID
Category: Single Responsibility Principle (SRP), ,
Languages: C++
Targets: Class, Struct

This design flaw is inspired by Martin Fowler’s namesake code smell and refers to a subclass, which doesn’t seem to want to have anything to do with a particular direct supertype. It has two forms:

  • The interface form, which is also the more severe case, occurs when a subclass refuses to support the interface of the supertype by means of private or protected inheritance. This practice is called implementation inheritance, and although it is supported by the C++ language, it is considered abusive because it breaks the contract defined by the base class by reducing the visibility of the offered services. A subclass, inheriting implementation from a base class, cannot be used in place of the base class, which is why many argue that implementation inheritance should never be used. Instead it should be replaced by composition, which is much closer in intent to implementation inheritance than normal inheritance (public inheritance).
  • The implementation form occurs when a subclass neigher overrides any methods nor does it use any members inherited from this supertype. This also includes members inherited by the supertype in question from its ancestors. This form is less severe and it may not always be a problem, so reported inheritance relationships should be checked carefully to see if they make sense from a semantic perspective.

The detection rule for this design flaw looks for a class, which satisfies at least one of the following conditions:

  • the class has at least one non-public inheritance relationship with another class
  • the class neither overrides any methods nor does it reference any members (data members, operation members, type members) inherited from a direct supertype

The severity of this flaw depends on the number of non-public inheritance relationships of the subtype and the number of direct supertypes, whose methods are not overridden and whose members are not referenced in the subtype.

References: Riel96, Fowler99, Martin02

Bundle: SOLID
Category:
Other names: Ignored Abstraction

Languages: C++
Targets: Class, Struct

This design flaw is inspired by Martin Fowler’s code smell “Speculative Generality” and refers to the mistake of over-engineering an abstraction (an interface or a pure abstract class) by adding methods intended to accomodate potential future requirements. Often such requirements do not materialize, so the added methods clutter the design with unnecessary complexity, making it harder to maintain.

The detection rule for this design flaw looks for an abstarction (a pure abstract class or an interface), which defines at least 3 unused methods. A method is considered unused if there is no reference (operation call or operation access) from anywhere in the project folder or its subfolders to:

  • the method definition and any of its declarations
  • the definitions and declarations of its overridden methods
  • the definitions and declarations of its overriding methods

The severity of this flaw is a function of the number of unused methods defined in the abstraction.

References: Fowler99, Simon06

Bundle: SOLID
Category: Open / Closed Principle (OCP),
Languages: C++
Targets: Class, Struct

This design flaw refers to a group of classes, where each class is connected either directly or indirectly to all the other classes in the group. A class is said to be directly connected to another class if it directly references the other class or one of its members, and it is said to be indirectly connected to another class if there is a chain of direct connections, involving only classes in the group, linking the two classes in question. Such a group is problematic because it is hard to understand and maintain. Furthermore, it also makes it impossible to reuse a single class from the group without the others.

The detection rule for this design flaw looks for strongly connected componnets, containing at least 2 classes, in the graph having all the classes in the system as nodes and direct connections between them as edges. The severity of this flaw depends on the number of classes involved in the clique and the total number of direct connections between them.

References: Martin02, Simon06

Bundle: SOLID
Category: Open / Closed Principle (OCP),
Other names: Knows of Derived

Languages: C++
Targets: Class, Struct

This design flaw refers to the mistake of directly referencing a subtype from a supertype.

The detection rule for this design flaw looks for a class or struct directly referencing at least one of its subtypes. The severity of this flaw depends on the number of referenced subtypes and the number of references to these types.

References: Riel96, Martin02

Bundle: SOLID
Category: Open / Closed Principle (OCP),
Other names: SAP Breaker

Languages: C++
Targets: Class, Struct

This design flaw refers to the mistake of directly referencing a concrete class or struct instead of referencing one of its supertypes from an abstract class or struct.

The detection rule for this design flaw looks for an abstract class or struct, which has at least 30% of all its methods (including inherited ones) abstract, directly referencing a concrete class or struct, having at least one supertype and no subtypes. The severity of this flaw depends on the number of referenced concrete types and the number of references to these types.

References: Riel96, Martin02

Bundle: SOLID
Category: Open / Closed Principle (OCP),
Other names: Interface Bypass

Languages: C++
Targets: Variable

This design flaw is inspired by the design principle “Program to an interface, not an implementation” expressed in Erich Gamma’s famous Design Patterns book. It refers to the mistake of calling the methods of a concreate class directly instead of calling them through a reference to the interface or the abstract class defining these methods. This makes the client code depend on concrete implementations, making it very hard to replce these implementations.

The detection rule for this design flaw looks for a variable having as data type a pointer or a reference to a concrete class or struct, but the variable is only used in expressions where a certain supertype of the concrete class or struct would suffice. Note that this usage must also include the usage of the supertype’s interface, meaning the variable must be used to invoke at least one method defined in the bypassed supertpe or one of its supertypes. Such an invokation is called a bypassing invokation. The severity of this flaw is a function of the number of bypassed supertypes and the number of bypassing invokations.

References: Gamma94, Martin02, Simon06

References

Brown98 W.J. Brown, R.C. Malveau, W.H. Brown, H.W. McCormick, and T.J. Mowbray. AntiPatterns: Refactoring Software, Architectures, and Projects in Crisis. John Wiley and Sons, 1998.
Fowler99 Martin Fowler. Refactoring. Improving the Design of Existing Code. Addison- Wesley, 1999.
Gamma94 Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley Professional, 1994.
Lanza06 Michele Lanza and Radu Marinescu. Object-Oriented Metrics in Practice. Springer, 2006.
Martin02 Robert C. Martin. Agile Software Development: Principles, Patterns and Practices. Pearson Education, 2002. ISBN 0-13-597444-5.
Riel96 A.J. Riel. Object-Oriented Design Heuristics. Addison-Wesley, 1996.
Simon06 Frank Simon, Olaf Send, Thomas Mohaupt. Code Quality Management: Technische Qualitaet industrieller Softwaresysteme transparent und vergleichbar gemacht, dpunkt, 2006.
Trifu05 Adrian Trifu, Radu Marinescu. Diagnosing Design Problems in Object Oriented Systems. Proc. IEEE Working Conference on Reverse Engineering (WCRE), 2005.
Trifu08 Adrian Trifu. Towards Automated Restructuring of Object-Oriented Systems. PhD thesis, University of Karlsruhe, 2008.

Lower your software maintenance costs, by turning design review into a cheap commodity for your development team!