3

At work, a 3-layer-architecture is the go to whenever a web application is needed.

I don't mind this, but many of the applications we start, do not seem to have an initial need for this. These applications are pretty much just a user interface to the database. This results in a ton of business logic that just sends the data from the data layer to the presentation layer.


I have come up with an alternative, however I have not tried it yet.

Normal 3-Layer-Architecture: (Arrows denote dependency) Normal 3-layer-architecture

Updated design: enter image description here

Instead I can do this, allowing me to keep a layer of indirection, but by having it be only interfaces, the implementation cost (and chance of error) is lowered.

Updated design, when business becomes relevant at a later stage:enter image description here

This would look similar to this:

public class BusinessClass : IDataAccessInterface<string>
{
    public BusinessClass(IDataAccessInterface<string> dataRepository)
    {
        this.dataRepository = dataRepository;
    }

    public string Read()
    {
        var something = dataRepository.Read();
        //Do something with something
        return something;
    }
}

And my DI would simply inject an implementation from the DataAccess implementation into my business class, and my business class into my presentation, which was already using the same interface.

My question is:

  • Are there drawbacks I am blind to?
  • Do you use this approach (is it well spread)?
  • Any other arguments I might bring with me to work?
  • 1
    You must work where I work... I think the best solution here is to remove what you don't need. You don't necessarily need a BLL or a DAL at all (as you say). And even if you want to keep those you don't need interfaces if there are not multiple implementation (90% of the cases). Rip stuff out.; I don't understand about your updated design how it is possible that DAL implementations and "Business" expose the same interface?! Usually, the BLL has a significantly different interface being at a higher level (that's the point). DAL and "Business" are not special, you can have any number of layers. – usr Jul 3 '17 at 15:55
  • 1
    Including 1 and including more than 3. Each layer's purpose is to abstract something away. This means that the interface usually changes.; Often, people think they need to abstract stuff away when they don't (e.g. the idea of replacing the ORM through inheritance). – usr Jul 3 '17 at 15:56
  • "do not have an initial need for this" - so you don't have to dig yourself out a hole later. – frattaro Aug 1 '17 at 4:37
4

It looks like your design is biased by your experience of Applications which have no functionality other than reading from/updating a database.

Normally you would not expect the business logic layer's exposed method to mirror the Data Access Layer.

To take your Read() example, I would expect the Business logic to expose say, Read(string userId) and have some logic checking filtering the DAL read results to only return those which apply to the user.

An Update() call on the DAL would never be directly called by the UI, instead we would expect something like Purchase() or Calculate() which after business rules had been applied might result in a number of Update() calls to the DAL layer.

Obviously if the client has full access to call update in anyway they please they could bypass business rules such as having to pay for your purchases!!

I can see how having the Business layer mirror the DAL might help, for those applications where you are simply prototyping and just want to expose a CRUD interface so your UI can work with sample data and the user can click through a process and see state persisted.

But I would advise sticking to the 3 layer model and not inheriting the DAL interface in your business objects. Its not much more code.

public class ShoppingBasket //Business Layer Object
{
    public Business(IDAL dataLayer)
    {
        this.dataLayer = dataLayer; // DAL object
    }
    public Order GetOrderForUser(string userId)
    {
        return this.dataLayer.Read();
        //todo:: implement business logic here later!
    }

    public void Purchase(Order order)
    {
         this.dataLayer.Update(order);
         //todo:: update the audit and billing tables!
    }

    //no requirement to implement this method. calling it directly would bypass the user filtering.
    //public Order Read()

    //no requirement to implement this method. calling it directly would bypass audit/payment requirements
    //public void Update(Order order)
}
  • "Normally you would not expect the business logic layer's exposed method to mirror the Data Access Layer.". Your normally differs from mine, obviously. This is meant to be a solution to that kind of application, from which further capabilities are added directly to the business layer with time. – Chris Wohlert Jul 3 '17 at 9:32
  • Do your applications expose raw Update() methods to the UI? – Ewan Jul 3 '17 at 9:35
  • I've update the code sample to use a more specific example as I think it demostrates the point better than the abstract – Ewan Jul 3 '17 at 9:47
  • This is what I am doing now, however, in cases where there is no domain specific naming, yes, I provide the presentation with a Update method. Your example provides semantic value, but I am trying to solve the problem where no such thing exists. – Chris Wohlert Jul 3 '17 at 10:19
  • So in the case where the presentation logic wants to use a CRUD method, would you still employ a 3-layer-architecture? – Chris Wohlert Jul 3 '17 at 10:21
0

One of the main reasons to separate code into layers is to organize and align each knowledge base with a code base.

For example, if you have these three layers

  • UX
  • Business
  • Data access

...then you have divided up your knowledge base like this:

  1. A UX developer who understands HTML and workflows and knows what the pages should look like and what they do. His job is to make the pages look the way they're supposed to while integrating with a business layer that exposes only just what he needs to get the job done. If he makes a mistake regarding business logic (e.g. he attempts to stuff a date of birth into a name field) the business layer will catch his mistake for him.

  2. A business layer developer who maybe doesn't know HTML so well but has the business knowledge on fleek. He knows what sort of operations are valid and when, and knows how to translate user-provided data into the data model. His job is to expose these business entities and rules to the UX developer in a manner that is easy for him to digest and difficult to do incorrectly.

  3. A data layer developer who understands the database, what R/I is in place, how to get data into/out of it efficiently, etc. His job is to expose the data model to the business layer in a manner that allows quick and consistent access and guarantees integrity when saving data.

Even if your team is very small, or even one person, it can help to divide up the work this way so your brain doesn't have to perform so many context switches when thinking about a problem. It also helps to know where to go find each type of logic in the code base when you have to fix bugs or make enhancements.

You can of course eliminate any of the layers, or add more of your own, but hopefully you will do so in alignment with an overall knowledge management strategy, or else your application will become very confusing as it grows.

0

I think that for your intentions (reading from/ updating a database) can be used CQRS (Command Query Responsibility Segregation).

enter image description here

In such a principle command used for change of state an object. Query used only reading from database.

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.