{"id":21301836,"url":"https://github.com/marcossic/architecture-example","last_synced_at":"2026-05-19T07:12:10.052Z","repository":{"id":167599243,"uuid":"548156117","full_name":"MarcossIC/architecture-example","owner":"MarcossIC","description":"Example of how to apply a clean architecture in Java, in two ways, one conventional and the other using CQRS","archived":false,"fork":false,"pushed_at":"2023-09-07T13:13:17.000Z","size":451,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-22T08:15:01.776Z","etag":null,"topics":["clean-architecture","cqrs-pattern","java","spring-boot"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MarcossIC.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-10-09T02:36:59.000Z","updated_at":"2023-12-21T21:38:32.000Z","dependencies_parsed_at":"2024-11-21T15:52:54.128Z","dependency_job_id":"bc240b81-b4eb-4efd-8c6f-1c3340ef94f3","html_url":"https://github.com/MarcossIC/architecture-example","commit_stats":null,"previous_names":["marcossic/architecture-example"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarcossIC%2Farchitecture-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarcossIC%2Farchitecture-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarcossIC%2Farchitecture-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarcossIC%2Farchitecture-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MarcossIC","download_url":"https://codeload.github.com/MarcossIC/architecture-example/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243773590,"owners_count":20345866,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clean-architecture","cqrs-pattern","java","spring-boot"],"created_at":"2024-11-21T15:52:46.163Z","updated_at":"2025-10-24T06:07:27.887Z","avatar_url":"https://github.com/MarcossIC.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Clean Architectura Example\nRepository that shows an example of how to make a clean architecture in Java following the SOLID principles. In addition, not only a simple hexagonal architecture is applied, but it is also applied together with a Vertical Slizing, in addition to applying it in two ways, one conventionally and another applying CQRS\n\n## More Info\nThe hexagonal architecture is generally divided into 3 layers of abstraction (although there are some cases where it's divided into 4, but 3 is the most common). These layers are typically referred to as \"Domain,\" \"Application,\" and \"Infrastructure.\"\n\n\u003cp product-select=\"none\" align=\"center\"\u003e\n  \u003cimg src=\"https://refactorizando.com/wp-content/uploads/2020/11/Arquitectura-Hexagonal.png\"/\u003e\n\u003c/p\u003e\n\nGenerally, these layers follow a top-down dependency rule, where the upper layer knows about the lower ones, but the lower layers are unaware of the upper ones, as can be seen in the image.\n\nStarting with the infrastructure layer, it's the highest layer in the hierarchy, thus depending on both the domain and the application since it interacts with both. In this layer, you typically place everything related to input and output connections and application configuration. For instance, input connections could include a Kafka consumer, RabbitMQ, or an API controller. Examples of output connections might involve database connections, Kafka consumers, sending emails, or REST connections (like RestTemplate, Feign, or WebClient).\n\nMoving on to the application layer, this layer doesn't have knowledge of the infrastructure but knows about the domain. Here, you usually place the logic related to use cases and where you call all the domain logic or other application services.\n\nThe lowest layer in the hierarchy is the domain layer. Even though it's the lowest, it can be considered the most important because it contains all the domain logic or bussiness logic of your application, including models, interfaces, and any other utilities you may need.\n\n# Ports And Adapters\n\nSome might wonder, \"But what if the logic of use cases resides in the application layer, the repositories are in the domain layer, and the outgoing database connections are in the infrastructure layer? How do they communicate? Because in theory, according to the top-down dependency rule, the application and the domain are unaware of the infrastructure.\n\nTo comprehend how this works, it's important to consider two concepts, which are another way to refer to this architecture, and this is the \"Ports and Adapters\" architecture.\n\n\u003cp product-select=\"none\" align=\"center\"\u003e\n  \u003cimg src=\"./imgs/ports_and_adapters.jpg\"/\u003e\n\u003c/p\u003e\n\nAs depicted in the image, communication can be achieved through \"Ports\" and \"Adapters.\" To better grasp this concept, when we refer to a \"port,\" we are essentially talking about interfaces. \"Adapters,\" on the other hand, are nothing more than the adaptation of a port, in other words, an implementation of the interface. This flexibility exists because when we define a port in the domain layer, its implementation can reside in either the infrastructure or the application layer. This flexibility stems from the fact that the port remains agnostic to how or where  is implemented.\n\nAlso, since the application and infrastructure layers are aware of the domain layer, they can consume these ports. Therefore, we continue to comply with the dependency rule, as the domain layer remains independent of the other layers while also serving as a bridge to communicate between the application and infrastructure layers.\n\n# Vertical Slizing \n\"Vertical slicing\" is a technique that can be applied to virtually any software architecture and proves to be highly beneficial. But why is it applied and how does it work? The reason for employing this technique is quite straightforward. As a development project progresses and the number of files increases, there comes a point where navigating through all these files can become challenging and confusing when trying to find the one you need. This is where \"vertical slicing\" comes into play.\n\n**Horizontal Structure**\n\u003cp product-select=\"none\" align=\"center\"\u003e\n  \u003cimg src=\"https://xurxodev.com/content/images/2017/02/Horizontal_Slice.png\"/\u003e\n\u003c/p\u003e\n\n**Vertical Structure**. One way to do it might look like this\n\u003cp product-select=\"none\" align=\"center\"\u003e\n  \u003cimg src=\"https://xurxodev.com/content/images/2017/03/Vertical-Slice.png\"/\u003e\n\u003c/p\u003e\n\nThe concept of \"vertical slicing\" is based on dividing the project's structure into multiple \"slices.\" Each \"slice\" has the function of grouping a set of functionalities that are related by the same concept or feature. For example, in the hexagonal architecture, it can be implemented by creating three layers, which are the domain, the application, and the infrastructure. Each of these layers groups a set of functionalities. However, if we stop at this point, we still face the same problem because this separation alone is not sufficient. To address this issue more effectively, one of the best ways to apply \"vertical slicing\" is through the \"contexts\" or \"entities\" of your domain. This allows you, when entering and exploring the structure, to clearly identify the folder you need at a glance. This is because when adding extra functionality, the first thing you will encounter are the contexts, and you can be sure that what is within this group of functions is related only to this context. This way, you won't get confused or have unrelated classes mixed in that you may not need or want to see for this specific case.\n\n# Ports And Adapter Architecture + vertical slizing\nOnce these concepts are understood, combining \"vertical slicing\" with \"clean architecture\" produces quite a favorable result. And this is the way I decided to apply it in this project:\n\n\u003cp product-select=\"none\" align=\"center\"\u003e\n  \u003cimg src=\"./imgs/vertizal_slizing_clean_architecture.jpg\"/\u003e\n\u003c/p\u003e\n\n# Shared Context\nWhen we mention the concept of dividing by context, an additional feature that further enhances the effectiveness of combining \"vertical slicing\" and \"clean architecture\" is that different contexts should not have mutual awareness; in other words, they should function as independent modules. This practice significantly contributes to code quality. However, there may be instances where a class is needed in multiple contexts for specific reasons. To address this situation, it is recommended to incorporate the \"Shared\" module, where both domain and infrastructure folders would be included. This makes sense because there might be shared elements in these areas, even though having shared use cases would not be logical. The \"Shared\" context proves useful in these particular cases.\n\n# CQRS (Command Query Responsability Segregation)\nCQRS, which stands for Command Query Responsibility Segregation, is an architectural pattern that focuses on separating read and write operations within a data store. Implementing CQRS in an application can have a positive impact on performance, scalability, and security. This is because in a conventional system, all operations interact with the same database, which can lead to overload when the requirements are high. By applying the CQRS pattern, these two aspects are separated, alleviating the load and preventing issues in one area from affecting the other. This, in turn, contributes to the resilience of the system, preventing the breakdown of one part from affecting the entire codebase.\n\nIn this example, I have also applied the CQRS pattern by separating write and read operations. To achieve this, I've created a 'mirror' of the product context, allowing for a contrast between the CQRS approach and the more conventional one.\n\nTo implement the CQRS pattern in this case, I've used the 'bus' and 'handler' patterns. These patterns simplify implementation and contribute to cleaner and decoupled code.\n\n### Handler\nA 'Handler' is a pattern used to manage events and execute the necessary logic to perform specific actions. In this context, they are used to handle both queries and commands, resulting in two types of handlers: 'Command Handler' and 'Query Handler.'\n\n### Bus\nOn the other hand, the 'Bus' pattern is a widely used architectural approach as an intermediary for communicating and coordinating components or modules within an application. This pattern facilitates communication between different components without the need for tight coupling. It is also known as a 'Message Bus' or 'Event Bus.'\n\n### Implementation\nTherefore, with these two components, I can manage the received commands and queries. The handlers remain decoupled from the caller. Furthermore, by using the bus, I can ensure that the controller in the infrastructure layer directs the command or query to the corresponding handler in the application layer. This allows each component to remain decoupled and facilitates system modularity.\n\n\u003cp product-select=\"none\" align=\"center\"\u003e\n  \u003cimg src=\"./imgs/cqrs_pattern.jpg\"/\u003e\n\u003c/p\u003e\n\n### Considerations with CQRS\nAnother important aspect to consider is that the CQRS pattern is not suitable for implementation throughout an entire system, as it can introduce a significant amount of unnecessary complexity. Typically, it is applied to specific modules within an application, especially when the requirements for reading and writing differ significantly. For example, in a blog, the comments section is likely to have many more read operations than write operations. For this reason, it may be more convenient to scale the read operations while keeping the writing unchanged.\n\nFurthermore, the CQRS pattern is commonly used in microservices architectures, as it allows the system to be more resilient and specific components to be scaled as needed. However, this also brings with it common challenges in this architecture, such as the 'Eventual Consistency' problem. What does this mean? Well, it refers to situations where, for example, you have a business rule that requires information to be read only after it has been stored in the database. Sometimes, even if you have executed the command correctly in the write database, it may still not be possible to read the desired information in the read database due to various factors, such as delays, connection issues, or message queue congestion, among others. This can lead to issues because the databases have not yet completed synchronization.\n\nIn this way, a service with CQRS could be seen in a microservices architecture.\n\u003cp product-select=\"none\" align=\"center\"\u003e\n  \u003cimg src=\"./imgs/cqrs_microservices.jpg\"/\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcossic%2Farchitecture-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarcossic%2Farchitecture-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcossic%2Farchitecture-example/lists"}