- โปรเจ็กต์มักแยกไปได้ง่ายระหว่างกระแสแบบ ลงมือทำให้เสร็จทันที กับกระแสที่การค้นคว้าและการออกแบบพองตัวจนหลุดจากปัญหาเดิม และในแง่ความคืบหน้าจริง หลายครั้งฝั่งที่ ลองทำไปเลย กลับไปได้ไกลกว่า
- แม้จะเริ่มจากการทำ fuzzy path search สำหรับ Emacs แต่ ฟีเจอร์เสริมของไลบรารีที่ดี ก็สร้างความต้องการใหม่จนงานออกแบบบวมขึ้น สุดท้ายต้องทิ้งโค้ดฟีเจอร์ anchor ที่ไม่จำเป็นทั้งหมด และได้กลับมายืนยันหลัก YAGNI อีกครั้ง
- ในการทำ code diff การเทียบแบบรายบรรทัดจับโครงสร้างระดับบนอย่างฟังก์ชันหรือ type ได้ไม่ดี และแม้แต่เครื่องมือบนฐาน treesitter ก็อาจอ่านยากได้หากการจับคู่เอนทิตีคลาดเคลื่อน จนแสดงเป็นการลบและเพิ่มยาว ๆ
- ทิศทางที่จำเป็นคือสร้างเครื่องมือขอบเขตเล็กให้รองรับ การรีวิวผลลัพธ์ LLM แบบทีละรอบ ก่อน โดยเริ่มจากการดึงเอนทิตีสำหรับ Rust และการจับคู่แบบง่าย ๆ เพื่อให้เห็น ภาพรวมการเปลี่ยนแปลงระดับสูง ได้อย่างรวดเร็ว
คิดมากเกินไปและการขยายขอบเขต
- โปรเจ็กต์มักแยกออกได้ง่ายเป็นสองทาง: ทางหนึ่งคือ ลงมือทำให้เสร็จทันที อีกทางคือขุดคุ้ยกรณีก่อนหน้าไปเรื่อย ๆ จนขอบเขตพองขึ้น และสุดท้ายกลับแก้ปัญหาตั้งต้นไม่ได้
- ชั้นวางของในครัวที่ทำช่วงสุดสัปดาห์ชิ้นหนึ่ง ถูกออกแบบระหว่างจิบกาแฟ ปรับไม้แขวนที่พิมพ์ 3D อยู่ไม่กี่รอบ แล้วใช้เศษวัสดุและสีที่เหลืออยู่ทำจนเสร็จภายในสุดสัปดาห์
- CAD สำหรับไม้แขวนถัง Ikea ถูกเผยแพร่ไว้ที่ OnShape CAD
- วัสดุถูกนำของเหลือจากโต๊ะทำงานกลับมาใช้ใหม่ และขอบมุมก็ขัดแต่งคร่าว ๆ ด้วย palm sander
- สำหรับชั้นวางนี้ เกณฑ์ความสำเร็จหลักไม่ใช่การทำของให้พอดีกับครัวอย่างแม่นยำ แต่เป็นการ สนุกกับงานไม้ร่วมกับเพื่อน ซึ่งช่วยลดความจำเป็นในการกังวลรายละเอียดเกินไป
- ในทางกลับกัน ระหว่างมองหาเครื่องมือ structural diff หลังจากไม่พอใจกับผลลัพธ์ของ difftastic ก็ใช้เวลา 4 ชั่วโมงค้นคว้าเครื่องมือและ workflow ที่เกี่ยวข้อง แต่สุดท้ายก็กลับมาหาเกณฑ์เดิม คือ workflow diff ที่ดีกว่าสำหรับใช้ใน Emacs
- ความสนใจระยะยาวอย่างอินเทอร์เฟซสำหรับฮาร์ดแวร์ต้นแบบ ภาษาแบบผสม Clojure กับ Rust หรือภาษาสำหรับ CAD ล้วนใช้เวลาไปหลายร้อยชั่วโมงกับการค้นคว้าพื้นหลังและต้นแบบเล็ก ๆ แต่ยังไม่ต่อยอดเป็นผลลัพธ์ที่แก้แรงจูงใจตั้งต้นได้โดยตรง
- อินเทอร์เฟซสำหรับฮาร์ดแวร์ต้นแบบอยู่ใน กันยายน 2023, การออกแบบภาษาอยู่ใน พฤศจิกายน 2023, และไอเดียเกี่ยวกับ CAD ต่อเนื่องไปยัง constraints, bidirectional editing, และ other dubious ideas
- ในโปรเจ็กต์ภาษาและ CAD นั้น เกณฑ์ความสำเร็จยังคลุมเครือ เช่น จะมาแทน Rust หรือ Clojure หรือไม่ จะจัดการแค่บางปัญหาหรือเปล่า ถ้าเป็น playground เพื่อการเรียนรู้ก็พอไหม จะมาแทน CAD เชิงพาณิชย์หรือไม่ และต้องมีประโยชน์กับคนอื่นด้วยหรือเปล่า
- การพิจารณาคำถามเหล่านี้มีคุณค่า แต่แทนที่จะเอาแต่พิจารณาหลายเรื่อง ผู้เขียนมองว่าการลงมือสร้างอะไรจริง ๆ ให้มากกว่านี้ดีกว่า
- ต่อให้ภายหลังมองย้อนกลับมาแล้วเห็นว่าผลงานนั้นไม่ดีชัดเจน การ ลองทำไปเลย ก็ยังทำให้โดยรวมไปได้ไกลกว่า
กฎอนุรักษ์ของการขยายขอบเขต
- เวลาสำหรับการลงมือทำแบบไม่คิดมากก็มีขีดจำกัดและต้องมีสมดุล แต่ประสบการณ์ที่เคยใช้ LLM agent เขียนโค้ดจำนวนมากแล้วสุดท้ายต้องทิ้งทั้งหมด ก็ทำให้นึกถึง YAGNI อีกครั้ง
- ผู้เขียนอยากทำ fuzzy path search แบบทั้งไฟล์ซิสเต็มสไตล์ Finda สำหรับใช้ใน Emacs และเคยเขียนฟีเจอร์แบบเดียวกันนี้ด้วยมือมาก่อน จึงคิดว่าถ้าคุม LLM ดี ๆ ก็น่าจะเสร็จได้ในไม่กี่ชั่วโมง
- ตอนแรกในการคุยวางแผน ได้รับคำแนะนำให้ใช้ Nucleo ซึ่งออกแบบและทำเอกสารไว้ดี จึงเลือกใช้เพื่อได้ฟีเจอร์ smart case และ Unicode normalization
- เช่น query
fooจะ match ได้ทั้งFooและfooแต่Fooจะไม่ matchfoo - การจัดการ
cafeและcaféก็อยู่ในบริบทเดียวกัน
- เช่น query
- ปัญหาไม่ได้อยู่ที่ตัวไลบรารีที่ดี แต่คือ Nucleo รองรับฟีเจอร์ anchor ด้วย
- ใน corpus ที่มีแต่ file path ฟีเจอร์ anchor ที่จุดเริ่มต้นบรรทัดดูไม่ค่อยมีประโยชน์ จึงพยายามตีความมันใหม่เป็น anchor ตาม path segment
- เช่น อยากให้
^foomatch/root/foobar/แต่ไม่ match/root/barfoo/
- เช่น อยากให้
- หากจะทำให้มีประสิทธิภาพ ดัชนีต้องเก็บขอบเขตของแต่ละ segment และต้องตรวจ query กับแต่ละ segment ได้อย่างรวดเร็ว
- นอกจากนี้ยังต้องรองรับ anchor query ที่มี slash อย่าง
^foo/barด้วย ทำให้การตรวจแบบราย segment เพียงอย่างเดียวจับ path อย่าง/root/foo/bar/baz/ได้ยาก - ผู้เขียนใช้เวลาอีกหลายชั่วโมงกับการออกแบบนี้ แลกไอเดียกับ LLM และเขียนโค้ดห่อ type ของ Nucleo ก่อนจะพบว่าโค้ดมันบวมเกินไปและไม่น่าพอใจ สุดท้ายจึงกลับมาเขียน wrapper ที่เล็กกว่าด้วยตัวเองใหม่
- หลังพักสักหน่อย ก็คิดไม่ออกว่าเคยต้องใช้ฟีเจอร์ anchor ใน Finda จริง ๆ เมื่อไร และตระหนักว่าใน corpus ที่เป็น path การเติม
/หน้า אוหลัง query ก็ช่วยแทนบทบาทของ anchor ได้เกือบทั้งหมด- ข้อยกเว้นเดียวคือ anchor สำหรับท้ายชื่อไฟล์
- สุดท้ายโค้ดที่เกี่ยวกับ anchor ถูกทิ้งทั้งหมด และผู้เขียนก็ไม่แน่ใจว่ายังถือว่าคุ้มกว่าการเขียนเองตั้งแต่ต้นโดยไม่คุยกับ LLM หรือคนอื่นหรือไม่
- ดูเหมือนยิ่งความเร็วในการเขียนโปรแกรมเพิ่มขึ้น ก็ยิ่งมี ฟีเจอร์ที่ไม่จำเป็น, rabbit hole, และ ทางอ้อม เพิ่มตามขึ้นมา เหมือนเป็นกฎอนุรักษ์บางอย่าง
Structural diffing
- ในโค้ด คำว่า diff มักหมายถึง สรุปการเปลี่ยนแปลงแบบรายบรรทัด ระหว่างไฟล์สองเวอร์ชัน และในมุมมองแบบ unified จะใช้
+,-แทนการเพิ่มและลบ - diff เดียวกันสามารถเรนเดอร์แบบเทียบซ้ายขวาได้ด้วย และยิ่งการเปลี่ยนแปลงซับซ้อน รูปแบบนี้ก็อาจอ่านง่ายกว่า
- ปัญหาของ line-based diff คือมันไม่รับรู้โครงสร้างระดับบนอย่างฟังก์ชันหรือ type และถ้าวงเล็บปีกกาดันลงตัวพอดี ก็อาจละการแสดงผลไปทั้งที่จริงอยู่คนละฟังก์ชันกัน
- difftastic พยายามลดปัญหานี้ด้วย concrete syntax tree จาก treesitter แต่การจับคู่เอนทิตีข้ามเวอร์ชันไม่ได้แม่นเสมอไป
- ใน diff ที่เป็นจุดเริ่มต้นโดยตรงนั้น
struct PendingClickไม่ถูกจับคู่กันระหว่างสองฝั่ง ทำให้ฝั่งซ้ายถูกแสดงเป็นการลบ ส่วนฝั่งขวาถูกแสดงเป็นการเพิ่ม - ผู้เขียนไม่ได้ขุดลึกว่าทำไมการจับคู่ถึงล้มเหลว แต่ตัดสินใจว่าต่อให้ diff โดยรวมจะยาวขึ้น การเห็นว่า
PendingClickRequestและPendingClickสอดคล้องกันข้ามสองฝั่งก็ดีกว่า
เครื่องมือ structural diff และแหล่งอ้างอิง
- เครื่องมือ semantic diff ที่ผู้เขียนมองว่าสมบูรณ์และขัดเกลามารอบคอบที่สุดคือ semanticdiff.com
- ให้บริการโดยบริษัทเล็ก ๆ จากเยอรมนี มีปลั๊กอิน VSCode ฟรี และ เว็บแอป สำหรับดู GitHub PR diff
- แต่ไม่มีไลบรารีโค้ดที่นำไปเป็นฐานของ workflow ที่ต้องการได้
- บทความ semanticdiff vs. difftastic มีรายละเอียดมีประโยชน์มาก รวมถึงปัญหาที่ difftastic แสดง การเปลี่ยนแปลง indentation ที่มีความหมาย ใน Python ไม่ได้ด้วย
- หนึ่งในผู้เขียนระบุใน คอมเมนต์ HN ว่าเลิกใช้ treesitter สำหรับงานเชิงความหมาย เพราะ parsing ล้มเหลวจาก keyword ที่ขึ้นกับบริบทและพฤติกรรมของ lexer จนเครื่องมืออาจหยุดทำงานได้แม้ในกรณีที่ใช้ชื่ออย่าง
asyncเป็นพารามิเตอร์
- diffsitter เป็นเครื่องมือบนฐาน treesitter และมี MCP server มาด้วย
- แม้จะมี GitHub star จำนวนมาก แต่เอกสารดูไม่ค่อยดีนัก และหาเนื้อหาที่อธิบายวิธีทำงานได้ยาก
- ในวิกิของ difftastic ระบุว่าเครื่องมือนี้ทำ longest-common-subsequence บน leaf ของต้นไม้
- gumtree เป็นเครื่องมือที่มีที่มาจากงานวิจัยและวิชาการในปี 2014
- ต้องใช้ Java จึงไม่เหมาะกับการใช้งานส่วนตัวแบบต้องเรียกใช้เร็ว ๆ ใน Emacs
- mergiraf เป็น merge-driver บนฐาน treesitter ที่เขียนด้วย Rust
- architecture overview เรียบเรียงไว้ดี และภายในใช้ algorithm ของ Gumtree
- จากเอกสารและภาพประกอบ ให้ความรู้สึกว่าเป็นโปรเจ็กต์ที่ทำอย่างประณีต
- ผู้เขียน semanticdiff.com เขียนใน คอมเมนต์ HN ว่า GumTree ให้ผลเร็ว แต่ถึงจะเอาการปรับปรุงจากงานวิจัยภายหลังหลายชิ้นมาใช้ ก็ยังมีกรณีที่คืนค่าการจับคู่แย่ ๆ อยู่ไม่น้อย สุดท้ายจึงเปลี่ยนไปใช้ แนวทางบนฐาน dijkstra ที่ทำให้ต้นทุนการแมปต่ำที่สุด
- weave เป็น merge-driver บนฐาน treesitter อีกตัวที่เขียนด้วย Rust
- หน้าแลนดิ้งที่หวือหวา จำนวน GitHub star มาก และ MCP server ทำให้ภาพรวมดูค่อนข้างโอ้อวดอยู่บ้าง
- ผู้เขียนลองดู crate สำหรับดึงเอนทิตีชื่อ sem
- โค้ด diff หลักทำได้โอเคแต่ค่อนข้างเยิ่นเย้อ และการจับคู่เอนทิตีใช้ greedy algorithm
- data model ไม่สามารถตรวจจับการย้ายตำแหน่งภายในไฟล์ได้ ทั้งที่การย้ายแบบนี้อาจมีความหมายมาก
- ยังมี impact analysis เชิง heuristic อยู่มาก ซึ่งดูเหมือนต้องการการผสานกับภาษาในระดับที่ลึกกว่านี้หากจะให้เชื่อถือได้
- ตอนรัน
sem diff --verbose HEAD~4ก็ยังเจอบั๊กที่แสดงว่าบรรทัดที่ไม่ได้เปลี่ยนถูกเปลี่ยน
- ตอนรัน
- แม้จะมีฟีเจอร์ที่ดูเหมือนมีประโยชน์แต่ยังอยู่ในสภาพเหมือนเสร็จไปแค่ราว 80% มากเกินไปจนไม่เหมาะจะนำมาเป็นฐาน แต่ผู้เขียนก็ชื่นชมว่าทำได้ถึงระดับนี้ภายใน 3 เดือน
- diffast คำนวณ tree edit-distance ของ AST โดยอิงอัลกอริทึมจากงานวิชาการปี 2008
- รองรับ Python, Java, Verilog, Fortran และ C/C++ ผ่าน parser เฉพาะทาง
- example AST differences gallery จัดทำไว้ดีมาก
- สามารถส่งออกข้อมูลในรูป tuple เพื่อนำไปใช้กับ datalog ได้
- autochrome เป็นเครื่องมือ diff สำหรับ Clojure โดยเฉพาะ และใช้ dynamic programming
- คำอธิบายเชิงภาพและตัวอย่าง walkthrough ทำได้ดีมาก
- บทความ Designing a Tree Diff Algorithm Using Dynamic Programming and A* ของ Tristan Hume เป็นงานเขียนด้านการออกแบบ tree diff algorithm ที่ควรค่าแก่การอ้างอิง
Workflow ที่ต้องการและแผนขอบเขตขั้นต่ำ
- use case หลักคือ การรีวิวผลลัพธ์ LLM แบบทีละรอบ และผู้เขียนจะไม่ปล่อยให้ agent สร้างโค้ดเกินหมื่นบรรทัดในครั้งเดียวแบบไร้การควบคุม
- ผู้เขียนต้องการมอบงานที่มีขอบเขตชัดเจนให้ agent แล้วกลับมาดูภาพรวมการเปลี่ยนแปลงในอีกไม่กี่นาที จากนั้นค่อยแก้เองใน Emacs ทิ้งทั้งหมดแล้วลองใหม่ หรือเขียนใหม่เองตั้งแต่ต้น
- workflow ที่ต้องการคือการเห็น ภาพรวมระดับสูง ก่อนว่า type, function, method ไหนถูกเพิ่ม ลบ หรือแก้ไข
- จากนั้นควรจะกางดู text diff ของแต่ละเอนทิตีได้อย่างรวดเร็ว เพื่อให้ขยายจากสรุปไปสู่ diff รายละเอียดได้อย่างเป็นธรรมชาติ
- อีกทั้งควรแก้ไขการเปลี่ยนแปลงได้ตรงนั้นเลยโดยไม่ต้องย้ายไปที่อื่น และต้องการ inline editing โดยไม่ต้องสลับจากหน้าจอ diff ไปยังหน้าจอ file
- เป้าหมายคือย้าย workflow การตรวจทานและ staging การเปลี่ยนแปลงของ Magit จากหน่วยระดับไฟล์/บรรทัด ไปเป็นระดับเอนทิตี
- ให้สอดคล้องกับบทเรียนเรื่องขอบเขตขั้นต่ำที่เพิ่งนึกขึ้นได้อีกครั้ง ผู้เขียนจึงวางแผนจะรีบทำ เฟรมเวิร์กดึงเอนทิตีบนฐาน treesitter สำหรับ Rust เท่านั้นก่อน
- การจับคู่จะเริ่มจากวิธี greedy แบบง่าย ๆ และจะเรนเดอร์ diff ออกทาง command line ก่อน
- ถ้าระดับนี้ให้ผลดีกว่า difftastic สำหรับ commit เฉพาะจุดได้ ค่อยไปเชื่อมเข้ากับ workflow Emacs แบบโต้ตอบได้มากขึ้นอย่าง Magit ต่อไป
- หากเป็นไปได้ ก็ยังเปิดทางไว้สำหรับการนำ Magit เองกลับมาใช้ซ้ำ
- การรองรับภาษาใหม่จะค่อยเพิ่มเมื่อจำเป็น
- หลังจากนั้นอาจลองสำรวจ global matching แบบให้คะแนน แทน greedy ธรรมดา
- หากพอใจมากพอก็อาจเปิดเผยสู่สาธารณะ แต่เป้าหมายไม่ใช่การสะสม GitHub star หรือ HN karma และมันอาจคงเป็นเพียงเครื่องมือที่ใช้เงียบ ๆ คนเดียวต่อไป
- ตอนท้าย ผู้เขียนสรุปกลับไปที่แนวคิดว่า บางครั้งเราแค่ต้องการชั้นวางสักอันเท่านั้น เป็นการย้ำอีกครั้งถึง ท่าทีที่สร้างเท่าที่จำเป็นแทนการขยายเกินพอดี
1 ความคิดเห็น
ความเห็นจาก Hacker News
ผมว่ามันแสดงให้เห็นความยากที่ใหญ่ที่สุดของงานวิจัยระดับ PhDได้ดีมาก
พอหยิบหัวข้อที่น่าสนใจขึ้นมาแล้วพยายามอ่านงานก่อนหน้าให้ได้มากที่สุด ก็จะเริ่มตระหนักว่ามีคนทำสิ่งที่เรากำลังจะทำไปแล้วมากแค่ไหน จนทำให้เกิดscope creepได้ง่าย
หลังจากใช้พลังและความตื่นเต้นช่วงต้นไปหมดแล้ว ก็ต้องฝืนดันอีก 20~30% ที่เหลือให้ไปถึงจุดที่พร้อมตีพิมพ์ให้ได้
พอถึงวันที่ 400 กลับเกือบจะอธิบายทฤษฎีแห่งสรรพสิ่งครบแล้ว และกำลังจะสร้างอุปกรณ์ทดลองในวงโคจรจุดลากร็องจ์เพื่อตรวจจับอนุภาคสากลที่เป็นตัวกลางของแรงทั้งหมดในเอกภพที่รู้จัก
เลยสงสัยว่าควรทำอย่างไรถึงจะบรรเทาเรื่องนี้ได้
ในความเป็นจริงมันมักเป็นงานประเภทเพิ่มความสามารถในการสังเกตระบบจาก 1% เป็น 1.001% และใกล้เคียงกับด่านผ่านสำหรับเข้าสู่อาชีพสายวิชาการมากกว่า
เพราะงั้นแทบไม่ค่อยเห็นวิทยานิพนธ์ที่น่าสนใจจริง ๆ ใหม่มากจริง ๆ หรือเอาไปใช้กับวิทยาศาสตร์โดยตรงได้จริง
แทบไม่เคยเห็นใครทำวิจัยแบบนั้นจริง ๆ ปกติอ่านสักสองสามเปเปอร์แล้วค่อยต่อยอดจากตรงนั้นมากกว่า
การไล่อ่านวรรณกรรมวิจัยอย่างลึกจริง ๆ ควรทำหลังเริ่มมีผลลัพธ์ออกมาแล้ว และกำลังเริ่มเขียนสรุปงานมากกว่า
ประโยคที่ว่า ให้มันดีกว่าเดิมก็พอ ผุดขึ้นมาในหัวตลอด
การปรับปรุงเล็ก ๆ สะสมไปตามเวลาได้ และก็ไม่มีอะไรใหม่เอี่ยมสมบูรณ์แบบมาตั้งแต่ต้นอยู่แล้ว ดังนั้นการนั่งพยายามออกแบบให้สมบูรณ์แบบตั้งแต่แรกกลับให้ผลเสียมากกว่า
คำที่ว่าอุปสรรคนี่แหละคือเส้นทางก็ดูเข้ากับเรื่องนี้ดี
เพื่อนร่วมงานคนหนึ่งเวลาเขาวิจารณ์การเปลี่ยนโค้ด ถ้ารู้สึกว่าตัวเองกำลังจับผิดเรื่องเล็กเกินไป เขาจะพูดว่า "ดีกว่าเมื่อก่อน"
มันช่วยให้ยังชี้จุดที่ควรปรับปรุงได้ แต่ก็ให้ไฟเขียวไปพร้อมกันว่าถ้ามีตำหนิเล็กน้อยเหลืออยู่ก็เดินหน้าต่อได้ และผมเห็นด้วยกับท่าทีแบบนี้มาก
เมื่อก่อนผมคิดว่าความสมบูรณ์แบบนิยมคือการฝืนไล่ล่าความสำเร็จที่สูงเกินจริงเท่านั้น แต่การยอมรับอะไรที่ไม่สมบูรณ์แบบไม่ได้จนเลิกไปทั้งที่ยังไม่คืบหน้า ก็อาจเป็นความสมบูรณ์แบบนิยมได้เหมือนกัน
การผัดวันประกันพรุ่งกับงานใหญ่ ๆ ก็มักมีรากเดียวกัน
ผมชอบคำพูดของ CEO ของ Rec Room
เขาบอกว่าทีมมักพูดเสมอว่าอยากให้โปรเจ็กต์สั้นกว่านี้ แทบไม่เคยมีใครบอกว่าอยากเลื่อนเปิดตัวออกไปอีก ทำให้มันซับซ้อนขึ้น และขัดเกลาเพิ่มขึ้น
มันอาจไม่ถูกกับทุกสถานการณ์ 100% แต่ถ้าจะพลาด ผมว่าพลาดแบบทำให้เล็กแล้วปล่อยให้เร็วดีกว่าขยายใหญ่เกินไปจนเสียเวลา
มนุษย์มีธรรมชาติที่คิดไอเดียคล้าย ๆ กันได้ง่าย ดังนั้นถ้าทำโปรเจ็กต์จนเสร็จโดยไม่รู้มาก่อน สุดท้ายมันก็มักจะกลายเป็นการคิดขึ้นใหม่ซ้ำอยู่บ้าง
ในทางกลับกัน ถ้าไปสำรวจก่อนก็อาจพบว่าส่วนหนึ่งเป็นแค่การทำสิ่งที่มีอยู่แล้วซ้ำอีก จนหมดไฟได้
ถึงอย่างนั้น การทำมันให้จบเพื่อการเรียนรู้ของตัวเองอาจเป็นสิ่งที่สำคัญที่สุดอยู่ดี
แน่นอนว่าถ้าต้องสร้างผลงานวิชาการใหม่จริง ๆ หรือหารายได้จากโปรเจ็กต์ที่เป็นเอกลักษณ์จริง ๆ มันก็ยากกว่า แต่แม้แต่ในพื้นที่แบบนั้น แค่บิดของเดิมนิดหน่อยก็มักได้รับการยอมรับมากกว่าที่คิด
ตอนนี้ผมกำลังเจอสถานการณ์นี้กับside projectพอดี
สายงานคือ Information Retrieval เลยยังมีประสบการณ์ไม่มาก และแน่นอนว่ามี prior art จำนวนมากที่เรียนรู้หรือเอามารวมได้
เพราะงั้นพออ่านโพสต์นี้แล้ว ผมเลยเอนเอียงไปทางทำของตัวเองก่อน แล้วค่อยดูงานก่อนหน้าเฉพาะตอนที่ตันหรือต้องการไอเดีย
อีกด้านหนึ่ง ถ้าดูสารคดี Clojure ที่เพิ่งออกมา Rich Hickey ก็ดูเหมือนจะใช้เวลานานกับการลงลึกในงานก่อนหน้า เปเปอร์ และภาษาอื่น ๆ ก่อนจะลงมือทำ
แต่เขาเองก่อนหน้านั้นก็เคยสร้างภาษาอื่นมาแล้ว ดังนั้นภาพใหญ่ก็คือทุกอย่างเริ่มจากการเรียนรู้ผ่านการลงมือทำอยู่ดี
อาจจะต้องไม่คิดนานเกินไป ลองสร้างมันก่อน สะสมบทเรียนจากของจริง ชนกำแพงให้พอ แล้วค่อยทำการค้นคว้าเชิงลึกเมื่อจำเป็นมากกว่า
แล้วยิ่งไปดู "Easy made Simple", "Hammock Driven Development" ต่อ ก็ยิ่งอยากเรียน Clojure
Clojure documentary on CultRepo channel: https://www.youtube.com/watch?v=Y24vK_QDLFg
Simple Made Easy: https://www.youtube.com/watch?v=SxdOUGdseq4
Hammock Driven Development: https://www.youtube.com/watch?v=f84n5oFoZBc
การตั้งกำหนดส่งช่วยแก้ปัญหา scope creep ได้เกือบทั้งหมดสำหรับผม
จากประสบการณ์ โปรเจ็กต์ที่มีเดดไลน์แข็งแบบ game jam หรือการแข่งขันเขียนโปรแกรมจะทำให้จบได้ง่ายกว่า ในขณะที่โปรเจ็กต์ที่เปิดปลายไว้จบยากกว่ามาก
มันดูเป็นบริบทเดียวกับที่มาตรฐาน C++ ออกทุก 3 ปี ไม่ได้รอให้ทุกฟีเจอร์ที่อยากได้พร้อมครบก่อนค่อยปล่อย
https://news.ycombinator.com/item?id=20428703
บทความน่าสนใจดี แต่ความคิดของผู้เขียนดูกระจัดกระจายไปหน่อย
สำหรับคนที่บอกว่าตัวเองโดน scope creep ถล่ม ผมกลับรู้สึกว่าเจ้าตัวเป็นคนที่ทำอะไรได้เยอะมาก เพราะท้ายบทความยังมีลิงก์สารพัดหัวข้อเต็มไปหมด
สุดท้ายก็ดูเป็นคนประเภทที่ชอบเรียนรู้และลองไปเรื่อย ๆ จริง ๆ และกระบวนการหลุดลง rabbit hole นั่นเองก็น่าจะกระตุ้นสมองให้สนุก
ในฐานะคนทำคนเดียว ผมมีข้อสังเกตหนึ่งที่ช่วยได้มาก
สิ่งที่ดูเหมือนเป็นabstraction ที่จำเป็นส่วนใหญ่นั้น จริง ๆ แล้วเป็นแค่ scope creep ที่เปลี่ยนชื่อ
ผมเคยติด flag ให้ฟีเจอร์ใหม่ทุกตัว จนเริ่มเห็นแพตเทิร์นในโค้ดตัวเอง เลยตั้งกฎข้อหนึ่งขึ้นมา
คือจะไม่ปล่อยฟีเจอร์ถ้ายังไม่มีการทดสอบพฤติกรรมตอนปิด flag
พอทำแบบนั้น ผมก็เริ่มมองว่า flag ไม่ใช่ทางหนี แต่เป็นส่วนหนึ่งของผลิตภัณฑ์ และฟีเจอร์สามตัวในแบ็กล็อกก็หายไปเองตามธรรมชาติเมื่อเริ่มคิดแบบนี้
แม้การวางแผนมากเกินไปและ scope creep จะเป็นปัญหาจริง แต่ในทางกลับกันก็ต้องระวังไม่เหวี่ยงไปทางพัฒนาแบบสด ๆ ตามใจมากเกินไป
โปรเจ็กต์ที่ประสบความสำเร็จที่สุดบางชิ้นของผม เกิดจากการวางแผนและทบทวนฟีเจอร์ส่วนใหญ่ล่วงหน้าระหว่างทำโมเดลข้อมูล ก่อนจะเริ่มสร้างซอฟต์แวร์ที่ใช้งานได้จริง
ในขั้นนั้นมักยังไม่รู้ว่าอะไรเกินจำเป็น และถ้าตัดฟีเจอร์ที่ผมหรือผู้ใช้น่าจะต้องการออกไป สุดท้ายจะเสียเวลาเยอะมากกับการออกแบบแกนโค้ดใหม่ในภายหลัง
แต่ถ้าคิดพลาด โปรเจ็กต์ก็จะใหญ่เกินไปจนถูกเรียกว่า scope creep
สุดท้ายแล้วการตัดสินนี้ขึ้นอยู่กับว่าคุณเข้าใจโดเมนนั้นดีแค่ไหน
ถ้ารู้โดเมนน้อยกว่าที่คิด ก็ต้องรีเวิร์กเยอะ แต่ถ้ารู้โดเมนมากกว่าที่คิด ก็อาจจริง ๆ แล้วไปได้ไกลกว่านั้นแต่กลับเสียเวลากับ baby step
ไม่ว่าจะไปทางไหนก็มีความเสียดายเหลืออยู่ เลยรู้สึกว่าสุดท้ายมันเป็นปัญหาเรื่องการตัดสินใจอย่างมาก
อย่าตกหลุมsunk cost fallacy และต่อให้ใช้เวลาหลายชั่วโมงไปกับการค้นเรื่องระดับหัวข้อ PhD ก็ไม่ได้แปลว่าต้องเอามันมาใส่ในโปรเจ็กต์เสมอไป
ถ้ามันไม่ตรงกับปัญหาตอนนี้จริง ๆ ก็ควรตัดทิ้งอย่างกล้า ๆ