0

I have recently come across the idea of persistence ignorance, the idea that your domain model should be ignorant of the persistence layer of the application, and that got me thinking.

I have been doing my best to keep different parts of the application loosely coupled, wrapping things like the ORM in interfaces so that I could (relatively) easily swap them out if needed. However, I did find aspects of the ORM and, even more so, the underlying database leaking through into my domain model, forcing me to restructure my data model to fit into and within the limits of the database.

So I was thinking of adding a persistence data model that would be specifically for dealing with the ORM and would directly map to database tables and relationships. Then, when reading data, map from that data model to the domain model, and when writing data, map from the domain model back to the persistence data model. (Currently working in .NET so I can use the wonderful AutoMapper for converting from one type to the other).

Is something like this common practice? Is it worth the extra maintenance overhead when making changes to the domain model? Could this be considered an anti-pattern?

Entith
  • 338
  • 1
  • 11
  • It is common pattern. The reason why Automapper was invented – Fabio Oct 27 '17 at 20:32
  • Are you a self taught programmer ? Pretty much any decent school class where ORM is taught will taught you that too.So yes it is a common practice, is it worth ? it depends off your project. It is not an anti pattern, but if you implements this badly it can end with very poor performance and Oout of memory error by loading the whole base in memory. – Walfrat Oct 27 '17 at 21:03
  • I am self taught. – Entith Oct 27 '17 at 23:54
  • 1
    @Entith curious to know about being “self-taught”. You’ve had no formal instruction in programming at all? Keep in mind that you would not likely learn about ORMs at the university level in computer science. I’ve found the only people who will dismiss you for being “self-taught” are people who need to feel that the gobs of money that they spent on education is worth more than experience. It’s a prejudice based on their own self-importance. – RibaldEddie Oct 28 '17 at 00:45

2 Answers2

3

I think perhaps part of what you are struggling with here is that ORMs are designed to sit in the same spot in the design where the persistence layer would decouple the storage and the domain model. If you want to use an ORM and do this, the only effective solution is to push the ORM down and treat it as the underlying storage which is precisely what you've correctly concluded.

However, I did find aspects of the ORM and, even more so, the underlying database leaking through into my domain model, ...

This is one of my biggest issues with heavyweight ORM. It's very 'opinionated' and tends to be roughly isomorphic to the structure of the underlying database. At the same time, it's easy (even encouraged) to hook it directly into your domain model which then becomes roughly isomorphic to the database structure. You can fight this with complex configurations in many ORM tools but I think (from experience) that it's a bad idea as you will likely create a ton of issues getting the ORM to behave as needed.

So where you end up is essentially an extra layer with a lot of types that exist simply to interface between your domain layer and your ORM. This is where the 'extra' maintenance comes in.

An alternate solution is to ditch the ORM and build a persistence layer that maps directly from the domain layer to one or more persistence layers. In the kind of work my team does, we typically start with multiple storage systems/targets that we need to support and expect to have to swap or accommodate a change in those targets on the scale of every 1 to 2 years. So this kind of decoupling is pretty essential for us to be able to also accommodate functional requirement changes in the domain and yes, it can be done.

JimmyJames
  • 24,682
  • 2
  • 50
  • 92
  • "An alternate solution is to ditch the ORM and build a persistence layer that maps directly from the domain layer to one or more persistence layers." This sounds interesting, can you elaborate on this a bit more, or link to some resources on this approach? – Entith Oct 28 '17 at 02:29
  • I'd love to but I'm not sure where to start. The technique is simply to create domain classes and then define a persistence layer that creates these objects and persists them to the database. What you use to do this is up to you. You can do it with ORM and essentially you are on that path. One thing that came to mind is that you might want to be sure you are not building an [Anemic Domain Model](https://www.martinfowler.com/bliki/AnemicDomainModel.html). The rest of this stuff won't matter much if you don't get the domain model right. – JimmyJames Oct 30 '17 at 13:37
  • I am still poking around to find something to help with your question. It's a pretty large topic. A lot of the design depends on what kind of application this is. Is it a basic CRUD app or something more esoteric? – JimmyJames Oct 30 '17 at 14:44
  • Here are few links to start. I'm a little hesitant to point you to [this one](http://www.yegor256.com/2014/12/01/orm-offensive-anti-pattern.html), mainly because the author has a very 'I know the truth' attitude. He will engage with you if you reply to his posts. I wouldn't recommend it. Here's some [more Fowler](https://martinfowler.com/bliki/OrmHate.html). He's pretty solid and even-handed on this subject. Here's a post about [micro-ORMs](https://martinfowler.com/bliki/OrmHate.html). I'm not a C# guy so I can't vouch for any specific tools. – JimmyJames Oct 30 '17 at 16:17
  • Thanks for the info! That first article is interesting; I can see where he is coming from, and to some extent I agree, but it seems like you'd have a lot of duplicated boilerplate-ish code littered in all your domain classes, and if you ever need to change your persistence layer, you have to reimplement every domain class. I actually read Fowler's article on Anemic Domain Models not too long ago and am still trying to wrap my head around it. All my data models so far have been anemic, with data access handled by the ORM and domain logic handled in services and hooks into read/write events – Entith Oct 30 '17 at 19:37
  • @Entith Just to be perfectly clear, I would take the first article with a big grain of salt. The guy is pretty smart and a lot of what he says is really quite correct but I find his prescriptions lacking in pragmatism. The problem I see is that ORM seems to be treated as a necessity by many burgeoning designers. That article is a polar opposite view of that presumption. I'm not suggesting his solution is the right one for you. In a pure design, I don't believe the domain objects should have any knowledge of their persistence. Try starting from there and make reasonable compromises. – JimmyJames Oct 30 '17 at 20:18
  • @Entith There's also a good explanation of [CQRS](https://martinfowler.com/bliki/CQRS.html) buried in the Fowler links above. This is an effective way to avoid the need/desire for ORM. It might seem like a lot of extra effort at first but reading and writing data are such different problems that it ends up being two relatively simple problems to solve instead of one really hard one. Another point he touches on is that if you are working with an RDBMS, you should know SQL. Not mastery, just the basics. – JimmyJames Oct 30 '17 at 20:28
-1

In my view it’s not worth the effort. In the late 90s I worked for a non-profit and they had a dbase IV based application— I don’t even remember what the app code was written in. Pascal? COBOL? I don’t remember. Anyway it got rewritten for the next technology, MS Access and VB.

Every project I’ve been involved with hasn’t ever needed to rip out the ORM layer nor the database. These just aren’t the parts of the system that need a lot of change. Business logic, front-end— that’s where all the changes tend to be.

I don’t really understand some people’s obsession with swapping out infrastructure. It’s almost never worth it. When you do start to be restricted by your infrastructure, it will likely be only in a tiny part of your application for a few specific use-cases, and in that scenario you’re better off moving those small, core parts to infrastructure made specifically for your use case, and that infrastructure will be so radically different that you’ll need to rewrite your data model entirely anyway.

RibaldEddie
  • 3,168
  • 1
  • 15
  • 17
  • "and that infrastructure will be so radically different that you’ll need to rewrite your data model entirely anyway." If you need to rewrite your data model because you changed your infrastructure, that pretty much proves they weren't actually decoupled. – JimmyJames Oct 27 '17 at 21:06
  • 1
    @JimmyJames the point is that the mapping stops making any sense at all. It becomes a category error. Like moving from a relational schema to an HBase data store. Trying to “map” it is a waste of time and won’t help you get the benefit of the new store. – RibaldEddie Oct 27 '17 at 21:08
  • 3
    You seem to be suggesting that it's not possible to decouple the storage and the domain model. If you want to argue that, that's fair enough but I think you should be direct about it. I've personally done it, seen it done, and I know lot's of people who claim to have done it. – JimmyJames Oct 27 '17 at 21:12
  • @JimmyJames no I’m saying that it’s not worth the extra work. Yes it’s possible but in the end any purported benefit is lost. And a good ORM will already take care of abstracting away the underlying proprietary store. So it should make it easy to go from MS SQL Server to Oracle or PostGres. That’s what the ORM is for. But spending time to go from an SQL server to some other kind of store, like NoSQL of some kind, will probably be a change in bounded context and the domain / data model will be radically different. You get no benefit from adding another layer of abstraction there. – RibaldEddie Oct 27 '17 at 21:15
  • You are better off building an anti-corruption later when you need it to bridge the different data representations. That extra layer of abstraction becomes YAGNI debt real quick. – RibaldEddie Oct 27 '17 at 21:16
  • 1
    I would say that most ORMs make this difficult. This is part of why I don't like heavyweight ORM. if you dispense with the ORM, it gets a lot easier. I think we can debate the value. It's very expensive to rewrite an application simply to move to a new persistence mechanism. Needing to do so is a failure in design, IMO. – JimmyJames Oct 27 '17 at 21:19
  • @JimmyJames maybe I’m not expressing myself well. You would not rewrite an entire application. Instead you would identify a component of the application that would benefit from a change in infrastructure and then move just that component. But you wouldn’t be likely to do that, say, moving from one RDBMS to another— and if you were to do so, your ORM should handle that. So the extra abstraction is unnecessary. And, when the component is something altogether different from an RDBMS, then it is more likely that the existing abstractions wouldn’t apply anyway. – RibaldEddie Oct 27 '17 at 22:49
  • In my current projects I have things separated and abstracted to the point where I could switch to any RDBM my ORM supports with little to no change in my code anywhere except where I configure the ORM. I could probably swap ORMs with minimal effort. However, I more so find the limits of the DB, or even relational DBs in general, impacting my domain model. For example, I might have a certain inheritance hierarchy in my domain that doesn't fit nicely in a RDBM, so I end up modifying the hierarchy to make it fit, and then my domain model no longer represents what it is trying to model as well. – Entith Oct 28 '17 at 00:09
  • @Entith that’s my point. You’re better off simply not using a RDBMS for that part of the model than writing an extra abstraction on top of the ORM to make it fit. – RibaldEddie Oct 28 '17 at 23:44
  • I was thinking about my comments here and I should clarify that there is a place for disposable applications. For example if the domain logic is really simple, there's not much to gain in avoiding rewriting it each time. It's important to consider what it will mean to rewrite from scratch. Specifically: will most of the effort be in moving to a new back-end or rebuilding the domain layer? – JimmyJames Oct 30 '17 at 20:24