A Tool to Unmask the Scent of Code Smells in Object Oriented Languages
A Java Static Analysis tool for detecting code smells via Visual Studio code extension. It can be extended with custom rules. Rules can be written in Java or using a XPath query. Based on Charles Jonas's vscode-apex-pmd extension. Using the underlying source code analyzer, PMD, for leveraging of JavaCC and Antlr to parse source files into abstract syntax trees (AST) and runs rules against them to find violations.
💩 Code Smells: An indication that the code is not following fundamental standards that decrease the quality of the code
🎯 Objective
- Create a tool for developers, streamlining their tasks and guaranteeing the code's quality.
- This is accomplished by pinpointing issues and providing suggested solutions before the code is deployed to production.
- Requirements: issue detection, actively contributing to improving code readability, maintainability, and overall consistency.
🚀 Installation and Usage (Local)
- Install extension via extension store on Visual Studio Code
- Click
CTRL/CMD + SHIFT + P
to open the command palette
- Run commands
Java Static Analysis: On Workspace
to scan your entire project for code smells
- Run commands
Java Static Analysis: On File
to scan one file in your project for code smells
- Run commands
Java Static Analysis: Clear Problems
to remove all the violations of detected code smells
- Run commands
Java Static Analysis: Create Report
to create a report of all the code smells found in a project or file
🚀 Installation and Usage (Dev)
git clone
npm ci
- Debug mode →
run extension
- Press
F5
to open a new window with your extension loaded
- Run command from the command palette by pressing (
Ctrl+Shift+P
or Cmd+Shift+P
on Mac) and typing Java Static Analysis: On Workspace
- Set breakpoints in code inside
src/extension.ts
to debug the extension
- Locate output from the extension in the debug console
🤖 Run Tests Locally
- Navigate to directory using terminal
- Run command
npm run test
🩻 Basic File Structure
.
├── .vscode
│ ├── launch.json // Config for launching and debugging extension
│ └── tasks.json // Config for build task that compiles TypeScript
├── .gitignore // Ignore build ouput and node_modules
├── README.md // Markdown description of the extension
├── src
│ └── extension.ts // Extension source code
├── package.json // Extension package manifest
└── tsconfig.json // Config for TypeScript
✏️ Features
Our Code Smell detection strategies and implementation:
✅ Constant Class
Description: The Constant Class smell occurs when a class contains only constants (such as static final variables) without any behavior.
Problem: This indicates a lack of proper object-oriented design, as the class serves no purpose beyond storing values, violating the Single Responsibility Principle.
Fix: Refactor the constants into appropriate classes or use enums/interfaces where applicable to encapsulate related behavior.
✅ Feature Envy
Description: Feature Envy happens when a method of one class excessively uses methods or data of another class, suggesting that it should belong to the latter class instead.
Problem: It increases coupling between classes and can lead to maintenance issues and difficulty in understanding the codebase.
Fix: Move the method to the class where it's envious of, improving encapsulation and adhering to the principle of high cohesion.
✅ God Class
Description: The God Class smell occurs when a class has too many responsibilities and knows too much about other classes, becoming overly complex and difficult to maintain.
Problem: It violates the Single Responsibility Principle, making the class fragile and hard to modify without affecting other parts of the system.
Fix: Break down the class into smaller, more cohesive classes, each responsible for a specific set of related functionality, promoting better maintainability and readability.
✅ Inappropriate Intimacy
Description: Inappropriate Intimacy refers to tight coupling between classes where one class excessively relies on the internals of another, often accessing its private members or invoking its methods excessively.
Problem: It increases dependency between classes, making changes to one class impact others unexpectedly and hindering code reuse and maintenance.
Fix: Refactor the code to reduce coupling by using interfaces, defining clear boundaries, and encapsulating behavior properly to improve modularity and flexibility.
✅ Interface Segregation Principle
Description: The Interface Segregation Principle states that clients should not be forced to depend on interfaces they do not use. It emphasizes creating specific interfaces tailored to the needs of clients.
Problem: Violating this principle can lead to unnecessary dependencies and bloated interfaces, making code harder to understand and maintain.
Fix: Split large interfaces into smaller, more focused ones, each catering to a specific set of behaviors, thereby promoting loose coupling and better adherence to the principle.
✅ Lazy Class
Description: The Lazy Class smell occurs when a class does not provide enough functionality or value to justify its existence in the system.
Problem: It adds unnecessary complexity and maintenance overhead without contributing meaningfully to the functionality of the application.
Fix: Either remove the class altogether if it serves no purpose, or refactor it to incorporate additional functionality or merge it with another class to improve code clarity and maintainability.
✅ Misplaced Class
Description: Misplaced Class happens when a class is located in the wrong package or module, leading to confusion about its purpose and responsibilities.
Problem: It disrupts the organization of the codebase and makes it harder for developers to locate and understand the class.
Fix: Move the class to the appropriate package or module where it logically belongs, ensuring a more coherent structure and improving code navigation and maintenance.
✅ Refused Bequest
Description: Refused Bequest occurs when a subclass inherits from a superclass but only uses a subset of its inherited methods or overrides them with empty implementations.
Problem: It violates the Liskov Substitution Principle and can lead to confusion and incorrect assumptions about the subclass's behavior.
Fix: Refactor the inheritance hierarchy by either removing the inheritance relationship if it's not appropriate or ensuring that the subclass fully utilizes the inherited methods in a meaningful way.
✅ Shotgun Surgery
Description: Shotgun Surgery happens when a single change in the codebase requires modifications to multiple classes or modules, indicating poor cohesion and excessive coupling.
Problem: It increases the risk of introducing bugs and makes the codebase harder to maintain and evolve.
Fix: Consolidate related functionality into cohesive modules or classes, reducing dependencies and promoting encapsulation to minimize the impact of future changes.
🧮 Notable Metrics
Disclaimer: The utilization of metrics can assist in delineating software systems, assessing their performance, and identifying design flaws, thereby facilitating the implementation of suitable refactorings.
Metric |
Abbreviation |
Description |
Access to Foreign Data |
ATFD |
Number of external classes from which a given class accesses attributes, directly or via accessor-methods |
Average Method Weight |
AMW |
Average static complexity of all methods in a class |
Changing Classes |
CC |
Number of classes in which the methods that call the measured method |
Changing Methods |
CM |
Number of distinct methods that call the measured method |
Foreign Data Providers |
FDP |
Number of classes in which the attributes accessed |
Locality of Attribute Accesses |
LAA |
Number of attributes from the method’s definition class, divided by the total number of variables accessed |
Tight Class Cohesion |
TCC |
Relative number of methods directly connected via accesses of attributes |
Weighted Method Count |
WMC |
Sum of the statical complexity of all methods in a class |
Weight Of a Class |
WOC |
Number of “functional” public methods divided by the total number of public members |
Reference: M. Lanza and R. Marinescu, "Object-Oriented Metrics in Practice," Springer, 2006.
📝 License
BSD-style license