FDE PulseViệc làm FDE đang mở 641Mới trong 7 ngày 41Công ty đang tuyển 97Nhận làm từ xa 25%Lương trung vị (Mỹ) $204kTuyển nhiều nhất Databricks 122
EN

Tờ báo của nghề Forward Deployed Engineer

Công cụ

Ruff: lint và format repo Python của khách mà không tạo ra một PR nghìn dòng

Ở repo của khách, công cụ chạy nhanh vẫn chưa đủ: bạn còn phải giữ diff nhỏ để code review không biến thành cuộc tranh cãi.

Màn hình laptop hiển thị code Python, hoặc hai kỹ sư đang cùng xem code trong văn phòng.
Ảnh: Emile Perron / Unsplash
Chia sẻLinkedInFacebookX

Tóm tắt nhanh

  • Trên repo đã format bằng Black, Ruff formatter tương thích hơn 99,9% tính theo số dòng thay đổi, và chạy nhanh hơn Black hơn 30 lần.
  • Mặc định, ruff check không sửa gì cả. Muốn sửa phải thêm --fix, còn unsafe fix cần bật riêng --unsafe-fixes.
  • Dùng --add-noqa và per-file-ignores để chưa phải sửa nợ cũ ngay, rồi đưa hash của commit format vào .git-blame-ignore-revs trong một commit tiếp theo để git blame vẫn dùng được.
Sơ đồ dạng lịch sử commit nằm ngang. Bước đầu là đo bằng ruff check ., chưa sửa gì và không tạo commit. Sau đó có bốn commit: 1 là --add-noqa để chặn code mới; 2 là ruff format, chỉ chạy một lần, được tô màu cam làm điểm nhấn; 3 là thêm .git-blame-ignore-revs để giấu commit format khỏi blame; 4 là ruff check --fix, chỉ dùng các bản sửa an toàn.
Cách áp dụng Ruff ở repo của khách: đo trước rồi tách việc thành bốn commit nhỏ. Commit format nằm riêng để diff dễ duyệt, sau đó được giấu khỏi git blame. Nguồn: tài liệu chính thức của Ruff, theo bài viết.

Tuần đầu ở chỗ khách, bạn mở repo Python và thấy cùng lúc ba thứ: một file cấu hình Flake8, một hook isort và một dòng Black trong CI mà chẳng ai còn chắc nó có chạy hay không. Bạn muốn dọn lại, nhưng chỉ cần một PR “chuẩn hóa style” làm đổi hàng nghìn dòng là team của khách sẽ nghi ngờ bạn ngay.

Ruff hợp với tình huống này vì formatter của nó được thiết kế để thay Black và cho ra kết quả gần như giống hệt trên code đã format bằng Black.

Charlie Marsh của Astral cho biết trên các dự án như vậy, Ruff đạt độ tương thích hơn 99,9% tính theo số dòng thay đổi. Nghĩa là bạn có thể thay công cụ mà gần như không làm đổi code.

Với FDE, điều này quan trọng hơn tốc độ. Một PR vài chục dòng thì khách đọc được và duyệt được. Một PR vài nghìn dòng thì khách chỉ có thể tin hoặc không tin.

Một binary thay cho cả chồng công cụ

Ruff là linter kiêm formatter, viết bằng Rust, phát hành theo giấy phép MIT. Đứng sau nó là Astral, nhóm cũng làm ra uv và ty. Tài liệu chính thức nói Ruff có thể thay Flake8 cùng hàng chục plugin, Black, isort, pydocstyle, pyupgrade, autoflake và một số công cụ khác.

Cũng theo tài liệu, Ruff nhanh hơn từ 10 đến 100 lần so với các linter và formatter hiện có. Nó còn có cache sẵn, nên những file không đổi sẽ không bị phân tích lại. Riêng phần formatter, Astral công bố tốc độ hơn 30 lần so với Black.

Ở repo khách, tốc độ này cho bạn chạy lint toàn repo trong lúc ngồi cùng team của họ, không cần đợi CI. Nhưng lợi ích lớn hơn là cả repo chỉ còn một chỗ cấu hình, thay vì mỗi công cụ một file riêng.

Đo trước, rồi bốn commit nhỏ

Thử hình dung một repo nội bộ có thư mục legacy/ không ai dám động vào và một thư mục services/ đang được phát triển tích cực. Trình tự an toàn là đo trước khi đụng vào bất cứ thứ gì, rồi tách việc thành bốn commit, mỗi commit chỉ làm một việc.

Việc đo không tạo ra commit nào. ruff check . liệt kê vi phạm mà không sửa gì, vì Ruff chỉ sửa khi bạn truyền cờ --fix. Kết quả này là bản đồ nợ kỹ thuật, và bạn có thể mang nó vào buổi họp với khách.

Commit đầu tiên thêm cấu hình Ruff và đánh dấu nợ cũ thay vì sửa ngay. ruff check . --add-noqa tự chèn comment noqa vào mọi dòng đang vi phạm. Từ đó trở đi, chỉ code mới bị chặn. Với những thư mục cần nới lỏng lâu dài, hãy dùng per-file-ignores trong pyproject.toml:

[tool.ruff.lint.per-file-ignores]
"legacy/*" = ["E501"]

Commit thứ hai là ruff format, đứng riêng và không chứa thay đổi nào khác. Chỉ sau khi commit này tồn tại bạn mới có hash của nó, nên commit thứ ba là một commit tiếp theo, thêm file .git-blame-ignore-revs chứa hash đó để giao diện blame của GitHub bỏ qua commit format.

Như vậy người đọc lịch sử vẫn thấy ai viết dòng nào, chứ không phải ai bấm format.

Commit cuối là ruff check --fix. Mặc định Ruff chỉ áp dụng các bản sửa được xếp loại an toàn. Những bản sửa có thể làm đổi hành vi code phải bật thêm --unsafe-fixes. Ở repo khách, bạn nên để cờ này cho từng PR nhỏ có người review.

Khi nào diff vẫn phình to?

Con số hơn 99,9% chỉ đúng với code đã format bằng Black. Tài liệu Ruff nói rõ formatter cố ý khác Black ở một vài điểm, chẳng hạn cách xử lý dòng trống đầu block, f-string và tuple một phần tử. Nếu repo của khách chưa từng dùng Black, lần format đầu tiên có thể tạo diff đáng kể.

Vì thế, câu đầu tiên nên hỏi khách là “CI có thật sự chạy Black không?”, chứ không phải “dùng linter gì?”. Nếu có, bạn có thể kỳ vọng diff nhỏ. Nếu không, hãy báo trước rằng có thể sẽ có một commit format lớn, và chính vì vậy cần .git-blame-ignore-revs.

Bẫy cấu hình trong monorepo

Ruff hỗ trợ monorepo bằng cấu hình phân cấp, đọc từ pyproject.toml, ruff.toml hoặc .ruff.toml. Có một chi tiết dễ làm bạn mất cả buổi chiều. Với mỗi file, Ruff dùng file cấu hình gần nhất trong cây thư mục và không gộp cài đặt giữa các file.

Giả sử services/billing/ có ruff.toml riêng chỉ để đổi độ dài dòng. Khi đó, mọi rule bạn đặt ở pyproject.toml gốc sẽ không áp dụng cho thư mục này nữa. Trước khi kết luận “Ruff bỏ sót lỗi”, hãy kiểm tra xem cấu hình nào đang áp dụng cho file đó.

Nên học gì trước

Hãy học trình tự đo rồi bốn commit trước khi học danh sách rule. Lý do là rủi ro ở repo khách nằm ở quy trình áp dụng, không nằm ở việc chọn rule nào. Sau đó, đọc trang liệt kê khác biệt giữa Ruff và Black, vì đó là nơi bạn cần câu trả lời khi khách hỏi vì sao một dòng bị đổi.

Về hồ sơ xin việc, một dòng như “di chuyển repo Python từ Flake8, isort và Black sang Ruff, giữ diff format dưới mức X dòng, không làm hỏng git blame” có giá trị hơn nhiều so với việc chỉ ghi “thành thạo Ruff”.

Công cụ nhanh giúp bạn tiết kiệm vài phút. Một PR nhỏ mà khách đọc hiểu được mới là thứ giúp bạn có được lòng tin của họ.

Bài này có hữu ích không?

Dùng cùng trợ lý AIHỏi Claude ↗Hỏi ChatGPT ↗
7 nguồn
Đọc tiếp trên lộ trình · Chặng 1: Nền tảngPolars và scan_csv: mở file khách hàng vài GB mà máy không treo như khi dùng pandasỞ chỗ khách, chạy read_csv lên một file lớn rồi ngồi nhìn laptop đứng hình thì rất mất mặt; đọc lười giúp bạn tránh cảnh đó.