1

During my first attempt of implementing a project with the "Clean Architecture" I try to implementation a job portal where I came across a problem concerning the communication between (hopefully) two loosely coupled modules.

The two modules are:

  • Identity - responsible for user operations like register
  • Catalog - responsible for job operations like find

The Problem

When searching for one or more jobs, information about the employer should be sent along with the job information.

Brief Architect Description

A Job (inside Catalog) references an User (inside Identity) by an id called employee:

class Job {
    private Identifier id;
    private Identifier employee;
    /* ... */
}

First Attempt

My first idea was to query the information inside a Use Case but this would couple the two modules:

class FindJobByIdUseCase {
    
    private final FindUserByIdUseCase findUserById; // from Identity module
    /* ... */
       

    JobResponse execute(FindJobInput input) {
      User employee = findUserById.execute(input.employee);
      Job job = /* ... */;
      /* ... */
      return new JobResponse(jobDTO, employeeDTO); 
    }

}

Second Attempt

I thought I could create a third module coupled to Identity and Catalog to aggregate the required data:

Identity <----- Identity-Catalog-Aggregat -------> Catalog

// in Identity-Catalog-Module
class FindJobAndEmployeeUseCase {
    
    private final FindUserByIdUseCase findUserById; // from Identity module
    private final FindJobByIdUseCase findJobById;   // from Catalog module
    /* ... */
       

    Response execute(FindJobAndEmployeeInput input) {
      User employee = findUserById.execute(input.employee);
      Job job = findJobById.execute(input.job);
      / * ... */
      return new Response(jobDTO, employeeDTO); 
    }

}

Both attempts feel wrong.. Can you advise me on the solution that makes the most sense?

1
  • 1
    Why does a Job reference a User? More to the point, what does registering a User have to do with finding a Job? Hint: Two domain entities can share an identifier. Commented Apr 29, 2020 at 17:50

2 Answers 2

2

The use case (solution 1) would not lead to coupling of the modules.

Yes, the use case is dependent on both modules, but the modules themselves are independent from each other and that is what coupling is all about. (At least, as long as the use case is not part of one of the modules, but then the use case would be misplaced.)

And that is the whole idea: you main modules are independent and testable, whereas the outer layers in the architecture integrate possibly more-than-one module from the inner layers, as your application needs.

1

Aggregates are the correct call for situations like this and (in general) a very useful tool in domain-driven-design. They "bundle" abstracted functionality to provide comfortable use of your API. An alternative would be, if you want to completely omit inter-module-communication (which in general is no good idea), you can make your API-users collect all the data they want by simply calling multiple endpoints instead of just one aggregate one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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