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

เราพูดถึง framework กันเยอะมาก ไม่ว่าจะเป็น React, Vue, Svelte หรืออะไรก็ตามที่จะเปิดตัวในสัปดาห์หน้า ต่างก็ดึงดูดความสนใจไปหมด งานคอนเฟอเรนซ์ถูกจองเต็มไปด้วยการประกาศเปิดตัว framework ใหม่ๆ บทความบล็อกต่างพากันวิเคราะห์ syntax sugar แต่ภายใต้เสียงรบกวนที่ผู้ใช้สัมผัสได้เหล่านั้น พื้นฐานกำลังเปลี่ยนไปในทางที่จะเปลี่ยนวิธีการเขียนโค้ดของคุณจริงๆ การปฏิวัติไม่ได้มาจาก frontend framework แต่มันกำลังเกิดขึ้นในเลเยอร์ของเครื่องมือ (tooling layer) และมันกำลังถูกเขียนขึ้นด้วย Rust และ Go

เป็นเวลาหลายปีที่เครื่องมือ JavaScript ถูกสร้างขึ้นด้วย JavaScript ซึ่งมันก็สมเหตุสมผล Babel สอนคนรุ่นหนึ่งให้รู้จักการเขียนไวยากรณ์ของวันพรุ่งนี้ตั้งแต่วันนี้ Webpack ช่วยรวมโค้ดที่แยกส่วนของเราให้กลายเป็นสิ่งที่เบราว์เซอร์สามารถประมวลผลได้ ESLint ช่วยตรวจจับบั๊กก่อนที่เราจะ commit โค้ด เครื่องมือเหล่านี้ถูกออกแบบมาเพื่อเว็บที่มีขนาดเล็กกว่า โดยสมมติว่ามีโมดูลเพียงไม่กี่ร้อย ไม่ใช่หมื่นโมดูล พวกมันสมมติถึงการใช้ repo เดี่ยว ไม่ใช่ monorepo ที่การเปลี่ยนแปลงใน shared UI package เพียงจุดเดียวจะส่งผลกระทบต่อเนื่องไปยังแอปพลิเคชันนับสิบ

จากนั้นแอปพลิเคชันก็เติบโตขึ้น codebase ขยายตัวกลายเป็น repository ขนาดมหึมา เครื่องมือยังคงเหมือนเดิม และความหน่วง (latency) ก็เริ่มแทรกซึมเข้ามา การทำ hot reload ที่เคยใช้เวลาสองวินาทีกลายเป็นสิบสองวินาที แล้วก็กลายเป็นสามสิบวินาที การรันชุดทดสอบ (test suite) ทั้งหมดก่อนพักเที่ยงกลายเป็นเรื่องเพ้อฝัน Linter เริ่มติดขัดกับไฟล์ที่มันเคยตรวจสอบมาแล้วเป็นพันครั้ง ทุกความล่าช้าอาจดูเล็กน้อยเมื่อดูในกระดาษ แต่ในทางปฏิบัติ ช่วงเวลาหยุดชะงักเหล่านี้ทำลายสมาธิ พวกมันฝึกให้คุณทำงานเป็นชุดๆ (batch) ทำให้คุณลังเลก่อนจะตรวจสอบว่าการแก้ไขนั้นได้ผลหรือไม่ และทำให้คุณหลีกเลี่ยงการทดลองสิ่งใหม่ๆ เพราะต้นทุนในการรอผลตอบรับนั้นสูงเกินไป

เครื่องมือยุคถัดไปจะเข้าจัดการกับความหน่วงนั้น โดยการถอยออกมาจาก JavaScript

ห้องเครื่องยุคใหม่

ลองดูว่างานเฉพาะด้านต่างๆ กำลังถูกทวงคืนมาได้อย่างไร

Transformation เคยหมายถึง Babel มันคือ preprocessor สากลที่แปล JSX และ stage-3 proposals ให้กลายเป็น ES5 ธรรมดา มันยังคงเป็นซอฟต์แวร์ที่น่าประทับใจ แต่มันคือ JavaScript แบบ single-threaded ที่กำลัง parse JavaScript จนกระทั่ง OXC เข้ามา ซึ่งเป็น toolchain ที่เขียนด้วย Rust มันจัดการงานแบบเดียวกับที่ Babel ทำ แต่ผลการทดสอบ (benchmarks) ระบุว่ามันเร็วกว่าประมาณ 40 เท่า ในขณะที่ใช้หน่วยความจำน้อยลงถึง 70% นี่ไม่ใช่การพัฒนาแบบทีละเล็กทีละน้อย แต่มันคือความแตกต่างระหว่างเครื่องมือที่คุณสังเกตเห็น กับเครื่องมือที่คุณแทบไม่รู้สึกเลยว่ามันกำลังทำงานอยู่

Bundling คือจุดที่ความเจ็บปวดรุนแรงที่สุด Webpack เป็นมาตรฐานมานานนับทศวรรษ แต่โครงสร้างภายในของมันถูกสร้างขึ้นเพื่อสเกลที่ต่างออกไป Turbopack ซึ่งเป็นตัวสืบทอดที่เขียนด้วย Rust ไม่ได้เพียงแค่คอมไพล์ได้เร็วขึ้นเท่านั้น แต่มันยังใช้การทำ memoization อย่างเข้มข้นเพื่อทำความเข้าใจว่ามีอะไรเปลี่ยนแปลงไปบ้าง และทำการ rebuild เฉพาะส่วนนั้นเท่านั้น ในแอปพลิเคชันขนาดใหญ่ การแก้ไขคอมโพเนนต์เพียงตัวเดียวไม่ควรทำให้คุณต้องเสียเวลาไปกับการไล่ตรวจสอบกราฟทั้งหมด (full graph traversal) ด้วย Turbopack การ build จะขยับเข้าใกล้ความรวดเร็วในระดับทันทีทันใด แถบแสดงความคืบหน้าจะหายไปเพราะไม่มีอะไรให้ต้องนั่งเฝ้า

Testing มีความล่าช้าในแบบของมันเอง Jest ได้สร้างนิยามใหม่ให้กับการทดสอบ JavaScript แต่ใน watch mode มันอาจให้ความรู้สึกเหมือนกำลังเรียนรู้ codebase ของคุณใหม่ในทุกๆ การกดปุ่ม Vitest ใช้แนวทางสถาปัตยกรรมที่ต่างออกไป เนื่องจากมันนำ module graph ของ Vite กลับมาใช้ใหม่แทนที่จะสร้าง dependency tree ของตัวเองขึ้นมาใหม่ทั้งหมด มันจึงรายงานความเร็วที่เร็วกว่า Jest ใน watch mode ประมาณ 8.5 เท่า ชัยชนะในที่นี้ไม่ใช่แค่เรื่องความเร็วเพียงอย่างเดียว แต่คือความสอดคล้อง (coherence) ในที่สุด test runner และ dev server ของคุณก็เห็นพ้องตรงกันว่าโปรเจกต์ของคุณมีหน้าตาเป็นอย่างไร

Linting ก็ประสบปัญหา overhead ที่คล้ายกัน ความยืดหยุ่นของ ESLint คือพลังพิเศษของมัน กฎต่างๆ ของมันเป็นเพียงฟังก์ชัน JavaScript ที่ทำงานบน AST ซึ่งความยืดหยุ่นนั้นต้องแลกมาด้วยรอบการประมวลผล (cycles) Oxlint ซึ่งเขียนด้วย Rust ได้จำกัดขอบเขตให้เหลือเพียงกรณีที่พบบ่อยและทำงานได้อย่างรวดเร็วปานสายฟ้า มันทำงานเร็วกว่า ESLint ระหว่าง 50 ถึง 100 เท่า ผลลัพธ์ในทางปฏิบัติคือการ lint ที่เสร็จสิ้นก่อนที่แอนิเมชันการบันทึกไฟล์ใน editor ของคุณจะทำงานเสร็จเสียอีก คุณจะไม่ต้องทนกับเส้นหยักสีแดงที่ค้างอยู่หลายวินาทีหลังจากที่คุณแก้ไขปัญหาไปเรียบร้อยแล้ว

การเปลี่ยนแปลงที่เป็นสัญลักษณ์ที่สุดอาจเกิดขึ้นในเรื่อง การตรวจสอบประเภท (type checking) ขณะนี้ Microsoft กำลังเขียนคอมไพเลอร์ของ TypeScript ใหม่ด้วยภาษา Go ผลการทดสอบเบื้องต้นนั้นน่าทึ่งมาก: VS Code โหลดเร็วขึ้นประมาณ 8 เท่าด้วยการปรับปรุงใหม่นี้ และการตรวจสอบประเภทเองก็เร็วขึ้นประมาณ 10 เท่า ลองพิจารณาดูว่านั่นหมายถึงอะไร TypeScript คือเรื่องราวความสำเร็จของ JavaScript มันคือภาษาที่คอมไพล์เป็น JavaScript ใช้เพื่อตรวจสอบประเภทของระบบนิเวศ JavaScript และตอนนี้คอมไพเลอร์ของมันเองกำลังย้ายไปสู่ภาษาสำหรับระบบ (native systems language) เพราะ JavaScript ไม่สามารถมอบประสิทธิภาพตามที่ระบบนิเวศต้องการได้ เครื่องมือนี้กำลังกัดกินเส้นทางของตัวเองเพื่อมุ่งสู่ความเร็ว

สิ่งเหล่านี้ไม่ได้มาแทนที่ React ไม่ได้ทำลาย Next.js หรือทำให้ TypeScript ล้าสมัย เฟรมเวิร์กยังคงเป็นตัวกำหนดโมเดลคอมโพเนนต์และการกำหนดเส้นทาง (routing) ของคุณ เครื่องมือใหม่เหล่านี้เพียงแค่ทำให้ทุกอย่างที่อยู่เบื้องหลังทำงานได้เร็วขึ้น พวกมันคือถนน ไม่ใช่รถยนต์

เมื่อความเร็วเปลี่ยนพฤติกรรม

บทสนทนาเรื่องเครื่องมือมักจะติดอยู่กับแผนภูมิการทดสอบประสิทธิภาพ (benchmark charts) ตัวเลขนั้นเปรียบเทียบได้ง่าย แต่ผลกระทบที่แท้จริงนั้นอยู่ที่พฤติกรรมของมนุษย์

เมื่อการตอบสนอง (feedback) ลดลงจากระดับวินาทีเหลือเพียงมิลลิวินาที คุณไม่ได้แค่ทำงานเสร็จเร็วขึ้นเท่านั้น แต่คุณจะทำงานในรูปแบบที่ต่างออกไป คุณจะหยุดสะสมการเปลี่ยนแปลงไว้ทีละเยอะๆ คุณเขียนโค้ดหนึ่งบรรทัด ดูผลลัพธ์ แล้วปรับปรุง คุณรันการทดสอบเพราะมันทำได้ทันที ไม่ใช่เพราะ pull request ของคุณบังคับให้ทำ คุณลองทำ refactor ที่อาจจะไม่สำเร็จก็ได้ เพราะการย้อนกลับ (undo) นั้นไม่มีต้นทุน คุณจดจ่ออยู่กับปัญหาแทนที่จะต้องมารอให้เครื่องจักรอนุญาตให้คุณกลับเข้าไปทำงานต่อ

นี่คือสิ่งที่นักจิตวิทยาเรียกว่า flow (สภาวะลื่นไหล) ซึ่งต้องอาศัยวงจรที่กระชับระหว่างการกระทำและผลลัพธ์ นักกีตาร์ไม่สามารถเล่นได้หากแอมป์ดีเลย์ทุกตัวโน้ต จิตรกรไม่สามารถผสมสีได้หากแปรงอัปเดตช้าไปครึ่งวินาที นักพัฒนาก็ไม่ต่างกัน ความหน่วง (latency) ไม่ใช่แค่ความน่ารำคาญ แต่มันคือภาษีที่ต้องจ่ายด้วยความคิด

ดังนั้น การเพิ่มผลิตภาพจึงไม่ใช่แค่เรื่องทางเทคนิค แต่เป็นเรื่องของความเคยชิน เครื่องมือที่เร็วจะฝึกให้คุณทดลอง เครื่องมือที่ช้าจะฝึกให้คุณลังเล เมื่อเวลาผ่านไปหนึ่งปี ความแตกต่างนี้จะสะสมจนกลายเป็นซอฟต์แวร์ที่ต่างกันอย่างสิ้นเชิง ทีมที่มีการตอบสนองทันทีจะส่งมอบงานได้อย่างมั่นใจมากขึ้น พวกเขาแบ่งงานออกเป็นชิ้นเล็กๆ เพราะต้นทุนในการทดลองนั้นเป็นศูนย์ การรีวิวโค้ด (code reviews) ของพวกเขาก็สั้นลงเพราะบั๊กถูกตรวจพบในทันที ไม่ใช่ใน CI อีกยี่สิบนาทีต่อมา

งานที่มองไม่เห็น

นี่คือเหตุผลที่พาดหัวข่าวต่างๆ มักทำให้เข้าใจผิด เฟรมเวิร์กนั้นเขียนถึงได้ง่าย พวกมันมีโลโก้ มี API และมีดราม่าใน Twitter แต่อินฟราสตรัคเจอร์ (infrastructure) ถูกออกแบบมาให้มองไม่เห็น คุณไม่ได้ตื่นมาด้วยความตื่นเต้นที่จะต้องตั้งค่า bundler คุณต้องการให้มันหายไปต่างหาก แต่การหายไปนี่แหละคือสิ่งที่อินฟราสตรัคเจอร์ที่ดีทำ มันแบกรับน้ำหนักเอาไว้เพื่อให้เลเยอร์ที่มองเห็นได้ยังคงความเบาบาง

หากคุณกำลังนำทีมหรือดูแลโค้ดเก่า (legacy codebase) สิ่งนี้ควรเป็นข้อมูลประกอบการจัดลำดับความสำคัญของคุณ การย้ายจาก React ไป Vue อาจเปลี่ยนโครงสร้างคอมโพเนนต์ของคุณ แต่การย้ายจาก Webpack ไป Turbopack หรือจาก Babel ไป OXC อาจเปลี่ยนรูปแบบการทำงานในแต่ละวันของคุณทั้งหมด เรื่องหลังนี้เป็นเรื่องที่นำเสนอต่อผู้บริหารได้ยากกว่า เพราะมันไม่มีเดโมหน้าโฮมเพจใหม่ๆ ให้ดู มีเพียงทีมงานที่เลิกถอนหายใจใส่หน้าจอ terminal ตอน build เท่านั้น

จงตรวจสอบว่าอะไรที่ทำให้คุณช้าลงจริงๆ หากคุณกำลังรัน monorepo สมัยใหม่บนชุดเครื่องมือ (toolchain) ที่สร้างขึ้นในปี 2015 คุณไม่ได้กำลังทำตัวระมัดระวัง แต่คุณกำลังจ่ายภาษีความฝืดเคืองในทุกๆ วัน วิธีแก้ไขไม่ใช่การเรียนรู้พาราไดม์ (paradigm) ของ frontend ใหม่ แต่คือการเปลี่ยนเครื่องยนต์

เฟรมเวิร์กจะยังคงมีออกมาเรื่อยๆ พวกมันจะยังคงได้รับทวีตและเป็นหัวข้อหลักในงานคอนเฟอเรนซ์ แต่การเปลี่ยนแปลงที่แท้จริงในความรู้สึกขณะเขียน JavaScript กำลังเกิดขึ้นภายใต้ฝากระโปรง ในภาษาคอมไพล์ที่มองว่าเวลาของคุณมีค่า นั่นคือการปฏิวัติ ไม่ใช่การหาวิธีใหม่ในการเรนเดอร์รายการ (list) แต่คือชุดเครื่องมือที่เร็วพอที่จะไม่มาขวางทางและปล่อยให้คุณได้ใช้ความคิด