iStock_000001225226Small__10avt3__
เรื่องที่ 33 ที่นักพัฒนาควรรู้ และ เข้าใจก็คือ Write Small Functions Using Examples

นักพัฒนาทุกคนชอบเขียน code ให้มันถูกต้อง ตามที่คาดหวัง
นักพัฒนาทุกคนมีหลักฐานในมือว่า code ที่สร้างขึ้นมามันทำงานถูกต้อง
นักพัฒนาทุกคนรู้ว่าจะต้องทำอะไร
นักพัฒนาทุกคนรู้ว่าจะทดสอบอย่างไร
มันจริงไหมนะ ?

ถ้านักพัฒนาจะเขียน code ให้ทำงานได้อย่างถูกต้องแล้ว

ก็ควรที่จะมีสิ่งที่บอกว่า สิ่งที่จะทำมันถูกต้องอย่างไร
นั่นคือต้องมีข้อมูลตัวอย่างใช่ไหม ประกอบไปด้วย

  • Business logic และ Business condition
  • Input
  • Output หรือ Expected result

จากข้อมูลเหล่านี้มันจะช่วยทำให้เราเห็นว่า

  • ภาพรวมของสิ่งที่เราต้องสร้าง และ แก้ไข ว่าเป็นอย่างไร
  • เห็นว่ามีปัญหาอะไรบ้าง
  • เห็นว่าจะมี input และ output อะไรบ้าง

ทำให้เราสามารถแยกย่อยปัญหาต่างๆ ออกมาแก้ไขได้
ดังนั้น มันน่าจะส่งผลต่อขนาดของ method/function ของ code
ที่เราจะสร้างขึ้นมาด้วยหรือไม่ ?

เนื่องจาก code ที่สร้างขึ้นมานั้น เพื่อแก้ไขปัญหาเล็กๆ
ไม่น่าจะมี code ที่เยอะใช่ไหม ?
ไม่น่าจะมี test case เยอะใช่ไหม ?
ไม่น่าจะมี test data หรือ ข้อมูลตัวอย่างในการทดสอบ เยอะใช่ไหม ?

สิ่งที่น่าสนใจก็คือ จำนวน test data ?

จำนวนของ test data มันจะแปรผันตรงตามตัวแปร และ ความน่าจะเป็น
ถ้ายิ่งจำนวน parameter ของ method เยอะจำนวน test case และ test data ก็เยอะตาม
ยังไม่พอนะ ชนิดข้อมูลของแต่ละตัวแปรก็เก็บข้อมูลได้เยอะอีก
เราจะต้องทดสอบให้ครบเลยใช่ไหม ?

ตัวอย่างเช่น
การคิดเกรดจากคะแนน เราสามารถเขียน function การคำนวณได้ดังนี้

public String calculateGradeFromScore( int score ) {
}

มันเป็น method ที่ง่ายมากๆ
แต่เมื่อมองถึงชนิดของข้อมูลคือ int
แล้วตัวแปร int ในภาษา Java มันเก็บข้อมูลอะไรได้บ้างล่ะ ?

  • ค่าต่ำสุด -2^31
  • ค่าต่ำสุด 2^32

ความน่าจะเป็นของข้อมูลมันสูงมากๆ
แล้วคุณจะทดสอบอย่างไรให้ครบล่ะ ?
เพราะว่า คุณจะบอกได้ว่างานคุณเสร็จ ?
เพราะว่า คุณจะมั่นใจได้ว่า bug มันจะน้อยหรือไม่มีเลย ?
แต่ปัญหาคือ จำนวนข้อมูลทดสอบมันมีจำนวนเยอะมากๆ นะสิ !!

แก้ไขปัญหาอย่างไรดีล่ะ ?

สามารถแก้ไขปัญหาด้วย domain type สิ เลิกใช้ int ไปซะ !
โดยข้อมูลที่เราสนใจจริงๆ คือ 0 ถึง 100 เท่านั้น ไม่ใช่ int นะสิ ใช่ไหม ?
ดังนั้นเขียน code ใหม่เป็นดังนี้ดีกว่าไหม

กำหนดให้ StudentScore score = [0-100]
public String calculateGradeFromScore( StudentScore score ) {
}

โดย code แบบนี้มันเข้าใจง่ายกว่าเดิมไหม ?

เห็นสิ่งที่ method มัน return ไหม ?
คือ String …
ลองคิดกันหน่อยว่าสิ่งที่เราต้องการจริงๆ คือ String ไหม ?
ตามจริง String นั้นมันคือ เกรด A, B, C, D, F ใช่ไหม ?

ดังนั้นทำแบบนี้ดีกว่าไหม

กำหนดให้ StudentScore score = [0-100]
กำหนดให้ Grade = [A, B, C, D]
public Grade calculateGradeFromScore( StudentScore score ) {
return Grade.A;
}

แนวทางการแก้ไข code รูปแบบนี้
ทำให้ code อ่านง่าย และ เข้าใจง่ายขึ้นกว่าไหม ?
ทำให้เราสามารถไล่ code ง่ายขึ้นไหม ?
ทำให้เรารู้ทันทีว่า ข้อมูลการทดสอบมันมีขอบเขตอย่างไรบ้าง ?
ทำให้เราสามารถระบุข้อมูลทดสอบได้เลย ?

ดังนั้น แนวทางนี้จึงน่าจะมีเหตุผลที่ดีสำหรับการเขียน code นะ

โดยใช้แนวคิดของ domain type เข้ามาช่วย
ลด ล่ะ เลิกการใช้งาน primitive data type ซะ
แล้วจะส่งผลทำให้ code ในแต่ละ method มันสั้นๆ ด้วยนะ

แต่ก่อนที่จะสร้าง domain type ขึ้นมาได้
คุณจะต้องหาข้อมูลตัวอย่าง สำหรับปัญหาใน domain นั้นก่อนเสมอนะครับ
แล้วคุณจึงเริ่มเขียน method นั้นได้