08/10/2026 · VietTechies · Biên tập

Năm 1968, một nhà khoa học máy tính người Hà Lan gửi qua bưu điện một bài viết ngắn tới tạp chí Communications of the ACM. Ông đặt tên cho nó là “A Case against the GO TO Statement” (tạm dịch: Lý lẽ chống lại lệnh GO TO).
Không ai nhớ đến cái tên đó cả.
Biên tập viên Niklaus Wirth muốn đăng bài thật nhanh. Cách nhanh nhất là đăng nó dưới dạng thư gửi ban biên tập, và trong quá trình ấy, tựa bài đã bị đổi. Bài xuất hiện trên số tháng 3/1968, ở trang 147 và 148, với cái tên “Go To Statement Considered Harmful” (Lệnh Go To bị xem là có hại).
Tác giả là Edsger W. Dijkstra. Hơn ba thập kỷ sau, ông nhận xét một cách khô khan rằng bức thư chủ yếu được những người chỉ đọc mỗi cái tựa trích dẫn. Chính cái tựa ấy lại trở thành một khuôn mẫu. Từ đó đến nay, cụm “X considered harmful” đã bị gắn vào gần như mọi thứ trong ngành máy tính.
Một bài viết nổi tiếng nhầm chỗ
Cái tựa mới khiến bức thư nghe như một lệnh cấm. Nhưng lập luận bên trong lại nói về một chuyện khác: cách con người tư duy.
Dijkstra mở đầu bằng một nhận xét mà ông nói mình đã giữ trong nhiều năm: chất lượng của lập trình viên là “một hàm giảm theo mật độ lệnh go to trong các chương trình họ viết ra”. Rồi ông thử giải thích vì sao.
Câu trả lời của ông không nằm ở phong cách hay sở thích. Nó nằm ở khoảng cách giữa chương trình dưới dạng văn bản và chương trình dưới dạng một tiến trình. Khi đọc code, bạn thấy một thứ tĩnh. Khi chạy, nó trở thành một chuỗi sự kiện diễn ra theo thời gian. Dijkstra viết rằng “năng lực trí tuệ của chúng ta vốn thiên về việc làm chủ các quan hệ tĩnh”, còn khả năng hình dung các tiến trình diễn biến theo thời gian thì “tương đối kém phát triển”.
Vì vậy, theo ông, việc của lập trình viên là “thu hẹp khoảng cách khái niệm giữa chương trình tĩnh và tiến trình động”. Văn bản chương trình phải giúp người đọc dễ dàng biết mình đang ở đâu trong chương trình đang chạy.
Lệnh goto thực sự phá vỡ điều gì
Đây là chi tiết cụ thể mà một developer có thể kể lại cho đồng nghiệp. Với các câu lệnh tuần tự, lựa chọn if/else và vòng lặp, bạn có thể mô tả chương trình đang ở đâu chỉ bằng một bộ tọa độ nhỏ: bạn đang ở dòng nào, đã đi vào nhánh nào, và mỗi vòng lặp bao quanh đã chạy bao nhiêu lần. Mô tả đó vẫn giữ nguyên ý nghĩa khi bạn đọc code từ trên xuống dưới.
Một lệnh goto không bị giới hạn sẽ phá hủy điều đó. Một khi luồng điều khiển có thể nhảy đi bất cứ đâu, vị trí trong văn bản gần như không cho bạn biết mình đã đến đó bằng cách nào. Để hiểu một giá trị tại một dòng nào đó, có thể bạn phải dựng lại mọi đường đi có khả năng dẫn tới nó. Phán quyết của Dijkstra rất thẳng thừng: goto “quá dễ mời gọi người ta làm rối tung chương trình của mình”.
Ông thực sự muốn loại bỏ nó. Bức thư kết luận rằng lệnh go to nên bị bãi bỏ khỏi mọi ngôn ngữ lập trình “bậc cao”. Nhưng lý do nằm ở khả năng suy luận, chứ không phải ở luật lệ.
Ông không phải người đầu tiên, và chính ông nói vậy
Một phiên bản kể lại phổ biến biến Dijkstra thành nhà tiên tri đơn độc. Chính văn bản của ông thì không nói thế.
Ông ghi công Heinz Zemanek, người đã đặt câu hỏi về goto tại một cuộc họp tiền ALGOL ở Copenhagen năm 1959. Ông viết rằng mình “không phải không chịu ảnh hưởng” của Peter Landin và Christopher Strachey. Ông ghi nhận Tony Hoare và Wirth về câu lệnh case, và nhắc tới một bài báo năm 1966 của Corrado Böhm và Giuseppe Jacopini, mà theo lời ông, dường như đã chứng minh rằng goto là thừa về mặt logic.
Rồi ông thêm một lời cảnh báo dễ bị bỏ qua. Việc viết lại một cách máy móc một lưu đồ rối rắm thành lưu đồ không có lệnh nhảy, như kết quả của Böhm–Jacopini cho phép, là điều “không nên khuyến khích”. Gỡ bỏ goto một cách cưỡng ép vẫn có thể để lại thứ code không ai lần theo nổi. Điều quan trọng là một cấu trúc mà bạn có thể suy luận được, chứ không phải việc vắng bóng một từ khóa.
Làn sóng phản đối
Bức thư gây chấn động. Donald Knuth sau này viết rằng Dijkstra từng kể với ông là mình đã nhận được “một cơn lũ thư lăng mạ”.
Tháng 12/1974, Knuth công bố một bài báo dài với cái tựa cố tình khiêu khích: “Structured Programming with go to Statements” (Lập trình có cấu trúc với lệnh go to). Ông thấy cả hai phía đều có điểm đúng. Ông chỉ ra những trường hợp, như thoát ra khi gặp lỗi và một số kiểu vòng lặp, mà một lệnh nhảy có kỷ luật có thể rõ ràng hơn hoặc nhanh hơn các phương án khác, và ông đề xuất những cấu trúc ngôn ngữ tốt hơn để xử lý chúng. Cũng chính bài báo này chứa câu nói về sau còn nổi tiếng hơn cả cái tựa của Dijkstra: “tối ưu hóa quá sớm là cội nguồn của mọi tội lỗi”.
Cuộc tranh cãi chưa bao giờ kết thúc hẳn. Tháng 3/1987, một độc giả tên Frank Rubin đăng bài “‘GOTO Considered Harmful’ Considered Harmful” trên cùng tạp chí, đưa ra một bài toán lập trình nhỏ mà ông cho là sẽ gọn gàng hơn nếu dùng goto. Năm phản hồi nối tiếp nhau. Dijkstra viết một ghi chú gọi cả cuộc trao đổi là “một sự thất vọng”. Ông chỉ ra rằng một trong các phiên bản của Rubin chạy sai khi đầu vào rỗng, rồi giải bài toán bằng các vòng lặp lồng nhau.
Điều gì thực sự chiến thắng
Nếu hôm nay bạn viết code, phần lớn thời gian bạn đang sống trong thế giới của Dijkstra mà không hề nhận ra. Vòng lặp, hàm, return sớm, break và continue, exception: tất cả đều là những dạng nhảy có cấu trúc, có tên gọi. Chúng cho bạn quyền điều khiển cần thiết, trong khi vẫn giữ văn bản chương trình là một tấm bản đồ đáng tin cậy của tiến trình đang chạy.
Bản thân goto không biến mất. Tài liệu coding style của Linux kernel khuyến nghị dùng nó trong một trường hợp cụ thể: “khi một hàm thoát ra từ nhiều vị trí và cần làm một số việc chung như dọn dẹp”. Đó chính là kiểu sử dụng có kỷ luật, dễ đọc mà Knuth bảo vệ năm 1974. Nó cũng nhất quán với mối bận tâm thực sự của Dijkstra, vì một lệnh nhảy duy nhất, được đặt tên rõ ràng, tới một khối dọn dẹp không che giấu việc chương trình đã đi qua những đâu.
Bài học đằng sau cái tựa
Có ba điều đáng giữ lại từ câu chuyện này.
- Phiên bản nổi tiếng không phải lúc nào cũng là phiên bản của tác giả. Chính cái tựa của biên tập viên, chứ không phải của Dijkstra, đã định hình cách hàng triệu lập trình viên ghi nhớ lập luận này.
- Tranh cãi về cú pháp thường là tranh cãi về cách suy luận. Điều Dijkstra quan tâm là liệu người đọc có thể đoán được trạng thái của chương trình từ văn bản của nó hay không.
- Quy tắc sống lâu hơn lý do sinh ra nó. “Đừng bao giờ dùng goto” đã trở thành khẩu hiệu. “Hãy làm cho luồng điều khiển dễ theo dõi” mới là nguyên tắc gốc.
Cuộc tranh cãi này chưa bao giờ thực sự là chuyện giành phần thắng cho một quy tắc. Nó là chuyện giữ cho code dễ hiểu với những người phải đọc nó.
Vậy nên lần tới, khi bạn thêm một flag, một callback hay một event khiến luồng điều khiển nhảy tới một nơi không ngờ, hãy tự hỏi câu hỏi của Dijkstra: người đọc dòng này có còn biết chương trình đã đến đây bằng cách nào không?
Đọc bằng ngôn ngữ khác: English · Español · Deutsch · Français · Português (Brasil) · Tiếng Việt
Nguồn
- E. W. Dijkstra, EWD215: “A Case against the GO TO Statement” (bản thảo của bức thư năm 1968), Kho lưu trữ E. W. Dijkstra, Đại học Texas tại Austin
- E. W. Dijkstra, EWD1308: “What led to ‘Notes on Structured Programming'” (2001)
- E. W. Dijkstra, EWD1009: “On a somewhat disappointing correspondence” (1987)
- D. E. Knuth, “Structured Programming with go to Statements,” ACM Computing Surveys 6(4), tháng 12/1974
- Wikipedia: “Considered harmful” (thông tin xuất bản của các bức thư năm 1968 và 1987)
- Hướng dẫn coding style của Linux kernel: “Centralized exiting of functions”
- Ảnh đại diện: Edsger Dijkstra giảng bài tại ETH Zurich năm 1994. Andreas F. Borchert, qua Wikimedia Commons, CC BY-SA 4.0
