My question is in the header. I would like to know is there architectural solution that enables to perform nested transactions on the business model. Let me to explain - the standard flow for web service is

  • validate input data
  • process request
  • persist results
  • write response

However, there are cases when i Can not validate data before request is processed - meaning i should validate system after request execution - lets call this case inverted validation case. If system becomes invalid - i would like to roll back changes in business model to the initial state. I should be noted that system should has good performance. Processing of request consumes big amount of computational power - so it is impossible to perform changes twice - once for validation and once for actual request processing. At the moment i am using temporary storage for results of request processing, than i perform validation if it passes - i apply data from temporary storage to business model. However, this solution is working great if i have one transaction - meaning i have to perform inverted validation only once, but is there another inverted validation - this turns into spaghetti code.

Here is example: Lets say we have logistics service that gets as input list of cargos with there amounts and outputs - list of warehouses for each cargo where cargo can be stored. Each warehouse can store only some amount of cargo another warehouse will store the rest. For example warehouse A store 10% of cargo, warehouse B store 50% and warehouse C 40% of cargo. To compute the list of warehouses - server should perform heavy computations. Request should be rejected if cargo can not be stored in less than 10 warehouses. Also it can turn out that some cargo supplier has not enough founds - so this supplier should be rejected. NOTE system should consider that warehouse capacity can be changed by already processed cargos from current request. So here we have two transactions - one big transaction for whole request and two nested - for case when there no warehouses and when there no funds - as you can see you can not apply changes to the business model right away. NOTE: the problem in the example is a toy problem - i created it only to show the actual problem.

New contributor
Oleksandr Papchenko is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
  • See unit of work pattern – candied_orange Dec 6 at 10:07
  • @candied_orange, i think i need solution of higher level - EF for C# world and JPA for java world provide implementation of Unit of work pattern - however what i was trying to show in my question is that i can not modify entity right away - as it can turn out at the end of transaction that this changes are invalid. At the same time i need accamulate computed data in temporary storage. I would like to get safepoints(like for DB transactions) in EF or JPA for business entities - when you can rollback you Unit of work to some point in the past. – Oleksandr Papchenko Dec 6 at 10:40

As I see it, you have a paradigm which works when the request follows the expected sequence of operations, namely: validate request, process request, persist results, write response. Presumably each request has its individual implementation for each of these steps, but the steps remain constant.

Now you're given a situation in which the steps can change. There are several approaches for this. One would require less refactoring, but is ultimately the less flexible of the two solutions. The other should potentially address any new types of issues of this type in the future. Let me pitch both, and I'll let you choose which you prefer:

Event hooks approach

Right now you have a class which calls these four operations. If you ultimately decide that this sequence of operations should still be respected for the most part, then this means the processing which needs to be done prior to validation could be considered "part of the validation". However your current validation if I guess correctly is probably only built to handle request input.

To solve this, you can simply add event hooks which initially when added to your class do nothing. Examples of these hooks might be:

onPreValidation, onPostValidation, onPreProcess, onPostProcess, etc.

Your class would call each one in their respective order and pass on any information returned in the pre phase to the actual handling of that phase. You would then create stubs of these methods which do nothing, and so for most requests, nothing would change.

However this allows you to override this class and perform special actions before or after each phase. This would require the least amount of refactoring, and it's faithful to the "four-phase" idea of your request. If you need to, you can also create a custom phase for particular requests which don't deviate too much from this.

However you shouldn't take this approach if you feel what you need to obtain is too different from the "four-phase" idea. A radically new request should be handled radically different, which leads me to the second approach.

Abstract request handler type

This takes the concept of your four-phase class and abstracts it. Ideally, it should be able to take the input of the request and returns an response instance. So potentially this could be implemented in any number of ways.

Your current class then derives from this abstract request handler, and when invoked, performs the typical four-phases it always executes normally, returning the response instance to be potentially serialized and returned to the caller.

Using this type, you create a new request type for your new inverted validation case. This new request handler performs any necessary processing prior to validation. If done properly, the actual implementation of these phases should be done elsewhere, so likely you'd be using an abstract factory to create concrete classes to handle these individual phases. This abstract factory would probably be provided by the abstract request handler itself. So ideally, all that is being modified are the steps and the order of these steps in the context of your request handler.

While this would require the most refactoring, it creates a good basis for new types of requests in the future.

Conclusion

Let me emphasize that in both solutions, we're abstracting the steps of the request, and not the actual implementation. This should create a good basis for future development and ensure that you can accomodate new requests in the future.

  • This is good solution to abstract structure of the request processing, however i am interested on how propertly hold business model in valid state. When validation is failed after request processing what should i do - rollback changes on businss model manually, hold copy of untouched business model before request processing or there are some ready to use patters and libs that implement them ? – Oleksandr Papchenko Dec 6 at 12:57
  • @OleksandrPapchenko If "persisting" also entails registering the changes made up until that point, then no rollback is required. Though if you want to have a sophisticated approach, each step would have its own label, and you'd persist each step as it gets performed. And in case of error, call a dedicated rollback method in each step successfully finished in reverse order to reverse the operation entirely (most steps likely wouldn't require a rollback, in which case it would do nothing). – Neil Dec 6 at 21:06

Your Answer

Oleksandr Papchenko is a new contributor. Be nice, and check out our Code of Conduct.

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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