80 คะแนน โดย GN⁺ 2025-07-15 | 2 ความคิดเห็น | แชร์ทาง WhatsApp
  • การสร้างสมดุลระหว่าง ความสมบูรณ์แบบ กับ ความเร็ว ไม่ใช่เรื่องง่าย แต่สิ่งสำคัญคือ คุณภาพที่เหมาะสม กับ การส่งมอบให้ทันกำหนด
  • การพัฒนาแบบทำฉบับร่างก่อน แล้วค่อยปรับปรุงคุณภาพโค้ดภายหลัง เป็นวิธีที่ได้ผล
  • การ ผ่อนคลายข้อกำหนด หรือลดความต้องการที่มากเกินไป ช่วยเพิ่มความเร็วและประสิทธิภาพได้
  • ควรมีนิสัย หลีกเลี่ยงสิ่งรบกวนและ commit บ่อย ๆ เป็นหน่วยเล็ก พร้อมโฟกัสกับสิ่งสำคัญ
  • มีทักษะเชิงปฏิบัติเฉพาะที่ช่วยให้พัฒนาได้เร็วขึ้นจริง เช่น การอ่านโค้ด, การทำ data modeling, การเขียนสคริปต์, การดีบัก, การเน้น pure function เป็นต้น

“โค้ดควรดีแค่ไหน?” – มาตรฐานคุณภาพและการเลือกอย่างสมจริง

  • ในช่วงแรก ๆ ผม อยากให้ทุกบรรทัดของโค้ดสมบูรณ์แบบ
    • ฝันถึงโค้ดที่ทุกฟังก์ชันมีการทดสอบอย่างเข้มงวด ชื่อตัวแปรสวยงาม abstraction ชัดเจน และเป็น โค้ดที่ไม่มีบั๊กเลยแม้แต่น้อย
  • แต่เมื่อเวลาผ่านไป ก็ได้เรียนรู้ความจริงว่า “ไม่มีคำตอบที่ถูกต้องเพียงหนึ่งเดียว”
    • คุณภาพโค้ดที่ต้องการนั้นต่างกันไปตามสถานการณ์
    • เกมแจม 24 ชั่วโมง: โค้ดที่เสร็จแล้วไม่จำเป็นต้องสะอาดหรือไร้บั๊กเสมอไป
      • สิ่งที่สำคัญกว่าคือการสร้างผลลัพธ์ที่ใช้งานได้ภายในเวลาจำกัด
    • ซอฟต์แวร์เครื่องกระตุ้นหัวใจ: ความผิดพลาดเพียงครั้งเดียวอาจคุกคามชีวิตคนได้
      • จึงจำเป็นต้องมี ความน่าเชื่อถือและความปลอดภัยระดับสูงสุด
  • โปรเจกต์ส่วนใหญ่จะอยู่ ระหว่างสองขั้วสุดโต่งนี้
    • บางบริษัทต้องการ การส่งมอบที่รวดเร็ว และยอมรับบั๊กเล็กน้อยได้
    • บางโปรเจกต์ต้องการ คุณภาพสูง แต่มีเวลาตารางงานที่ยืดหยุ่น
    • ในงานจริง ความสามารถในการมองสมดุลนี้เป็นเรื่องสำคัญ
    • ก่อนอื่นต้องทำความเข้าใจว่า มาตรฐาน “ดีพอ (good enough)” ของทีมคืออะไร
      • ร่วมกันตรวจสอบเกณฑ์ที่ใช้ได้จริง เช่น ขอบเขตของบั๊กที่ยอมรับได้ หรือส่วนไหนที่ไม่จำเป็นต้องสมบูรณ์แบบ
  • มาตรฐานส่วนตัวของผมคือ
    • “ทำคุณภาพระดับ 8/10 ให้เสร็จภายในกำหนด”
      • โค้ดต้องทำหน้าที่ตามเป้าหมายได้ดี ไม่มีปัญหาร้ายแรง แต่อาจยังมีประเด็นเล็กน้อยหลงเหลืออยู่
      • สิ่งที่สำคัญที่สุดคือ ส่งให้ทันกำหนด
    • อย่างไรก็ตาม มาตรฐานนี้ก็ ปรับอย่างยืดหยุ่นตามบริบทของโปรเจกต์
      • บางครั้งการไล่หาความสมบูรณ์แบบจนกำหนดเลื่อนก็ยอมรับได้
      • บางครั้งงานที่ยังไม่เนี้ยบมากแต่เสร็จเร็วกลับมีคุณค่ามากกว่า

Rough drafts – การใช้ฉบับร่างและการทำ prototyping อย่างเป็นรูปธรรม รวมถึงข้อดี

  • การพัฒนาซอฟต์แวร์ก็เหมือนการเขียนหนังสือ คือการทำ ฉบับร่าง (rough draft, spike, walking skeleton) มีประโยชน์มาก
  • ควร ทำ rough draft ให้ได้เร็วที่สุด แล้วค่อยนำมาขัดเกลาให้กลายเป็นโซลูชันที่สมบูรณ์ในภายหลัง
  • โค้ด rough draft ของผมมักจะ เต็มไปด้วยบั๊ก มีทั้งเทสต์ล้มเหลว คอมเมนต์ TODO เต็มไปหมด จัดการ exception ไม่ครบ ใช้ print/log มากเกินไป
    ไม่ได้คำนึงถึงประสิทธิภาพ มีข้อความ commit แบบ WIP เพิ่มแพ็กเกจที่ไม่จำเป็น มีโค้ดซ้ำ hardcode และคำเตือนจาก linter อีกมากมาย เรียกได้ว่า เละเทะ
  • แม้กระบวนการนี้จะดูไม่มีประสิทธิภาพ แต่เป้าหมายคือการไปให้ถึง “สภาวะที่อย่างน้อยเข้าใจแก่นของปัญหาได้”
  • แน่นอนว่าโค้ดในสภาพฉบับร่างแบบนี้จะไม่ถูกปล่อยเป็นเวอร์ชันสุดท้าย และก่อนปล่อยจริงต้องขัดเกลาเสมอ
    (บางครั้งในทีมก็มีแรงกดดันให้ส่งโค้ดฉบับร่างออกไปตรง ๆ แต่ผมจะพยายามต้านให้มากที่สุด)
  • ข้อดีหลักของแนวทาง rough draft

    • ทำให้ “ปัญหาที่ยังไม่รู้ว่ามีอยู่ (unknown unknowns)” โผล่ออกมาเร็วขึ้น
      • การเจออุปสรรคที่ไม่คาดคิดตั้งแต่ช่วงต้นของการทำ prototype ดีกว่ารอจนทำเสร็จแล้วค่อยทิ้งโค้ดนั้นไปมาก
    • ปัญหาหลายอย่างหายไปเองระหว่างทำ prototype
      • ฟังก์ชันที่ช้าหรือโครงสร้างที่ผิดพลาด บางครั้งภายหลังก็อาจไม่จำเป็นต้องใช้เลย ช่วยหลีกเลี่ยงการเสียเวลา
      • จึงไม่จำเป็นต้องทุ่มกับ optimization หรือ testing เร็วเกินไป
    • ช่วยเพิ่มสมาธิ
      • ป้องกันการเสียเวลาไปกับ refactor ที่ไม่จำเป็น การคิดชื่อ หรือการไปแก้ codebase อื่น
        ทำให้โฟกัสกับปัญหาที่ต้องแก้ตอนนี้ได้เต็มที่
    • ป้องกัน abstraction ที่เกิดเร็วเกินจำเป็น
      • เมื่อมุ่งทำคำตอบที่ใช้งานได้ให้เร็วที่สุด เรามักพยายามสร้าง abstraction สำหรับอนาคตน้อยลง
      • ทำให้โฟกัสกับปัญหาตรงหน้า และหลีกเลี่ยงการออกแบบที่ซับซ้อนเกินจำเป็น
    • สื่อสารความคืบหน้าได้ชัดเจน
      • rough draft ช่วยให้คาดการณ์ได้แม่นขึ้นว่ายังเหลืองานอีกเท่าไร
      • การแสดงสิ่งที่พอใช้งานได้ให้ดูตั้งแต่ต้น ทำให้รับ feedback จากผู้มีส่วนเกี่ยวข้องและเปลี่ยนทิศทางได้รวดเร็ว
  • วิธีใช้ rough draft ในภาคปฏิบัติ

    • การตัดสินใจที่ย้อนกลับได้ยาก (binding decision) ต้องทดลองในช่วงฉบับร่างให้เรียบร้อย
      • เช่น ภาษา เฟรมเวิร์ก DB schema และทิศทางใหญ่ ๆ ควรตรวจสอบตั้งแต่ต้น
    • ทุกทางแก้ชั่วคราว/hack ต้องบันทึกไว้ด้วยคอมเมนต์ TODO หรือวิธีอื่นเสมอ
      • ในช่วง polish จะใช้ git grep TODO เป็นต้น เพื่อตรวจสอบทั้งหมดและเก็บงานให้ครบ
    • พัฒนาแบบ Top-Down (บนลงล่าง)
      • เขียน scaffold ของ UI, API หรือรูปแบบการใช้งานก่อน ส่วน logic ภายในจะ hardcode หรือทำแบบชั่วคราวก็ได้
      • ในความเป็นจริง เมื่อ UI/ประสบการณ์ใช้งานถูกกำหนดแล้ว logic ชั้นล่างมักเปลี่ยนตามอยู่บ่อย จึงคุ้มกว่าถ้าทำจากเลเยอร์บนก่อน
      • การทำส่วนล่างให้สมบูรณ์ก่อนแล้วค่อยปรับให้เข้ากับส่วนบนเป็นวิธีที่ไม่มีประสิทธิภาพ
    • แยกแพตช์สำหรับการเปลี่ยนแปลงเล็ก ๆ ออกต่างหาก

ลองเปลี่ยนข้อกำหนดดู

  • ผู้เขียนเน้นหลักว่า ทำน้อยกว่าย่อมเร็วและง่ายกว่า
  • ในการทำงานจริง ผมมักคิดเสมอว่า ข้อกำหนดของงานที่ได้รับสามารถผ่อนให้เบาลงได้หรือไม่
    • ตัวอย่างคำถาม:
      • รวมหลายหน้าจอให้เหลือหน้าจอเดียวได้ไหม?
      • จำเป็นต้องรองรับ edge case ที่ยุ่งยากทั้งหมดจริงหรือ?
      • ถ้าบอกว่าต้องรองรับอินพุต 1000 รายการ แล้วรองรับแค่ 10 รายการพอได้ไหม?
      • ใช้ prototype แทนของที่เสร็จสมบูรณ์ได้หรือไม่?
      • ตัดฟีเจอร์นี้ออกไปเลยได้ไหม?
  • แนวทางนี้ช่วยเพิ่มทั้งความเร็วและประสิทธิภาพในการพัฒนา
  • ผมยังพยายามค่อย ๆ ผลักดันวัฒนธรรมองค์กรให้ไปสู่ จังหวะการทำงานที่ช้าลงเล็กน้อยแต่สมเหตุสมผลมากขึ้น
    • การเรียกร้องให้เปลี่ยนใหญ่แบบฉับพลันมักไม่ได้ผล
    • จึงค่อย ๆ เปลี่ยนบรรยากาศผ่านข้อเสนอทีละน้อย หรือการเปลี่ยนรูปแบบการพูดคุยถกเถียง

หลีกเลี่ยงสิ่งรบกวน (Distraction) ในการเขียนโค้ด

  • ไม่ใช่แค่สภาพแวดล้อมภายนอกอย่างการแจ้งเตือนหรือการประชุมเท่านั้น แต่ การเผลอไหลออกนอกเรื่องระหว่างทำงานกับโค้ด ก็เป็นตัวรบกวนใหญ่เช่นกัน
  • ผมเองก็มักเริ่มจากแก้บั๊ก แต่สุดท้ายกลับไปแกะส่วนที่ไม่เกี่ยวข้องเลย จนงานเดิมถูกเลื่อนออกไป
  • มีวิธีปฏิบัติที่ชัดเจนอยู่สองอย่าง:
    • ตั้งตัวจับเวลา: กำหนดเวลาสำหรับแต่ละงาน และเมื่อสัญญาณดังให้ตรวจสอบสถานะปัจจุบัน
      • ช่วยเตือนตัวเองเมื่อใช้เวลานานเกินคาด
      • ถ้ากด git commit พร้อมเสียงเตือน ก็ยังได้ความรู้สึกสำเร็จเล็ก ๆ ด้วย
      • (วิธีนี้ยังช่วยฝึกการประเมินเวลาด้วย)
    • pair programming: เมื่อทำงานร่วมกับคนอื่น จะหลุดไปทำเรื่องไม่จำเป็นน้อยลง และช่วยรักษาสมาธิได้ดี
  • สำหรับนักพัฒนาบางคน การหลีกเลี่ยงสิ่งรบกวนเป็นเรื่องธรรมชาติ แต่สำหรับผม มันต้องอาศัย การตั้งใจจดจ่อและฝึกให้เป็นนิสัย

เปลี่ยนแปลงเป็นหน่วยเล็ก ๆ แบ่งให้ย่อย

  • เมื่อก่อนผมเคยมีหัวหน้าที่สนับสนุน แพตช์ใหญ่ ๆ และการเปลี่ยนแปลงวงกว้าง
    แต่จากประสบการณ์จริง มันไม่มีประสิทธิภาพอย่างมาก
  • ผมรู้สึกว่า diff ที่เล็กและโฟกัสชัดเจน แทบจะดีกว่าเสมอ
    • ภาระในการเขียนโค้ดน้อยกว่า
    • code review ง่ายและเร็วขึ้น ลดความเหนื่อยล้าของเพื่อนร่วมงาน และทำให้หาความผิดพลาดของตัวเองได้ง่ายขึ้น
    • เมื่อมีปัญหา ก็ rollback ได้ง่ายและปลอดภัยกว่า
    • เพราะขอบเขตที่เปลี่ยนในแต่ละครั้งเล็ก จึงลดความเสี่ยงที่จะเกิดบั๊กใหม่ได้ด้วย
  • แม้แต่ฟีเจอร์ใหญ่หรือการเพิ่มความสามารถใหม่ ก็ประกอบขึ้นจากการเปลี่ยนแปลงเล็ก ๆ สะสมกัน
    • เช่น ถ้าต้องเพิ่มหน้าจอใหม่ ก็อาจแยก bug fix / อัปเกรด dependency / เพิ่มฟีเจอร์ ออกเป็นแพตช์คนละชุด
  • ผู้เขียนย้ำว่า การเปลี่ยนแปลงเป็นหน่วยเล็ก ช่วยให้พัฒนาซอฟต์แวร์ได้ทั้งเร็วขึ้นและมีคุณภาพสูงขึ้น

ทักษะเชิงปฏิบัติที่ช่วยให้พัฒนาได้เร็วขึ้นจริง

สิ่งที่พูดถึงก่อนหน้านี้อาจฟังดูค่อนข้างเป็นนามธรรม แต่ก็มี ทักษะภาคปฏิบัติที่ได้ผลจริงในการพัฒนาให้เร็วขึ้น อยู่ด้วย

  • การอ่านโค้ด (Reading code): เป็น ความสามารถสำคัญที่สุดของนักพัฒนา ที่ผมได้เรียนรู้มาจนถึงตอนนี้

    • ถ้าอ่านและตีความโค้ดเดิมได้คล่อง การดีบัก ก็จะง่ายขึ้นมาก
    • ทำให้ไม่ค่อยกลัวบั๊กหรือเอกสารที่ไม่ครบของไลบรารีโอเพนซอร์ส/third-party เท่าไร
    • การอ่านโค้ดของคนอื่นยังช่วยให้เรียนรู้ได้มหาศาล และยกระดับทักษะการแก้ปัญหาโดยรวมโดยตรง
  • Data modeling: ถึงจะใช้เวลา แต่การ ออกแบบ data model ให้ถูกต้อง เป็นเรื่องสำคัญมาก

    • database schema ที่ออกแบบผิดจะนำไปสู่ปัญหาหลากหลายอย่างและต้นทุนการแก้ไขที่สูงในภายหลัง
    • การออกแบบให้ ไม่สามารถแสดงสถานะที่ไม่ถูกต้องได้ตั้งแต่ต้น ช่วยลดบั๊กได้จากราก
    • ยิ่งเป็นข้อมูลที่ต้องจัดเก็บหรือแลกเปลี่ยนกับภายนอก ยิ่งต้องรอบคอบ
  • การเขียนสคริปต์ (Scripting): ความสามารถในการ เขียนสคริปต์สั้น ๆ ได้อย่างรวดเร็ว ด้วย Bash, Python ฯลฯ ช่วยเพิ่มประสิทธิภาพการพัฒนาอย่างมาก

    • ผมนำมาใช้ทำงานอัตโนมัติหลายครั้งต่อสัปดาห์ เช่น จัดรูปแบบ Markdown จัดระเบียบข้อมูล หรือหาความซ้ำซ้อนของไฟล์
    • สำหรับ Bash ใช้เครื่องมืออย่าง Shellcheck เพื่อป้องกันข้อผิดพลาดทางไวยากรณ์ล่วงหน้า
    • ถ้าเป็นงานที่ไม่จำเป็นต้อง robust มาก ก็สามารถใช้ LLM ช่วยทำให้เสร็จเร็วขึ้นได้
  • การใช้ debugger: การใช้ debugger จำเป็นต่อการวินิจฉัยปัญหาอย่างรวดเร็วและทำความเข้าใจ flow ของโค้ดในแบบที่ print/log อย่างเดียวทำไม่ได้

    • ทำให้หาต้นตอของบั๊กซับซ้อนได้เร็วขึ้นมาก
  • จังหวะที่ควรพักให้เหมาะสม: มีนิสัย พักอย่างเด็ดขาดเมื่อเริ่มตัน

    • บ่อยครั้งมากที่ปัญหาซึ่งแก้มานานก็ยังไม่ออก กลับแก้ได้ทันทีหลังพักแค่ 5 นาที
    • สิ่งนี้สำคัญต่อประสิทธิภาพของสมาธิด้วย
  • การเน้น pure function และ immutable data: functional programming: ถ้าชอบใช้ pure function และ immutable data

    • จะช่วยลดบั๊ก ลดภาระในการตามสถานะ และเพิ่มความชัดเจน/คาดเดาได้ของโค้ด
    • หลายครั้งมันเรียบง่ายและได้ผลกว่าการออกแบบลำดับชั้นของคลาสที่ซับซ้อน
    • แม้จะไม่สามารถทำได้เสมอไป แต่โดยพื้นฐานแล้วผมจะพิจารณาแนวทางนี้ก่อน
  • การใช้ LLM (large language models): LLM (เช่น ChatGPT) แม้จะมีข้อเสีย แต่ก็ช่วยเพิ่มความเร็วอย่างมากในงานพัฒนาที่ซ้ำ ๆ หรือทำให้อัตโนมัติได้

    • ผมใช้งานอย่างจริงจังหลังจากเข้าใจดีทั้งวิธีนำ LLM มาใช้กับโค้ดของตัวเองและข้อจำกัดของมัน
    • รวมถึงอ้างอิงประสบการณ์ เคล็ดลับ และกรณีศึกษาหลากหลายจากชุมชนด้วย
      ทักษะทั้งหมดนี้เป็นสิ่งที่ผมฝึกซ้ำมาอย่างยาวนาน และมันกลายเป็นทรัพย์สินสำคัญในการพัฒนาให้เร็วขึ้นจริง

สรุป

  • บทเรียนหลักที่ผมได้จากการพัฒนาซอฟต์แวร์ให้รวดเร็วมีดังนี้
    • ต้องเข้าใจให้ชัดว่าแต่ละงานต้องการมาตรฐานคุณภาพโค้ดระดับไหน
    • เขียน rough draft (ฉบับร่าง) ให้เร็ว เพื่อมองภาพรวมของงานให้ได้ก่อน
    • คอยมองหาโอกาสในการ ผ่อนคลายข้อกำหนด อยู่เสมอ
    • ไม่ปล่อยให้สิ่งรบกวนดึงออกนอกทาง และรักษาสมาธิไว้
    • เปลี่ยนแปลงทีละเล็กและ commit บ่อย หลีกเลี่ยงแพตช์ขนาดใหญ่
    • ฝึก ทักษะเชิงปฏิบัติที่เฉพาะเจาะจง (เช่น การอ่านโค้ด, data modeling, debugging, scripting) อย่างต่อเนื่อง
  • ทุกอย่างดูเหมือนเป็นเรื่องธรรมดามาก แต่กว่าผมจะได้บทเรียนเหล่านี้มาก็ใช้เวลานานมาก

2 ความคิดเห็น

 
nicewook 2025-07-15

มีหลายเรื่องที่รู้สึกเห็นด้วยมากครับ
คอมเมนต์ก็ดีด้วย แต่พอมีใครสักคนมาช่วยเรียบเรียงและพูดออกมาแบบนี้ คือช่วยปูพื้นที่ให้การโต้แย้ง การสนับสนุน และการเสริมรายละเอียดตามมา จนดูเหมือนจะสมบูรณ์ยิ่งขึ้นครับ

ป.ล. ช่วงนี้เห็นคำว่า "เทคโนโลยีที่น่าเบื่อ" บ่อยมาก ซึ่งในภาษาอังกฤษก็คือ boring technology นั่นเองครับ

 
GN⁺ 2025-07-15
ความคิดเห็นบน Hacker News
  • ช่วงไม่กี่ปีที่ผ่านมาได้เรียนรู้วิธีสร้างระบบที่ทั้งเร็วและแข็งแรงเพียงพอ

    • ได้เรียนรู้ว่าการเชี่ยวชาญเครื่องมือหนึ่งให้ลึกสำคัญมาก เครื่องมือที่เราคุ้นเคยดีมีประสิทธิภาพกว่ามากเมื่อเทียบกับเครื่องมือที่ดูเหมือนจะเหมาะกว่าในเชิงผิวเผิน และในความเป็นจริง Django ก็เป็นตัวเลือกที่พอดีสำหรับโปรเจกต์ส่วนใหญ่

    • บางครั้งก็เริ่มโปรเจกต์ด้วยความกังวลว่า Django จะหนักเกินไปหรือเปล่า แต่สุดท้ายโปรเจกต์ก็มักเติบโตเกินเจตนาเริ่มต้นไปมาก ตัวอย่างเช่น เคยทำแอป status page แล้วก็รู้แทบจะทันทีว่าความพยายามจะหลบข้อจำกัดของ Django นั้นไม่มีประสิทธิภาพ

    • สำหรับแอปส่วนใหญ่ที่เข้ากับ Django model ได้ data model คือหัวใจสำคัญ แม้จะเป็นแค่ต้นแบบ ถ้าเลื่อนการ refactor data model ออกไป ต้นทุนและความยากในภายหลังจะเพิ่มขึ้นแบบทวีคูณ

    • แอปส่วนใหญ่ไม่ต้องการ single-page app หรือ frontend framework หนัก ๆ บางส่วนอาจต้องใช้ แต่ 80% ของทั้งหน้าใช้ Django view แบบดั้งเดิมก็พอแล้ว ส่วนที่เหลือค่อยพิจารณา AlpineJS หรือ HTMX

    • ในกรณีส่วนใหญ่ การทำเองง่ายกว่า ด้วย Django สามารถสร้าง CRM, status page, support system, sales process และความสามารถอื่น ๆ ได้อย่างรวดเร็ว เร็วกว่าการเชื่อมต่อ CRM เชิงพาณิชย์มาก

    • เลือกเทคโนโลยีธรรมดาจนน่าเบื่อ ชุด Python/Django/Postgres แก้ปัญหาได้เกือบทั้งหมด ลืม Kubernetes, Redis, RabbitMQ, Celery ไปได้เลย Alpine/HTMX เป็นข้อยกเว้น เพราะช่วยเลี่ยง JS stack ส่วนใหญ่ได้

    • สำหรับฉัน Redis และ Kubernetes คือ ‘เทคโนโลยีน่าเบื่อ’ ของปี 2025 ทั้งคู่เสถียรอย่างมาก มี use case ชัดเจน และข้อเสียก็เป็นที่รู้กันดีอยู่แล้ว จึงเชื่อถือได้สูง ส่วนตัวฉันเป็นแฟนของสองอย่างนี้ เพราะมันทำสิ่งที่ต้องการได้ตรงเป๊ะจึงไว้ใจได้มาก

    • ฉันเองก็ชอบ Django มากจริง ๆ มันช่วยให้เริ่มโปรเจกต์และ deploy ได้เร็วมาก

      • ที่ทำงานใช้ Go แต่การพัฒนา API endpoint แบบเดียวกันกลับต้องเขียนโค้ดยาวกว่า 10 เท่า ทุกครั้งที่เพิ่มความสามารถอย่าง query parameter หรือ pagination โค้ดก็ยิ่งยาวขึ้น และถ้าเพิ่ม permission model ก็ยิ่งหนักเข้าไปอีก
      • แน่นอนว่าความต่างด้านประสิทธิภาพก็มีมาก แต่ในความเป็นจริง DB query เป็นตัวกำหนดประสิทธิภาพส่วนใหญ่ Python ก็เร็วพออยู่แล้ว
    • ถ้าจะเลือก ‘เทคโนโลยีน่าเบื่อ’ จริง ๆ แม้แต่ Postgres เองก็ควรคิดอีกที

      • Sqlite รองรับขนาดงานได้มากกว่าที่หลายคนคิดมาก โดยเฉพาะในการพัฒนาแบบ local หรือ isolated CI instance และสำหรับแอปขนาดเล็กก็ใช้ใน production ได้สบาย
    • ผมใช้ Celery กับโปรเจกต์ Django ค่อนข้างบ่อย ไม่ชอบความซับซ้อนของมันนัก แต่ในสภาพแวดล้อมแบบ PaaS มันกลับเป็นตัวเลือกที่เจ็บปวดน้อยที่สุด

      • ทุกครั้งจะเริ่มด้วยความตั้งใจว่าจะลองทำโดยไม่ใช้ Celery แต่สุดท้ายงานที่ trigger ผ่าน HTTP ก็มักชน timeout จนต้องกลับมาใช้ Celery อยู่ดี พอถึงจุดนั้นก็ต้องเลือกอย่างใดอย่างหนึ่งระหว่าง thread, cron job (โดยเฉพาะบน PaaS ที่ยาก) หรือ Celery อยากรู้ว่าคนอื่นรับมืออย่างไร
    • ข้อความที่ว่า "แอปส่วนใหญ่ไม่ต้องการ SPA หรือ frontend framework หนัก ๆ" ดูเหมือนจะขัดกับคำแนะนำว่า "เชี่ยวชาญเครื่องมือหนึ่งให้ลึก"

      • ฉันทำทุกหน้าด้วย React เหตุผลไม่ใช่ว่าจำเป็นต้องเป็น SPA แต่เพราะสุดท้ายมักมีงานที่ต้องจัดการ client-side state อยู่ดี เลยรู้สึกว่าสะดวกกว่าที่จะสร้างทุกอย่างด้วย React ตั้งแต่แรก แม้ตอนแรกจะดูหนัก แต่สุดท้ายมีประสิทธิภาพกว่า
  • เมื่อปล่อยให้โค้ดอยู่ในสภาพ draft หยาบ ๆ ผู้จัดการก็มักจะนำโค้ดนั้นไปปล่อยเป็น ‘เวอร์ชันสุดท้าย’ เลย

    • เพราะงั้นจึงเขียนให้ robust ตั้งแต่แรก แม้แต่ test harness ก็ทำให้แข็งแรงเกือบระดับพร้อมปล่อยจริง

    • หัวใจสำคัญคือการสร้างโมดูลคุณภาพสูงมาก ส่วนที่แทบไม่มีโอกาสเปลี่ยน หรือถ้าเปลี่ยนแล้วจะเกิดปัญหาใหญ่ ก็ควรแยกเป็นโมดูลอิสระแล้ว import เป็น dependency

    • โมดูลแบบนี้ทำให้พัฒนาแอปใหม่ได้เร็วมาก และรักษาคุณภาพให้สูงอย่างต่อเนื่องได้

    • ตัวอย่างที่เคยใช้จริงมีเช่น RVS_Checkbox, ambiamara, RVS_Generic_Swift_Toolbox เป็นต้น

    • มีคำถามว่า ใน Swift การใช้แพตเทิร์นโค้ดอย่าง "* ##################################################################" เป็น comment marker ถือเป็นมาตรฐานหรือไม่

      • มันโดดเด่นมากในซอร์สโค้ดเมื่อมองด้วยตา
  • วิธีการจะต่างกันมากตามขนาดของโปรเจกต์

    • ถ้าเป็นโปรเจกต์ส่วนตัวหรือทีมเล็ก การพัฒนาแบบ ‘เร็วและหยาบ’ มักเหมาะที่สุด นี่คือจุดแข็งของการพัฒนาขนาดเล็ก

    • ในทีมเล็ก หากมีบั๊กก็แก้ได้เร็ว และสมาชิกทุกคนมักเข้าใจโค้ดทั้งหมดแทบสมบูรณ์

    • เมื่อขนาดใหญ่ขึ้น ต้นทุนของความผิดพลาดด้านสถาปัตยกรรมหรือการแก้บั๊กจะพุ่งสูง สถาปัตยกรรมย่อมซับซ้อนขึ้น และการ refactor ครั้งใหญ่แทบเป็นไปไม่ได้ ในสภาพแวดล้อมแบบนี้ ความถูกต้องในทุกก้าวต้องมาก่อนเสมอ

    • บริบทสำคัญมาก คำว่า ‘ขนาดใหญ่’ อาจหมายถึงคนละระดับ แต่จากประสบการณ์ของฉัน การตกลง API ระหว่างแอปให้เร็วตั้งแต่ต้น เพื่อให้ทั้งฝั่ง frontend และ backend เริ่มทำงานได้ไว เป็นสิ่งที่ถูกต้องเสมอ

      • การ deploy ขึ้น production server ให้เร็วที่สุดเพื่อเปิดเผยปัญหาจากการทดสอบและปัญหาระหว่างทีมมีประสิทธิภาพมาก
      • ผู้เขียนดูเหมือนจะเน้นจากมุมมองของโค้ด แต่ฉันคิดว่ายิ่งเป็นทีมใหญ่ ประเด็นนี้ยิ่งสำคัญ
      • อย่างไรก็ตาม ฉันไม่ค่อยชอบสถาปัตยกรรมที่มี dependency แบบลำดับชั้นระหว่างทีม แม้ในความจริงจะพบได้บ่อยก็ตาม
    • ในสถานการณ์แบบนี้ควรลดขนาดของระบบลง ทุกคนอยากได้ระบบยักษ์ แต่ความจริงแล้วมักไม่จำเป็น

  • มีคำพูดว่า “ในเกมแจม 24 ชั่วโมงไม่ต้องใส่ใจคุณภาพโค้ด” แต่จากประสบการณ์แฮกกาธอนและโค้ดรีวิวส่วนใหญ่ของฉัน ทีมที่ทำผลงานได้ดีที่สุดมักใส่ใจทั้งคุณภาพโค้ดและสภาพแวดล้อมการทดสอบขั้นพื้นฐานด้วย

    • สองข้ออ้างข้างต้น (ถ้าจะทำให้เร็วต้องยอมเสียคุณภาพโค้ด vs ทีมที่ผลงานดีมักมีคุณภาพสูงกว่า) จริง ๆ แล้วไม่ได้ขัดกัน ทีมที่มีคุณภาพไม่ได้หมกมุ่นอยู่กับความเนี้ยบของโค้ดอย่างเดียวเสมอไป

    • ในกรณีของเกมแจม ถ้ายึดติดกับความสะอาดของโค้ดมากเกินไป กลับอาจทำให้ผลงานโดยรวมออกมาไม่ดี ระบบอย่าง UE blueprint แสดงให้เห็นว่าทำไมบางครั้งต้องให้ความสำคัญกับผลลัพธ์มากกว่าความ ‘สะอาด’

    • บางคนประเมิน ‘ความสะอาด’ ของโค้ดในภาพรวม ขณะที่บางคนประเมินต้นทุน/ประโยชน์ของการปรับปรุงโค้ดที่ไม่จำเป็นในรายละเอียด

      • ฉันคิดว่าแนวทางหลังให้ผลลัพธ์ดีกว่ามากในทุกสถานการณ์ ไม่ว่าจะในแฮกกาธอนหรือโค้ดผลิตภัณฑ์ที่ต้องการความเสถียรสูง
  • ต่างจากแนวคิดที่ว่า “พอลองทำ prototype แล้ว unknown unknowns ที่ไม่คาดคิดจะโผล่ออกมา” เวลาฉันเริ่มจับอะไรใหม่ ๆ ฉันมักเห็นแต่ข้อดี และมองไม่ค่อยเห็นข้อเสีย

    • ในความจริง ปัญหาที่แท้จริงหรือ unknown unknowns มักโผล่มาในช่วงทำฟีเจอร์ให้สมบูรณ์ เช่น การจัดการ edge case, ข้อความ error ที่เป็นมิตรกับผู้ใช้, หรือการกำจัดผลข้างเคียง

    • บางที unknown unknowns ที่ฉันเจออาจมาจากตัวเครื่องมือ/framework/library เอง ขณะที่ผู้เขียนอาจกำลังพูดถึง unknown unknowns ในตัว problem domain

    • ก็จริงที่ rough draft ไม่ควรหยาบเกินไป ถ้ามีส่วนที่ไม่ควรปล่อยผ่านแบบลวก ๆ ปัญหาจริงจะระเบิดออกมาตรงนั้น

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

  • ในยุคนี้ที่วงการเทคโนโลยีมีการปรับลดพนักงานบ่อย ๆ สิ่งนี้ต่างหากคือภัยคุกคามใหญ่ที่สุดต่อคุณภาพซอฟต์แวร์และผลิตภาพของวิศวกร

    • ความกังวลเรื่องการปลดพนักงานและแรงกดดันให้สร้างผลงานเร็ว ๆ ฆ่าความคิดสร้างสรรค์และจิตวิญญาณแห่งการทดลอง พร้อมทั้งทำให้เกิด burnout

    • ทุกคนถูกกระแสประเด็นฮิตอย่าง AI พัดพาไปตามแรงหมู่ชน จนกลายเป็นสภาพแวดล้อมที่แม้แต่การวิจารณ์ก็ทำได้ยาก

    • นี่เป็นปัญหาเร่งด่วนยิ่งกว่า LLM auto-coding เสียอีก

    • ภัยคุกคามสูงสุดต่อคุณภาพซอฟต์แวร์คือ ผู้บริโภคไม่ยอมจ่ายเงินเพื่อคุณภาพมาโดยตลอด

      • แม้จะมีกลุ่มผู้ใช้ที่ ‘รับรู้’ ถึงคุณภาพ แต่ก็ยังไม่พอจะทำให้ผลิตภัณฑ์ใหม่ประสบความสำเร็จได้ด้วยคุณภาพเพียงอย่างเดียว
      • ในอุตสาหกรรมอื่นนอกเหนือจากซอฟต์แวร์ เช่น รถยนต์หรือเครื่องใช้ไฟฟ้า ราคาแตกต่างกันตามคุณภาพ แต่ในซอฟต์แวร์ไม่เป็นเช่นนั้น
    • vendor lock-in ในระดับการเขียนโปรแกรมจริง ๆ แล้วทำลายล้างยิ่งกว่า SaaS lock-in มาก

      • ตลาดฮาร์ดแวร์ก็ถูกผูกขาดโดยคนเพียงไม่กี่รายอยู่แล้ว และต่อไปซอฟต์แวร์ก็จะถูกบริษัทกลุ่มเดียวกันผูกขาดเหมือนกัน
      • สุดท้ายแล้วอาจเหลือเพียง LLM prompter แทนที่จะเป็นโปรแกรมเมอร์คอมพิวเตอร์
  • ในรอบการพัฒนาที่เร็วมากอย่างเกมแจม 24 ชั่วโมง ยิ่งรู้สึกว่าโค้ดแย่ ๆ เป็นเรื่องถึงตาย

    • ยิ่งโค้ดสะอาด ก็ยิ่งผิดพลาดน้อยลง ภาระต่อ working memory ก็น้อยลง และช่วงท้ายก็แก้ไข เพิ่มฟีเจอร์ หรือแก้ปัญหาตามต้องการได้ง่ายกว่ามาก

    • สิ่งที่ทำให้โปรเจกต์ 24 ชั่วโมงพังบ่อยที่สุด ไม่ใช่การเขียนโค้ดช้า แต่เป็นการต้อนตัวเองเข้ามุมหรือเจอปัญหาที่คาดเดาไม่ได้จนหลุดราง

    • แน่นอนว่าไม่ได้หมายความว่าต้องแก้ทุกบั๊ก แต่ถ้าคุณภาพพื้นฐานต่ำ ประสบการณ์ทำโปรเจกต์โดยรวมจะลำบากมาก

    • หลักการนี้ใช้ได้กับโปรเจกต์ที่มีเวลามากกว่าด้วย มีเวลาเยอะไม่ได้แปลว่าควรเขียนแบบลวก ๆ

    • ถ้าทำให้การเขียนโค้ดดีเป็นนิสัย ก็สามารถคงคุณภาพไว้ได้โดยแทบไม่มีต้นทุนเพิ่ม และถึงจะใช้เวลามากขึ้นบ้าง สุดท้ายก็คุ้มค่าอยู่ดี

    • ฉันก็คิดเหมือนกัน เคยทำเกมแจมมาหลายครั้ง แต่ ‘โค้ดหละหลวม’ ยอมรับได้แค่ในช่วง 1-2 ชั่วโมงก่อนหมดเวลา และต้องอยู่ในไฟล์ที่คนอื่นจะไม่แตะเท่านั้น

      • การจัดระเบียบโค้ดอย่างการรวบรวม logic ร่วม ใช้เวลาไม่นานอย่างที่คิด
      • ในทางปฏิบัติ บั๊กที่เกิดจากโค้ดเขียนลวก ๆ มีต้นทุนสูงกว่าและเสี่ยงกว่ามากเมื่อเทียบกับเวลาที่ประหยัดได้จากการไม่จัดระเบียบโค้ด
      • อย่างไรก็ตาม สำหรับฟังก์ชันที่คล้ายกันแต่ต่างกัน เช่น fade out ของแสง กับ fade out ของสี ฉันมักปล่อยให้มีโค้ดซ้ำ เพราะ requirement มีโอกาสแยกทางกันได้ง่าย
    • ถ้าอยากเขียนโค้ดให้ทั้งเร็วและดี สุดท้ายคำตอบคือเขียนให้เยอะ

      • แม้อาจจะเกลียดงานซ้ำ ๆ แต่ในทางปฏิบัติมันได้ผล
      • คนที่เขียนโค้ดได้สะอาดภายในเวลาที่จำกัด คือคนที่เคยเขียนโค้ดแบบนั้นมามากแล้ว
    • เวลาต้องรีบ ก็ไม่ไปสนใจอะไรอย่าง fancy asset loader แต่ใช้ไฟล์ static ตรง ๆ เลย

      • ถ้าต้องมีการค้นหา path ก็ใช้วิธีง่าย ๆ อย่าง breadth first search ไปเลย
      • สิ่งเหล่านี้ไม่ใช่ ‘โค้ดแย่’ แต่เป็นแค่ทางออกชั่วคราวและวิธีแก้ปัญหาที่เร็ว
      • แน่นอนว่าบางครั้งกฎข้อบังคับอาจห้ามใช้โมดูลแบบนี้ ซึ่งในกรณีนั้นก็ต้องทำตามกติกาที่มี
    • ฉันคิดว่าความเชื่อที่ว่า ‘การเขียนโค้ดที่ดีใช้เวลานานกว่า’ เป็นความเข้าใจผิด หากต้องให้ถึงระดับ requirement อย่างหนึ่งอย่างใด โค้ดที่ดีไม่ได้เป็นอุปสรรคต่อความเร็ว

  • มาตรฐานว่า “ระดับไหนถึงจะ good enough” แต่ละทีมต่างกันมาก และนั่นเป็นสาเหตุความขัดแย้งใหญ่ที่สุดในเส้นทางอาชีพของฉัน

    • คนจากบิ๊กเทคไม่พอใจกับการทดสอบที่ไม่เพียงพอ ส่วนคนจากสตาร์ทอัปไม่พอใจกับความเร็วที่ช้า

    • การบันทึกมาตรฐานของคำว่า ‘good enough’ ให้ชัดเจนเป็นเอกสารและแชร์ในทีม น่าจะเป็นประโยชน์มาก

    • นั่นแหละคือ team charter หรือเอกสาร ‘วิธีที่เราทำงานร่วมกัน’

  • ปัจจัยสำคัญอย่างหนึ่งที่บทความไม่ได้พูดถึงคือ ความเร็วในการพัฒนาที่ลดลงตามกาลเวลา

    • เมื่อโปรเจกต์และทีมใหญ่ขึ้น ความเร็วในการพัฒนาก็ย่อมช้าลงตามธรรมชาติ

    • แม้จะต้องยอมเสียความเร็วระยะสั้นไปบ้าง แต่ก็ควรเตรียมเรื่องการทดสอบ เอกสาร decision log และ Agile meeting ตั้งแต่ต้น เพื่อให้ความเร็วในการพัฒนาระยะยาวลดลงน้อยที่สุด

    • หากไม่เตรียมสิ่งอย่าง observability หรือโครงสร้างโค้ดที่ทดสอบได้ง่ายไว้ล่วงหน้า ภายหลังจะส่งผลเสียอย่างมหาศาล

    • แม้จะเป็นนักพัฒนาคนเดียว แต่ฉันก็สัมผัสได้ถึงความสำคัญของสามอย่างคือ decision log, การทดสอบ และเอกสาร

      • ฉันเขียนบันทึกการออกแบบแบบเรียลไทม์ที่เรียกว่า “lab notebook” ซึ่งกลายเป็นพื้นฐานของการทดสอบและเอกสารในภายหลัง
      • ถ้ามี lab notebook ต่อให้เริ่มช้าก็ยังเขียนเอกสารที่ดีกว่าได้อย่างรวดเร็ว และการทดสอบก็ช่วยยืนยันได้ว่าการออกแบบไม่ได้เปลี่ยนไป
      • ถ้าเป็นเครื่องมือใช้ครั้งเดียวสั้น ๆ จะเริ่มแบบลุยเลยก็ได้ แต่ถ้าเป็นระบบที่จะใช้นาน ต่อให้ช้าหน่อย การวางรากฐานให้แน่นก็ให้ผลลัพธ์ที่สมเหตุสมผลและดูแลรักษาได้ในที่สุด
      • แม้จะเป็นความเห็นที่ไม่ค่อยนิยม แต่การออกแบบบนกระดาษก่อนแล้วค่อยย้ายไปดิจิทัลนั้นได้ผลมาก
  • นี่ก็เป็นแพตเทิร์นที่คุ้นเคยสำหรับฉันเหมือนกัน เริ่มจาก rough draft หรือโค้ดเล็ก ๆ ที่ใช้ภาษา scripting อื่นหรือการรันแบบ manual เพื่อพิสูจน์แนวคิด

    • ผ่านกระบวนการแบบนี้ บางครั้งกลับได้ข้อสรุปว่า “เราไม่จำเป็นต้องสร้างสิ่งที่คิดไว้ก็ได้”
    • ฉันเห็นด้วยมากกับประเด็นที่ว่าระหว่างเขียนโค้ดสมาธิอาจหลุด พอเริ่มเก็บกวาดก็เผลอตกลงไปใน rabbit hole จนขนาดของ commit ใหญ่เกินไปและเพื่อนร่วมทีมรีวิวลำบาก สุดท้ายก็มักต้องทิ้งงานทั้งหมดแล้วเริ่มใหม่ให้เล็กลงและโฟกัสกับเป้าหมายมากขึ้น
    • บางครั้งก็แยกเฉพาะชิ้นส่วนที่ใช้ได้ออกมาแล้วส่งเป็น PR อื่นต่างหากได้
    • ธุรกิจต้องการผลลัพธ์เร็ว และมักไม่เข้าใจ trade-off ของโค้ด จนกว่าจะเจอ technical debt พอกพูนเป็นภูเขาและทำให้ความเร็วในการพัฒนาช้าลงอย่างหนัก
    • สิ่งสำคัญคือความสมดุล และแต่ละโปรเจกต์อาจใช้มาตรฐานต่างกันได้
    • เพราะงั้นการเปลี่ยนแปลงเล็ก ๆ ที่มีโฟกัสและเรียบง่าย แต่ทำบ่อย ๆ จึงช่วยได้มาก
    • อย่างไรก็ดี การแยกทางออกใหญ่ ๆ ออกเป็นชิ้นเล็ก ๆ นั้นไม่ง่ายอย่างที่คิด
    • ฉันเห็นบ่อยมากว่ามีคน commit โค้ดที่ไม่เกี่ยวข้องและไม่ได้ใช้งานเลยด้วยเหตุผลว่า ‘เผื่ออนาคตต้องใช้’ แต่สุดท้ายเมื่อ priority เปลี่ยน คนย้ายทีม หรือเวลาผ่านไปหนึ่งปี โค้ดทั้งหมดนั้นก็กลายเป็นโค้ดไร้ประโยชน์ และไม่มีใครรู้แผนในตอนนั้นอีกต่อไป