5 điểm bởi GN⁺ 2024-05-05 | 1 bình luận | Chia sẻ qua WhatsApp

Hành trình của Figma đến TypeScript: biên dịch để loại bỏ ngôn ngữ lập trình tùy chỉnh

  • Figma đã phát triển các phần cốt lõi của kiến trúc render trên thiết bị di động bằng một ngôn ngữ lập trình tùy chỉnh tên là Skew
    • Ngôn ngữ được tạo ra để đạt thêm hiệu năng trong engine render
    • Giới thiệu cách di chuyển tự động Skew sang TypeScript mà không gián đoạn một ngày làm việc nào

Sự bắt đầu và giới hạn của ngôn ngữ Skew

  • Skew bắt đầu như một dự án phụ trong giai đoạn đầu của Figma
    • Khi đó có nhu cầu nhanh chóng xây dựng một trình xem trước mẫu hoạt động trên cả web lẫn mobile
    • Trở thành ngôn ngữ lập trình biên dịch toàn phần JavaScript, giúp tối ưu hóa sâu hơn và thời gian compile nhanh hơn
  • Khi thời gian trôi qua và mã Skew ngày càng tích lũy, các giới hạn dần bộc lộ
    • Người mới vào việc khó thích nghi
    • Khó tích hợp dễ dàng với phần còn lại của codebase
    • Hệ sinh thái nhà phát triển bên ngoài Figma còn thiếu
    • Khó mở rộng bắt đầu vượt trội hơn lợi thế ban đầu

Các yếu tố giúp di chuyển sang TypeScript

  • Hỗ trợ WebAssembly ngày càng mở rộng trên trình duyệt di động
  • Thay thế các thành phần cốt lõi của Skew engine bằng thành phần tương ứng của C++ engine
    • Việc chuyển sang TypeScript gây ít tổn thất hiệu năng hơn
  • Khi đội ngũ phát triển lớn mạnh, có thể phân bổ nguồn lực để tập trung vào trải nghiệm nhà phát triển

Quy trình chuyển đổi codebase

  • Mục tiêu: chuyển toàn bộ mã Skew sang TypeScript
    • Chọn phương án di chuyển tự động thay vì viết lại thủ công
    • Ngăn chặn tốc độ phát triển chậm lại và lỗi runtime/giảm hiệu năng mà người dùng gặp phải
  • Quy trình rollout 3 giai đoạn
    1. Viết Skew, build bằng Skew
      • Giữ nguyên quy trình build ban đầu, phát triển transpiler, commit mã TypeScript lên GitHub
    2. Viết Skew, build bằng TypeScript
      • Bắt đầu triển khai production traffic trực tiếp từ codebase TypeScript
      • Nhà phát triển vẫn viết Skew, transpiler chuyển đổi Skew sang TS
    3. Viết TypeScript, build TypeScript
      • Biến TypeScript thành nguồn sự thật cho việc phát triển
      • Chặn quá trình tạo mã tự động và xóa mã Skew khỏi codebase

Lưu ý về công việc transpiler

  • Compiler gồm frontend và backend
    • Frontend: phân tích cú pháp đầu vào và hiểu code, kiểm tra type, kiểm tra cú pháp
    • Chuyển sang IR (biểu diễn trung gian) để giữ trọn ngữ nghĩa và logic của code gốc
    • Backend: chuyển IR sang nhiều ngôn ngữ khác nhau
  • Transpiler là một loại compiler đặc biệt tạo ra mã dễ đọc cho con người

Các vấn đề gặp phải trong quá trình di chuyển

  • Vấn đề hiệu năng của array destructuring
    • Nếu không dùng array destructuring của JavaScript có thể cải thiện hiệu năng tới 25%
  • Tối ưu hóa "devirtualization" của Skew
    • Trong quá trình rollout, thêm bước để devirtualization không làm vỡ hành vi hoạt động của codebase
  • Ở TypeScript, thứ tự khởi tạo rất quan trọng
    • Transpiler cần tạo ra mã tôn trọng đúng thứ tự này

Trải nghiệm nhà phát triển với Source Map

  • Tập trung vào việc giúp migration dễ dàng hơn và đảm bảo trải nghiệm debug mượt mà
  • Liên kết mã đã biên dịch với mã nguồn thông qua source map
    • Trình duyệt chỉ hiểu JavaScript
    • Nhờ source map, trình duyệt biết nơi đặt breakpoint trong code được biên dịch từ JavaScript bundle
  • Tạo source map theo quy trình 3 giai đoạn
    1. Tạo source map từ TypeScript → JavaScript
    2. Tạo Skew → TypeScript source map cho từng file nguồn Skew
    3. Kết hợp source map để tạo mapping từ Skew sang JavaScript

Ví dụ xử lý conditional compilation

  • Trong Skew, cho phép biên dịch có điều kiện bằng câu lệnh "if" cấp cao
    • Dùng hằng số thời gian biên dịch để xác định điều kiện
    • Cho phép định nghĩa các build target khác nhau trong cùng codebase
  • TypeScript không có conditional compilation
    • Chuyển sang xử lý tại giai đoạn bundling
    • Dùng tính năng "defines" và dead code elimination của esbuild
    • Gây ra tác dụng phụ là bundle size tăng nhẹ

Prototyping thời đại TypeScript

  • Nhờ chuyển mã Skew sang TypeScript, codebase cốt lõi của Figma đã được hiện đại hóa
    • Mở ra con đường tích hợp dễ dàng hơn nhiều với cả mã nội bộ và bên ngoài
    • Giúp nhà phát triển làm việc hiệu quả hơn
  • Khi đó TypeScript chưa phù hợp, nhưng hiện tại đã trở thành lựa chọn rõ ràng
  • Tiếp tục các công việc kế tiếp để tận dụng toàn bộ lợi ích của việc chuyển sang TypeScript
    • Tích hợp với phần còn lại của codebase
    • Quản lý package trở nên dễ dàng hơn
    • Sử dụng trực tiếp các tính năng mới trong hệ sinh thái TypeScript

Ý kiến của GN⁺

  • Figma đã chuyển đổi từ ngôn ngữ lập trình tùy chỉnh Skew sang TypeScript theo cách rất có hệ thống và theo từng giai đoạn. Việc họ thực hiện migration tự động mà không gián đoạn phát triển trong cả một ngày là rất ấn tượng. Đây là một ví dụ tốt cho việc xử lý technical debt khi quy mô công ty tăng và phù hợp với biến động của hệ sinh thái.

  • Trong hành trình chuyển từ ngôn ngữ hướng tối ưu hiệu năng sang ngôn ngữ phổ dụng, sự thay đổi môi trường công nghệ như sự xuất hiện của WebAssembly đóng vai trò quan trọng. Việc lựa chọn công nghệ không chỉ phụ thuộc nhu cầu trước mắt mà còn cần cân nhắc tốc độ và hướng phát triển kỹ thuật.

  • Các cách làm về source map để tối ưu trải nghiệm nhà phát triển, xử lý conditional compilation được trình bày rất hữu ích cho công việc thực tế. Việc giữ tương thích với legacy trong khi migration dần dần là rất ấn tượng.

  • Với mã cơ sở quy mô lớn như vậy, việc xây dựng bộ chuyển đổi mã tự động gần như bắt buộc cho cuộc di chuyển này. Dường như phần lõi đã nằm ở việc phát triển transpiler trên nền compiler của Skew. Đây là công việc đòi hỏi chuyên môn sâu về lý thuyết compiler và triển khai nội bộ.

  • Chuyển ngôn ngữ lập trình không chỉ ảnh hưởng ở mức đổi mã; nó còn tạo thay đổi tích cực cho văn hóa phát triển và hệ sinh thái rộng hơn. Cần tiếp cận thận trọng, nhưng nếu tổ chức có năng lực đủ thì đây là thử thách xứng đáng để làm.

1 bình luận

 
GN⁺ 2024-05-05
Ý kiến trên Hacker News
  • Theo lời của Andrew Chan, một thành viên tham gia dự án, Figma đã dùng TypeScript trong một số phần trong gần 10 năm và trong hầu hết thời gian đó TypeScript được dùng nhiều hơn Skew. Skew được dùng trong một vài mảng sản phẩm như động cơ di động, trình phát tạo mẫu và tính năng mirror.

  • Điều gây ngạc nhiên là Figma từng có một ngôn ngữ riêng cho JS, và đáng ngạc nhiên hơn là nó nhanh hơn TS. Sau đó lại chuyển sang TS, dù TS chậm hơn.

  • Theo Evan Wallace, cựu CTO của Figma, Skew nhanh hơn TypeScript khoảng 1,5 đến 2 lần nhờ tối ưu hóa tốt hơn mà một hệ thống kiểu chặt chẽ hơn cho phép.

  • Điều thú vị là khi destructuring mảng, thay vì JS lập chỉ mục trực tiếp trên mảng, nó lại tạo iterator lặp qua mảng. Tôi tò mò tại sao JS không truy cập trực tiếp chỉ số của mảng.

  • Skew dường như chỉ có callback. Người ta nhắc đến các tính năng JavaScript hiện đại như async/await và hệ thống kiểu linh hoạt hơn.

  • Figma đã viết một DSL TypeScript tùy chỉnh và trình biên dịch để giải quyết các vấn đề bảo mật như quyền truy cập.

  • Tội nghiệp là mỗi tập đoàn có các công cụ, ngôn ngữ nội bộ và Kubernetes riêng nhưng lại không chia sẻ với nhau. Nếu Skew đã là mã nguồn mở, có lẽ đã trở thành TypeScript tốt hơn.

  • Tôi tò mò về động lực khiến Figma dùng WebAssembly.

  • Bài học rút ra: Đừng tạo ngôn ngữ riêng.

  • Nhìn thấy ý kiến phản đối TypeScript rất thú vị. TypeScript gần như là một công cụ mà gần như cải thiện mọi dòng code với chi phí thấp. Có vẻ như họ sợ phải học cái mới, không muốn dành thời gian, hoặc hiểu sai giá trị của nó. Nếu đồng tình với những người phản đối TypeScript, hãy suy nghĩ kỹ hơn về lý do; nếu không, bạn sẽ phải chịu thiệt hại lớn.