Glorp Wisdom (pt. 313): Never make two collections exclusive that can share objects

(Please note: the problems described here are not limited to Glorp. This is an issue to keep in mind in all O/R mapping technologies, not only in Smalltalk. What I’m talking about here is also relevant in other languages and frameworks. It just fits nicely into the Glorp Wisdom series)

Some days are even worse than you might think (see the last installment in this series), because they make you shake your head and pray that at least this last stupid error was not yours.

In this case, it was. As I’ve mentioned before, marking a OneToManyRelationship in Glorp to #beExclusive can cause problems if you want to move the object from one such collection to any other collection or even a 1:1 relation.

Looking a bit deeper, this error is quite pardonable compared to an even dumber one:

Never mark two (or more) OneToManyRelationships as exclusive if they could ever share objects.

Why, you ask? Glad you do, because it makes me feel a bit better. Because as I said in pt. 312, teh object will be relentlessly deleted if it is removed from one of the two collections. No matter if you intended it to remain present in the other one, Glorp will be ruthless (because you told it to be, not because it is a bad guy) and kill it. Forever.

Okay, you think that’s obvious and clear and not worth mentioning, and this would never happen to you. I bet you are wrong!

Because object models evolve. What once was clearly a case of “if it’s not referenced by this object, there’s no use in its existence, ever” may one day look completely different. You may add some 1:m relationship for performance reasons, or you may simply look at another aspect of your business model for a new feature and have the same idea: “well, if it’s removed from here, than it cannot be anywhere else”. Unless it can for reasons that are long forgotten or just not in your focus today.

After the experiences I’ve had today, I’d tend to say #beExclusive should be avoided as long as possible. It does make sense in some cases, but only if an object in an exclusive relationship really is onle related to its containing object and cannot be referenced from anywhere else. And even if you think that is clearly the case in your project, be careful!

Why do I say such stupid things? Because if you have a few thousand unreferenced objects in your database after a while of operation, you can always delete them or simply let them linger a little longer. Storage is cheap. Maybe you’ll finde a bug one day and be glad there are ways to recover their references and build some highly complex SQL code to get them back. An unreferenced object in the DB will not disturb your application’s operations and not get in your way.

If Glorp, however, deleted too many objects because of your mapping error, you may have trouble recovering any data. And it can take months and years to find this problem.

I’m in the flow today, so I’ll give you another word of wisdom for free:

Always act as if you had no relationship mappings, foreign keys or contsraints like ON DELETE CASCADE and clean up your backpointers and stuff in the application instead of relying on some “obscure” database functionality. Clean up on the object side and make sure objects that shouldn’t reference an object, really don’t, rather than assuming the database will do it anyways.

If you follow this rule, there are multiple benefits:

  • Your objects in the image reflect the situation in the database much better. The objects in the image may look good before and after a commit, but once you read them back in another session, the situation may be completely different
  • Hunting for issues becomes much easier because you can watch what is being de/referenced in the debugger. There is no magic hidden in an ORM layer or even the Database (which is not even visible in an SQL log…)
  • Your application is better suited for moving it to other storage techniques, be it simple serialization, NoSQL databases or an OODB system, because these all have no equivalent for constraints like #beExclusive