I was wondering if anyone could suggest the best approach for simplicity, maintainability, and extensibility on the below scenario.

Overview

I am building a service application that will be used for both a web and a mobile interface. This is not very important to the question I have, however it may give a more complete understanding of the scenario.

On the core layer i have the below modules:

  • Project_CS: contains entities that hold information about the different projects and people involved in these projects. 
  • Plan_CS: contains entities that hold information about how each project will be executed (entities: tasks, schedule, strategy etc.). How each project will be executed will depend on a complex calculation according to the different project attributes; calculation which will be responsible with how some of the entities of these modules will be populated.

The reason I separated the above to different modules is that in the future there will be additional functionality that will only need to interact with the entities of the Project_CS (and new modules) and not the entities under the Plan_CS module.

The UI layer will need to consume both these modules and the Plan_CS module will need to consume the Project_CS.

Scenario A

I thought of creating a business logic (Execution_BL) module to contain the complex calculation that will be responsible for deciding the data that would populate some of the entities of the Plan_CS module, but then it seemed like the solution will become more complex as it will create one more module that will be consumed by the UI (Projects_CS, Plan_CS, and Execution_BL) while both Plan_CS and Execution_BL will consume the Projects_CS.

Scenario B

Since, the above became a bit complicated my second thought was to have the Execution_BL to consume the other 2 modules and the UI to only consume the Execution_BL, which will mean that the Execution_BL will be the one responsible for both the reading and editing of the data on the other two modules. This seems cleaner and simpler, but I am not sure that makes sense to have a "bridge" module for reading the data. 

Question

I believe that neither of the above scenarios violates the 4 Layer Architecture, but I am not totally sold on either of them, so I was hoping someone will have a better approach. What is the best way to architect the above solution? Do I really need the Execution_BL, how complex a calculation must and what other factors will be a good determiner of whether a BL module should be created?

The complex solutions can sit on their CS modules already (since this will contain their Services (OS11) to create update, delete, etc.). 


Another solution is to create a service for each entity so as to ensure scalability and lessen monolithic services. You can break down the Plan_CS into different services and if a project and plan needs to be referenced, you cna create a ProjectPlan_CS service.

Hi S.

Scenario 2. is feasible but requires an extra layer of abstraction, as anything used by the UI needs to be defined in Execution_BL, which means it will have to define Structures to "hide" the entities in Plan_CS that are manipulated in the UI.

How your Plan_CS entities are instantiated seems to be an integral part of the Plan functionality itself, no? Have you considered Scenario 3., where you put the "complex calculation that will be responsible for deciding the data that would populate some of the entities of the Plan_CS module" directly on the Plan_CS (instead of your current Execution_BL)? A *_CS module can contain entities and business logic that are closely related, it doesn't have to be just entities and wrapper actions.

I don't know how much logic is in the Project_CS module, but I get the idea that it's basically a database module. You could separate the Plan_CS module into a database module and a business logic module (Plan_BL), and create a new module on the same level which holds the new logic (Execution_BL).

With this option you could visually represent the Project_CS and Plan_CS modules as a bottom layer, with Plan_BL and Execution_BL in an additional layer on top. It seems sound to me in terms of the 4-layer architecture seeing as you've only got vertical communication, and it frees up possibilities to reuse the entities in Project_CS and Plan_CS with more modules later on without creating horizontal references (or references you could define as 'it's complicated'). 

I'm very curious to read other solutions to this topic, I really like the question.

Geraldine Ablaza wrote:

The complex solutions can sit on their CS modules already (since this will contain their Services (OS11) to create update, delete, etc.). 


Another solution is to create a service for each entity so as to ensure scalability and lessen monolithic services. You can break down the Plan_CS into different services and if a project and plan needs to be referenced, you cna create a ProjectPlan_CS service.

Hi Geraldine, 

If I understand correctly the scenario you mention in the second paragraph (creating a service module) the solution you propose will be to have the 2 core modules Project_CS and Plan_CS to hold the entities and perhaps some business logic. Then create a Service Module ProjectPlan_API (I added the API prefix to distinguish it from the other Core Modules) which will be exposing all the CRUD functions any UI module or external application that needs to interact with the data on the two core modules (Project_CS and Plan_CS). This will be similar to scenario B with converting the Execution_BL to a service module (API). 

I like the idea and have few follow up questions:

  1. If I create the Service Module (ProjectPlan_API) should the complex logic reside on this module or on the Plan_CS? are there any benefits of choosing one over the other?
  2. If I create a Project Service application to place the Project_CS, Plan_CS, and ProjectPlan_API modules in, can I set it up in a way that other applications consuming the Project Service application to only have access to the ProjectPlan_API  while the ProjectPlan_API module will have access to all other modules within the Project Service application?

Thanks for your help!

Jorge Martins wrote:

Hi S.

Scenario 2. is feasible but requires an extra layer of abstraction, as anything used by the UI needs to be defined in Execution_BL, which means it will have to define Structures to "hide" the entities in Plan_CS that are manipulated in the UI.

How your Plan_CS entities are instantiated seems to be an integral part of the Plan functionality itself, no? Have you considered Scenario 3., where you put the "complex calculation that will be responsible for deciding the data that would populate some of the entities of the Plan_CS module" directly on the Plan_CS (instead of your current Execution_BL)? A *_CS module can contain entities and business logic that are closely related, it doesn't have to be just entities and wrapper actions.

Thanks for the response Jorge!

I have thought about the scenario 3 you mention above and after reading your reply and Geraldins I am leaning more towards it. To answer your question on the begin of your second paragraph is yes.

You mentioned creating Structure to "hide" entities from Plan_CS and I was wondering if you could provide some further details or point me to any reading material to better understand how that is accomplished.

Like, is it possible to make the UI modules to only be able to consume the Execution_BL module and not be able to add the Project_CS and Plan_CS as a dependency? 

Monique de Vos wrote:

I don't know how much logic is in the Project_CS module, but I get the idea that it's basically a database module. You could separate the Plan_CS module into a database module and a business logic module (Plan_BL), and create a new module on the same level which holds the new logic (Execution_BL).

With this option you could visually represent the Project_CS and Plan_CS modules as a bottom layer, with Plan_BL and Execution_BL in an additional layer on top. It seems sound to me in terms of the 4-layer architecture seeing as you've only got vertical communication, and it frees up possibilities to reuse the entities in Project_CS and Plan_CS with more modules later on without creating horizontal references (or references you could define as 'it's complicated'). 

I'm very curious to read other solutions to this topic, I really like the question.

Thanks, Monique

What you describe above is similar to scenario B but you introduced a new business logic module (Plan_BL). Couldn't the Execution_BL handle anything that will be on the Plan_BL? What logic or functions would you have inside the Plan_BL?


Solution

S. wrote:

Jorge Martins wrote:

Hi S.

Scenario 2. is feasible but requires an extra layer of abstraction, as anything used by the UI needs to be defined in Execution_BL, which means it will have to define Structures to "hide" the entities in Plan_CS that are manipulated in the UI.

How your Plan_CS entities are instantiated seems to be an integral part of the Plan functionality itself, no? Have you considered Scenario 3., where you put the "complex calculation that will be responsible for deciding the data that would populate some of the entities of the Plan_CS module" directly on the Plan_CS (instead of your current Execution_BL)? A *_CS module can contain entities and business logic that are closely related, it doesn't have to be just entities and wrapper actions.

Thanks for the response Jorge!

I have thought about the scenario 3 you mention above and after reading your reply and Geraldins I am leaning more towards it. To answer your question on the begin of your second paragraph is yes.

You mentioned creating Structure to "hide" entities from Plan_CS and I was wondering if you could provide some further details or point me to any reading material to better understand how that is accomplished.

Like, is it possible to make the UI modules to only be able to consume the Execution_BL module and not be able to add the Project_CS and Plan_CS as a dependency? 

Hi S.

Given your positive answer, I'd say Scenario 3. is definitely the one you want to follow. It will simplify your development without negative impact on your architecture.

As for the Scenario 2. implementation approach I mention:

  • If any public action of Execution_BL receives as Input Parameter or returns as Output Parameter an Entity or Structure defined in Plan_CS, then consumers of that action of Execution_BL will also need to consume said Entities or Structures from Plan_CS, no other way around it.
  • Upfront warning: I don't recommend this approach in most cases. If you want to hide Plan_CS completely from consumers of Execution_BL, then public actions of Execution_BL need to receive as inputs or return as outputs entities or structures defined in Execution_BL itself. So you would create Structures in Execution_BL that hold the necessary information for Execution_BL to work and, internally (in Execution_BL's actions) you need to be able to convert the Structures from Execution_BL into any entities necessary from Plan_CS). The naïve approach would be to copy the necessary Entities from Plan-CS and paste them to the Structures folder in Execution_BL (this will create Structures with the exact same definition as the original entities).

Hope this helps.

Solution

Thank you all for your responses.

I decided to go with scenario 3 and having the complex login in the Plan_CS module without creating the Execution_BL module. In the future and depending on how this application will grow I may create an API module and have the UI applications (Web, Mobile, external) interact with the core modules through an API interface.