{"id":13764443,"url":"https://github.com/ddd-by-examples/library-nestjs","last_synced_at":"2025-04-06T12:12:36.999Z","repository":{"id":40723807,"uuid":"432287619","full_name":"ddd-by-examples/library-nestjs","owner":"ddd-by-examples","description":null,"archived":false,"fork":false,"pushed_at":"2023-05-11T20:00:27.000Z","size":33828,"stargazers_count":335,"open_issues_count":2,"forks_count":41,"subscribers_count":16,"default_branch":"main","last_synced_at":"2024-05-28T16:02:36.986Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ddd-by-examples.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2021-11-26T19:56:53.000Z","updated_at":"2024-05-27T12:54:55.000Z","dependencies_parsed_at":"2024-01-07T18:06:54.139Z","dependency_job_id":"c5c62461-7e65-42e8-a4b2-a3d570b5fadb","html_url":"https://github.com/ddd-by-examples/library-nestjs","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddd-by-examples%2Flibrary-nestjs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddd-by-examples%2Flibrary-nestjs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddd-by-examples%2Flibrary-nestjs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddd-by-examples%2Flibrary-nestjs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ddd-by-examples","download_url":"https://codeload.github.com/ddd-by-examples/library-nestjs/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247406082,"owners_count":20933802,"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":[],"created_at":"2024-08-03T16:00:20.659Z","updated_at":"2025-04-06T12:12:36.968Z","avatar_url":"https://github.com/ddd-by-examples.png","language":"TypeScript","funding_links":[],"categories":["Resources"],"sub_categories":[],"readme":"# Table of contents\n\n- [Table of contents](#table-of-contents)\n\n  - [About](#about)\n  - [Domain description](#domain-description)\n  - [General assumptions](#general-assumptions)\n    - [Process discovery](#process-discovery)\n    - [Project structure and architecture](#project-structure-and-architecture)\n    - [Architecture-code gap](#architecture-code-gap)\n    - [NestJS](#nestjs)\n  - [How to contribute](#how-to-contribute)\n  - [References](#references)\n\n- [How to contribute](#how-to-contribute)\n- [References](#references)\n\n## About\n\nThis project is an implementation of the well-known [ddd-by-examples/library](https://github.com/ddd-by-examples/library), but this time using TypeScript and Node.js.\n\nThis is a project of a library, driven by real [business requirements](#domain-description).\nWe use techniques strongly connected with Domain Driven Design, Behavior-Driven Development,\nEvent Storming, User Story Mapping.\n\n**The project is currently under development. Some solutions are temporary and may change.**\n\n## Domain description\n\nA public library allows patrons to place books on hold at its various library branches.\nAvailable books can be placed on hold only by one patron at any given point in time.\nBooks are either circulating or restricted, and can have retrieval or usage fees.\nA restricted book can only be held by a researcher patron. A regular patron is limited\nto five holds at any given moment, while a researcher patron is allowed an unlimited number\nof holds. An open-ended book hold is active until the patron checks out the book, at which time it\nis completed. A closed-ended book hold that is not completed within a fixed number of\ndays after it was requested will expire. This check is done at the beginning of a day by\ntaking a look at daily sheet with expiring holds. Only a researcher patron can request\nan open-ended hold duration. Any patron with more than two overdue checkouts at a library\nbranch will get a rejection if trying a hold at that same library branch. A book can be\nchecked out for up to 60 days. Check for overdue checkouts is done by taking a look at\ndaily sheet with overdue checkouts. Patron interacts with his/her current holds, checkouts, etc.\nby taking a look at patron profile. Patron profile looks like a daily sheet, but the\ninformation there is limited to one patron and is not necessarily daily. Currently a\npatron can see current holds (not canceled nor expired) and current checkouts (including overdue).\nAlso, he/she is able to hold a book and cancel a hold.\n\nHow actually a patron knows which books are there to lend? Library has its catalogue of\nbooks where books are added together with their specific instances. A specific book\ninstance of a book can be added only if there is book with matching ISBN already in\nthe catalogue. Book must have non-empty title and price. At the time of adding an instance\nwe decide whether it will be Circulating or Restricted. This enables\nus to have book with same ISBN as circulated and restricted at the same time (for instance,\nthere is a book signed by the author that we want to keep as Restricted)\n\n## General assumptions\n\n### Process discovery\n\nThe first thing we started with was domain exploration with the help of Big Picture EventStorming.\nThe description you found in the previous chapter, landed on our virtual wall:  \n![Event Storming Domain description](docs/images/eventstorming-domain-desc.png)  \nThe EventStorming session led us to numerous discoveries, modeled with the sticky notes:  \n![Event Storming Big Picture](docs/images/eventstorming-big-picture.jpg)  \nDuring the session we discovered following definitions:  \n![Event Storming Definitions](docs/images/eventstorming-definitions.png)\n\nThis made us think of real life scenarios that might happen. We discovered them described with the help of\nthe **Example mapping**:  \n![Example mapping](docs/images/example-mapping.png)\n\nThis in turn became the base for our _Design Level_ sessions, where we analyzed each example:  \n![Example mapping](docs/images/eventstorming-design-level.jpg)\n\nPlease follow the links below to get more details on each of the mentioned steps:\n\n- [Big Picture EventStorming](./docs/big-picture.md)\n- [Example Mapping](docs/example-mapping.md)\n- [Design Level EventStorming](docs/design-level.md)\n\n### Project structure and architecture\n\nAt the very beginning, not to overcomplicate the project, we decided to assign each bounded context\nto a separate package, which means that the system is a modular monolith. There are no obstacles, though,\nto put contexts into maven modules or finally into microservices.\n\nBounded contexts should (amongst others) introduce autonomy in the sense of architecture. Thus, each module\nencapsulating the context has its own local architecture aligned to problem complexity.\nIn the case of a context, where we identified true business logic (**lending**) we introduced a domain model\nthat is a simplified (for the purpose of the project) abstraction of the reality and utilized\nhexagonal architecture. In the case of a context, that during Event Storming turned out to lack any complex\ndomain logic, we applied CRUD-like local architecture.\n\n### Architecture-code gap\n\nWe put a lot of attention to keep the consistency between the overall architecture (including diagrams)\nand the code structure. Having identified bounded contexts we could organize them as a set of libraries (one of the reasons why Nx is used). Thanks to this we gain the famous microservices' autonomy, while having a monolithic\napplication (modular monolith). Each package has well defined public API, encapsulating all implementation details by using\n_nx-enforce-module-boundaries_.\n\nJust by looking at the package structure:\n\n```\n└── libs\n    ├── catalogue\n    └── lending\n        ├── application\n        ├── infrastructure\n        ├── ui-rest\n        └── domain/\n            ├── /book\n            ├── /dailysheet\n            ├── /librarybranch\n            ├── /patron\n            └── /patronprofile\n```\n\nyou can see that the architecture is screaming that it has two bounded contexts: **catalogue**\nand **lending**. Moreover, the **lending context** is built around five business objects: **book**,\n**dailysheet**, **librarybranch**, **patron**, and **patronprofile**, while **catalogue** has no sublibraries,\nwhich suggests that it might be a CRUD with no complex logic inside. Please find the architecture diagram\nbelow.\nYou may ask why, unlike a Java project, all business objects don't have their own hexagonal libraries. Indeed all business objects have now only their own catalog in each tier.\nWe changed that here because in Java these libraries made extensive use of each other, while in Node.js it will produce a circular dependency. So, when two libraries strongly depend on each other, they have to be merged together.\n\n![Component diagram](docs/c4/component-diagram.png)\n\nYet another advantage of this approach comparing to packaging by layer for example is that in order to\ndeliver a functionality you would usually need to do it in one package only, which is the aforementioned\nautonomy. This autonomy, then, could be transferred to the level of application as soon as we split our\n_context-packages_ into separate microservices. Following this considerations, autonomy can be given away\nto a product team that can take care of the whole business area end-to-end.\n\n#### NestJS\n\nNestJS is taking a big part of the market. Currently, the most popular framework is still Express, but for complex business applications, NestJS will fit better, thanks to its advanced Dependency Injection system, TypeScript as the main language, and many out-of-the-box solutions that make the development more organized and standardized from the very beginning.\n\nIn oposite to the goal from the [ddd-by-examples/library#spring](https://github.com/ddd-by-examples/library#spring), we will not categorically avoid dependence on our framework. As Eric Evans said in his book\n\n\u003e The best architectural frameworks solve complex technical\n\u003e problems while allowing the domain developer to concentrate on expressing a model. But frameworks can easily get in the way, either by making too many assumptions that constrain domain\n\u003e design choices or by making the implementation so heavyweight that development slows down.\n\nFollowing that sentence, we will try still using the framework in a few places to speed up the development without strongly affecting the structure of our model.\n\n## How to contribute\n\nThe project is still under construction, so if you like it enough to collaborate, just let us\nknow or simply create a Pull Request.\n\n## References\n\n1. [Introducing EventStorming](https://leanpub.com/introducing_eventstorming) by Alberto Brandolini\n2. [Domain Modelling Made Functional](https://pragprog.com/book/swdddf/domain-modeling-made-functional) by Scott Wlaschin\n3. [Software Architecture for Developers](https://softwarearchitecturefordevelopers.com) by Simon Brown\n4. [Clean Architecture](https://www.amazon.com/Clean-Architecture-Craftsmans-Software-Structure/dp/0134494164) by Robert C. Martin\n5. [Domain-Driven Design: Tackling Complexity in the Heart of Software](https://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215) by Eric Evans\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fddd-by-examples%2Flibrary-nestjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fddd-by-examples%2Flibrary-nestjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fddd-by-examples%2Flibrary-nestjs/lists"}