5

After asking about the implementation in Ruby of the Identity Map pattern because the potential memory leak in long running server apps, I am considering my initial concept of that pattern.

Initially I thought it was intended to cache database results AND guarantee that only one instance of the same object exist in memory. Is this last assumption right?

Within DDD there is the tendency where Entity equality is based on having the same id not the same memory address, that fits perfectly with the memory problem, however after using many ORMs I always had the "feeling" of having a unique instance of my objects. Is this assumption a dangerous idea? Should I normally be concerned about my objects having multiple instances? Or even being out of sync with the database?

  • This is a fantastic question. I used a similar idea. However, after realizing that managing the Map so that I won't have memory leak is going to be lot of work I switched to a different approach. My thought about the advantage of this Identity Map is that it saves memory and help managing concurrent write to the same object from different aspect easier. My later approach is that only load into Identity Map objects that in my model will not be changed, or objects that will be changed in some non-business logic attributes. All other objects are loaded from the database on demand no fancy mapper. – InformedA Aug 14 '14 at 15:35
  • .. Identity Map saves memory and database IO (caching) too, but the saving on IO is only worth it if it is correct (ie, we can somehow guarantee that the cached version in the map is in synch with the version in DB) – InformedA Aug 14 '14 at 15:41
4

Is this last assumption right?

Yes, what else do you think?

Within DDD there is the tendency where Entity equality is based on having the same id not the same memory address.

This has nothing to do with DDD. "Database objects" always need a unique key or Id, there is typically no "memory address" to be stored in the DB to distinguish them. So there is always an id available, which can be also used for checking equality for objects in memory, regardless from using the identity map pattern or not. Having an "Identity Map" in place, and assumed in your context you can make 100% sure that no object can be created without checking the "Identity Map" first, it is indeed possible to replace the id test by a memory address test, but in practice the advantages are IMHO very small.

I always had the "feeling" of having a unique instance of my objects*

Honestly, having a "feeling" about something like this is IMHO a different word for not knowing how something works. And yes, using a framework without knowing what goes on is always "dangerous" (I prefer the term "error-prone"). To be more specfic: when using an ORM, one should inform himself thoroughly if the ORM already provides something like an "Identity Map" or "Object Cache", and what features it provides exactly.

Should I normally be concerned about my objects having multiple instances?

This depends heavily on the kind application you are going to write, on the kind of business transactions, on the number of records involved, on the kind of queries, and so on. It is perfectly possible to write applications which create objects from the database in a local scope, manipulate them and write them back, without caring about other parts of the application which might have a 2nd copy of the same "db object" at the same time. But if you need the same piece of information in your application always in sync, this might not be the way to go.

Or even being out of sync with the database?

Again, this depends. For lots of applications you cannot even avoid things to get out of sync, at least for a short time (think of a scenario where a second client changes the DB over the network, without any "push" mechanic). But how long this is tolerable, and if certain transactions need to be 100% sure to have the newest version data, depends on your requirements.

| improve this answer | |
  • Somehow I got my basics messed up because after reading again the DDD and Enterprise Pattern books I cannot stop rethinking basic things I thought I already knew quite well. Probably I have been spoiled by too much abstraction of some tools that never made me think what was under the hood – SystematicFrank Aug 14 '14 at 11:55
2

Your understanding is correct.

Identity maps are meant to help object-oriented programmers deal with state management issues. They write imperative programs which, if care is not taken, might end up having different areas of the program dealing with an outdated copy of a persistable object.

Consider basic concurrency issues. Alice pulls up a particular record on her screen. Bob does the same a moment later. Alice updates her copy and saves, then Bob does. Alice's changes are lost if the program doesn't consider this scenario.

Now take into account the same thing but within the confines of a single program. Some nebulous Area A of the program loads an object into memory while some other nebulous Area B does the same. Area A updates its copy, then Area B. It is always the design of the program that permits internal concurrency issues.

In the imperative world state change runs rampant. The identity map is pattern for alleviating in-memory concurrency issues. In programs designed to avoid concurrency issues identity maps are unnecessary. The problem is that the path of imperative code can be unpredictable and one has to wonder if there might ever be a concurrency issue and guard against it -- just in case.

This would all be less of an issue in functional programming because there is an emphasis on having immutable data. Everything is represented in data structures. Each piece of data is represented just once (SPOT) as part of some larger data abstraction that represents the entirety of all the data in its world. Identity maps are completely unnecessary. Or, in one respect, you could say that the entire foundation of functional programming is built on using identity maps -- a single big ball of world state.

| improve this answer | |
  • I have a question that I wonder how an expert would solve: What if in a single program, area A loads the data object. Then the user decides that he needs to edit the data so he opens another area B of the program where he can edit the data and makes the changes, saves it to the DB. Now when he goes back to area A, he will have the data not in synch. What would be the approach for this situation? I have some solution myself, but I am not sure that would be the best practice. – InformedA Aug 14 '14 at 17:14
  • Area A only matters if it's still around when Area B gets ahold of an object. The trick is to avoid holding state whenever possible. Think of how the classic web worked. Web pages used to maintain no longer-term state (which is very good). However, today browser clients are single-page apps that maintain long-term state which is a more difficult model. So design to avoid keeping state around. And if you can't do that, use the entity map pattern. It's for precisely this scenario. – Mario T. Lanza Aug 14 '14 at 17:37
  • Think about it this way: The user opens a web app in a browser window. Then he realizes he has to make some edit before going further, so he opens another browser window to get to the edit page. He makes the edit, and goes back to the initial browser window. Of course now, the data is not in synch. If the whole browser window collection is part of a single desktop app, then identity map will help as the initial window is there with old data can be easily updated, but you get memory leakage. What should one do here in this case? – InformedA Aug 14 '14 at 17:45
  • Your higher-level abstraction -- the app that contains the browser windows and the identity map itself -- knows who is using what and so it manages and disposes of objects properly (disconnecting events for example) so that there are no memory leaks. – Mario T. Lanza Aug 14 '14 at 17:49
  • That will be lot and lot of very difficult work. I hope to see some expert giving another solution – InformedA Aug 14 '14 at 17:53
2

Identity Map should be scoped per-request or per-form, not open-ended in scope. Memory should thus be proportional to concurrent usage (and perhaps timeout of expired sessions) and should not grow beyond that.

Keying the Identity Map by database identity (eg primary key) is best. Other people talk about using business key (eg. name, address, DOB) as the key but that approach has significant deficits -- eg. no longer matches when address changes.

Identity Map is a separate concept from locking -- concurrent users should have separate instances of the objects they are potentially modifying; without distinct instances, it's hard to represent their separate changes/ or to track the optimistic locking 'version number' they are expecting to save to.

| improve this answer | |

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.