
เราจะมานั่งอ่านบทความเรื่อง Clean Architecture กัน ต้นฉบับจากที่นี่ Link
โดยเราจะเขียนแปลและสรุปสิ่งที่ได้อ่าน เพื่อทำความเข้าใจ สำหรับใครที่กำลังสนใจเรื่อง Clean Architecture เรามาเรียนรู้ไปพร้อมกันโลด
- ที่มาของ Clean Architecture
- Clean Architecture
- สิ่งที่ไม่ใช่ Clean Architecture
- ความแตกต่างระหว่าง Clean Architecture และ Onion Architecture
- บทความเพิ่มเติม
Everything feels difficult
when you’re about to level up.
Keep going!
Clean Architecture คือหลักการในการออกแบบซอฟต์แวร์ที่เน้นในเรื่องการจัดการโครงสร้างของระบบเพื่อความชัดเจน การดูแลรักษา และความยืดหยุ่น
เน้นไปที่หลักการ Separation of Concerns และ Independence of Implementation Details โดยเป้าหมายคือทำให้ระบบถูกปรับแต่งได้ง่ายแม้เวลาผ่านไป
โดยจะให้ความสำคัญกับกฎเกณฑ์ทางธุรกิจเป็นลำดับแรก เช่น หากสร้างระบบการยืม-คืนอุปกรณ์ จะต้องมีกฎว่า เมื่อยืมอุปกรณ์ไปแล้วจะต้องนำอุปกรณ์มาคืนในเวลาที่กำหนดไว้
ซึ่ง Clean Architecture จะทำให้กฎเกณฑ์เหล่านี้เป็นอิสระกับรายละเอียดต่างๆของระบบ เช่น ด้วยการออกแบบของ Clean Architecture ไม่ว่าจะเปลี่ยนไปใช้ Framework หรือฐานข้อมูลตัวไหน จะต้องไม่กระทบกับโค้ดในส่วนของกฎเกณฑ์ทางธุรกิจ
ซึ่งการออกแบบนี้นั้นจะช่วยในเรื่องการทดสอบระบบ และทำให้ซอฟต์แวร์มีอายุการใช้งานที่นานขึ้นแม้จะต้องเจอกับการเปลี่ยนแปลงต่างๆของระบบ
ที่มาของ Clean Architecture
หลักการ Clean Architecture ถูกคิดค้นโดย Robert C. Martin หรือ ลุงบ๊อบ (Uncle Bob) เมื่อปี 2012 และเป็นที่นิยมขึ้นมาในปี 2017 จากหนังสือของเขา

Ref: https://en.wikipedia.org/wiki/Robert_C._Martin
แต่ลุงบ๊อบไม่ได้เป็นคนคิดค้นหลักการทั้งหมดขึ้นมาเอง มาหาคำตอบกันต่อว่าแล้วมันมาได้ไง
Hexagonal Architecture
ต้นแบบหลักอันหนึ่งของ Clean Architecture คือ Hexagonal Architecture หรือเรียกว่า Ports & Adapters ซึ่งถูกคิดค้นโดย Alistair Cockburn ในปี 2005
Hexagonal Architecture มีจุดประสงค์หลักคือต้องการแยกส่วนตรรกะทางธุรกิจของการใช้งานออกจากปัจจัยภายนอกอื่นๆ เช่น ฐานข้อมูล โดยกำหนดขอบเขตการแบ่งระหว่างตรรกะทางธุรกิจกับส่วนที่บริการที่ภายนอก

Ports คือ การกำหนดว่าตรรกะทางธุรกิจต่างๆจะสื่อสารกับบริการภายนอกอย่างไร โดยที่มี Adapters เป็นตัวเชื่อมให้ Ports มีการสื่อสารกับภายนอก
Onion Architecture
ในปี 2008 Jeffrey Palermo โดยคิดค้น Onion Architecture เพื่อที่จะแยกตรรกะทางธุรกิจออกจากปัจจัยภายนอกเช่นกัน แต่ทำในวิธีที่ต่างกันออกไป อ้าววว
ในการออกแบบซอฟต์แวร์พี่ Palermo ได้กำหนดไว้ 4 Layers:

- Core (Domain Model) – เป็นชั้นในสุด มีหน้าที่ในการเก็บลักษณะของข้อมูลที่ใช้ และเก็บตรรกะทางธุรกิจต่างๆ
- Infrastructure (Domain Service) – อยู่ล้อมรอบ Core มีหน้าที่นำลักษณะและตรรกะทางธุรกิจต่างๆที่อยู่ใน Core มาใช้งานและทำการเชื่อมต่อกับการบริการภายนอกต่างๆ เช่น ฐานข้อมูล
- Application Services – จะเก็บการทำงานต่างๆของระบบ ว่าระบบนี้สามารถทำอะไรได้บ้าง เช่น ระบบยืม-คืนอุปกรณ์ สามารถยืมอุปกรณ์ได้ สามารถคืนอุปกรณ์ได้ หรือสามารถสร้างอุปกรณ์ใหม่เพิ่มเข้ามาใช้งานในระบบได้ โดยจะเป็นการทำงานร่วมกันของ Layer Core และ Infrastructure
- Presentation/UI – เป็น Layer ที่อยู่นอกสุด ทำหน้าที่คอยควบคุมและสื่อสารการทำงานระหว่างระบบและผู้ใช้งาน เช่น User Interface หรือ Controllers ที่มาหน้าที่ในการรับ Request จากผู้ใช้งานระบบและส่ง Response กลับไปหาผู้ใช้งานระบบ
Onion Architecture นั้นพึ่งพาการใช้งาน Dependency Injection เป็นหลัก เลยทำให้ Core เป็นอิสระกับการดำเนินการภายนอกต่างๆ อีกทั้งยังได้พึ่งพากับ Interface Class ทำให้มีการเชื่อมต่อที่ไม่ผูกติด สามารถเปลี่ยนองค์ประกอบต่างๆได้ง่าย
Architecture อื่นๆ
นอกจาก Architecture ที่เล่ามาทั้งหมดแล้ว ยังมีส่วนอื่นๆที่เป็นต้นแบบของ Clean Architecture อีกนะ
Lean Architecture
ช่วยในการแยกโครงสร้างข้อมูลของธุรกิจออกจากการใช้งานของมันและวิธีการทำงานร่วมกันระหว่างโครงสร้างข้อมูลและการใช้งาน
ลองยกตัวอย่างเป็นระบบยืม-คืนอุปกรณ์
โครงสร้างข้อมูลของอุปกรณ์จะประกอบด้วย ชื่ออุปกรณ์และจำนวนอุปกรณ์
ซอฟต์แวร์นี้มีการใช้งาน เช่น การยืมอุปกรณ์
โครงสร้างข้อมูลทำงานร่วมกับการใช้งาน เช่น มีการส่งคำขอการยืมอุปกรณ์เข้ามา ต้องมีการตรวจสอบว่าอุปกรณ์นั้นมีอยู่ในคลังหรือไม่ ถ้ามีก็ลดจำนวนของอุปกรณ์ที่มีอยู่ออกเพื่อแสดงถึงมีการยืมเกิดขึ้น
Object-Oriented Software Engineering
พูดถึงในเรื่องของ Use Cases หรือเรียกว่าเป็นการใช้งานของระบบ ระบบนี้จะโดนเรียกใช้งานในกรณีไหนบ้าง เช่น ต้องการ CRUD อุปกรณ์
Screaming Architecture

เป็นอีกหนึ่งวิธีการที่จะเจอได้ใน Clean Architecture โดยลุงบ๊อบได้ให้แนวคิดไว้ว่า:
- หากเรากำลังดูแบบแปลนแผ่นหนึ่ง สิ่งที่เราเห็นคือ ประตูทางเข้า ห้องอยู่อาศัย ห้องน้ำ ห้องนอน เราก็สามารถสรุปได้เลยว่าสิ่งนี้คือ “บ้าน” หรือเรียกได้ว่า Architecture ที่เราเห็นนี้คือ Scream ของบ้าน
- มาที่ Architecture บนซอฟต์แวร์ของเรา เหมือนเราดูที่โครงสร้างของ Directory เราเห็นอะไร? เห็นระบบการจัดการอุปกรณ์ หรือเห็น Framework ที่ใช้ในโปรเจคนั้นๆ
- เพราะฉะนั้นแบบแปลนของสิ่งต่างๆควรจะบอกการใช้งานของสิ่งนั้นๆ ซึ่ง Architecture ของซอฟแวร์ก็ควรจะบอกการใช้งาน (Use Cases) ของซอฟต์แวร์นั้นๆนั่นเองงง
Humble Object
แนวคิดหลักคือการแยกพฤติกรรมที่ทดสอบยากจากพฤติกรรมที่ทดสอบได้ง่าย ซึ่งทำได้ด้วยการแบ่งการทำงานออกเป็น 2 ส่วน
- ส่วนที่เรียบง่ายที่สุด (Humble Part) ซึ่งเป็นโค้ดที่ทดสอบได้ยาก เช่น ในโค้ดประกอบด้วยการเรียกใช้ Dependency ต่างๆ
- ส่วนที่เก็บวิธีการทำงานหรือพฤติกรรมที่สามารถทดสอบได้ง่าย เช่น ตรวจสอบว่าอุปกรณ์ชิ้นนี้มีในคลังหรือไม่ ถ้าไม่มีต้องส่งข้อมูลกลับไปหาผู้ใช้ว่าไม่พบอุปกรณ์นี้
Component Design Principles
ระบบขนาดใหญ่นั้นเกิดขึ้นจากองค์ประกอบเล็กๆทำงานร่วมกัน
ลุงบ๊อบได้ให้หลักการไว้ว่าส่วนประกอบต่างๆควรประกอบกันอย่างไร โดยสามารถศึกษาได้จาก Component Design Principles
Clean Architecture
มาถึงพระเอกของเราแล้ว! มีหลายส่วนที่ประกอบกันขึ้นมาเป็น Clean Architecture

Clean Architecture ประกอบด้วย 4 Layers เรียงจากด้านในมาด้านนอก:
- Entities – เป็นตัวแทนของแก่นสำคัญทางธุรกิจที่ห่อหุ้มแนวคิดหรือกฎเกณฑ์ทางธุรกิจ ซึ่งเป็นอิสระจาก Layer ชั้นนอก
- Use Cases – เป็นตัวแทนของพฤติกรรมการทำงานและเป็นตัวกำหนดการกระทำต่างๆที่สามารถทำได้ในระบบนี้ โดยจะห่อหุ้มลำดับการทำงานที่ทำเพื่อบรรลุเป้าหมายที่กำหนด ซึ่ง Use Cases จะทำหน้าที่ควบคุมการทำงานระหว่าง Entities และ Layer ภายนอก
- Interface Adapters – ทำหน้าที่เสมือนคนกลางระหว่าง Layer ด้านในและ Layer ด้านนอก รับผิดชอบในการแปลงรูปแบบข้อมูลที่ใช้งานได้ง่ายใน Use Cases และ Entities ไปเป็นรูปแบบข้อมูลที่ใช้งานได้ง่ายที่ Layer ภายนอก
- Frameworks and Drivers – ประกอบด้วย Web Framework, User Interface, เครื่องมือ, ฐานข้อมูล และอื่นๆ โดยใน Layer จะรับผิดชอบดูแลการทำงานของเครื่องมือต่างๆ
เราสามารถเรียก Entities & Use Cases รวมกันได้ว่า “Business” หรือ “Domain”
และเราสามารถเรียก Interface Adapters & Frameworks ว่า “Infrastructure”
The Dependency Rule
กฎนี้พูดถึงว่าใน Layer ด้านในนั้น จะต้องไม่พึ่งพา Layer ด้านนอก หรือเรียกได้ว่าวงกลมด้านในจะต้องไม่รู้อะไรเลยเกี่ยวกับวงกลมด้านนอก
ชื่อของ Function, Class, Variable หรืออะไรก็ตามที่ถูกประกาศด้านนอกวงกลมจะต้องไม่ถูกเรียกโดยด้านในของวงกลม
เช่นเดียวกันกับรูปแบบของข้อมูลที่ใช้ด้านนอกวงกลม จะต้องไม่ถูกใช้งานในด้านในวงกลม โดยเฉพาะรูปแบบข้อมูลที่ถูกสร้างขึ้นมาด้วย Framework ที่ด้านนอกวงกลม
ทั้งหมดนี้เนื่องมาจากว่าเราไม่ต้องการให้ด้านนอกวงกลมส่งผลกลับด้านในวงกลมนั่นเองง
อ่านมาถึงตรงนี้แล้วอาจจะสงสัยว่า มันจะเป็นไปได้จริงหรอ? Use Cases มันก็จำเป็นต้องสื่อสารกับภายนอก หรือสื่อสารไปที่ Adapter เพื่อใช้งาน Use Cases นั้นๆ
คำตอบคือ ทำได้จริง! เพราะเรามีสิ่งที่เรียกว่า “Dependency Injection”
โดยมี Interface ที่ถูกกำหนดไว้ในด้านในวงกลม และถูกนำมา Implement ด้านนอก
Common Misconception
Data Access
แม้ว่าจะน่าดึงดูดใจที่จะกำหนดเกตเวย์การเข้าถึงข้อมูลภายในเลเยอร์ Framework & Drivers แต่นั่นไม่ใช่ที่ที่เกตเวย์ควรอยู่! เพียงเพราะคุณใช้เฟรมเวิร์กหรือไดรเวอร์เพื่อร้องขอฐานข้อมูลของคุณ ไม่ได้ทำให้เกตเวย์ของคุณเป็นส่วนหนึ่งของเลเยอร์ด้านนอกสุด
ลักษณะสำคัญคือการไหลของข้อมูล: เป็นเกตเวย์สำหรับการเข้าถึงข้อมูล ซึ่งเห็นได้ชัดเจนในไดอะแกรม Clean Architecture: เกตเวย์เป็นส่วนหนึ่งของเลเยอร์ Interface Adapters
Controller
ถ้าเราลองทำตามสิ่งที่ Clean Architecture กำหนดอย่างเคร่งคัด เราอาจจะเจอปัญหาเกี่ยวกับการนิยาม Controller เนื่องด้วยระบบส่วนใหญ่ Controller จะใช้ฟังก์ชันบางอย่างจาก Framework ทำให้ไม่สอดคล้องกับหลักการ The Dependency Rule
จริงๆแล้วนั้น Controller สามารถอยู่ในหลาย Layer ได้ ซึ่งมักจะอยู่ในส่วนของ Framework & Driver และ Interface Adapters Layer
ซึ่งเราสามารถทำให้ Controller ที่อยู่ในส่วนของ Interface Adapters เป็นอิสระจาก Framework & Driver ได้ด้วยการ แบ่ง Controller ทุกตัวให้อยู่ในทั้ง 2 Layer และแปลงรูปแบบของ Response จาก Interface Adapters ไปที่ Framework & Driver
อย่างไรก็ตามในทางปฏิบัติ แนวคิดนี้มีข้อเสียหลายอย่างและอาจไม่ได้มีประโยชน์ อ่าว 555
Presenter
เป็นส่วนที่ทำงานร่วมกับ User Interface หากเรามองในมุมมองของ Humble Object User Interface จะเป็นส่วนที่ทดสอบได้ยากและ Presenter จะเป็นส่วนที่สามารถทดสอบได้
ซึ่ง Presenter ก็จะเป็นส่วนที่รับผิดชอบในการรับส่งข้อมูลจาก User Interface นั่นเองง
ในบริบทของ Front-End นั้น Controller ทำหน้าที่ประสานงานระหว่างคำสั่งของผู้ใช้กับ Use Cases ของซอฟต์แวร์ ส่วน Presenter ทำหน้าที่แปลงรูปแบบข้อมูลที่ได้รับจาก User Interface
Crossing Boundaries
ลุงบ๊อบนั้นเน้นย้ำในเรื่องของการที่ข้อมูลไหลข้าม Layer นอกจากที่จะใช้ Dependency Injection เพื่อให้เป็นไปตามกฎของ Dependency Rule แต่ต้องระวังในเรื่องของประเภทข้อมูลที่ไหลข้าม Layer ด้วย
เราคงไม่ต้องการใช้โครงสร้างข้อมูลที่ออกมาจาก Framework หรือ Library ไปใช้งานในทุก Layer เราควรแปลงโครงสร้างของข้อมูลเป็นโครงสร้างที่ง่ายเพื่อนำไปใช้งานต่อสำหรับวงกลมด้านใน
Entities นั้นไม่ใช่กฎที่ตายตัว เช่น โดยปกติ Repository จะส่งค่ากลับมาเป็น Entities เพราะ Repository เป็นตัวกลางในการเข้าถึงข้อมูลจากฐานข้อมูล
// item คือ Entity ที่ได้จากฐานข้อมูล
const item = await itemRepository.findById(item_id);
ในทางกลับกันเราก็ไม่อยากให้ Entity ถูกใช้งานนอกเหนือจาก Layer ของ Use Cases และเมื่อไหร่ก็ตามที่ Entities อยู่นอก Layer ของ Use Cases แปลว่าเริ่มมีกลิ่นแปลกๆเกี่ยวกับ Architecture นี้แล้วนะ (เขาเรียกกันว่า Architecture Smell)
มีแค่ 4 Layer?
Clean Architecture สามารถเปลี่ยนแปลงจำนวน Layer ได้ขึ้นอยู่กับความต้องการในการใช้งาน
การลด Layer อาจะทำให้ Architecture เราดูเรียบง่ายขึ้น แต่ก็อาจส่งผลให้ความสามารถในการประกอบส่วนต่างๆและความยืดหยุ่นของซอฟต์แวร์เราลดลง
การเพิ่ม Layer ก็เป็นไปได้เช่นกัน เช่น การเพิ่ม Domain Layer ที่อยู่ระหว่าง Layer ของ Entities และ Use Cases
โดย Domain Layer มักจะเก็บเกี่ยวกับตรรกะหรือกฎเกณฑ์ของธุรกิจที่เป็นพื้นฐานของซอฟต์แวร์ จะช่วยให้สามารถบำรุงรักษาได้ง่าย ที่สำคัญคือช่วยให้สามารถทำความเข้าใจโค้ดของเราได้ง่ายยิ่งขึ้นด้วยนะ
สิ่งที่ไม่ใช่ Clean Architecture
Domain-Driven-Design (DDD)
มีหลายหลักการที่เราเจอใน Clean Architecture และมีต้นกำเนิดมาจาก DDD เช่น Domain Services, Domain Events, Domain-specific Value Objects ซึ่งก็จะเป็นส่วนเสริมที่ดีของ Clean Architecture แต่ไม่ใช่ส่วนหลักที่จำเป็นต้องมี
CQS/CQRS
เราอาจจะพบสิ่งที่เรียกว่า Commands และ Queries แทนการใช้ Use Cases ซึ่งเป็นหลักการที่มาจาก CQS & CQRS ซึ่งสามารถทำงานร่วมกับ Clean Architecture ได้ดี แต่ก็ไม่ใช่ส่วนหลักของ Clean Architecture
ความแตกต่างระหว่าง Clean Architecture และ Onion Architecture
แม้ว่า 2 Architecture นี้จะดูคล้ายกัน แต่ก็มีพื้นฐานที่ต่างกันนะ
| หัวข้อ / Architecture | Onion Architecture | Clean Architecture |
| การแบ่ง Layer | แบ่ง Layer จากบทบาท | แบ่ง Layer จาก การไหลของข้อมูลและ Dependencies |
| ทิศทางของ Dependency | Invert Dependencies* | จะพึ่งพากันจากชั้นด้านนอก ไปที่ชั้นด้านใน |
| จุดสำคัญ | เน้นการแยกส่วนผ่าน การจัด Layer | เน้น Dependency และแยกส่วนโดยอ้างอิงตาม การไหลของข้อมูล |
บทความเพิ่มเติม
- Clean Architecture by Uncle Bob
- Hexagonal Architecture
- Onion Architecture
- Lean Architecture: for Agile Software Development
- Object-Oriented Software Engineering: A Use Case Driven Approach
- Data, context and interaction
- Use Cases
- Screaming Architecture
- Humble Object
- xUnit Test Patterns: Refactoring Test Code
- Component Design Principles
- CQS
- CQRS


Leave a comment