You touch on many topics and keywords in your question. It shows you put a lot of thought and effort into this. However, you're very imprecise and often a bit off about how things work or what they mean, which makes it very hard to accurately pinpoint precisely what the problem is.
As a quick example:
- Your question is "how to split" whereas the problem you describe happends when you merge things. Those are opposite things. This suggest to me that the problem is in the opposite direction of where you're looking.
- Having separate GUI windows is an implementation detail that doesn't belong on the same (high) level discussion that project structure does.
- To the backend, it doesn't matter what the frontend does or what it looks like. For all you (the backend) care, the frontend could mash all your neat little contexts into a single form. That is unlikely to be a good idea, but the point I'm trying to get across is that it's not the backend's problem if the frontend makes some bad decisions on its own.
- "Bounded context" does not mean "singleton core of the onion". Your onion core can have many, many bounded contexts. Using the example of webshop software:
Person
, Product
, Order
, Inventory
bounded contexts co-exist within the same domain (i.e. core of the onion).
- The separation maintained between these bounded contexts is one of self-discipline, not rigorously enforced via project dependency graph.
- Microservices are a deployment detail and are not the driving factor for how you structure your internal logic. Microservices are much more relevant in terms of availability, independence and deployability, which are not things you've touched on in your question.
- Future integration with other languages is irrelevant as to how you structure your current project in a single language. Other language's runtimes are considered external resources as far as your (current language) project is concerned.
I'm going to make an educated guess here, based on what I infer the underlying driving force behind your decisions and argumentations is.
If I'm spot on, the below answer should explain everything. Depending on how off I am, the below answer may only partially apply to your case. Let me know where I'm wrong and I'll correct the answer as needed.
I suspect that you're unhappy that when merging your two bounded contexts into the same domain, there is no rigorously enforced boundary between them anymore (since one could freely reference the other if it wanted to), and you are therefore looking for ways to build a concrete wall between them to ensure that they never reference each other even if they tried.
And because you're looking for ways to divide your code, you've taken a shine to microservices, which have a generally secessionist attitude towards how logical modules should interact with one another.
Am I in the right ballpark here?
Problems started when adding the "Optimisation" part to the same Intellij project. In DDD terms, "Exploration" and "Optimisation" are distinct bounded contexts. Combining both in one project would require having two "onions" side-by-side. The complexity is noticeably greater than with the "Exploration"-only project.
Merging two DDD codebases inherently means that their individual boundaries cease to exist, and they instead use shared boundaries. To describe it visually, you're thinking of your merged codebase this:
Exploration Optimization
-*-*-*-*-*-*- -*-*-*-*-*-*-
┌─────────────┐ ┌─────────────┐
│ Persistence │ │ Persistence │
└──────▲──────┘ └──────▲──────┘
│ │
│ │
┌──────┴──────┐ ┌──────┴──────┐
│ Domain │ │ Domain │
└──────┬──────┘ └──────┬──────┘
│ │
│ │
┌──────▼──────┐ ┌──────▼──────┐
│ Application │ │ Application │
└─────────────┘ └─────────────┘
But it should be this:
Exploration + Optimization
-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
┌───────────────────────────────┐
│ Persistence │
└───────────────▲───────────────┘
│
│
┌───────────────┴───────────────┐
│ Domain │
└───────────────┬───────────────┘
│
│
┌───────────────▼───────────────┐
│ Application │
└───────────────────────────────┘
To use your diagrams, I would expect your merged diagram to merge their bubbles. There shouldn't be a separate "View" bubble for exploration and optimization. There should be one "View" bubble which is the combined content of those two bubbles.
When you start applying this to your diagram, you'll notice that all the bubbles of the same name merge into the same blob.
Everything from the same layer should be merged with one another, since it now all belongs to the same layer. Let go of the old boundaries, embrace the new ones (from a code structure perspective. Whether you separate them for the end user is a different story).
Merging the bubbles doesn't mean that these merged bubbles must invariably interact with one another. They often don't. If we were to observe a specific use case threaded across these layers, the entire use case would usually entirely belong to one of the old parts, i.e. it's completely Optimization or completely Exploration logic.
That's not a problem. There is no inherent requirement that code that lives in the same project are forced to interact with one another. It is very common for bounded contexts within the same domain to either never interact with one another, or only marginally interact with other bounded contexts which reference them (e.g. how an Order
references the Product
s of a webshop, even though they're separate bounded contexts in all other regards).
Microservices have their purposes, but they're not the right solution to this particular problem. I suspect you're stumbling on microservices because you're thinking about this problem on the wrong level, leading you to stumble onto concepts that are in fact unrelated but seem relevant because they similarly promote a separation of concerns.
But using
My wife and I want to eat out at different restaurants tonight. How do we divorce so we can go our own ways?
It's not that divorce is inherently a bad idea, it's just that it's not really relevant to the discussion as to what you have for dinner tonight, making it a bad (or at the very least unjustified) idea for the current question.
But example highlights another complication here: maybe there are other unmentioned/unrelated reasons that a divorce is a good idea. Or, in other words, maybe there are other reasons for why you'd want to use microservices.
Just because I now say that you shouldn't be using them, that doesn't mean that you should never use them, it only means that it's not an appropriate solution for the specific problem discussed here.
This makes it very hard to respond to your microservice idea, because I'd run the risk of (a) implying that microservices are always a bad idea or (b) implying that there will never be a reason for you to implement microservices. Neither is the case. It's just a matter of microservices being the wrong solution to this particular problem you've brought up.