Single Responsibility กับ Service Granularity

Teerayut Hiruntaraporn
3 min readSep 4, 2022

--

เมื่อวานได้อ่านหนังสือ Software Architecture: The Hard Part แล้วไปเจอประเด็นที่น่าสนใจ เพราะน่าจะเจอกันในตอนทำงานบ่อยๆ

เขายกเคสตัวอย่างเรื่องหนึ่งคือ การแยก Service ที่ Software Engineer มักจะยกเรื่อง Single Responsibility Principle(SRP) มาเป็นปัจจัยในการแยก Service เช่น

ถ้าเราต้องทำ Service สำหรับส่งเมลหรือ SMS ให้กับลูกค้า Software Engineer หลายท่านก็จะบอกว่า มันต้องทำ Service มาเป็น 2 ชุด คือ Mail Service กับ SMS Service เพราะมันจะได้รับผิดชอบงานเพียงอย่างเดียว ตามหลัก SRP นั่นเอง

อย่างไรก็ตาม แม้ว่าส่วนตัวจะชื่นชอบ กับเรื่องของ SRP แต่คำว่า SRP ก็มีความ Subjective ในระดับหนึ่ง ซึ่งคำว่า Subjective นั้น คือ การที่เราเอาอะไรมาตัดสินกับคำว่า ความรับผิดชอบของ Service

มันมีทฤษฎีเรื่องหนึ่งที่ควรนำมาเข้าคู่กับมันด้วย นั่นคือเรื่องของ Level of Abstraction เช่น ในกรณีของ Notification Service นั้น เราสามารถที่จะตีความ SRP ตาม Level of Abstraction เช่น เราอาจจะตีความในมุมของ Business ทั้งก้อนว่ามันเป็น การแจ้งเตือนหาลูกค้า มันก็จะอยู่ใน Notification Service ทั้งยวง แต่ถ้าเราบอกว่ามองตาม Implementation Protocol เราก็จะได้ เป็น Service ย่อยๆ เช่น Email , SMS , Line ฯลฯ

คำถามคือเราจะเลือกระดับ Granularity Level ในระดับไหนดี ตรงนี้อาจจะต้องมีปัจจัยที่มากกว่าเพียงแค่ SRP ในการตัดสินใจ

อย่างแรกเราต้องทราบก่อนกว่า Trade-off ของ การตั้ง Service เล็กๆ ยิบย่อยไปหมดคืออะไร

ถ้าเราเขียนโปรแกรมอยู่ใน System เดี่ยว เราจะพอทราบว่า ถ้า class หรือ method มีขนาดเล็ก มันก็จะรับผิดชอบได้เฉพาะส่วน detail ของงาน

นั่นหมายถึงว่า งานและความซับซ้อนส่วนใหญ่จะถูกยิงกลับมาหา คนที่ implement ในส่วน business logic ตรงกลาง ซึ่งถ้าอยู่ภายใต้ Service ตัวเดียวกัน คนที่เขียนโปรแกรมอย่างช่ำชองแล้ว จะไม่ได้ ร้สึกถึงปัญหาตรงนี้มากนัก

อย่างไรก็ตามพอเปลี่ยนเป็น Microservice จะมีปัญหาใหม่เพิ่มขึ้นมาคือ เรื่องของ Nature ของ Distributed System เช่น เรื่องของ 8 fallacies ที่คนเพิกเฉย จนต้องไปเจ็บตัวกันในระบบจริง

ที่มา: https://architecturenotes.co/fallacies-of-distributed-systems/

ที่โหดร้ายกว่านั้น คือ ถ้าเราเจอ Software Engineer ที่เล่นบอลชายเดี่ยว ไม่สนใจว่า เพื่อนๆในทีมจะซวยแค่ไหน ไม่ว่าจะเป็น Devops หรือ Software Engineer ในระบบอื่น สักพักระบบจะ scale ได้ยากขึ้น จากความซับซ้อนที่มากเกินไปของระบบตรงกลาง

แต่ว่า การที่จะจะบอกว่า ไปอยู่ในระดับ Granularity ที่สูงสุด ก็อาจจะไม่ใช่คำตอบ เช่น Notification Service ตัวเดิม มี SMS , Email , Line, จดหมายกระดาษรวมกัน แต่ จดหมายกระดาษ เปลี่ยน config หน้าตาบ่อยมาก หรือ กรณีของ SMS พอจะคุยกับลูกค้าคนอื่น ต้อง implement SMS Protocol ตามลูกค้านั้นๆ ตรงนี้ หรือ ถ้าเราจำเป็นมีส่วนที่จำเป็นต้องมีระดับความปลอดภัยสูงมากๆ การ apply ทุกอย่างให้กับ ทุก service ย่อยๆ มันก็อาจจะเกินไป และ เสียเวลาในการ deploy ระบบมากตาม

ที่นี้แล้วเราจะดูอะไรเพิ่มเติมนอกเหนือจากเรื่อง SRP บ้าง ในหนังสือ จะพูดถึงเรื่อง Service Granularity Integrator และ Disintegrator ซึ่งจะเป็นปัจจัยในการแบ่งหรือรวม Service เข้าหากัน เช่น

Service Disintegrator

  • Service Functionality — ตรงนี้จะหมายถึง Service Cohesion ซึ่งหมายถึง ทุก public interface ที่มี มีวัตถุประสงค์ไปในทางเดียวกันหรือไม่
  • Code Volatility — Code เปลี่ยนแปลงบ่อยหรือไม่ ถ้าเปลี่ยนบ่อยแปลว่า release cycle จะถี่เกิด test cycle เกิด deploy cycle และ test ก็จะขยายตัวขึ้นเรื่อยๆ function ส่วนที่ไม่เปลี่ยนบ่อยก็จะกระทบในทางอ้อม
  • Scalability and Throughput — ถ้าใน Service นั้นมี function ที่ทำงานหนักๆ ถี่ๆ transactionเยอะๆ มากกว่าตัวอื่น อาจจะทำให้ service ไม่ทัน ส่วนผลต่อ function ที่ไม่ได้ใช้บ่อย อาจจะต้อง scale ซึ่ง ตัวที่ไม่ได้ใช่บ่อยก็จะ scale ไปด้วย ซึ่งอีกมุมหนึ่งเป็นการสิ้นเปลือง
  • Fault Tolerance — ถ้า Service down ตัว function ภายในจะหายหมด ถ้าเราต้องการให้ functionอื่นๆ ยังคงทำงานได้ ก็แยก
  • Data Security — ในบางกรณี บาง service ต้องการระดับความปลอดภัยที่สูงกว่าปกติ เช่น profile ลูกค้า กับ ข้อมูลสุขภาพส่วนบุคคลที่ได้รับความคุ้มครองตามกฎหมาย

Service Integrator

  • DB transactions — ถ้า function ของ service มากกว่า 2 ตัวต้องการ ACID Transaction การรวมเป็น Service เดียวจะง่ายกว่า การแยกย่อยเยอะมาก
  • Workflow choreography — พอเป็น service แยกแล้วเราจำเป็นต้องควบคุมลำดับการทำงานของระบบ แล้วก็ควบคุมลำดับง่ายหรือ ซับซ้อน
  • Data dependencies — ถ้าทำ Microservice แล้ว ข้อมูล มัน depend กับ service เป็นเหมือนน้ำตก ถ้าอันล่างๆ ตาย อันบนก็ไม่รอด ไม่มี workaround อันนี้รวม service ดีกว่า’

จริงๆ พอทำงานจริงๆ มันก็จะมีปัจจัยยิบย่อย ที่ต้องมาใช้ช่วยในการตัดสินใจ on-top จากปัจจัยที่บอกมาข้างต้นอีก อย่างไรก็ตาม อยากให้เริ่มต้นด้วยปัจจัยกลุ่มนี้ก่อน เพราะจะเป็นพื้นฐานที่ดีครับ

จุดที่สำคัญที่ในหนังสือจะเตือนมาคือ

หลายคนมักจะคิดแต่เรื่องแยก Service แต่ไม่ค่อยคิดเรื่องรวม service หน้าที่เราคือ จะต้องรักษาสมดุลย์ของ service เพื่อให้ระบบ มี Tradeoff ที่เหมาะสม

ดังนั้นอย่าลืมเอาปัจจัยในการรวม service มาคิดพร้อมกันด้วยนะครับ

อ้างอิง

  1. https://www.amazon.com/Software-Architecture-Trade-Off-Distributed-Architectures/dp/1492086894
  2. https://architecturenotes.co/fallacies-of-distributed-systems/

--

--

Teerayut Hiruntaraporn
Teerayut Hiruntaraporn

No responses yet