- Home
- LLBLGen Pro
- Architecture
Martin Fowler's "Separated Interface" Design Pattern
Joined: 05-Aug-2008
Hello, Forum:
We are currently using DevExpress' XPO, but are strongly considering switching to LLBLGEN (as for their controls, they are unsurpassed by any other component vendor We've downloaded it twice over the past 6 months or so. (I must say, I would pay you guys $279 just for the manual. I've learned more from it than I have from anywhere else ).
I'm only about two years old in the ORM space, but I can say that, after having used XPO for nearly a year now, I can be fairly articulate about why I think LLBLGEN would be a better way to go.
A concern has arisen, however, about the impact on the architecture of our software as a consequence of XPO (or any other ORM, for that matter). It would be desirable to be able to employ Fowler's Separated Interface pattern to insulate from any future, unforeseen changes.
I have two questions:
1) Does the DataAdapter obviate the need to use the SI pattern? 2) If not, is it possible (or even necessary with LLBLGEN)?
Thanks.
Joined: 17-Aug-2003
Eric wrote:
Hello, Forum:
We are currently using DevExpress' XPO, but are strongly considering switching to LLBLGEN (as for their controls, they are unsurpassed by any other component vendor We've downloaded it twice over the past 6 months or so. (I must say, I would pay you guys $279 just for the manual. I've learned more from it than I have from anywhere else ).
I'm only about two years old in the ORM space, but I can say that, after having used XPO for nearly a year now, I can be fairly articulate about why I think LLBLGEN would be a better way to go.
We're pleased to hear that you're considering our work Could you also explain what made you consider a switch? (just so we learn more about our strong points from the point of view of (potential) customers )
A concern has arisen, however, about the impact on the architecture of our software as a consequence of XPO (or any other ORM, for that matter). It would be desirable to be able to employ Fowler's Separated Interface pattern to insulate from any future, unforeseen changes.
You can do this, by generating the interfaces on the fly and have the classes implement the interface as well. There's a downside to this though: it's giving a false sense of decoupling. The point is that the entity classes have behavior inside them, they manage themselves, and they manage the graph they're in. The thing is that when you switch to another framework this might not be the case anymore (e.g. nhibernate doesn't do entity graph management in-memory nor do the entities track their own changes) which could lead to severe changes inside your application (e.g. sending llblgen pro entities over the wire is no problem, change tracking is build in, but with other systems this might cause extra code being necessary to make sure an existing entity isn't inserted twice )
I have two questions: 1) Does the DataAdapter obviate the need to use the SI pattern? 2) If not, is it possible (or even necessary with LLBLGEN)?
Depends on what you need it for. If you want to use the interfaces to be o/r mapper independent, then no. If you want to use the interfaces to be able to work with entities on multiple databases or to not have any persistence logic (like save/delete etc.) inside the entities, then yes.
Joined: 05-Aug-2008
I would happy to explain why we're considering the switch. I'll do that in a separate post. But first, I'll address the issue of the SI pattern.
There's a downside to this though: it's giving a false sense of decoupling.
From my understanding of the SI pattern, it addresses precisely the issue of different underlying implementations. I understand what you mean, though.
Suppose I have an interface that supports Save(), Fetch(), and Delete(), but for whatever reason, the underlying ORM doesn't support deleting. So I implement Delete() in such a way as to throw a NotImplemented exception. But obviously this has an affect on the semantics of the application. Could (or even should) the application simply accommodate the absence of deletion semantics? I should say not.
I don't see the SI pattern as anything but a convenience. It could lessen the impact of having to refactor the middle tier. Let's just say that it would be desirable to be able to write:
ICustomer customer;
instead of this:
XPObject customer;
You pointed out the NHibernate is lacking a number of features that are present in LLBLGEN. I see the SI pattern as a solution to that problem. The missing features could be layered on in a separate implementation, so that the UI would never know that the features were missing. A lot of work, to be sure, but less than refactoring the entire application, I think.
But I feel that you answered my question well. And, no, once I embrace LLBLGEN, I don't see myself switching. If any changes or additional features were desirable in LLBLGEN, I would simply encourage and prod until they were implemented. The only two instances where I think a switch may be warranted is if one finally decides that the whole philosophy of approach is incompatible with the architecture of the software, or if the customer requires a particular ORM due to existing circumstances. I'm facing the former with XPO.
Thanks.
Joined: 05-Aug-2008
We're pleased to hear that you're considering our work Could you also explain what made you consider a switch? (just so we learn more about our strong points from the point of view of (potential) customers )
I should say, first, that XPO is a wonderful product. It's a good place to start if you're completely uninitiated into the ORM space. I was up an running on XPO in under an hour. I had a fairly robust database in about 4 hours. At 6 hours, I could swap between Access and SQL Server at will. But after 6 months, and intense studying of Genome, NHibernate, and LLBLGEN, including using all of them in a small test application and listening to .NET Rocks, it became clear where some of the sticking points are with XPO.
Here's a list of the issues we're having with XPO:
- Unable to map more than one entity onto a table.
- Stateful, which is a security concern.
- Sessions are located inside the entity as opposed to existing apart from the entity (as in Genome).
- One is constantly trying to defend against session mismatches.
- An entity's PK, called the Oid, is set to -1 when creating a new entity. Multiple new entities of the same type will carry this same id, until saved. This can adversely affect certain logic in the UI.
- Unable to ask an XPObject this question: HasChanges().
- No distinction is made between Context and Unit of Work. One establishes "context" with a UOW.
- Supports only optimistic concurrency (no pessimistic concurrency support).
- XPObjects cannot be serialized.
- Relationships cannot be created dynamically, must be known at design time.
- Session can introduce multithreading/remoting issues.
- Toolset for working with existing databases is weak.
- Seems to be a bit chatty.
- Documentation is sparse. The last item is particularly troubling. XPO is a vast product and is in desperate need of a manual, a good old-fashioned linear manual.
One of the things that's attractive to me about LLBGEN (one of many), is that it puts me back in touch with my data.
Joined: 17-Aug-2003
Eric wrote:
I would happy to explain why we're considering the switch. I'll do that in a separate post. But first, I'll address the issue of the SI pattern.
There's a downside to this though: it's giving a false sense of decoupling.
From my understanding of the SI pattern, it addresses precisely the issue of different underlying implementations. I understand what you mean, though.
Suppose I have an interface that supports Save(), Fetch(), and Delete(), but for whatever reason, the underlying ORM doesn't support deleting. So I implement Delete() in such a way as to throw a NotImplemented exception. But obviously this has an affect on the semantics of the application. Could (or even should) the application simply accommodate the absence of deletion semantics? I should say not.
Agreed
I don't see the SI pattern as anything but a convenience. It could lessen the impact of having to refactor the middle tier. Let's just say that it would be desirable to be able to write:
ICustomer customer;
instead of this:
XPObject customer;
You pointed out the NHibernate is lacking a number of features that are present in LLBLGEN. I see the SI pattern as a solution to that problem. The missing features could be layered on in a separate implementation, so that the UI would never know that the features were missing. A lot of work, to be sure, but less than refactoring the entire application, I think.
Not necessarily. It's more like this: myOrder.Customer = myCustomer; now, in LLBLGen Pro, myOrder is automatically added to myCustomer.Orders, and myOrder.CustomerId is automatically synced with myCustomer.CustomerId.
If you do: myOrder.Customer = null; this is reversed: myOrder is removed from myCustomer.Orders, and the myOrder.CustomerId is reset to null.
In nhibernate this isn't the case, you've to do this yourself. Solving this by implementing an interface can be impossible due to the nature of the classes you're working with.
But I feel that you answered my question well. And, no, once I embrace LLBLGEN, I don't see myself switching. If any changes or additional features were desirable in LLBLGEN, I would simply encourage and prod until they were implemented. The only two instances where I think a switch may be warranted is if one finally decides that the whole philosophy of approach is incompatible with the architecture of the software, or if the customer requires a particular ORM due to existing circumstances. I'm facing the former with XPO. Thanks.
Switching persistence frameworks is a task which is very deep, even if you build the app using DDD with repositories and POCO classes: moving away from a poco framework which does entity graph management to a poco framework which doesn't (nhibernate), or vice versa, has a huge impact on the application while it's unexpected. It's similar to switching UI control vendor for grids, docking stuff etc. : it's very hard to make the switch though hardly anyone develops code to be able to switch UI control vendors easily, because.. why spend time on something which isn't expected to happen or when it happens, it will take a lot of time anyway?
Eric wrote:
We're pleased to hear that you're considering our work Could you also explain what made you consider a switch? (just so we learn more about our strong points from the point of view of (potential) customers )
I should say, first, that XPO is a wonderful product. It's a good place to start if you're completely uninitiated into the ORM space. I was up an running on XPO in under an hour. I had a fairly robust database in about 4 hours. At 6 hours, I could swap between Access and SQL Server at will.
I have always found that a bit of a story too good to be true, although access and sqlserver have a lot of types in common. I mean: unless there's a small set of types you can use among all databases, it's tough to swap between databases without making changes. Not that I don't believe you, I do, and I heard this story from other XPO users, though it can't be without a price: somewhere consessions had to be made to make this possible.
But after 6 months, and intense studying of Genome, NHibernate, and LLBLGEN, including using all of them in a small test application and listening to .NET Rocks, it became clear where some of the sticking points are with XPO.
Here's a list of the issues we're having with XPO:
- Unable to map more than one entity onto a table.
- Stateful, which is a security concern.
- Sessions are located inside the entity as opposed to existing apart from the entity (as in Genome).
- One is constantly trying to defend against session mismatches.
- An entity's PK, called the Oid, is set to -1 when creating a new entity. Multiple new entities of the same type will carry this same id, until saved. This can adversely affect certain logic in the UI.
- Unable to ask an XPObject this question: HasChanges().
- No distinction is made between Context and Unit of Work. One establishes "context" with a UOW.
- Supports only optimistic concurrency (no pessimistic concurrency support).
- XPObjects cannot be serialized.
- Relationships cannot be created dynamically, must be known at design time.
- Session can introduce multithreading/remoting issues.
- Toolset for working with existing databases is weak.
- Seems to be a bit chatty.
- Documentation is sparse. The last item is particularly troubling. XPO is a vast product and is in desperate need of a manual, a good old-fashioned linear manual.
Thanks for the list! . I'll comment on and have some questions regarding some things you mentioned above with respect to our framework, as I like clarity and honesty.
Stateful, which is a security concern.
With 'stateful', what exactly do you mean by that, as an entity object has state, namely the data of the entity instance (the tuple with the data) is inside the entity class instance (object== container) ?
Sessions are located inside the entity as opposed to existing apart from the entity (as in Genome).
With sessions you mean the centralized object like in nhibernate which performs the persistence logic etc. ? Entities in LLBLGen Pro contain their own change tracking, however don't contain references to a central session object.
An entity's PK, called the Oid, is set to -1 when creating a new entity. Multiple new entities of the same type will carry this same id, until saved. This can adversely affect certain logic in the UI.
With LLBLGen Pro you're free to pick whatever PK you'd like, even compound PK's. If you opt for an identity PK, or sequenced pk, the field in a new entity has the value of 0, or better: it has an undefined value. We also don't give it a sequenced in-memory value, as that could clash with entities created in other threads which still have the same value, or it could potentially clash with entities obtained from the db, or it could trigger validation (e.g. id > 0). Equality checks therefore take this into account: Equals with new entities will compare instances, Equals with existing entities will compare PKs.
Supports only optimistic concurrency (no pessimistic concurrency support).
Pessimistic concurrency with active locks set on the DB by the O/R mapper is rare among o/r mappers, because it's often leading to deadlocked applications as the locks have to be removed by the o/r mapper but this might fail for various reasons. LLBLGen Pro uses a flexible scheme for concurrency, where you can decide how to do concurrency checks, as you provide the filters. However, locks are set by the RDBMS through transactions, not actively set by the O/R mapper.
Documentation is sparse.
Yes, docs suck in general when it comes to O/R mappers, we spend a lot of time on it to write as much docs as possible, not only for how to use it, but also about the background of why things are the way they are.
DevExpress' docs in general aren't that great either, but this seems to be a common theme among control vendors (like: Janus' docs are non-existant). They use pretty pictures but the depth is limited.
XPO's linq provider is also very weak btw, but not a lot of people are using Linq at the moment so it's not noticed by many (yet)
One of the things that's attractive to me about LLBGEN (one of many), is that it puts me back in touch with my data.
The general goal of LLBLGen Pro is and always has been that it's a framework to work with your data in a flexible, easy but also non-limited way, with code which looks like you'd have written it yourself. I'm glad you experienced that from our work
Joined: 05-Aug-2008
Before I move on with my response, I'm sorry to say that I'm no longer a potential customer...I am a customer! I made the purchase the morning. Whew! When they said the dollar was weak against the Euro, I didn't think they meant LLBLGEN.
Switching persistence frameworks is a task which is very deep, even if you build the app using DDD with repositories and POCO classes.
Couldn't argue with that.
I have always found that a bit of a story too good to be true, although access and sqlserver have a lot of types in common.
You're right: it's too good to be completely true. But in my case, it was true.
...somewhere consessions had to be made to make this possible.
And there were concessions. LLBLGEN appears to embrace the uniqueness of each back-end database by conforming the interface to the particular feature set. XPO, on the other hand, normalizes the interface so that we wind up with the common denominator. I can tell you from personal experience that moving back and forth from Access to SQL Server was, indeed, painless. But that feature was never really a deal-maker for me. Normalizing the interface at a higher level (the ORM itself), on the other hand, is an intriguing problem to solve, even if only academically.
Responding to your responses to the list...
With 'stateful', what exactly do you mean by that, as an entity object has state, namely the data of the entity instance (the tuple with the data) is inside the entity class instance (object== container) ?
By 'stateful' I mean dependent upon a session that has associated with it a cache. In my software, as it stands now, I have to call DropCache() at particular points in the framework (which, in itself, is wrought with problems).
With sessions you mean the centralized object like in nhibernate which performs the persistence logic etc. ? Entities in LLBLGen Pro contain their own change tracking, however don't contain references to a central session object.
Yes, that's what I mean. Sessions come in three flavors in XPO: Session, UnitOfWork, and NestedUnitOfWork. A Session is unable to track its changes; UOWs and NUOWs, on the other hand, do. One of the problems I have with XPO is that can't ask the question: CustomerEntity.HasChanges(). I had to implement this myself using events.
Pessimistic concurrency with active locks set on the DB by the O/R mapper is rare among o/r mappers.
It would seem so, yes. Genome supports it. I take pessimistic locks only when the user, usually an administrator, has entered into an area of the software that truly needs to throw up barriers (e.g. security management, UI modification tools, etc.). Even then, there are usually some creative ways around pessimism, but sometimes not.
XPO's linq provider is also very weak btw
I didn't know that as I, too, am not yet using LINQ.
I look forward to learning and using LLBLGEN. I noticed that it just finished downloading, so I'm off...
Joined: 17-Aug-2003
Eric wrote:
Before I move on with my response, I'm sorry to say that I'm no longer a potential customer...I am a customer! I made the purchase the morning. Whew! When they said the dollar was weak against the Euro, I didn't think they meant LLBLGEN.
Yes, the euro - dollar rate is getting more and more skewed... Let's hope it gets more in balance soon...
With 'stateful', what exactly do you mean by that, as an entity object has state, namely the data of the entity instance (the tuple with the data) is inside the entity class instance (object== container) ?
By 'stateful' I mean dependent upon a session that has associated with it a cache. In my software, as it stands now, I have to call DropCache() at particular points in the framework (which, in itself, is wrought with problems).
whoa, that's not very clever from them indeed... having an entity tied to a context has advantages in some areas, but also big disadvantages...
Pessimistic concurrency with active locks set on the DB by the O/R mapper is rare among o/r mappers.
It would seem so, yes. Genome supports it.
They do? Hmm... Well I think it's a burden which can often go wrong so I wouldn't go that route...
Welcome 'aboard, Eric!