22

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
  • 3
    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 '16 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 '16 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 '18 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 '19 at 13:58
48

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 '16 at 11:41
  • 14
    If the function takes an argument of that data type, it is already coupled to the data. Dec 15 '16 at 11:48
  • 9
    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 '19 at 23:36
  • 8
    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 '19 at 0:07
  • 3
    -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 '19 at 13:03
12

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 '19 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 '19 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 at 0:28
5

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
  • 1
    An explanation for the downvote would be cool... Apr 25 '19 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.
    – Sipo
    Nov 30 '19 at 17:28
  • What about classes that have behaviour but no data...? Apr 19 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 at 11:00
4

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 '19 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 '19 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 '19 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 '19 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 '19 at 12:05
2

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, privacy policy and cookie policy

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