5

I ask this because it seems people usually consider the code that goes into a DAO or Repository implementation as "data access code", while the code that directly uses these DAOs/Repositories as "business logic code".

However, this doesn't seem to make logical sense.

Consider a business service method with code like the following (using Java, but it would be similar in C#, etc.):

public BigDecimal computeCustomerTotal(Customer customer) {
    List<Order> orders = orderRepository.findByCustomer(customer);

    BigDecimal total = orders.stream()
        .filter(Order::isActive).map(Order::getTotal).reduce(ZERO, BigDecimal::add);

    return total;
}

Sure, the above implementation doesn't make "proper" use of a database's capabilities, but bear with me. The point here is that, I assume, everyone agrees it contains only business logic code, with Customer and Order being domain entities (ie, they are not "data" objects).

So, what if I want to make it right, by moving the whole computation to the database, instead of executing in the client program? If I follow "conventional wisdom", I would create a new method in the repository:

public BigDecimal getCustomerTotal(Customer customer) {
    BigDecimal total = performQuery(
        "select sum(o.total) from Order o where o.customer = ?1 and o.active",
        customer);

    return total;
}

(Assume performQuery is a JPA-based utility method which takes a JPA-QL sentence with optional arguments.)

The second implementation is obviously better than the first, as it probably performs better, and makes proper use of the underlying technologies (JPA/Hibernate, and a relational database).

The problem, though, is that business logic (the rule that only active orders should be considered) has been moved from a business service method to a (supposed) data access method, through a simple implementation change. Also, this code which is now in the DAO/Repository does not actually know about data access concerns, such as the mapping from entity types and attributes to tables and columns, or about the actual SQL code that gets generated and sent to the DB engine.

Wouldn't it be more logical to regard both methods as containing only business logic code, and just get rid of the DAO/Repository/DAL altogether?

Personally, I don't see any data access code there, and to me things like DAOs, Repositories, or "data access layers" (DAL) are in reality anti-patterns. Note that even when using JDBC + SQL in a DAO/Repository implementation, it will inevitably contain business logic, typically in the form of "where" clauses.

4

The database layer is intended to isolate the rest of the application from the details of the database -- how to make a connection, the syntax used to talk to the db engine, etc.

The .Net Entity Framework version of your code would be:

var id = customer.id;
var customerOrdersTotal = db.Orders.
                          Where(o => o.CustomerId == id && o.Active).
                          Sum(o => o.Total);

Note that this would get translated into the sql your JPA version would use, but the exact same thing could be done without involving sql at all.

If you have a Customer that has Orders, then it would be:

var customerOrdersTotal = customer.Orders.
                          Where(o => o.Active).Sum(o => o.Total);

And this version could be written regardless of whether Orders is a virtual list or an actual list of orders.

The business doesn't care where the data is kept or how it is retrieved. The point of a DAL is to abstract away the "how is this bit of data retrieved" and turn it into just the necessary (i.e. unavoidable) "how to request the data I want". Without a DAL you have to mix the two functions together, which means you can't change one without changing the other.

Note that about half the time, you don't ever end up making any changes...but when you do it's a real pain if they are mixed together.

Edit: I'll add that your implication that "where" clauses in the data access code is a business concern is incorrect. The data layer exists to serve business needs. The data can be carved up and served in an infinite number of ways, some more useful than others. Moving a condition from the business layer to the data layer simply means that the request is common enough to be included in the ways that are usefully provided out of the box. Preventing new orders when existing active orders exceeds $X is a business decision.

  • I did not write any SQL; that was JPA-QL, an object-oriented query language with syntax similar to SQL, but simpler and operating on entities, not on tables. Also, your C# lambda-based expression can be written in Java as well, provided we use Java 8 (not sure about the SQL generation, though, but that was not the point). Anyway, are you saying that these two C# queries are data access code, or business logic code? To me, it is business logic code because it deals with domain entity types, not with database-specific artifacts (tables, columns, etc.). – Rogério Jul 4 '15 at 0:52
  • What exactly is the DAL here? – Rogério Jul 4 '15 at 1:28
  • 1
    @Rogério: in my example it is the dbcontext for the linq to sql (aka db). Basically the DAL is outsourced to an ORM. – jmoreno Jul 4 '15 at 5:49
  • Ah, I see. So, in Java, I would say the DAL is the JPA implementation. The problem with this, though, is that when we talk about "layers" we normally mean parts of the application codebase, not code inside third-party libraries such as the ORM implementation. So, I wouldn't call it a layer at all. – Rogério Jul 4 '15 at 14:36
  • 1
    @Rogério: I didn't say write an ORM. But another way of putting it is that an ORM is a type or part of a DAL. nhibernate.info/blog/2008/08/31/…. It can either be the whole DAL or a part of the DAL depending on your needs. – jmoreno Jul 4 '15 at 16:27
1

What is business logic code and what is data access code, and what's the difference?

There is a short answer to that:

a) Code, that is used to open a connection to a DB, to retrieve data, do OR-mapping etc. is called data access code

 static public int AddProductCategory(string newName, string connString)
 {
     Int32 newProdID = 0;
     string sql =
         "INSERT INTO Production.ProductCategory (Name) VALUES (@Name); "
         + "SELECT CAST(scope_identity() AS int)";
     using (SqlConnection conn = new SqlConnection(connString))
     {
         SqlCommand cmd = new SqlCommand(sql, conn);
         cmd.Parameters.Add("@Name", SqlDbType.VarChar);
         cmd.Parameters["@name"].Value = newName;
         try
         {
             conn.Open();
             newProdID = (Int32)cmd.ExecuteScalar();
         }
         catch (Exception ex)
         {
             Console.WriteLine(ex.Message);
         }
     }
     return (int)newProdID;
 }

Example taken from MSDN

b) Code, that is used transform this data or conataining the rules, when to retrieve this data is called business logic

Both are different responsibilities and are usually implemented in different layers of your application:

a) In a layer sometimes called service-layer sits the logic, when to retrieve what kind of data and how this data is treated aka business logic

b) In case you are implementing the Repository Pattern: this is the place where the data acces code lives.

The point here is that, I assume, everyone agrees it contains only business logic code, with Customer and Order being domain entities (ie, they are not "data" objects).

No. It is data access code, it retrieves data in a way which is relevant for the business logic.

Wouldn't it be more logical to regard both methods as containing only business logic code, and just get rid of the DAO/Repository/DAL altogether?

Neither of the methods contain any business logic. It is really only access code. The reason why you filter the data like you do is lead by business concerns, but that doesn't make them itself business logic.

Personally, I don't see any data access code there, and to me things like DAOs, Repositories, or "data access layers" (DAL) are in reality anti-patterns. Note that even when using JDBC + SQL in a DAO/Repository implementation, it will inevitably contain business logic, typically in the form of "where" clauses.

Maybe you should think about your definition of business logic. These patterns are not in any way anti-patterns, these patterns allow clear separation of concerns.

  • Ok, you say that the methods I wrote in the question are "data access code". But you yourself described it as code to: a.1) "open a connection to a DB", a.2) "retrieve data [from the DB]", or "do OR-mapping". However, both methods do none of these things! DB connections, OR-mapping, and the actual data retrieval is handled by the JPA (ORM) implementation (a 3rd-party library) - there is OR-mapping metadata in entities, of course, but that's separate. The ORM implementation does all the SQL generation and executes all the JDBC code that actually communicates with the DB server. – Rogério Jul 4 '15 at 14:49
  • Now for the "business logic code". You say it is responsible for things like b.1) "transform data", b.2) "contain the [business] rules", b.3) "[decide] when to retrieve data". And I agree with that; this is what business code is about. Just note that both my example methods do precisely these things: b.1) they add values to produce a total (a form of data transformation), b.2) they contain the business rule that only active Orders should be considered, and b.3) they know that customer order data needs to be fetched from persistent state for it to be filtered and summed up. – Rogério Jul 4 '15 at 15:00
  • In your example the boilerplate part is obfuscated. You are using the repository pattern to actually retrieve the data. The fact, that you apply additional filtering is in your case neglectable. You only retrieve data. The reason why you retrieve only active order is a business rule. The filtering either via db or javaside is only an implementation detail,but is as such no logic. – Thomas Junk Jul 4 '15 at 16:40
  • There is no boilerplate code in my example. If retrieving only active orders is a business rule, as we both agree, and since both of my methods implement it, why shouldn't they both be considered as businnes logic methods? – Rogério Jul 6 '15 at 15:48
  • As I said, the boilerplate-part is obfuscated: orderRepository.findByCustomer(customer); does the boilerplate part in the background. »why shouldn't they both be considered as businnes logic methods« because they are only written do get data. The purpose is part of the business logic. – Thomas Junk Jul 6 '15 at 16:12
0

It seems to me that you're just missing a class definition.
Declare a class CustomerOrders with GetOrdersTotal method.
It's a pure business object. There no such table in the db. It wraps an Order DAO and applies business rules on on it (active order, filter by customer id).
So, OrderRepository is your DAL and CustomerOrders is your BL

  • Sure, we could call the class containing the computeCustomerTotal method as CustomerOrders. But why have a DAO, given that getCustomerTotal is all we need to perform the business operation, and it only contains business logic code, not knowing about persistence details? – Rogério Jul 6 '15 at 15:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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