ปัญหาการนำไปใช้งานทางเลือก (Alternative Implementation Problem)
(pointersgonewild.com)- การนำไปใช้งานทางเลือก เช่น runtime ของภาษาและ JIT อาจมีประสิทธิภาพดี แต่การนำไปใช้จริงอาจถูกจำกัด เพราะต้องคอยตามการเปลี่ยนแปลงของ implementation หลักและความคาดหวังของผู้ใช้อยู่ตลอด
- PyPy, LuaJIT และ TruffleRuby แสดงให้เห็นประสิทธิภาพการรันที่รวดเร็ว แต่ ช่องว่างด้านความเข้ากันได้ และภาระในการติดตามฟีเจอร์ใหม่กลายเป็นอุปสรรคต่อการนำไปใช้ในงานจริง
- YJIT เลือกเส้นทางที่ไม่ได้เป็น implementation ของ Ruby แยกต่างหาก แต่เข้าไปอยู่ ภายใน CRuby ทำให้ตั้งแต่แรกสามารถเข้ากันได้ 100% กับฟีเจอร์ของ CRuby และถูกนำไปใช้ที่ Shopify, Discourse, GitHub และอื่น ๆ
- ทางเลือกแบบ Crystal ซึ่งคล้ายกับภาษาที่มีอยู่มากแต่ไม่ได้เข้ากันได้จริง อาจทำให้ผู้ใช้ต้องเผชิญกับความแตกต่างแบบ “เกือบเป็น Ruby แต่ไม่ใช่ Ruby” อยู่ตลอด
- ในพื้นที่ที่ มาตรฐานเปิด แยกออกจาก implementation เช่น JSON parser หรือ JavaScript ภาระของ implementation ทางเลือกจะลดลง แต่ใน ecosystem ที่ implementation หลักเป็นมาตรฐานโดยพฤตินัย จำเป็นต้องใช้กลยุทธ์อื่น
กับดักที่เกิดซ้ำของ implementation ทางเลือก
- ในโลกซอฟต์แวร์ มักเกิดซ้ำ ๆ ที่โปรเจกต์ซึ่งเริ่มต้นจาก implementation ทางเลือกที่ดีกว่า ของระบบเดิม กลับติดอยู่ใต้เงาของ implementation หลัก
- implementation ทางเลือกจะถูกเปรียบเทียบกับ canonical implementation ที่ได้รับการยอมรับเสมือนมาตรฐาน ทั้งในด้านฟีเจอร์ ประสิทธิภาพ ecosystem และความคาดหวังของผู้ใช้
- เมื่อ implementation หลักเปลี่ยนแปลงไปเรื่อย ๆ implementation ทางเลือกต้องใช้พลังงานจำนวนมากไปกับการตามการเปลี่ยนแปลงนั้น แทนที่จะกำหนดทิศทางของตัวเอง
- ในกรณีที่เพิ่ม JIT implementation ให้กับภาษาที่เดิมทีเป็น interpreter ฟีเจอร์ใหม่มักถูกใส่เข้าไปใน interpreter ได้เร็วกว่า ทำให้ภาระในการติดตามของฝั่ง JIT สูงขึ้น
รูปแบบที่เห็นจาก PyPy, LuaJIT และ TruffleRuby
- PyPy เป็น JIT compiler ขั้นสูงสำหรับ Python ที่สามารถเพิ่มความเร็วได้มากเมื่อเทียบกับ CPython แต่การใช้งานจริงมีน้อยมาก
- Python เป็น เป้าหมายที่เคลื่อนที่ตลอดเวลา เพราะมีเวอร์ชันและฟีเจอร์ใหม่ของ CPython ออกมาเป็นประจำ
- PyPy ประสบความยากลำบากในการตามให้ทัน จึงมักอยู่ในสถานะตามหลัง Python อยู่หลายเวอร์ชันเสมอ
- หากต้องการทำให้ซอฟต์แวร์ Python เข้ากันได้กับ PyPy ฟีเจอร์ของ Python ที่ใช้ได้จะถูกจำกัด และโปรแกรมเมอร์ Python ส่วนใหญ่ไม่อยากต้องใส่ใจกับเรื่องนี้
- LuaJIT ให้ประสิทธิภาพที่ดีขึ้นมากเมื่อเทียบกับ Lua implementation แบบ interpreter พื้นฐาน และได้รับการยกย่องสูงพร้อมกับการใช้งานจริงในระดับหนึ่ง
- Mike Pall ผู้สร้าง LuaJIT ถูกหลายคนประเมินว่าเป็นโปรแกรมเมอร์ที่ยอดเยี่ยม
- เมื่อภาษา Lua เพิ่มฟีเจอร์ใหม่อย่างต่อเนื่อง LuaJIT ก็ยังตามหลังอยู่หลายเวอร์ชัน
- ผู้ใช้ Lua บางส่วนจึงลังเลที่จะใช้ LuaJIT ด้วยเหตุนี้
- Lua เป็นภาษาที่ขึ้นชื่อเรื่องความมินิมัล แต่ก็ไม่ได้มีความพยายามในการชะลอการเพิ่มฟีเจอร์ใหม่หรือประสานงานกับ Mike Pall
- TruffleRuby ชูตัวเลขประสิทธิภาพที่น่าประทับใจที่สุดในบรรดา Ruby JIT แต่การนำไป deploy ยังจำกัด
- เหตุผลเชิงปฏิบัติอย่างหนึ่งคือ เวลา warm-up ของ TruffleRuby ยาวกว่า CRuby มาก
- เมื่อ CRuby เพิ่มฟีเจอร์อย่างต่อเนื่อง ผู้ร่วมพัฒนา TruffleRuby ก็ต้องพยายามตามให้ทัน
- ผู้ใช้ Ruby มองว่า CRuby คือ implementation หลัก และมองว่า implementation ที่ไม่เข้ากันได้อย่างสมบูรณ์มีคุณค่าน้อยในการพิจารณา
เส้นทางที่แตกต่างของ YJIT
- YJIT เริ่มต้นเป็น Ruby JIT อีกตัวหนึ่ง แต่ไม่ได้เป็น implementation แยกต่างหาก หากถูกสร้างขึ้น ภายใน CRuby เอง
- การเลือกนี้ทำให้เกิด trade-off หลายด้านในการออกแบบ แต่ก็ทำให้ YJIT เข้ากันได้ 100% กับฟีเจอร์ทั้งหมดของ CRuby ตั้งแต่เริ่มต้น
- ปัจจุบัน YJIT เป็น JIT “อย่างเป็นทางการ” ของ Ruby และถูก deploy ที่ Shopify, Discourse, GitHub และอื่น ๆ
- ผู้ใช้ที่เคยเข้า github.com หรือร้านค้า Shopify ก็เท่ากับเคยมีปฏิสัมพันธ์กับ YJIT แล้ว
- จนถึงตอนนี้ ในบรรดา Ruby JIT compiler ทั้งหมด YJIT ประสบความสำเร็จมากที่สุด และ ความเข้ากันได้ มีบทบาทสำคัญต่อความสำเร็จนั้น
แค่ “ถ้าชนะไม่ได้ ก็เข้าร่วม” ยังไม่พอ
- หากวางตำแหน่งตัวเองเป็น implementation ทางเลือก ก็มีโอกาสสูงที่จะต้องเล่นเกมไล่ตามอยู่ใต้เงาของ implementation หลักต่อไป
- เมื่อโปรเจกต์หลักวิวัฒนาการอย่างต่อเนื่อง implementation ทางเลือกต้องตามไปโดยมีอำนาจตัดสินใจจำกัดเกี่ยวกับทิศทางของโปรเจกต์ตัวเอง
- การเข้าร่วมกับ implementation หลักอาจให้ผลลัพธ์ที่ดีกว่า แต่ก็ไม่ได้แก้ได้ทุกกรณี
- Crystal ใน ecosystem ของ Ruby เป็นภาษาคอมไพล์แบบ static ที่มีไวยากรณ์คล้าย Ruby และใช้ type inference
- Crystal ตั้งใจไม่ตั้งเป้าความเข้ากันได้กับ Ruby และแยกออกมาจาก Ruby
- สำหรับ Rubyist มันดูเหมือนภาษา “เกือบเป็น Ruby แต่ไม่ใช่ Ruby อย่างสมบูรณ์” และในความเป็นจริงมีความแตกต่างเล็ก ๆ น้อย ๆ และความไม่เข้ากันได้จำนวนมาก
- ความคล้ายแบบนี้ทำให้ความคาดหวังของผู้ใช้สั่นคลอนและสร้างความสับสน
- Crystal อาจได้ผลลัพธ์ที่ดีกว่านี้ หากไม่ได้ทำการตลาดว่าคล้าย Ruby ตั้งแต่แรก
การเลือกหลีกเลี่ยงการแข่งขันและมีทิศทางของตัวเอง
- คำพูดของ Peter Thiel ที่ว่า “competition is for losers” ถูกใช้ในบริบทว่าอย่าพาตัวเองเข้าไปอยู่ในตำแหน่งที่ต้องแข่งขันโดยไม่จำเป็น
- สิ่งนี้นำไปสู่คำแนะนำว่า หากจะสร้างภาษาโปรแกรมใหม่ ก็ควรหลีกเลี่ยงการสร้างบางส่วนย่อยของ Python หรือสิ่งที่หน้าตาใกล้เคียงกับภาษาที่มีอยู่มากเกินไป
- หากสร้างสิ่งที่เป็นของตัวเอง ก็จะไม่ถูกผูกมัดด้วยความคาดหวังว่าต้องเทียบให้ได้กับประสิทธิภาพ ชุดฟีเจอร์ และ ecosystem ของไลบรารีจาก implementation อื่น และสามารถพัฒนาระบบด้วยจังหวะและทิศทางของตัวเองได้
- คำแนะนำนี้ใช้กับสถานการณ์ที่ภาษาหรือระบบมี canonical implementation อยู่
- พื้นที่ที่มีมาตรฐานเปิดอาจเป็นข้อยกเว้น
- JSON parser เป็นสิ่งที่มีสเปกชัดเจน ค่อนข้างเล็ก และไม่เปลี่ยนแปลงเร็ว จึงเป็นเป้าหมายที่สามารถทำ implementation เองได้
- JavaScript มี implementation หลายตัวที่อิงกับเบราว์เซอร์ ซึ่งเป็นไปได้เพราะมีองค์กรมาตรฐานภายนอกที่ดูแลสเปกของ JS
- ผู้ทำงานด้านมาตรฐาน JS เข้าใจว่า JIT compiler implementation สำคัญต่อประสิทธิภาพ และนำวิวัฒนาการของภาษาไปในทิศทางที่สอดคล้องกับเรื่องนั้น
- พวกเขาไม่ได้กำลังเล่นเกมเพิ่มฟีเจอร์ใหม่ให้มากที่สุดและเร็วที่สุดเท่าที่จะทำได้
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
มีประเด็นสำคัญอีกอย่างที่ OP พลาดไป เมื่อสร้าง การใช้งานทดแทน โดยทั่วไปสถาปัตยกรรมมักต่างจาก implementation อ้างอิง และสิ่งที่ทำได้ง่ายใน implementation อ้างอิง อาจยากมากใน implementation ของเรา
เช่น สมมติว่าซอฟต์แวร์ proprietary สำหรับรายงานทางการเงินบันทึกเอกสารเป็นรูปแบบไบนารีประหลาด ๆ ขณะทำทางเลือกฟรี เราเลือกโครงสร้างที่อ่านทั้งเอกสารเข้า memory และตอนบันทึกก็เขียนทั้งไฟล์ใหม่ทั้งหมด แต่ตัวต้นฉบับอาจถูกสร้างในยุคที่ RAM มีน้อย จึงอ่านและเขียนเฉพาะ section ที่ผู้ใช้กำลังทำงานอยู่ และอาจแก้ไขแบบ in-place ได้ด้วย
ต่อมาหากต้นฉบับเพิ่มฟีเจอร์ใส่ไฟล์แนบในเอกสาร ไฟล์ใหญ่ ๆ อย่างบันทึกเสียง investor call หรือ PDF สแกนหลายร้อยหน้าก็ยังทำงานได้ดีเพราะโหลดเป็นราย section ในทางกลับกัน implementation ของเราต้อง deserialize เอกสารทั้งฉบับ จึงเกิดปัญหาทันทีที่เอกสารใหญ่กว่า RAM ของผู้ใช้ และอาจต้อง ออกแบบซอฟต์แวร์ทั้งตัวใหม่ เพียงเพราะการเปลี่ยนแปลงที่ในต้นฉบับนักพัฒนาคนเดียวทำเสร็จได้ในหนึ่งสัปดาห์
ในทางกลับกัน ก็มีฟีเจอร์ที่ทำยากกว่าในต้นฉบับ แต่กลายเป็นเรื่องเล็กน้อยใน implementation ที่สอง การออกแบบใหม่ครั้งใหญ่มีแค่ครั้งเดียว และนั่นก็เกิดใน implementation ต้นฉบับที่มีสมมติฐานซึ่งทำให้เกิดการพุ่งโตแบบ exponential
ตัวอย่างสาธารณะคือปัญหาการรันแอปพลิเคชัน Windows บน Linux เคอร์เนล Linux เป็น implementation ที่แตกต่างจาก NT โดยสิ้นเชิง และไม่ได้มีเป้าหมายเรื่อง compatibility ด้วย แต่การรันแอป Windows ก็ไม่ได้ต้องออกแบบเคอร์เนลทั้งหมดใหม่ แค่มีฟีเจอร์เคอร์เนลที่ค่อนข้างทั่วไปไม่กี่อย่างกับ compatibility layer ใน user space ก็พอ Wine ต้องใช้ความพยายามมากในการเขียนและดูแลรักษา แต่น้อยกว่าการ implement Windows เองมาก และรันอยู่บนแพลตฟอร์มที่เดิมไม่ได้มุ่งให้ compatible กับ Windows อย่างไรก็ตาม อย่างที่บทความว่าไว้ คือต้องไล่ตาม Windows ต่อไปเรื่อย ๆ และยังเกิดโค้ดที่พึ่งพาบั๊กของ implementation อ้างอิงด้วย ดังนั้นถ้าจะ compatible แม้กระทั่งบั๊ก ก็ต้องค้นให้ได้ก่อนว่าต้อง implement บั๊กไหน
ดังนั้นโค้ดใด ๆ ก็สามารถแก้ไขสิ่งอื่นระหว่างรันได้ จริง ๆ ไม่ได้ใช้กันแบบนั้นมากนัก แต่ถ้าจะเอาออก ผู้คนก็จะโวยวาย implementation ที่ compile Python จริง ๆ ต้องรับมือแม้แต่กรณีที่ thread หนึ่งจู่ ๆ ไปเปลี่ยนอะไรบางอย่างใต้เท้าของอีก thread
นี่เป็นหนึ่งในวิธีที่บริษัทเล็กเพิ่มภาระให้บริษัทใหญ่ได้ และบริษัทที่ปล่อยหนี้เทคนิคน้อยกว่าก็ทำแบบนั้นได้เช่นกัน ยังเป็นช่วงเวลาที่หาได้ยากในการทำให้ผู้บริหารเห็นหนี้เทคนิคอย่างชัดเจน เพราะสามารถพูดได้ว่า “เราใช้เวลาทำฟีเจอร์นี้นานกว่า Acme”
เห็นด้วยกับข้ออ้างที่ว่า “อย่าพยายามสร้าง subset ของ Python” โปรเจกต์ที่ทำตลาดว่า “เหมือน Python แต่ X ดีกว่า” มักแข่งขันกับ implementation อ้างอิงได้ยากเสมอ โดยเฉพาะถ้า X คือความเร็ว คนที่ใช้ภาษา dynamic type สุดท้ายก็มักไม่ได้ใส่ใจความเร็วในการรันมากนัก
แต่ alternative implementation ไม่ได้ล้มเหลวเสมอไป MicroPython ดูเหมือนจะประสบความสำเร็จพอสมควร แม้แทบไม่รองรับเกินระดับ Python 3.4 เพราะมันถูกออกแบบให้รันบนไมโครคอนโทรลเลอร์ จึงไม่ได้แข่งขันกับ CPython แต่แข่งขันกับสภาพแวดล้อมการเขียนโปรแกรมไมโครคอนโทรลเลอร์อื่น ๆ
อย่างไรก็ตาม maintainers ของ MicroPython น่าจะได้รับคำขอฟีเจอร์ Python รุ่นใหม่ ๆ เยอะ ครั้งหนึ่งผมเคยคิดถึง alternative implementation ของ Python ที่เบาและเน้น embedding สำหรับฝังในแอปพลิเคชัน ซึ่งกรณีนั้นก็ตั้งใจจะแข่งกับ Lua ไม่ใช่ CPython แต่คำขอฟีเจอร์อันดับหนึ่งคือ “รองรับ NumPy ไหม?”
ในเวลาเดียวกัน ฝั่ง CPython เองก็ดูเหมือนกำลังมีงานเพื่อให้ทำงานบน frontend ได้ดีขึ้น และจุดเจ็บหลักคือ ขนาดแพ็กเกจ
ได้เรียนรู้อะไรคล้าย ๆ กันตอนสร้างสตาร์ทอัพ ถ้าทำใหม่ ผมคงหลีกเลี่ยง ฟีเจอร์ค่าตั๋วขั้นต่ำเพื่อเข้าตลาด ในสาขาของเราอย่างแข็งขัน
แทนที่จะทำแบบนั้น เราควรสร้างเพียงเท่าที่จำเป็นเพื่อให้มั่นใจว่าสถาปัตยกรรมของเรารองรับข้อกำหนดแบบ enterprise ได้ แล้วทุ่มทั้งหมดไปที่จุดต่างที่ทำให้คนตอบว่า “อ๋อ เห็นแล้วว่านี่ไปได้ไกลแค่ไหน” ไม่ใช่ฟีเจอร์ที่ทำให้ได้คำตอบว่า “ก็แค่ clone ของ X นี่”
กลยุทธ์ที่พูดถึงใกล้เคียงกับการ implement ฟีเจอร์พื้นฐานที่จำเป็น แต่ไม่ลงลึกไปถึงฟีเจอร์ขยาย “ทั่วไป” หลังจากนั้น ทำให้ผู้คนติดต่อกลับมาเพราะฟีเจอร์ที่น่าสนใจ และในขณะเดียวกันก็มีฟีเจอร์พื้นฐานครบพอไม่ให้ถูกคัดออกเพราะขาดองค์ประกอบจำเป็น
รู้สึกคล้ายกันกับ โค้ด wrapper ทั้งหมด บางครั้งมีคนพูดว่า “เราต้องการเวอร์ชันภายในของ API นี้”
เหตุผลมีได้หลายอย่าง แต่ก็มักเป็นทำนองว่า “ไว้ใจไม่ได้ว่าจะใช้ API ทางการอย่างถูกต้อง” มันอาจเป็นแบบนั้นได้ แต่เวอร์ชันภายในมักมีมาตรฐานน้อยกว่าและเอกสารก็แย่กว่า
บางครั้งเหตุผลคือ “ต้องการฟีเจอร์เพิ่มเติม” ซึ่งถ้าเป็นอย่างนั้นก็ไม่ควรห่อ API ทั้งชุด แค่เพิ่มฟังก์ชัน 3 ตัวก็พอ เมื่อเวลาผ่านไป 99% ของ codebase อาจกลายเป็น polyfill ได้
ประเด็นคือ ถ้าไม่ใช้ค่าเริ่มต้นมาตรฐาน คนที่มารับช่วง codebase ต่อในภายหลังจะต้องเจ็บปวดมาก
เช่น ไลบรารี ziggy-pydust สำหรับเขียน Python native module ด้วย Zig นั้นดูดีกว่าการ import
Python.hแบบทั่วไปอย่างชัดเจน ถึงอย่างนั้นก็ยังมี.ffiสำหรับเข้าถึงฟังก์ชันที่ยังไม่ได้ implement แต่มีอยู่ในPython.hได้โดยตรงถ้าไม่มีตัวเลือกแบบนี้ ปกติแล้วก็จะเลิกใช้ไลบรารีแบบนั้นและเลือกใช้ต้นฉบับแทน อย่างไรก็ดี ในความหมายหนึ่งนี่ก็เป็น wrapper เช่นกัน คือเป็น native module และเพื่อความเร็วในการพัฒนา บางครั้งการใช้ ctypes โดยตรงอาจดีกว่า
เป็นบทความที่ดีและมีบทเรียนยอดเยี่ยมมากมาย แต่ยังขาดส่วนประกอบสำคัญไปหนึ่งอย่าง เรื่องนี้คล้ายกับทางเลือกคู่แข่งของผลิตภัณฑ์ใด ๆ
มันคล้ายกับการพูดว่า Amazon ล้มเหลวเพราะไม่มีร้านหนังสือออฟไลน์แบบที่ผู้คนคุ้นเคย แต่จริง ๆ แล้วไม่ได้เป็นเช่นนั้น
เหตุผลที่ทางเลือก JIT เหล่านี้ล้มเหลวและเอาแต่ไล่ตามอยู่ตลอด คือในทางปฏิบัติแล้ว นักพัฒนาภาษา X ส่วนใหญ่ไม่ได้ให้ความสำคัญกับ JIT มากนัก พูดให้แม่นกว่านั้นคือพวกเขาให้ความสำคัญกับฟีเจอร์ของภาษาและ interoperability มากกว่า JIT
ดังนั้นผลิตภัณฑ์ที่ “เข้าร่วม” มากกว่าจะแข่งขันจึงชนะ เพราะไม่สามารถให้ความเสถียรหรือ interoperability ที่ดีกว่าได้
ผมทำงานกับภาษาและคอมไพเลอร์มานาน และบทความนี้สนุกมาก ถ้าพูดแนวคิดเดียวกันอีกแบบ ภาษานั้นเป็นอะไรที่มากกว่าแค่ ความเร็วในการคอมไพล์ อย่างมาก
ความเร็วในการคอมไพล์สำคัญมาก และแน่นอนว่าอยู่ใน 10 มิติสำคัญแรก ๆ โดยเฉพาะเมื่อเพิ่มความเร็วในการคอมไพล์ได้ ก็จะทำให้ feedback loop ของนักพัฒนาเร็วขึ้น และทีมหลักก็สามารถปรับปรุงมิติอื่น ๆ ทั้งหมดได้เร็วขึ้นด้วย
ถึงอย่างนั้น ภาษาโปรแกรมมิงยังมีมิติที่สำคัญมากอีกกว่า 30 ด้าน
ข้อสรุปเกี่ยวกับวิธีที่โปรเจกต์แบบนี้จะประสบความสำเร็จนั้นดี แต่ยังมีปัจจัยที่ถูกพูดถึงน้อยไปว่าทำไมหลายโปรเจกต์ถึงไม่ดังขึ้นมา นั่นคือ compatibility ของ implementation ทางเลือกมักต่ำกว่าที่กล่าวอ้างในทางปฏิบัติ และเป็นแบบนั้นแม้กับฟีเจอร์ภาษาเก่า ๆ
ตัวอย่างเช่น แอป Ruby และ Python มักมี native C extension อยู่สักแห่งใน dependency ซึ่งเท่าที่รู้ implementation ทางเลือกหลัก ๆ ไม่เคยรองรับสิ่งนี้ เคยมีความพยายามแล้ว แต่ก็ไปได้ไม่ดีด้วยเหตุผลทางเทคนิคที่ชัดเจน และทางเลือกที่คาดหวังให้ไลบรารีต่าง ๆ จัดเตรียมหลาย implementation ก็มีประวัติที่ไม่ราบรื่นนัก
เมื่อรวมกับข้อเท็จจริงที่ว่าภาษาเหล่านี้มักถูกใช้กับเว็บไซต์ CRUD ซึ่ง I/O เป็นปัจจัยด้านประสิทธิภาพที่ใหญ่กว่า CPU เสน่ห์ของทางเลือกที่เร็วกว่าเลยลดลงไปมาก
เป็นบทความที่ยอดเยี่ยมจริง ๆ สังคมวิทยาของเทคโนโลยี น่าสนใจมาก
ผู้ดูแล implementation ของภาษาต้องการความยืดหยุ่นสูงสุดในการออกแบบและปล่อยฟีเจอร์ใหม่ที่เป็นประโยชน์ต่อผู้ใช้ พวกเขาไม่อยากถูกถ่วงเพราะต้องได้รับฉันทามติจากหลาย implementation ก่อนปล่อยฟีเจอร์ ดูตัวอย่างได้จากการพัฒนา JavaScript ที่รู้สึกช้าเหมือนธารน้ำแข็งมาหลายปี และ TypeScript ที่วิวัฒนาการได้เร็วกว่าเมื่อเทียบกัน
ขณะเดียวกัน implementation ทางเลือกก็อาจเป็นสัญญาณว่าระบบนิเวศของภาษานั้นแข็งแรง จึงมีข้อดีเช่นกัน ถ้า implementation ทางเลือกนั้นดีจริง ๆ แม้จะดีเฉพาะกับผู้ใช้ที่มีความต้องการเฉพาะกลุ่มบางส่วน ก็สามารถเพิ่มคุณค่าจริงให้กับระบบนิเวศได้
ดังนั้นถ้าคุณเป็นผู้ออกแบบภาษาหรือผู้ดูแล ก็อาจไม่ได้เป็นศัตรูกับ implementation ทางเลือกอย่างแข็งขัน แต่ก็มีข้อเสียอยู่ โดยทั่วไป feedback จากผู้ใช้จะมาในทิศทางให้ปล่อยฟีเจอร์ใหม่และพัฒนาภาษา ไม่ค่อยมีคนขอให้ชะลอความเร็วเพื่อให้ PyPy, IronRuby, LuaJIT ฯลฯ ตามทัน
เมื่อผู้ใช้ภาษาเลือกว่าจะสร้างบน implementation ใด ลำดับความสำคัญสูงสุดมักเป็นความปลอดภัยและความเสถียร ไม่มีใครอยากให้ codebase หนึ่งล้านบรรทัดไปพึ่งพาลักษณะพฤติกรรมละเอียดอ่อนของ implementation ทางเลือกที่ครั้งหนึ่งนักศึกษาปริญญาเอกที่ฉลาดมากสร้างไว้ แต่ตอนนี้ย้ายไปทำโปรเจกต์อื่นแล้ว ดังนั้นผู้ใช้จึงไหลไปหา implementation ที่ใช้กันมากที่สุด และข้อเท็จจริงนั้นก็สร้าง วงจรป้อนกลับเชิงบวก ที่แข็งแรง ดึงดูดผู้ใช้คนอื่นเข้ามาอีก
ผลก็คือ หากไม่มีแรงผลักดันที่แข็งแกร่งในทิศทางตรงข้าม ภาษาส่วนใหญ่จะลู่เข้าหา implementation อ้างอิงเพียงหนึ่งเดียว จะเถียงว่านี่เป็นเรื่องดีก็ได้ เพราะความพยายามด้านวิศวกรรมเกือบทั้งหมดที่ทุ่มให้ implementation ของภาษาไม่ถูกแบ่งกระจายไปหลาย implementation แต่เป็นประโยชน์ต่อผู้ใช้ทุกคน แน่นอนว่าข้อเสียคือ implementation อาจติดอยู่ใน local optimum ได้
มีการกล่าวถึง LuaJIT แต่ก็เป็นตัวอย่างว่าผลลัพธ์ไม่ได้เป็นไปตามข้อสรุปของบทความเสมอไป ผู้คนและโปรเจกต์จำนวนมากตั้งใจเลือก LuaJIT แทน Lua
luajittexก็หาได้ง่ายควบคู่กับluatexอาจเป็นความคิดที่ไม่ค่อยเป็นที่นิยม แต่ผู้คนควรตรวจสอบ อัตตา ของตัวเองเป็นครั้งคราว รวมถึงตัวเองด้วย การสร้างโปรเจกต์คู่ขนานที่เป็น “ของฉัน” อาจง่ายกว่าการมีส่วนร่วมกับโปรเจกต์โอเพนซอร์สที่มีอยู่เดิม แต่ควรถามว่าทำไปเพื่อใคร
เพื่อผู้ดูแลโปรเจกต์ เพื่อโปรเจกต์เอง เพื่อผู้ใช้ หรือเพื่ออัตตาของตัวเอง หากโกรธกับข้อสุดท้าย ก็มีแนวโน้มว่าน่าจะเกี่ยวข้องอยู่
การเพิ่ม JIT ให้กับภาษาที่มีอยู่เป็นงานใหญ่ ดังนั้นเกณฑ์ที่ implementation หลักจะยอมรับก็คงสูงเช่นกัน ถึงอย่างนั้น ผมคิดว่าเป้าหมายควรเป็นทางนั้น การ fork หรือสร้างใหม่ก็ให้เสรีภาพในการทำงานใหญ่ได้เช่นกัน แต่บ่อยครั้งควรมองว่าเป็นสิ่งชั่วคราว
หากเป้าหมายคือการแสดงให้เห็นว่าฉันทำอะไรได้บ้าง ก็มีแนวโน้มว่าจะไปได้ไม่ไกล หากเป้าหมายคือการสร้างสิ่งที่ดีกว่า ก็จะได้เรียนรู้วิธีทำงานภายใต้ข้อจำกัดของผู้อื่น
ผมคิดว่าบทความนี้แสดงให้เห็นว่า Python, Lua, Ruby เลือกแนวทางแบบนั้นจนทำให้คนจำนวนมากผิดหวังอย่างไร ผลลัพธ์คือ นักพัฒนาหลายพันคนและผู้ใช้นับล้านต้องยอมรับการพัฒนาและซอฟต์แวร์ที่ช้าลง ไม่ใช่เพราะเป็นไปไม่ได้ แต่เพราะในเชิงบริหารไม่มีแรงจูงใจให้ทำเช่นนั้น