มาเล่น Go-Kit กัน
นอกจาก Design Pattern ที่ใช้อยู่ของ acoshift ที่ Production อยู่แล้ว ผมก็ยังศึกษา Go-Kit อยูด้วยนะ
มันวางตัวเป็น toolkit for microservice ใช้ domain-driven design (DDD) และ declarative composition เหมือนกันในการวางโครงให้กับ Service ของเรา ใช้ interface เป็น contracts หรือข้อตกลงระหว่าง Layer ของ Transport → Endpoint → Service แบบเดียวกัน
ในปี 2014 ผู้สร้าง Go kit คือ Peter Bourgon แห่ง SoundCloud เขาพบว่าหลายทีมเลือกใช้ Scala และ JVM เพียงเพราะมันมีเครื่องมือตัวช่วยสำหรับ Microservice เยอะ ซึ่งในขณะนั้นโกไม่มีเครื่องมือในระดับเดียวกันอยู่เลย จึงเป็นต้นกำเนิดไอเดียที่เขาทำ Go Kit ขึ้นมา
a set of standards, best practices, and usable components for doing microservices in Go
ไอเดียที่ได้
Go kit ให้ไอเดียของการแยกดีไซน์ของไมโครเซอรวิสออกเป็น 3 ชั้น
ตามนี้ Transport, Endpoint, Service(Business logic) สอดคล้องกับแนวคิดของ Clean Architecture
Request จาก Service อื่นๆ หรือ Client จะผ่านเข้ามาเป็นชั้นทาง Transport → Endpoint → Service และการ Response จะย้อนกลับไปเป็นชั้นๆ เช่นเดียวกัน การออกแบบลักษณะนี้เรียกอีกอย่างว่า Separation of Concern คือ ชั้นข้างนอกจะ “สนใจ” รู้จักชั้นด้านในถัดไปเท่านั้น ตัวมันจะไม่สนใจข้างนอก ใครจะมาคุยกับมันก็จะมี “บริการ” ของแต่ละชั้นให้
Go kit รองรับ Transport ที่หลากหลายพร้อมๆกันใน Service เดียว เช่น NATS, gRPC, Thrift, HTTP, AMQP กระทั่ง AWS Lambda เป็นต้น
โดยที่การสื่อสารภายในของ Go kit จะใช้ RPC เป็นหลัก ซึ่งตัว endpoint ก็คือ RPC method ที่ทำการ map Service method ออกมานั่นเอง แต่ละ endpoint สามารถถูกเรียกใช้ได้จาก Transport หลายๆ ตัวได้
ส่วนชั้นของ Service คือที่เก็บ Business Logic ไว้ด้านใน ส่วนนี้ทำให้ developer ที่ทำ application ไม่ต้องสนใจเกี่ยวกับ endpoints หรือ transports ใดๆ เพราะ Go kit จัดการให้หมดแล้ว โดยที่ตัว service เองจะวางโครงเป็น interface และ implement business logic ไว้ข้างใน
จากแนวคิดของ separation of concerns นี้ Go kit ให้ความมั่นใจกับคุณที่จะรับเอา SOLID design principles และ clean architecture เข้ามาในระบบของคุณ
ซึ่งที่จริงแล้วโค้ดตัวอย่างเป็น Monolith ทั้งนั้น
การใช้ Middleware เป็นอย่างไร?
Go kit ใช้ separation of concerns ไปไกลมากขึ้นด้วยการใช้ middleware โดยใช้ “Decorator pattern” มี middleware ให้ใช้ทั้งในชั้นของ endpoint ในขณะที่ application developer สามารถเขียน middleware สำหรับชั้นของ service ขึ้นมาเองก็ได้ และเขียนเป็นลูกโซ่ (chain middleware) ได้ด้วย
ตัวอย่างของ middleware ที่ Go-kit เตรียมมาให้
- Endpoint: Load balancing, safety, operational metrics, circuit breaking, rate limiting.
- Service: app-level logging, analytics, and instrumentation.
ตาม decorator pattern, endpoint middleware จะรับ endpoint และ return endpoint, service middleware จะรับ service และ return service
มีแพคเกจอะไรให้ใช้งานบ้าง?
ตัวอย่างนี้ยังไม่ใช่ทั้งหมดนะ
- Authentication: Basic, casbin, JWT.
- Circuit Breaker: Hystrix, GoBreaker, and HandyBreaker.
- Logging: Provide an interface for structured logging. Recognizes that logs are data. They need context and semantics to be useful for analysis. Supported formats are logfmt and JSON.
- Metrics: Provides uniform interfaces for service instrumentation. Comes with counters, gauges, and histograms. Has adapters for CloudWatch, Prometheus, Graphite, DogStatsD, StatsD, expvar, and more.
- Rate Limit: Uses Go’s token bucket implementation.
- Service Discovery: Consul, DNS SRV, etcd, Eureka, ZooKeeper, and more.
- Tracing: OpenCensus, OpenTracing, and Zipkin.
- Transport: AMQP, AWS Lambda, gRPC, HTTP, NATS, Thrift.
Bestpractice อะไรที่เราได้จาก Go Kit
Framework อื่นๆ อาจใช้ dependency injection แต่ใน go-kit จะใช้การ wire up ชิ้นส่วนทั้งหมดจาก func main บังคับให้คุณประกาศค่าต่างๆ ของส่วนประกอบทั้งหมดผ่าน constructors หลีกเลี่ยงการสร้าง global state
Errors ควรจะถูก encoded สองแบบคือ ใส่เป็น error field ใน response struct สำหรับ service และ return error value สำหรับ endpoints
แต่ละ service ไม่ควรเก็บหรือจัดการ logs เอง ปล่อยให้เป็นหน้าที่ของ platform เช่น gcloud ก็จะใช้ Stackdriver มาจัดการให้ service ควรพ่น log ออกทาง stdout/stderr ก็พอ
สำหรับคำวิพากษ์ว่า Go-Kit is too verbose
อันนี้จริง การใส่ API ให้กับ microservice มันต้องการ boilerplate code ซึ่งก็มี Tools หลายตัวเข้ามาช่วยเช่น kitgen, gokit cli เป็นต้น แต่ที่เจ๋งและอยากจะลองถัดจากนี้คือ Grab-kit ที่สร้างขึ้นด้วยทีมของ Grab ซึ่งเห็นว่า go-kit มีงานหลายอย่างที่ต้องทำมืออยู่มาก Grab-kit ก็เลยทำขึ้นมาเพื่อให้หลายอย่างเป็นมาตรฐานเดียวกันให้กับทีม
สรุป
Go kit ไม่ได้เหมาะสำหรับมือใหม่เขียนโก (ใจเย็นๆ ให้ไปหัดเฟรมเวิร์คสำเร็จรูปก่อนก็ได้) แต่สำหรับทหารผ่านศึกที่มีพื้นฐานการใช้งาน net/http, interface, database connector, middle ware มาระดับหนึ่งแล้ว สามารถใช้ Go Kit เป็นเครื่องมือในการฝึกฝนการโค้ดด้วยสถาปัตยกรรมแบบสะอาด เรียนรู้ Design Pattern ดีๆ อย่าง SOLID, Separation of Concerns, Decorator pattern เหล่านี้มาวางโครงสร้างโค้ดให้ทีมทำงานร่วมกันง่าย มีมาตรฐานเดียวกัน แบ่งงานกันทำแล้วไม่พัง และ Scale งานที่ซับซ้อนออกมาได้ แม้จะจบในโค้ดเบสเดียวออกมาเป็น Monolith Service ก็ตาม โครงสร้างที่ได้ก็พร้อมจะแตก Domain/Service ภายในออกมารันแยก Micro-Service ได้ในอนาคตโดยไม่ยากเย็น
อ้างอิง
https://medium.com/swlh/getting-started-with-go-kit-f2ccf71d491f