Ayende @ Rahien

Refunds available at head office

Plain old .Net classes

Frans Bouma commented on my post about persistance ignorance, which I feel deserve a post in reply.

First, let me define the term POCO or PONO, it means Plain Old C# (or .NET) Object. The term comes from the Java world, where it is used to describe objects that are not encumbered with frameworks (like EJB, for instnace). A good example of a non-POCO class would be the WebForm1 class. It cannot be usefully utilized outside the ASP.Net envrionment.  Persistance ignorance is not having the entity class involve in its own persistance (or in persistance at all).

Persistance ignorance is not always nice to have, Castle Active Record, which I am using in my current project, is certainly not Persistance Ignorance, it explicitly puts the responsabilities for persistance on the class (and handle it in the base class). Active Record make it much easier to work with NHibernate. The important thing about Active Record is that I can decide that I want this and that class to be ignorant of their persistance, and handle it seperatedly, even to the point where their assembly do not reference the Active Record assembly. This is no minor thing.

Now let me get into Frans' comment (note: I edited the comment to concentrate on the stuff that I want to bring to discussion and to reply to. You can read the full comment here):

Persistence ignorance is as useless as POCO is as a term. A POCO class isn't persistable unless some post-compile or runtime-magic is added to the class. This is often overlooked by some of the vocal 'POCO or bust' people, and it gets really annoying. Because, it really matters WHAT is added to the POCO class: O/R mapper A adds different magic than O/R mapper B. [...]

So swapping O/R mappers will change the behavior of your application [...]
So is this 'persistence ignorance' really existing? No. Not only is the database part of your application, if you want it or not, it also makes up a huge part of your application's execution time, so your application spends a lot of time inside the DB. Ignoring that doesn't make it go away. In fact, ignoring that makes you vulnerable for bad performing applications which you could have avoided with simple thinking and proper architectural decisions.

I agree with everything that is said here, except the bolded part (emphasis mine). Because to my way of thinking, even with all the conditions that Frans mentions, persistance ignorance is important. It is important because my business logic isn't cluttered with other respnsabilities, it is important because we don't have mixins in .Net, and I got only one base class, and I am already using it. It is important because I may use types from other assemblies, including stuff that the author never though would ever be persisted.

Everything that Frans says is true, but it is not true for the object itself. The object is blissfully unaware that it is persisted, or how it is persisted. A good runtime-magic is mostly transperant, and do not require much thinking about in most cases. I was surprise to learn by just how much, to tell you the truth.

Persistance Ignorance has another point in its favor, if you classes are open for persistance ignorance, they are open for other extensability points as well. Validation being the key stone here, but I have done some interesting things with this recently, NHibernate Search, for instance.

If a POCO class ends up with 60% plumbing code for databinding, xml, helper code for producing strongly typed filters, prefetch paths etc. and 40% BL code, what's so great about having to write that 60% of the code by hand? Isn't that tying your code to some persistence framework as well?

If a POCO is 60% plumbing, it is not a POCO, period.

I mean: dyn. proxy using POCO frameworks also force you to write your code in a given way.

Yes, you are forced to use virtual methods. I would have love to remove this restriction, but the CLR won't let me. I consider this a failing of the CLR. That said, it is not a burden, IMO. The most insightful part is this:

After all, the core issue with this is that what POCO people really want is a place to write their own code without having to comply to a set of rules forced upon them by a 3rd party library they use the POCO classes with. If that can be solved, one way or the other, you've solved the problem.

And that is exactly what I like having the POCO option. Because it means that the designer of the tools let me have a lot more freedom than I would have otherwise. Again, take a look at WebForm1 as an example of a non POCO class, just try to work with it without also having the UI instansiated, and try having that outside a request, etc.

Comments

Steve
03/20/2007 12:38 AM by
Steve

This is one of the reasons I'm prefering NHibernate right now - all the mappings are done outside of my objects.

Layering applications is important for many reasons, and if you put your database plumbing in your POCO classes, you are going to make it difficult to make changes down the road.

Frans Bouma
03/20/2007 10:01 AM by
Frans Bouma

"If a POCO is 60% plumbing, it is not a POCO, period."

Though, doesn't that mean that poco classes can be really aenemic? (Which according to some people is an anti pattern, because mr. Fowler said so). I agree that it would be better to have no plumbing in a class, though in some occasions you can't avoid it, basicly because the .NET framework wants you to implement given interfaces so the object can be used with .NET framework functionality.

So you then have a choice:

1) write controllers for most parts of your application, so you can avoid plumbing in your classes, though this comes down to re-doing a lot of the functionality already available to you via the .NET framework

2) utilize the .NET framework in full and add plumbing to your classes.

Both have downsides and advantages. I'm not so sure point 2) is that bad, as in most cases the domain objects aren't re-used in another application anyway, so the sole reason to go through all the work for point 1) is basicly 'because someone said it was better though we won't utilize the advantages in this project'.

At least, that's what I have to conclude, as the # of times one will swap o/r mappers is rather small and most people won't do that at all, as doing so will cause problems anyway so doing all the work for 1) isn't making it less painfull.

@Steve: I wasn't talking about db plumbing, I was talking about .NET framework plumbing, like databinding crap, XML serialization code etc. Especially code for databinding is a true pain if you want to do it correctly.

Ayende Rahien
03/20/2007 10:35 AM by
Ayende Rahien

utilize the .NET framework in full

Can you define what you mean not utilize the .Net framework in full?

You mention data binding, XML serialization, etc.

All of them require non trivial work on the side of the class in question, I agree, and that get fairly annoying very fast.

I don't have a problem with POCO being anemic, it simply means that it has no business logic associated with it. Usually it is meant mostly for display / reference.

As I mentioned, POCO is not always the easiest solution, Active Record handles a lot of the stuff that NHibernate does for me, and base classes such as Rocky's CSLA framework handle data binding, undo, etc.

Also, am I the only one who literally had given up on two way databinding ? The amount of stuff you have to do to get it right is simply too big. I write custom code for this, and it is much simpler to use and work with.

Sergio Pereira
03/20/2007 12:45 PM by
Sergio Pereira

(persistence ignorance) is important because we don't have mixins in .Net

Since I learned bout the extension methods in .Net 3.5 I've been playing with the notion of an "ActiveRecord mixin". Granted it's not exactly the same thing and would still have limitations.

I'm curious to know if anyone else has any thoughts on that. I mean, implementing some of the AR instance methods as extension methods and freeing your object's inheritance decision (maybe requiring one marker interface.) One drawback I saw is the need to import the mixin namespace whenever you need persistence code.

Comments have been closed on this topic.