Clean architecture

Chokchai Phatharamalai
odds.team
Published in
3 min readSep 2, 2024

ผมได้ยินคำว่า clean architecture หลายครั้ง ตัวผมเองไม่เคยศึกษามันจริงจัง แต่พอมีโอกาสได้ทำงานกับระบบที่ใช้ clean architecture แล้วเขียน unit test ยากเย็นเกินจริง ผมจึงต้องตามหาว่า clean architecture มันคืออะไรนะ จนผมเจอจิ๊กซอว์ที่หายไปในระบบที่ผมทำงานด้วย

สิ่งที่ผมเห็น

สิ่งที่ผมสังเกตเห็นในระบบที่เรียกตัวเองว่าใช้ clean architecture คือ จะแบ่ง package นอกสุดตาม feature ต่าง ๆ และในแต่ละ feature จะค่อยแบ่งเป็น layer ภายใน feature นั้น ๆ ตั้งแต่ controllers, use cases, entities เป็นต้น

สิ่งที่ขัดใจผม

คือมันมันมี layer ของ usecase เข้ามาขั้นอีกชั้น เช่นพอเราทำ backend จากเดิม handler เรียก repository ตอนนี้ผมมี usecase อีกชั้นมาขั้นระหว่าง handler กับ repository

มี usecase มาขั้นระหว่าง handler กับ repository

และใน unit test ของ handler ที่ผมเจอก็ mock use case ส่วน unit test ของ use case ก็ mock repository อีกที

HandlerTest
UsecaseTest
ตัวอย่าง usecase test ที่ mock repository

ตัวผมเองที่ชอบ Chicago style TDD (mock เมื่อจำเป็น) ขัดใจกับ London style TDD (mock ทุกสิ่ง เน้น test isolation) ที่ผมเจออยู่มาก พอได้ศึกษาดูเจอว่า บทความ clean architecture เขียนโดย uncle Bob และเค้าก็ prefer Chicago style เหมือนผม

จิ๊กซอว์ที่หายไป

ถ้าลองดูรูปที่ uncle Bob อธิบาย

The Clean Architecture source: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

สิ่งที่หายไปจากระบบที่เคลมว่าใช้ clean architecture คือ The Dependency Rule นี่แหละ

กฎบอกว่า dependency ของ source code จะชี้เข้าด้านในได้เท่านั้น ของที่อยู่ชั้นในจะรู้อะไรเกี่ยวกับชั้นนอกไม่ได้เลย ไม่ว่าจะเป็น class, function, ตัวแปร หรือสิ่งอื่นใด

ถ้าเราดูบรรทัด import ที่ต้น file จะเห็นว่า usecase ที่อยู่ด้านใน จะ import repository ที่อยู่ด้านนอกไม่ได้

usecase import repository ไม่ได้

ถ้าเราจะเคารพ dependency rules code ก็จะเปลี่ยนหน้าตาเป็นแบบนี้แทน

usecase returns entity ให้ handler ไปเรียก repository ต่อให้

ซึ่งทำให้ test หน้าตาเปลี่ยนไปด้วย

ตัวอย่าง usecase test ที่ไม่มี dependency ไปยัง repository

สังเกตว่า เราไม่ต้อง mock อะไรเพื่อเขียน test เลย เราสามารถจำลองสถานการณ์ต่าง ๆ ขึ้นมาได้จาก input และ output ของ usecase เฉย ๆ

ถ้าเราจัดโครงสร้างแบบนี้ได้ ก็ไม่ยากที่เราจะมี test drive business logic ของเราได้อย่างง่าย ๆ ไม่ต่างอะไรกับการทำ programming kata แล้ว

ผมเจอคนถามบ่อยมากว่าฝึกทำ TDD กับ programming kata แล้ว จะเอาไปใช้ในงานจริงอย่างไร ซึ่งที่ผ่านมาผมตอบได้เพียง ต้องฝึกแยก business logic ออกจาก code ของ framework ต่าง ๆ ให้ได้ก่อน แล้วก็จะทำในงานจริงได้เช่นกัน

พอได้ศึกษา clean architecture ถึงตรงนี้ ผมพูดได้ชัดขึ้นว่า ถ้าเราเคารพ dependency rules code เราจะไม่ depend on framework เพราะ framework อยู่ชั้นสีเขียว มันจะเป็น code ที่เรียก framework จะ depend on business logic ของเราแทน และในชั้นสีแดงเข้าไป ทุกอย่างอยู่ใน memory หมดเหมือน programming kata เลย

ที่ผมเลือกเรื่องนี้มาแบ่งปันเพราะว่า เมื่อก่อนตอนผมจบมาใหม่ ๆ กว่าจะศึกษาสักเรื่องอย่าง clean architecture ใช้เวลาเป็นเดือน ๆ เลย แล้วในโลกซอฟต์แวร์ที่ทุกอย่างเปลี่ยนแปลงบ่อย บางครั้งมันก็อดท้อแท้ไม่ได้ ยังศึกษาเรื่องเก่าไม่ทันเสร็จเลย เรื่องใหม่ออกมาอีก 3 เรื่องแล้ว

วันนี้ที่พอจะเข้าใจ clean architecture อ่านบทความไม่ถึงชั่วโมงก็เข้าใจได้แล้ว เพราะน้ำพักน้ำแรงของตัวผมในวัยเด็กที่อดทนศึกษา ฝึกฝน มีกำลังใจก็อ่าน เหนื่อยก็พัก แต่ไม่ล้มเลิกเนี่ยแหละที่ค่อย ๆ สะสมไปทีละหยาดหยดของความรู้ วันหนึ่งมันก็เป็นทะเลสาบได้เหมือนกันนะ

นอกจากนี้ ถึงผมอาจจะไม่ใช่คนที่มีชื่อเสียงหรือชำนาญด้าน architecture ที่สุด แต่ผมก็เลือกจะแบ่งปันเท่าที่ผมมี มันต้องมีประโยชน์กับคนอื่นบ้างแหละน่า และมันก็ยังเปิดโอกาสให้คนที่เก่งกว่าผมได้แลกเปลี่ยนให้ผมเติบโต หรือปรับความเข้าใจให้ลึกซึ้งขึ้นด้วย

ที่ทุกวันนี้เราสามารถดื่มด่ำกับเสียงนกในป่าได้ เพราะนกทุกตัว ไม่ว่าจะร้องเพราะมากหรือน้อยต่างขับขานเสียงของมันตามสภาพที่มี ถ้าเราอนุญาตให้เพียงนกที่ร้องเพราะที่สุดเท่านั้นร้อง ป่าจะเงียบกว่าที่เป็นอยู่มากเลย

อ้างอิง

ขอบคุณ Weerasak Chongnguluam ที่แบ่งปันคลิปด้านล่าง Moving I/O to the edges อธิบายสิ่งที่ผมอยากสื่อในบทความนี้ได้ดี

c

--

--