jhipster / generator-jhipster

JHipster is a development platform to quickly generate, develop, & deploy modern web applications & microservice architectures.
https://www.jhipster.tech
Apache License 2.0
21.27k stars 4k forks source link

DDD approach in JHipster #11122

Closed hdurix closed 3 years ago

hdurix commented 4 years ago

DDD approach

For now, JHipster is only able to create CRUD entities and JHipster's goal is to help developers in building all the technical aspect of an application. It could be interesting to explore how JHipster could also help them build the "business" of the application. One approach for that is the methodology called Domain Driven Design.

Why this ticket?

This ticket is to:

First step

I would like to work on a application generated by JHipster and to refactor it in order to bring DDD concepts (aggregates, entities, value objects, domain events, ...) and have example to show and to discuss about.

More to come...

If some of you have experience with bringing DDD concepts to a JHipster application, feel free to participate, to give ideas and feedback.

pascalgrimaud commented 4 years ago

For me, it is a must have. It can be helped by repositories as example, by documentation, by modifying the current generated code etc... There is a lot of work I think, so I'm putting a big bounty on this. You'll be the lead on this part @hdurix, don't hesitate to ask help

pascalgrimaud commented 4 years ago

cc @nonomoho as you probably have ideas on this

johnbanq commented 4 years ago

I think the most important part of DDD lies in the strategic patterns(bounded contexts and context mapping) instead of the tatics patterns(repositories, aggregates etc). As long as you have a clear separation of contexts, a good idea of their relationships and a conceptual model within each context, you are using DDD even you are just CRUDing all the way through in each these contexts.

So perhaps we should start by telling people how to organize their code by contexts and apply “clean architecture“ within some key context which have a relatively complex domain model, instead of going for the tactics patterns right away?

huytmb commented 4 years ago

I completely agree with @johnbanq advice. In early phase, starting with "clean architecture" for complex domain model.

gmarziou commented 4 years ago

Do you have a specific flavor of "clean architecture" in mind? Hexagonal, onion, ... Personally I like the modulith approach: package by feature/context and using spring events for inter module communication

mohamedzaki90 commented 4 years ago

@gmarziou spring events have the problem of lost events if an exception happens during event publication, listeners will never get notified

gmarziou commented 4 years ago

@mohamedzaki90 Well, I never experienced this in my apps, do you have some reference to share?

My understanding is that if an exception is thrown during event publication, the publisher will get it and its transaction will rollback. So I can't imagine how you could lose an event at least in a transactional context. If you' re not in a transaction, then you will have to catch and manage the exception.

mohamedzaki90 commented 4 years ago

@gmarziou take a look at the caveats here https://www.baeldung.com/spring-data-ddd

here's a proposed workaround (by the author of @Modulith) https://github.com/odrotbohm/spring-domain-events

gmarziou commented 4 years ago

Thanks, I have never experienced this case maybe because I always used them inside a transaction and recording state change in database both from publisher and listeners, and then scheduling retry for unprocessed changes.

gmarziou commented 4 years ago

Interesting DSL: https://www.innoq.com/en/blog/code-your-model/

johnbanq commented 4 years ago

Do you have a specific flavor of "clean architecture" in mind? Hexagonal, onion, ... Personally I like the modulith approach: package by feature/context and using spring events for inter module communication

My take on this is pretty much the same, build modulith and use a hexagon-ish architecture in each of the contexts but I also allow cross-context communication by calling interfaces in a dedicated "api" package in each context(the implementation of the interfaces are provided by DI).

Maybe we can build a small sample that demonstrates this as a starting point? PetClinic might be a good project to start

ksilz commented 4 years ago

@hdurix I hope to start on my first DDD JHipster / Angular application on Feb 1. To me, DDD has two advantages:

phipex commented 4 years ago

It seems to me that a functionality associated with this tickect could be to create a multi-module project with the same notation in JDL of microservices, that is to say, use the same microservice notation to map DDD modules, said roughly, the possibility of having microservices packaged in the same application.

pascalgrimaud commented 4 years ago

@hdurix : what is the state of this ticket ?

avdev4j commented 3 years ago

hi @hdurix, do we have to consider this ticket for the v7?

ksilz commented 3 years ago

@hdurix After close to 5 months of using DDD with JHipster, I can wholeheartedly recommend this approach:

ecostanzi commented 3 years ago

@ksilz that's interesting. Are you willing to share more details about the project structure? As @johnbanq suggested, we should start with some samples.

desprez commented 3 years ago

DDD strategic patterns are just a way of naming, delineating and organizing concepts. I think developers who want to use a DDD approach in their project want to be able to use tactical DDD patterns. In my opinion, the biggest challenge with the DDD approach in JHIPSTER is to model the processing and the business rules inside the entities which will be overwritten during the next regeneration. The “side by side” approach does not work well in this case without making the domain model more complex, which we especially don't want in DDD. Another thing, it is also currently impossible to model concepts in JDL using ValueObjects. It can be a good start ...

ksilz commented 3 years ago

@ksilz that's interesting. Are you willing to share more details about the project structure?

@ecostanzi Sure! In my current projects, I have three goals:

  1. Keep doing JHipster upgrades: Since the upgrade regenerates all files, I keep my changes as much away from "JHipster files" as possible. For instance, I have my own Gradle build file that the main build file includes. I don't add query methods to the Spring JPA repository files; instead, they extend my own interface where I put my methods. And I have my own set of Docker files.
  2. Use and "extend" JDL: I have both my application and my entities defined in JDL files. I don't touch the JHipster generated files anymore but update the entity JDLs so that they accurately reflect my data model. But I do have some columns/fields that all my entities share. So through a shell script, I make all the required changes, like adding database columns to the Liquibase DB scripts and setting base classes for my entity classes and DTOs.
  3. Use DDD & clean architecture: This is my first DDD project with a clean architecture. I have my own, handwritten Angular UI und my own Java backend. But I use the JHipster back-end code, either starting that the service method level (with DTOs) or at the JPA query level, as my "persistence layer". I currently have four different bounded domains. In my code, there's a "clean" package/folder where all my code resides. That's a standard clean architecture layout in Java: The application/port/in folder has the use case, application/port/out the ports, and application the services that implement the use case with the help of the ports. adapter/out has the adapters implementing my ports, and adapter/in the REST controllers. My domain classes are in domain. Angular is nearly the same: It's missing the application/port/in folder but has a ui folder with Angular UI modules. I still have JHipster generate an Angular UI, but I disabled its loading and move all these UI files into a separate folder outside of src (just in case I want to see how something is done there in the latest JHipster version).
pascalgrimaud commented 3 years ago

This approach in JHipster is something a lot of people want: it's in V7 roadmap.

But as this ticket has been opened since january, so I'd like to know if someone is willing to work on this. Otherwise, I'll remove this ticket from our roadmap.

Anyway, the sample app can be coded during JHipster Code, and probably the templates would be for the next major version V8, in 1 or 2 years.

cc @hdurix @jhipster/developers @johnbanq @huytmb @ksilz

murdos commented 3 years ago

I plan to work at some point on extending what has been called embedded entities - which could be seen as ValueObjects - currently supported only for MongoDB and Couchbase, to other databases that could be supported (SQL, Cassandra, ...), because IMO ValueObjects are a must have for DDD approach. Not sure I can do it for V7, but since it would be a new feature without breaking change, it doesn't have to wait for a major release.

ksilz commented 3 years ago

@pascalgrimaud I didn't find any good documentation on "How to make JHipster upgrades less painful", beyond these two presentations from 2019 and 2018. What is a good place for me to share my lessons learned?

pascalgrimaud commented 3 years ago

@ksilz : really sorry I didn't saw you mentioned me. Use what you want:

For your information, at JHipster Code, we'll have a live stream Twitch and we'll talk about Hexagonal Architecture, so it will be really interesting I'm sure ;)

ksilz commented 3 years ago

@pascalgrimaud Thank you for your reply! I'll watch the conference videos for sure! My current project is a JHipster Angular application, soon with Flutter apps for iOS & Android. Using the same clean architecture in two platforms (Java, Angular) has helped a lot. Using the same approach in Flutter will make my life easier.

DamnClin commented 3 years ago

Here is the example application produced during JHipster code: https://gitlab.com/cdamon/padbowl feel free to use any part you want.

Replays of the live will come as soon as we finished editing them

pascalgrimaud commented 3 years ago

thanks a lot @DamnClin ! Sure it will help a lot

hdurix commented 3 years ago

Wooow that's HUGE! I didn't have the opportunity to watch the live video yet but the code is a really great example of how DDD can be applied in a JHipster project.

A big thanks to @DamnClin!

I'm sure that adding this video (with the GitLab repository link) to a dedicated section in jhipster.tech would help a lot of people wishing to understand how DDD can be used in a JHipster project.

pascalgrimaud commented 3 years ago

I agree @hdurix so I'm proposing this:

Then, after that, I think the bounty is for @DamnClin ! Really well deserved

About Hexagonal Architecture, it can't be done for v7. There are too much work in our template. But we can start it in a blueprint or for v8. But for V8, we'll have it !

mshima commented 3 years ago

@pascalgrimaud just to let you know I plan to work on this sooner. Probably next month. Currently I am applying DDD to projects ignoring the fact everything is monolith for now.

I have plan to create the following structure for Foo entity and Bar domain:

Without this basic structure, it's really difficult to create blueprints for DDD approach.

I am using spring events and hibernate events, which aren't scalable. They would fit as blueprints, but don't have plans to do it.

Thoughts?

pascalgrimaud commented 3 years ago

It's similar to https://gitlab.com/cdamon/padbowl/-/tree/master/src/main/java/com/jhipster/padbowl/game :

For blueprint, I thought about changing destination of folder. Instead of moving to "repository/", moving to "infrastructure/secondary", etc... That's why I think a blueprint would be not so difficult. And maybe directly in generator-jhipster too. But I need time to think more :D

mshima commented 3 years ago

I don't like infrastructure and primary/secondary naming. Infrastructure as a non native speaker means something physical, it should be something more generic as adapter or port. Primary/secondary means importance but I think they are just adapters/ports, every one doing it's job.

Replaced rest with web, it's more specific. I have implemented adapter/event and adapter/monolith. I created monolith has a service abstraction form keeping domains independent, so they communicate using adapter/monolith/*Service.

pascalgrimaud commented 3 years ago

yes, the final name can be discussed and maybe could be customized, as I've seen so different namings

as you seem very active these last months, do you think it could be possible to have this for JHipster v7 ?

Of course, all the team need to agree

mshima commented 3 years ago

@pascalgrimaud yes, it's possible, but this new rule to require reviews can complicate, most of my PRs are related to the generator, and they stay most of the time unreviewed forever just like the incremental changelog one that you said to merge it after almost 1 month. My workflow was: create PRs, keep them open for 2-7 days (new features I kept longer) depending on how certain I was about the implementation, then If no feedback was given, I went ahead and merge. I have 4 PRs ready, I think they can be merged, but the angular one I would keep open longer. In my opinion this change should be reverted or we should implement code owners so a member of a team could commit to some files without requiring reviews.

IMO the basic task are:

After that, we should discuss domain isolation.

pascalgrimaud commented 3 years ago

I agree with you. We should not block workflow and go on cc @deepu105 : do you agree to remove the last rule about asking each PR to be approved ?

DamnClin commented 3 years ago

@mshima I don't think using web / repository or some other protocol / pattern specific naming for adapters is a good idea because you'll have other type of adapters as soon as you need orchestration between your contexts (just an example).

Perhaps driving (for primary) and driven (for secondary) can be good candidates as they speak what they are doing. I like using primary and secondary simply because it's the name you'll find most of time since they are coming from Alistair : "In implementation, ports and adapters show up in two flavors, which I’ll call ‘’primary’’ and ‘’secondary’’, for soon-to-be-obvious reasons. They could be also called ‘’driving’’ adapters and ‘’driven’’ adapters.".

Using this kind of architecture without breaking it's principle is hard enough when you are not used to it so I try to stick to some well known references.

For the "infrastructure" level I think all naming can be good as soon as it exists, I think "outside" can also be good (same, i don't really using a pattern name for a package (module if we stick to ddd)).

@pascalgrimaud I was also think about a fun idea to help people stick to this architecture: blocking all spring dependencies in **/domain. This shouldn't be hard to do an may be a good help.

BUT, as i sayed many time during that day: I'm not a JHipster contributor (and probably never will be) so, those are just my though on this. It's easy for me since I'm only here to criticize :D. Of course, this in just an advice of a guy doing this (and really enjoying the approach) on multiple products for a year now. Take it as an advice, nothing more !

pascalgrimaud commented 3 years ago

@DamnClin : about blocking spring dependencies in /domain, it's easy to do with ArchUnit. This librairies is there for this specific reason, something like: `all class in /domain should not import org.springframework.* `

Then, we can add more rules of courses.

DamnClin commented 3 years ago

Bounty claim: https://opencollective.com/generator-jhipster/expenses/25541

pascalgrimaud commented 3 years ago

thanks a lot @DamnClin : approved

deepu105 commented 3 years ago

@pascalgrimaud if you think thats appropriate its ok for me. Anyway my aim was just to disable direct commit to master without PR. The review rule was just a way to achieve it

deepu105 commented 3 years ago

I don't know if we should do a drastic breaking change of folder structure closer to release. I assume this would break all server side blueprints. We should have atleast communicated earlier to give blueprints authors time to prepare. Else we should do it as an option but then it will be maintainance burden unless we find some smart solutions

On Sat, 26 Sep 2020, 8:40 am Pascal Grimaud, notifications@github.com wrote:

thanks a lot @DamnClin https://github.com/DamnClin : approved

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/jhipster/generator-jhipster/issues/11122#issuecomment-699440584, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAIOKF3FTQ65RLW6YQGYLY3SHWEHTANCNFSM4KGXDFYQ .

DevAlves1993 commented 3 years ago

Hello,

I would like to propose the following hierarchy for the domain package and application package, the objective being to have a hierarchy quite close to the principles defined by the Domain Driven Design and Hexagonal Architecture.

Domain Layer

├───domain/
│   ├───entity/
│   ├───objectvalue/
│   ├───exception/
│   ├───service/
SUB-DIRECTORY CONTENT REQUIRED
Entity The business entities of the domain. Yes
ValueObject The business value objects of the domain. No
Exception Business exceptions in the domain. No
Service Business Domain Service. No

Application Layer

├───application/
│   ├───usecase/
│   ├───command/
│   ├───commandhandler/
│   ├───queries/
│   ├───port/
SUB-DIRECTORY CONTENT REQUIRED
UseCase The use cases are the processes that can be triggered in our Application Core by one or several User Interfaces in our application. Yes
Command The commands used in use cases supported by the command handler. Yes
CommandHandler The Command Handlers. Yes
Queries Query Managers or Handlers. No
Port Secondary ports. No
DTO Data transfert object No

The Command Handlers can be used in two different ways:

The secondary ports will be interfaces implemented in the infrastructure. Typically, their role is to :

pascalgrimaud commented 3 years ago

@deepu105 : I'm not sure we are closer to the release. There are still some work to achieve. Then, we should not target a specific date, it will be released when it's ready. Major version is perfect to introduce breaking changes. We should not be afraid about that.

Otherwise, we'll need to wait V8, it will be in 2 years

Then, this ticket is opened since January so the users are already aware of that

DamnClin commented 3 years ago

@DevAlves1993 I strongly advise against this as this is totally the opposite of DDD principles. In DDD modules (packages in Java) are parts of the Ubiquituous Language. Packaging by feature allow really better designs, one of the main goal of this package organization is to keep an high cohesion in each module.

We don't really need to see immediately if some class is an Aggregate or a Value Object since it will be obvious when looking at the APIs. We do really need to know what business logic stands in a given module.

Another important thing: ports, queries and command are part of the domain otherwise you'll have to break the: "Everything depends on the domain, the domain depends on nothing" principle. The application layer must remain really thin: for a given context there is no need to split it.

mshima commented 3 years ago

@pascalgrimaud the changes I will implement are opt-in, so traditional generation will be applied if no domain is specified. About your hexagonal project, I think we shouldn't convert the main application/user management into domain for v7 by default but it would be ok with opt-in. But it's really cool to test different package structure.

pascalgrimaud commented 3 years ago

@mshima : I'm beginner in this kind of architecture, don't rely on my project, I only played this morning with JHipster, and did some refactoring/renaming folder, nothing more

If we can keep both type of generation, I afraid it will be a lot of stuff to maintain...

Let's keep on thinking and discussing about how to deal with the future of JHipster

cc @jhipster/developers : your opinion is important here. Should we change the JHipster folder to match with an Hexagonal Architecture or is it too early ?

DevAlves1993 commented 3 years ago

@DamnClin

Another important thing: ports, queries and command are part of the domain otherwise you'll have to break the: "Everything depends on the domain, the domain depends on nothing" principle. The application layer must remain really thin: for a given context there is no need to split it.

I agree with you ports, queries and command are part of the domain. The mention "Application Layer" can be confusing, I would have said "Application Business Rule". I define the domain as the combination of the Application Business Rule and the Enterprise Business Rule and the fact that the Application Business Rule is closely related to the Enterprise Business Rule.

Packaging by feature allow really better designs, one of the main goal of this package organization is to keep an high cohesion in each module.

Indeed, an organization by functionality would be the best and would be closer to the representation of the company. What is your definition of the word "feature", is it a sub-domain or a delimited context or both?

Personal opinion : Enterprise Business Rule and Application Business Rule must be as pure as possible, it must not depend on external elements (framework & co). Nevertheless, Application Business Rule can depend on hundreds of libraries (also quite pure) such as the Javax Validation library.

New proposals

First proposal

├───domain/
│   ├───subdomain1/
│       ├───entity/
│       ├───objectvalue/
│       ├───exception/
│       ├───service/
│       ├───command/
│       ├───commandhandler/
│       ├───queries/
│       ├───port/
│  ├───subdomain2/
│       ├───entity/
│       ├───objectvalue/
│       ├───exception/
│       ├───service/
│       ├───command/
│       ├───commandhandler/
│       ├───queries/
│       ├───port/
├───application/
│   ├───usecase/
├───infrastructure/
│   ├───primary/
│      ├───rest/
│      ├───cli/
│   ├───secondary/
│      ├───repository/
│      ├───entity/
│      ├───service/
│      ├───config/
│      ├───otherspackage/

or

├───domain/
│   ├───subdomain1/
│       ├───.... (java files)/
│  ├───subdomain2/
│       ├───.... (java files)/
├───application/
│   ├───usecase/
├───infrastructure/
│   ├───primary/
│      ├───rest/
│      ├───cli/
│   ├───secondary/
│      ├───repository/
│      ├───entity/
│      ├───service/
│      ├───config/
│      ├───otherspackage/

Second proposal

├───domain/
│   ├───application/
│       ├───usecase/
│   ├───subdomain1/
│       ├───entity/
│       ├───objectvalue/
│       ├───exception/
│       ├───service/
│       ├───command/
│       ├───commandhandler/
│       ├───queries/
│       ├───port/
│   ├───subdomain2/
│       ├───entity/
│       ├───objectvalue/
│       ├───exception/
│       ├───service/
│       ├───command/
│       ├───commandhandler/
│       ├───queries/
│       ├───port/
├───infrastructure/
│   ├───primary/
│       ├───rest/
│       ├───cli/
│   ├───secondary/
│       ├───repository/
│       ├───entity/
│       ├───service/
│       ├───config/
│       ├───otherspackage/

or

├───domain/
│   ├───application/
│       ├───usecase/
│  ├───subdomain1/
│       ├───.... (java files)/
│  ├───subdomain2/
│       ├───.... (java files)/
├───infrastructure/
│   ├───primary/
│      ├───rest/
│      ├───cli/
│   ├───secondary/
│      ├───repository/
│      ├───entity/
│      ├───service/
│      ├───config/
│      ├───otherspackage/

Third proposal

├───domain/
│   ├───subdomain1/
│       ├───application(Application Business Rule)/
│            ├───usecase/
│            ├───command/
│            ├───commandhandler/
│            ├───queries/
│            ├───port/
│      ├───core(Enterprise Business Rule)/
│           ├───entity/
│           ├───objectvalue/
│           ├───exception/
│           ├───service/
│   ├───subdomain2/
│       ├───application(Application Business Rule)/
│            ├───usecase/
│            ├───command/
│            ├───commandhandler/
│            ├───queries/
│            ├───port/
│       ├───core(Enterprise Business Rule)/
│            ├───entity/
│            ├───objectvalue/
│            ├───exception/
│            ├───service/
├───infrastructure/
│   ├───primary/
│      ├───rest/
│      ├───cli/
│   ├───secondary/
│      ├───repository/
│      ├───entity/
│      ├───service/
│      ├───config/
│      ├───otherspackage/

Personally I prefer the third proposal.

@DamnClin what would be the best hierarchy for you ?

deepu105 commented 3 years ago

I honestly don't care about DDD and such. To me you use whatever works for your project (many benefits that we theoritically claim from certain approach is often superficial in practice). So if there is a majority consensus on something then go with that. my only concern would be if we end up making things more complicated than it is today just to fit certain approach without any tangible value in real world use. But if DDD makes things simpler than I'm fine with it.

On Sat, 26 Sep 2020, 3:05 pm Pascal Grimaud, notifications@github.com wrote:

@mshima https://github.com/mshima : I'm beginner in this kind of architecture, don't rely on my project, I only played this morning with JHipster, and did some refactoring/renaming folder, nothing more

If we can keep both type of generation, I afraid it will be a lot of stuff to maintain...

Let's keep on thinking and discussing about how to deal with the future of JHipster

cc @jhipster/developers https://github.com/orgs/jhipster/teams/developers : your opinion is important here. Should we change the JHipster folder to match with an Hexagonal Architecture or is it too early ?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/jhipster/generator-jhipster/issues/11122#issuecomment-699493168, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAIOKF4ZSYNMF4O7VBU5DP3SHXRITANCNFSM4KGXDFYQ .

mshima commented 3 years ago

@DevAlves1993 your proposal seems too specific and complex. Having a common infrastructure for the entire application hurts DDD concepts, by hurting domain isolation.

A jdl concept: store_domain.jdl:

entity Product {}
entity Consumer {}
entity Order {}

domain Store {
    entity Product, Consumer, Order
}

notification_domain.jdl:

entity Channel {}

domain Notification {
   entity Channel
}

commerce_application.jdl:

application Commerce {
    config {
        applicationType: monolith
        prodDatabaseType: postgres
    }
    load domain Store from 'store_domain.jdl', Notification from 'notification_domain.jdl'
    entity Store.*, Notification.*
}

Convert commerce to microservice:

application Commerce {
    config {
        applicationType: gateway
        prodDatabaseType: postgres
    }
    load domain Store from 'store_domain.jdl', Notification from 'notification_domain.jdl'
    entity Store.*, Notification.*
}
application Store {
    config {
        applicationType: microservice
        prodDatabaseType: neo4j
    }
    load domain Store from 'store_domain.jdl'
    entity Store.*
}
application Notification {
    config {
        applicationType: microservice
        prodDatabaseType: couchbase
    }
    load domain Notification from 'notification_domain.jdl'
    entity Notification.*
}
DevAlves1993 commented 3 years ago

@DevAlves1993 your proposal seems too specific and complex.

I admit, it's really complex.

Having a common infrastructure for the entire application hurts DDD concepts, by hurting domain isolation.

The proposals I made completely ignore the infrastructure (it's done express), the most important for an application that uses the DDD principle is to have a code base that identically represents the business. I consider the infrastructure as a disposable element.

I also note that the objective of the hexagonal architecture is to completely isolate the business code base (while keeping it pure enough) from the infrastructure code base.

A proposal based on your jdl concept.

├───commerce(domain)/
│   ├───store(sub-domain)/
│       ├───usecase/
│       ├───entity/
│       ├───port/
│       ├───command/
│       ├───commandhandler/
│       ├───other/
│       ├───infrastructure/
│             ├───primary/
│                 ├───rest/
│                 ├───cli/
│             ├───secondary/
│                 ├───repository/
│                 ├───entity/
│                 ├───service/
│                 ├───config/
│                 ├───otherspackage/
│   ├───notification(sub-domain)/
│       ├───usecase/
│       ├───entity/
│       ├───port/
│       ├───command/
│       ├───commandhandler/
│       ├───other/
│       ├───infrastructure/
│             ├───primary/
│                 ├───rest/
│                 ├───cli/
│             ├───secondary/
│                 ├───repository/
│                 ├───entity/
│                 ├───service/
│                 ├───config/
│                 ├───otherspackage/

or

├───commerce(domain)/
│   ├───store(sub-domain)/
│       ├───application/
│       ├───core/
│       ├───infrastructure/
│             ├───primary/
│                 ├───rest/
│                 ├───cli/
│             ├───secondary/
│                 ├───repository/
│                 ├───entity/
│                 ├───service/
│                 ├───config/
│                 ├───otherspackage/
│   ├───notification(sub-domain)/
│       ├───application/
│       ├───core/
│       ├───infrastructure/
│             ├───primary/
│                 ├───rest/
│                 ├───cli/
│             ├───secondary/
│                 ├───repository/
│                 ├───entity/
│                 ├───service/
│                 ├───config/
│                 ├───otherspackage/
mraible commented 3 years ago

I don't like all the nested packages with generic names. People hate Java because you have to navigate so deep to find anything. This seems to be just making it worse.

On Sep 25, 2020, at 14:49, Pascal Grimaud notifications@github.com wrote:

 I agree with you. We should not block workflow and go on cc @deepu105 : do you agree to remove the last rule about asking each PR to be approved ?

— You are receiving this because you are on a team that was mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.