7 điểm bởi GN⁺ 2026-02-18 | 1 bình luận | Chia sẻ qua WhatsApp
  • Trong Go 1.26, lệnh go fix được viết lại hoàn toàn đã được giới thiệu, cho phép tự động cải thiện mã để tận dụng các tính năng mới nhất của ngôn ngữ và thư viện
  • Công cụ này phát hiện các mẫu mã thông qua hàng chục analyzer và áp dụng nhiều modernizer như minmax, rangeint, stringscut để chuyển đổi mã lặp lại hoặc lỗi thời sang dạng hiện đại hơn
  • Để hỗ trợ tính năng mới new(expr), analyzer newexpr đã được thêm vào, có thể tự động đơn giản hóa các hàm helper như newInt
  • go fix tạo ra hiệu ứng cộng hưởng khi chạy nhiều lần; các analyzer khác nhau có thể liên tiếp đề xuất cải tiến, đồng thời bao gồm khả năng tự động hợp nhất khi xung đột và loại bỏ các import không cần thiết
  • Nhóm Go dự định trong tương lai sẽ mở rộng theo mô hình phân tích “Self-service” để các nhà phát triển có thể tự định nghĩa và phân phối modernizer cho API của riêng họ

Tổng quan về lệnh go fix

  • Trong Go 1.26, go fix được triển khai lại hoàn toàn, cung cấp khả năng tự động chuyển đổi codebase sang phong cách Go hiện đại
    • Có thể sửa tất cả package trong thư mục hiện tại trở xuống bằng lệnh go fix ./...
    • Có thể xem trước thay đổi bằng tùy chọn -diff
  • Có thể xem danh sách analyzer đã đăng ký bằng go tool fix help, bao gồm nhiều quy tắc chuyển đổi như any, forvar, mapsloop, minmax
  • Nếu chỉ muốn chạy một analyzer cụ thể thì dùng cờ như -any, còn để loại trừ thì chỉ định -any=false
  • Có thể chạy nhiều lần theo từng tổ hợp GOOS, GOARCH để tính đến khác biệt mã theo nền tảng

Modernizers — công cụ hiện đại hóa mã

  • Từ Go 1.18 trở đi, việc giới thiệu generics giúp mở rộng đáng kể khả năng đơn giản hóa mã
    • Ví dụ: dùng maps.Keys để thu thập khóa của map, dùng strings.Cut để tách chuỗi
  • Để giải quyết vấn đề các công cụ sinh mã dựa trên LLM vẫn giữ các mẫu cũ, bài viết nhấn mạnh sự cần thiết của việc cập nhật mã nguồn mở để phản ánh các idiom Go mới nhất
  • Các modernizer có trong go fixgopls giúp tăng khả năng đọc hiểu mã và hiệu quả học tập
  • Một số modernizer tiêu biểu:
    • minmax: thay câu lệnh if bằng hàm min/max
    • rangeint: chuyển vòng lặp for 3 thành phần sang range-over-int
    • stringscut: đơn giản hóa mã dựa trên strings.Index thành strings.Cut

Tính năng new(expr) trong Go 1.26

  • Hàm new được mở rộng để chấp nhận đối số giá trị, cho phép khởi tạo theo dạng new("go1.26")
  • Analyzer newexpr tìm các hàm helper như newInt và đơn giản hóa thành return new(x), đồng thời thay các chỗ gọi bằng new(expr)
  • Chỉ áp dụng khi đáp ứng phiên bản Go tối thiểu, ví dụ chỉ thị go 1.26
  • Có thể áp dụng cho toàn bộ codebase bằng lệnh $ go fix -newexpr ./...
  • Sau khi dùng, các hàm helper không còn cần thiết có thể được nhận diện bằng công cụ deadcode

Hiệu ứng cộng hưởng và xử lý xung đột

  • hiệu ứng cộng hưởng khi một lần sửa tạo ra cơ hội cho các lần sửa khác
    • Ví dụ: sau khi áp dụng minmax có thể xuất hiện thêm các đề xuất chuyển đổi khác
    • Có thể có chuỗi tối ưu hóa liên tiếp như stringsbuilderfmt.Fprintf
  • go fix tự động hợp nhất xung đột sửa đổi bằng thuật toán 3-way merge
    • Nếu có xung đột cú pháp thì bỏ qua thay đổi đó và hiển thị cảnh báo
    • Xung đột ngữ nghĩa, ví dụ xóa biến hoặc import không còn dùng, có thể cần điều chỉnh thủ công
    • Các import không cần thiết sẽ được tự động loại bỏ

Tích hợp với framework phân tích Go

  • go vetgo fix được tích hợp để chia sẻ cùng một framework phân tích
    • vet tập trung vào phát hiện lỗi, còn fix tập trung vào tự động sửa an toàn
  • Analyzer có thể chạy trên nhiều driver như unitchecker, multichecker, gopls, staticcheck, Tricorder
  • Hệ thống fact cho phép chia sẻ thông tin giữa các package
    • Ví dụ: suy luận rằng log.Printf là wrapper của fmt.Printf
  • gopls cung cấp chẩn đoán thời gian thực và gợi ý sửa tự động

Cải tiến hạ tầng phân tích

  • Mở rộng gói inspector giúp tăng hiệu quả duyệt AST, với kiểu Cursor hỗ trợ di chuyển lên/xuống/trái/phải
  • typeindex giúp lập chỉ mục lời gọi hàm, tăng tốc độ phân tích lên đến 1000 lần
  • Các cải tiến bổ sung:
    • Cung cấp đồ thị phụ thuộc của thư viện chuẩn
    • Hỗ trợ truy vấn phiên bản Go theo từng tệp
    • Mở rộng các primitive refactoring để sửa mã an toàn, như thao tác với chú thích
  • Một số modernizer bị loại trừ do có thay đổi hành vi tinh vi (ví dụ append([]string{}, slice...)slices.Clone(slice))
  • Trong tương lai dự kiến phát triển engine so khớp mẫu, test harness tự động, và thư viện toán tử sửa đổi chính xác

Mô hình Self-service

  • Từ Go 1.26 sẽ bắt đầu giới thiệu mô hình phân tích self-service
    • Nhà phát triển có thể tự định nghĩa và phân phối modernizer cho API của riêng mình
    • Có thể chạy ở cấp dự án mà không cần quy trình phê duyệt tập trung
  • Ở giai đoạn đầu, tính năng annotation-driven inliner đã được đưa vào dưới dạng bản xem trước
  • Kế hoạch tương lai:
    • Chạy analyzer tùy biến thông qua dynamic loading (trong go fix hoặc gopls)
    • Khái quát hóa kiểm tra dựa trên control flow, ví dụ xác minh các bất biến như “open rồi phải close”, “lock rồi phải unlock”
  • Mục tiêu là nâng cao hiệu quả bảo trì và hỗ trợ áp dụng nhanh các tính năng Go mới nhất

1 bình luận

 
GN⁺ 2026-02-18
Ý kiến trên Hacker News
  • Vào cuối năm 2024, khi các trợ lý viết mã bằng LLM lan rộng rất nhanh, điều thú vị là các công cụ này có xu hướng tái tạo nguyên trạng phong cách mã Go cũ từ dữ liệu huấn luyện
    Ngay cả khi được yêu cầu dùng cú pháp mới nhất, chúng vẫn bỏ qua, thậm chí có lúc còn phủ nhận là nó tồn tại
    Để các mô hình tương lai phản ánh được idiom Go 1.25 mới nhất, toàn bộ mã nguồn mở cũng sẽ phải được cập nhật sang phong cách đó

    • PHP trước đây cũng từng có nỗ lực dọn dẹp những lời khuyên lỗi thời trên Stack Overflow, chẳng hạn như magic_quotes
      Nhưng với LLM, một khi dữ liệu sai đã lọt vào thì gần như không thể sửa được
      Rất khó lần theo cơ sở mà mô hình dùng để đi đến kết luận, và chỉ còn biết hy vọng nó sẽ được sửa trong mô hình thế hệ sau
    • Mã đồng thời trong Go do LLM tạo ra đặc biệt nguy hiểm
      Nó trông đơn giản nên dễ qua review, nhưng thực tế lại thiếu xử lý lỗi và các trường hợp biên
      Sau khi review rồi đưa lại cho LLM, bề ngoài có vẻ mã đã được sửa, nhưng bên trong lại phát sinh data race hoặc deadlock
      Đây là vấn đề lặp lại ở gần như mọi mô hình
    • Tôi cũng gặp chuyện này thường xuyên
      Go có khả năng tương thích ngược tốt nên vẫn biên dịch được, nhưng phong cách mã thì thay đổi quá nhiều
      Với Python, thay đổi API còn gây ra vỡ tương thích thật sự
      Dù vậy, nhờ độ ổn định của ngôn ngữ và thư viện chuẩn, Go vẫn là một ngôn ngữ rất xuất sắc để sinh mã
    • Việc dùng LLM rốt cuộc sẽ chỉ tạo ra mã đồng dạng, tầm thường với số lượng lớn
    • Tôi nghĩ nên từ bỏ hẳn ý tưởng dùng LLM để viết mã
      Như Rob Pike đã cảnh báo, công nghệ kiểu này là sự ô nhiễm của hệ sinh thái phần mềm
      Nhiều người muốn thứ slop mang lại “sự tiện lợi”, nhưng đó mới chính là cốt lõi của vấn đề
  • Một công cụ có thể tự động chuyển đổi mã nguồn sang phong cách mới nhất thực sự rất tuyệt
    OpenRewrite của Java là ví dụ tiêu biểu, nhưng ở các ngôn ngữ khác thì khó nghĩ ra thứ tương tự
    Nếu một khả năng như vậy được tích hợp sẵn trong ngôn ngữ như Go, thì độ trưởng thành của ngôn ngữ tăng lên rất nhiều
    Có lẽ các ngôn ngữ mới sau này sẽ tham khảo cách tiếp cận tích hợp kiểu Go

    • Với C có Coccinelle, và đã được giới thiệu trong bài viết LWN năm 2009
      IDE của JetBrains có thể refactor hàng triệu dòng mã cùng lúc hoặc tự động chuyển sang cú pháp mới
      Cũng có các tính năng như ConvertToPrimaryConstructor
      Ngoài ra, Structural Search and Replace hoạt động ở mức cú pháp ngôn ngữ chứ không chỉ là văn bản thuần
      Bộ phân tích Roslyn của .NET cũng đưa ra gợi ý sửa mã ngay trong IDE
      Liên kết hướng dẫn
    • clippy của Rust khuyến nghị cú pháp mới nhất, và một số trường hợp còn có thể tự sửa
      Nhờ vậy mã đã sạch sẽ hơn rất nhiều
    • hlint của Haskell cũng đã có từ lâu
      Nó có thể đổi concatmap thành concatMap, hoặc đơn giản hóa những biểu thức if không cần thiết
    • Tôi tò mò không biết đã có ai chuyển đổi codebase TypeScript theo kiểu này chưa
      Máy chủ LSP thiếu chức năng, thậm chí còn không hỗ trợ các thao tác refactor cơ bản như xóa tham số
      Tôi đang cân nhắc liệu có thể kết hợp jscodeshift hay Claude để làm việc đó hay không
  • Nhờ những công cụ tự động sửa lỗi (go fix) như thế này mà Go thực sự là một ngôn ngữ xuất sắc
    Tính năng mới rangeint cũng dự kiến sẽ được áp dụng tự động qua go fix, nên rất đáng mong đợi
    Xin gửi lời khen ngợi tới đội ngũ Go

    • Nhiều khi tôi cũng muốn dùng ngôn ngữ khác, nhưng công cụ build·test·lint của Go quá tốt nên cuối cùng lại quay về với Go
      Tốc độ biên dịch cũng nhanh đến mức khó tin
    • Trước đây tôi từng tự dùng regex để tìm rồi sửa vòng lặp for, còn giờ công cụ này xử lý theo cách tinh tế hơn nhiều
  • Bài viết không nhắc đến, nhưng tính năng tôi thích nhất là chỉ thị //go:fix inline
    Nó chèn một hàm chỉ có một dòng inline vào chỗ gọi
    Nhờ đó tác giả thư viện có thể tự động migration từ hàm cũ sang hàm mới một cách tự nhiên
    Ngay cả khi semver thay đổi, vẫn có thể tự động nâng cấp bằng go fix

  • Trong podcast của Wes McKinney mà tôi xem gần đây,
    ông nói Go rất lý tưởng cho coding agent nhờ chu kỳ compile-run nhanh, hệ thống kiểu mạnh, và độ an toàn đa luồng
    Nghe vậy xong tôi lại thấy hứng thú với Go

  • Hệ thống công cụ và quy ước đã được thiết lập của Go rất hữu ích cho phát triển dựa trên agent
    Có thể dựng ngay môi trường phát triển bằng go run main.go, đồng thời hỗ trợ nhiều worktree, cấu hình trung tâm và cả cơ sở dữ liệu đã migration
    housecat-inc/cheetah có chia sẻ kiểu công cụ này
    Tôi đang định thêm go fix vào vòng lặp nhanh vốn đã có go generate, go build, go test, go vet

    • Tốc độ biên dịch siêu nhanh cũng là lợi thế lớn cho các vòng lặp thử nghiệm với LLM
  • Khi học Python, tôi thấy có quá nhiều cách để làm cùng một việc và thiếu nhất quán
    Đôi khi lại thấy nhớ kiểu chỉ có một cách như ở C
    Tôi muốn biết liệu Go đã đạt tới giai đoạn đó chưa
    Nó có phải là ngôn ngữ mà ngay cả không cần trợ giúp từ LLM vẫn có thể làm theo best practice hay không

    • Go là một ngôn ngữ khá có chính kiến, nên phần lớn chỉ có một cách để làm
      Điều đáng ấn tượng là nó cố giữ mọi thứ không phức tạp và đơn giản
      Tôi khuyên dùng cho những ai đã mệt mỏi với sự hỗn loạn của Python
  • Khái niệm self-service analyzer thực sự rất thú vị
    Có vẻ các đội thư viện lớn hoặc đội hạ tầng sẽ tận dụng nó rất tích cực

  • Có công cụ như vậy thì khiến tôi nghĩ liệu ngay cả ngôn ngữ không có tương thích ngược cũng có thể khả thi hơn không

  • Trong thế giới TypeScript, biome đóng vai trò như vậy
    Ví dụ, nó khuyến nghị dùng for...of thay cho forEach, và nếu dùng cùng ultracite thì quy trình làm việc trở nên mượt hơn nhiều
    Tôi đã ghi rõ trong file agents.md là “sau khi sửa thì chạy biome fix”, và nhờ vậy chất lượng mã được duy trì tự động
    Đây là trải nghiệm nhẹ và hiệu quả hơn nhiều so với eslint