การเดินทางสู่ TypeScript ของ Figma
(figma.com)การเดินทางสู่ TypeScript ของ Figma: คอมไพล์ภาษาการเขียนโปรแกรมแบบกำหนดเองให้หายไป
- Figma เคยเขียนส่วนสำคัญของสถาปัตยกรรมการเรนเดอร์บนมือถือด้วยภาษาการเขียนโปรแกรมแบบกำหนดเองที่ชื่อว่า Skew
- ภาษาแห่งนี้ถูกคิดค้นขึ้นเพื่อเพิ่มประสิทธิภาพในเครื่องยนต์การเรนเดอร์เพิ่มเติม
- บทความนี้แนะนำวิธีการย้ายจาก Skew ไปยัง TypeScript แบบอัตโนมัติ โดยไม่หยุดงานพัฒนานานแม้แต่วันเดียว
จุดเริ่มต้นและข้อจำกัดของภาษา Skew
- Skew เริ่มต้นเป็นโปรเจกต์เสริมในระยะแรกของ Figma
- ตอนนั้นจำเป็นต้องสร้างตัวดูตัวอย่างต้นแบบที่รองรับทั้งเว็บและมือถือได้อย่างรวดเร็ว
- และพัฒนากลายเป็นภาษาคอมไพล์ทั้งชุดเป็น JavaScript ที่ช่วยให้เกิดการปรับแต่งประสิทธิภาพที่สูงขึ้นและลดเวลาคอมไพล์ได้เร็วขึ้น
- เมื่อเวลาผ่านไปและโค้ด Skew สะสมมากขึ้น ข้อจำกัดก็เริ่มปรากฏชัด
- บุคคลใหม่อาจปรับตัวได้ยาก
- ไม่สามารถผสานเข้ากับ codebase อื่นๆ ได้ง่าย
- ขาด ecosystem ของนักพัฒนานอก Figma
- ความยากในการขยายมากขึ้นเรื่อยๆ จนเกินข้อดีเดิมของภาษา
ปัจจัยที่ทำให้การย้ายไป TypeScript เป็นไปได้
- การขยายการรองรับ WebAssembly ในเว็บเบราว์เซอร์มือถือ
- การแทนที่ส่วนประกอบสำคัญของเอนจิน Skew ด้วยส่วนประกอบที่สอดคล้องในเอนจิน C++
- ทำให้การย้ายไป TypeScript สูญเสียประสิทธิภาพน้อยลง
- การเติบโตของทีมทำให้สามารถจัดสรรทรัพยากรเพื่อโฟกัสที่ developer experience ได้
กระบวนการแปลง codebase
- เป้าหมาย: แปลงโค้ด Skew ทั้งหมดเป็น TypeScript
- เลือกใช้การย้ายแบบอัตโนมัติแทนการเขียนใหม่ด้วยมือ
- ป้องกันการชะลอความเร็วในการพัฒนา และป้องกัน runtime error และการลดประสิทธิภาพต่อผู้ใช้
- กระบวนการ rollout 3 ขั้นตอน
- เขียน Skew, build Skew
- รักษากระบวนการ build เดิม พัฒนา transpiler และเช็คอินโค้ด TS บน GitHub
- เขียน Skew, build TypeScript
- เริ่ม rollout production traffic โดยตรงจาก codebase TypeScript
- นักพัฒนายังคงเขียน Skew; transpiler จะแปลง Skew เป็น TS
- เขียน TypeScript, build TypeScript
- ทำให้ TS เป็น source of truth สำหรับการพัฒนา
- ตัดขั้นตอนการสร้างอัตโนมัติและลบโค้ด Skew ออกจาก codebase
- เขียน Skew, build Skew
หมายเหตุเกี่ยวกับงานของ transpiler
- คอมไพลเลอร์ประกอบด้วย front-end และ back-end
- Front-end: วิเคราะห์และทำความเข้าใจซินแทกซ์ของโค้ดต้นทาง ทำการตรวจสอบชนิดข้อมูล และตรวจสอบโครงสร้างประโยค
- แปลงเป็น IR (Intermediate Representation) เพื่อบันทึก semantics และ logic ของโค้ดต้นทางได้ครบถ้วน
- Back-end: แปลง IR เป็นภาษาเป้าหมายต่างๆ
- Transpiler คือคอมไพลเลอร์แบบพิเศษที่สร้างโค้ดที่มนุษย์อ่านได้
ปัญหาที่พบระหว่างการย้าย
- ประเด็นประสิทธิภาพของ array destructuring
- หากไม่ใช้ array destructuring ของ JavaScript สามารถเพิ่มประสิทธิภาพได้สูงสุดถึง 25%
- การปรับแต่ง "devirtualization" ของ Skew
- ระหว่าง rollout ทำเพิ่มขั้นตอนเพื่อให้แน่ใจว่า devirtualization จะไม่ทำให้พฤติกรรม codebase หยุดชะงัก
- ใน TypeScript ลำดับการ initialize มีความสำคัญ
- transpiler ต้องสร้างโค้ดที่เคารพลำดับนี้
ตัวอย่างการใช้ Source Map เพื่อเพิ่มคุณภาพ developer experience
- Figma มุ่งเน้นให้การย้ายนี้ทำได้ง่ายและช่วยให้ประสบการณ์ดีบักราบรื่นมากขึ้นสำหรับนักพัฒนา
- เชื่อมโค้ดที่คอมไพล์แล้วเข้ากับโค้ดต้นทางด้วย Source Map
- เบราว์เซอร์อ่านได้เฉพาะ JavaScript เท่านั้น
- Source Map ช่วยให้เบราว์เซอร์รู้ว่า breakpoint ใน source code ควรหยุดที่จุดใดใน JavaScript bundle ที่คอมไพล์แล้ว
- สร้าง Source Map ใน 3 ขั้นตอน
- สร้าง Source Map ระหว่าง TypeScript → JavaScript
- สร้าง Source Map ระหว่าง Skew → TypeScript สำหรับไฟล์ต้นทาง Skew ทุกไฟล์
- ประกอบ Source Map เพื่อสร้างการแมปจาก Skew ไปยัง JavaScript
ตัวอย่างการจัดการ conditional compilation
- ใน Skew อนุญาตให้คอมไพล์โค้ดเชิงเงื่อนไขด้วยคำสั่ง "if" ระดับบนสุด
- ใช้ค่าคงที่คอมไพล์เวลาในการกำหนดเงื่อนไข
- กำหนด build target ที่ต่างกันได้ภายใน codebase เดียวกัน
- TypeScript ไม่มีความสามารถ conditional compilation
- ย้ายการทำงานนี้ไปยังขั้นตอน bundling
- ใช้คุณสมบัติ "defines" และ dead code elimination ของ esbuild
- มีผลข้างเคียงคือขนาด bundle เพิ่มขึ้นเล็กน้อย
การพัฒนาโปรโตไทป์ในยุค TypeScript
- ด้วยการย้ายโค้ด Skew ไปยัง TypeScript ทำให้ codebase แกนหลักของ Figma มีความทันสมัยมากขึ้น
- เปิดทางให้ผสานกับโค้ดภายในและภายนอกได้ง่ายขึ้นมาก
- ทำให้นักพัฒนาสามารถทำงานได้มีประสิทธิภาพขึ้น
- ตอนนั้น TypeScript อาจยังไม่เหมาะสม แต่ปัจจุบันเป็นตัวเลือกที่เหมาะสมอย่างชัดเจน
- กำลังดำเนินงานตามขั้นต่อไปเพื่อรับประโยชน์จากการย้ายไป TypeScript อย่างครบถ้วน
- การผสานกับ codebase ส่วนที่เหลือ
- การจัดการแพ็กเกจที่ง่ายขึ้นมาก
- การใช้ความสามารถใหม่ๆ จาก ecosystem ของ TypeScript โดยตรง เป็นต้น
ความคิดเห็นของ GN⁺
-
Figma ดำเนินการเปลี่ยนจากภาษาการเขียนโปรแกรมแบบกำหนดเองอย่างเป็นระบบและค่อยเป็นค่อยไปไปยัง TypeScript อย่างมีโครงสร้างได้อย่างน่าประทับใจ โดยไม่หยุดการทำงานแม้แต่หนึ่งวันเพื่อย้ายจาก Skew เป็น TypeScript แบบอัตโนมัติ คิดว่าเป็นตัวอย่างที่ดีในการแก้ปัญหาหนี้เทคนิคที่เกิดขึ้นเมื่อองค์กรมีขนาดเพิ่มขึ้นและสอดคล้องกับการเปลี่ยนแปลงของ ecosystem ได้ดี
-
ในการเปลี่ยนจากภาษาที่เน้นประสิทธิภาพแบบกำหนดเองไปสู่ภาษาทั่วไป กระบวนการ WebAssembly ช่วยสร้างความสำคัญสูงสุด สิ่งนี้สะท้อนว่าในการเลือกเทคโนโลยี นอกจากความต้องการระยะสั้นแล้ว การพิจารณาความเร็วและทิศทางของวิวัฒนาการเทคโนโลยีก็สำคัญไม่แพ้กัน
-
การใช้ Source Map เพื่อให้คนทำงานมีประสบการณ์ดีขึ้น และการแก้ปัญหา conditional compilation เป็นแนวทางปฏิบัติที่มีคุณค่ามากในการใช้งานจริง ความสามารถในการย้ายแบบค่อยเป็นค่อยไปพร้อมคงความเข้ากันได้กับ legacy codebase เป็นสิ่งที่น่าประทับใจ
-
สำหรับการย้าย codebase ขนาดใหญ่แบบนี้ ดูเหมือนว่าการมี transpiler สำหรับแปลงโค้ดแบบอัตโนมัติจะเป็นสิ่งจำเป็น การใช้คอมไพเลอร์ Skew เพื่อพัฒนา transpiler น่าจะเป็นกุญแจสำคัญ และเป็นงานที่ต้องอาศัยความเชี่ยวชาญด้านทฤษฎีคอมไพลเลอร์และการออกแบบภายใน
-
การย้ายภาษาการเขียนโปรแกรมไม่ใช่แค่การแปลงโค้ด แต่ส่งผลกระทบเชิงลึกต่อวัฒนธรรมการพัฒนาและ ecosystem ทั้งระบบ มันอาจไม่ง่าย แต่ถ้าองค์กรมีขีดความสามารถ ก็อาจเป็นความท้าทายที่คุ้มค่าที่จะลองทำ
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
Andrew Chan ผู้มีส่วนร่วมในโปรเจกต์ระบุว่า Figma ใช้ TypeScript ในส่วนอื่นมานานเกือบ 10 ปี และในช่วงเวลาส่วนใหญ่ TypeScript มีมากกว่า Skew มาก โดย Skew ใช้เฉพาะในบางพื้นที่ของผลิตภัณฑ์ เช่น เอนจินมือถือ โปรโตไทป์เพลเยอร์ และฟังก์ชันการซิงค์ภาพ
ที่น่าทึ่งคือ Figma เคยมีภาษาที่กำหนดเองสำหรับ JavaScript และที่น่าทึ่งกว่านั้นคือมันเร็วกว่าการใช้ TypeScript มาก หลังจากนั้นจึงมีการย้ายมาใช้ TypeScript ซึ่งช้ากว่า
Evan Wallace (อดีต CTO ของ Figma) กล่าวว่า Skew เร็วกว่า TypeScript 1.5 ถึง 2 เท่า โดยอาศัยการปรับประสิทธิภาพที่ดีขึ้นซึ่งทำได้ด้วยระบบชนิดข้อมูลที่เคร่งครัดกว่า
สิ่งที่น่าสนใจคือ เมื่อทำการ destructuring อาร์เรย์ JavaScript จะสร้าง iterator ที่วนลูปอาร์เรย์แทนการใช้การเข้าถึง index โดยตรง ทำให้สงสัยว่าทำไม JavaScript ไม่ได้ดัชน่าตรงๆ จากอาร์เรย์
ดูเหมือนว่า Skew จะมีเพียง callback เท่านั้น และมีการกล่าวถึง async/await พร้อมระบบชนิดที่ยืดหยุ่นกว่า
Figma สร้าง TypeScript DSL และคอมไพเลอร์เฉพาะตัวเพื่อต้องแก้ปัญหาความปลอดภัย เช่น เรื่องสิทธิ์การเข้าถึง
บริษัทยักษ์ใหญ่แต่ละแห่งมีเครื่องมือภายใน ภาษา และ Kubernetes ของตัวเองที่ไม่ค่อยถูกแชร์กัน เสียดายถ้า Skew เปิดโอเพ่นซอร์สมากกว่านี้ อาจกลายเป็น TypeScript ที่ดีกว่า
อยากรู้จุดประสงค์ที่ทำให้ Figma ใช้ WebAssembly
บทเรียนที่ได้: อย่าสร้างภาษากำหนดเอง
ความคิดเห็นของผู้ที่คัดค้าน TypeScript เป็นเรื่องที่น่าสนใจมาก TypeScript เป็นเครื่องมือที่แทบไม่มีข้อเสียในการปรับปรุงโค้ดได้เกือบทุกบรรทัด ดูเหมือนว่าพวกเขากลัวการเรียนรู้สิ่งใหม่ ไม่ต้องการสละเวลา หรือเข้าใจประโยชน์ของมันผิด หากคุณเห็นด้วยกับการคัดค้าน TypeScript ต้องคิดให้ลึกเรื่องนั้นให้มากขึ้น ไม่เช่นนั้นก็อาจต้องรับความเสี่ยงที่รุนแรง