Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request support for multiple (bounded) contexts #660

Open
mahono opened this issue Dec 20, 2024 · 5 comments
Open

Request support for multiple (bounded) contexts #660

mahono opened this issue Dec 20, 2024 · 5 comments
Labels
question Further information is requested version: 4.0.x

Comments

@mahono
Copy link

mahono commented Dec 20, 2024

Hi guys,

first of all: I am happy that I clicked the link to your library in one of the recent Symfony blog posts. You did a great job here! I'm looking for an event sourcing solution with Symfony since ages now. And for the first time, this seems to be something that could fit my needs. Nice and fresh developer experience. I really like it. I love UUIDv7 and PostgreSQL. So I'm looking forward to testing your library in the upcoming weeks.

I noticed that you dropped support for "one table per aggregate type". I understand that this makes things complicated. I also found the ticket where you explained the reasons. But I have one concern here:

I am using a "modular monolith" approach where I separate the features of a Symfony project into multiple modules. A little bit similar like it was at the beginning of Symfony 2/3, when you had to implement everything in a bundle. I am also using bundles to separate code into modules with a layered architecture proposed by Matthias Noback in his nice Web Application Architecture book that nicely explains this kind of programming that nicely fits with DDD.

So my question basically is: Would it be possible to support multiple "contexts"?

What I mean is basically fully isolate everything and allow the event sourcing to run multiple instances in a project.

I don't need to have tables per aggregate type. But I would really appreciate having dedicated tables per bounded context.

I had a look at your event sourcing bundle documentation and it seems there is only one single connection? I would like to be able to somehow configure multiple instances/connections of the event sorcing, one for each context (module/bundle), and then either in the config tell the system where the matching aggregates/events/subscriber/whatever are, or have a way to configure this with Attributes.

It would be totally fine for me and even a good thing in my opinion, if each "context" would be isolated with dedicated tables for events and subscriptions. Somehow a way to basically prefix an instance of "event-sourcing" with a context name.

I think this would be a nice compromise and allow the library to be used with bigger projects without adding too much complexity.

I am not sure if this request belongs to the library or the bundle. I did not read each and every file, yet. ;o)
But I can imagine that it would need changes in both packages.

What do you think about this idea?

@mahono mahono changed the title Request to support for multiple (bounded) contexts Request support for multiple (bounded) contexts Dec 20, 2024
@mahono
Copy link
Author

mahono commented Dec 20, 2024

For example in the CLI commands, you could add a --context option that defaults to "default". Similar like connections with the Doctrine bundle. But I think it would be better to allow having multiple context in one single database or provide the possibility to have both, either everything in one database or separate connections per context.

@DanielBadura
Copy link
Member

Hi 👋

glad that you like our library! First, technically this should be possible. On the library side the commands would need some work I think, something like you already suggested: providing an option to define in which context the command should be executed. But most of the work would be on bundle side I think. But the issue here is fine 🙂

But I still have some question to get a full grasp on what you want to achieve and why you want that.

  1. How do you want then communicate between the bounded contexts? Do you have an extra messaging queue then in between with infrastructure events?
  2. What about everything else, do you split & recreate all infrastructure things in the different bounded contexts?
  3. Do you want to use different DB's for different bounded contexts for the event store?
  4. How would you handle migrations then? Also everything separate?

@DanielBadura DanielBadura added the question Further information is requested label Dec 20, 2024
@mahono
Copy link
Author

mahono commented Dec 24, 2024

Regarding your questions:

  1. I would call a command in a subscriber/processor. I already do this in other projects where I decouple modules within one single project by providing commands and queries using Symfony messenger. This is a very powerful architecture pattern because this way you can start a project as modular monolith and later move a module into a different Microservice while your application only needs minimal refactoring.
  2. To me it would be totally fine to separate/isolate things. Similar to Doctrine and different Entity Managers. Of course it would be nice to have the possibility to subscribe to events of different/multiple contexts. But this might be something that could be added later.
  3. It would be nice to have both possibilities, either different databases or multiple tables in the same database by using a prefix for example that could be the context name. Probably if the context would always be used as prefix („default“ or „main“ if there is only one) it would be easy to switch.
  4. This one is probably tricky. For your library it’s probably overhead to manage multiple migration tables. Maybe an interface would be nice to allow for more complex setups.

This is generally a good idea to provide interfaces when there could be needs for different implementations. For example it’s great that I can have my own store implementation. For example I probably need the possibility to have a store based on API calls. But this is easily doable because of the interface you provide.

@DanielBadura
Copy link
Member

  1. I'm doing the same, dispatching commands from processors to trigger other aggregates to do something.
  2. The subscribing of events from different store would be definitely extra work, if even possible right now. You said that you read the issue/PR where we removed the multitable store. It would be the same problem to have the events in the right order then.
  3. & 4. Yeah, my questions here were aimed for this problem with the migrations.

I'm also working in general in the same approach. I just do not split the eventstore in the project per default. As soon as i would like to split a bounded context out of the "main" project i would copy the needed events and code into the new project then.

This does not mean that I think your approach is wrong or something like that. I think it's worth it to investigate on this and try to get it working.

We try to achieve with this library a high DX to get the people into event sourcing, which means that we should keep all the nice features like migrations working if using this approach imho.

These topics do i have in my mind right now:

  • Migrations
  • Subscriptions auto-setup etc. in dev
  • Subscriptions Worker (we need then multiple)
  • Our WIP Dashboard bundle
  • Listening to events from different stores, otherwise the project should be split already

One last note: this would most probably lead to BC-Break(s), which means this would land earliest in 4.x.

@DavidBadura wdyt?

@DavidBadura
Copy link
Member

As @DanielBadura has already said, we are taking exactly the same approach. We are building Moduliths and trying to isolate our modules as much as possible. But that doesn't mean that we have 3 entity managers, 3 event stores, etc. We only use one entity manager and one event store. Because I believe that further isolating the benefit is not enough.

Of course you have to be consistent and not make joins and queries beyond your bounded context, but you can get this convention and can partly ensure it with tools like deptrac.

But of course I also looked at what is necessary to implement it. Unfortunately it only works with BC breaks or lots of BC layers. Also in the bundle, because each of our services that has to be instantiated multiple times need a new service ID with the context included. There is much, much more to do.

To be honest, I don't know if the effort is worth it. It is quite simple to split the project afterwards by simply migrating the events from one store to the next. We have tools for that. On the other hand, there is the high level of effort and subsequent maintenance.

I would suggest leaving this ticket open and looking at this issue again for version 4.0. This way we can also possibly track whether more users are interested in this feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested version: 4.0.x
Projects
None yet
Development

No branches or pull requests

3 participants