srp-thumb1
เรื่องที่ 13 ที่นักพัฒนาควรรู้ และ เข้าใจก็คือ The Single Responsibility Principle(SRP)
เป็นหนึ่งแนวคิดสำคัญในการออกแบบระบบ และ code ที่ดี
ที่นักพัฒนา software ทุกคนควรศึกษา
เพื่อให้รู้ เข้าใจ และนำไปใช้ด้วยความเคารพ
สามารถอธิบายสั้นๆ ได้ว่า

ให้รวมส่วนการทำงานที่เปลี่ยนแปลงด้วยเหตุผลเดียวไว้ด้วยกัน
ให้แยกส่วนการทำงานที่เปลี่ยนแปลงด้วยเหตุผลที่ต่างกันออกมา

ลองดูสิว่า ระบบที่เราพัฒนากันนั้น มันเป็น SRP ไหม ?

Single Responsibility Principle(SRP) คืออะไร

ในแต่ละ module, class, method/function
ควรจะมีเหตุผลในการเปลี่ยนแปลงเพียงเหตุผลเดียวเท่านั้น
พูดไปอาจจะไม่เห็นภาพกัน ลองมาดูตัวอย่างกันดีกว่า

ตัวอย่าง
เป็น class Employee ที่มีหน้าที่สำหรับทำงานในส่วน

  • Business rule
  • สร้างและแสดง Report
  • จัดการข้อมูลใน Database
public class Employee {
 public Money calculatePay() ...
 public String reportHours() ...
 public void save() ...
}

นักพัฒนาบางคน

อาจจะคิดและเขียน code ที่รวมเอาการทำงานทั้ง 3 ส่วนหลักไว้ในที่เดียวกัน
มันน่าจะเหมาะสมที่สุดแล้วนะ
ดังนั้น class หรือ file ที่สร้างจะมี 3 method/function
ซึ่งแต่ละ method/function ล้วยมีเหตุผลในการเปลี่ยนแปลงที่แตกต่างกัน !!
กล่าวคือ

  • calculatePay() จะเปลี่ยนแปลงเมื่อ business rule ของการคำนวณการจ่ายเปลี่ยนไป
  • reportHours() จะเปลี่ยนแปลงเมื่อใครบางคนต้องการรายงานรูปแบบอื่น
  • save() จะเปลี่ยนแปลงเมื่อผู้ดูแล database ต้องการเปลี่ยนแปลง schema หรือโครงสร้างของ database

ดังนั้น เราพบว่า class Employee มีเหตุผลในการเปลี่ยนแปลงถึง 3 เหตุผล
นั่นแสดงว่า เราไม่เคารพต่อ Single Responsibility Principle เลยนะ

ผลที่ตามมาก็คือ class Employee จะถูกเปลี่ยนแปลงได้ตลอดเวลา
ลองคิดดูสิว่า ถ้า class Employee มันมีความสำคัญต่อระบบมากๆ
เมื่อทำการเปลี่ยนแปลงแล้ว มันอาจจะส่งผลกระทบต่อ 2 method/function แน่นอน
คุณคิดว่า งานมันจะเข้าคุณไหมล่ะ ?
หรือว่าคุณชินเสียแล้ว ?

ระบบที่ดีเป็นอย่างไรบ้างนะ ?

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

แต่จากตัวอย่าง class Employee ข้างบน มันขัดแย้งหมดเลยใช่หรือไม่ ?
ดังนั้น เรามาสร้างระบบงานที่ดีกว่าเดิมดีไหม ?

ลองทำดังนี้ดูสิ
ง่ายๆ ด้วยการแยกแต่ละการทำงานออกมาเป็น class เล็กๆ ดังนี้

 public class Employee {
 public Money calculatePay() ...
}

public class EmployeeReporter {
 public String reportHours(Employee e) ...
}

public class EmployeeRepository {
 public void save(Employee e) ...
}

นั่นคือ

  • class Employee ทำหน้าที่คำนวณค่าใช้จ่ายตาม business rule
  • class EmployeeReporter ทำหน้าที่แสดงรายงานของพนักงาน
  • class EmployeeRepository ทำหน้าที่บันทึกข้อมูลพนักงานลงใน database

ส่งผลทำให้เราสามารถแยกส่วนงานออกจากกันแล้ว ง่ายจัง !!

แต่ถ้าสังเกตดีๆ จะพบว่า

code ที่ได้มานั้น มันยังมีส่วนที่ผูกกันอยู่ นั่นก็คือ class Employee ไงล่ะ !!
ดังนั้น ถ้า class Employee มีการเปลี่ยนแปลง
แน่นอนว่าต้องกระทบกับ class ที่เหลืออย่างแน่นอน
เพราะว่า ต้องทำการ compile และ deploy ใหม่

ซึ่งจุดนี้เราจะเรียกว่า Dependency
ดังนั้นเราสามารถแก้ไขด้วยวิธีการ Dependency Inversion Principle (DIP)
ซึ่งผมเคยเขียนอธิบายไว้ใน blog
เรื่อง Dependency Injection ต่างจาก Dependency Inversion Principle อย่างไรนะ

หรือสามารถอ่านได้จากหนังสือ
Agile Software Development, Principles, Patterns, and Practices

โดยสรุปแล้ว

เราในฐานะของนักพัฒนา software
ลองกลับไปดูสิว่าระบบที่คุณพัฒนานั้น
คุณได้สนใจเรื่อง Single Responsibility Principle(SRP) บ้างหรือไม่ ?
ซึ่งแนวคิดนี้เป็นแนวคิดหลักที่นักพัฒนาทุกๆ คนจะต้องศึกษา และ เข้าใจมันอย่างจริงจัง

ไม่เช่นนั้น ก็มักจะเกิดปัญหาประมาณว่า

  • แก้ที่หนึ่ง แต่ทำไมอีกทีหนึ่งทำงานไม่ได้ล่ะ
  • ยิ่งแก้ไข ยิ่งเกิดความผิดพลาดสูง
  • มีคำถามมาเสมอว่า มั่นใจนะว่า ถ้าแก้ไขแล้วจะไม่กระทบต่อส่วนงานอื่นๆ

คุณเคยเจอปัญหาเหล่านี้ไหม ?
ถ้าเจอคุณไม่คิดที่จะเปลี่ยนแปลงมันเลย หรือ ว่าชินกันมันเสียแล้ว !!!