What is your confidence level?

Posts   
 
    
mattsmith321 avatar
Posts: 146
Joined: 04-Oct-2004
# Posted on: 28-Jun-2008 00:34:21   

Frans -

I just stumbled on the ADO .NET Entity Framework Vote of No Confidence movement. Actually I ran across it on this post which has a few more thoughts and links: Entity Framework vote of no confidence.

Normally when I run across an OR/M related topic, I see end up running across your position in the comments or via posts on your own blog. So far, I haven't seen or heard anything from you.

What is your position? Or are you staying out because it is EF-specific? I believe I recall that in the past you hinted as much (a framework like this is really complicated and despite having lots of resources, they have a pretty big learning curve).

Just curious what your thoughts are. stuck_out_tongue_winking_eye

Matt

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 28-Jun-2008 10:49:57   

mattsmith321 wrote:

Frans -

I just stumbled on the ADO .NET Entity Framework Vote of No Confidence movement. Actually I ran across it on this post which has a few more thoughts and links: Entity Framework vote of no confidence.

Yes I've seen it. After I read the letter I knew who wrote it, and indeed, it was Bellware.

Normally when I run across an OR/M related topic, I see end up running across your position in the comments or via posts on your own blog. So far, I haven't seen or heard anything from you.

What is your position? Or are you staying out because it is EF-specific? I believe I recall that in the past you hinted as much (a framework like this is really complicated and despite having lots of resources, they have a pretty big learning curve).

Just curious what your thoughts are. stuck_out_tongue_winking_eye

Matt

The point is that if you sign the petition, you state that you agree with what's said in the letter. But the letter contains a lot of bullshit, hand-waving pseudo science based nonsense and above all: it lacks focus on the real problems with the EF.

Because the letter was so crap, I couldn't sign it. I understand the motivation behind it, which is plain and simple: the 'EF' shouldn't become the de-facto O/R mapper of choice for .NET just because it's from MS, and I agree with that. However, as with most alt.net communication: it lacks serious focus. Signing this letter would mean that I'd agree with the points stated in the letter which are good humour, but a bad set of arguments.

I also find the whole point of a petition rather meaningless. It surprises me that MS even pays attention to this, as if it matters. Even if there are 1000 or more people signing it, it is of no use: the EF design team does what they think should be done, and not what the nhibernate followers think should be done.

I thought about writing about it, but what's the point? 'O/R mapper developer X says EF isn't good', that's a surprise! wink . In my long blogpost about the EF a couple of weeks ago, I discussed things on a more fundamental level, and I think that's the way people should discuss topics like the EF.

I mean: if this is enterprise material, try it with 300-400 entities. You mightbe able to create something, but then we'll put to rest, and after a few weeks you've to pick it up again and alter 20 entities and create 10 new ones. You'll then clearly see that maintainability is simply not there. This crucial point, (there are many more) isn't even in the letter. Anyone who has seen the EF designer with even the 90 entities from adventureworks is convinced that this isn't going to work. Sure, one can write all the crap by hand, but why use the EF then? simple_smile

So I stayed away from the petition, and haven't signed it because of these reasons. simple_smile

You signed?

Frans Bouma | Lead developer LLBLGen Pro
mattsmith321 avatar
Posts: 146
Joined: 04-Oct-2004
# Posted on: 28-Jun-2008 20:25:24   

Otis wrote:

You signed?

I did not sign. I decided I wasn't qualified.

While I keep up with most of the bigger OR/M discussions that hit the blogosphere, I actually haven't tried any other tools since doing my research and settling on LLBL Gen Pro back in 2004. Even then, things have been pretty stagnant for me personally from a development perspective. I'm barely hanging on to the technical side of things (moving up at work and not much time for MyHP). So, while I understand most of the arguments, it isn't something that I have personally experienced so I felt like I would be piling on or taking a 'Me too!' or 'What he said!' mentality.

It is unfortunate that the masses will buy in to the concept just because it comes from the mothership. You'd think that people would be a little smarter. After all, under how many different names has Microsoft tried to pursue (unsuccessfully) these object/entity/ORM concepts.

And why are they choosing to petition this particular little bit of technology? It's not like this is the one exception that Microsoft didn't get right. Where were they for all of the other limited ideas that ran us into dead-ends? How many different data grids have we had? What about those validators? Post-back model? View state? Why does MS choose to screw with my client-side control IDs (I know why technically, but it is a PITA)? And on and on. So I don't see why this should come as a surprise.

A lot of people accuse MS of running the smaller players out of the market (for various niches). However, since most MS products only get you 80-85% of the way there, to me that leaves a huge hole for others to step in to try to fill. I don't have a lot of money to spend on components and controls but whenever I see something that MS has done, I like to do some research to find the people who have kicked it up to the next level.

Matt

Posts: 3
Joined: 28-Oct-2006
# Posted on: 29-Jun-2008 00:33:38   

I subscribed..

Otis wrote:

bullshit, hand-waving pseudo science based nonsense

That’s an accurate definition for day to day software design. smile

Nobody ever starts a petition thinking that someone else will actually be counting the number of subscribers. Nevertheless I did sign because indeed I have some concerns “for the welfare of software projects undertaken in the Microsoft customer community that will make use of the forthcoming ADO .NET Entity Framework.” The fact that I signed may not change anything about EF, but it will certainly not do any harm.

In general I fear that the adoption of EF will make for some bad publicity for O/R mapping (regardless of what the official purpose of the framework will be) in the .NET world.

The letter mentions, as one of the problems, the insufficient support/flexibility for full OO domain models (where behavior is implemented inside entities and less in domain services or regular procedures). Is this statement true or not? Sure you could write (or generate) code yourself to improve the situation, but still, I think they have a point.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 30-Jun-2008 09:55:22   

mattsmith321 wrote:

Otis wrote:

You signed?

I did not sign. I decided I wasn't qualified.

Why not? Everyone on that list except Oren and Wilson are O/R mapper users, just like you. The petition is for o/r mapper users, not for o/r mapper writers. simple_smile

While I keep up with most of the bigger OR/M discussions that hit the blogosphere, I actually haven't tried any other tools since doing my research and settling on LLBL Gen Pro back in 2004. Even then, things have been pretty stagnant for me personally from a development perspective. I'm barely hanging on to the technical side of things (moving up at work and not much time for MyHP). So, while I understand most of the arguments, it isn't something that I have personally experienced so I felt like I would be piling on or taking a 'Me too!' or 'What he said!' mentality.

Oh don't worry simple_smile Most of these discussions are rather useless anyway. The big point is: a developer wants to work with data, so that developer has to be able to do that in the least problematic way where s/he can make as less errors as possible. Everything else is just politics.

And why are they choosing to petition this particular little bit of technology? It's not like this is the one exception that Microsoft didn't get right. Where were they for all of the other limited ideas that ran us into dead-ends? How many different data grids have we had? What about those validators? Post-back model? View state? Why does MS choose to screw with my client-side control IDs (I know why technically, but it is a PITA)? And on and on. So I don't see why this should come as a surprise.

I think what the majority of the petition signers doesn't want to say out loud is that they're not really happy with nhibernate and want MS to do it right this time. Though they didn't have much success, so the EF isn't what the nhibernate crowd expected / needed / wanted.

Because: if they're so good and respected as they say they are, and you're hired to run a team, and someone said 'We'll use the EF' while you want to use nhibernate, why not just say so and use nhibernate? People who are hired to get things done get the stuff to do their job, because that's in the interest of the employer, as these people in general aren't cheap, but they're worth their money.

That's why I never understood why the nhibernate followers put so much energy in fighting the EF.

A lot of people accuse MS of running the smaller players out of the market (for various niches). However, since most MS products only get you 80-85% of the way there, to me that leaves a huge hole for others to step in to try to fill. I don't have a lot of money to spend on components and controls but whenever I see something that MS has done, I like to do some research to find the people who have kicked it up to the next level. Matt

Exactly simple_smile 15% of 1-2million developers is still a lot simple_smile

Though it's unfortunate that MS has released not 1 but 2 o/r mapper frameworks instead of just providing an API which 3rd party o/r mappers could implement and be done with it. Luckily they made mistakes all over the place in their designers, which are key to make an o/r mapper a success, so in the end it will be ok I think.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 30-Jun-2008 10:14:39   

Marc wrote:

I subscribed..

Otis wrote:

bullshit, hand-waving pseudo science based nonsense

That’s an accurate definition for day to day software design. smile

Not entirely. simple_smile . The thing with the claims in the petition is that they're stated without proof, and it looks like the reader should just accept them because the writer(s) are so incredibly good. I don't buy that kind of reasoning wink . On a blogpost, sure, but on a petition text.... no way.

Nobody ever starts a petition thinking that someone else will actually be counting the number of subscribers. Nevertheless I did sign because indeed I have some concerns “for the welfare of software projects undertaken in the Microsoft customer community that will make use of the forthcoming ADO .NET Entity Framework.” The fact that I signed may not change anything about EF, but it will certainly not do any harm.

Remember the VB6 petition? It was started by Karl Peterson. He was a long-term VB MVP (one of the MVPs with the most years under the belt), and he even designed the old MVP logo. In the year of the petition, he didn't get renewed as MVP, although he answered over 4000 usenet posts, more than the year before. It could harm, trust me.

I agree that it won't make a difference.

In general I fear that the adoption of EF will make for some bad publicity for O/R mapping (regardless of what the official purpose of the framework will be) in the .NET world.

You'd think so? I think Linq to Sql has a far better position to make O/R mapping look bad, with a wider acceptance ration and with a framework with more flaws. But indeed, some might feel O/R mapping is bad, although they'll base their experience on MS' stuff.

The letter mentions, as one of the problems, the insufficient support/flexibility for full OO domain models (where behavior is implemented inside entities and less in domain services or regular procedures). Is this statement true or not? Sure you could write (or generate) code yourself to improve the situation, but still, I think they have a point.

I find that kind of claims always pretty stupid. There are a few weird things about this: 1) if they're so full of OO, why is the change tracking of an entity outside the entity in some separate object, while the data tracked is inside the entity? That breaks encapsulation 2) there are more or less 3 different types of BL rules which form the behavior on data: a) single entity field oriented behavior (id>10) b) multi field, single entity oriented behavior (orderdate <= shipping date etc.) c) multi entity oriented behavior.

If one decides to implement 'c' inside entities, they'll create a web of dependencies between types, which will fragment logic all over the place. You can still implement behavior inside entities, but behavior which affects multiple entities, in which entity will you implement the routine which controls that behavior? People are so afraid to create an 'aenemic domain model', simply because someone once said that it is bad (that same someone is now only doing ruby so go figure).

Similar to that, is the wizardry in the petition about canonical domain models. It claims that these are bad. But, based on what proof is this conclusion drawn?

Think about it for a second: if I have a meta model with entity definition data, am I then able to leverage that data to form new entities/queries to feed report engines for example? If one says: "No!", that person has no clue what 'entity' is all about or what it means (Chen's paper is very clear).

Of course, if you want to re-use the big truck of classes into a report engine, no, that's not going to work, but building new queries on top of that model, sure that's going to work pretty fine, as that's the cornerstone of Codd's theory. Though, you'll get problems if the definition of what an entity instance is in memory gets blurred out due to the code it has to be used in: code doesn't give data context nor meaning, though the petition claims it can.

Frans Bouma | Lead developer LLBLGen Pro
stefcl
User
Posts: 210
Joined: 23-Jun-2007
# Posted on: 30-Jun-2008 12:33:47   

I find that kind of claims always pretty stupid. There are a few weird things about this: 1) if they're so full of OO, why is the change tracking of an entity outside the entity in some separate object, while the data tracked is inside the entity? That breaks encapsulation 2) there are more or less 3 different types of BL rules which form the behavior on data: a) single entity field oriented behavior (id>10) b) multi field, single entity oriented behavior (orderdate <= shipping date etc.) c) multi entity oriented behavior.

If one decides to implement 'c' inside entities, they'll create a web of dependencies between types, which will fragment logic all over the place. You can still implement behavior inside entities, but behavior which affects multiple entities, in which entity will you implement the routine which controls that behavior?

Do you mean that entities should not be used as business objects?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 30-Jun-2008 13:19:48   

stefcl wrote:

I find that kind of claims always pretty stupid. There are a few weird things about this: 1) if they're so full of OO, why is the change tracking of an entity outside the entity in some separate object, while the data tracked is inside the entity? That breaks encapsulation 2) there are more or less 3 different types of BL rules which form the behavior on data: a) single entity field oriented behavior (id>10) b) multi field, single entity oriented behavior (orderdate <= shipping date etc.) c) multi entity oriented behavior.

If one decides to implement 'c' inside entities, they'll create a web of dependencies between types, which will fragment logic all over the place. You can still implement behavior inside entities, but behavior which affects multiple entities, in which entity will you implement the routine which controls that behavior?

Do you mean that entities should not be used as business objects?

No, what I meant is that if you have multi-entity business logic, you should place that logic in governing classes ('manager classes'), which are more or less stateless. This has the advantage that you have the logic for a procedure in one place so it's more maintainable, and you don't make a web of fragmented code scattered all over the place. But that doesn't mean you can't place parts of that code inside the entities. For example the manager classes call just methods inside entities, however the order in which the calls take place isn't stored inside one entity, but in a central place, as multi-entity logic isn't owned by one of the entities participating in the procedure.

Creating methods and classes is all about making things easier to understand by creating an abstraction. However, one shouldn't apply that rule all over the place, just in places where it makes sense. In category c logic it often doesn't make sense to scatter that all over the place, you need 1 routine in a manager class. Sure, some people find that mindboggling stupid, and cry foul that it's so incredibly bad and what not, but have you ever read hard evidence why manager classes are bad for category c logic (in a lot of cases) ? I havent.

Frans Bouma | Lead developer LLBLGen Pro
stefcl
User
Posts: 210
Joined: 23-Jun-2007
# Posted on: 30-Jun-2008 15:03:03   

I do use manager classes with static methods which expose business logic as an API. One of our recently hired developer asked why we would write the following code :


AddressEntity shippingAddress = CustomerManager.GetCustomerShippingAddress( customer );

rather than something like :


customer.ShippingAddress;

which seems much more object oriented?

NB: What it does is checking if the shipping address is specified, if not, the billing address is returned. Lazy loading wouldn't help because there might be no shipping address at all.

He was sure that he could achieve better results with a tool like nHibernate, embedding logic inside a Customer business object and making use of LL. I argued that it was because we needed fine-grained control of what's actually fetched from the DB as well as the possibility of sharing a common database transaction between entities in case it's required (very often). He agreed but wasn't convinced... Nevertheless I had to recognize that it isn't as object oriented as what I would have done if I didn't have to care about persistence...

So what about OO? Is it possible to have a pure domain model in real world applications? I mean one which would abstract the database and leave you in your object oriented world?

Posts: 3
Joined: 28-Oct-2006
# Posted on: 30-Jun-2008 16:18:17   

Otis wrote:

No, what I meant is that if you have multi-entity business logic, you should place that logic in governing classes ('manager classes'), which are more or less stateless. This has the advantage that you have the logic for a procedure in one place so it's more maintainable, and you don't make a web of fragmented code scattered all over the place. But that doesn't mean you can't place parts of that code inside the entities.

I agree, I often use what you call "manager classes"... I think it corresponds to what I like to call (domain) Services (based on the DDD). If behaviour can not be placed inside an entity (or aggregate) in a non-awkward way (pseudo science), a Service is definitely an option.

But, ofcourse, Services can/will also become tangled and hard to maintain (Services using Services using Services, excessive contracts, unclear responsabilities, dependance on implicit behaviour,...) don't doubt about that... I basically would like to choose between two "evils" without considering frameworks...

About the petition; you are right to say that it's more awkward for MVP's... For me, Microsoft is very far away... :-)

Posts: 3
Joined: 28-Oct-2006
# Posted on: 30-Jun-2008 23:56:11   

Otis wrote:

Creating methods and classes is all about making things easier to understand by creating an abstraction. However, one shouldn't apply that rule all over the place, just in places where it makes sense. In category c logic it often doesn't make sense to scatter that all over the place, you need 1 routine in a manager class. Sure, some people find that mindboggling stupid, and cry foul that it's so incredibly bad and what not, but have you ever read hard evidence why manager classes are bad for category c logic (in a lot of cases) ? I havent.

It’s not only the business rules. In object oriented systems/components objects typically collaborate to get something done. Objects are (IMHO) core pieces of logic that get connected with each other (in a static or dynamic way). These core functionalities together with the connections determine the behavior of the system/component.   Pure polymorphism and delegation could conceptually be viewed in that way. The same applies for most GoF patterns.   Imagine I have a hierarchical structure of entities and I would like to use the composite pattern in order to aggregate what is only single-entity-field-oriented behavior on entity level. From the system/component perspective the aggregation becomes multi entity oriented behavior.   If you need to externalize this peer-2-peer object collaboration you not only need to break encapsulation big time, you are also in for writing complicated, hard-to-maintain and ugly code. It's true that you could use some kind of Visitor patterns, if the framework allows you to add acceptance behavior to your entities.

I think the urge for a non Anemic Domain Model starts in scenario's like these. Should I start doing Ruby too? :-)

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 01-Jul-2008 10:46:44   

stefcl wrote:

I do use manager classes with static methods which expose business logic as an API. One of our recently hired developer asked why we would write the following code :


AddressEntity shippingAddress = CustomerManager.GetCustomerShippingAddress( customer );

rather than something like :


customer.ShippingAddress;

which seems much more object oriented?

Could be, if the logic for ShippingAddress is only accessing data inside Customer. However, things like: customer.IsGoldCustomer isn't, if this property returns true if the customer has ordered at least 5 orders in the last n months: customer then has to know how to obtain order data, which isn't something you might want to do inside customer. (as order data is for example fetched over a webservice)

He was sure that he could achieve better results with a tool like nHibernate, embedding logic inside a Customer business object and making use of LL. I argued that it was because we needed fine-grained control of what's actually fetched from the DB as well as the possibility of sharing a common database transaction between entities in case it's required (very often). He agreed but wasn't convinced... Nevertheless I had to recognize that it isn't as object oriented as what I would have done if I didn't have to care about persistence...

I really fail to understand why some people find it the ultimate goal to achieve 'total OO-ness' or something, it has absolutely no value whatsoever: the world isn't modelable for 100% in OO constructs, some things are just procedural.

As McConnell wrote in Code Complete: one should create a class if it makes things EASIER to understand and maintain, not just for the sake of creating classes and being able to do so.

For example, the IsGoldCustomer property. One could argue to create a method which accepts an ID and returns true/false. One could argue to call that method from within the IsGoldCustomer property. All fine, however the true logic isn't inside Customer then, but outside it. If one is focussed on technical issues instead of fundamental functional issues, this might be a problem, however for the application it's completely irrelevant. Too many people spend countless hours solving problems which aren't problems at all, and achieving OO-completeness is one of them.

So what about OO? Is it possible to have a pure domain model in real world applications? I mean one which would abstract the database and leave you in your object oriented world?

My answer would be: No. The simple argument for that is that one can't abstract away a database, as it's a valuable and scarce resource and a big part of your application (your application likely spends a lot of time inside the DB).

If a set of webservices are used in an app, one can't ignore the fact that they're not local API's, but services with network transportation etc.. If one uses a relational database, one has to take into account, that using such a resource takes time compared to in-memory constructs, and has limits on its own (one can't expect to be able to fetch 1 million rows in 10 ms just to find some element).

Sure, some people argue that a developer should develop without thinking about the database which will be used, but IMHO that's just silly. It's the same as ignoring how many million rows of data an application has to wade through at production when developing the application. Things like that are real factors, and people have to deal with them. Not by ignoring them, but by acknowledging them and by taking into account the limitations and weaknesses. Only then the developer won't run into surprises.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 01-Jul-2008 11:51:06   

(2 posts combined into one post. Sorry for the length wink )

Marc wrote:

Otis wrote:

No, what I meant is that if you have multi-entity business logic, you should place that logic in governing classes ('manager classes'), which are more or less stateless. This has the advantage that you have the logic for a procedure in one place so it's more maintainable, and you don't make a web of fragmented code scattered all over the place. But that doesn't mean you can't place parts of that code inside the entities.

I agree, I often use what you call "manager classes"... I think it corresponds to what I like to call (domain) Services (based on the DDD). If behaviour can not be placed inside an entity (or aggregate) in a non-awkward way (pseudo science), a Service is definitely an option.

yes, that's what I meant indeed. simple_smile

But, ofcourse, Services can/will also become tangled and hard to maintain (Services using Services using Services, excessive contracts, unclear responsabilities, dependance on implicit behaviour,...) don't doubt about that... I basically would like to choose between two "evils" without considering frameworks...

The thing is though: will it become hard to maintain because the people who wrote it sucked bigtime, or because no matter how good the people were, the methodology sucked bigtime and therefore, it will be unmaintainable, period.

I definitely go for the former. My evidence is: a random well-known, well-established operating system's sourcecode, like FreeBSD or Linux: the codebases are huge, they're completely procedural (0.0% OO), written in a language which doesn't clean up the drivel one leaves behind (C) and there are no unit-tests.

Yet, they work marvelously well. Considering the fact that they completely lack any form of OO (I don't see a void pointer list in a C struct a form of OO, if you don't mind wink ) it's not the methodology used that makes great software (otherwise one could argue that OO is required to write good software for example, but with almost every kernel / OS on the planet being procedural code, that's a bit hard to believe), it's the people writing it.

So the argument 'if you use ABC, it will become unmaintainable' is IMHO not the right argument. The argument should be: "If you use incapable people to write your code, the code will become unmaintable, if you're not careful".

Marc wrote:

Otis wrote:

Creating methods and classes is all about making things easier to understand by creating an abstraction. However, one shouldn't apply that rule all over the place, just in places where it makes sense. In category c logic it often doesn't make sense to scatter that all over the place, you need 1 routine in a manager class. Sure, some people find that mindboggling stupid, and cry foul that it's so incredibly bad and what not, but have you ever read hard evidence why manager classes are bad for category c logic (in a lot of cases) ? I havent.

It’s not only the business rules. In object oriented systems/components objects typically collaborate to get something done. Objects are (IMHO) core pieces of logic that get connected with each other (in a static or dynamic way). These core functionalities together with the connections determine the behavior of the system/component.

Pure polymorphism and delegation could conceptually be viewed in that way. The same applies for most GoF patterns.

To be honest, I find polymorphism a nice thing to have, but at the same time something related to the implementation / code space, outside of the problem and solution space. I.o.w.: the solution for the problem has already been defined before it comes down to the choice if polymorphism should be used or not to solve the problem in a practical, working way. In short: if one can't describe the solution to a problem in terms which have nothing to do with a certain language specific aspects, I doubt the solution is really the solution or if the person really understood the problem.

Imagine I have a hierarchical structure of entities and I would like to use the composite pattern in order to aggregate what is only single-entity-field-oriented behavior on entity level. From the system/component perspective the aggregation becomes multi entity oriented behavior.

you mean, for example, you have a property 'Total' on 'Order' which in fact aggregates over orderlines and perhaps even deeper? which thus looks like single-entity behavior but in practise is multi-entity behavior?

Anyway, aggregation is a procedural action. One shouldn't strive for OO encapsulation of procedural actions, nor should one strive for procedural encapsulation of OO behavior: the world isn't 100% procedural, nor 100% OO.

What intrigues me is your 'I'd like to use the composite pattern' remark. I think the core point is in that sentence: what's the goal, the real goal here: 1) applying patterns or 2) getting the results required (here the aggregated value). ? If 1), go ahead. If 2), is the composite pattern here the best solution to this problem? ('best' is debateable, true) If one takes a step back and tries to formulate the problem (the order total aggregation has to be produced), in terms not tied to a given paradigm/language, is it then obvious to use the composite pattern? That's the point I'm trying to make: I'm not convinced the patterns are a logical choice, or a starting point to begin with.

If you need to externalize this peer-2-peer object collaboration you not only need to break encapsulation big time, you are also in for writing complicated, hard-to-maintain and ugly code. It's true that you could use some kind of Visitor patterns, if the framework allows you to add acceptance behavior to your entities.

Why is it hard to maintain, ugly code? Consider the fact that the aggregation building blocks might be scattered around multiple entities. If the entities change, these code blocks have to move perhaps, but ... where are they? To have overview over a procedural action, which for example takes 10 steps, one has to check all 10 steps, and if they're at 10 different locations in 10 different entities, how will you find those 10 steps? Isn't that also hard to maintain?

If I have 1 method with 10 calls, I see where they are, immediately. Procedural? Sure. An OO-fanatic would likely run to the doctor to get his eyes fixed because they hurt so badly wink

But, is it really important to please the OO fanatic, or is it important to make things simple, easy to understand etc. ?

Mind you, I'm not arguing for breaking encapsulation, nor advocating that people should write procedural code all over the place. What I'm arguing is that people should use encapsulation when it is useful and adds something for the user: accessing 10 properties on an object and then setting an 11th with the processing result of the 10 retrieved values isn't that helpful at first, however it might be better in some situations (e.g. where rules are flexibly defined, based on parameters obtained elsewhere etc.), who knows.

I think the urge for a non Anemic Domain Model starts in scenario's like these. Should I start doing Ruby too? :-)

If the urge for non anemic domainmodels starts with the struggle how to apply patterns to a given object graph, I don't think having non-anemic domain models is the silver bullet which will make things suddenly maintainable, less buggy and easier to understand. It just makes it compliant to some set of rules one has cooked up that if you have all these, your software must be great.

Which is of course nonsense. The point is: if a non-anemic domain model indeed makes the stuff YOU have to make truly more easier to understand, maintain and less buggy, you should create a non-anemic domain model. However, it's not said that just by applying that pattern, things become OK. that's the sillyness of the petition which was the indirect start of this thread: one should not apply a pattern or methodology in the assumption that by applying it, it suddenly will become better. It won't become better.

I'll leave you with an example of an Algorithmia unittest. Algorithmia is our upcoming .NET 3.5 algorithm and datastructures library (likely BSD2, open source released) which is also the foundation (one of them) for LLBLGen Pro v3. If you remember GoF's command pattern, you'll remember that the commands have to be defined externally, and if you want to have 1 command to undo which actually spawned multiple commands and thus undo-es those too, you have to write everything in combined commands, which is a pain, because you've to understand every sequence of commands in your system. Which is undoable, if you're looking at undo-ing and re-doing actions on a graph of objects.

In Algorithmia, commands are implicitly spawned, and through a singleton (thread safe!, so multi-threaded undo/redo) and an active command queue stack, by running 1 command which spawns multiple commands elsewhere (unknown to the initial command but it doesn't care either) one can undo the whole sequence of commands by simply undoing the single command:


[Test]
public void CommandifiedGraphAddRemoveNodeWithUndoTest()
{
    Guid sessionId = Guid.NewGuid();
    CQManager.ActivateCommandQueueStack(sessionId);

    DirectedGraph<int, DirectedEdge<int>> graph = new DirectedGraph<int, DirectedEdge<int>>(true);
    graph.Add(42);
    Assert.IsTrue(graph.Contains(42));
    CQManager.UndoLastCommand();
    Assert.IsFalse(graph.Contains(42));
    Assert.AreEqual(0, graph.NodeCount);

    graph.Add(42);
    graph.Add(13);
    graph.Add(10);
    Assert.IsTrue(graph.Contains(42));
    Assert.IsTrue(graph.Contains(13));
    Assert.IsTrue(graph.Contains(10));

    graph.Add(new DirectedEdge<int>(42, 13));   // 42 -> 13
    graph.Add(new DirectedEdge<int>(42, 10));   // 42 -> 10
    Assert.AreEqual(2, graph.EdgeCount);
    Assert.IsTrue(graph.ContainsEdge(42, 13));
    Assert.IsTrue(graph.ContainsEdge(42, 10));

    graph.Remove(42);
    Assert.IsFalse(graph.Contains(42));
    Assert.AreEqual(0, graph.EdgeCount);
    Assert.AreEqual(2, graph.NodeCount);

    // undo removal of 42. This should re-add 42, but also re-add the edges
    CQManager.UndoLastCommand();
    Assert.AreEqual(2, graph.EdgeCount);
    Assert.IsTrue(graph.ContainsEdge(42, 13));
    Assert.IsTrue(graph.ContainsEdge(42, 10));
    Assert.IsTrue(graph.Contains(42));

    CQManager.ActivateCommandQueueStack(Guid.Empty);
}

(CQManager is a property which obtains the singleton instance of the commandqueuemanager). No commands are used to work with the graph, yet everything is undoable. graph.Remove is doing this (all inside the graph class)


/// <summary>
/// Removes a node from this graph.
/// </summary>
/// <param name="node">The node to remove from this graph.</param>
public void Remove(TNode node)
{
    ArgumentVerifier.CantBeNull(node, "node");
    if(!_graph.ContainsKey(node))
    {
        // not a node in this graph.
        return;
    }

    if(_isCommandified)
    {
        // use a command to call the method so all the commands spawned by the method called are undoable with a single undo.
        CommandQueueManagerSingleton.GetInstance().EnqueueAndRunCommand(new Command<TNode>(() => PerformRemoveNode(node)));
    }
    else
    {
        PerformRemoveNode(node);
    }
}

which in fact is somewhat procedural: it spawns a new command and runs it, that new command simply calls PerformRemoveNode, which does:


/// <summary>
/// Performs the remove node.
/// </summary>
/// <param name="nodeToRemove">The node to remove.</param>
/// <remarks>If you want to undo actions performed by this method, call this method using a Command object.</remarks>
private void PerformRemoveNode(TNode nodeToRemove)
{
    // Remove the node itself...
    RemoveNodeFromGraphStructure(nodeToRemove);
    // ...and also all edges to it.
    foreach(TNode key in _graph.Keys)
    {
        RemoveNodeFromAdjacencyList(nodeToRemove, key);
    }
}

which calls 2 different routines which spawn commands like:


/// <summary>
/// Removes the node from graph structure. 
/// </summary>
/// <param name="nodeToRemove">The node to remove.</param>
/// <remarks>Do not call this method directly. Call Remove() to remove a node. This method is used to physically remove the node from the datastructures</remarks>
private void RemoveNodeFromGraphStructure(TNode nodeToRemove)
{
    if(_isCommandified)
    {
        CommandQueueManagerSingleton.GetInstance().EnqueueAndRunCommand(
            new Command<MultiValueDictionary<TNode, TEdge>>(
                    () =>   {
                                _graph.Remove(nodeToRemove);
                                OnNodeRemoved(nodeToRemove);
                            }, 
                    ()=>_graph[nodeToRemove], 
                    al=>    {
                                _graph.Add(nodeToRemove, al);
                                OnNodeAdded(nodeToRemove);
                            }));
    }
    else
    {
        _graph.Remove(nodeToRemove);
        OnNodeRemoved(nodeToRemove);
    }
}

which comes down to having commands which contain just a set of lambda's, or better: functions.

Would I just go out and apply 'the command pattern', it wouldn't have been so simple, in fact it would have been impossible, as the sequences of which commands are spawned becomes unclear when you take into account observers which control graph structure when some element changes: which object observes which event and in what order are they executed? Unclear. So blindly applying patterns as they're described isn't really working in a lot of cases.

The observers are also a good example of logic outside the object. Removing an entity field which is an FK, requires to have the relation it is part of removed as well (which might cause an M:N relation to get removed as well, and if the relation is part of a typedlist, it might be that the removal isn't allowed). Where to put that logic? Inside the entitydefinition class? That would require that the entitydefinition gets references to a lot of objects it has no business with. Raising an event and let an external manager do the rest is better: it has the overview and can delegate the work to the elements which can do the work, without tying the original event raising class to these elements.

Frans Bouma | Lead developer LLBLGen Pro