Key Highlights:
- Clean Architecture เป็นรูปแบบการเขียนโค้ดรูปแบบหนึ่งที่แยกการทำงานของโค้ด ตามหน้าที่ของมัน และไม่สามารถเรียกข้าม Layer ได้ ที่สำคัญคือ การเรียกใช้งานจะเป็นแบบ Outer Layer to Inner Layer
- กรณีที่ Requirement Change ก็หมดปัญหากับการแก้ Souce Code มากมายก่ายกอง เพราะด้วยความที่ Clean Architecture แยกเป็น Layer ทำให้ถ้า database เปลี่ยน เราก็แก้แค่ 1 Layer โดยที่มันไม่ไปกระทบ กับ Layer อื่นๆ
จากที่ได้ลองศึกษาเกี่ยวกับ Clean Code Architecture จาก ลุงบ๊อบมาสักพัก เราก็เกิดอาการคันมือขึ้นมา อยากจะลองนำมาใช้กับการ Coding ซึ่งประจวบเหมาะกับเพิ่งได้มาศึกษา GoLang พอดี ก็เลยนำมาลอง Apply กันดู เลยอยากจะมาแชร์การนำ Clean Architecure มาใช้กับ GoLang ในบทความนี้ครับ
ก่อนอื่นขออธิบายเกี่ยวกับ Clean Architect ก่อน
What’s Clean Architecture ?
Clean architect คือสถาปัตยกรรม (รูปแบบ) ในการเขียนโค้ดชนิดหนึ่ง ซึ่งเราจะแยกการทำงานของโค้ดตามหน้าที่ (Responsibilities) ของมัน
จากรูปด้านบนจะเห็นได้ว่า ลุงบ๊อบเขาได้แบ่ง Architecture มาเป็น 4 Layers ใหญ่ๆ (ปล. อันนี้เป็นทฤษฏีเนาะ ตอนเอาไปใช้จริงสามารถปรับใช้ได้ตามหน้างาน อย่ายึดติดมาก เพราะแต่ละ Techstack มันไม่ได้เหมือนกันหมด ต้องมาปรับใช้กันไป)
ทีนี้ 4 Layers มีอะไรบ้าง มาดูกัน
- Entities: เปรียบเสมือน Data Model ของเรา ที่ไว้คอยจำแนก หรือประกาศ ว่า Data เราจะเก็บอะไรบ้าง มี Structure ยังไง
- Use Case: เป็นส่วนที่ไว้เก็บพวก Business Logic ต่างๆ แล้วคอยเรียกใช้งาน Entity อีกที
- Interface Adapter: ส่วนนี้ ถ้าจะให้มองง่ายๆ มันเหมือนกับเป็นตัวแปลงที่คอยเชื่อมต่อ ระหว่าง Frameworks Layer กับ Use Case layer สมมติว่าเรามีการเรียกใช้ Use Case ผ่าน Frameworks หลายๆเจ้า เจ้า Interface Adapter ก็จะคอยช่วยแปลงให้สามารถสื่อสารกับ Use Case ได้
- Frameworks & Driver: ส่วนนี้จะเป็นพวก Request ต่างๆ รวมไปถึง External Library
**ตาม Concept ของ Clean Architect แล้ว เราไม่สามารถให้แต่ละ Layer เรียกข้าม Layer ไปอีกอันได้ เช่น เราไม่สามารถ เรียก Frameworks Layer ข้ามไป Use Case Layer โดยไม่ผ่าน Interface Layer เพราะมันจะทำให้ Concept ตัวนี้ผิดเพีเยนไปเลย ต้องระวังไว้นะ
**การเรียกใช้ Layer จะเป็นการเรียกจาก Outer Layer ไป Inner Layer ไม่ควรให้ Inner Layer เรียกใช้ Outer
ทีนี้…ลองมาดูข้อดีของการใช้ Clean Architect กัน
Why do we use Clean Architect ?
ทำไมเราถึงต้องใช้ Clean Architect ทั้งๆที่มี Architect แบบอื่นอีกมากมาย
สมมติว่าเรา Develop Backend services มาตัวนึง ซึ่งตอนแรกมีการ Define Techstack แบบนี้
Database: MongoDB
Language: NodeJs
Gateway: HTTP Server
โดยส่วนมาก พอเรา Define มาแบบนี้ ก็จะเริ่ม Develop เลย เขียน Config ต่างๆ Model ต่างๆ ให้มันเชื่อมต่อกับ MongoDB ได้ ทำ API เสร็จพร้อมส่ง
…แล้วถ้าหากดันมี Requirement Change ขึ้นมาว่า “ต้องการเปลี่ยนจาก MongoDB ไปใช้พวก Relational DB แทน” ทีนี้ปัญหาก็จะเกิดขึ้นกับฝั่ง Development เพราะต้องมานั่ง แก้ Source Code เยอะแยะ จนคล้ายๆกับว่าทำใหม่
ซึ่ง Clean Architect สามารถเข้ามาแก้ไขปัญหาเหล่านี้ได้
ลองมองภาพว่า Clean Architect มันคือการแยก Layer ออกมาตาม Responsibilities นั่นหมายความว่าถ้าเราจะเปลี่ยน Database เราก็แก้แค่ 1 Layer โดยที่มันไม่ไปกระทบ กับ Layer อื่นๆ (จากโจทย์นี้ เราก็แก้แค่ Interfacre Adapter Layerเพื่อเชื่อมระหว่าง Frameworks Layer กับ Use Case Layer ใหม่) ซึ่งก็ค่อนข้างจะ Flexible และประหยัดเวลามากกว่ามาก
ซึ่งจุดๆนี้ เรามองว่าเป็นจุดแข็งของ Clean Architect เลยทีเดียว
ต่อไปจะเป็นวิธีการ Apply Clean Architect กับ GoLang ว่ามันใช้กันยังไง
How to Use ?
จาก Concept ที่เราพูดมาก่อนหน้า เราจะมาลองแบ่งในรูปแบบของ GoLang กันบ้าง โดยจะแบ่งเป็น 4 Layers เหมือนกัน
Domain(Entities) : เป็น Data Model หรือ Data Structure ที่เราจะใช้
Repository : ส่วนที่จะคอยเชื่อมต่อกับ Database ซึ่งก็จะ Apply ให้เป็นไปตามแต่ละยี่ห้อ Databse ได้ เช่น Postgres, SqlServer, MongoDB ตามแต่สะดวก หรือจะเชื่อมต่อกับ External Services อื่นๆ เช่น AWS Services ต่างๆ
Use Case : เป็นส่วนที่เก็บ Business Logic ต่างๆ
Delivery : เป็นส่วนที่จะเปิดให้ข้างนอก มาเรียกใช้ API ของเรา (HTTP Request)
สังเกตุได้ว่า เราทำแบบนี้ มันไม่เห็นตรงตาม Diagram ที่ลุงบ๊อบสร้ามาเลย อย่าลืมนะครับ ว่าสิ่งที่ลุงบ๊อบเขาบอก มันคือ Concept ของ Clean Architect นั่นหมายความว่า เราก็จะมา Adapt และ Apply ให้เหมาะกับหน้างาน อีกที
จากภาพข้างล่าง จะเป็นตัวอย่างที่เรานำ Clean Architect มา Apply กับ GoLang
The growth of interest to design systems in Russian market began somewhere in the mid-tens. The starting point is probably Anton Vinogradov’s speech at PiterCSS about the architecture of Alfa-Bank’s design system in March 2016. Although the roots, of course, should be looked for earlier.
Example Clean Architect structure with GoLang
//root
|–app
|–module
|–book
|–domain
|–book_entity.go //model
|–book_repository.go //interface
|–book_usecase.go //interface
|–delivery
|–main.go
|–book_create_delivery.go
|–book_fetch_delivery.go
|–…..
|–repository
|–postgres
|–model
|–book_model_repository.go
|–main.go
|–book_create_repository.go
|–book_fetch_repository.go
|–…..
|–usecase
|–main.go
|–book_create_usecase.go
|–book_fetch_usecase.go
จาก Folder Structure จะเห็นได้ว่า เราจะแยก Responsibilities แต่ละ Directory อย่างชัดเจน
Domain : เป็น Entity ที่เราจะใช้ รวมไปถึง Interface Model ต่างๆ
Repository : เป็นส่วนที่ไว้เชื่อมต่อกับ External Data Provider ต่างๆ
Use Case : ส่วนของ Business Logic
Delivery : ส่วนของ Request Handle จากภายนอก
พอจะเห็นภาพขึ้นไหมครับ พอเราเอา Clean Architect มา Apply ปุป Soure Code เราก็มีความ Structure ปัป ทำให้ง่ายต่อการ Plugin-Plugout แต่ละ Services
ทีนี้ถ้าจากโจทย์ก่อนหน้า ว่าอยากจะเปลี่ยน Database ก็แค่แก้ไขในส่วน Repositiry Directory ก็เพียงพอ
Native (iOS & Android) vs Flutter
การนำ Clean Architect มาใช้กับการเขียนโค้ด ช่วยให้โค้ดเรามีความ flexible มากขึ้น ง่ายต่อการเพิ่มเข้า หรือถอดออกของแต่ละส่วน
ทั้งนี้ Clean Architect เป็นเพียง concept ของการเขียนโค้ดหากเราจะนำมาใช้ ต้องนำมาปรับใช้งาน หรือ structure ให้เหมาะกับแต่ละภาษาที่เราจะให้อีกที
เรามองว่ามันไม่มีถูกไม่มีผิด 100% ว่าจะวางstructure แบบไหน แค่ให้มันตรงตาม concept ก็พอ
หากผู้เขียนอธิบายส่วนไหนไม่เข้าใจหรืออธิบายผิด กราบขออภัยมาล่วงหน้านะครับ
สามารถติชมกันได้
Reference:
https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html