For my application, I am looking at using an ORM and currently trying to decide if the domain layer should interface with it through a Data Access Object, Repositories, or something else? I am hesitant to pair an ORM with repositories because they can become redundant if the ORM entities are identical with the domain objects, but having one big DAO seems cludgy. I want to keep my SQL centralized, but I can't figure which of these options, if any, would make the most sense. Any suggestions on an appropriate design pattern?
This is very opinion-based, but I tend toward creating separate entities from my domain models. The domain model needs to closely match your domain, whereas your entities need to closely model your storage. They may initially match very closely, and seem really redundant, but they very often drift dramatically from each other very quickly.
That being said, wrappers that do nothing but map domain entities to persistence entities often feels horrible, and a giant waste of time. Additionally, it doesn't pay off until much later in the game, when you are doing refactoring, and you realize that your domain isn't quite right, but you don't want to modify your persistence layer.
The good news is, most languages/frameworks have some form of a mapping library that will let you automatically map from one object to another that is similarly structured. This is a great way to speed this up initially, while still giving yourself flexibility to create a manual mapping when the requirements change out from under you.
Related
I run across Orika recently.
And I couldn't find a good explanation of why I should use it. If I have, say, a User domain object, why not use that? Why do I need to create a UserDTO with more or less the same members.
Of course there are times when I need to hide some fields. But that doesn't explain the need to have dozens of libraries.
Can someone explain to me why I should not re-use domain objects from one architectural boundary to another? Saying boundary to include layers or micro-service interfaces or anything similar.
It all depends! Good designpatterns for big systems are often overkill for smaller ones. Is the data you are getting really the same as your logical intuitive domain objects or are there extra data there.
Do you find yourself in the situation described in the answer to this post, then DTO it up. DTO's exist to limit the amount of expensive network operations by transmitting more data in each request. Say you have 'User' and 'AddressDetail' domain objects, and that you could get the data for both these objects in a single call(and the data is useful in the same area of the application) then you'd use a dto and send all the data at once.
It can be hard predicting how your system will grow(especially if you are working against a living API which someone else controls), and data transfer object on some level provides a clear separation of responsibility which is often a good thing.
I'd say reuse domain objects with caution in large systems.
I read a debate in the comments here (current live site, without comments).
Why the debate? A Dataset for me is like a relational database, an Object is a hierarchical-like model. Why do people absolutely want a "pure" Object model, whereas we still deal with relational databases, so why not combine the two?
And if we should, is there any lightweight, comprehensive framework that allows us to do that (not a heavy mammoth, like NHibernate, which has a huge learning curve)?
"Pure objects" are a lot easier to work with, the typed object gives you intellisense and compile-time type checking.
Bare datasets are very cumbersome and annoying to work with - you need to know the column names, there's no type checking possible, so if you mistype a column name, you're out of luck and won't discover the error until runtime (the worst possible scenario).
Typed datasets are a step in the right direction, but the "things" you work with in your .NET code are still tied very closely and tightly to your database implementation - not typically a good thing, since any change in the underlying database might affect your app all the way up to your UI and cause a lot of changes being necessary.
Using an ORM like NHibernate allows you to better abstract and decouple the database (physical storage) layer from your logical business model - only in the simplest of scenarios will those two be an exact 1:1 match, so you'll need some kind of "translation" or mapping between the two anyway.
So all in all - using typed datasets might be okay for small, simple apps, but for a challenging, larger-scale, enterprise-level business app, I would never recommend coupling your business object model so closely and tightly to the database.
Marc
why do people absolutly want "pure" Object model
Because you don't want your application to depend on the database schema
Well, all the reasons you give were the same as the academical reasons that were given for EJB in Java which was a mess in the past. So arent't people falling into another fashionable hype ?
As I read here:
http://blogs.tedneward.com/2006/06/26/The+Vietnam+Of+Computer+Science.aspx
the promise is one thing, the reality is other thing.
Where is the proof upon the claims ?
Scientifically, Complexity is tight to the Concept of Entropy, you cannot reduce the inherent complexity of things, you can just move it somewhere else, so for me there is something fundamentally irational.
Ted Newards is highly controversial because it seems to me that everybody is herding like in the old EJB days: nobody dared to say EJB suck until Rod Johnson gets out with Hibernate.
Now it seems nobody cares to say ORM frameworks like Hibernate, Entity Framework, etc. are too complex, because there isn't yet another Rod Johnson II maybe :)
You pretend that adding a new layer solves the problem, it's not always the case even theorcially, like adding more team members when a project becomes a mess because adding more programmers also mean add to coordination and communication problem.
And in practice, what it seems, is that the layers that should be independant at least from the GUI viewpoint, aren't really. I see many people struggle to do simple stuff in the GUI when they use an ORM.
I'm exposing some CRUD methods through WCF service, for some data objects persisted in a database through NHibernate. Is it a good approach to use NHibernate classes as data contracts, or is it better to wrap them or replace them with some other data contracts? What is your approach?
Our team just went through a good few months debating this design point, so I've got a lot of links to share ;-)
Short answer: You "should" translate from your NHibernate classes into a domain model.
Long answer: I think the answer to this is a matter of principle. If you ever want to be interoperable, you should not use Datasets as your DTOs (I love Hanselman's post on this). I'm not saying that it's never a good idea; clearly people have had success doing so. Just know that you are cutting corners and it's a risky proposition.
If you have complete control over the classes you are pushing the data into, you could build a nice domain model and just map the NHibernate data into those classes. You will more than likely have serious issues doing that, as IList<> (which a <bag> maps to) is not serializeable. You'd have to write your own serializer, or use something like NetDataContractSerializer, but you lose interoperability.
You will need to measure the amount of work involved in building some wrapper classes, and the translation between, but then you have complete flexibility in what your domain model will look like. Then, you're able to do things (as we have done) like code generation for your NHibernate maps and objects. Then, your data contracts serve as an abstraction from your data, as they should.
P.S. You might want to take a look at ADO.NET Data Services, which is a RESTful way to expose your data, which, at this point, seems to be the most interoperable choice to expose your data.
You would not want to expose your domain model directly, but map the domain to some kind of message as it hits the process boundary. You could leverage NHibernate to do the mapping work for you. In this case you would have 2 mappings, one for you domain model and another for your lightweight messages.
I don't have direct experience in doing this, but I have sent Datasets across via WCF before and that works just fine. I think your biggest issue in using NHibernete as data objects over WCF will be a lack of interoperability (as is also the case when using Datasets). Not only does the client have to use .NET, the client must also use NHibernate. This goes against SOA principles, but if you know for sure that you won't be reusing this component then there's not a great reason not to.
It's at least worth a try.
I'm a student currently dabbling in a .Net n-tier app that uses Nhibernate+WCF+WPF.
One of the things that is done quite terribly is object graph serialisation, In fact it isn't done at all, currently associations are ignored and we are using DTOs everywhere.
As far as I can tell one method to proceed is to predefine which objects and collections should be loaded and serialised to go across the wire, thus being able to present some associations to the client, however this seems limited, inflexible and inconsistent (can you tell that I don't like this idea).
One option that occurred to me was to simply replace the NHProxies that lazy load collection on the client tier with a "disconnectedProxy" that would retrieve the associated stuff over the wire. This would mean that we'd have to expand our web service signature a little and do some hackery on our generated proxies but this seemed like a good T4/other code gen experiment.
As far as I can tell this seems to be a common stumbling block but after doing a lot of reading I haven't been able to figure out any good/generally accepted solutions. I'm looking for a bit of direction as much as any particular solution, but if there is an easy way to make the client "feel" connected please let me know.
You ask a very good question that unfortunately does not have a very clean answer. Even if you were able to get lazy loading to work over WCF (which we were able to do) you still would have issues using the proxy interceptor. Trust me on this one, you want POCO objects on the client tier!
What you really need to consider...what has been conceived as the industry standard approach to this problem from the research I have seen, is called persistence vs. usage or persistence ignorance. In other words, your object model and mappings represent your persistence domain but it does not match your ideal usage scenarios. You don't want to bring the whole database down to the client just to display a couple properties right??
It seems like such a simple problem but the solution is either very simple, or very complex. On one hand you can design your entities around your usage scenarios but then you end up with proliferation of your object domain making it difficult to maintain. On the other, you still want the rich object model relationships in order to write granular business logic.
To simplify this problem let’s examine the two main gaps we need to fill…between the database and the database/service layer and the service to client gap. NHibernate fills the first one just fine by providing an ORM to load data into your objects. It does a decent job, but in order to achieve great performance it needs to be tweaked using custom loading strategies. I digress…
The second gap, between the server and client, is where things get dicey. To simplify, imagine if you did not send any mapped entities over the wire to the client? Try creating a mechanism that exchanges business entities into DTO objects and likewise DTO objects into business entities. That way your client deals with only DTOs (POCO of course), and your business logic can maintain its rich structure. This allows you to leverage not only NHibernate’s lazy loading mechanism, but other benefits from the session such as L1 cache.
For brevity and intellectual property reasons I will not go into the design of said mechanism, but hopefully this is enough information to point you in the right direction. If you don’t care about performance or latency at all…just turn lazy loading off all together and work through the serialization issues.
It has been a while for me but the injection/disconnected proxies may not be as bad as it sounds. Since you are a student I am going to assume you have some time and want to muck around a bit.
If you want to inject your own custom serialization/deserialization logic you can use IDataContractSurrogate which can be applied using DataContractSerializerOperationBehavior. I have only done a few basic things with this but it may be worth looking into. By adding some fun logic (read: potentially hackish) at this layer you might be able to make it more connected.
Here is an MSDN post about someone who came to the same realization, DynamicProxy used by NHibernate makes it not possible to directly serialize NHibernate objects doing lazy loading.
If you are really determined to transport the object graph across the network and preserve lazy loading functionality. Take a look at some code I produced over here http://slagd.com/?page_id=6 . Basically it creates a fake session on the other side of the wire and allows the nhibernate proxies to retain their functionality. Not saying it's the right way to do things, but it might give you some ideas.
I look around and see some great snippets of code for defining rules, validation, business objects (entities) and the like, but I have to admit to having never seen a great and well-written business layer in its entirety.
I'm left knowing what I don't like, but not knowing what a great one is.
Can anyone point out some good OO business layers (or great business objects) or let me know how they judge a business layer and what makes one great?
Thanks
I’ve never encountered a well written business layer.
Here is Alex Papadimoulis's take on this:
[...] If you think about it, virtually every line of code in a software
application is business logic:
The Customers database table, with
its CustomerNumber (CHAR-13),
ApprovedDate (DATETIME), and
SalesRepName (VARCHAR-35) columns:
business logic. If it wasn’t, it’d
just be Table032 with Column01,
Column02, and Column03.
The
subroutine that extends a ten-percent
discount to first time customers:
definitely business logic. And
hopefully, not soft-coded.
And
the code that highlights past-due
invoices in red: that’s business
logic, too. Internet Explorer
certainly doesn’t look for the strings
“unpaid” and “30+ days” and go, hey,
that sure would look good with a #990000 background!
So how then is possible to encapsulate all of this business logic
in a single layer of code? With
terrible architecture and bad code of
course!
[...] By implying that a system’s architecture should include a layer dedicated to business logic, many developers employ all sorts of horribly clever techniques to achieve that goal. And it always ends up in a disaster.
I imagine this is because business logic, as a general rule, is arbitrary and nasty. Garbage in, garbage out.
Also, most of the really good business layers are most probably proprietary. ;-)
Good business layers have been designed after a thorough domain analysis. If you can capture the business' semantics and isolate it from any kind of implementation, whether that be in data storage or any specific application (including presentation), then the logic should be well-factored and reusable in different contexts.
Just as a good database schema design should capture business semantics and isolate itself from any application, a business layer should do the same and even if a database schema and a business layer describe the same entities and concepts, the two should be usable in separate contexts--a database schema shouldn't have to change even when the business logic changes unless the schema doesn't reflect the current business. A business layer should work with any storage schema provided that it's abstracted via an intermdiate layer. For example, the ADO.NET Entity framework lets you design a conceptual schema which maps to the business layer and has a separate mapping to the storage schema which can be changed without recompiling the business object layer or conceptual layer.
If a person from the business side of things can look at code written with the business layer and have a rough idea of what's going on then it might be a good indication that the objects were designed right--you've succesfully conveyed a solution in the problem domain without obfuscating it with artifacts from the solution domain.
I've always been stuck between a rock and a hard place. Ideally, your business logic wouldn't be at all concerned with database or UI-related issues.
Keys Cause Problems
Still, I find things like primary and foreign keys causing problems. Even tools like Entity Framework don't completely eliminate this creep. It can be extremely inefficient to convert IDs passed as POST data into their respective objects, only to pass this to the business layer, which then passes them to the data layer to just be stripped down again.
Even NoSQL databases come with problems. They tend to return full object models, but they usually return more than you need and can lead to problems because you're assuming that object model won't change. And keys are still found in NoSQL databases.
Reuse vs. Overhead
There's also the issue of code reuse. It's pretty common for data layers to return fully populated objects, including every column in that particular table or tables. However, often business logic only cares about a limited subset of this information. It lends itself to specialized data transfer objects that only carry with them the relavent data. Of course, you need to convert between representations, so you create a mapper class. Then, when you save, you need to somehow convert these lesser objects back into the full database representation or do a partial UPDATE (meaning a another SQL command).
So, I see a lot of business layer classes accepting objects mapping directly to database tables (data transfer objects). I also see a lot of business layers accepting raw UI values (presentation objects), as well. It's also not unusual to see business layers calling out to the database mid-computation to retrieve needed data. To try to grab it up-front would probably be inefficient (think about how and if-statement can affect the data that gets retrieved) and lazy loaded values result in a lot of magic or unintended calls out to the database.
Write Your Logic First
Recently, I've been trying to write the "core" code first. This is the code that performs the actual business logic. I don't know about you, but many times when going over someone else's code, I ask the question, "But, where does it do [business rule]?" Often, the business logic is so crowded with concerns about grabbing data, transforming it and whatnot that I can't even see it (needle in a hay stack). So, now I implement the logic first and as I figure out what data I need, I add it as a parameter or add it to a parameter object. Getting the rest of the code to fit this new interface usually falls on a mediator class of some kind.
Like I said, though, you have to keep a lot in mind when writing business layers, including performance. The approach above has been useful lately because I don't have rights to version control or the database schema yet. I am working in a dark room with just my understanding of the requirements so far.
Write with Testing in Mind
Utiltizing dependency injection can be useful for designing a good architecture up-front. Try to think about how you would test your code without hitting a database or other service. This also lends itself to small, reusable classes that can run in multiple contexts.
Conclusion
My conclusion is that there really is no such thing as a perfect business layer. Even in the same application, there can be times when one approach only works 90% of the time. The best we can do is try to write the simplest thing that works. For the longest time I avoided DTOs and wrapped ADO.NET DataRows with objects so updates were immediately recorded in the underlying DataTable. This was a HUGE mistake because I couldn't copy objects and constraints caused exceptions to be thrown at weird times. I only did it to avoid setting parameter values explicitly.
Martin Fowler has blogged extensively about DSLs. I would recommend starting there.
http://martinfowler.com/bliki/dsl.html
It was helpful to me to learn and play with CSLA.Net (if you are a MS guy). I've never implemented a "pure" CSLA application, but have used many of the ideas presented in the architecture.
Your best bet is keep looking for that elusive magic bullet and use the ideas that best fit the problem you are solving. Keep it simple.
One problem I find is that even when you have a nicely designed business layer it is hard to stop business logic leaking out, and development tools tend to encourage this. For example as soon as you add a validator control to an ASP.NET WebForm you have let business logic leak out into the view. The validation should occur in the business layer and only the results of it displayed in the view. And as soon as you add constraints to a database you then have business logic in your database as well. DBA types tend to disagree strongly with this last point though.
Neither have I. We don't create a business layer in our applications. Instead we use MVC-ARS. The business logic is embedded in the (S) state machine and the (A) action.
Possibly because in reality we are never able to fully decouple the business logic from the "process", the inputs, outputs, interface and that ultimately people find it hard to deal with the abstract let alone relating it back to reality.