software test นี่ทำ bot มาลาก mouse กด keyboard ก็ได้ สร้าง API เทียมทั้งหมดเลยก็เป็นไปได้ แต่ผมนึกออกอยู่สองอย่างคือ
1. ทำแบบที่ว่ามันออกแรงเยอะเทียบกับ test พวก pure function มาก ๆ
2. test แล้วก็อาจจะยังบอกไม่ได้ว่าไปพังที่ไหน
ดังนั้นควรจะมี unit test ด้วย
ส่วน TDD ผมว่าช่วยได้มากเลย ไม่งั้นผมนึกไม่ค่อยออกว่าจะไปใส่ test ที่ไหนเมื่อไหร่ บางทีก็ลืมตัวไปทำโปรแกรมที่ test ยาก
ผมไม่ได้คิดว่า TDD เหมาะกับทุกอย่าง เช่น บางทีนึกภาพไม่ออกด้วยซ้ำว่าจะ test อะไร และเริ่มเอา Pandas โหลดข้อมูลมาดู
นอกจากท่าพวก Jupyter Notebook ร่วมกับ Pandas แล้ว ผมว่า shell ต่าง ๆ เช่น Bash และ Powershell มันก็เป็นการเขียนโปรแกรมแบบลองรันก่อนเลย ไม่ได้คิด test case ก่อน พอรันคำสั่งนึงได้แล้วค่อยไปเขียนอีกคำสั่งนึงมากต่อ ๆ กันแล้วมัดรวมกันเป็น shell script; Lisp และพวก ผมว่าก็อยู่ในข่ายนี้เหมือนกัน คือลองรันดูก่อนแล้วก็โปรแกรมมาต่อ ๆ กัน
กลุ่มนี้ที่มี Jupyter Notebook, shell, Lisp ผมจะเรียกรวมกันเลยว่ากลุ่ม interactive
พื้นฐานของกลุ่มโต้ตอบ (interactive) ก็คือรันแล้วคำสั่งนึงแล้วก็มาดูผลลัพธ์ วิธีนี้ก็ใช้ต่อไปได้เรื่อย ๆ ถึงแม้ว่าโปรแกรมจะใหญ่ขึ้นแค่ไหนก็ตาม เพราะว่าเราสร้างคำสั่งใหม่ได้ซึ่งในบางภาษาอาจจะเรียกว่าฟังก์ชันในบางภาษาก็อาจจะเป็น shell script หนึ่งไฟล์เลย
การสร้างคำสั่งใหม่ถึงแม้ว่าจะไม่ได้พัฒนาโปรแกรมแบบโต้ตอบก็มีการสร้างคำสั่งใหม่อยู่ดี ยกเว้นจะเขียน assembly แบบไม่มี macro หรือภาษา BASIC รุ่นใช้เลขบรรทัด
สิ่งที่ต่างไปของกลุ่มโต้ตอบคือเกือบทุกคำสั่งควรรันแยกกันได้และดูผลลัพธ์การรันนั้นได้
เมื่อผลลัพธ์การรันแต่ละคำสั่งย่อย ๆ มันเยอะเกินไปกว่าที่คนจะคอยมาตรวจเอง หรือว่าต้องรันหลายครั้งหลายแบบเกินไปจนเป็นตัวถ่วง ก็ค่อยสร้าง test อัตโนมัติก็ได้ ผมพอจะเห็นเครื่องมือในลักษณะนี้ เช่น testbook[1] ก็ใช้ test ฟังก์ชันที่อยู่ใน Jupyter Notebook และ bash_unit ที่เอาไว้ test shell script ส่วนของ Lisp ก็มี Fiveam
จะว่ากันไปจริง ๆ เครื่องมือสำหรับ unit test ก็เกิดมาจากกลุ่มโต้ตแบ เพราะ unit test ตัวแรกที่สาธารณะรู้จักคือ sUnit ก็มาจากหนังสือ Simple Smalltalk Testing: With Patterns ของ Kent Beck เมื่อ 33 ปีที่แล้ว ซึ่ง Smalltalk ก็เป็นที่รู้จักกันดีเลยว่าไม่ใช่แค่ภาษาแต่เป็นสิ่งแวดล้อมในการพัฒนาโปรแกรมแบบโต้ตอบในโหมดกราฟฟิค
กลุ่มโต้ตอบมันไม่เห็นภาพเลย จะลองเรียกว่าการพัฒนาแบบรันดูผลทีละคำสั่งหรือละหลายคำสั่งแล้วกัน พอเรียกแบบนี้ชวนให้คิดเลยว่าต้องใช้ interpreter เท่านั้นใช้ compiler ได้ ซึ่งไม่จริง เพราะมีตัวอย่างตามนี้ ตัวอย่างแรก Jupyter Notebook ใช้ Swift ได้ซึ่งใคร ๆ ก็รู้ว่า Swift ใช้ compiler และอีกอันคือ Interlisp อย่างน้อย 49 ปีหรือนานกว่านั้นใช้ compiler เหมือนกัน
ประเด็นหนึ่งเถียงกันตามเครือข่ายสังคมออนไลน์คือเรื่อง static type พ่อทุกสถาบัน หรือว่า dynamic type สิของจริง
เป็นเรื่องจริงว่าการพัฒนาโปรแกรมแบบรันดูผลทีละส่วน ภาษาแบบ dynamic type เป็นที่นิยมกว่าแบบ static type ผมจิตนาการว่าได้ไฟล์ข้อมูล csv มาหนึ่งไฟล์ เราไม่ได้มีความรู้มาก่อนว่าไฟล์นั้นมันต้อง type อะไรบ้าง หรือว่าแต่ละบรรทัดซึ่งอาจจะมีเป็นล้านบรรทัดจะมีข้อมูลอะไรขาดไปได้บ้าง ก็เลยง่ายกว่าที่จะโหลดข้อมูลขึ้นมาประมวลผลก่อน ซึ่งหลายครั้งก็ใช้แค่คอลัมน์เดียวก็มี
ลักษณะที่ว่าไม่รู้จักข้อมูลโดยละเอียดมาก่อน มันเข้าทาง dynamic type พอดี
แต่ว่าก็ไม่จำเป็นต้องเป็น dynamic type เท่านั้น บางทีเราอาจจะมีฟังก์ชันเสริม เช่น ตัดคำ ตัดเครื่องหมายพิเศษออก คำนวณกำไร พวกนี้เรารู้อยู่แล้วว่าตัดคำตัดเครื่องหมายพิเศษพวกนี้ต้องใช้ string แน่ ๆ คำนวณกำไรพวกนี้เป็นตัวเลขแน่ ๆ ไม่จำเป็นต้องมา dynamic พอไม่ dynamic ก็ช่วยให้ compiler หรือ linter ช่วยหาข้อพิดพลาดได้เยอะขึ้นละเอียดขึ้น ในบางระบบเช่น Common Lisp โปรแกรมก็อาจรันไวขึ้นด้วยถ้าระบุ type ก่อน compile
อย่างแรกคือภาษา static typing เอามาใช้ใน Jupyter Notebook ก็มี เช่น Swift หรือ Rust
หรือกระทั่งเดี๋ยวนี้ พ.ศ. 2565 ภาษา dynamic typing ก็ใส่ type ได้ check type ได้ หรือภาษา static typing ก็มี type ที่แทบจะใส่อะไรก็ได้คล้าย ๆ กับ dynamic type
45 ปีก่อน MacLisp ก็ใส่ type แล้วก็ compile ทำให้ความเร็วออกมาดี ทั้งที่ Lisp เป็นภาษาแบบ dynamic typing ทุกวันนี้ Common Lisp compiler ก็ check type ได้ Julia ก็คือมาแนวเดียวกันเลย ส่วน Python Ruby เดี๋ยวนี้ก็ใส่ type ได้แล้วมี linter แยกมา check อีกที
สรุปว่าควรจะ test นั่นล่ะ แต่ถ้า TDD แล้วรู้สึกว่าไม่ไหว ก็มาแนวรันแล้วดูผลทีละฟังก์ชันก็ได้ วิธีนี้ก็ไม่ได้มีข้อจำกัดด้วยว่าต้อง compile หรือ interpret จะใช้ dynamic type หรือ static type ก็ได้