Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
344 views
in Technique[技术] by (71.8m points)

clean architecture - CQRS and shared logic in Controllers level

I am playing around with CQRS and the MediatR library, trying to learn some of the best practices. I've found hard to understand how to split all business logic into commands and queries.

Here it is an example:

I have an Address entity and I already created two commands and one query: InsertAddressCommand, UpdateAddressCommand and GetAddressByUserIdQuery.

There are endpoints in the controller in charge of execute the Insert, the Update or in charge of returning Addresses by user id.

There is also an endpoint named UpdateOrInsertAddress which reuses the 2 commands and 1 query: first to get the address by user id and based on the result to execute the insert or the update.

So far so good.

Now, there is another endpoint SubmitPurchaseOrder which is receiving a bigger object. All the information related to a purchase is received at once. The shipping and billing addresses are part of the posted object.

Then I would like to reuse the logic inside UpdateOrInsertAddress since all the logic is already there (and I was taught to reuse code); but since UpdateOrInsertAddress is an endpoint, I cannot execute it from another endpoint (SubmitPurchaseOrder).

So here it is the question: What is the best practice in this context?

Some ideas off the top of my head:

  1. Move the logic in UpdateOrInsertAddress endpoint to another method in the controller and reuse it from both UpdateOrInsertAddress and SubmitPurchaseOrder endpoints. In such case, I would be putting logic in the controller and I don't know if that is correct.
  2. Create another layer, maybe close to the one with all commands and queries, and write there this kind of shared logic which will be later consumed by the two endpoints.
  3. Forget about reuse, avoid sunk cost fallacy and just create a new UpdateOrInsertAddress command which will be used by the two endpoints. In such case, the "logic" of retrieving address by user id, updating or inserting will be duplicated in this command.

Have you come across a scenario like this? What is the best practice?

question from:https://stackoverflow.com/questions/66054400/cqrs-and-shared-logic-in-controllers-level

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Well... First you have to ask yourself if there would ever be a case where UpdateOrInsertAddress logic changes, but you would still want to use old logic in SubmitPurchaseOrder, in other words: is UpdateOrInsertAddress logic tightly coupled with SubmitPurchaseOrder and it should always change together in both places?


If UpdateOrInsertAddress logic IS tightly coupled with SubmitPurchaseOrder, then do not overcomplicate things and use simple refactoring techniques such as "Extract Method" to reuse the code (your 1st idea works fine for this) just make the method private for internal use. It does not mean that you are putting logic into the controller, you are just refactoring and if you are concerned about that you could even isolate those two endpoints in their own controller so no other endpoint sees the shared code.


If UpdateOrInsertAddress logic IS NOT coupled with SubmitPurchaseOrder, then duplicating code (you 3rd idea) is quite an obvious choice, because, even if visually code looks the same, both duplicates have their own reason to exist. Tho you have to be careful when duplicating conditions, they probably represent some business rule (you should evaluate it), which should be extracted into Domain wide Policy (e.g.: only users of age >= 18 can register, etc.) and reused between shared code to protect you from business rule changes.


Your problem has more to do with common programming practices than CQRS specifically.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...