3

Where should the business logic for a project that utilizes Onion Architecture be placed?

In my case, it's a C#-based project, utilizing Web API and possibly a MVC UI for the presentation. But that may not matter, since I'm just curious about this conceptually.

The two diagrams below seem to be the most common ones that appear all over the web when I'm Googling info on onion architecture:

enter image description here enter image description here Enlarged images: diagram 1 and diagram 2

If I'm not mistaken, anything below the outer ring is considered the Core.

In Diagram #1 the most outer of the Core (blue ring) contains service interfaces, and it shows that the purple outer ring has the logging, services, etc. So does that mean the outer purple ring contains the service layer and business logic?

In Diagram #2 it shows Application and Domain Services as a part of the Application Core (not just interfaces and the domain model).

I feel that these two diagrams seem to define Onion Architecture completely different, but yet they seem to be the two primarily referenced. Or am I reading this wrong?

Maybe the end-result is no different, and it's just a matter of how I'm viewing the project layout in my head, but I've been trying to think of the service layer as a part of the Infrastructure on the outer ring. Is that a wrong way to think of it?

My service layer classes can have repositories or other service classes injected. The services themselves can be injected into the presentation layer projects (e.g. a Web API or MVC Controller) and from there converted into a presentable object (DTO or ViewModel) via Automapper.

Thank you

  • While "A picture is worth a thousand words" is true, this is not universal rule. In this case, you should actually read what people have to say about onion architecture, not just look at pictures. IMO there is lots of written about it, that would clarify why and how onion architecture works. – Euphoric Jul 1 '18 at 4:26
1

What you usually call "business layer" on a layered architecture here may be called domain model but that's not the point.

You say that a ring contains another and it's a conceptual error: any outer ring communicates with its inner ring and possibly with the core. Obviously UI doesn't contain domain logic (as tests do not contain application services).

Differences with a traditional layered architecture are more fundamental than the shape you use to sketch dependencies and in this case this memoizable name (and shape) doesn't really help to grasp the fundament difference: domain model is the central absolute source of truth for the entire system. Note the breaking difference: UI will use domain model, it's not limited to Application Services ring (despite what images may mistakenly induce to think). It doesn't mean that there is a direct dependency: interfaces and IoC are in-place to provide the required abstraction and isolation, the core point isn't to isolate each ring but to isolate your domain model from any external entity.

  • Thanks for the reply. I currently have layers referencing any/all layers below them. My main issue is, I don't know the service layer implementations belong below the outer ring. I understand the interfaces belong there, so the callers know nothing about the implementations - but do the implementations belong there? I'm using Autofac for IoC/cross-cutting. I'm currently passing all serices from teh service layer via DI of the interfaces to the presentation layers. Repositories come from the outer ring via DI, as well. It seems like the services should live in the same "ring" as the repos – Adam Plocher Jul 1 '18 at 23:36
  • Because if the implementations of the services lived below the presentation layers, couldn't the presentation layers reference them directly? And isn't that one issue that onion is trying to avoid? – Adam Plocher Jul 1 '18 at 23:39
  • I'm not sure about what you mean but implementations definitely belong to that specific ring. A better description of what Onion is looking for is maube material for another question but: you might reference underlying rings directly. Nothing stops you but it'll be much harder to unit test outer rings in isolation because...how do you mock, for example, database access? Onion is not trying to avoid something, it's a VERY natural way (especially when paired with DDD) to put the focus on the OO language you're using (that's why the MODEL is the central point, without any dependency). – Adriano Repetti Jul 2 '18 at 11:49
  • A small note: despite its apparent simplicity to build an application with this architecture is (IMO) more complex (in the sense that it's easier to introduce big design mistakes) than with a classic layered architecture. The "domain model does not depend on anything else" requirement is often (at least in my experience) partially ignored and this leads to REALLY complex dependencies. – Adriano Repetti Jul 2 '18 at 11:58
1

Business logic is actually split into two kinds in either one.

Data                                | Domain Entities      | Domain Model  
Data Business Logic                 | Repository Interface | Domain Service  
Software Environment Business Logic | Service Interface    | Application Service  

Data Business Logic is the purest, most abstract, business logic. Here things like your age are derived from your birthdate and a timestamp. Here, only things that would make sense to a domain expert are allowed to exist.

Software Environment Business Logic is allowed to be aware of more than the domain. It may acknowledge the existence of the software and do some housekeeping for that. Such as express your age as a number, in a particular language, as a % of a progress bar, or as a cartoon picture with a long beard.

Onion Architecture isn't the only one to split up business rules like this. You see the same thing in Clean Architecture1:

enter image description here

0

Business logic is the inner circle in both pictures (domain model/domain entities). This if where the meaningful processing takes place, the rest is just plumbing to make the system work.

The left picture assumes application of the repository pattern, hence the differing terminology (repository interface vs domain service). Basically the pictures are identical.

Business logic is a term used to identify a layer in so called 3-tier architecture, which is a model often used for older systems that lacked the added complexity of web applications and typically have a relational database at the bottom/core. In 3-tier you have presentation, business logic and storage. The latter layer is ignored as not interesting in the above pictures, for architectural illustration purposes it does not matter whether you are dealing with data and/or behavior and what the system ultimately does.

  • Thank you for your answer. Wouldn't Domain Entities / Domain Model represent plain objects that wouldn't necessarily have logic, but get utilized by a service layer? The service layer being (correct me if I'm wrong) the business layer I'm referring to - the layer with the business logic that utilize the domain entities and links the presentation to everything (well to the business logic, and persistence/repositories). I'm still not seeing the service layer in the core on the first pic. Service interfaces, sure... I feel like I'm looking at this wrong and/or I'm crazy. I dunno :) – Adam Plocher Jul 1 '18 at 6:37
  • @Adam Plocher A layer is a collection of interfaces that are in scope for code that is qualified as being part of an outer layer. That layer or set of interfaces may be regarded (called) a (set of) service(s). Do not get hung up on the use of either term (layer, services or interfaces). Which term is used depends on the author's perspective. If the stuff is implemented as web services, the term service will likely be used. If it is operating system function calls, the term API or interface will be more common. Interface is the more generic term, service usually implies a network boundary. – Martin Maat Jul 1 '18 at 6:55
  • I think from the caller viewpoint, what you say makes a lot of sense. The place calling the method doesn't need to know or care if it's an interface or a concrete implementation. I have the interfaces living below the outer ring so anything on the outer ring can reference them and know about them. The implementation of those interfaces I would think needs to exist on the outer ring, because otherwise they could be referenced and instantiated directly, right (since onion allows references to layers lower than itself)? Thanks again – Adam Plocher Jul 1 '18 at 23:41
  • 1
    You're right that "business logic" is sometimes used as a generalized "the backend without the web request handler", but that is not the only definition of business logic. In the more detailed definition, business logic is not the lowest layer, but rather the layer that generally sits on top of the repositories. For example, while a repository handles the CRUD for its type (Foo => FooRepository, Bar => BarRepository), the service (= business logic) is the layer that decides which objects need to be retrieved/created/updated (and then calls the needed repositories). – Flater Jul 2 '18 at 8:35
  • 1
    @MartinMaat: I feel like your reply comment missed OP's core question: Wouldn't Domain Entities / Domain Model represent plain objects that wouldn't necessarily have logic, but get utilized by a service layer? In other words, shouldn't the entities inherently be logic-free objects that are used by the logical layers (= outer layers)? – Flater Jul 2 '18 at 10:00

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.