5

I am currently starting a new project with a 4-tier architecture design. The layers is set as follow.

                                          +------------------+
                         +----------------+   Presentation   |
                         |                +------------------+
                         |                         |
                         |                         |
                         |         +---------------v----------------+
                         |         |                                |
                         |         |         Services (dll)         |
                         |         |                                |
                         |   +-----+  +------+  +------+  +------+  |
                         |   |     |  | Log  <-->Print <--+Other |  |
                         |   |     |  +------+  +------+  +------+  |
                         |   |     |                                |
                         |   |     +--------------------------------+
                         |   |                     |
                         |   |                     |
                         |   |            +--------v---------+
                         |   |   +--------+  Business Logic  |
                         |   |   |        +------------------+
                         |   |   |                 |
                        +v---v---v+                |
                        |         |       +--------v---------+
                        |   DTO   <-------+   Data Access    |
                        |         |       +------------------+
                        +---------+

In service Layer, I encountered a circular referencing problem as

  1. Print Service references Log service when it need to log the print task down.
  2. Log Service references Print Servicewhen it need to get some printing detail via some method in Print Service

All of the services and other tiers/layers is existed as a csproj, so it will be compiled as a dll.

I would like to know how can I get rid of such scenario? After doing some research, the most possible solution is to create an interface project for each service. Is there any other better solution?

If I really adopt interface projects approach as a solution, Does it mean that I must go along with Dependency Injection? Dependency Injection is powerful, but it makes codes to be more difficult to trace too!

Lastly, as Presentation Layer cannot reference BLL directly. Therefore, some classes and models defined in BLL cannot be referenced. Is it a good idea to store those classes and models in DTO project so that it can be used by upper-indirectly-referenced layers? (Of course I will rename the DTO project to some more meaningful name e.g. BusinessObjects)

UPDATE 1

I know my example may not be good enough. Let me change the requirement.

CourseService and StudentService this time. The dependency is visualized as follow

                            +--------------------------------+
                            |                                |
                            |         Services (DLL)         |
                            |                                |
                            |   +-------+        +-------+   |
                            |   |Course <-------->Student|   |
                            |   +-------+        +-------+   |
                            |                                |
                            +--------------------------------+
  1. CourseService has a method GetEligibleStudent(Course crs) to list Student[] those are qualified to enroll certain Course base on some course-specific information and complex logic in StudentService.
  2. StudentService need to call PrintGrade(Course crs, Student stu) to retrieve certain course grade of the a student.

Seems this example is better. I know someone may challenge that GetEligibleStudent(Course crs) should be placed in StudentService or PrintGrade(Course crs, Student stu) should be placed in CourseService. However, circular dependency may exist anytime in development. An appropriate solution should be took, not just in my example.

mannok
  • 189
  • 5

1 Answers1

2

There is a clear data relationship of Course with Student. That's where primary domain modelling should terminate. If not, it infects design decision making for the worse.

Orchestration instead

Generally people forget about "orchestration" (or they were not taught it). If you stick with entity thinking, all you do is model entities everywhere. Entities are data, but you need to deal with "information".

So in this case:

  • Course is an entity
  • Student is an entity
  • GetEligibleStudents becomes - GetEligibleStudents(int CourseId) in an Orchestration service called something like CoursePolicy
  • PrintGrade become - PrintToPDF(int CourseId, int StudentId) in an Orchestration service called something like GradeResult

There are also potential benefits in modelling: CoursePolicy as an Entity - where the policy configuration can also be stored; and, GradeResult - where the Grade stores the grade result itself and can be retrieved in different forms. But we only consider this now, because we first considered "orchestration" and broke away from the original entities.

This applies in many other cases too of course.

Kind Contributor
  • 890
  • 4
  • 13