Uv: Tuyệt vời nhưng trải nghiệm quản lý gói còn lộn xộn
uv của Astral đã tạo nên cơn sốt trong cộng đồng Python nhờ tốc độ xử lý ấn tượng và khả năng thay thế nhiều công cụ cùng lúc. Tuy nhiên, trải nghiệm người dùng trong việc bảo trì dự án, đặc biệt là kiểm tra và nâng cấp các gói phần mềm, lại khá kém so với các đối thủ như pnpm hay Poetry.

Công cụ uv của Astral đã tạo nên một cơn địa chấn trong thế giới Python, và hoàn toàn có lý do cho điều đó. Nó có tốc độ cực nhanh, xử lý các phiên bản Python một cách nhẹ nhàng và thay thế cả chục công cụ khác chỉ bằng một tệp binary duy nhất. Tôi đã từng viết nhiều bài ca ngợi về nó.
uv python package manager
Bắt đầu một dự án Python mới bằng uv và thêm các thư viện phụ thuộc đầu tiên rất dễ dàng. Nhưng một khi bạn vượt qua giai đoạn thiết lập ban đầu và bước vào giai đoạn bảo trì dự án — tức là kiểm tra các gói đã lỗi thời và thực hiện các bản nâng cấp định kỳ — giao diện dòng lệnh (CLI) này bắt đầu cảm thấy cồng kềnh một cách đáng ngạc nhiên khi so sánh với các đối thủ như pnpm hay Poetry.
Tìm kiếm các gói đã lỗi thời
Trong các dự án JavaScript của tôi, nếu muốn xem những gì cần cập nhật, tôi chỉ cần chạy:
$ pnpm outdated
Lệnh này đưa ra một danh sách gọn gàng, ngắn gọn về các gói lỗi thời, phiên bản hiện tại, phiên bản mới nhất và phiên bản được phép bởi các ràng buộc của bạn.
Ở uv, không có lệnh uv outdated. Thay vào đó, bạn phải thuộc lòng câu lệnh dài dòng sau:
$ uv tree --outdated --depth 1
Kết quả đầu ra cũng là một vấn đề. Nó không chỉ hiển thị những gì đã lỗi thời; nó hiển thị toàn bộ cây phụ thuộc cấp cao nhất của bạn, với một chú thích nhỏ bên cạnh những gói có bản cập nhật. Nếu bạn có 50 phụ thuộc và chỉ có hai cái lỗi thời, bạn vẫn phải lướt qua một danh sách 50 dòng.
Poetry cũng không tốt hơn nhiều với lệnh poetry show --outdated, nhưng ít nhất nó chỉ hiển thị các gói thực sự đã lỗi thời.
Ràng buộc phiên bản không an toàn theo mặc định
Đây là sự khác biệt về triết lý lớn nhất của uv so với pnpm và Poetry, và nó là một điều nguy hiểm cho sự ổn định của môi trường sản xuất (production).
Cách pnpm/Poetry xử lý:
Khi bạn thêm một gói bằng pnpm add, nó sẽ ghi vào package.json bằng yêu cầu dấu mũ (caret) (^1.23.4). Dấu mũ ở đầu có nghĩa là bất kỳ phiên bản 1.x.x nào đều được phép, nhưng nó sẽ không cập nhật lên 2.0.0.
Poetry cũng làm tương tự theo mặc định, sử dụng định dạng như >=1.23.4,<2.0.0.
Cách uv xử lý:
Khi bạn chạy uv add pydantic, nó sẽ ghi vào pyproject.toml như sau:
dependencies = [
"pydantic>=2.13.4",
]
Hãy lưu ý sự thiếu vắng một giới hạn trên (upper bound). Trong mắt của uv, phiên bản pydantic 2, 3 và 100 đều hoàn toàn chấp nhận được.
Điều này có nghĩa là các bản cập nhật của uv không an toàn theo mặc định. Nếu bạn chạy một bản cập nhật hàng loạt, bạn không chỉ nhận được các bản sửa lỗi; bạn đang tự nguyện chấp nhận mọi thay đổi gây phá vỡ (breaking change) được xuất bản bởi mọi người duy trì trong đồ thị phụ thuộc của mình.
Trải nghiệm kém của lệnh nâng cấp
Các lệnh để thực sự thực hiện cập nhật trong uv cảm giác như được thiết kế cho máy móc hơn là cho con người.
Nếu bạn muốn cập nhật mọi thứ trong pnpm hoặc Poetry, đó là một lệnh đơn giản pnpm update hoặc poetry update. Trong uv, bạn sử dụng:
$ uv lock --upgrade
Do vấn đề "không có giới hạn trên" đã đề cập ở trên, uv lock --upgrade là một giải pháp hạt nhân (nuclear option). Nó sẽ nâng cấp mọi gói đơn lẻ trong lockfile của bạn lên các phiên bản mới nhất tuyệt đối, bỏ qua tính an toàn của SemVer. Và điều này bao gồm cả các phụ thuộc lồng nhau sâu mà bạn chưa từng nghe tới! Chúc bạn may mắn, hy vọng không có thay đổi nào gây phá vỡ ở bất kỳ đâu.
Khi bạn nhận thấy điều này quá rủi ro, bạn sẽ muốn chỉ nâng cấp các gói cụ thể. Sau khi mò mẫm trong kết quả đầu ra kém chất lượng của uv tree --outdated --depth 1 để tìm chúng, cú pháp trở thành một công việc lặp lại nhàm chán.
Cách pnpm làm:
$ pnpm update pydantic httpx uvicorn
Cách uv làm:
$ uv lock --upgrade-package pydantic --upgrade-package httpx --upgrade-package uvicorn
Việc phải lặp lại cờ --upgrade-package cho từng mục là một rắc rối lớn khi bạn muốn cập nhật một loạt các gói. Tôi không hiểu tại sao trải nghiệm người dùng của các lệnh của uv lại kém đến vậy.
Có hy vọng: cờ bounds
May mắn thay, uv gần đây đã giới thiệu tùy chọn --bounds cho uv add:
$ uv add pydantic --bounds major
Điều này tạo ra ràng buộc an toàn hơn pydantic>=2.13.4,<3.0.0 mà chúng ta mong đợi. Tuy nhiên, hiện tại đây là một tính năng chọn tham gia (opt-in). Bạn phải nhớ nhập nó mỗi lần, và cho đến nay, nó được coi là một tính năng xem trước.
Cho đến khi --bounds major (hoặc cấu hình tương tự) trở thành hành vi mặc định, người dùng uv về cơ bản bị buộc phải chọn giữa hai lựa chọn tồi:
- Chỉnh sửa thủ công
pyproject.tomlđể thêm giới hạn trên cho mọi phụ thuộc đơn lẻ. - Sống trong nỗi sợ hãi rằng
uv lock --upgradesẽ vô tình kéo theo một thay đổi phiên bản chính (major version) gây phá vỡ.
Những gì tôi mong muốn
Tôi yêu uv. Tốc độ của nó mang tính chuyển đổi, và cách nó quản lý các chuỗi công cụ Python là vô địch. Nhưng với tư cách là một trình quản lý gói, trải nghiệm của nhà phát triển trong việc bảo trì một dự án hiện đang là một bước lùi so với các công cụ trước đây.
Chúng tôi cần một lệnh uv outdated chuyên dụng để lọc nhiễu, một lệnh cập nhật thuận tiện hơn không yêu cầu lặp lại các cờ, và các ràng buộc phiên bản mặc định tôn trọng tính hợp lý của Semantic Versioning.
Cho đến lúc đó, tôi sẽ kiểm tra kỹ từng dòng trong các thay đổi lockfile của mình với một chút hoài nghi lành mạnh.
Bài viết liên quan

Công nghệ
Cảnh sát bắt giữ nghi can được cho là "ông trùm" của trang web buôn bán ma túy Dream Market
14 tháng 5, 2026

Công nghệ
Thử nghiệm tính năng Avatar AI của Google Gemini: Bản sao số của tôi thật đáng sợ nhưng chân thực
21 tháng 5, 2026
Công nghệ
Người Mỹ không thể nhận diện deepfake: Đây là cuộc khủng hoảng doanh nghiệp chứ không chỉ là vấn đề truyền thông
21 tháng 5, 2026
