ทำ
ก้อน data กับ function ที่เปลี่ยนรูปร่างมัน
ในวันที่ AI เขียน code ให้เราได้มากขึ้น ผมยังอยากจดวิธีคิดเรื่อง functional programming ไว้ เพราะมันเป็นวิธีที่ผมใช้ขึ้น project ดูแล project และทำให้ business logic อยู่ในรูปที่เทสง่ายขึ้น
เมล็ดอ่าน 3 นาทีเปิดแล้ว 0 ครั้ง
ช่วงนี้ AI เขียน code ให้เราได้มากขึ้นเรื่อยๆ
บางทักษะที่เคยสำคัญ อาจไม่ได้จำเป็นเท่าเดิมแล้ว
ผมเองก็ยังไม่รู้เหมือนกันว่า อีก 5 ปี developer จะต้องรู้เรื่องเดิมๆ มากแค่ไหน
แต่มีวิธีคิดหนึ่งที่ผมยังอยากจดไว้
ไม่ใช่เพราะมันเป็นของใหม่
แต่เพราะผมใช้มันมาตลอด ตอนขึ้น project ตอน maintain project และตอนพยายามทำให้ business logic ไม่กระจายจนกลับมาแก้ยาก
วิธีคิดนั้นมาจาก functional programming
สำหรับผม มันเริ่มจากภาพง่ายๆ ภาพหนึ่ง
มี data ก้อนหนึ่ง วิ่งผ่าน function หนึ่ง แล้วออกมาเป็น data อีกก้อนหนึ่ง
ก้อน data
เวลาผมคิดถึง program ผมมักไม่ได้เริ่มจาก class หรือ framework ก่อน
ผมเริ่มจาก data
ตอนนี้เรามี data รูปร่างแบบไหน
เราอยากให้มันกลายเป็นรูปร่างแบบไหน
ระหว่างทางต้องผ่านอะไรบ้าง
ภาพนี้ทำให้ระบบที่ดูซับซ้อน กลับมาเหลือสิ่งที่จับต้องได้มากขึ้น
มี data ตั้งต้น
มี function ที่เปลี่ยนรูปร่าง data
แล้วก็มี data ปลายทางที่เราเอาไปใช้จริง
อาจจะเอาไป serve เป็น API response
อาจจะเอาไปแสดงบน UI
อาจจะเอาไปบันทึกต่อ
แต่ภาพข้างในยังคล้ายกันมาก
ก้อน data ผ่าน function หลายอัน จนได้รูปร่างที่ต้องการ
function ที่ pure
function ที่ผมชอบที่สุด คือ function ที่ pure
ความหมายง่ายๆ คือ input เดิม ต้องได้ output เดิมเสมอ
ถ้าผมส่ง data ชุดหนึ่งเข้าไป แล้วได้ผลลัพธ์แบบหนึ่ง
ต่อให้ส่ง data ชุดเดิมเข้าไปอีก 1 ล้านครั้ง ผลลัพธ์ก็ควรออกมาเหมือนเดิมทุกครั้ง
ไม่มีการแอบ query database
ไม่มีการแอบเรียก external service
ไม่มีการแอบอ่านเวลาปัจจุบัน
ไม่มีการแอบแก้ค่าอะไรข้างนอก
มันรับ data เข้าไป แล้วคืน data ที่ผ่านการ transform ออกมา
แค่นั้น
ตรงนี้ทำให้มันเทสง่ายมาก
ใน unit test เราไม่ต้อง mock โลกทั้งใบ
เราแค่เตรียม input
เรียก function
แล้วดู output
ถ้า input แบบนี้ ต้องได้ output แบบนี้
มันเรียบง่ายจนบางทีดูไม่น่าสนใจ
แต่ความเรียบง่ายแบบนี้ช่วยชีวิตผมหลายครั้งมาก ตอน project โตขึ้น แล้วต้องกลับมาแก้ business logic เดิม
transform function
ผมมักเรียก function แบบนี้ว่า mapping หรือ transform function
หน้าที่ของมันไม่ใช่การไปคุยกับโลกข้างนอก
หน้าที่ของมันคือเปลี่ยนรูปร่าง data
จาก raw data ให้กลายเป็น view model
จาก database row ให้กลายเป็น object ที่ business เข้าใจ
จาก form input ให้กลายเป็น payload ที่ระบบข้างในใช้ต่อได้
จากหลายก้อนรวมกัน ให้กลายเป็นก้อนเดียวที่พร้อมส่งออกไป
พอเราแยก function พวกนี้ออกมาได้ business logic จะเริ่มมีรูปร่างชัดขึ้น
ไม่ใช่ code ก้อนใหญ่ที่ทำทุกอย่างพร้อมกัน
แต่เป็นทางเดินของ data
ก้อนนี้ผ่าน function นี้
แล้วผ่าน function นี้
แล้วผ่าน function นี้
จนสุดท้ายได้ data ที่ต้องการ
ถ้าวันหนึ่ง output ผิด ผมมักไล่ดูได้ว่า data เปลี่ยนรูปผิดตรง function ไหน
ไม่ต้องเดาทั้งระบบพร้อมกัน
side effect
อีกฝั่งหนึ่งคือ function ที่มี side effect
function พวกนี้ไม่ผิด
ระบบจริงยังต้องมีมันอยู่
เราต้อง query database
เราต้องเรียก external service
เราต้องอ่านไฟล์
เราต้องเขียน log
เราต้องส่ง email
โลกจริงมีสิ่งเหล่านี้เสมอ
แต่ปัญหาเริ่มเกิดขึ้นตอนเราเอา side effect ไปปนกับ business logic จนแยกไม่ออก
พอ function หนึ่งทั้ง query database ทั้งคิดราคา ทั้ง format response ทั้งเรียก service อีกตัว
function นั้นเริ่มเทสยาก
แก้ยาก
อ่านยาก
และที่หนักกว่านั้นคือ เราเริ่มไม่รู้ว่าความผิดพลาดมาจากตรงไหน
มาจาก data ตั้งต้นผิด
มาจาก business rule ผิด
มาจาก service ข้างนอกตอบไม่เหมือนเดิม
หรือมาจาก database state ตอนนั้น
เวลาผมขึ้น project เอง ผมเลยพยายามแยก function ที่มี side effect ไปไว้อีก layer หนึ่งให้ชัด
ให้มันรับผิดชอบเรื่องการคุยกับโลกข้างนอก
ส่วน business logic ข้างใน พยายามให้เป็น pure function ให้มากที่สุด
business logic ในหัวผม
ถ้ารวมภาพทั้งหมดเข้าด้วยกัน business logic ในหัวผมหน้าตาประมาณนี้
เริ่มจาก function ที่มี side effect ไปเอา data ตั้งต้นมาก่อน
อาจจะมาจาก database
อาจจะมาจาก API
อาจจะมาจาก user input
หลังจากนั้น data ก้อนนี้จะถูกส่งผ่าน transform function หลายอัน
แต่ละอันทำหน้าที่เล็กๆ ของตัวเอง
เปลี่ยนรูปร่างตรงนี้
เติมค่าตรงนี้
กรองบางอย่างออก
จัดกลุ่มบางอย่างใหม่
รวม data หลายก้อนเข้าด้วยกัน
จนสุดท้ายได้ data รูปร่างที่ระบบต้องการ
แล้วค่อยส่งมันออกไปใช้จริง
จะเอาไปเป็น API response ก็ได้
จะเอาไป render บน UI ก็ได้
จะเอาไปส่งต่อให้ service อื่นก็ได้
หลักการข้างในยังเหมือนเดิม
function ที่มี side effect ควรอยู่ตรงขอบของระบบ
มันคุยกับ database, API หรือโลกข้างนอก
ส่วน pure function รับ data เข้ามา แล้วเปลี่ยนรูปร่างมันอยู่ข้างในระบบ
ในวันที่ AI เขียน code
พอมี AI เข้ามา หลายอย่างเปลี่ยนไปมาก
เราอาจไม่ต้องนั่งพิมพ์ code ทุกบรรทัดเอง
เราอาจไม่ต้องจำ syntax ทุกอย่างเหมือนเมื่อก่อน
AI อาจ generate function ให้เราได้เร็วกว่าเราเขียนเองหลายเท่า
แต่ผมเริ่มรู้สึกว่า ภาพในหัวของคนสั่งยังสำคัญอยู่
ถ้าผมมองไม่ออกว่า data ควรไหลยังไง AI ก็อาจเขียน code ที่ทำงานได้ แต่กลับมา maintain ยาก
ถ้าผมไม่แยก pure function ออกจาก side effect AI ก็อาจรวมทุกอย่างไว้ใน function เดียว เพราะมันดูเร็วและตรงโจทย์ที่สุดในตอนนั้น
ถ้าผมไม่มีภาพของ transform function ผมก็อาจ prompt แค่ให้มันทำงานให้เสร็จ โดยไม่ได้บอกว่าระบบควรแบ่งความรับผิดชอบยังไง
ตรงนี้อาจเป็นทักษะที่ยังเหลืออยู่
ไม่ใช่ทักษะในการพิมพ์ code ให้เร็ว
แต่เป็นทักษะในการเห็นรูปร่างของระบบก่อน code จะถูกเขียนออกมา
สิ่งที่อยากจดไว้
ผมไม่ได้คิดว่า functional programming คือคำตอบของทุกอย่าง
ผมก็ไม่ได้เขียน pure ทุก function ในชีวิตจริง
หลายครั้งโลกจริงก็ยุ่งกว่านั้น
framework มีข้อจำกัด
เวลาในงานมีข้อจำกัด
ทีมมีวิธีทำงานของตัวเอง
แต่ภาพเรื่อง data กับ transform function ยังช่วยผมอยู่เสมอ
เวลา code เริ่มยุ่ง ผมกลับมาถามแค่นี้
ตอนนี้ data ก้อนไหนกำลังวิ่งอยู่
function นี้กำลังเปลี่ยนรูปร่าง data หรือกำลังคุยกับโลกข้างนอก
side effect อยู่ตรงไหน
ถ้าตอบคำถามพวกนี้ได้ ระบบมักจะเริ่มเบาลง
อาจไม่ใช่หลักการที่ตื่นเต้นแล้ว
อาจไม่ใช่ทักษะที่ดูสำคัญในวันที่ AI เขียน code ได้เร็วมาก
แต่สำหรับผม มันยังเป็นภาพพื้นฐานที่ทำให้การเขียนโปรแกรมชัดขึ้น
ก้อน data เข้าไป
function เปลี่ยนรูปร่างมัน
แล้วก้อน data ใหม่ก็เดินทางต่อ