29

This article claims that a data class is a "code smell". The reason:

It's a normal thing when a newly created class contains only a few public fields (and maybe even a handful of getters/setters). But the true power of objects is that they can contain behavior types or operations on their data.

Why is it wrong for an object to contain only data? If the core responsibility of the class is to represent data, wouldn't add methods that operate on the data break the Single Responsibility Principle?

4
  • 4
    This is going to depend strongly on language features. In Python, for example, there's no distinction between the "field" and its accessors, unless you go out of your way to write Java in Python.
    – jscs
    Dec 15, 2016 at 11:39
  • 1
    I think having some data only classes is not a code smell per se, but if most classes are like that then we are talking about the "anemic domain" antipattern en.wikipedia.org/wiki/Anemic_domain_model Dec 15, 2016 at 12:03
  • 1
    I don't see how this question is a duplicate. The other questions is about the use of data classes in OO, while this one is about the downsides of data classes - entirely different subjects. May 18, 2018 at 10:04
  • You may want to read this answer on stackoverflow which is much more differentiated than the top voted answer here that postulates the inferiority of the rich domain model and present it like a proven fact. stackoverflow.com/questions/23314330/… Mar 28, 2019 at 13:58

7 Answers 7

65

There is absolutely nothing wrong with having pure data objects. The author of the piece quite frankly doesn't know what he's talking about.

Such thinking stems from an old, failed, idea that "true OO" is the best way to program and that "true OO" is all about "rich data models" where one mixes data and functionality.

Reality has shown us that actually the opposite is true, especially in this world of multi-threaded solutions. Pure functions, combined with immutable data-objects, is a demonstrably better way to code.

18
  • 3
    Although it is nice if those pure functions that only take an instance of the immutable data object as argument are implemented as methods on the data object. Dec 15, 2016 at 11:41
  • 15
    If the function takes an argument of that data type, it is already coupled to the data. Dec 15, 2016 at 11:48
  • 15
    Downvoting because this is incorrect, or at best a matter of opinion. In an OO language, it usually makes sense to have an object contain both the data (which can still be immutable!) and the methods that act on it. Pure functions and separate data are great in other language paradigms, but if you’re doing OO, do OO fully. Mar 25, 2019 at 23:36
  • 12
    Reality has shown us a lot of things. -1 for dogmatic know-it-all "the others have failed" opinion. Also, the author does not say that pure data objects are "wrong", just that they are a "code smell" and worthy of questioning. I only regret that I have one downvote to give for my country. :-)
    – user949300
    Mar 26, 2019 at 0:07
  • 4
    -1 Load of rubbish because A) Using a lower level of abstraction has ALWAYS been the answer when high performance is needed & B) Data classes are a code smell exactly because classes are much more than just a "bag of data" abstraction. And using them like that will only result in fragmented code tightly coupled with your data rather than the operations and behaviours you would apply to that data.
    – ZombieTfk
    Nov 13, 2019 at 13:03
17

There is absolutely nothing wrong with having pure data objects. The author has an opinion not shared by the software developers I know.

Especially for database mapping you in general have entity classes which only contain the fields stored in the data base and getters and setters. Wikipedia on the Hibernate framework

The whole idea of Java beans used by a lot of tools / frameworks is based on data classes called beans that only contain fields and the related getters and setters. Wikipedia on JavaBeans

Bottom line:
If someone claims that something is 'bad' or 'a code smell' you should always look for the reasons given. If the reasons do not convince you ask someone else for better reasons or a different opinion. (Like you did here.)

3
  • 1
    The author does not say that pure data objects are "wrong". They say that pure data objects are a "code smell", which means that you should think twice about using them.
    – user949300
    Mar 26, 2019 at 0:09
  • 1
    @user949300, you seem confused. If the author refers to them as a code smell, then he indicates there might be something wrong with them. As they are widely recognised these days as very good practice, they clearly aren't a code smell. Thus MrSmith42 is correct: there is absolutely nothing wrong with them.
    – David Arno
    Mar 26, 2019 at 8:46
  • @david arno Since OP's data objects are explicitly noted as mutable, they are a smell in both OOP and FP.
    – user949300
    Mar 30, 2021 at 0:28
6

What you need to understand is that there are two kinds of objects:

  • Objects that have behavior. These should refrain from giving public access to most/any of their data members. I expect only very few accessor methods defined for these.

    An example would be a compiled regex: The object is created to provide a certain behavior (to match a string against a specific regex, and to report the (partial) matches), but how the compiled regex does its work is none of the user's business.

    Most classes that I write are in this category.

  • Objects that are really just data. These should just declare all of their members public (or provide the full set of accessors for them).

    An example would be a class Point2D. There is absolutely no invariant that needs to be ensured for the members of this class, and users should be able to just access the data via myPoint.x and myPoint.y.

    Personally, I don't use such classes much, but I guess there is no larger piece of code that I've written that doesn't use such a class somewhere.

Becoming proficient with object orientation includes realizing that this distinction exists, and learning to classify a class' function into one of these two categories.


If you code in C++, you can make this distinction explicit by using class for the first category of objects, and struct for the second. Of course, the two are equivalent, except that class means that all members are private by default, while struct declares all members public by default. Which is exactly the sort of information you want to communicate.

4
  • 2
    An explanation for the downvote would be cool... Apr 25, 2019 at 7:21
  • Thanks for the answer. I hate it when people downvote for no reason. If you have a problem with an answer, explain why. Nov 30, 2019 at 17:28
  • 1
    What about classes that have behaviour but no data...? Apr 19, 2021 at 20:07
  • @OlleHärstedt That's just a special case of objects that have behavior, the special case that has no accessors by definition, actually. Apr 20, 2021 at 11:00
5

A good argument why by Martin Fowler:

"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."

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

12
  • 2
    The problem here is that Fowler artificially restricts "tell don't ask" by changing functions from asking a wider scope to just asking the object scope. They are still asking. "Tell don't ask" can in fact be taken a step further by truly telling those functions via their argument lists. And thus we arrive at data objects and separate (data wise) functions being the true implementation of "tell don't ask". So rather than being a good argument for the claim that data classes are a code smell, it in fact further proves the opposite.
    – David Arno
    Mar 26, 2019 at 9:59
  • 2
    @DavidArno You’re forgetting about encapsulation and hiding. You tell an object to execute a member method, and the member method goes into the black box of the object and does whatever it has to to get the answer. If you ask an object from outside, you don’t have access to its private state, and so either the object exposes more state than is wise, or the asker has to jump through more hoops than should be necessary. I don’t see why you’d ever “ask” an object in an OO environment. (Other programming paradigms may call for different approaches, of course.) Mar 26, 2019 at 22:09
  • 2
    @DavidArno Of course you can pass baz in as a parameter to a static method, but to do that, you first need to ask the object for it. Perhaps in a programming paradigm where methods were primary (like, say, functional programming) this makes sense, but in an OO environment, it absolutely does not, because objects are primary and should contain both the data and the functions to act on it. Your claim that removing the method from the object has increased encapsulation is also exactly backwards, as far as I can tell, because it means that you now have baz appearing outside the object. Mar 27, 2019 at 11:48
  • 1
    @MarnenLaibow-Koser, I don't claim to "be doing OO". I write code and I use good techniques to do so. Whether those techniques come from the functional paradigm, or the OO paradigm, or who-gives-a-damn paradigm is of no interest to me. Picking a paradigm and sticking to it as fully as possible is pure dogma. It is bad. It is ridiculous. It stifles you and results in inferior code. Don't do it.
    – David Arno
    Mar 27, 2019 at 11:58
  • 1
    @DavidArno On the contrary, if you commit fully to a paradigm (any decent paradigm, not just OO), you get powerful high-level abstractions and logically consistent, maintainable code. I’m not saying this to be dogmatic, but rather pragmatic. I’ve seen and maintained too much code that was apparently produced with an attitude like yours, where the author didn’t really commit to the logical consistency of the system being used. It’s hard to understand, hard to maintain, and hard to modify. No paradigm is perfect, but generally a mixture (unless carefully considered) is harder to understand. Mar 27, 2019 at 12:05
5

In Robert Martin's (Uncle Bob) book "Clean Code", he provides a great argument supporting data classes. He argues that "Data Structure" objects and "Data Transfer Objects" can be a good. They have data only and no functions.

Objects: hide their data (be private) and have functions to operate on that data.

Data Structures: show their data (be public) and have no functions.

The two concepts are opposites:

Procedural code (code using data structures)

Makes it easy to add new functions without changing the existing data structures.

Makes it hard to add new data structures because all the functions must change.

OO code (code using object oriented)

Makes it hard to add new functions because all the existing classes must change.

Makes it easy to add new classes without changing existing functions.

The Law of Demeter(LoD)

A method M of class C should only have access to C and M parameters. It should not access parameter1.getSubItem().getSubSubItem(). It should not know about the inner workings of its parameter classes.

Data Transfer Objects

This is a form of a data structure which is a class with public variables and no functions and sometimes called DTO. DTOs are very useful structures, especially when communicating with databases or parsing messages from sockets and so on.

Source: Clean Code | Chapter(6) | Objects and Data Structures

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


Uncle Bob requires that you not mix data classes and OO classes. So if your class has any logic, it becomes an OO class and if it also exposes it's internals via getters/setters, that is bad.

An interesting case of "Data Structure" classes is static inner classes. I regularly use "Data Structure" static-inner classes which are only accessible by the containing class. They are used to construct the data structures for my class. For example HashNode, ListNode, Pair, Tuple.

I would potentially even extend this static-inner-class argument to a module. There might be some "module-private" data-structure classes. They are not part of the module's public api. They are only for internal use inside the module (by the function-classes or services with a public api). But to another developer reading the code who is averse to data-structure classes, they might have trouble seeing the distinction that the class is a "module-private" class (not accessible by the module api) and just see a plain class among many classes in the repo which exposes all its internals publicly (this situation happened to me once in a PR review). So this kind of design can be slightly controversial/problematic.

I often program MVC code-bases. We have model objects or database ORM data objects. Should these be data-structures? Or should they be OO classes and have all their internals hidden? I find this is a common difficult situation hit by a lot of people. And these ORM classes commonly have both OO methods and getters/setters to access the database data. I don't have a great, definite answer to this. I don't necessarily think that all model objects should be locked down with zero getters, with a zealous fanaticism. But Tell-Don't-Ask can be a good principle to try to follow. Whatever you do, I really believe in simple, readable code. I feel like ORM classes are a special example because they are like the api to accessing the database. (Note also that the database can be thought of as a store of globals!)

What is definitely bad is when every object everywhere can freely reach into any other object freely without constraints, across a huge code-base. Particularly if there are lots of globals/singletons/globally-injected-services. This descends into a spaghetti mess. You want to reduce the scope of what-depends-on-what. If I change the structure of this class, what will break? Nothing outside the module should break if you have not changed the module public api. More importantly, when you are troubleshooting, it is hard to reason about code if an object's internals can be fiddled with all across the code-base.

4

Here's what Martin Fowler has to say about data classes in his book "Refactoring":

Such classes are dumb data holders and are often being manipulated in far too much detail by other classes.

Data classes are often a sign of behavior in the wrong place, ...

Note the use of the word "often". Data classes are not always problematic. The way I understand it, such classes are a "code smell" in the sense that you should find out if there is any behavior related to them that is implemented somewhere outside the classes. If there is no such behavior, you are good. Continue using them. Otherwise, refactor them by moving the behavior to those classes.

1

In my experience, "data-only classes" are often used to ensure that the object will never accept an incorrect value – nor, deliver one. The class is brimming with "trip wires," at least in development mode, which will throw exceptions if any of the values they're being assigned, or that they are asked to produce, are wrong.

And, in my humble experience, "that is a life-saver!"

The benefit of this strategy is simply that it gives you a way to detect the problem – to realize that the boat is sinking in the first place – and do so the moment that it happens. "Gotcha!! There's the culprit ... line #2 in the traceback." Without this, you never have known that the problem existed. And you certainly wouldn't [yet ...] know where.

Conversely: "if the exception didn't go off, the bug that you're looking for isn't right here."

"Always write code that is suspicious – looking for trouble."

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.