Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I am building an architecture like this: These are my SW layers

 ______________
|              |
|    Views     |
|______________|

 ______________
|              |
|Business Logic|
|______________|

 ______________
|              |
|  Repository  |
|______________|

My views are going to generate my HTML to be sent to the user Business logic is where all the business logics are Repository is a layer to access the DB

My idea is that the repository uses entities (that are basically the representation of the tables, in order to perform DB queries.

The layers communicate between themselves using Business Objects, that are objects that represent the real-world-object itself. They can contain business rules and methods.

The views build/use DTOs, they are basically objects that have the information required to be shown on the screen. They expect also this kind of object on actions and, before calling the business logic, they create BO.

First question: what is your overall feeling about this architecture?

I've used similar architecture for some projects and I always got this problem: If my view has this list to show :

Student1, age, course, Date Enrolled, Already paid?

It has information from different BO. How do you think one should build the structure?

These were the alternatives I could think of:

  • The view layer could call the methods to get the student, then the course it studies, then the payment information. This would cause a lot of DB accesses and my view would have the knowledge about how to act to generate this information. This just seems wrong for me.
  • I could have an "adapter object", that has the required information (a class that would have a properties Student, Course and Payment). But I would required one adapter object for each similar case, this may get very bad for big projects.

I still don't like them. Would you have ideas? How would you change the architecture to avoid this kind of problems?

@Rory: I read the CQRS and I don't think this suits my needs. As taken from a link references in your link

Before describing the details of CQRS we need to understand the two main driving forces behind it: collaboration and staleness

That means: many different actors using the same object (collaboration) and once data has been shown to a user, that same data may have been changed by another actor – it is stale (staleness).

My problem is that I want to show to the user information from different BO, so I would need to receive them from the service layer. How can my service layer assemble and deliver this information?

Edit to @AndrewM: Yes, you understood it correctly, the original idea was to have the view layer to build the BOs, but you have a very nice point about the creation of the BO inside the business layers. Assuming I follow your advice and move the creation logic inside the business layer, my business layer interface would contain the DTOs, for instance

public void foo(MyDTO object)

But as far as I understand, the DTO is tightly coupled to each view, so it would not be reusable by a second view. In order to use it, the second view would need to build a specific DTO from a specific view or I would have to duplicate the code in the business layer. Is this correct or am I missing something?

share|improve this question

3 Answers 3

up vote 7 down vote accepted
+100

Object-relational mappers like NHibernate want you to do all of your data processing using business objects. However, as you've recognised, pulling a whole aggregate out of the repository is a costly operation when all you want is one aspect of it. Why rehydrate a whole Customer, including all of their Orders and so on - potentially joining across a number of tables - when all you need to display on-screen is a FirstName? The problem balloons when you need a little information from a lot of aggregates.

The solution is Command/Query Responsibility Segregation. (I believe the idea is due to Greg Young.) An individual view needs a very specific set of information which an ORM may struggle to provide efficiently. So why not write view-specific queries which bypass the ORM, using a language which is designed for expressive, efficient querying? (You could use straight SQL, stored procedures, LINQ-to-SQL, HQL, or some other declarative language.) This way, you can optimise your queries to the nines when necessary - after all, reading data is far more common than writing data.

In a CQRS architecture, the domain model (and NHibernate) only exists to facilitate writing. Its entire job is to protect your business invariants and keep the database in a consistent state. Reading from the database is handled in a completely separate part of your application, known as the Thin Read Layer, which doesn't use the domain model at all.

Typically, in your thin read layer, you'll have one specialised query per view. This may seem wasteful but as Kent Beck and Martin Fowler say, "We think reuse is overrated (we just use)." The thin read layer is thin - it just pulls a specific set of data out of the DB as fast as it can. So queries are easy to write, which in turn makes them cheap to throw away when the view changes.


When you get serious about optimising your application for reading, you may realise your database schema is holding you back and you need to perform some denormalisation. However, denormalisation can have the effect of making writes to the database unfeasibly complex, making your domain model slow and harder to maintain. So, some people move their entire query side out to a separate database! This could take the form of a SQL database which has been optimised for reading, but you don't have to use SQL - your views might be most efficient with something like Mongo or Lucene.

In this type of system, the thin read layer has to watch for changes in the domain model. Typically, this is implemented using an asynchronous publish/subscribe pattern - the domain model raises events to which the read-side subscribes in order to update its cache. You should set up the message broker to record your events, so you can always reconstruct your projections in case something goes wrong or you need to spin up a new instance.

This architecture is easy to distribute, when the time comes to scale up your app. You'd set up one write-side database (with a domain model) to be the 'source of truth', and lots of thin read layers sitting on top of caches all around the world.

share|improve this answer
    
There's a lot more to say on the topic, such as how this architecture naturally leads to event sourcing. Hopefully I've been able to whet your appetite and given you enough pointers to learn more. –  Benjamin Hodgson Mar 5 at 22:02
    
Hey! thanks for the answer. I will read it during the day and get back to you! Tks! One last question (I'm still reading you answer, so sorry if you already answered): Would you agree with w/ @AndrewM when he says that BO should be created on the view layer? If so, how would you solve the issue that my business layer be coupled with my DTO's and, therefore, to my view layer, since DTO's represent the set of information required for a specific view? –  Oscar Mar 6 at 14:01
    
"Creation" is an overloaded term: do you mean newing-up an object in memory, or the start of an Entity's lifecycle? It should be evident that the latter is a business process that belongs in the business layer (think "new user signed up"), and is typically implemented using a Factory. By comparison, new may appear in a Factory, or it may appear when loading from a Repository. Either way, your view shouldn't directly handle the business objects; you should be able to refactor your domain freely. Keep them separate using Application Services (or their more sophisticated cousins, Commands). –  Benjamin Hodgson Mar 6 at 15:18
    
Links for the jargon in my comment above (there wasn't room to put them directly in the prose): Entity, Factory, Repository, Command. I learned all this from the book Domain Driven Design by Evans, I highly recommend it ;) –  Benjamin Hodgson Mar 6 at 15:23
    
wow, while I know some of the concepts you talked about, there is a lot to read, so it will take a while, so one last question before I accept this answer (the points in this question will be the best points ever spent here :) ): I would receive the DTOs in my BL. So if I have a method foo() called by 2 views, I will have foo(DTOView1) and foo(DTOview2), each would instantiate a new BO object and populate it and then call the "real" foo(). Correct? This would cause my BL to have many foo's, is this correct? –  Oscar Mar 6 at 15:52

You may want to look at the Command Query Responsibility Segregation pattern. Essentially, you introduce new models to match how the system is used. You might have e.g. an enrolment reporting model to handle your query, while using Student, Course etc. models for your basic CRUD operations.

share|improve this answer
    
That looks interesting, I will take a look tonight and get back to you ASAP :D –  Oscar Feb 27 at 18:19
    
This pattern deals with the idea of collaboration and staleness. (Please see the edit). When you say to create a new model, you have the same idea of my adapter object. The problem is that this would be a "disguised DTO", it would be attached to the VIEW needs and I could require many different combinations of informations, causing my system to have many different objects, one for each request. –  Oscar Feb 28 at 15:10
    
@Oscar That's right. In a CQRS architecture, your queries will generally be specialised for the needs of the view. It's OK because the thin read layer is dumb, and segregated from the business logic. See my answer for a more detailed discussion of this issue. –  Benjamin Hodgson Mar 5 at 22:45

I'm not sure I follow completely, let me see if I have this right.

The View Layer has components that generate DTOs for the UI, but generate BO's to call components in the business layer. The components in the business layer then hand these to components in the repository layer for storage/retrieval.

If this is the case, then I'm not really sure the point of the business layer. It is hard to tell its responsibilities from the description. If the components n the view layer are the ones creating BO's then it has fairly intricate knowledge of those.

You might want to put all BO constructions and management into components in the business layer. It seems that the business layer should be the adapter. (This is usually what business logic is for.) I would expect that components in the business layer would consume requests for data from view components (e.g. get me info from student foo) and create complete objects (student, age, course, etc.) by assembling the data from the components in the repository layer. I would expect the type (and qualities) of objects that flow between the different layers to be different in this case.

Can you explain a little more about what you are sending between the components?

share|improve this answer
    
I've edited the question with a reply for you. :) –  Oscar Mar 5 at 16:36

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.