1

I like programming in such a way that every component/injectable of the applications I build, has a clearly defined scope, and it's easily tested.

With years working as a Developer I've come to ensure every component I declare and implement fits one of the following categories:

  1. Technical components: those behind the scenes over which everything works. Usually not implemented by us, but part of some library. Database connections, server engines, http clients, etc.

  2. Business logic components: they describe and encode business rules, and never deal with stuff like Http request parsing, Db connections, or serialization/deserialization of data. (OrdersService, UsersService, etc)

  3. Boundary components: They deal with the translation between business intents, and technical operations (ie, translating the intention of creating an entity, into an insert statement, or parsing the body of an Http Request, into a business intent, or encoding into JSON the result of some business operation). DAOs/repos, controller and API clients are usually among this category.

That being said, no business logic components never interact directly with Technical components, but rather other business logic components, and boundary components.

Now, when encoding business rules, one should use business logic components, right? but what if such rules need to be run under some kind of transaction that is DB dependent?

How do I encode multiple business steps that need to run under the scope of some transaction, without a leaky abstraction as a result?

So let's say I want to add a payment, and then change the state of an order from Pending to Processing

It's a business rule that when one happens, the other must happen too. Yet those to actions belong to two different domains, and yet, they must happen transactionally... These steps must be encoded in a business logic component, and without leaky abstractions, still express the fact that they belong to some transaction. How???

1
  • 1
    Why can't a there be a transaction concept in your business domain? Surely you've participated in some form of transaction outside a database before. E.g., with your bank, or your employer when you transact work for money, etc.
    – svidgen
    Commented Dec 10, 2022 at 15:49

2 Answers 2

2

The traditional answer would be a "unit of work" pattern. But its not particularly good in my view.

A better solution is to do away with the transactions. Or at least remove them from the business language.

So for example, lets say we have a business rule:

  • Only allow new orders to be created if the items are in stock!

Uh oh, you think, now I need to somehow reserve the stock, create the order, assign the reserved stock and if anything fails roll, it all back! This breaks my system of object types! woe is me!

OR! you could just tweak that business rule. I mean what does "created" even mean? not "saved to the database" because business rules shouldn't know about databases right? So you slap the order in the DB with some status "Not Created Yet!" do your other bits, something goes wrong, change the status to "Not Enough Stock", put a message of a queue to push back to the customer and update their order screen, etc etc.

You'll find you can do the whole thing in a distributed system with no locks or transactions and it all works out fine.

1

Introduce a Workflow component. Using this Workflow component we can define rules (or logical conditions) at business level like 'if and only if a payment is received the order is processing' (tangent: here we see a problem with the example rule) (the rules don't have to be imperative).

With the workflow component we compose and orchestrate the business level operations. These compositions we hand over to the technical level to execute.

Depending on how isolated you want your business level operations to be, the technical level either executes the operations in a regular ACID DB transaction or you require that each business level operation defines one (or more) undo/reverse methods and you can execute them in a saga.

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.