Showerthought: On FP and OOP
Chakrit Likitkhajorn
Posted on December 13, 2019
อันนี้จะเป็น Series Showerthought ซึ่งจะเขียนแบบร่ายยาวไม่ปูทางอะไรมาก ระบายความคิดออกมาเฉยๆ
ช่วงนี้เปิดเรียน Domain Driven design แบบสมัยเก่า ที่เขายังบริหาร Complex domain ด้วย Monolith กัน (ซึ่งดีมากๆ ได้วิธีคิดหลายอย่างที่ใช้ในการเขียนโค้ดให้ดีได้) แล้วมันเห็นพลังอย่างหนึ่งของหลักการ Object-oriented คือหลักการที่ว่า ให้เอา Operation ที่ทำกับ Data ไว้ที่เดียวกันใน Object
คือเวลา Codebase ใหญ่ๆ ถ้ามันมีหลักแบบนี้ เวลาเกิดปัญหาหรือจะแก้ไขโค้ดก็ตามง่ายไง สมมติว่ามีคนบอกว่าช่วยทำให้ User มีชื่อเล่นให้หน่อย ก็รู้ละว่าให้ไปดูแถวๆ User Object หรือถ้ามีคนบอกว่า User Login ไม่ได้ เราก็ไปหาตรง User
แต่พอเราไปวิธีนี้มากๆ เข้า บางครั้งจุดเด่นของระบบมันอยู่ที่ Operation เช่น ถ้าคุณสร้างของที่คล้ายๆ Sendgrid ขึ้นมา ตัว Operation ที่ชื่อว่าส่งอีเมล์ (SendEmail) มันจะเป็นศูนย์กลางของระบบ หรือถ้าทำระบบเคลมประกัน ตัว Operation การส่งเคลม ก็เป็นศูนย์กลางของระบบ
ถามว่าถ้าเราเอาไปกระจายว่าเรามี ProductA.claim()
หรือ ProductB.claim()
หรือ ProductC.claim()
ไปทั่ว มันเข้าหลัก OOP นะ แต่แล้วเนื่องจากการเคลมประกันเป็นศูนย์กลางของระบบ ที่น่าจะถูกแก้ไข พัฒนา ปรับปรุง บ่อยมากๆ แล้วถ้าเราไปยึดกฎอีกว่า 1 Class = 1 File สิ่งที่เกิดขึ้นก็คือการแก้ไขระบบส่วนมากเราต้องเปิดไฟล์หลายๆ ไฟล์ แก้หลายๆ ที่ ดูหลายๆ จอพร้อมๆ กัน ซิงค์กันตลอด มันก็ทำงานลำบากกว่าที่ควรเป็น
แต่ถ้าใน FP Language ที่มี Pattern matching ผมยกตัวอย่าง Elixir ละกัน เราสามารถ
defmodule Claim do
def claim(%ProductA{} = product) do
end
def claim(%ProductB{} = product) do
end
def claim(%ProductC{} = product) do
end
end
ซึ่งถ้าเราใช้ OOP เราจะโมเดลแบบนี้ได้มั้ย ได้สิ เราก็แค่หาคำนามที่แทนกริยาการ Claim มาเข้าระบบ ผมเอาคำว่าใบรับประกัน (Warranty certification) เข้ามา
public class WarrantyCertification {
// Something
public void Claim(Product product) {
// Claiming
}
}
ทีนี้เราก็สามารถแรเงาขับเน้น Operation การเคลมได้แล้ว
ในทางกลับกัน แม้แต่ใน Functional programming หลายๆ ครั้งเราก็ไม่ได้มีระบบที่ Operation ควรจะเป็นศูนย์กลาง เช่น ถ้าเราจะหาว่าเวลาเคลม ของต้องซ่อมหรือเปลี่ยนใหม่ หรือ reimburse ซึ่งขึ้นอยู่กับปัจจัยหลายๆ อย่างมากเลยต้องคำนวณมา
defmodule xxxx do
def get_compensate_operation(product, warranty) do
# Here
end
end
คำถามคือเราจะตั้งชื่อ Module xxx นี้ยังไงให้หาได้ง่ายๆ ???? ถ้าเราตั้งชื่อว่า CalculateWarranty แล้วระบบเราจะไม่เต็มไปด้วยโมดูลเล็กๆ ที่มีแค่ 1 ฟังก์ชั่น แล้วกลายเป็นว่ามีไฟล์เป็นพันๆ ไฟล์ หาของกันไม่เจอหรือเปล่า??
ซึ่ง OOP มอบกฎให้ว่า ไปวางไว้ใน Data ที่เกี่ยวข้อง กรณีนี้คือไปวางไว้ในใบ Class WarrantyCertification ได้
พอมีกฎนี้การหาของทุกอย่างก็ง่ายขึ้นในกรณีนี้
ซึ่งกรณีนี้ถ้าเราทำ Functional เราก็อาจจะต้องไปวางไว้ใน Warranty เหมือนกันนะ ผมคงสร้าง Module นั้นขึ้นมา
มันทำให้ตกผลึกว่า ถ้าใช้ภาษา OOP ต้องรู้ว่าตัวภาษามันมีแนวโน้มที่จะเน้นคำนาม บางครั้งถ้าเราต้องการเน้นคำกริยา เน้น Operation บางอย่าง เราต้องหาคำนามมาใส่ให้มันถึงจะเมคเซนส์ในภาษา OOP
และถ้าใช้ภาษา Functional หลักการที่ว่าเอา Operation มาใกล้ๆ กับ Data ก็ยังเป็นอะไรที่ช่วยได้ในกรณีทั่วไปจริงๆ ยกเว้นเคสที่เราต้องการเน้น Operation ให้มันเป็นศูนย์กลางการแก้ไขปรับปรุงของระบบ
การเลือกแรเงา ลงสี ขับเน้น แต่ส่วนของระบบ สร้าง Contrast สร้างความสำคัญ สร้างความ Trivia เป็นศิลปะในการออกแบบโค้ดเบสและการบริหารโปรแกรมเมอร์ เพราะถ้าโค้ดเบสตรงไหนถูกออกแบบมาให้ Trivia ก็จะไม่มีใครไปแตะ และถ้าตรงไหนถูกขับเน้น คนก็จะแตะมากขึ้น
นี่เป็นเครื่องมือการบริหารทีมโปรแกรมเมอร์ที่ดีมากและไม่ค่อยมีใครเข้าใจหรือพูดถึง
Posted on December 13, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
March 21, 2024