In my latest Spring Boot 3 tutorial, I adopted the "Package by Feature" approach. In my old Spring Boot 2 tutorial, for the same running example, I used the "Package by Layer" approach. If you are interested, please take a look. Feel free to provide any feedback.
@DanVega waiting on the above request. Just a reminder. That will be really helpful for community as there is so much of confusion around this concepts which and how to use.
Love it! I was iffy about posing this question in office hours a few months back, but after seeing how much engagement there is on this video I'm so glad I did and am not the only one that was interested!
Thanks, Dan - this is very insightful as always! Aside from just sounding right, generally speaking, the biggest upside for me is the ease with which you can fork out a microservice when packaging by feature (and maybe modularity to a certain extent). That is a good litmus test on how cohesive and less coupled your code is. But then, you don’t create new projects every day, so you’re basically stuck with whatever the original authors intended, and that’s usually packaging by layer.
Hi Dan. Thank you for another great video. I clearly see the benefits of the package by feature approach. However, I am wondering what your opinion is on implementing relationships between the entities. For low coupling I imagine that every package would only have one single point of entry for other packages (e.g. a service or interface exposed to be used by other features). In which case how would you go about designing the relationships between the entities? You ofc won't be able to leverage the Spring Data JPA annotations so I guess you would create DTOs between the features (which, in my opinion, may introduce unnecessary complexity depending on the size of the project). And maybe just storing the id of the referenced entity? Is some leakage acceptable? Let me hear your opinion, thank you! :)
I packaged by layer for years. Until I saw some people packaging by feature and I thought that was a crazy idea. Until I tried it myself. I found package by feature is very nice for large projects. No going back for me.
I generally work by packaging by feature and then layers within as you mentioned at the end. In my code each feature module stays quite compact but the additional layer packages give me a bit of structure and make it easier to navigate the code. Its usually up to 20 files per feature, 2-3 services, 7-10 use case interfaces, entities, DTO-s for Inputs and outputs, filtering etc.. I think the boundaries between features are clear and not an issue at all even though i lose the package visibility benefit of packaging by feature in a flat package. What i really struggle with is having Data JPA relationships having references to other feature entities. I feel like Data JPA is not well suited for this way of structuring code, or I am not using it correctly. So as an example in sports, having a "Matches" Feature, and a "Teams" feature, where a match references a team, but a team is also standalone. So if i just use teamId in match its really hard to query (lets say i want to get a list of matches filtered by a specific team), so i have a JPA OnetoMany relationship there.
what about a package strucuture with 4 main packages: api (containing other packages such as controller, mappers/assemblers, listeners), domain, core, infrastructure? Then the tradicional layer package within domain, core and infra?
I generally prefer package-by-feature. But: I also like API-first development (generating controller interfaces using OpenAPI Generator for example) and I feel it clashes a little with the package-by-feature approach, because you generate an entire "layer" (the controllers) in one go, and all the results tend to be put in the same package. Is there a solution to this apparent tension?
Very interesting discussion indeed. If a service A need a service B datas to build a response, how you handle this in feature design. You need to keep public accessor, is n it ?
I think your article lacks the "comment" implementation to make clear the boundaries of layer vs feature, to show us how comment and post will relate to each other.
I also like this approach the best but I have a question. When I access from a service in one package to another service or a repository etc. in a different package, is that OK? My second question is is there a resource like a book or video series or something similar to learn more about this approach in more details?
is it possible to do a packaging by layer inside the features , in my case i have a lot of DTOs and and sevral repositories since the feature containe many entities , and i want to know is it correct to split them by layers inside the feature package ?
What should be done when a model in a feature package has a relation with other models outside of the feature package, such as when a Post model has a relation with a Comment model? Is there any way to handle that?
Hi Dan, In a scenario where the API-First methodology is employed, and we have an openapi.yml file representing all the operations of our API (in this case, the blog API), I understand that in the case of a layered architecture, we would typically have a BlogController where we implement all our methods. However, in the case of adopting a feature-based architecture, would we create a separate openapi file for each feature, where the specific functionality is implemented? Or would we follow a similar approach as in the layered architecture by sharing this interface among all the features in some way?
Application specs are typically in one file with multiple endpoints. That file doesn’t have to be in the repo at all if there is a dedicated place for the specs of the services.
There is nothing special. Unit tests are still match the package structure and each test class would test each class with some non-trivial logic. I see some devs are testing getters, which is out of my mind…
I am mixing both types. I found that keeping packages such as: configuration, entities, controller, dtos, and mappers as "Package by Layer" works well, but I organize all services in the following manner: services ---- product -------- business In this package, you can find our main code. Everything we have to write manually, come up with, etc., is because it's business-related. This package should also be tested 100% by unit tests. -------- data Here we have a package where we can find all the classes from which we obtain data for a product. We can source this data from databases, external services, etc. There is no logic; the primary responsibility is simply to retrieve raw data from external sources. I find this structure the most readable. I disliked searching for controllers or entities using "Package by Feature". On the other hand, writing clean code with tons of business classes in "Package by Layer" is not possible, or at least I've never seen it done.
This all makes sense until we begin doing something more complicated. Let's say we have Authors, who write the posts. Naturally we want our entites to have relations. This way we no longer can make entity classes package-private. We also create coupling. In the end, the whole idea of package by feature becomes not viable. At least not in the way presented in the video. In my experience module will always contain all the stuff, which is related to each other in some way. An we come back again to package by layer. True modularity is possible only on not related stuff. e.g. i18n module for our FE. What do you think about that?
This was my thought originally too. But if we look at the "loose" wording for coupling and not the fact that it's "no coupling", I think we can make an argument that some features can be coupled. In your example, if we had an "author" we might also have some other higher level models like "user" or "settings" or something like that. We could easily make a "top_level" package as a "feature" that contains these items. So say we now have a feature packaged app as follows, we still have loose coupling overall. Only the top level package is coupled to other packages. Auth doesn't care about post at all. So our structure isn't completely coupled, it's just loosely coupled. |-> post |-> postModel |-> postService |-> auth |-> authModel |-> topLevel |-> userModel |-> settingsModel |-> authorModel If we ever want to break this out to a microservices pattern in the future, we would be able to fairly easily. The top level package can become a service on it's own, while auth and post get pulled out as well. As you mentioned, in complex environments, you need SOME level of coupling. The Design Principle is to limit that coupling as much as possible. (this is an example I came up with in 10 seconds while reading comments on this post, please do not read explicitly into it. I'm just using it as an example of the thought process)
the only advantages of having maven modules are if you have different teams taking care of the same software. Usually a maven module project is bundled to only one jar or war.
I'd usually store them by according to their scope. For example, I keep Global Exception Handler under web package as it's about translating Exceptions to HTTP status.
These are part of configuration for the application, they all can be package private, if too many classes clogging the configuration package, then regroup them inside of the configuration.
Thanks for video but too much time spent on explaining package scanning. I have been worked on different projects and can say that if there is a shortcut, good lazy developer will take it. Using any of mentioned approaches without discipline will sooner or later lead to spaghetti code and dependency mix. Personally, hexagonal architecture seems like overhead at the beginning but it puts constraints and at the end there is benefit from it. All the best!
For a total beginner this video is packed with useful information. Thanks for explaining it in Layman's terms.
So glad that you found this useful, thank you!
Dan, it would be great a demo with a comparison of Hexagonal architecture ,Layer, Package
We are working towards that...one step at a time.
Hexagonal architecture just makes unnecessary complexity to your project.
In my latest Spring Boot 3 tutorial, I adopted the "Package by Feature" approach. In my old Spring Boot 2 tutorial, for the same running example, I used the "Package by Layer" approach.
If you are interested, please take a look. Feel free to provide any feedback.
@DanVega waiting on the above request. Just a reminder. That will be really helpful for community as there is so much of confusion around this concepts which and how to use.
Love it! I was iffy about posing this question in office hours a few months back, but after seeing how much engagement there is on this video I'm so glad I did and am not the only one that was interested!
Killing it... always love to watch your videos 😉
This was very useful. You've just gained a new subscriber in me!
Thanks, Dan - this is very insightful as always!
Aside from just sounding right, generally speaking, the biggest upside for me is the ease with which you can fork out a microservice when packaging by feature (and maybe modularity to a certain extent). That is a good litmus test on how cohesive and less coupled your code is.
But then, you don’t create new projects every day, so you’re basically stuck with whatever the original authors intended, and that’s usually packaging by layer.
Hi Dan. Thank you for another great video.
I clearly see the benefits of the package by feature approach. However, I am wondering what your opinion is on implementing relationships between the entities. For low coupling I imagine that every package would only have one single point of entry for other packages (e.g. a service or interface exposed to be used by other features). In which case how would you go about designing the relationships between the entities? You ofc won't be able to leverage the Spring Data JPA annotations so I guess you would create DTOs between the features (which, in my opinion, may introduce unnecessary complexity depending on the size of the project). And maybe just storing the id of the referenced entity? Is some leakage acceptable?
Let me hear your opinion, thank you! :)
Short video but proving the good overview. Thanks for that.
Glad it helped
Dan, thanks for the video, it was helpful.
Good video. Thanks for making such useful videos
Thank you for watching them David!
Great article/video! Thank you!
Thank you!
I packaged by layer for years. Until I saw some people packaging by feature and I thought that was a crazy idea. Until I tried it myself. I found package by feature is very nice for large projects. No going back for me.
Thanks for sharing!
I generally work by packaging by feature and then layers within as you mentioned at the end. In my code each feature module stays quite compact but the additional layer packages give me a bit of structure and make it easier to navigate the code. Its usually up to 20 files per feature, 2-3 services, 7-10 use case interfaces, entities, DTO-s for Inputs and outputs, filtering etc.. I think the boundaries between features are clear and not an issue at all even though i lose the package visibility benefit of packaging by feature in a flat package.
What i really struggle with is having Data JPA relationships having references to other feature entities. I feel like Data JPA is not well suited for this way of structuring code, or I am not using it correctly.
So as an example in sports, having a "Matches" Feature, and a "Teams" feature, where a match references a team, but a team is also standalone. So if i just use teamId in match its really hard to query (lets say i want to get a list of matches filtered by a specific team), so i have a JPA OnetoMany relationship there.
Really great explaination!
In package by feature, would you put a security config into a config package, or a security package? What about a controller advice?
I put them of a package called shared/configs/SecurityConfig
I do package by feature 100% of the time.
What is the best way to structure junit tests with package by feature?
@@PeterSarazinthat would be exactly the same package structure, not matter what architecture you use. The test should match exactly the same.
what about a package strucuture with 4 main packages: api (containing other packages such as controller, mappers/assemblers, listeners), domain, core, infrastructure? Then the tradicional layer package within domain, core and infra?
Great video
If you doing monolithic apps package feature is more maintainable for microservices package by layer.
I generally prefer package-by-feature. But: I also like API-first development (generating controller interfaces using OpenAPI Generator for example) and I feel it clashes a little with the package-by-feature approach, because you generate an entire "layer" (the controllers) in one go, and all the results tend to be put in the same package. Is there a solution to this apparent tension?
X2
Thanks Dan
Very interesting discussion indeed. If a service A need a service B datas to build a response, how you handle this in feature design. You need to keep public accessor, is n it ?
Shouldn't we call packages plural like controllers, models?
Or that's just up to us to call model or models?
How do I get the spring tool on the sidebar so I can see what spring beans are in application context?
I think your article lacks the "comment" implementation to make clear the boundaries of layer vs feature, to show us how comment and post will relate to each other.
Agree that can also be a discussion on DDD
What do you think about multi-module approach?
I also like this approach the best but I have a question. When I access from a service in one package to another service or a repository etc. in a different package, is that OK?
My second question is is there a resource like a book or video series or something similar to learn more about this approach in more details?
Coupling between layers can be mitigated by interfaces, no?
is it possible to do a packaging by layer inside the features , in my case i have a lot of DTOs and and sevral repositories since the feature containe many entities , and i want to know is it correct to split them by layers inside the feature package ?
Just the GOAT
You just mae my day!
How will test be written if the classes are not public in the package by feature version?
What should be done when a model in a feature package has a relation with other models outside of the feature package, such as when a Post model has a relation with a Comment model? Is there any way to handle that?
Shared classes are going to have a public access and moved to another package within other feature packages, like a common.
Hi Dan,
In a scenario where the API-First methodology is employed, and we have an openapi.yml file representing all the operations of our API (in this case, the blog API), I understand that in the case of a layered architecture, we would typically have a BlogController where we implement all our methods. However, in the case of adopting a feature-based architecture, would we create a separate openapi file for each feature, where the specific functionality is implemented? Or would we follow a similar approach as in the layered architecture by sharing this interface among all the features in some way?
Application specs are typically in one file with multiple endpoints. That file doesn’t have to be in the repo at all if there is a dedicated place for the specs of the services.
Thanks for doing this
What is the best way to structure junit tests with package by feature? Are there any examples of this?
There is nothing special. Unit tests are still match the package structure and each test class would test each class with some non-trivial logic. I see some devs are testing getters, which is out of my mind…
I am mixing both types. I found that keeping packages such as: configuration, entities, controller, dtos, and mappers as "Package by Layer" works well, but I organize all services in the following manner:
services
---- product
-------- business
In this package, you can find our main code. Everything we have to write manually, come up with, etc., is because it's business-related. This package should also be tested 100% by unit tests.
-------- data
Here we have a package where we can find all the classes from which we obtain data for a product. We can source this data from databases, external services, etc. There is no logic; the primary responsibility is simply to retrieve raw data from external sources.
I find this structure the most readable. I disliked searching for controllers or entities using "Package by Feature". On the other hand, writing clean code with tons of business classes in "Package by Layer" is not possible, or at least I've never seen it done.
thankyou sir of such contents
This all makes sense until we begin doing something more complicated. Let's say we have Authors, who write the posts. Naturally we want our entites to have relations. This way we no longer can make entity classes package-private. We also create coupling. In the end, the whole idea of package by feature becomes not viable. At least not in the way presented in the video. In my experience module will always contain all the stuff, which is related to each other in some way. An we come back again to package by layer. True modularity is possible only on not related stuff. e.g. i18n module for our FE.
What do you think about that?
This was my thought originally too. But if we look at the "loose" wording for coupling and not the fact that it's "no coupling", I think we can make an argument that some features can be coupled. In your example, if we had an "author" we might also have some other higher level models like "user" or "settings" or something like that. We could easily make a "top_level" package as a "feature" that contains these items.
So say we now have a feature packaged app as follows, we still have loose coupling overall. Only the top level package is coupled to other packages. Auth doesn't care about post at all. So our structure isn't completely coupled, it's just loosely coupled.
|-> post
|-> postModel
|-> postService
|-> auth
|-> authModel
|-> topLevel
|-> userModel
|-> settingsModel
|-> authorModel
If we ever want to break this out to a microservices pattern in the future, we would be able to fairly easily. The top level package can become a service on it's own, while auth and post get pulled out as well.
As you mentioned, in complex environments, you need SOME level of coupling. The Design Principle is to limit that coupling as much as possible.
(this is an example I came up with in 10 seconds while reading comments on this post, please do not read explicitly into it. I'm just using it as an example of the thought process)
@DanVega Could you also make a video comparing java packages vs maven modules when structuring your application
the only advantages of having maven modules are if you have different teams taking care of the same software. Usually a maven module project is bundled to only one jar or war.
i have to try package by feature one day. But i wonder what happens when i have 50 domain objects for different services
Common or if used in multiple services, then a dedicated library, then pull that as a dependency.
Code explosion. All classes except for the Service differ(almost) only in name. Should they even exist?
Great Explanation!!
What about Global Exception Handler and Security configurations in package like feature structure?
I'd usually store them by according to their scope. For example, I keep Global Exception Handler under web package as it's about translating Exceptions to HTTP status.
These are part of configuration for the application, they all can be package private, if too many classes clogging the configuration package, then regroup them inside of the configuration.
Thanks for video but too much time spent on explaining package scanning.
I have been worked on different projects and can say that if there is a shortcut, good lazy developer will take it.
Using any of mentioned approaches without discipline will sooner or later lead to spaghetti code and dependency mix.
Personally, hexagonal architecture seems like overhead at the beginning but it puts constraints and at the end there is benefit from it.
All the best!