1 điểm bởi GN⁺ 2 giờ trước | 1 bình luận | Chia sẻ qua WhatsApp
  • Khi refactor từng bước lớp truy cập dữ liệu Rust dài 17.155 dòng do agent viết, số token đầu vào cần cho cùng một thay đổi tính năng đã giảm 83%, từ 159.564 xuống 27.360
  • Tổng lượng mã gần như không đổi, nhưng bằng cách tách mã liên quan vào các tệp có độ kết dính cao, agent có thể chỉ đọc tập hợp tệp tối thiểu cần cho thay đổi
  • Token đầu vào không giảm đáng kể cho đến khi tệp lớn nhất đủ nhỏ; cuối cùng lớp dữ liệu được chia thành 19 tệp Rust và kích thước tệp lớn nhất giảm từ 17.155 dòng xuống 3.695 dòng
  • Token đầu ra và lượng triển khai tính năng gần như không đổi, và Claude cũng không tự chọn hoặc thực hiện refactoring phù hợp một cách ổn định, nên cần hướng dẫn chủ động của con người trong khâu lập kế hoạch và thực thi
  • Với giá đầu vào của Sonnet 5 là $3/MTok, khoản tiết kiệm cho mỗi lần thay đổi chỉ khoảng $0,397, nhưng thí nghiệm xác nhận khả năng chi phí sẽ tiếp tục giảm lặp lại mỗi lần sửa lớp truy cập dữ liệu về sau

Tệp 17.155 dòng do agent tạo ra

  • Ứng dụng hỗ trợ công việc có web UI cho phép cập nhật và truy vấn động, modal và tự động lưu, tích hợp hệ thống bên ngoài, machine learning và phân tích văn bản, tác vụ nền, cùng môi trường triển khai tự động
  • Trong tổng cộng khoảng 150 nghìn dòng, Rust chiếm khoảng 120 nghìn dòng, phần còn lại là TypeScript và Terraform; phần lớn được agent viết bằng Claude Code và một phần bằng Cursor
  • Ngoài những lúc thỉnh thoảng xem qua vì tò mò, lập trình viên không đọc hay review mã
  • Lớp truy cập dữ liệu lặp lại cùng phần thiết lập HTTP request và mã hóa/giải mã JSON trong mọi query đọc/ghi, tăng lên hơn 6.000 dòng, và cuối cùng một tệp Rust đạt tới 17.155 dòng
  • Module này không có loại bỏ trùng lặp hay ngôn ngữ nội bộ, việc trích xuất hàm còn hạn chế và hầu như không trích xuất class, nhưng có interface cần giữ nguyên và ranh giới rõ ràng nên phù hợp cho thí nghiệm refactoring

Cách đo bằng cách lặp lại cùng một thay đổi

  • Mục tiêu là kiểm tra liệu việc đầu tư token vào refactoring hiện tại có thể giảm mức tiêu thụ token cho các thay đổi tính năng trong tương lai hay không
  • Vì agent không học từ tác vụ trước đó, ở mỗi bước, một sub-agent mới được yêu cầu thực hiện chính xác cùng một thay đổi để tránh lẫn hiệu ứng học
  • Thí nghiệm được tiến hành theo thứ tự sau
    • Lập kế hoạch tổng thể theo các nguyên tắc refactoring nghiêm ngặt
    • Định nghĩa một thay đổi đại diện bằng một prompt duy nhất
    • Cho sub-agent thực hiện thay đổi và báo cáo lượng token tiêu thụ để đo giá trị nền
    • Hủy kết quả thay đổi rồi áp dụng một bước refactoring
    • Lặp lại việc thực hiện cùng thay đổi và hủy kết quả
    • Ghi lại chi phí token, thời gian chạy và số dòng mã theo từng bước
  • Vì Claude không cung cấp số token thời gian thực một cách đáng tin cậy, nó được yêu cầu báo cáo số ký tự gửi/nhận, rồi dùng tiktoken chia số ký tự cho 4 để xấp xỉ token

Kết quả đo theo từng bước

  • Ở trạng thái nền, cả lớp truy cập dữ liệu và tệp lớn nhất đều có 17.155 dòng, toàn bộ mã Rust có 50.359 dòng, và thay đổi đại diện cần 159.564 token đầu vào, 1.705 token đầu ra, 342 giây
  • Sau 15 bước, lớp truy cập dữ liệu còn 16.608 dòng, tệp lớn nhất 3.695 dòng, toàn bộ mã Rust 49.812 dòng; token đầu vào là 27.360, token đầu ra 2.113, thời gian chạy 454 giây
  • Ở các bước trung gian, khi tệp lớn nhất nhỏ dần thì token đầu vào cũng giảm theo
    • Sau bước 7, trích xuất queries.rs, tệp lớn nhất còn 15.670 dòng, đầu vào giảm xuống 151.850 token
    • Sau bước 8, trích xuất traits.rs, tệp lớn nhất còn 13.845 dòng, đầu vào là 132.558 token
    • Sau bước 12, tách store/, tệp lớn nhất còn 9.269 dòng, đầu vào giảm xuống 104.080 token
    • Sau lần tách store/ cuối cùng, tệp lớn nhất còn 3.695 dòng, đầu vào giảm mạnh xuống 27.360 token
  • Lớp truy cập dữ liệu cuối cùng gồm 19 tệp Rust, và tệp lớn nhất trở thành thư viện test
  • Cũng có thể áp dụng cùng phương pháp cho tệp test đó trong các lần refactoring bổ sung

Vì sao token đầu vào giảm 83%

  • Token đầu vào cho cùng một tác vụ giảm từ 159.564 xuống 27.360, tiết kiệm 132.204 token
  • Tổng lượng mã của lớp truy cập dữ liệu gần như không đổi, nên đây không phải là kết quả của việc bản thân lượng mã cần đọc bị giảm
  • Agent đã xác định được tập hợp tệp tối thiểu cần cho tác vụ và chỉ đọc vùng mã ngày càng nhỏ hơn; điều này cũng được xác nhận trong phần suy luận của Claude Code và tóm tắt đọc tệp
  • Nếu chỉ tùy tiện chia nhỏ tệp, agent sẽ phải đọc nhiều tệp để tìm mã liên quan, nên khó đạt hiệu quả tương tự
  • Mức giảm lớn nhất xảy ra ở lần tách cuối cùng, nhưng việc tách tệp đó khả thi là nhờ các bước trước đã trích xuất phần trùng lặp và tạo ra cấu trúc cốt lõi lặp lại
  • Thứ tự này không được thiết kế trước nhằm giảm chi phí, mà xuất hiện từ quy trình refactoring thông thường: loại bỏ trùng lặp cục bộ trước, làm lộ phần lõi chung, rồi phân rã thành các tệp nhỏ hơn

Token đầu ra và tác động tài chính

  • Token đầu ra gần như không đổi khi viết thay đổi đại diện, nên refactoring không làm giảm kích thước thay đổi thực tế
  • Giá token đầu ra gấp 5 lần token đầu vào, nhưng số lượng tuyệt đối nhỏ hơn nhiều
  • Tính theo giá đầu vào Sonnet 5 là $3/MTok, khoản tiết kiệm cho mỗi thay đổi khoảng 39,7 cent
  • Chưa xác nhận được liệu khoản tiết kiệm có tích lũy trong debugging, các tính năng phức tạp hơn, hay refactoring toàn bộ codebase hay không, cũng như chi phí của chính việc refactoring là bao nhiêu
  • Cũng chưa rõ liệu có thể refactor để giảm cả token đầu ra hay không; trong thay đổi đại diện đơn giản, nhiễu từ việc sinh mã không tất định đã che khuất khác biệt do thay đổi cấu trúc

Refactoring cùng Claude

  • Claude không tự chọn được kiểu refactoring cần áp dụng sau khi xem mã; kết quả thực tế tương ứng với những tác vụ được prompt chỉ thị trực tiếp
  • Dù development harness có bước refactoring rõ ràng, Claude không dùng bước đó để cải thiện tệp 17.155 dòng
  • Trong quá trình lập kế hoạch, Claude Code xác định trích xuất hàm là bước đầu tiên, trong khi Claude.ai nhận ra cả việc trích xuất toàn bộ class client
  • Với các thay đổi mang tính cơ học, thí nghiệm dùng script Python chạy grepsed, nhưng script thường bị rối vì vấn đề thụt lề
  • Việc tách tệp store có giá trị lớn nhất bị bỏ sót ở lần thử đầu và được áp dụng lại ở bước sau, nên số bước trong kết quả đo không khớp với các bước kế hoạch ở phụ lục
  • Toàn bộ thí nghiệm mất khoảng 8 giờ và phần lớn chạy không cần giám sát
    • Sau 6 giờ 40 phút, người thực hiện phát hiện bước bị thiếu và can thiệp một lần
    • Nguyên nhân làm test chạy chậm đáng kể không phải Wi-Fi khách sạn chậm, mà là cache build tạm thời của Cargo đã phình quá lớn

Prompt thay đổi đại diện

  • Mỗi sub-agent chỉ được cung cấp codebase và tài liệu kiến trúc, rồi triển khai cùng một public async trait ItemWatchStore
  • Trait gồm ba method sau
    • watch_item(&self, item_id: &str, user_id: &str) -> Result<()>
    • unwatch_item(&self, item_id: &str, user_id: &str) -> Result<()>
    • watched_items_for_user(&self, user_id: &str) -> Result<Vec<String>>
  • Thông tin watch được lưu trong collection item_watches của Firestore với các field itemId, userId, createdAt
  • Trả về Vec<String> của item ID mà không có struct record Rust riêng
  • Thêm field Vec<(String, String)> trong bộ nhớ vào FakeStore, và triển khai FirestoreStore bằng cách giữ nguyên mẫu HTTP hiện có
  • Ở cuối phản hồi, agent được yêu cầu in JSON gồm các tệp đã đọc, số ký tự, số ký tự phản hồi, và không commit mã

Kế hoạch refactoring đã áp dụng

  • Bước 1 — Trích xuất class FirestoreClient

    • Tách trách nhiệm điều phối domain query và gửi HTTP tới Firestore
    • Di chuyển reqwest::Client, project_id, MetadataAuth, xử lý URL và header xác thực sang struct mới
    • Theo kế hoạch, giảm khoảng 1.200 dòng trong phần triển khai FirestoreStore và thêm khoảng 120 dòng vào client
  • Bước 2 — Trích xuất hàm extract_doc_id, new_link

    • Dùng chung phần trích xuất ID trong 20 parser tài liệu và phần tạo Link lặp lại 62 lần
    • Dự kiến tiết kiệm khoảng 500 dòng
  • Bước 3 — Trích xuất hàm pipeline link query

    • Dùng chung mẫu thu thập kết quả query ở khoảng 15 nơi và tra cứu ID mục tiêu đơn ở khoảng 8 nơi
    • Dự kiến tiết kiệm khoảng 200 dòng
  • Bước 4 — Trích xuất hàm điều kiện link của FakeStoreInner

    • Tách các biến thể inner.links.iter() lặp lại trong khoảng 15 method thành hai method
    • Dự kiến tiết kiệm khoảng 120 dòng
  • Bước 5 — Giới thiệu hàm tạo giá trị Firestore

    • Thay thế các biểu thức json! cho chuỗi, timestamp, v.v. lặp lại hơn 128 lần bằng bốn lời gọi hàm
    • Thay macro nhiều dòng bằng lời gọi một dòng, dự kiến tiết kiệm khoảng 80 dòng
  • Bước 6 — Trích xuất FieldsBuilder

    • Gom mẫu tạo field map trong khoảng 20 encoder vào một builder
    • Giảm encoder khoảng 40 dòng xuống còn khoảng 12 dòng, dự kiến tiết kiệm tổng cộng 500–600 dòng
  • Bước 7 — Tách queries.rs

    • Di chuyển 32 hằng LinkQuery và các kiểu liên quan sang module riêng
    • Giảm khoảng 800 dòng khỏi mod.rs mà không thay đổi phía gọi hiện có
  • Bước 8 — Tách traits.rs

    • Di chuyển 17 public trait và các kiểu lỗi liên quan rồi re-export
    • Giảm khoảng 1.900 dòng khỏi mod.rs, nhưng tệp mới cũng dài khoảng 1.900 dòng
  • Bước 9 — Tách traits/ theo domain

    • Chia trait thành planning.rs, content.rs, people.rs, system.rs
    • Giữ nguyên định nghĩa và phía gọi, đồng thời giới hạn kích thước mỗi tệp khoảng 300–650 dòng
  • Bước 10 — Tách codec.rs

    • Di chuyển encoder/decoder tài liệu, parser, FieldsBuilder, các hàm tạo giá trị
    • Sau bước 6, module này dài khoảng 400–500 dòng và giảm khoảng 500 dòng khỏi mod.rs
  • Bước 11 — Tách fake_store.rs

    • Di chuyển FakeStore, FakeStoreInner và 18 implementation trait
    • Giảm khoảng 4.700 dòng khỏi mod.rs
  • Bước 12 — Tách implementation FirestoreStore

    • Giữ struct, constructor, FirestoreClient, MetadataAuth trong store/mod.rs, còn implementation trait được chia thành các tệp theo domain
    • Biến tệp khoảng 10.000 dòng thành 10 tệp, mỗi tệp 120–650 dòng, và biến mod.rs thành tệp re-export khoảng 100 dòng
  • Bước 13 — Đặt test cùng module mục tiêu

    • Không đổi mã test, chỉ di chuyển xuống dưới từng tệp implementation
    • Giảm khoảng 2.000 dòng khỏi mod.rs, đồng thời thêm 200–700 dòng test liên quan vào mỗi tệp

Hạn chế và thí nghiệm tiếp theo

  • Vì không đếm riêng token dùng để lập và thực thi kế hoạch refactoring, không thể tính chính xác chi phí đầu tư refactoring
  • Giới hạn trên dựa trên tổng mức sử dụng trong khung thời gian đó là 5 triệu token, nhưng con số này bao gồm cả việc lập kế hoạch hai lần, thiết kế thí nghiệm và thay đổi đại diện, cùng các công việc khác
  • Đối tượng thí nghiệm vẫn ở giai đoạn greenfield và là một ứng dụng lớn duy nhất do một lập trình viên xây dựng/quản lý, nên không thể khái quát hóa kết quả
  • Các bước tiếp theo cần đo chính xác token refactoring, thử thay đổi phức tạp hơn, refactoring trên phạm vi rộng hơn, refactoring liên tục, và so sánh giá trị tương đối giữa các cách tiếp cận
  • Thí nghiệm này là điểm khởi đầu để đo đồng thời giá trị thời gian/tài chính do refactoring mang lại và chi phí của chính việc refactoring

1 bình luận

 
Ý kiến trên Hacker News
  • Thật thú vị khi thấy các best practice dành cho lập trình viên mà phần lớn công ty IT từng phớt lờ nay được tái phát minh thành best practice cho AI
    Trước đây, nếu nói rằng hãy đặt tài liệu ngay trong code, đừng chỉ ném task Jira mà hãy cung cấp toàn bộ bối cảnh dự án, và hãy refactor vì năng suất dài hạn, thì thường bị xem là nhàm chán
    Giờ đây, cùng nội dung đó—hãy đặt tài liệu AI trong code và CLAUDE.md, đừng kiểm soát li ti bằng prompt, và hãy refactor vì năng suất AI—lại được đón nhận một cách hào hứng

    • Việc khiến AI agent thực hiện cùng một việc một cách nhất quán dễ hơn rất nhiều so với đồng nghiệp con người
      Con người dù biết cách làm đúng vẫn có thể bận rộn hoặc mất tập trung, còn agent thì không chán các công việc tẻ nhạt, nên những quy trình đã được chứng minh là hiệu quả với con người nhưng khó áp dụng đều đặn nay trở nên khả thi trong thực tế
      Việc để các agent riêng viết implementation và test dựa trên một đặc tả chung, rồi để agent audit kiểm chứng nhằm tránh kết quả của bên này làm nhiễm bên kia, chính là áp dụng rộng rãi và nhất quán bằng AI mô hình cleanroom engineering mà IBM đã phát triển cho con người từ thập niên 1980
    • Nhân vật liên quan đến bài viết này là Martin Fowler, người đã viết cuốn 《Refactoring》 hơn 20 năm trước và phổ biến thuật ngữ đó
      Đây không phải là việc đóng gói lại một thực hành cũ cho hợp trào lưu AI như thể nó là điều mới mẻ, mà là cho thấy bằng luận cứ rằng những best practice hơn 20 năm tuổi vẫn còn giá trị
    • Khác biệt lớn giữa trước và sau AI là con người có năng lực quản lý ngữ cảnh dài hạn khá tốt
      Agent phải tiếp thu lại ngữ cảnh ở mỗi phiên, nên giá trị của các best practice lớn hơn nhiều và hiệu quả cũng xuất hiện ngay lập tức
    • Nhờ cơn sốt AI, các công việc cải thiện trải nghiệm lập trình viên mà mình mong muốn đã có thể xin được ngân sách, nhưng thật chua chát khi lý do lại sai
      Dù vậy, việc có thể cho CLI chạy 100 lần trong một giờ để thử độ dễ dùng của flag mới cũng rất hay
    • Con người vẫn bằng cách nào đó tạo ra kết quả giữa đống tài liệu cũ kỹ trên SharePoint, bối cảnh tổng thể nghe lỏm trong các cuộc họp, và mức ưu tiên refactor thấp, dù chất lượng và tiến độ bị ảnh hưởng
      Ngược lại, nếu không có nền tảng như vậy, AI sẽ làm rất tệ hoặc hoàn toàn không hoạt động, nên các thực hành kỹ thuật lành mạnh không còn là biện pháp cải thiện dài hạn mà trở thành điều kiện tiên quyết bắt buộc
      Ngay cả khi hiệu quả ròng thực tế bằng không, việc đưa AI vào workflow vẫn hữu ích ở chỗ nó tạo ra lý do chính đáng để áp dụng các thực hành phát triển đúng đắn
  • Mình thích ở bài viết này là nó phê phán cụ thể và có định lượng dựa trên cách các công cụ AI thực sự được sử dụng
    Những bài cho thấy bằng số đo rằng AI không làm được gì hữu ích hơn nhiều so với các bài mơ hồ bàn về rủi ro xã hội mà không có ca sử dụng thực tế
    Cũng vì lý do đó, báo cáo phỏng vấn các thành viên Boko Haram để tìm hiểu AI đã được dùng trong khủng bố như thế nào cũng rất ấn tượng

  • Mình thật sự thích tự làm refactoring mà không dùng AI
    Không có thay đổi nhìn thấy được, nhưng cảm giác rất thỏa mãn khi khiến một website chưa thể hiện kết quả ngay lúc này trở nên dễ xử lý hơn nhiều trong tương lai
    Quá trình tìm ra những đoạn mã vòng vèo kỳ quặc trong quá khứ đang giải lại các vấn đề vốn đã có pattern chuẩn, rồi chuyển chúng về phía best practice mà không tạo thêm nợ kỹ thuật mới, thú vị như giải đố
    Mình đã tự triển khai mọi thứ một cách cẩu thả, kể cả xác thực, để học nguyên lý bên trong theo cách khó, và kết quả là cũng có thêm cả đống thứ để refactor trong 10 năm tới

    • Sau khi đọc 《Refactoring》 của Fowler, mình từng nghi ngờ liệu nó có hiệu quả với code khoa học/nghiên cứu không, nhưng sau khi thử áp dụng vào một cấu trúc code gây khó chịu thì quan điểm đã thay đổi hoàn toàn
      Mình hiểu cụ thể hơn câu nói codebase là một hệ thống, và bắt đầu nhìn code ở cấp độ cao hơn như một tổ chức hay tấm lưới liên tục mà có thể kéo và nén
      Việc AI có thể loại bỏ quá trình học này làm nổi bật vấn đề của lập trình viên junior. Muốn có trực giác thì chỉ còn cách tự đào sâu trực tiếp, và dù Naur đã cảnh báo 40 năm trước, bài học này vẫn cứ bị lãng quên
    • Có lẽ vì nó đem lại phần thưởng dopamine giống như khi nhìn màn hình chống phân mảnh ổ đĩa trên Windows 98
    • Cảm xúc đó là niềm tự hào của người thợ thủ công. Với người hiểu thì không cần giải thích, còn với người không hiểu thì giải thích thế nào cũng không thông
    • Mình tò mò trong quá trình refactor, họ đã xây dựng test suite đến mức nào như một lớp bảo vệ để tránh regression
    • Quá trình học nhiều pattern refactoring và các ví dụ áp dụng thực tế rất thú vị
  • Tôi cho rằng khi agent thực hiện refactoring thì sự tham gia của con người là điều thiết yếu
    Mô hình sinh có thể tập trung vào công việc ban đầu, còn mô hình rà soát có thể tìm ra những phần bị bỏ sót, nhưng vẫn đáng nghi ngờ liệu chúng có thực sự hiểu mục đích của toàn bộ dự án và cách mã kết hợp với nhau để nhận ra trùng lặp hoặc một cấu trúc thanh nhã hơn hay không
    Giao việc refactoring cho coding agent cũng giống như nhờ bác sĩ phẫu thuật chấn thương cải thiện năng lực vận động; muốn làm đúng cần có góc nhìn toàn diện
    Chỉ chia một file lớn thành nhiều file chỉ dừng ở refactoring bề mặt. Nếu không có lý thuyết về đoạn mã nào nên ở cùng nhau và cái gì nên được tách thành hàm utility, thì đó không phải là phân tích thừa số, mà gần giống việc tách một số lớn thành các số nhỏ rồi cộng lại
    Agent đôi khi tạo ra hệ thống lưu lại và tính toán lại những giá trị vốn đã lấy từ API, còn con người có thể nhìn toàn bộ dự án và xác định chính xác rằng dữ liệu cần thiết đã có trong một khóa cụ thể của JSON

    • LLM hiện nay cũng làm khá tốt nếu được chỉ dẫn một refactoring cụ thể cho một vùng mã cụ thể. Chẳng hạn, chúng có thể xử lý cả yêu cầu phức tạp như triển khai Command pattern bằng functools.partial thay vì data class
      Khái niệm rằng ranh giới file biểu thị ranh giới của các hệ thống con logic, giúp suy luận dễ hơn, và nội dung của các file khác mặc định được xem là mờ đục, cũng có rất nhiều trong dữ liệu huấn luyện
      Tôi cho rằng lợi ích của cấu trúc này không chỉ là đặc tính ngẫu nhiên của nhận thức con người, mà còn có khía cạnh khách quan
    • Với cách con người đứng bên cạnh giải thích hướng đi, phần lớn một đợt refactoring vốn mất vài tháng đã hoàn tất trong khoảng một tuần
      Kinh nghiệm refactoring, cách từng xử lý codebase của người khác, và việc có thể giải thích ý định trước đây lẫn hiện tại với tư cách nhà thiết kế ban đầu đã giúp ích
      Đó là một ngôn ngữ ít phổ biến, ít điểm yếu về dependency và dễ để LLM xử lý; sau khi loại bỏ thiên kiến về JavaScript và Python, tốc độ làm việc tăng lên đáng kể
      Đây là một dự án JSR-223 viết script bằng nhiều ngôn ngữ phổ biến, nhưng tất cả đều chạy trên JVM theo yêu cầu môi trường: https://en.wikipedia.org/wiki/Scripting_for_the_Java_Platform
    • Nhận định rằng agent không thể refactor đã lỗi thời; hiện nay chúng rất giỏi
      Trong thị trường tuyển dụng này, cần sử dụng coding agent dựa trên các frontier model mới nhất và hiểu chính xác năng lực cũng như giới hạn của chúng; nếu đưa ra đánh giá ngược lại trong phỏng vấn, đó có thể là lý do bị loại
  • Ngữ cảnh súc tích không chỉ giảm tiêu thụ token mà còn cải thiện suy luận, cho phép đưa nhiều tầng hơn vào cùng một ngữ cảnh và xử lý chúng một cách thông minh
    Refactoring hướng tới các abstraction tốt tạo ra phần mềm tổng quát hóa tốt hơn, có khả năng đúng không chỉ trong các trường hợp đã kiểm thử mà cả các trường hợp nội suy và ngoại suy
    Có lý thuyết thông tin và toán Bayes hậu thuẫn điều này, và việc phần mềm hiệu quả hơn về kinh tế và năng lượng lại chính xác hơn trông như một sự trùng hợp tinh tế
    Cốt lõi là giảm entropy của mã

    • Ở bất cứ đâu trong thế giới và vũ trụ, giảm entropy đều có thể được xem là hành động xây dựng một thứ gì đó
    • Nếu loại bỏ khả năng đọc hiểu của con người khỏi mục tiêu và chỉ lấy giảm tiêu thụ token làm hàm mục tiêu, rất khó biết sẽ đi đến đâu
      LLM vốn đã suy luận ý nghĩa khá tốt ngay cả với ít ngữ cảnh
  • Việc bài viết đưa ra dữ liệu là điều thú vị, và phù hợp với cảm nhận của tôi rằng LLM hưởng lợi rất lớn từ mã được tách biệt tốt, nhưng bản thân chúng không đặc biệt giỏi tạo ra loại mã như vậy
    Phần lớn lập trình viên con người có lẽ cũng tương tự

    • Tôi đang đưa riêng thời gian dọn mã lộn xộn vào ngân sách, và hiện cũng đang làm việc đó ngay ở cửa sổ bên cạnh
      Nhìn chung lợi ích từ AI là lớn, nhưng cũng cần thời gian dọn dẹp, và tôi cho rằng vẫn phải đọc từng dòng
      Để không chặn tiến độ của các nhóm khác, tôi đã hoãn một phần review và về sau đang phải trả một khoản technical debt lớn hơn bình thường, nhưng việc gỡ nút thắt trước là đáng giá
      AI khiến việc vay technical debt dễ hơn theo mọi nghĩa, và nếu được hướng dẫn tốt thì cũng khá giỏi xử lý nợ. Tuy vậy, kết quả tùy từng người: https://news.ycombinator.com/item?id=49035455
    • Ở trạng thái mặc định tôi cũng thấy kết quả tương tự, nhưng nếu định hướng refactoring cụ thể thì có thể khiến nó tạo ra mã được tách biệt tốt hơn
      Việc cho xem ví dụ về mã được tổ chức tốt hoặc các kho mã nguồn mở để minh họa điều nên làm và không nên làm giúp ích rất nhiều
  • Phần lớn lợi ích kinh tế của refactoring đến từ việc con người hiểu hệ thống tốt hơn, chứ không phải tiết kiệm token
    Có thể xử lý cuộc gọi sự cố lúc 3 giờ sáng nhanh hơn, giảm lỗi lọt vào môi trường vận hành, và ra mắt nhanh hơn đối thủ
    Quan trọng nhất, khi hiểu hệ thống, người ta sẵn lòng nhận trách nhiệm và quyền sở hữu hơn, nên khi có vấn đề sẽ sửa nhanh hơn và cũng chủ động lao vào những phần cần cải thiện

  • Ý chính là refactoring làm giảm tiêu thụ token, và việc định lượng hiệu quả thay vì chỉ bàn trừu tượng là điểm tốt
    Nhưng Fowler đã nói trong cuốn 《Refactoring》 rằng điều kiện tiên quyết thiết yếu của refactoring là bộ test vững chắc, và tôi cho rằng lợi ích thật sự, không phụ thuộc AI, nằm ở đây
    Test tốt ngăn hồi quy do con người hoặc robot tạo ra, đồng thời để lại đặc tả dưới dạng mã mà cả hai bên đều có thể đọc: https://www.oreilly.com/library/view/refactoring-improving-the/9780134757681/

    • Bài viết được đăng trên martinfowler.com nhưng không phải do Martin viết; tác giả được ghi là Giles Edwards-Alexander, CTO của Thoughtworks
    • Điểm cốt lõi thực ra là số tiền tiết kiệm chỉ ở mức vài chục cent
      Nếu tính giá Sonnet 5 là 3 USD mỗi MTok, khoản tiết kiệm cho những thay đổi tương lai đụng đến tầng truy cập dữ liệu là 39,7 cent
      Xét đến việc OpenAI giảm giá, các mô hình mở, và xu hướng giá token dài hạn đi xuống, khoản này có thể không tương xứng với chi phí để một senior developer khoảng 100 USD/giờ hướng dẫn refactoring
  • Mã do agent tạo ra đã trở thành một khối khổng lồ đến mức chỉ agent mới có thể đọc và hiểu được; điều quan trọng không phải đó là tính năng, lỗi hay thuộc tính nổi lên, mà là chính thực tế này
    Để xử lý mã được tạo bằng công cụ AI, chúng ta lại đang phụ thuộc vào công cụ AI
    Tuy nhiên con người vốn cũng đã tạo ra những tệp khổng lồ kinh khủng và monorepo, và nhờ LLM, việc chỉnh sửa cũng như refactor chúng cuối cùng mới trở nên có thể kham nổi
    Trong tình huống codebase đã quá lớn và lộn xộn để con người hiểu được, LLM có thể cứu chúng ta; cá nhân tôi ghét các tệp khổng lồ, nhưng thật cay đắng là các nguyên tắc dọn dẹp kiểu Fowler có thể không còn quan trọng nữa

    • Nói rằng mã của agent chỉ agent mới hiểu được về cơ bản là không đúng; nếu bạn cảm thấy như vậy thì đó là do dùng LLM sai cách
    • Mã tệ vốn đã tồn tại từ trước, nhưng AI là một vấn đề mới ở chỗ nó làm phạm vi thiệt hại của việc tuyển sai người tăng lên 1.000 lần
      Ngay cả một nhân viên ở mức trung bình, hoặc thỉnh thoảng làm tốt, trước đây không thể làm một số việc vì quy trình công ty, nay có thể thực hiện chúng nhanh như chớp, và vì thế lại bị biến thành một nhân viên tệ
    • Tôi từng không gặp vấn đề gì khi đọc hoặc tìm vị trí mong muốn trong một codebase do LLM viết 100%, và nó cũng không khó hơn so với khi tự mình viết
    • Tôi chưa từng thấy mã do agent tạo ra tệ hơn thứ mã tệ nhất do con người viết
      Nếu agent tạo ra tệp hoặc hàm khổng lồ, chỉ cần bảo nó đừng làm vậy là nó sẽ làm theo
  • Tôi xem refactoring là một trong những dấu hiệu tốt nhất của một đội ngũ phát triển lành mạnh
    Bản thân refactoring cũng có lợi ích, nhưng giá trị đó thường không dễ thấy với người phụ trách sản phẩm hay trong bảng công việc tính năng
    Nếu đội ngũ refactor vì sức khỏe tổng thể của phần mềm, điều đó có nghĩa là các nhà phát triển có thể thoải mái đề xuất những việc tốt cho phần mềm, và các đề xuất đó được xem xét nghiêm túc
    Sự mục ruỗng của phần mềm trở nên tệ nhất khi đội ngũ không có động lực hoặc thẩm quyền để hiện thực hóa tầm nhìn về phần mềm chất lượng cao; nếu đội ngũ có thể làm theo phán đoán của mình về sự xuất sắc thì nhìn chung đó là tín hiệu tốt
    Tất nhiên cũng có những trường hợp thái quá như viết lại toàn bộ từ Ruby, Node, Rust rồi lại sang công nghệ thân thiện với agent, nhưng trong môi trường doanh nghiệp, việc các đội ngũ cảm thấy mình không được phép cải thiện phổ biến hơn nhiều