3-layer architecture - passing data between layers
Asked Answered
A

1

6

Trying to implement 3-layer (not: tier, I just want to separate my project logically, on one machine) architecture I've found so many different approaches that I'm confused, what's the best way (if there's any) to make that in WinForms app.

Now I have no doubts only about 3 layers that should be present in the project:

  • UI (Presentation Layer)
  • BLL (Business Logic Layer)
  • DAL (Data Acces Layer)

In UI I put all the WinForms. There must be also some logic to fill the object with data from controls and pass it to BLL layer.

In DAL I want to put classes and methods for data manipulations using ADO.NET, like:

public class OrderDAL
{
    public OrderDAL()
    {
    }

    public int Add(Order order)
    {
        //...add order to database
    }

    public int Update(Order order)
    {
        //...update order in database
    }

    //...etc.
}

The problem is with BLL and the question - should I use Data Transfer Objects to pass data between layers, or should I pass the whole Class?

If I choose to use DTO, then I've to create additional common class, Order, that reference to UI, BLL and DAL:

public class Order
{
    public int Id { get; set; }
    public DateTime Date { get; set; }
    public string Number { get; set; }
    public string CustomerName { get; set; }

    public Order ()
    {
    }
}

and put the logic separated into BLL:

public class OrderBLL
{
    public OrderBLL()
    {
    }

    public int Add(Order order)
    {
        OrderDAL orderDAL = new OrderDAL();
        return orderDAL.Add(order);
    }

    public int Update(Order order)
    {
        OrderDAL orderDAL = new OrderDAL();
        return orderDAL.Update(order);
    }

    //...etc.
}

This approach, under different names, is used among others: here or here.
On the other hand, some "wise guys" and their followers (like here) call it Anemic Domain Model and complain it's a bad design and anti-pattern that should not be used.

The pros:

  • DTO can easily by design to represent Database table,
  • it's light and clear, contains only fields needed for database,
  • DAL doesn't have to reference BLL,

The cons:

  • anti-pattern (sounds scary ;P),
  • violation of OOP (separated properties from methods),
  • because logic is in different class, it may be more difficult to maintain when something changes.

So, the opposite approach is to pass the whole object between layers, like here: no DTO, just BLL looking like that:

public class Order
{
    public int Id { get; set; }
    public DateTime Date { get; set; }
    public string Number { get; set; }
    public string CustomerName { get; set; }

    public Order()
    {
    }

    public int Add()
    {
        OrderDAL orderDAL = new OrderDAL();
        return orderDAL.Add(this);
    }

    public int Update(Order order)
    {
        OrderDAL orderDAL = new OrderDAL();
        return orderDAL.Update(order);
    }
}

The pros:

  • it's a nicely encapsulated object, following OOP rules (I suppose ;)).
  • both logic and properties are in one place, easier to maintain and debug.

The cons:

  • to use the object, DAL has to reference BLL (that's not how the 3-tier layer should do, isn't it?).
  • class may contain some fields that are not used in Database, as well as some fields from Database (like Id) do not represent "real life" object.

So, it looks like whatever I choose, I'll violate some rules. What's better way then, which should I choose? Maybe there is other approach I haven't found?

Acescent answered 29/6, 2012 at 9:54 Comment(1)
I would suggest you to look in to en.wikipedia.org/wiki/Domain-driven_designScott
K
8

I don't like DTOs, because they mean creating a dual hierarchy with little or no value.

I also don't like the idea of making model objects responsible for their own persistence. I prefer a separate persistence layer. Why? Model objects don't always need to be persisted to be useful. Business logic and functionality are orthogonal to persistence.

If you have two layers it's possible to keep a one way dependency graph: persistence knows about model, but model does not know about persistence. You end up with a cyclic dependency if model objects are responsible for persistence. You can never test or use model objects without persistence.

My advice? Don't do DTOs. Break out a separate persistence layer.

Kirkman answered 29/6, 2012 at 10:1 Comment(7)
so I don't understand - you prefer the first or second option as shown by OP?Wow
Ten years ago I recommended a separate data access layer that would return model objects, not DTOs. I don't understand why you're asking now.Kirkman
well I'm not OP - so I just found this thread which is new to me. whether it was started ten years ago isn't really the point. To my understanding model object is the same as a DTO - "Data Transfer Object". It doesn't have any functionality other than transferring data. So you say "model object" or "DTO" what is the difference between the two in your definition?Wow
You are correct - DTO is an ephemeral object whose only purpose is to shuttle data from one layer to another. It used to be a J2EE "best practice" because using EJB entity beans in UI layers was a bad idea. The "fix" was the load the data into dummy DTOs and let them carry the data, sans behavior, to the UI. A model object has become a POJO that has data and behavior but is free of all that EJB baggage. The more modern approach would use REST services that would serialize data as JSON or protobufs and let the user deserialize them as they wish.Kirkman
but I think OPs question was about between layers within and application - not between services (where JSON serialization would come into play). In that case you advised against DTO objects and to pass model objects (which has both data and behavior). But this is separate from an entity object which you might store in a database?Wow
Disagree. I am talking about layers in applications. If your React UI calls my REST service for data, I'm going to deserialize it to you as a JSON object. That's how it's done now. The J2EE standard and DTO design pattern both assumed that it was Java from front to back. The UI was a JSP (compiled to a servlet that generated HTML) and the back end was servlets and EJBs.Kirkman
You missed a key point: the difference between a POJO and an EJB. Go do some research if that's a new concept to you.Kirkman

© 2022 - 2024 — McMap. All rights reserved.