A design problem is the result of design decisions that negatively impact quality attributes. For example, a stakeholder introduces a design problem when he decides to addresses multiple unrelated responsibilities in a single class, impacting the modifiability and reusability of the system. Given their negative consequences, design problems should be identified and refactored. The literature still lacks evidence on which symptoms' characteristics can be used as strong indicators of design problems. For example, it is unknown if the density and diversity of certain symptoms (e.g., violations of object-oriented principles) are correlated with the occurrence of design problems. Thus, in this paper, we report a case study involving two C# systems. We evaluated the impact of refactoring, focused on removing design problems, on the density and diversity of symptoms. Results indicate that refactored classes usually present higher density and diversity of symptoms. However, the density and diversity of some symptoms, such as the violation of object-oriented principles, was not predominantly higher in refactored classes. Moreover, contrary to our expectations, refactorings caused almost no positive impact on the density and diversity of symptoms.
The paper is available for download in the following link: [Download]
The ISO/IEC 25010 standard [20] provides a quality model, which specifies the characteristics that should be analyzed when evaluating software quality. This quality model is composed of eight main quality attributes: Functional Suitability, Efficiency, Compatibility, Usability, Reliability, Security, Maintainability, and Portability. Each quality attribute is subdivided into two or more sub-attributes. Compatibility, for example, is subdivided into co-existence and interoperability. Each quality attribute should be adequately addressed so that the software is able to meet the expectations of its stakeholders. In this work, we restricted our analyzes to the following quality attributes:
• Efficiency: Ability of the software to present appropriate performance, relative to: the amount of resources used, time behaviour, and capacity.
• Compatibility: Degree to which the software is able to exchange data with other software and/or function while sharing the same hardware or software environment.
• Reliability: Ability of the software to perform its responsibilities under specified conditions for a specified period of time.
• Maintainability: Software’s ability to be modified. Modifications may include software patches, enhancements, or adaptations due to changes in the environment and its functional requirements or specifications.
We focused on these quality attributes because they are the ones that appeared consistently in refactoring tasks of our target systems.
Design problems occur when stakeholders make decisions that negatively impact quality attributes [3]–[5]. Each design problem may impact one or more quality attributes. Due to the negative impact caused by design problems, software systems have often been discontinued or redesigned when they were allowed to persist [6]. Unmanaged Design Problems are design problems that exist but are neither tracked nor controlled throughout the evolution of the system. An unmanaged design problem occurs because stakeholders either are not aware of its existence or are unable to track and control it. Thus, in such cases, developers need to identify and to confirm the existence of a design problem. Next, we present an example to illustrate how quality attributes may be impacted by unmanaged design problems
Sousa et al. [17] identified five types of symptom that developers frequently rely to identify design problems. Similarly to other related work [16], [21]–[23], they observed that developers tend to combine multiple symptoms, considering dimensions such as diversity and density to decide if there is a design problem or not. According to them, developers often combine two or more of the following symptom types: violation of non-functional requirements, incidence of code smells, misuse of design patterns, violation of quality requirements, and principle violations.
Refactoring consists in transforming the source code structure without changing the functional behaviour of the system [9], [10]. Thus, we consider that refactoring is any sequence of source code changes that is aimed at improving quality attributes of the system’s design.
Code smells are surface indicators of possible design problems [9]. This type of smell have been extensively investigated by different researchers (e.g. [11], [24]–[26]). Recent studies [16], [17], [21], [23] suggest that combining multiple code smells may improve the precision when identifying design problems. An example of code smell type is the God Class. This type of smell is used to identify classes that are long and excessively complex. We used a set of 11 categories of code smells, which are the following: Long Method, Complex Method, Long Parameter List, Long Identifier, Long Statement, Complex Conditional, Virtual Method Call from Constructor, Empty Catch Block, Magic Number, Duplicate Code, and Missing Default.
In object-oriented systems, design problems usually impact object-oriented design characteristics, such as abstraction, encapsulation, modularity, and hierarchy. Therefore, the second symptom type we used is the principle violation. Principle violations are symptoms that may indicate the violation of object-oriented principles [12]. An example of object-oriented principle is the Single Responsibility Principle, which determines that each class should have a single responsibility in the system [12]. We detected 18 categories of principle violations: Imperative Abstraction, Unnecessary Abstraction, Multifaceted Abstraction, Unutilized Abstraction, Duplicate Abstraction, Deficient Encapsulation, Unexploited Encapsulation, Broken Modularization, Insufficient Modularization, Hublike Modularization, Cyclically-dependent Modularization, Wide Hierarchy, Deep Hierarchy, Multipath Hierarchy, Cyclic Hierarchy, Rebellious Hierarchy, Unfactored Hierarchy, and Missing Hierarchy.
A complete description of the Code Smells and Principle Violations used in this work is available at the Taxonomy of Software Smells website.
Quality requirements represent characteristics that are considered fundamental for software design. Examples of quality requirements are coupling, cohesion, and complexity. In this work, we opted for using coupling and complexity as representatives of this type of symptom. Coupling is a fundamental requirement that indicates the number of classes that a single class uses [27]. High coupling usually indicates the class contains one or more design problems. Cyclomatic Complexity, which we call here only by Complexity, is a property that measures the structural complexity of the code [28]. In a simplified way, the complexity of a class is determined by the number of decisions taken by its methods. High complexity usually indicates the class is difficult to maintain. We opted for not collecting cohesion, because the correct measurement of this quality requirement is still challenging.
Project | Architectural Style | Domain | Size (KLOC) | # of Commits |
---|---|---|---|---|
OpenPOS | Layers | Sales | 97 | 3318 |
UniNFe | Layers | Invoice | 492 | 2373 |
KLOC = Kilo Lines of Code |