Skip to content

Commit 11b36b0

Browse files
committed
refactor: remove class-based implementation to reduce implementation obfuscation
1 parent 0e74c17 commit 11b36b0

28 files changed

+278
-202
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<br>
22
<div align="center">
3-
<h1>📦 clean-architecture</h1>
3+
<h1>🏗️ Clean Architecture</h1>
44
<strong>A clean architecture example to implement testable and evolutive systems</strong>
55
</div>
66
<br>

hosts/web/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<br>
22
<div align="center">
3-
<h1>📦 Clean Architecture</h1>
3+
<h1>🏗️ Clean Architecture</h1>
44
<strong>The web host</strong>
55
</div>
66
<br>

modules/catalog/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<br>
22
<div align="center">
3-
<h1>📦 Clean Architecture</h1>
3+
<h1>🏗️ Clean Architecture</h1>
44
<strong>The catalog <a href="https://deviq.com/domain-driven-design/bounded-context">bounded context</a></strong>
55
</div>
66
<br>
Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
1-
import { Controller } from "@clean-architecture/shared-kernel";
1+
import type {
2+
Controller,
3+
ControllerFactory,
4+
} from "@clean-architecture/shared-kernel";
25

36
import type { GetQuoteInputData } from "../useCases/GetQuoteUseCase";
47

5-
export class GetQuoteController extends Controller<GetQuoteInputData> {}
8+
export type GetQuoteController = Controller<GetQuoteInputData>;
9+
10+
export const createGetQuoteController: ControllerFactory<
11+
GetQuoteController,
12+
GetQuoteInputData
13+
> = (useCase) => {
14+
return {
15+
async execute(input) {
16+
return useCase.execute(input);
17+
},
18+
};
19+
};

modules/catalog/src/GetQuote/frameworks/GetQuoteView.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { useEffect, useMemo, useState } from "react";
22
import type { Hook } from "@clean-architecture/shared-kernel";
33

4-
import { GetQuoteUseCase } from "../useCases/GetQuoteUseCase";
4+
import { GetQuoteInteractor } from "../useCases/GetQuoteUseCase";
55
import type { GetQuoteViewModel } from "../adapters/GetQuoteViewModel";
66
import { GetQuotePresenter } from "../adapters/GetQuotePresenter";
7-
import { GetQuoteController } from "../adapters/GetQuoteController";
7+
import { createGetQuoteController } from "../adapters/GetQuoteController";
8+
import type { GetQuoteController } from "../adapters/GetQuoteController";
89
import { useDependencyInjection } from "../../shared/frameworks/DependencyInjection";
910

1011
export const GetQuoteView = () => {
@@ -34,14 +35,14 @@ const useGetQuote: Hook<GetQuoteController, GetQuoteViewModel> = () => {
3435
const [viewModel, setViewModel] = useState<GetQuoteViewModel>({});
3536
const presenter = useMemo(() => new GetQuotePresenter(setViewModel), []);
3637

37-
const useCase = useMemo(
38-
() => new GetQuoteUseCase(entityGateway, presenter),
38+
const useCaseInteractor = useMemo(
39+
() => GetQuoteInteractor(entityGateway, presenter),
3940
[entityGateway, presenter],
4041
);
4142

4243
const controller = useMemo(
43-
() => new GetQuoteController(useCase),
44-
[useCase],
44+
() => createGetQuoteController(useCaseInteractor),
45+
[useCaseInteractor],
4546
);
4647

4748
return useMemo(() => {
Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1 @@
1-
export { GetQuotePresenter } from "./adapters/GetQuotePresenter";
2-
export { GetQuoteController } from "./adapters/GetQuoteController";
3-
export { GetQuoteUseCase } from "./useCases/GetQuoteUseCase";
41
export { GetQuoteView } from "./frameworks/GetQuoteView";
Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { UseCaseInteractor, success } from "@clean-architecture/shared-kernel";
1+
import { success } from "@clean-architecture/shared-kernel";
22
import type {
33
UseCaseInputData,
4+
UseCaseInteractor,
45
UseCaseOutputData,
56
} from "@clean-architecture/shared-kernel";
67

@@ -14,22 +15,24 @@ export type GetQuoteOutputData = UseCaseOutputData<{
1415
content: string;
1516
}>;
1617

17-
export class GetQuoteUseCase extends UseCaseInteractor<
18+
export const GetQuoteInteractor: UseCaseInteractor<
1819
GetQuoteInputData,
1920
GetQuoteOutputData,
2021
QuoteEntityGatewayBoundary
21-
> {
22-
public override async execute(input: GetQuoteInputData) {
23-
const entityGatewayResult = await this.entityGateway.getOne(input.id);
22+
> = (entityGateway, presenter) => {
23+
return {
24+
async execute(input) {
25+
const entityGatewayResult = await entityGateway.getOne(input.id);
2426

25-
if (entityGatewayResult.type === "failure") {
26-
this.presenter.error(entityGatewayResult);
27-
} else {
28-
this.presenter.ok(
29-
success({
30-
content: entityGatewayResult.payload.attributes.content,
31-
}),
32-
);
33-
}
34-
}
35-
}
27+
if (entityGatewayResult.type === "failure") {
28+
presenter.error(entityGatewayResult);
29+
} else {
30+
presenter.ok(
31+
success({
32+
content: entityGatewayResult.payload.content,
33+
}),
34+
);
35+
}
36+
},
37+
};
38+
};
Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
import { success } from "@clean-architecture/shared-kernel";
22

33
import type { QuoteEntityGatewayBoundary } from "../entities/QuoteEntityGatewayBoundary";
4-
import { QuoteEntity } from "../entities/QuoteEntity";
5-
import type { QuoteEntityCreateInput } from "../entities/QuoteEntity";
4+
import { createQuoteEntity } from "../entities/QuoteEntity";
65

7-
export class QuoteEntityGateway implements QuoteEntityGatewayBoundary {
8-
public async getMany() {
6+
export const QuoteEntityGateway: QuoteEntityGatewayBoundary = {
7+
async getMany() {
98
await Promise.resolve();
109

1110
return success([]);
12-
}
13-
14-
public async getOne(id: string) {
11+
},
12+
async getOne(id) {
1513
// TODO: use data source interface (that can be implemented by https://dummyjson.com/ or fake concrete implementation) (interface + concrete implementations are not specific to the catalog module, can be implemented in shared kernel?)
1614
const dataSourceOutput = await Promise.resolve({
1715
id,
@@ -20,9 +18,8 @@ export class QuoteEntityGateway implements QuoteEntityGatewayBoundary {
2018
});
2119

2220
return this.toEntity(dataSourceOutput);
23-
}
24-
25-
public toEntity(input: QuoteEntityCreateInput) {
26-
return QuoteEntity.create(input);
27-
}
28-
}
21+
},
22+
toEntity(input) {
23+
return createQuoteEntity(input);
24+
},
25+
};
Lines changed: 34 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,48 @@
11
import {
2-
Entity,
32
Guard,
4-
IdValueObject,
3+
createEntityFactory,
4+
createIdValueObject,
55
success,
66
} from "@clean-architecture/shared-kernel";
7-
import type { GetValueFromValueObject } from "@clean-architecture/shared-kernel";
7+
import type { Entity } from "@clean-architecture/shared-kernel";
88

9-
import { CreatedAtValueObject } from "../../shared/entities/CreatedAtValueObject";
10-
import { AuthorValueObject } from "../../shared/entities/AuthorValueObject";
9+
import { createCreatedAtValueObject } from "../../shared/entities/CreatedAtValueObject";
10+
import type { CreatedAtValueObject } from "../../shared/entities/CreatedAtValueObject";
11+
import { createAuthorValueObject } from "../../shared/entities/AuthorValueObject";
12+
import type { AuthorValueObject } from "../../shared/entities/AuthorValueObject";
1113

12-
type QuoteEntityAttributes = {
13-
id: IdValueObject;
14+
export type QuoteEntity = Entity<{
1415
author: AuthorValueObject;
1516
content: string;
1617
createdAt: CreatedAtValueObject;
18+
}>;
19+
20+
export type QuoteEntityFactoryInput = Pick<QuoteEntity, "content"> & {
21+
id?: string;
22+
fullName: string;
1723
};
1824

19-
export type QuoteEntityCreateInput =
20-
GetValueFromValueObject<AuthorValueObject> &
21-
Pick<QuoteEntityAttributes, "content"> & {
22-
id?: string;
23-
};
25+
export const createQuoteEntity = createEntityFactory<
26+
QuoteEntity,
27+
QuoteEntityFactoryInput
28+
>((helpers, { id, content, fullName }) => {
29+
const guardContentResult = Guard.mustBeLessThanCharacters(content, 280);
30+
31+
if (guardContentResult.type === "failure") return guardContentResult;
32+
33+
const authorValueObject = createAuthorValueObject({ fullName });
2434

25-
export class QuoteEntity extends Entity<QuoteEntityAttributes> {
26-
private constructor(public override attributes: QuoteEntityAttributes) {
27-
super(attributes);
28-
}
35+
if (authorValueObject.type === "failure") return authorValueObject;
2936

30-
public static override create({
31-
id,
37+
const entity: QuoteEntity = {
38+
id: createIdValueObject(id),
39+
author: authorValueObject.payload,
3240
content,
33-
fullName,
34-
}: QuoteEntityCreateInput) {
35-
const guardContentResult = Guard.mustBeLessThanCharacters(content, 280);
36-
37-
if (guardContentResult.type === "failure") return guardContentResult;
38-
39-
const author = AuthorValueObject.create({ fullName });
40-
41-
if (author.type === "failure") return author;
42-
43-
return success(
44-
new QuoteEntity({
45-
id: IdValueObject.create(id),
46-
author: author.payload,
47-
content,
48-
createdAt: CreatedAtValueObject.create(),
49-
}),
50-
);
51-
}
52-
}
41+
createdAt: createCreatedAtValueObject(undefined),
42+
isEqualTo(input) {
43+
return helpers.isEqualTo(entity, input);
44+
},
45+
};
46+
47+
return success(entity);
48+
});

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ import type {
33
Result,
44
} from "@clean-architecture/shared-kernel";
55

6-
import type { QuoteEntity } from "./QuoteEntity";
6+
import type { QuoteEntity, QuoteEntityFactoryInput } from "./QuoteEntity";
77

8-
export type QuoteEntityGatewayBoundary = EntityGatewayBoundary<QuoteEntity> & {
8+
export type QuoteEntityGatewayBoundary = EntityGatewayBoundary<{
99
getMany: () => Promise<Result<QuoteEntity[]>>;
1010
getOne: (id: string) => Promise<Result<QuoteEntity>>;
11-
};
11+
toEntity: (input: QuoteEntityFactoryInput) => Result<QuoteEntity>;
12+
}>;

0 commit comments

Comments
 (0)