Very good @VaugnVernon, I understood a lot his baseline and saw that dependency inversion very useful inside architectures and also with the adapter design pattern
I would also separate the adapters to separate Gradle projects (Maven modules), to ensure that people later on don't introduce the popular Spaghetti-pattern and introduce dependencies in the wrong directions. That would then necessitate an "Application" project that binds the internals and adapters together.
Right. You brought that up in Part 2 as well. I could do a brief follow up in the next video. I've done that before with Java but I'm not up to speed for how to do the same using a .NET build. I could just state that whatever build process you use could enforce the direction of dependencies.
Isn't that the whole point of P&A, direction of dependencies? In C# we also use projects to prevent dependencies going the wrong way since it doesn't allow circular references. However I much prefer the way F# deals with this by enforcing strict dependency ordering, even down to the function declarations in a file. Even though it may be a little annoying, it allows for code to become structured like P&A without even knowing about P&A.
Exactly. As an added benefit of using modules to separate model, application and infrastructure is that you no longer need packages to do so. Personally I like to use my packages to group domein specific stuff and use that name consistent over the the 3 modules. So here I would use a io.kalele.ecommerce.catalog package. There are two nice things about this imho: first, when opening the project one sees directly what this application is about. Secondly, in Java one can use the package scope for classes that don’t need to be accessible outside the catalog domain. E.g, nobody needs access to the PostgressCatalogRepository. Loved this series. Going to share them at work with the colleagues.
Thank you for the presentation! Looking forward to the next part! I want to ask about the Repositories' location, would you put all the repositories side by side with the models or create a repository package for them: model/repository? In our application, we're trying to follow the Ports&Adapters architectural pattern - we have a separate repository package for repositories outside the model package: application/repository.
@@VaughnVernon Not sure why I'm excited, but I am. Thanks for doing these btw! Wonder if you are familiar with the "Functional Event Sourcing Decider" work done by Jeremie chassaing? Any opinions on it? I'm currently working with a company that uses this encoding and it really feels like a breath of fresh air when comparing to other eventsourcing code. Pure functions are nice.
Hi Vaughn. Nice one, appreciate it. Though I have a couple of questions: 1. What if we need to persist our Catalog using third-party API? Would there be just another implementation of CatalogRepository interface? 2. What if we also need to generate a PDF view of the Catalog while persisting it? Where would that application logic for generating PDF live? Thanks.
Thanks! 1. Yes, sure. There are tradeoffs vs. temporary (or permanent) local storage followed by an API call. The details might get into the weeds so I'll stop there. 2. That introduces similar tradeoffs as with 1. Assuming you want the PDF generation to always happen, persisting the catalog data should occur first. Again, how you follow up with the PDF generation step is an implementation detail that I could cover in a later video.
When there aren't many use cases, it's fine, but as the number of use cases increases, I'm not sure if this architecture is good due to cognitive overload.
Why would the number of use cases make P&A less desirable and effective? Please provide a better alternative. If there are an overwhelming number of use cases in a single course-grained component and there's a large team working on it, you've got a different problem. You are missing a higher-level abstraction that is used to manage cognitive load.
I'd keep it simpler when it comes to packaging: - keep the app in the root of the package that hosts the bounded context, so in this case it would just have io.kalele.ecommerce and io.kalele.ecommerce.infra - avoid subpackaging the app, so I want to clearly see Catalog, CatalogRepository and CatalogService altogether, it makes it clear if the bounded context is growing too big I also have one question, I prefer not to use the word repository because it helps me think more about the language and the concept I am dealing with. For instance if I had a Product domain entity, I would probably call my repository ProductCatalog, rather than ProductRepository. In your example is there something in the domain that might actually be a better name candidate instead of CatalogRepository?
Very good @VaugnVernon, I understood a lot his baseline and saw that dependency inversion very useful inside architectures and also with the adapter design pattern
I would also separate the adapters to separate Gradle projects (Maven modules), to ensure that people later on don't introduce the popular Spaghetti-pattern and introduce dependencies in the wrong directions. That would then necessitate an "Application" project that binds the internals and adapters together.
Right. You brought that up in Part 2 as well. I could do a brief follow up in the next video. I've done that before with Java but I'm not up to speed for how to do the same using a .NET build. I could just state that whatever build process you use could enforce the direction of dependencies.
Isn't that the whole point of P&A, direction of dependencies? In C# we also use projects to prevent dependencies going the wrong way since it doesn't allow circular references.
However I much prefer the way F# deals with this by enforcing strict dependency ordering, even down to the function declarations in a file. Even though it may be a little annoying, it allows for code to become structured like P&A without even knowing about P&A.
Exactly. As an added benefit of using modules to separate model, application and infrastructure is that you no longer need packages to do so. Personally I like to use my packages to group domein specific stuff and use that name consistent over the the 3 modules. So here I would use a io.kalele.ecommerce.catalog package. There are two nice things about this imho: first, when opening the project one sees directly what this application is about. Secondly, in Java one can use the package scope for classes that don’t need to be accessible outside the catalog domain. E.g, nobody needs access to the PostgressCatalogRepository.
Loved this series. Going to share them at work with the colleagues.
Thank you Sir for all this sharing. Excellent content !
Thank you for the presentation! Looking forward to the next part!
I want to ask about the Repositories' location, would you put all the repositories side by side with the models or create a repository package for them: model/repository?
In our application, we're trying to follow the Ports&Adapters architectural pattern - we have a separate repository package for repositories outside the model package: application/repository.
@8:22 now I'm curious why wouldn't you use application services? Anybody guess?
Follow-up topic soon, but this one involves more time.
@@VaughnVernon Not sure why I'm excited, but I am. Thanks for doing these btw!
Wonder if you are familiar with the "Functional Event Sourcing Decider" work done by Jeremie chassaing? Any opinions on it?
I'm currently working with a company that uses this encoding and it really feels like a breath of fresh air when comparing to other eventsourcing code. Pure functions are nice.
Hi Vaughn. Nice one, appreciate it. Though I have a couple of questions:
1. What if we need to persist our Catalog using third-party API? Would there be just another implementation of CatalogRepository interface?
2. What if we also need to generate a PDF view of the Catalog while persisting it? Where would that application logic for generating PDF live?
Thanks.
Thanks!
1. Yes, sure. There are tradeoffs vs. temporary (or permanent) local storage followed by an API call. The details might get into the weeds so I'll stop there.
2. That introduces similar tradeoffs as with 1. Assuming you want the PDF generation to always happen, persisting the catalog data should occur first. Again, how you follow up with the PDF generation step is an implementation detail that I could cover in a later video.
@@VaughnVernon Thanks a lot. Would be great to cover the details in your upcoming videos.
When there aren't many use cases, it's fine, but as the number of use cases increases, I'm not sure if this architecture is good due to cognitive overload.
Why would the number of use cases make P&A less desirable and effective? Please provide a better alternative.
If there are an overwhelming number of use cases in a single course-grained component and there's a large team working on it, you've got a different problem. You are missing a higher-level abstraction that is used to manage cognitive load.
I'd keep it simpler when it comes to packaging:
- keep the app in the root of the package that hosts the bounded context, so in this case it would just have io.kalele.ecommerce and io.kalele.ecommerce.infra
- avoid subpackaging the app, so I want to clearly see Catalog, CatalogRepository and CatalogService altogether, it makes it clear if the bounded context is growing too big
I also have one question, I prefer not to use the word repository because it helps me think more about the language and the concept I am dealing with. For instance if I had a Product domain entity, I would probably call my repository ProductCatalog, rather than ProductRepository. In your example is there something in the domain that might actually be a better name candidate instead of CatalogRepository?