ข้ามไปยังเนื้อหาหลัก

Excessive Entities

Layer entities ใน Feature-Sliced Design เป็นหนึ่งใน Layer ล่างๆ ที่มีไว้สำหรับ Business logic เป็นหลัก นั่นทำให้มันเข้าถึงได้ง่าย — ทุก Layers ยกเว้น shared สามารถเข้าถึงมันได้ อย่างไรก็ตาม ความเป็น Global ของมันหมายความว่าการเปลี่ยนแปลงใน entities อาจส่งผลกระทบวงกว้าง ต้องใช้การ Design อย่างระมัดระวังเพื่อหลีกเลี่ยงการ Refactor ที่ราคาแพง

Entities ที่มากเกินไปอาจนำไปสู่ความกำกวม (โค้ดไหนควรอยู่ Layer นี้), Coupling, และปัญหา Import ตลอดเวลา (โค้ดกระจัดกระจายไปตาม Slices พี่น้อง)

วิธีรักษา entities layer ให้สะอาด

0. พิจารณาการไม่มี entities layer เลย

คุณอาจคิดว่าแอปของคุณจะไม่เป็น Feature-Sliced ถ้าไม่มี Layer นี้ แต่มันโอเคมากๆ ที่แอปจะไม่มี entities layer เลย มันไม่ได้ทำลาย FSD แต่อย่างใด ในทางตรงกันข้าม มันช่วยให้ Architecture เรียบง่ายและเก็บ entities layer ไว้สำหรับการ Scale ในอนาคต ตัวอย่างเช่น ถ้าแอปของคุณทำหน้าที่เป็น Thin client เป็นไปได้มากว่ามันไม่ต้องการ entities layer

Thick และ Thin clients คืออะไร?

การแยก Thick vs. Thin client อ้างถึงวิธีการที่แอปประมวลผลข้อมูล:

  • Thin clients พึ่งพา Backend สำหรับการประมวลผลข้อมูลส่วนใหญ่ Client-side business logic มีน้อยมากและเกี่ยวข้องแค่การแลกเปลี่ยนข้อมูลกับ Backend
  • Thick clients จัดการ Client-side business logic จำนวนมาก ทำให้พวกมันเป็นผู้สมัครที่เหมาะสมสำหรับ entities layer

จำไว้ว่าการแบ่งประเภทนี้ไม่ได้เป็นขาว-ดำอย่างเคร่งครัด และส่วนต่างๆ ของแอปเดียวกันอาจทำตัวเป็น "Thick" หรือ "Thin" client ก็ได้

1. หลีกเลี่ยงการ Preemptive slicing (แบ่ง Slice ล่วงหน้า)

ตรงข้ามกับเวอร์ชันก่อนๆ FSD 2.1 สนับสนุน Deferred decomposition ของ Slices แทนที่จะเป็น Preemptive และแนวทางนี้ก็ใช้กับ entities layer ด้วย ตอนแรก คุณสามารถวางโค้ดทั้งหมดของคุณใน model segment ของหน้า (Widget, Feature) แล้วค่อยพิจารณา Refactor ทีหลัง เมื่อ Business requirements นิ่งแล้ว

จำไว้ว่า: ยิ่งคุณย้ายโค้ดไป entities layer ช้าเท่าไหร่ การ Refactor ที่อาจเกิดขึ้นก็จะอันตรายน้อยลงเท่านั้น — โค้ดใน Entities อาจกระทบฟังก์ชันของ Slice ใดๆ ใน Layers ที่สูงกว่า

2. หลีกเลี่ยง Entities ที่ไม่จำเป็น

อย่าสร้าง Entity สำหรับ Business logic ทุกชิ้น ให้ใช้ Types จาก shared/api และวาง Logic ใน model segment ของ Slice ปัจจุบันแทน สำหรับ Business logic ที่ Reuse ได้ ให้ใช้ model segment ภายใน Entity slice โดยเก็บ Data definitions ไว้ใน shared/api:

📂 entities
📂 order
📄 index.ts
📂 model
📄 apply-discount.ts // Business logic ที่ใช้ OrderDto จาก shared/api
📂 shared
📂 api
📄 index.ts
📂 endpoints
📄 order.ts

3. แยก CRUD Operations ออกจาก Entities

CRUD operations ถึงจะจำเป็น แต่มักเต็มไปด้วย Boilerplate code ที่ไม่มี Business logic สำคัญ การรวมพวกมันไว้ใน entities layer อาจทำให้รกและบดบังโค้ดที่มีความหมายจริงๆ ให้วาง CRUD operations ใน shared/api แทน:

📂 shared
📂 api
📄 client.ts
📄 index.ts
📂 endpoints
📄 order.ts // รวม CRUD operations ที่เกี่ยวกับ Order ทั้งหมด
📄 products.ts
📄 cart.ts

สำหรับ CRUD operations ที่ซับซ้อน (เช่น Atomic updates, Rollbacks, หรือ Transactions) ให้ประเมินว่า entities layer เหมาะสมหรือไม่ แต่ใช้ด้วยความระมัดระวัง

4. เก็บ Authentication Data ใน shared

ให้เลือก shared layer แทนที่จะสร้าง user entity สำหรับ Authentication data เช่น Tokens หรือ User DTOs ที่ได้จาก Backend ข้อมูลพวกนี้เป็น Context-specific และไม่น่าจะถูก Reuse นอกขอบเขตของ Authentication:

  • Authentication responses (เช่น Tokens หรือ DTOs) มักขาด Fields ที่จำเป็นสำหรับการ Reuse ที่กว้างขึ้น หรือแปรเปลี่ยนตามบริบท (เช่น Private vs. Public user profiles)
  • การใช้ Entities สำหรับ Auth data อาจนำไปสู่ Cross-layer imports (เช่น entities เข้าไปใน shared) หรือการใช้ @x notation ซึ่งทำให้ Architecture ซับซ้อน

ให้เก็บ Authentication-related data ใน shared/auth หรือ shared/api แทน:

📂 shared
📂 auth
📄 use-auth.ts // authenticated user info หรือ token
📄 index.ts
📂 api
📄 client.ts
📄 index.ts
📂 endpoints
📄 order.ts

สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับการ Implement authentication ดูที่ Authentication guide

5. ลด Cross-Imports ให้น้อยที่สุด

FSD อนุญาตให้มี Cross-imports ผ่าน @x notation แต่มันอาจนำมาซึ้งปัญหาทางเทคนิคเช่น Circular dependencies เพื่อหลีกเลี่ยงสิ่งนี้ ให้ออกแบบ Entities ภายใน Business contexts ที่แยกจากกัน (Isolated) เพื่อกำจัดความจำเป็นในการ Cross-imports:

Non-Isolated Business Context (หลีกเลี่ยง):

📂 entities
📂 order
📂 @x
📂 model
📂 order-item
📂 @x
📂 model
📂 order-customer-info
📂 @x
📂 model

Isolated Business Context (แนะนำ):

📂 entities
📂 order-info
📄 index.ts
📂 model
📄 order-info.ts

Isolated context ห่อหุ้ม Logic ที่เกี่ยวข้องทั้งหมด (เช่น Order items และ Customer info) ภายใน Module เดียว ลดความซับซ้อนและป้องกันการแก้ไขจากภายนอกต่อ Logic ที่ผูกกันแน่น