Quantcast
Channel: cc :: somkiat
Viewing all articles
Browse latest Browse all 1997

สรุปเรื่องของ A theory of modern Go

$
0
0

จากบทความในโค้ดทัวร์ ตอน 1 ทำการอธิบาย code ที่เขียนด้วยภาษา Go มีรูปแบบหรือ pattern ที่น่าสนใจหลายตัว หนึ่งในนั้นคือ NewEntry(url string) [gist id="859ae178eb1a6e1f7636ca934e4a98e6" file="1.go"] ทำให้นึกถึงเรื่องของ A Theory of modern Go ซึ่งอธิบายถึงเกี่ยวกับ Global state/variable จึงนำมาสรุปไว้นิดหน่อย

ในภาษา Go นั้นพยายามจะไม่มี magic ในตัวภาษา

เนื่องจาก magic เป็นสิ่งที่ไม่ดี ส่งผลเสียเยอะ แต่ก็มีข้อดีนะ เพื่อทำให้ code อ่านเข้าใจได้ง่าย เพื่อทำให้ code ดูแลรักษาได้ง่าย แต่โชคไม่ดีเท่าไร ที่ Go developer มักจะสร้าง magic ขึ้นมาใช้เอง ยกตัวอย่างเช่น Global state/variable หรือ variable ในระดับ package !! ซึ่งทำให้ code อ่านและดูแลรักษายากมาก ๆ
คำถาม ใครทำแบบนี้อยู่บ้าง ?
จาก tweet ของ Dave Cheney พูดถึง Modern Go ไว้ว่า
  • No side effect imports
  • No package level variables
นั่นคือ ลด ละ เลิก Global state/variable ในระดับ package !! หรือการใช้งานให้น้อยที่สุด

มาดูแนวทางกันที่อธิบายไว้ในบทความ

สร้าง function NewXxxx() ขึ้นมาใช้งาน ใช้สำหรับการสร้าง instance ซึ่งทำหน้าที่เหมือนกับ constructor นั่นเอง ดังนั้นผู้เรียกใช้ก็ทำการสร้าง instance ผ่านทาง function นี้ ที่สำคัญต้องสร้างข้อตกลงร่วมกันภายในทีมด้วย ว่าต้องไม่สร้าง instance แบบตรง ๆ เหมือนเดิม ยังไม่พอนะ ถ้าใน NewXxx() มี dependency ต่าง ๆ ด้วย [gist id="859ae178eb1a6e1f7636ca934e4a98e6" file="2.go"] คำอธิบาย จะเห็นได้ว่ามีการ function จาก package database/sql.Conn, logger และ pool เป็นการทำงานภายในของ function นี้ เรียกว่าคือ dependency ซึ่งทำให้เกิดผลกระทบตามมา ทั้ง dbconn, logger และ pool ต่างก็เป็น variable ในระดับ package !! นั่นหมายความว่า ผู้เรียกใช้งานและเปลี่ยนค่าต่าง ๆ ได้เลย ทำให้ไม่สามารถคาดการได้เลยว่าจะเกิดอะไรขึ้นบ้าง ? database จะล่มไหม ? network จะช้าไหม ? ดึงข้อมูลจาก database ถูกหรือไม่ ? จะมี request ใน pool ไหม ?

ดังนั้นสิ่งที่ควรทำคือ ทำการส่งค่า dependency ต่าง ๆ ผ่าน parameter เข้ามาได้เลย

เรามักเรียกวิธีการนี้ว่า Dependency Injection นั่นเอง ทำให้ผู้ใช้งานอ่านเข้าใจได้ทันทีว่า ถ้าต้องการให้ทำงานอย่างถูกต้องแล้ว ต้องทำการส่ง parameter อะไรเข้ามาบ้าง เขียนได้ดังนี้ [gist id="859ae178eb1a6e1f7636ca934e4a98e6" file="3.go"] มันดูดีขึ้นนะ แถมไม่มีตัวแปรระดับ package อีก

แต่ถ้าต้องการให้ package นี้เป็น public API สามารถทำให้ดีกว่านี้ได้อีก

นั่นคือการสร้าง interface ขึ้นมา เพื่อไม่ให้เกิดการผูกมัดกันเกินไป แถมยังช่วยให้ทดสอบด้วยการ mock dependency ต่าง ๆ ง่ายขึ้นอีกด้วย เขียนได้ดังนี้ [gist id="859ae178eb1a6e1f7636ca934e4a98e6" file="4.go"]

สังเกตไหมว่า

เมื่อเหล่า constructor และ function ต่าง ๆ มีหน้าที่การทำงานและขอบเขตที่ชัดเจน กำหนด dependency ต่าง ๆ อย่างชัดเจนแล้ว เราไม่จำเป็นต้องมี global variable หรือ variable ในระดับ package อีกต่อไป เป็นการลด magic ต่าง ๆ ลงไป ผลที่ตามมาคือ การ refactor ที่ง่ายขึ้น การดูแลรักษา code ง่ายขึ้น ดูเพิ่มเติมสำหรับการเขียนตามแนวทางนี่จาก Go kit
วันนี้ Go developer เขียน code กันอย่างไร ? มัน simple ตามแนวคิดของภาษาหรือเปล่านะ ?
 

Viewing all articles
Browse latest Browse all 1997

Trending Articles