# 3.Coding convention

### 3.1. Mục tiêu chương

Chương này quy định chuẩn coding và nguyên tắc thiết kế nhằm:

- Đảm bảo code thống nhất giữa các module và các đơn vị phát triển
- Giúp code dễ đọc, dễ hiểu và dễ bảo trì
- Giảm lỗi phát sinh do cách đặt tên hoặc coding không đồng nhất
- Tăng hiệu quả review và kiểm soát chất lượng code
- Đảm bảo code tuân thủ nguyên lý thiết kế SOLID
- Đảm bảo kiến trúc backend Spring Boot nhất quán toàn hệ thống

---

### 3.2. Khái niệm / phạm vi áp dụng

Quy định này áp dụng cho:

- Toàn bộ source code của hệ thống
- Core Team và Partner Team
- Tất cả các module trong `modules/**`
- Các thành phần trong `common/**` và `config/**` do Core Team quản lý
- Tất cả service, controller, repository, DTO, entity

---

### 3.3. Quy định chính

#### 3.3.1. Quy tắc đặt tên

Các thành phần phải đặt tên theo quy ước thống nhất:

<div class="TyagGW_tableContainer" id="bkmrk-th%C3%A0nh-ph%E1%BA%A7n-quy-t%E1%BA%AFc-%C4%91"><div class="group TyagGW_tableWrapper flex flex-col-reverse w-fit" tabindex="-1"><table class="w-fit min-w-(--thread-content-width)" data-end="1755" data-start="1269"><thead data-end="1309" data-start="1269"><tr data-end="1309" data-start="1269"><th class="" data-col-size="sm" data-end="1282" data-start="1269">Thành phần</th><th class="" data-col-size="sm" data-end="1300" data-start="1282">Quy tắc đặt tên</th><th class="" data-col-size="sm" data-end="1309" data-start="1300">Ví dụ</th></tr></thead><tbody data-end="1755" data-start="1349"><tr data-end="1401" data-start="1349"><td data-col-size="sm" data-end="1360" data-start="1349">Controller</td><td data-col-size="sm" data-end="1381" data-start="1360">`<Name>Controller`</td><td data-col-size="sm" data-end="1401" data-start="1381">`UserController`</td></tr><tr data-end="1445" data-start="1402"><td data-col-size="sm" data-end="1410" data-start="1402">Service</td><td data-col-size="sm" data-end="1428" data-start="1410">`<Name>Service`</td><td data-col-size="sm" data-end="1445" data-start="1428">`UserService`</td></tr><tr data-end="1498" data-start="1446"><td data-col-size="sm" data-end="1457" data-start="1446">Repository</td><td data-col-size="sm" data-end="1478" data-start="1457">`<Name>Repository`</td><td data-col-size="sm" data-end="1498" data-start="1478">`UserRepository`</td></tr><tr data-end="1539" data-start="1499"><td data-col-size="sm" data-end="1506" data-start="1499">Entity</td><td data-col-size="sm" data-end="1523" data-start="1506">`<Name>Entity`</td><td data-col-size="sm" data-end="1539" data-start="1523">`UserEntity`</td></tr><tr data-end="1622" data-start="1540"><td data-col-size="sm" data-end="1552" data-start="1540">DTO Request</td><td data-col-size="sm" data-end="1599" data-start="1552">`<Name>CreateRequest`, `<Name>UpdateRequest`</td><td data-col-size="sm" data-end="1622" data-start="1599">`UserCreateRequest`</td></tr><tr data-end="1673" data-start="1623"><td data-col-size="sm" data-end="1636" data-start="1623">DTO Response</td><td data-col-size="sm" data-end="1655" data-start="1636">`<Name>Response`</td><td data-col-size="sm" data-end="1673" data-start="1655">`UserResponse`</td></tr><tr data-end="1714" data-start="1674"><td data-col-size="sm" data-end="1681" data-start="1674">Mapper</td><td data-col-size="sm" data-end="1698" data-start="1681">`<Name>Mapper`</td><td data-col-size="sm" data-end="1714" data-start="1698">`UserMapper`</td></tr><tr data-end="1755" data-start="1715"><td data-col-size="sm" data-end="1720" data-start="1715">Enum</td><td data-col-size="sm" data-end="1735" data-start="1720">`<Name>Enum`</td><td data-col-size="sm" data-end="1755" data-start="1735">`UserStatusEnum`</td></tr></tbody></table>

</div></div>---

#### 3.3.2. Quy tắc chung Java

Dùng camelCase cho:

- Biến
- Method

Dùng PascalCase cho:

- Class
- Interface
- Enum

Ví dụ:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-private-string-fulln"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">private</span> String fullName;      <span class="hljs-comment">// đúng</span><span class="hljs-keyword">private</span> String FullName;      <span class="hljs-comment">// sai</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">UserService</span> { }  <span class="hljs-comment">// đúng</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">userService</span> { }  <span class="hljs-comment">// sai</span>`</div></div>---

#### 3.3.3. Quy định về logging

Không được dùng:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-system.out.println%28%22"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`System.out.println(<span class="hljs-string">"Error"</span>);`</div></div>Phải dùng logging chuẩn:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-private-static-final"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">Logger</span> <span class="hljs-variable">log</span> <span class="hljs-operator">=</span>        LoggerFactory.getLogger(UserService.class);log.info(<span class="hljs-string">"User created"</span>);log.error(<span class="hljs-string">"Create user failed"</span>, ex);`</div></div>---

#### 3.3.4. Validation dữ liệu đầu vào

Tất cả dữ liệu đầu vào phải được validate bằng annotation.

Annotation chuẩn:

- `@NotNull`
- `@NotBlank`
- `@Size`
- `@Email`
- `@Pattern`

Ví dụ:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-public-class-usercre"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">UserCreateRequest</span> {    <span class="hljs-meta">@NotBlank</span>    <span class="hljs-meta">@Size(max = 100)</span>    <span class="hljs-keyword">private</span> String username;    <span class="hljs-meta">@NotBlank</span>    <span class="hljs-keyword">private</span> String password;}`</div></div>---

### 3.4. Nguyên lý thiết kế SOLID áp dụng trong dự án

#### 3.4.1. S — Single Responsibility

Một class chỉ có một trách nhiệm.

Quy định dự án:

- Controller → chỉ xử lý HTTP
- Service → xử lý nghiệp vụ
- Repository → truy cập DB
- Mapper → convert DTO ↔ Entity

Sai:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-public-class-usercon"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">UserController</span> {    <span class="hljs-meta">@Autowired</span> UserRepository repo;   <span class="hljs-comment">// sai tầng</span>}`</div></div>Đúng:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-public-class-usercon-1"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">UserController</span> {    <span class="hljs-meta">@Autowired</span> UserService userService;}`</div></div>---

#### 3.4.2. O — Open/Closed

Code phải mở rộng được nhưng không sửa code cũ.

Áp dụng:

- Dùng interface Service
- Không sửa class gốc khi thêm logic

Ví dụ:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-public-interface-not"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title class_">NotificationService</span> {    <span class="hljs-keyword">void</span> <span class="hljs-title function_">send</span><span class="hljs-params">(Message msg)</span>;}`</div></div>Triển khai:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-public-class-emailno"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">EmailNotificationService</span> <span class="hljs-keyword">implements</span> <span class="hljs-title class_">NotificationService</span> { }<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">SmsNotificationService</span> <span class="hljs-keyword">implements</span> <span class="hljs-title class_">NotificationService</span> { }`</div></div>---

#### 3.4.3. L — Liskov Substitution

Class con có thể thay thế class cha.

Quy định:

- ServiceImpl phải tuân interface
- Không throw exception mới trái contract

Sai:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-public-class-userser"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">UserServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title class_">UserService</span> {    <span class="hljs-keyword">public</span> User <span class="hljs-title function_">get</span><span class="hljs-params">(String id)</span> {        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">UnsupportedOperationException</span>();    }}`</div></div>---

#### 3.4.4. I — Interface Segregation

Không tạo interface quá lớn.

Sai:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-public-interface-use"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title class_">UserService</span> {    create();    update();    delete();    exportExcel();    sendEmail();}`</div></div>Đúng:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-public-interface-use-1"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title class_">UserService</span> { }<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title class_">UserExportService</span> { }<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title class_">UserNotificationService</span> { }`</div></div>---

#### 3.4.5. D — Dependency Inversion

Phụ thuộc abstraction, không phụ thuộc implementation.

Quy định:

- Inject interface
- Không new service

Sai:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-userservice-service-"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-type">UserService</span> <span class="hljs-variable">service</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">UserServiceImpl</span>();`</div></div>Đúng:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-%40autowired-userservi"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-meta">@Autowired</span>UserService userService;`</div></div>---

### 3.5. Quy tắc kiến trúc Spring Boot trong dự án

#### 3.5.1. Luồng chuẩn tầng

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-controller-%E2%86%92-service"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-attribute">Controller</span> → Service → Repository → Database`</div></div>Không được:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-controller-%E2%86%92-reposit"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-attribute">Controller</span> → RepositoryController → EntityManager`</div></div>---

#### 3.5.2. Controller không chứa nghiệp vụ

Sai:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-%40postmapping-public-"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-meta">@PostMapping</span><span class="hljs-keyword">public</span> User <span class="hljs-title function_">create</span><span class="hljs-params">(...)</span> {    user.setCreatedDate(LocalDateTime.now()); <span class="hljs-comment">// sai</span>}`</div></div>Đúng:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-%40postmapping-public--1"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-meta">@PostMapping</span><span class="hljs-keyword">public</span> UserResponse <span class="hljs-title function_">create</span><span class="hljs-params">(...)</span> {    <span class="hljs-keyword">return</span> userService.create(request);}`</div></div>---

#### 3.5.3. Service không chứa logic HTTP

Sai:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-throw-new-responsest"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ResponseStatusException</span>(HttpStatus.BAD_REQUEST);`</div></div>Đúng:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-throw-new-businessex"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">BusinessException</span>(<span class="hljs-string">"USER_EXISTS"</span>);`</div></div>---

#### 3.5.4. Repository chỉ truy vấn dữ liệu

Không chứa:

- validation
- business logic
- mapping

---

### 3.6. Design pattern sử dụng trong hệ thống

#### 3.6.1. Service pattern

Service là tầng nghiệp vụ trung tâm.

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-controller-%E2%86%92-service-1"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-attribute">Controller</span> → Service → Repository`</div></div>---

#### 3.6.2. DTO pattern

Tách DTO khỏi Entity.

Không trả Entity ra API.

Sai:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-public-userentity-cr"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">public</span> UserEntity <span class="hljs-title function_">create</span><span class="hljs-params">(...)</span> { }`</div></div>Đúng:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-public-userresponse-"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">public</span> UserResponse <span class="hljs-title function_">create</span><span class="hljs-params">(...)</span> { }`</div></div>---

#### 3.6.3. Mapper pattern

Convert DTO ↔ Entity.

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-userentity-entity-%3D-"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-type">UserEntity</span> <span class="hljs-variable">entity</span> <span class="hljs-operator">=</span> mapper.toEntity(request);`</div></div>---

#### 3.6.4. Exception pattern

Dùng BusinessException thống nhất.

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-throw-new-businessex-1"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">BusinessException</span>(ErrorCode.USER_NOT_FOUND);`</div></div>---

### 3.7. Cách thực hiện / quy trình

#### Quy trình tạo DTO đúng chuẩn

Bước 1: Tạo class DTO theo quy tắc đặt tên

Ví dụ:

- UserCreateRequest
- UserUpdateRequest
- UserResponse

Bước 2: Thêm validation annotation

Bước 3: Dùng DTO trong controller

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-%40postmapping-public--2"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-meta">@PostMapping</span><span class="hljs-keyword">public</span> ApiResponse<UserResponse> <span class="hljs-title function_">create</span><span class="hljs-params">(        </span><span class="hljs-meta">@Valid</span> <span class="hljs-meta">@RequestBody</span> UserCreateRequest request) {    <span class="hljs-keyword">return</span> ApiResponse.ok(userService.create(request));}`</div></div>---

#### Quy trình logging chuẩn

Bước 1: Khai báo logger trong class

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-private-static-final-1"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">Logger</span> <span class="hljs-variable">log</span> <span class="hljs-operator">=</span>        LoggerFactory.getLogger(UserService.class);`</div></div>Bước 2: Dùng logger thay cho System.out.println

---

### 3.8. Ví dụ minh họa

#### Trường hợp sai

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-public-class-usercon-2"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">usercontroller</span> {    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">CreateUser</span><span class="hljs-params">()</span> {        System.out.println(<span class="hljs-string">"Create user"</span>);    }}`</div></div>Sai vì:

- Tên class không đúng chuẩn
- Tên method không camelCase
- Dùng System.out.println
- Không theo kiến trúc tầng

---

#### Trường hợp đúng

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-%40restcontroller-publ"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-meta">@RestController</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">UserController</span> {    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">Logger</span> <span class="hljs-variable">log</span> <span class="hljs-operator">=</span>            LoggerFactory.getLogger(UserController.class);    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> UserService userService;    <span class="hljs-keyword">public</span> <span class="hljs-title function_">UserController</span><span class="hljs-params">(UserService userService)</span> {        <span class="hljs-built_in">this</span>.userService = userService;    }    <span class="hljs-meta">@PostMapping</span>    <span class="hljs-keyword">public</span> ApiResponse<UserResponse> <span class="hljs-title function_">create</span><span class="hljs-params">(            </span><span class="hljs-meta">@Valid</span> <span class="hljs-meta">@RequestBody</span> UserCreateRequest request) {        log.info(<span class="hljs-string">"Create user {}"</span>, request.getUsername());        <span class="hljs-keyword">return</span> ApiResponse.ok(userService.create(request));    }}`</div></div>---

#### Ví dụ DTO sai

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-public-class-userdto"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">userDTO</span> {    <span class="hljs-keyword">public</span> String name;}`</div></div>Sai vì:

- Tên class không chuẩn
- Không có validation
- Field public
- Không theo DTO pattern

---

#### Ví dụ DTO đúng

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-public-class-usercre-1"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">UserCreateRequest</span> {    <span class="hljs-meta">@NotBlank</span>    <span class="hljs-meta">@Size(max = 255)</span>    <span class="hljs-keyword">private</span> String name;    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">getName</span><span class="hljs-params">()</span> { <span class="hljs-keyword">return</span> name; }    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setName</span><span class="hljs-params">(String name)</span> { <span class="hljs-built_in">this</span>.name = name; }}`</div></div>---

### 3.9. Checklist áp dụng

Trước khi commit hoặc tạo PR:

### Naming

- [ ]  [ ]  Controller → `*Controller`
- [ ]  [ ]  Service → `*Service`
- [ ]  [ ]  Repository → `*Repository`
- [ ]  [ ]  Entity → `*Entity`
- [ ]  [ ]  DTO → `*Request / *Response`

---

### Coding

- [ ]  [ ]  Biến và method dùng camelCase
- [ ]  [ ]  Class dùng PascalCase
- [ ]  [ ]  Không dùng System.out.println
- [ ]  [ ]  Dùng logging chuẩn slf4j

---

### Validation

- [ ]  [ ]  DTO có validation annotation
- [ ]  [ ]  Không có field public trong DTO

---

### SOLID

- [ ]  [ ]  Controller không chứa nghiệp vụ
- [ ]  [ ]  Service không chứa HTTP logic
- [ ]  [ ]  Repository chỉ truy vấn DB
- [ ]  [ ]  Inject interface, không new
- [ ]  [ ]  Class có 1 trách nhiệm

---

### Architecture

- [ ]  [ ]  Không Controller → Repository
- [ ]  [ ]  Không trả Entity ra API
- [ ]  [ ]  Có DTO mapping
- [ ]  [ ]  Exception dùng chuẩn hệ thống

### 3.10. Cấu trúc chuẩn của một hàm xử lý nghiệp vụ

#### 3.10.1. Mục tiêu

Quy định cấu trúc thống nhất của một hàm xử lý nghiệp vụ nhằm:

- Dễ đọc và dễ review
- Tách rõ validate – logic – log – exception
- Tránh thiếu validate hoặc thiếu log
- Chuẩn hóa xử lý lỗi và response
- Giúp dev mới đọc code hiểu ngay luồng xử lý

---

#### 3.10.2. Cấu trúc chuẩn bắt buộc

Một hàm service/controller phải theo thứ tự:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-1.-validate-input-2."><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-bullet">1.</span> Validate input<span class="hljs-bullet">2.</span> Log input<span class="hljs-bullet">3.</span> Business logic<span class="hljs-bullet">4.</span> Catch exception (nếu cần)<span class="hljs-bullet">5.</span> Trả response / throw BusinessException`</div></div>---

#### 3.10.3. Quy định chi tiết từng phần

##### 1. Validate

- Validate annotation ở DTO
- Validate nghiệp vụ ở service

Ví dụ:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-if-%28repo.existsbyuse"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">if</span> (repo.existsByUsername(request.getUsername())) {    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">BusinessException</span>(ErrorCode.USER_EXISTS);}`</div></div>---

##### 2. Log

Phải log:

- input chính
- hành động nghiệp vụ
- lỗi

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-log.info%28%22create-use"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`log.info(<span class="hljs-string">"Create user {}"</span>, request.getUsername());`</div></div>---

##### 3. Business logic

Chỉ chứa xử lý nghiệp vụ:

- mapping
- tính toán
- gọi repository
- gọi service khác

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-userentity-entity-%3D--1"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-type">UserEntity</span> <span class="hljs-variable">entity</span> <span class="hljs-operator">=</span> mapper.toEntity(request);repo.save(entity);`</div></div>---

##### 4. Exception handling

Không catch Exception chung chung nếu không xử lý.

Sai:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-try-%7B-repo.save%28enti"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">try</span> {   repo.save(entity);} <span class="hljs-keyword">catch</span> (Exception e) {}`</div></div>Đúng:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-try-%7B-repo.save%28enti-1"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">try</span> {   repo.save(entity);} <span class="hljs-keyword">catch</span> (DataIntegrityViolationException ex) {   log.error(<span class="hljs-string">"DB error"</span>, ex);   <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">BusinessException</span>(ErrorCode.DB_ERROR);}`</div></div>---

##### 5. Response

Service:

- trả DTO
- hoặc throw BusinessException

Controller:

- trả ApiResponse

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-return-userresponse."><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">return</span> UserResponse.from(entity);`</div></div>Controller:

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-return-apiresponse.o"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">return</span> ApiResponse.ok(userService.create(request));`</div></div>---

#### 3.10.4. Ví dụ hàm sai

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-public-user-create%28u"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">public</span> User <span class="hljs-title function_">create</span><span class="hljs-params">(UserCreateRequest req)</span> {    <span class="hljs-type">UserEntity</span> <span class="hljs-variable">e</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">UserEntity</span>();    e.setUsername(req.getUsername());    repo.save(e);    <span class="hljs-keyword">return</span> e;}`</div></div>Sai vì:

- Không validate
- Không log
- Trả entity
- Không xử lý lỗi
- Không theo DTO pattern

---

#### 3.10.5. Ví dụ hàm đúng chuẩn dự án

<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary" id="bkmrk-public-userresponse--1"><div class="sticky top-[calc(var(--sticky-padding-top)+9*var(--spacing))]"><div class="absolute end-0 bottom-0 flex h-9 items-center pe-2"><div class="bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs">  
</div></div></div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-keyword">public</span> UserResponse <span class="hljs-title function_">create</span><span class="hljs-params">(UserCreateRequest request)</span> {    <span class="hljs-comment">// 1. Validate</span>    <span class="hljs-keyword">if</span> (repo.existsByUsername(request.getUsername())) {        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">BusinessException</span>(ErrorCode.USER_EXISTS);    }    <span class="hljs-comment">// 2. Log</span>    log.info(<span class="hljs-string">"Create user {}"</span>, request.getUsername());    <span class="hljs-comment">// 3. Business logic</span>    <span class="hljs-type">UserEntity</span> <span class="hljs-variable">entity</span> <span class="hljs-operator">=</span> mapper.toEntity(request);    repo.save(entity);    <span class="hljs-comment">// 4. Response</span>    <span class="hljs-keyword">return</span> mapper.toResponse(entity);}`</div></div>---

#### 3.10.6. Checklist

Khi review hàm service/controller:

- [ ]  [ ]  Có validate nghiệp vụ
- [ ]  [ ]  Có log input chính
- [ ]  [ ]  Không xử lý logic trong controller
- [ ]  [ ]  Không trả Entity
- [ ]  [ ]  Throw BusinessException đúng chuẩn
- [ ]  [ ]  Không catch Exception vô nghĩa
- [ ]  [ ]  Trả DTO / ApiResponse đúng chuẩn