เมื่อวานสอน programming เบื้องต้น ให้กับ non-tech staffsในทีม โดยใช้ sequence ที่ผมชอบ (และใช้ Python, REPL)
1. value (เอาแค่ integer และ boolean) และ basic operation/computation on values (พวก +, -, *, / รวมถึง boolean operation พวก >, <, ==)
2. variables
3. function (สร้างฟังก์ชั่นใหม่ ใช้ฟังก์ชั่นใหม่เอง)
4. if-else
แล้วก็หมดเวลาทำงาน (สอนตั้งแต่ประมาณ 14:30 - 18:30)
=========================
หลายคนอาจจะคิดว่า "แปลก" ที่เอา function มาก่อนพวก logical/flow control แบบ if-else, loop .... แต่ผมมีเหตุผลหลายอย่างว่าทำไมผมชอบ sequence นี้
0. ส่วนหนึ่งอาจจะมาจากการที่พื้นฐานส่วนตัว ผม preferred functional programming มากกว่า imperative ..... และ SICP (หนังสือในตำนวนเล่มหนึ่ง) รวมถึงอาจารย์ Abelson (คนเขียน) มีอิทธิพลกับผมเยอะมากอยู่
1. values -> computations -> variables -> functions
ผมคิดว่าอันนี้มันเป็น consequential flow ที่เป็นเหตุเป็นผลและเป็นธรรมชาติที่สุดแล้ว โดยเฉพาะถ้าคิดจากมุมของ functional programming (ซึ่งเป็น preferred paradigm ในปัจจุบัน) ....
เราทำงานกับ value ... พื้นฐานของโปรแกรมมันมีแค่นี้แหละ
ถ้าเรารู้ value ตรงๆ มันก็จบ จะทำอะไรก็ทำไป ... แต่หลายครั้งเรามักจะยังไม่รู้ว่ามันเป็นอะไร แต่เรารู้แล้วว่าจะทำอะไรกับมัน ... หรือว่าเรารู้แล้ว แต่เราต้องการจะ refer ถึงมันใน scope ที่กว้างขึ้น (ใช้ซ้ำนั่นเอง)
เช่น x = 10, y = 10 แล้วจากนั้นเราก็เขียน x + y กด enter ก็จะได้ 20 .... ไปเขียนอะไรเล่นอีก 2-3 บรรทัด จากนั้นเขียน x = 30 กด enter ... แล้วก็กดลูกศรขึ้นไป 2-3 ครั้ง ... เจอ x + y กด enter ใหม่ ก็จะได้ 40 ... เป็นต้น
จากนั้นทำยังไงให้ไม่ต้องกดลูกศรขึ้นแบบนี้ไปเรื่อยๆ เพราะสิ่งที่เราอยากใช้จริงๆ ก็คือ x + y ที่เราเคยเขียนไว้แล้ว ... ก็เขียน function ซะ
มัน natural มาก .... รู้ value -> อ้างอิง value นั้นๆ เพื่อใช้ซ้ำ (value -> variables) ... รู้ computation routine -> อ้างอิง routine นั้นๆ เพื่อใช้ซ้ำ (code -> functions)
2. การเริ่มต้นที่ if-else, loop ก่อน function อาจจะเป็น preferred sequence ในอดีตเมื่อหลายปีมาแล้ว แต่ทำให้เกิดผลเชิงลบในภาพใหญ่ โดยเฉพาะในปัจจุบัน ..
เพราะมันทำให้เราลงไปคลุกอยู่กับ low-level logical flow เร็วเกินไป .... คำนวนอะไรที่ซับซ้อนขึ้นได้เร็วเกินไป ... โดยยัดทุกอย่างลงไป "main" (หรือเทียบเท่าในระดับที่เรากำลังเขียนโค้ดอยู่) ก่อนที่จะได้จัดลำดับความคิด ว่านี่เรากำลังทำอะไรอยู่
มันฝึกนิสัยให้เราข้าม layer of abstraction โดยไม่รู้ตัว มันทำให้เราไม่แยกปัญหาออกเป็นปัญหาย่อย มันทำให้เราไม่คิดว่านี่เรากำลังทำอะไรอยู่และทำไปเพื่ออะไร (และไปโฟกัสแต่ว่าจะทำมันยังไง)
fast forward มาตอนที่หลายคนเป็น professional programmer .... ก็ไม่ต้องสงสัยหรอกว่านิสัยการ "ลัดไปที่ low-level logic" ก่อน และ "ยัดโค้ดลง controller" อะไรพวกนี้ มันมาจากไหน ... มันจาก early days ในการเขียนโปรแกรมของเราน่ะแหละ
ในตอนที่ฝึก เราก็สร้างฟังก์ชั่น sum2(x, y) ง่ายๆ น่ะแหละ แล้วต่อไปฟังก์ชั่น average2(x, y) .... ที่แน่นอนว่า มันก็คือ (x+y)/2 น่ะแหละ
แต่เอ๊ะ เดี๋ยวก่อน เราจะทำอะไรนะ .... อ่อ มันคือ เอาผลรวม มาหารด้วยจำนวนที่เอามารวมกัน .... เอ๊ะ ผลรวม เรามีแล้วนี่ ก็จะเขียน sum2(x, y)/2 แทน
ย้ำหน่อย ..... ผมยังไม่สนใจความเร็ว หรือเรื่อง optimization ณ จุดนี้ แต่สนใจเรื่องการสื่อสารสิ่งที่ต้องการทำ ลำดับความคิด และความถูกต้องของสิ่งเหล่านั้นมากกว่า (ดังนั้นไม่ต้องบอกว่า (x+y)/2 เร็วกว่า sum2(x, y)/2 นะ)
sum2 เป็นฟังก์ชั่นที่ไม่ยาก ต่อให้ไม่ใช้ และใช้ x+y ตรงๆ ในโค้ด ทุกคนก็คงจะอ่านออกไม่ยาก .... แต่ถ้ามันเป็นอะไรที่ยากกว่านี้ซับซ้อนกว่านี้และไม่ตรงไปตรงมาแบบนี้ล่ะ?