help.autocorrect=1 của Git sửa lệnh gõ sai rồi chỉ chờ 0,1 giây trước khi chạy, gần như là chạy ngay lập tức nên người dùng khó kịp xác nhận hoặc hủy
- Hành vi này không phải mặc định của Git; ở cấu hình mặc định, Git không chạy lệnh không xác định mà chỉ hiển thị các lệnh tương tự rồi thoát
- Trong cuộc thảo luận năm 2008,
help.autocorrect đã được đổi từ kiểu boolean sang thời gian chờ tính bằng decisecond, khiến 1 được hiểu là chờ 0,1 giây thay vì true
- Hiện
help.autocorrect hỗ trợ 0, số dương, immediate, prompt, never; nếu muốn xác nhận rồi mới chạy thì prompt là lựa chọn an toàn hơn
- Cơ chế suy đoán lệnh của Git dựa trên Levenshtein distance đã chỉnh sửa, và Scott Chacon đã đề xuất một bản vá để xử lý
1 cùng các chuỗi boolean theo cách tự nhiên hơn
Từ git pushy đến khi được chạy thành git push
- Khi
@dhh nhập git pushy, Git suy đoán đó là git push và chỉ chờ 0,1 giây trước khi chạy
- 0,1 giây là quá ngắn để người dùng đọc lệnh, đánh giá xem có đúng hay không, rồi hủy
- Hành vi này không phải hành vi mặc định của Git, mà xuất hiện khi cấu hình
help.autocorrect được bật
Hành vi mặc định và sự ra đời của help.autocorrect
- Phản ứng mặc định của Git là không chạy lệnh không xác định, mà hiển thị các lệnh khả dĩ dựa trên độ tương đồng chuỗi rồi thoát
- Ví dụ:
git pushy có thể được hiển thị là push, lệnh giống nhất
- Ban đầu, với lệnh không xác định, Git chỉ trả lời đơn giản rằng “không phải lệnh Git”
- Năm 2008, Johannes Schindelin đề xuất một bản vá nhỏ: duyệt qua các lệnh đã biết để tìm lệnh giống nhất, và nếu chỉ có một ứng viên gần thì chạy lệnh đó
- Alex Riesen đưa ra bản vá điều khiển việc này bằng cấu hình
help.autocorrect; ban đầu cấu hình này là boolean
- Trong cấu hình Git, giá trị boolean có thể hiểu
1 là true
- Vì vậy, trong bối cảnh ban đầu,
help.autocorrect=1 có thể trông giống như giá trị bật tự động sửa
Vì sao 1 trở thành 0,1 giây
- Junio Hamano đề xuất không để
help.autocorrect chỉ là boolean đơn giản, mà biến nó thành số decisecond cần chờ trước khi chạy
- Decisecond là đơn vị 0,1 giây
- Mục đích là cho người dùng cơ hội nhấn
^C
- Trong bản vá được chấp nhận sau đó, giá trị cấu hình được đổi thành thời gian chờ
- Kết quả là
help.autocorrect=1 không có nghĩa là “bật tính năng”, mà là “chờ 1 decisecond, tức 0,1 giây, rồi chạy”
- Lý do decisecond được chọn làm đơn vị thời gian phù hợp không còn được ghi lại trong cuộc thảo luận
Các giá trị cấu hình có thể chọn hiện nay
- Theo tài liệu Git,
help.autocorrect hỗ trợ các giá trị sau
0: giá trị mặc định, chỉ hiển thị lệnh được đề xuất
- Số dương: chạy lệnh được đề xuất sau số decisecond đã chỉ định
immediate: chạy ngay lệnh được đề xuất
prompt: hiển thị đề xuất và hỏi xác nhận có chạy hay không
never: không chạy và cũng không hiển thị lệnh được đề xuất
- Nếu muốn xác nhận rồi mới chạy,
prompt hợp lý hơn với hầu hết người dùng
- Ví dụ cấu hình như sau
git config --global help.autocorrect prompt
- Sau đó, khi nhập lệnh như
git pushy, Git sẽ hỏi bằng [y/N] xem có chạy push hay không
Cách Git chọn lệnh tương tự
- Git không đoán lệnh một cách tùy tiện; đến một ngưỡng nào đó, nó coi là quá xa và không đưa ra ứng viên
- Hành vi ví dụ như sau
git bass đủ gần với rebase nên sẽ hiện xác nhận chạy
git bassa bị xem là không còn giống rebase nữa, nên không chạy ứng viên nào
git dm hiển thị cả am và rm là các lệnh tương tự
git dma khớp với một lệnh duy nhất là am
- Logic này dựa trên thuật toán Levenshtein distance đã chỉnh sửa
- Thuật toán tính chi phí chỉnh sửa ký tự để biến một chuỗi thành chuỗi khác
- Một số thao tác được tính là tốn kém hơn các thao tác khác
- Git có cutoff được hard-code; nếu chi phí so với lệnh đã biết quá lớn, Git xem đó là người dùng đã nhập sai quá nhiều và không suy đoán
Bản vá nhằm thay đổi cách diễn giải 1
- Vì
help.autocorrect=1 về mặt con người gần như tương đương immediate, Scott Chacon đã viết một bản vá nhỏ để hiểu 1 là chạy ngay thay vì chờ 0,1 giây
- Junio Hamano yêu cầu không chỉ xử lý đặc biệt riêng
"1", mà phải diễn giải đúng các giá trị chuỗi boolean như yes, no, true, off
- Phiên bản thứ hai của bản vá đang được phát triển theo hướng bao gồm cả việc xử lý các chuỗi boolean này
- Nếu bản vá được đưa vào, sự nhầm lẫn quanh
help.autocorrect có thể giảm trong các phiên bản Git tương lai
1 bình luận
Ý kiến trên Hacker News
Vào thập niên 70, Hal Finney đang nhét trình thông dịch BASIC cho Mattel Intellivision vào ROM 2KB, nên từng byte đều quý giá
Để hiển thị lỗi cú pháp, ông rút gọn mọi thông báo lỗi thành
EH?, và đến giờ vẫn buồn cười ở chỗ chính ông khá tự hào về điều đóEH?có vẻ cũng rất hợp làm phản hồi của bộ phân tích cú pháp văn bản trong các trò interactive fiction kiểu cũHơi liên quan một chút, trong vài biến thể BASIC ngày xưa cũng có thể viết câu lệnh
PRINTthành?, nhưng có lẽ mục đích gần với việc giảm thời gian gõ trong REPL hơn là tiết kiệm bộ nhớedchỉ dùng một dấu?cho mọi lỗi, nên tiết kiệm gấp 3 lầnEh?làm phản hồi của trình thông dịch là trong JOSS của RAND[https://en.wikipedia.org/wiki/JOSS#/media/File:JOSS_Session....](https://en.wikipedia.org/wiki/JOSS#/media/File:JOSS_Session.jpg)
https://en.wikipedia.org/wiki/JOSS
Bộ nhớ khoảng 5KB, nhưng so với Intellivision thì cái máy nặng khoảng 5.000 pound
Vì vậy có thể bạn đoán một từ và cả 5 chữ cái đều xanh, nhưng nó vẫn không phải là một trong hai đáp án. Khi đó tôi cho hiện đơn giản
Huh?ở bên phải, và mọi người thích chi tiết đóNguyên nhân gốc rễ là tên cấu hình được đặt tệ
Nếu ban đầu cấu hình được đặt kiểu boolean như
help.autocorrect_enabled, thì yêu cầu cho nó nhận giá trị số nguyên rồi diễn giải theo đơn vị 0,1 giây đã không hợp lý. Thay vào đó hẳn cần một cấu hình khác nhưhelp.autocorrect_accept_after_dsec, và vìdsecquá lạ nên ai dùng cũng buộc phải traKhi review code tôi luôn yêu cầu điều này. Nếu có thể mơ hồ, tên biến phải có đơn vị. Ví dụ
int timeoutnên làint timeout_msecVới tên cấu hình, điều này còn quan trọng gấp 100 lần. Vì cấu hình là một phần của giao diện công khai nên về sau không thể đổi
Trong bối cảnh C++, tiêu chí đại khái là
void FooBar(std::chrono::milliseconds timeout);thì ổn. Vì đó là chữ ký hàm, khi nhìn vào cũng thấy luôn kiểuNhưng với biến thì
timeoutkhông ổn. Trong 99% trường hợp, lúc sử dụng thực tế ta sẽ thấy kiểu nhưauto timeout = gl_timeout;hoặcFooBar(timeout);Vì C++ dùng
autophổ biến, việc lần theo kiểu chính xác khi quan trọng trở nên khá phiềnKhi làm C++ tôi có dùng IDE hoặc trình soạn thảo gắn language server, nhưng không có thời gian cứ 5 giây lại rê chuột lên để kiểm tra kiểu
Nếu thấy thông báo “sẽ chạy sau 1ms” thì hẳn họ đã kiểm tra lại cấu hình ngay
TimoutSec=60lẫnTimeoutSec=1minTôi nghĩ thà đừng đưa đơn vị vào tên còn hơn. Dù vậy, ngoài trường hợp đặc biệt đó ra thì tôi hoàn toàn đồng ý
Phương án tốt nhất tôi tìm được đến giờ là để giá trị nhận kèm đơn vị. Ví dụ cho phép
5 secondshoặc5s, còn chỉ1thì coi là giá trị saiintnhư vậy và khuyến nghị dùng lớp giá trị truyền đơn vị đúng cáchVí dụ như
Second(2)hoặcMillisecond(2000)Tất nhiên điều này tùy vào tính năng và quy ước của ngôn ngữ
xmobar cũng dùng đơn vị 0,1 giây ở một chỗ tương tự nhưng còn có vấn đề hơn. Đó là cấu hình khai báo mỗi section nên được làm mới thường xuyên ra sao
Các con số trong cấu hình ví dụ nhỏ đến mức khó có thể là mili giây, nên khiến người ta hợp lý giả định là giây, và kết quả là lệnh bị chạy thường xuyên gấp 10 lần dự định
Tôi đã thấy nhiều lần tải tăng đột biến ngoài ý muốn bắt nguồn từ vấn đề này
Có vẻ là thiết kế khá tệ
Tuy nhiên điểm 1 là do đọc nhầm bài, và “giá trị trước đó” chưa từng tồn tại trong git
1=truethành1=độ trễ xác nhận 0,100ms. Nếu từng có giá trị cũ thì có thể muốn xóa, nhưng đúng ra cũng nên đổi cả tên cấu hìnhhelp.autocorrectlà thời gian, lại được đo bằng một đơn vị không chuẩn với đa số người dùng, đơn giản là tệ. Nên nhận boolean cho việc bật tính năng, và cho chỉnh thời gian xác nhận bằng giá trị thập phânThay đổi đó diễn ra năm 2008, trong quá trình review code của bản vá ban đầu định thêm tùy chọn này dưới dạng boolean, và trước khi nó được commit vào cây git chính
Cái này giống một nhánh phụ mọc lên hữu cơ hơn là thiết kế
Tôi xem đây là một ví dụ hay về chủ nghĩa nhồi nhét tính năng (creeping featurism)
Nhìn tích cực thì nó đưa vào độ phức tạp không cần thiết; nhìn tiêu cực thì khiến những người phụ thuộc vào nó bớt cẩn trọng về việc mình đang làm
Nhấn mũi tên lên rồi sửa lỗi khó đến thế sao? Tự động chạy thứ “đại khái đúng” là công thức dẫn tới việc làm điều ngoài ý muốn
Sai lầm nằm ở đây. Đáng lẽ không nên tái sử dụng cấu hình cũ với ý nghĩa khác, mà phải thêm cấu hình mới
help.autocorrectnên được tách thành bật/tắt, cònhelp.autocorrect.millisecondslà chờ bao lâuCác hệ thống khác cũng có lỗi tương tự. Ví dụ
innodb_flush_log_at_trx_commitcủa MySQL: 0 là vô hiệu hóa, 1 là bật, và 2 được thêm sau đó với một ý nghĩa đặc biệt1nghĩa là gìGiờ thì
1vẫn là boolean đúng, còn các số nguyên khác lại được tính theo đơn vị 0,1 giây, khiến mọi thứ càng lún sâu hơnĐây là kiểu logic đáng ngờ giống như
no == falsekhét tiếng của YAMLTheo ghi nhận, thời gian phản ứng ngẫu nhiên nhanh nhất khoảng 1,5ds, và tình cờ thời gian phản ứng trung bình của game thủ cũng tầm đó, nhưng phản ứng không ngẫu nhiên có thể nhanh hơn nhiều. Ví dụ như phản ứng theo nhịp
Nếu muốn nhanh đến mức đó thì vẫn có thể, và tốc độ gọi lệnh cũng phải tương đối ổn định. Có lẽ ở mức vài mili giây
Một năm trước tôi bật tính năng tự sửa và đặt thành 3 giây, rồi nhận ra hai điều
Đọc bài này xong thì sau một năm tôi đã có đủ lý do để tắt nó
Tất nhiên như vậy cũng sẽ “làm bẩn” lịch sử shell
Quay lại lịch sử rồi dùng lại nguyên lệnh sai cuối cùng chỉ vì dù sao nó cũng chạy được thì cũng như vậy thôi
Đơn vị 0,1 giây thật sự là một lựa chọn kỳ lạ
Độ trễ nên được chỉ định bằng mili giây hoặc giây, cả hai đều phổ biến hơn nhiều trong điện toán
decisecondslà đơn vị riêng của git, nghĩa là decision-seconds kiểu “số giây cần để đưa ra quyết định” xDNhân tiện, tiếng Anh không phải tiếng mẹ đẻ của tôi, nhưng tôi đến từ một vùng văn minh dùng hệ mét
Chênh lệch giữa 0 giây và 1 giây đủ dài để nhận thấy khi chờ đợi điều gì đó, còn chênh lệch giữa n mili giây và n+1 mili giây thì quá nhỏ để hữu ích
Thời gian phản ứng khác nhau tùy loại kích thích; thính giác hơi nhanh hơn thị giác, còn xúc giác nhanh hơn chút nữa, vào khoảng 90~180ms
Vì vậy nếu git đấm bạn một cái thay vì hiện thông báo lỗi, có khi bạn vẫn vừa kịp phản ứng
10ms liệu có đủ không?
Đọc bài này làm tôi nhớ đến khảo cổ học phần mềm và cụm “lập trình viên khảo cổ”
Khái niệm sau thì phải cảm ơn Vernor Vinge
Nhưng khái niệm đó chỉ được gợi ý thoáng qua trong phần mở đầu, rồi sau đó hoàn toàn biến mất. Tác động của khảo cổ học có liên quan đến cốt truyện, nhưng “nhà khảo cổ phần mềm” không phải là nhân vật có ý nghĩa trong tự sự
Tôi có cảm giác như bị câu view