Sharing thoughts and ideas
A code smell is any characteristic in the source code of a program that possibly indicates a deeper problem. These are indicators that warn you that something is wrong in the code, without showingany errors in execution.
Code smells can be categorized according to which aspect is impacted in the code base. A common categorization is : - Bloaters : - Practices that leads to increase the codebase in large proportions and make it hard to work with. - Object-Orientation Abusers: - Misapplication of object orientated paradigm - Change Preventers - Practices that prevents flexible changes in the code, meaning that doing a single change needs to be applied in several part of the code repeatably. - Dispensables - Points at parts of the source code that are unneeded, and that will make the code clearner if absent. - Couplers - Codes that excessively coupling together part of codes ( classes ).
Feature Envy occurs when a class of method accesses the data of another object more than its own data.
#include <string>
#include <vector>
using namespace std;
// Request.hpp
class Request{
public:
string get_some_data(){ return "A";}
string get_some_data2(){ return "B";}
[...]
};
// In Config.cpp
void process_config(const Request& iReq){
vector<string> list_data;
// Extract data
list_data.emplace_back(iReq.get_some_data());
list_data.emplace_back(iReq.get_some_data2());
[...]
// Process data
/* Do some work */
}
In this example, in the config module we pull several pieces of data, but the function process_config
just want to process the data. An alternative could be to provide the data directly as a parameter instead of the Request
object and retrieve the data through a iReq.extract_config_data()
. Another alternative, if the process only concern the Request
object, would be to directly use iReq
and tell it to process its own data : iReq.process_data()
.
This solution improves encapsulation and reduces duplication of logic.
Primitive Obsession is a code smell that arises when primitive types ( such as int
, float
, ...) are used to represent domain concepts instead of creating small and meaningful structures.
Common examples include:
- Using a float
to represent a monetary value instead of a dedicated Currency
type.
- Representing a phone number as a string
instead of a PhoneNumber
object.
- Passing coordinates as separate x
and y
values instead of a Point
or Position
structure.
Example : Bad example:
void set_pos(float x, float y){ ...}
Better example, encapsulating x and y
void set_pos(Pos pos){ ...}
By introducing a small structure like Pos
, we:
- Improve readability and expressiveness.
- Reduce the risk of incorrect parameter ordering.
- Enable validation and behavior inside the type itself.
- Prepare the code for future extension without breaking existing interfaces.
Codesmell