Mã spaghetti (Spaghetti code) là một cụm từ mang tính khinh miệt cho mã nguồn có tính phi cấu trúc và khó bảo trì. Mã spaghetti có thể được gây ra bởi vài yếu tố, chẳng hạn như do bản yêu cầu dự án có tính không ổn định, thiếu quy tắc phong cách lập trình, và do người viết không đủ năng lực hoặc kinh nghiệm.[1]
Mã mà dùng quá mức các câu lệnh GOTO hơn là các cấu tạo lập trình có cấu trúc – kết quả sinh ra là các chương trình lộn xộn và không thể bảo trì được – thì hay được gọi là mã spaghetti.[2] Mã như vậy có cấu trúc điều khiển phức tạp và rối rắm, kết quả sinh ra là một luồng chương trình mà về mặt khái niệm thì giống như một bát mì spaghetti – xoắn và rối.[3] Trong một xuất bản năm 1980 của Cục Tiêu chuẩn Quốc gia Hoa Kỳ, cụm từ chương trình spaghetti được sử dụng để mô tả các chương trình trước đây có "các tệp bị phân mảnh và rải rác".[4] Mã Spaghetti cũng có thể được dùng để mô tả một phản mô thức trong đó mã hướng đối tượng được viết theo phong cách thủ tục, chẳng hạn như bằng cách tạo các lớp có các phương thức quá dài và bừa bãi, hoặc vứt bỏ đi các khái niệm hướng đối tượng như đa hình.[5] Sự hiện diện của hình thức mã spaghetti này có thể làm giảm đáng kể tính dễ lĩnh hội của một hệ thống.[6]
Người ta không rõ rằng từ khi nào mà cụm từ mã spaghetti được sử dụng phổ biến; tuy nhiên, một số tài liệu tham khảo xuất hiện vào năm 1977 bao gồm Macaroni is Better Than Spaghetti bởi Steele được xuất bản trong 'Biên bản lưu' của hội nghị chuyên đề năm 1977 về trí năng nhân tạo và ngôn ngữ lập trình. Trong cuốn sách năm 1978 A primer on disciplined programming using PL/I, PL/CS, and PL/CT, Richard Conway đã sử dụng thuật ngữ này để mô tả các kiểu chương trình rằng "có cùng cấu trúc sạch có tính logic giống như một đĩa mì spaghetti",[7] một cụm từ được lặp đi lặp lại trong cuốn sách năm 1979 An Introduction to Programming mà ông là đồng tác giả với David Gries .[8] Trong bài báo khoa học năm 1988 A spiral model of software development and enhancement, thuật ngữ này được sử dụng để mô tả sự thực hành trước đây của mô hình mã và sửa lỗi (code and fix model) – nói về sự thiếu việc kế hoạch của nó, và cuối cùng đã dẫn đến sự phát triển của mô hình thác nước.[9] Trong cuốn sách năm 1979 Structured programming for the COBOL programmer, tác giả Paul Noll sử dụng các cụm từ mã spaghetti và tổ của chuột làm các từ đồng nghĩa để mô tả mã nguồn có cấu trúc kém.[10]
Trong hội nghị Ada – Europe '93, ngôn ngữ Ada đã được mô tả là nó ép lập trình viên phải "tạo ra mã code dễ hiểu, thay vì mã spaghetti", vì cơ chế lan truyền ngoại lệ (exception) mang tính hạn chế của nó.
Vào năm 1981 trong một bài viết biếm nhại các ngôn ngữ máy tính trong sách The Technic Michigan có tiêu đề "BASICally speaking...FORTRAN bytes!!", tác giả đã mô tả FORTRAN là "bằng chứng rành rành rằng các nhà đồng sáng lập của IBM là người Ý, vì nó toàn là từ mã spaghetti mà ra cả".[11]
Mã Ravioli là một thuật ngữ riêng cho lập trình hướng đối tượng. Nó mô tả mã bao gồm các lớp có cấu trúc tốt, về mặt cô lập thì dễ hiểu, nhưng về mặt tổng thể thì lại khó hiểu.[12]
Mã Lasagna dùng để chỉ mã có các tầng lớp rất phức tạp và đan xen với nhau, đến nỗi việc tạo ra một thay đổi trong một tầng lớp sẽ đòi hỏi phải thay đổi trong tất cả các tầng lớp khác.[13]
Đoạn mã dưới đây được coi là một ví dụ thông thường của mã spaghetti trong ngôn ngữ BASIC. Chương trình in từng số từ 1 đến 100 lên màn hình cùng với bình phương của nó. Ở đây việc thụt đầu dòng không hề được sử dụng để làm rõ sự khác nhau giữa nhiều hành động khác nhau do mã lệnh thực hiện, và các câu lệnh GOTO
của chương trình tạo ra một sự lệ thuộc chặt chẽ vào số dòng . Luồng thực thi từ miền này sang miền khác khó dự đoán hơn. Sự xuất hiện của mã spaghetti trong thế giới thực thì phức tạp hơn và có thể thêm rất nhiều vào chi phí bảo trì cho chương trình.
1 i=0
2 i=i+1
3 PRINT i; "bình phương=";i*i
4 IF i>=100 THEN GOTO 6
5 GOTO 2
6 PRINT "Chương trình đã hoàn tất."
7 END
Đây cũng là mã trên nhưng được viết lại theo kiểu lập trình có cấu trúc:
1 FOR i=1 TO 100
2 PRINT i;"bình phương=";i*i
3 NEXT i
4 PRINT "Chương trình đã hoàn tất."
5 END
Chương trình trên đây cũng nhảy từ miền này sang miền khác, nhưng bước nhảy đấy thì mang tính hình thức và dễ dự đoán hơn, bởi vì vòng lặp for và hàm đều cung cấp sự điều khiển luồng có kiểm soát còn câu lệnh goto lại khuyến khích điều khiển luồng tùy ý.
Mặc dù ví dụ trên này thì nhỏ, các chương trình trong thế giới thực thì được cấu thành từ nhiều dòng mã và nếu được viết theo kiểu cách mã spaghetti thì sẽ khó bảo trì.
Đây là một ví dụ khác về mã Spaghetti trong đó câu lệnh GOTO bị lạm dụng (ăn sâu vào logic của chương trình) và được dùng với các nhãn (label) có tên không rõ ràng.
SCREEN 0
INPUT "Bao nhiêu số để sắp xếp? "; T
DIM n(T)
FOR i = 1 TO T
PRINT "SỐ THỨ:"; i
INPUT n(i)
NEXT i
'Nhiều tính toán:
C = T
E180:
C = INT(C / 2)
IF C = 0 THEN GOTO C330
D = T - C
E = 1
I220:
f = E
F230:
g = f + C
SWAP n(f), n(g)
f = f - C
IF f > 0 THEN GOTO F230
E = E + 1
IF E > D THEN GOTO E180
GOTO I220
C330:
PRINT "Liệt kê theo thứ tự là"
FOR i = 1 TO T
PRINT n(i)
NEXT i
|date=
(trợ giúp)Quản lý CS1: nhiều tên: danh sách tác giả (liên kết)