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

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

ดูเพิ่มเติม