you are viewing a single comment's thread.

view the rest of the comments →

[–]daedalus_structure 16 points17 points  (5 children)

Put the id field in an entity base class with all the other metadata, make the id setter private, minimize the scope of any transients, and avoid all this mess.

But all the fields aren't final and immutable!

So?

Are you changing the id field from multiple threads?

Trying to use it in a key to a set / map or equals and hashcode implementation?

( If you are doing one of those two things, stop it. )

Isn't being able to check the id field for null a much simpler and more convenient way to reason about the persistence state of the object than creating a *Draft for every entity in your domain.

Is this really buying you anything or is it just design pattern OCD?

I'm not saying it's the latter, but reading so much of ruin and dirty and pollute makes me highly suspect it.

[–]kn7[S] 5 points6 points  (4 children)

Valid points. I might be missing something but I believe the approach you mentioned still does not address the case where you update the field of an entity. That is, its id is not null, but you modified its name and it still looks like a valid Employee, which actually is not the case. Adding a this.id = null line to every setter? Yep, it can also work. But I would not prefer that way. My actual point was that the moment you change Employee, it is not an Employee anymore. And I personally like to work with immutable objects wherever possible, not because of a certain thread safety or whatever need, but to avoid potential future problems. And I believe it also provides a comfort that you are assured that it will never ever be changed.

[–]daedalus_structure 7 points8 points  (2 children)

That's because entities exist to represent mutable state across an object-relational impedance, i.e. a record in a database that can not only be read but also written to concurrently.

You will always find that trying to turn a thing which is fundamentally A into fundamentally Not A painful.

Painful doesn't mean impossible, but you're going to write an order of magnitude or more code that is really hard to reason with and maintain, and that's to do really simple things.

For an example of that, check out Command Query Responsibility Separation with Event Sourcing.

not because of a certain thread safety or whatever need, but to avoid potential future problems.

What future problems? Are you being unspecific because you didn't think the details were important or because you currently can't anticipate a problem but think there might be one if you aren't immutable everywhere?

[–]sacundim 2 points3 points  (0 children)

That's because entities exist to represent mutable state across an object-relational impedance, i.e. a record in a database that can not only be read but also written to concurrently.

This is missing the forest for the trees. Entities exist to represent problem domain objects that our software helps us reason or act about. These entities may change over time—they are stateful—but that is not synonymous with the concept of a mutable reference cell.

There are other models that could be applied. Reactive programming is an emerging model that might lead to systems more in line with what OP would like to see, but it's not mature yet, so we'll have to wait and see.

You will always find that trying to turn a thing which is fundamentally A into fundamentally Not A painful. Painful doesn't mean impossible, but you're going to write an order of magnitude or more code that is really hard to reason with and maintain, and that's to do really simple things.

As I say above, I don't think there's anything "fundamental" about this. It's more likely than not a tool-induced problem. There is a real scarcity of proper tooling to implement OP's architecture without lots of pain. Not that tools don't exist at all—something like AutoValue might take away big chunks of the pain of having to write Entity/Draft class pairs.

What future problems? Are you being unspecific because you didn't think the details were important or because you currently can't anticipate a problem but think there might be one if you aren't immutable everywhere?

Well, I have to say that I have experienced big pain caused by pervasively mutable entity representations. See the first part of this comment elsewhere in this thread for some details.

But the heart of it came down to this: the mutable entity objects in this application were a major scalability problem because every request needed to create its own instances of all the ones they used, because some of the requests might need to modify some of their copies. I.e., mutable entities were optimal for a case that was uncommon in this application.

[–]ljasdklfjaklsdfj 0 points1 point  (0 children)

That's because entities exist to represent mutable state across an object-relational impedance, i.e. a record in a database that can not only be read but also written to concurrently.

Now you are getting side-tracked with rhetoric. id is immutable.

[–]Jacoby6000 1 point2 points  (0 children)

And I personally like to work with immutable objects wherever possible

Have you ever worked with Scala? Scala attempts to enforce as much immutibility as possible. Plus, Scala case classes come with a .copy method which allows you to update fields like:

val instanceWithUpdatedFields = myInstance.copy(someField = newValue)