Có một kiểu tự tin thái quá thường xuất hiện trong giới lập trình hệ thống: nếu bạn không tự tay giải phóng bộ nhớ, không nhìn trực tiếp vào assembly và không biết chính xác object nằm ở stack hay heap, bạn chỉ đang sống dựa dẫm vào người khác dọn phòng hộ.
Sự tự tin ấy đôi khi có ích để viết mã tối ưu sát máy. Nhưng đôi khi nó khiến ta quên mất một sự thật đơn giản: phần lớn phần mềm trên thế giới được viết ra để con người hoàn thành công việc cùng nhau một cách nhanh nhất.
Java tạo ra một thỏa thuận cực kỳ mạnh mẽ: biên dịch thành bytecode trung gian, chạy trên máy ảo JVM, giao phó hoàn toàn việc quản lý heap, dọn rác (GC), class loading và các chi tiết nền khác cho runtime. Cái giá phải trả là một bộ runtime khổng lồ và một mô hình thực thi không hoàn toàn hiện rõ trên mã nguồn. Đổi lại, hàng triệu lập trình viên có một nền tảng thống nhất, tooling cực kỳ trưởng thành, thư viện khổng lồ và khả năng chạy mã nguồn trên mọi hệ điều hành mà không cần viết lại.
Bất kỳ ai từng bảo trì một hệ thống doanh nghiệp lớn đều hiểu rõ giá trị của sự "nhà mọc rêu" ổn định ấy. Một dịch vụ phần mềm không cần phải khiến tác giả cảm thấy mình là một phi hành gia đang lái tàu vũ trụ. Nó cần nhân viên mới vào đọc hiểu ngay, công cụ profiler hoạt động đáng tin cậy, thư viện kết nối database ổn định, và một lỗi phát sinh lúc ba giờ sáng đã có quy trình xử lý (runbook) rõ ràng. Java thắng nhiều trận chiến không phải vì nó gần phần cứng nhất, mà vì hệ sinh thái của nó giúp tổ chức tồn tại lâu hơn bất kỳ cá nhân xuất sắc nào.
Go lại chọn một triết lý đơn giản khác. Cú pháp nhỏ gọn, thời gian biên dịch cực nhanh, công cụ định dạng code (gofmt) gần như bắt buộc, hệ thống package tường minh, và lập trình song song (concurrency) được đưa vào ngôn ngữ phổ thông qua goroutine và channel. Go thành thật công bố runtime đi kèm mỗi chương trình nhị phân để chịu trách nhiệm cho GC, quản lý concurrency và stack tự động phình co. Sự đơn giản trên bề mặt được mua bằng sự phức tạp vô cùng dưới phần thực thi của runtime.
Điều ấy không phải gian lận thiết kế. Đó là sự lựa chọn kiến trúc thông minh.
GC giúp chữ ký API của Go cực kỳ sạch sẽ vì không cần phải mang theo các tham số quyền sở hữu hay lifetime qua mọi biên giới hàm. Nó làm việc chia sẻ đối tượng giữa các goroutine hay thread trở nên cực kỳ an toàn và dễ tiếp cận. Java và Go chọn cách giải bài toán quản lý bộ nhớ một lần duy nhất bên trong bộ runtime chung, thay vì bắt từng dự án ứng dụng phải tự phát minh lại bánh xe dọn dẹp bộ nhớ. Với phần lớn ứng dụng mạng và backend, đây là một giao dịch thương mại cực kỳ hời.
Nhưng giao dịch nào cũng có hóa đơn thanh toán kèm theo. Bộ nhớ Heap là hữu hạn. GC tiêu tốn CPU, RAM và có chiến lược quét, chu kỳ dọn dẹp và các tham số tuning phức tạp. Go có cơ chế escape analysis để tự động quyết định giá trị nào được nằm ở Stack, giá trị nào bắt buộc phải đưa lên Heap; chính tài liệu của Go cũng thừa nhận thuật toán phân tích này cực kỳ phức tạp và liên tục thay đổi qua các phiên bản. JVM có các phân vùng dữ liệu runtime phức tạp, các chiến lược quản lý bộ nhớ tự động. Lập trình viên được giải phóng khỏi lệnh free thủ công, nhưng không được phép lười biếng trốn tránh việc tìm hiểu hành vi của runtime khi độ trễ (latency), dung lượng RAM thực tế (footprint) hay băng thông dữ liệu (throughput) trở thành yêu cầu sống còn của hệ thống.
DUY học hỏi sâu sắc từ Go ở sự tiết chế tính năng cú pháp và sức mạnh của tooling đi kèm. Một ngôn ngữ tốt không cần đến mười cách viết khác nhau cho cùng một vòng lặp. Biên dịch phải nhanh. Thông báo lỗi phải hỗ trợ trực tiếp công việc. Package và tài liệu phải là một phần hữu cơ của ngôn ngữ ngay từ ngày đầu tiên. DUY học hỏi Java ở sức mạnh của hợp đồng runtime tường minh và tính tương thích lâu dài.
Nhưng DUY kiên quyết chọn một hóa đơn thanh toán khác: không dùng tracing GC mặc định, quản lý vòng đời bộ nhớ tường minh qua static ownership, views và regions, các effect quan trọng phải hiện hình trên chữ ký. Lựa chọn này giúp chương trình hệ thống của DUY đạt tính dự đoán cao sát phần cứng, nhưng chắc chắn sẽ khiến việc thiết kế các thư viện API trở nên khó khăn hơn nhiều. Không có bữa trưa nào miễn phí trong thế giới lập trình hệ thống, chỉ có những nhà hàng in giá sòng phẳng và tường minh hơn trên thực đơn.
Go và Java không phải là đối thủ để DUY hạ bệ. Chúng là tấm gương nhắc nhở rằng trải nghiệm của nhà phát triển (developer experience), hệ thống thư viện và tính ổn định vận hành mới là thứ quyết định một ngôn ngữ lập trình có sống sót bên ngoài phòng nghiên cứu hay không. Một trình biên dịch xuất sắc nhưng cài đặt khó khăn vẫn chỉ là một bài tập học thuật được đóng gói trang trọng trong tủ kính.
Bình luận (0)
Đang tải bình luận...