Skip to content

Commit a1c7c69

Browse files
committed
feat: use full name
1 parent 090c46a commit a1c7c69

File tree

4 files changed

+31
-36
lines changed

4 files changed

+31
-36
lines changed

README.md

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@
88

99
## ✨ Features
1010

11-
A TypeScript implementation of [the Clean Architecture specified by Robert C. Martin (Uncle Bob)](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html).
11+
A TypeScript implementation of [the Clean Architecture specified by Robert C. Martin (Uncle Bob)](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html).
12+
The Clean Architecture is an architectural pattern that enables the creation of loosely coupled and testable systems by enforcing a clear separation of concerns. This separation isolates the business rules from the details (such as frameworks and external dependencies like databases), making the system more maintainable and evolutive.
1213

13-
The Clean Architecture is an architectural pattern (a layered architecture) that enables the creation of loosely coupled and testable systems by enforcing a clear separation of concerns. This separation isolates the business rules from the details (such as frameworks and external dependencies like databases), making the system more maintainable and evolutive.
14+
Following the ["decompose by subdomain" pattern](https://microservices.io/patterns/decomposition/decompose-by-subdomain.html), a **modular architecture** has also been implemented to encapsulate and group all concerns from presentation to data per bounded context[^1]. This modular monolith approach enables decision autonomy within a module boundary[^2] and the creation of [self-contained systems](https://scs-architecture.org/) centered around business capabilities[^3].
1415

15-
Following the ["decompose by subdomain" pattern](https://microservices.io/patterns/decomposition/decompose-by-subdomain.html), a **modular architecture** has also been implemented to encapsulate and group all concerns from presentation to data per bounded context[^1]. This modular monolith approach enables decision autonomy within a module boundary[^2] and the creation of [self-contained systems](https://scs-architecture.org/) centered around business capabilities[^3].
16-
Furthermore, drawing inspiration from [the Vertical Slice Architecture](https://www.jimmybogard.com/vertical-slice-architecture/) and the [package by feature not by layer pattern](https://phauer.com/2020/package-by-feature/), top-level directories within a module (excluding the `shared` folder) are centered around **business features**[^3] and, optionally, around actors for entities coupled to gateways. It allows not only to [scream the application intent](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html) allowing better discoverability from the domain point of view but also to create cohesive and loosely-coupled components.
16+
Furthermore, drawing inspiration from [the Vertical Slice Architecture](https://www.jimmybogard.com/vertical-slice-architecture/) and the [package by feature not by layer pattern](https://phauer.com/2020/package-by-feature/), top-level directories within a module (excluding the `shared` folder) are centered around **business features**[^3] and, optionally, around actors for entities coupled to gateways.
17+
It allows not only to [scream the application intent](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html) allowing better discoverability from the domain point of view but also to create cohesive and loosely-coupled components.
1718
Second-level directories and the `shared` directory are organized following the clean architecture layers to enforce/materialize the dependency rule and bring clarity about each layer scope.
1819

1920
[^1]: In this repository, a [bounded context](https://martinfowler.com/bliki/BoundedContext.html) is implemented by one module, so a bounded context is equivalent to a module here. However, it's not always the case since [a bounded context is not strictly equivalent to a module](https://stackoverflow.com/a/77923055). Indeed, while a module is a technical-oriented concept that defines logical boundaries in the code, a [bounded context](https://deviq.com/domain-driven-design/bounded-context) is a business-oriented one (domain-driven design tactical pattern) that represents a [cohesive area of the business domain](https://ddd-practitioners.com/2023/03/07/the-difference-between-domains-subdomains-and-bounded-contexts/). A module is a technical enabler to implement a bounded context, which can contain one or multiple modules.
@@ -28,15 +29,18 @@ Second-level directories and the `shared` directory are organized following the
2829

2930
### Overview
3031

31-
**TODO (architecture diagram with control flow following [Clean architecture diagram (from the book)](https://i.sstatic.net/K44FQ.jpg)).**
32+
**TODO:**
3233

33-
### Components
34+
- Functional view (main modules and features).
35+
- Architecture diagram with control flow following [Clean architecture diagram (from the book)](https://i.sstatic.net/K44FQ.jpg)).
3436

35-
Used building blocks (including [DDD tactical patterns](https://vaadin.com/blog/ddd-part-2-tactical-domain-driven-design)):
37+
### Modules
3638

37-
- Entities
38-
- Value Objects
39-
- ...
39+
**TODO: package diagram / choosen feature split (catalog, ...) with slice across the different layers.**
40+
41+
#### A special module: the Shared Kernel.
42+
43+
See [documentation](./modules/shared-kernel/).
4044

4145
### Layers
4246

@@ -48,13 +52,13 @@ Used building blocks (including [DDD tactical patterns](https://vaadin.com/blog/
4852
- [Frameworks & Drivers](./modules/catalog/src/frameworks/): React views (and hooks), data source (including HttpDataSource to make fetch calls with error management, database client (Redis, SQL, MongoDB, ...), ...), ... TODO (include hosts (main component orchestrator)).
4953
- [Hosts](./hosts): Act like the configurator instance in the [Hexagonal Architecture](https://alistaircockburn.com/Hexagonal%20Budapest%2023-05-18.pdf). Under the Clean Architecture, the host layer is the outermost layer. It includes the initial entry point of the system called the main component in the Clean Architecture book (in the "Main Component" chapter). This layer is not depicted in the diagram shown above. The main component is on the driver side (for example, Web UI, CLI, Back-end server, ...) and is responsible to instantiate inner layers.
5054

51-
### Modules
52-
53-
**TODO: package diagram / choosen feature split (catalog, ...) with slice across the different layers.**
55+
### Components
5456

55-
#### A special module: the Shared Kernel.
57+
Used building blocks (including [DDD tactical patterns](https://vaadin.com/blog/ddd-part-2-tactical-domain-driven-design)):
5658

57-
See [documentation](./modules/shared-kernel/).
59+
- Entities
60+
- Value Objects
61+
- ...
5862

5963
<br>
6064

modules/catalog/src/Quote/adapters/QuoteEntityGateway.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,12 @@ export class QuoteEntityGateway implements QuoteEntityGatewayBoundary {
1111
}
1212

1313
public async getOne(id: string) {
14-
await Promise.resolve();
15-
16-
const fullName = "Test Test";
17-
const [firstName, lastName] = fullName.split(" ") as [string, string];
18-
19-
return QuoteEntity.create({
14+
const dataSourceOutput = await Promise.resolve({
2015
id,
2116
content: "Fake content",
22-
firstName,
23-
lastName,
17+
fullName: "Test Test",
2418
});
19+
20+
return QuoteEntity.create(dataSourceOutput);
2521
}
2622
}

modules/catalog/src/Quote/entities/QuoteEntity.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@ type QuoteEntityAttributes = {
1616
createdAt: CreatedAtValueObject;
1717
};
1818

19-
type QuoteEntityCreateInput = GetValueFromValueObject<AuthorValueObject> &
20-
Pick<QuoteEntityAttributes, "content"> & {
21-
id: string;
22-
};
23-
2419
export class QuoteEntity extends Entity<QuoteEntityAttributes> {
2520
private constructor(public override attributes: QuoteEntityAttributes) {
2621
super(attributes);
@@ -29,14 +24,16 @@ export class QuoteEntity extends Entity<QuoteEntityAttributes> {
2924
public static override create({
3025
id,
3126
content,
32-
firstName,
33-
lastName,
34-
}: QuoteEntityCreateInput) {
27+
fullName,
28+
}: GetValueFromValueObject<AuthorValueObject> &
29+
Pick<QuoteEntityAttributes, "content"> & {
30+
id: string;
31+
}) {
3532
const guardContentResult = Guard.mustBeLessThanCharacters(content, 280);
3633

3734
if (guardContentResult.type === "failure") return guardContentResult;
3835

39-
const author = AuthorValueObject.create({ firstName, lastName });
36+
const author = AuthorValueObject.create({ fullName });
4037

4138
if (author.type === "failure") return author;
4239

modules/catalog/src/shared/entities/AuthorValueObject.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
import { Guard, ValueObject, success } from "@clean-architecture/shared-kernel";
22

33
type Value = {
4-
firstName: string;
5-
lastName: string;
4+
fullName: string;
65
};
76

87
export class AuthorValueObject extends ValueObject<Value> {
98
public static override create(input: Value) {
109
const failedGuard = Guard.against(
11-
Guard.mustBeNonEmptyString(input.firstName),
12-
Guard.mustBeNonEmptyString(input.lastName),
10+
Guard.mustBeNonEmptyString(input.fullName),
1311
);
1412

1513
if (failedGuard) return failedGuard;

0 commit comments

Comments
 (0)