Bài viết
So sánh đoạn mã mà không tải chúng lên
Mỗi lần bạn dán hai tệp vào một công cụ diff trực tuyến, mã đó rời khỏi máy của bạn. Tệp cấu hình, truy vấn cơ sở dữ liệu, khóa API nằm trong một đoạn .env: tất cả đều đi tới một máy chủ bạn không kiểm soát. Bài viết này nói về cách thuật toán diff hoạt động, các tùy chọn mức độ chi tiết có ý nghĩa gì trong thực tế, và vì sao giữ việc so sánh ở cục bộ lại quan trọng.
Diff tính toán điều gì
Một công cụ diff nhận hai văn bản và tìm tập thay đổi tối thiểu biến văn bản này thành văn bản kia. Ý tưởng cốt lõi là chuỗi con chung dài nhất, hay LCS: chuỗi dòng (hoặc token) dài nhất xuất hiện trong cả hai văn bản theo cùng thứ tự, dù không liền kề. Mọi thứ không nằm trong chuỗi con chung đó hoặc là phần thêm vào ở bản mới hoặc là phần bị xóa khỏi bản cũ. Thuật toán kinh điển cho việc này thuộc về Myers (1986), tìm kịch bản chỉnh sửa ngắn nhất trong thời gian O((N+M)D), với N và M là độ dài hai văn bản và D là số lần chỉnh sửa. Trong thực tế, hầu hết công cụ thêm một bước tiền xử lý để bỏ qua các dòng chung ở đầu và các dòng chung ở cuối, thu nhỏ bài toán về vùng đã thay đổi. Kết quả là một patch: một dãy các hunk, mỗi hunk mô tả một khối liền nhau gồm các dòng ngữ cảnh, dòng xóa và dòng thêm. Đây là định dạng được dùng bởi diff của Unix, Git, và phần lớn công cụ review mã.

Mức độ chi tiết: dòng, từ và ký tự
Mức độ chi tiết của một diff quyết định cái gì được tính là một đơn vị so sánh. Diff theo dòng là mặc định trong hầu hết công cụ: mỗi dòng được coi là một token đơn. Cách này nhanh và tạo ra đầu ra dễ đọc trong ngữ cảnh, nhưng nó đánh dấu cả một dòng là đã thay đổi ngay cả khi chỉ một từ trên dòng đó khác. Diff theo từ tách mỗi dòng thành các từ trước khi chạy LCS. Cách này cho bức tranh chi tiết hơn về điều đã thay đổi bên trong một dòng, hữu ích cho văn xuôi, giá trị cấu hình, hoặc JSON. Diff theo ký tự còn đi xa hơn và có thể làm nổi bật một chữ cái đổi duy nhất bên trong một định danh dài. Việc xử lý khoảng trắng thêm nhiễu. Một dòng kết thúc bằng CRLF và cùng dòng đó kết thúc bằng LF sẽ hiện ra khác nhau khi so sánh byte một cách nghiêm ngặt. Hầu hết công cụ cung cấp một tùy chọn để chuẩn hóa ký tự xuống dòng trước khi diff. Tương tự, khoảng trắng thừa ở cuối, thụt lề bằng tab so với dấu cách, và dòng trống đều có thể tạo ra đầu ra diff giả. Bật chuẩn hóa khoảng trắng thường là mặc định đúng khi so sánh mã từ các trình soạn thảo hoặc hệ điều hành khác nhau.
Rủi ro riêng tư của công cụ diff trực tuyến
Các dịch vụ diff và pastebin trực tuyến rất tiện: mở một URL, dán hai đoạn, nhận đầu ra có màu. Vấn đề là văn bản bạn dán được truyền tới một máy chủ của bên thứ ba. Tùy dịch vụ, văn bản đó có thể bị ghi log, lập chỉ mục, lưu trữ vô thời hạn, hoặc chia sẻ với các nhà cung cấp phân tích. Điều này quan trọng nhất khi mã chứa nội dung nhạy cảm. Thông tin đăng nhập gắn cứng, tên máy chủ nội bộ, logic nghiệp vụ độc quyền, hoặc dữ liệu nhận dạng cá nhân đều có thể nằm trong một bản dán. Ngay cả khi không có bí mật rõ ràng, cấu trúc của mã nội bộ có thể tiết lộ các quyết định kiến trúc bạn muốn giữ kín. Rủi ro này không phải giả định. Các nhà nghiên cứu bảo mật đã nhiều lần tìm thấy thông tin đăng nhập và token nội bộ trong các bản dán công khai. Một số dịch vụ vẫn giữ bản dán ngay cả sau khi người dùng xóa, vì bản sao tồn tại trong bộ nhớ đệm hoặc bản sao lưu. Không có cách nào để xác minh một dịch vụ từ xa làm gì với văn bản sau khi nó tới nơi. Biện pháp giảm thiểu đáng tin cậy duy nhất là giữ việc diff ở cục bộ, nghĩa là chạy nó trong một công cụ không bao giờ gửi văn bản qua mạng.

Các ứng dụng thực tế của diff cục bộ
Diff không chỉ dành cho review mã. Một vài trường hợp thường gặp khi diff cục bộ hữu ích: Xem lại các chỉnh sửa cho một tài liệu hoặc tệp cấu hình trước khi commit. So sánh hai phiên bản của một Dockerfile, một cấu hình Nginx, hoặc một manifest Kubernetes để hiểu chính xác điều gì đã đổi giữa các lần triển khai. Kiểm tra sai lệch cấu hình giữa các môi trường. Nếu cấu hình production và staging được cho là giống hệt nhau ngoại trừ tên máy chủ và bí mật, một diff lập tức cho thấy mọi khác biệt ngoài ý muốn. So sánh phản hồi API khi gỡ lỗi. Dán hai payload JSON từ một REST hoặc GraphQL API và chạy diff theo từ sẽ chỉ ra chính xác trường được thêm, giá trị đổi, hoặc khóa bị xóa mà không phải đọc qua hàng trăm dòng bằng tay. Xem lại mã do LLM tạo so với một bản nền. Khi một mô hình viết lại một hàm, một diff theo dòng cho thấy logic nào đã đổi và logic nào giữ nguyên, nhanh hơn đọc cả hai phiên bản riêng rẽ. Trong mọi trường hợp này, văn bản liên quan có thể nhạy cảm, và giữ nó tránh xa một máy chủ từ xa là lựa chọn hợp lý.
Làm trong trình duyệt, không tải lên
Công cụ text-diff trên trang này chạy toàn bộ phép tính diff trong trình duyệt của bạn bằng JavaScript. Bạn dán hai văn bản vào hai khung và diff hiển thị ngay lập tức, theo từng dòng, tối đa 3000 dòng mỗi bên. Không có gì được gửi tới máy chủ. Văn bản không bao giờ rời khỏi thiết bị của bạn. Phần triển khai dùng một thuật toán dựa trên LCS chuẩn vận hành trên các dòng: mỗi dòng là một token, và công cụ xác định xem nó không đổi, được thêm, hay bị xóa bằng cách tìm dãy con chung dài nhất giữa hai phiên bản. Dòng không đổi hiển thị không tô sáng, dòng thêm màu xanh, dòng xóa màu đỏ, cạnh một bộ đếm liên tục số dòng thêm và xóa. Hiện chưa có chế độ theo từ hay theo ký tự và cũng chưa có nút chuẩn hóa khoảng trắng, nên một dòng chỉ khác nhau ở khoảng trắng cuối dòng hoặc kiểu xuống dòng vẫn hiển thị là đã thay đổi. Vì phép tính chạy ở phía máy khách, nó hoạt động ngoại tuyến. Không có tài khoản, không có lịch sử, không có lưu giữ. Bạn có thể so sánh một tệp cấu hình cục bộ với một mẫu, xem lại một patch trước khi áp dụng, hoặc kiểm tra hai phản hồi API mà không có văn bản nào tới một bên thứ ba.
Công cụ trong bài viết này
Câu hỏi thường gặp
Diff theo dòng hay theo từ tốt hơn cho mã?
Với hầu hết tác vụ review mã, diff theo dòng là chuẩn và dễ đọc nhất, vì mã được cấu trúc theo dòng. Diff theo từ có thể hữu ích khi các dòng dài và chỉ một phần nhỏ thay đổi, chẳng hạn trong một giá trị JSON một dòng, nhưng công cụ này chỉ so sánh ở cấp độ dòng; trong trường hợp đó, hãy dùng dòng được tô sáng như một điểm chỉ dẫn và tự quan sát bằng mắt phần khác biệt nhỏ hơn bên trong nó.
Vì sao công cụ diff trực tuyến vẫn là rủi ro riêng tư ngay cả khi dùng HTTPS?
HTTPS bảo vệ văn bản khi truyền khỏi việc nghe lén, nhưng nó không bảo vệ văn bản một khi tới máy chủ. Người vận hành dịch vụ có toàn quyền truy cập nội dung đã dán và có thể ghi log, lưu trữ, hoặc chia sẻ nó. TLS là về bảo mật khi truyền, không phải về điều bên nhận làm với dữ liệu.
Công cụ text-diff có lưu lịch sử các lần so sánh trước không?
Không. Công cụ không có backend và không thực hiện yêu cầu mạng nào. Một khi bạn đóng hoặc tải lại tab, văn bản biến mất. Không có tài khoản, không có lịch sử được lưu, và không có log phía máy chủ.