Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Dealing with code maintenance when saving a large and complex entity in a single business transaction

+4
−0

Context

I am currently working on migrating a legacy application to an ASP.NET Core + Angular application. The Web API's main project is based on Jason Taylor's template (clean architecture) and among others relies on MediatR library.

The UI/UX experience for already migrated business flows relies on UI pages that look like the following:

Existing UI/UX for reading and editing data

When the user enters a page, each section (group) is loading its data, which ultimately relies on a MediatR query. Only the information from a specific group can be edited and saved. This helps our development and maintenance quite a lot:

  • data fetch is clearly separated for each part (component)
  • a good mapping between use cases and code structure (data fetch for a part = query, save group data = command)
  • smaller transactions (save small data, instead of bigger data)
  • each use case implementation is quite small and easy to maintain

Now, for migrating the functionality around another entity type, the product owner wants another approach to UI/UX that looks like the following:

Desired UI/UX for reading and editing data

  • there is no read-only view and the users can directly jump at editing stuff
  • there is the main Save button that will save "everything". We can have Save working only on the current section to keep things more manageable.
  • at least one section is quite heavy (dozens of fields and files to be uploaded)

The Issue

The main issue with the desired design is that the number of use cases is drastically reduced and I get way bigger and more complex payloads to handle.

The legacy application treats the saving functionality in a rather monolithic way resulting in a very hard-to-maintain code.

I am wondering about how to tackle this issue as I want to avoid maintenance issues.

Possible Solution

Since I cannot avoid a big payload being ingested in the API, I need to somehow split the business logic into more maintainable pieces of code. Chain of Responsibility pattern comes into my mind:

  • controller action received the payload
  • a save command is issued with the big payload
  • a bunch of middleware will receive the payload and each one will only process the part of interest (e.g. merging the section 1/group 1 data). I can even have the payload DTO implement an interface dedicated to each processing part (I will have to check if it works).
  • the final middleware will commit the transaction if everything goes fine until then

We are already using the concept for handling cross-cutting concerns in a way similar to what is depicted in this article, but I have used for handling business transactions.

**Is this a good approach for handling such a business scenario? **

Note: drawings were done using Excalidraw.

History
Why does this post require attention from curators or moderators?
You might want to add some details to your flag.
Why should this post be closed?

0 comment threads

1 answer

+2
−0

Chain of Responsibility doesn't strike me as appropriate for this problem, at least as I understand it. You want to use CoR if you have multiple different requirements for the processing of the same data—authentication, logging, A-B testing—things we generally call concerns. What it sounds like you're going to have is a large data structure where you want to process each of the pieces of that data structure individually and then commit the entire job in a single transaction. CoR is overkill for that; just have your payload object have a field for each logical section and have a function for handling each section. You can call those functions directly or over a mediator, depending on your other requirements.

In this scenario, your biggest maintenance worry is going to be how truly isolated each section's handler is from the others. If your DTO looks like

class Section1 {
  public Group1 Group1 { get; set; }
  public Group2 Group2 { get; set; }
}

but your handler for Group2 requires data from Group1, you'll have coupling that'll make it harder to change the processing of each group individually. Chain of Responsibility would not help with this; in fact, it would obscure what you need to do, since every middleware processor would get the entire Section1. The way to stay on top of this worry is:

  • try to keep the groups logically isolated
  • when that fails, pass inter-group data explicitly to the functions that need them

If the first bullet point is a challenge due to what the business wants from the UI, consider an intermediate stage that adapts an entire view model class into a logical model class but doesn't do anything with side effects, and then dispatches the fragments of the logical model to your handlers. This adaptation also doesn't need to be done with CoR; it's necessarily coupled to the types of your application code and must be invoked the same way with every request, which makes it a bad fit for a design pattern intended to be largely data-agnostic and dynamic.

History
Why does this post require attention from curators or moderators?
You might want to add some details to your flag.

0 comment threads

Sign up to answer this question »