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

Desegmentation

Desegmentation (หรือที่รู้จักว่า Horizontal Slicing หรือ Packaging by Layer) คือรูปแบบการจัดระเบียบโค้ดที่ไฟล์ถูกจัดกลุ่มตามบทบาททางเทคนิค (Technical Roles) แทนที่จะเป็น Business Domains ที่มันรับผิดชอบ นี่หมายความว่าโค้ดที่มีฟังก์ชันทางเทคนิคคล้ายกันจะถูกเก็บไว้ที่เดียวกัน ไม่ว่ามันจะจัดการ Business logic อะไรก็ตาม

แนวทางนี้เป็นที่นิยมใน Meta-frameworks อย่าง Next และ Nuxt เนื่องจากความเรียบง่าย เพราะเริ่มได้ง่ายและเปิดให้ใช้ฟีเจอร์อย่าง Auto-imports และ File-based routing:

  • 📂 app
    • 📂 components
      • 📄 DeliveryCard.jsx
      • 📄 DeliveryChoice.jsx
      • 📄 RegionSelect.jsx
      • 📄 UserAvatar.jsx
    • 📂 actions
      • 📄 delivery.js
      • 📄 region.js
      • 📄 user.js
    • 📂 composables
      • 📄 delivery.js
      • 📄 region.js
      • 📄 user.js
    • 📂 constants
      • 📄 delivery.js
      • 📄 region.js
      • 📄 user.js
    • 📂 utils
      • 📄 delivery.js
      • 📄 region.js
      • 📄 user.js
    • 📂 stores
      • 📂 delivery
        • 📄 getters.js
        • 📄 actions.js

Pattern นี้เกิดขึ้นใน FSD codebases ด้วย ในรูปแบบของ Generic folders:

  • 📂 features
    • 📂 delivery
      • 📂 ui
        • 📂 components ⚠️
  • 📂 entities
    • 📂 recommendations
      • 📂 utils ⚠️

ไฟล์ต่างๆ ก็เป็นแหล่งของ Desegmentation ได้เหมือนกัน ไฟล์อย่าง types.ts สามารถรวมหลาย Domains ไว้ด้วยกัน ทำให้การค้นหาและการ Refactor ในอนาคตยุ่งยาก โดยเฉพาะใน Layers อย่าง pages หรือ widgets:

  • 📂 pages
    • 📂 delivery
      • 📄 index.ts
      • 📂 ui
        • 📄 DeliveryCard.tsx
        • 📄 DeliveryChoice.tsx
        • 📄 UserAvatar.tsx
      • 📂 model
        • 📄 types.ts ⚠️
        • 📄 utils.ts ⚠️
      • 📂 api
        • 📄 endpoints.ts ⚠️
pages/delivery/model/types.ts
// ❌ ไม่ดี: ผสม Business domains ใน Generic file
export interface DeliveryOption {
id: string;
name: string;
price: number;
}

export interface UserInfo {
id: string;
name: string;
avatar: string;
}

ปัญหา​

แม้โครงสร้างนี้จะเริ่มต้นง่าย แต่มันนำไปสู่ปัญหาการขยายตัว (Scalability) ในโปรเจกต์ขนาดใหญ่:

  • Low Cohesion (ความเกาะเกี่ยวต่ำ): การแก้ไข Feature เดียวมักต้องแก้ไฟล์ในหลายโฟลเดอร์ใหญ่ๆ เช่น pages, components, และ stores

  • Tight Coupling (ความเกี่ยวพันสูง): Components อาจมี Dependencies ที่ไม่คาดคิด นำไปสู่ Dependency chains ที่ซับซ้อนและพันกันยุ่งเหยิง

  • Difficult Refactoring (Refactor ยาก): ต้องใช้ความพยายามเพิ่มขึ้นในการดึงโค้ดที่เกี่ยวข้องกับ Domain เฉพาะออกมาด้วยมือ

ทางแก้​

รวมโค้ดทั้งหมดที่เกี่ยวข้องกับ Domain เฉพาะไว้ในที่เดียวกัน

หลีกเลี่ยงชื่อโฟลเดอร์ Generic เช่น types, components, utils รวมถึงชื่อไฟล์ Generic เช่น types.ts, utils.ts, หรือ helpers.ts ให้ใช้ชื่อที่สะท้อนถึง Domain ที่มันเป็นตัวแทนโดยตรงแทน

หลีกเลี่ยงชื่อไฟล์ Generic เช่น types.ts ถ้าเป็นไปได้ โดยเฉพาะใน Slices ที่มีหลาย Domains:

  • 📂 pages
    • 📂 delivery
      • 📄 index.tsx
      • 📂 ui
        • 📄 DeliveryPage.tsx
        • 📄 DeliveryCard.tsx
        • 📄 DeliveryChoice.tsx
        • 📄 UserInfo.tsx
      • 📂 model
        • 📄 delivery.ts
        • 📄 user.ts

ดูเพิ่มเติม​