Data Class

A class holds data without meaningful behavior.

Sign of Smell

A Data Class smell occurs when a class lacks enough functionality to justify its existence. It refers to a class that only contains fields and basic methods (getters and setters) for accessing them. These classes are essentially containers for data used by other classes and do not have any additional independent functionality.

It is common for a newly created class to initially have only a few public fields. However, the true power of objects lies in their ability to encapsulate both data and behavior.

If I stop discussing this topic here and move on to the next section, it will become just another generic introduction blog post on the internet. However, the true power of object-oriented programming (OOP) is a highly controversial topic.

When you ask this question on Stack Overflow, the developer's best friend, about whether a Rich Domain Model or an Anemic domain model is better, it will say that there are no accepting answers for now and this question is opinion-based.

The proponents of the Rich Domain Model side, who believe that it is better to combine data with behavior, argue that Martin Fowler might also agree with this point, as evidenced by his famous "Tell-Don't-Ask principle".

Tell-Don't-Ask is a principle that helps people remember that object-orientation is about bundling data with the functions that operate on that data. It reminds us that rather than asking an object for data and acting on that data, we should instead tell an object what to do. This encourages to move behavior into an object to go with the data. β€” Martin Fowler

On the other hand, in the most well-known book "Clean Code," Robert Martin (Uncle Bob) argues in favor of data classes. He states that "Data Structure" objects and "Data Transfer Objects" can be beneficial as they only contain data without any functions. According to Uncle Bob, it is recommended to separate data classes from object-oriented (OO) classes. If a class has logic, it should be an OO class. However, exposing internals through getters and setters is considered bad practice.

To draw a conclusion, let's refer back to the author of "Refactoring" and see what Martin Fowler says about "Data Class". He states, "Data classes are often a sign of behavior in the wrong place, ..." It is important to note the use of the phrase "often a sign". This implies that data classes are not always problematic.

In my first blog of this series, Metz emphasizes a very important concept that changed my view significantly.

Code smells are neutral, they are not always bad. β€” Sandi Metz

If we jump into an argument without a concrete case, it may soon become a pointless debate. Just because something has a code smell doesn't necessarily mean it's bad. Code smells are nothing but useful information, helping us to write better code. This is especially true in the case of a Data Class smell.

Reason of Smell

Anemic Domain Model: If your entire codebase consists of only data classes and lacks meaningful behavior or encapsulation of behavior, it might be a sign of an anemic domain model. In domain-driven design (DDD), a rich domain model is encouraged, where objects contain both data and the behavior related to that data. Data classes should complement behavior-rich classes rather than replace them.

Overuse of Getters and Setters: Data classes often have fields with corresponding getter and setter methods. If your data class has numerous fields, and you find yourself writing many getters and setters, it can lead to bloated classes and violate the principle of encapsulation. This can be a code smell because it exposes too much of the internal structure of the class.

Encapsulation: Data Classes often expose their internal fields directly through getter and setter methods. This can break the principle of encapsulation by allowing direct access to the class's internal state, which can lead to unintended data manipulation and make it harder to maintain and change the class later.

Lack of Validation: If your data class doesn't perform adequate validation of its data, it can lead to invalid or inconsistent states in your application. This is especially important if the data class represents critical information.

Violate the Tell-Don't-Ask (TDA) principle: The TDA reminds us that instead of asking an object for data and acting on that data, we should tell an object what to do. The Data Class doesn't include any behavior, so it might depend on other classes to implement the data-related functions.

Low Cohesion: The main purpose of a Data Class is to store data, and it usually does not have any significant behavior or operations. This lack of behavior or responsibility leads to low cohesion, as the class does not have a specific purpose or a defined set of data-related tasks.

Refactoring Recipes

  • Move Method

  • Encapsulate Field

  • Encapsulate Collection

Move Method

The Data Class serves as a container for data used by other classes. In this case, it would be beneficial to consider moving the method into the Data Class. In this way, both the data and behavior can be kept within the same class, which maintains high cohesion.

Encapsulate Field

The Encapsulate Field technique involves converting public fields into private fields and providing getter and setter methods (or properties, depending on the programming language) to access and modify the value of the field.

Getter and setter methods offer a precise means of accessing and modifying data, allowing for the inclusion of validation, business logic, or side effects (like logging) in data operations. This can effectively remove the "Data Class" smell.

Encapsulate Collection

The "Encapsulate Collection" refactoring skill can help address the Data Class smell by encapsulating the collection (or array) within a class and providing controlled access to its elements. When a class primarily exists to hold a collection of data without any behavior or validation, it can lead to issues with maintainability, data integrity, and understanding of the codebase.

Reference

https://code-smells.com/dispensables/data-class

https://refactoring.guru/smells/data-class

https://stackoverflow.com/questions/23314330/rich-vs-anemic-domain-model

https://martinfowler.com/bliki/TellDontAsk.html

https://www.linkedin.com/pulse/clean-code-chapter6-objects-data-structures-mahmoud-ibrahim/

https://refactoring.guru/encapsulate-field

Last updated