面条式代码:修订间差异
(未显示16个用户的32个中间版本) | |||
第1行: | 第1行: | ||
{{ |
{{NoteTA |
||
|G1=IT |
|G1 = IT |
||
|G2 = 地名 |
|||
|1 = zh-hant:義大利直麵; zh-cn:意大利直面; zh-tw:義大利麵; zh-hk:意大利粉; zh-sg:意大利面; |
|||
}} |
}} |
||
[[file:Spaghetti.jpg|thumb|一 |
[[file:Spaghetti.jpg|thumb|一盘扭曲纠结的[[義大利直麵]],面条式代码也同样地扭曲纠结。]] |
||
''' |
'''面条式代码'''({{Lang-en|Spaghetti code}})是[[软件工程]]中[[反面模式]]的一种<ref name="William">William J. Brown, Raphael C. Malveau, Hays W. "Skip" McCormick, Thomas J. Mowbray (1998). ''AntiPatterns: refactoring software, architectures, and projects in crisis''.(1st ed.). Wiley. ISBN 0471197130.</ref>,是指[[源代码]]的[[控制流程]]复杂、混乱而难以理解<ref name="Stanley">J. Stanley Warford (2009). ''Computer Systems''.(4th ed.). Jones & Bartlett Publishers. ISBN 0763771449.</ref>,尤其是用了很多[[Goto|GOTO]]、[[异常处理|例外]]、[[线程]]、或其他无组织的[[分支 (計算機科學)|分支]]。其命名的原因是因为程式的流向就像一盘麵一样扭曲纠结。面条式代码的产生有许多原因,例如没有经验的程序设计师,及已经过长期频繁修改的复杂程序。[[结构化编程]]可避免面条式代码的出现。 |
||
== |
==举例== |
||
以下是一段用[[BASIC]] |
以下是一段用[[BASIC]]写的程序,是典型面条式代码的例子。程序在屏幕上显示数字 1 到 10 及其对应的平方。由于有<code>[[Goto|GOTO]]</code>语句,此程序需要配合[[行號 (程式語言)|行号]]才能知道程序的流向,也无法利用[[縮進風格|縮排]]的方式使程序比较容易阅读。而且由于有跳转指令,要执行的程序会由一个区域跳转到另一个区域,而且在讀到跳转指令前,很難事先知道程式會跳轉,此程式不易调试。现实世界中的面条式代码往往更加复杂,会大幅增加维护成本。 |
||
< |
<syntaxhighlight lang="qbasic"> |
||
10 i = 0 |
10 i = 0 |
||
20 i = i + 1 |
20 i = i + 1 |
||
第16行: | 第18行: | ||
60 PRINT "Program Completed." |
60 PRINT "Program Completed." |
||
70 END |
70 END |
||
</syntaxhighlight> |
|||
</source> |
|||
以下 |
以下程序则使用结构化控制,没有<code>GOTO</code>语句,因此可以缩进,增强程序的可读性: |
||
< |
<syntaxhighlight lang="gwbasic"> |
||
1 FOR i=1 TO 10 |
|||
Public Sub Main() |
|||
2 PRINT i;"squared=";i*i |
|||
For i As Integer = 1 To 10 |
|||
3 NEXT i |
|||
Console.WriteLine("{0} squared = {1}", i, i ^ 2) |
|||
⚫ | |||
Next |
|||
5 END |
|||
⚫ | |||
</syntaxhighlight> |
|||
End Sub |
|||
⚫ | |||
</source> |
|||
⚫ | |||
== |
==汇编语言及脚本语言== |
||
当使用各种[[汇编语言|汇编語言]](及其底层的[[机器语言]])时,编写面条式代码会带来更大的危险。其原因是由于这些[[低级语言]]很少有可以对应 [[FOR迴圈|FOR 循环]]或 [[WHILE迴圈|WHILE 循环]]的机制。许多[[脚本语言]]也有类似的情况,例如 [[DOS]] 的批处理文件或者 [[OpenVMS]] 上的[[資料控制語言]] (DCL)。 |
|||
如果将[[结构化编程]]中的做法移植到汇编语言的程序,会显著地增强可靠性和可维护性。例如限制 GOTO 的使用,只用 GOTO 来产生类似结构化程序设计中-{流程控制}-的效果、另外许多汇编语言都有提供[[子程序]]呼叫的机制,可以有类似[[过程式编程]](Procedural programming)的效果。汇编语言一般都会有[[巨集]],而且支持参数传递,以避免[[全局变量]]的使用,也可避免[[遠隔作用 (計算機科學)|远隔作用]] (action at a distance)的[[反面模式]]。 |
|||
使用[[高 |
使用[[高级语言]]编写的程式可以利用一些标准流程控制的作法(如以上第2例的 For 循环),不过当编译为汇编代码或者机器代码时,由于最后仍利用 GOTO 或 IF 之类的指令表示高级语言的标准流程控制,看起来仍会像面条式代码。因为编译器会忠实地将程序的结构转换为汇编代码,所以,其他结构性较弱的语言遇到的程序流程难以辨识的问题,不会遇到。不过,如果程序[[最优化|优化]]过多,可能在缩小程序大小的同时,也影响其程序的结构。若配合代码级调试使用,还可能会造成一些困难。 |
||
== |
==相關詞語== |
||
===餛飩式代碼=== |
|||
餛飩式代碼(Ravioli code)是指程式中是由許多小的、鬆散連接的部份所構成。餛飩式代碼可以和麵條式代碼作比較,後者用麵條來代表程式的結構,而前者用[[意大利餃|餛飩]](Ravioli)來代表程式中的[[对象 (计算机科学)|物件]]。 |
|||
馄饨式代码(Ravioli code)指由许多松散连接的小部份构成的程序。馄饨式代码可以和面条式代码作类比,后者用面条来代表程序的结构,而前者用[[意大利餃|馄饨]](Ravioli)来代表程序中的[[对象 (计算机科学)|对象]]。这种代码虽然满足了低[[耦合性 (計算機科學)|耦合性]]的要求,但是过度的分离与封装导致过多的调用,使得[[呼叫堆疊|堆栈]]容易变得臃肿,从而也增加了代码阅读的难度。 |
|||
===千層麵代碼=== |
|||
{{Main|抽象層|層 (物件導向設計)}} |
|||
千層麵代碼(Lasagna code)是指各層都很複雜的軟體。各層彼此相關性強,因此更改某一層时必须同步修改其他層<ref name="Latchezar18">{{cite journal|last1=Tomov|first1=Latchezar|last2=Ivanova|first2=Valentina|title=Teaching Good Practices In Software Engineering by Counterexamples|journal=Computer Science and Education in Computer Science|date=October 2014|issue=1|pages=397–405|url=https://www.researchgate.net/publication/301298530|access-date=5 March 2018}}</ref>。 |
|||
==參見== |
==參見== |
||
* [[ |
* [[结构化编程]]:程序中不使用 <code>GOTO</code>,只使用像 Loop, For 及其他的-{流程控制}-指令。 |
||
* [[国际C语言混乱代码大赛]]:一个设法写出让人难以理解的 C 语言代码的比赛。 |
|||
<!--* [[International Obfuscated C Code Contest]] A competition to produce pleasingly obscure C code.--> |
|||
*[[组合子逻辑]] |
|||
<!--* [[Spaghetti with Meatballs (programming)]] Twisted, tangled and unstructured code, that also includes objects.--> |
|||
*[[柯里化]] |
|||
*[[λ演算]] |
|||
*[[极小化求值]] |
|||
*[[求值策略]] |
|||
== 参考文献 == |
== 参考文献 == |
||
第48行: | 第57行: | ||
==外部連結== |
==外部連結== |
||
*[http://www.acm.org/classics/oct95/ Go To Statement Considered Harmful]. [[Edsger Dijkstra]]提出有 |
*[https://web.archive.org/web/20070703050443/http://www.acm.org/classics/oct95/ Go To Statement Considered Harmful]. [[Edsger Dijkstra]] 提出有关面条式代码的缺点。 |
||
*[http://www.fortran.com/fortran/come_from.html ''We don't know where to GOTO if we don't know where we've COME FROM'' by R. Lawrence Clark from DATAMATION, December, 1973] |
*[https://web.archive.org/web/20180716171336/http://www.fortran.com/fortran/come_from.html ''We don't know where to GOTO if we don't know where we've COME FROM'' by R. Lawrence Clark from DATAMATION, December, 1973] |
||
*[http://yost.com/computers/java/java-spaghetti/ Refactoring Java spaghetti code into Java bento code] |
*[http://yost.com/computers/java/java-spaghetti/ Refactoring Java spaghetti code into Java bento code] {{Wayback|url=http://yost.com/computers/java/java-spaghetti/ |date=20210117060538 }} 将一个类中许多的代码分解为七个不同类的代码。 |
||
[[Category:反模式]] |
[[Category:反模式]] |
2023年1月19日 (四) 03:29的最新版本
面条式代码(英語:Spaghetti code)是软件工程中反面模式的一种[1],是指源代码的控制流程复杂、混乱而难以理解[2],尤其是用了很多GOTO、例外、线程、或其他无组织的分支。其命名的原因是因为程式的流向就像一盘麵一样扭曲纠结。面条式代码的产生有许多原因,例如没有经验的程序设计师,及已经过长期频繁修改的复杂程序。结构化编程可避免面条式代码的出现。
举例
[编辑]以下是一段用BASIC写的程序,是典型面条式代码的例子。程序在屏幕上显示数字 1 到 10 及其对应的平方。由于有GOTO
语句,此程序需要配合行号才能知道程序的流向,也无法利用縮排的方式使程序比较容易阅读。而且由于有跳转指令,要执行的程序会由一个区域跳转到另一个区域,而且在讀到跳转指令前,很難事先知道程式會跳轉,此程式不易调试。现实世界中的面条式代码往往更加复杂,会大幅增加维护成本。
10 i = 0
20 i = i + 1
30 PRINT i; " squared = "; i * i
40 IF i >= 10 THEN GOTO 60
50 GOTO 20
60 PRINT "Program Completed."
70 END
以下程序则使用结构化控制,没有GOTO
语句,因此可以缩进,增强程序的可读性:
1 FOR i=1 TO 10
2 PRINT i;"squared=";i*i
3 NEXT i
4 PRINT "Program Completed."
5 END
程序中还是有由一个区域跳转到另一个区域的情况,不过这种跳转是可以预期的,也是标准的做法。使用FOR循环或子程序是处理程序控制流程的标准做法。若使用GOTO,就表示允许程序任意地跳转。上述示例的代码很短,实际使用的程式其源代码更长,若是面条式代码的话,会相当难以维护。
汇编语言及脚本语言
[编辑]当使用各种汇编語言(及其底层的机器语言)时,编写面条式代码会带来更大的危险。其原因是由于这些低级语言很少有可以对应 FOR 循环或 WHILE 循环的机制。许多脚本语言也有类似的情况,例如 DOS 的批处理文件或者 OpenVMS 上的資料控制語言 (DCL)。
如果将结构化编程中的做法移植到汇编语言的程序,会显著地增强可靠性和可维护性。例如限制 GOTO 的使用,只用 GOTO 来产生类似结构化程序设计中流程控制的效果、另外许多汇编语言都有提供子程序呼叫的机制,可以有类似过程式编程(Procedural programming)的效果。汇编语言一般都会有巨集,而且支持参数传递,以避免全局变量的使用,也可避免远隔作用 (action at a distance)的反面模式。
使用高级语言编写的程式可以利用一些标准流程控制的作法(如以上第2例的 For 循环),不过当编译为汇编代码或者机器代码时,由于最后仍利用 GOTO 或 IF 之类的指令表示高级语言的标准流程控制,看起来仍会像面条式代码。因为编译器会忠实地将程序的结构转换为汇编代码,所以,其他结构性较弱的语言遇到的程序流程难以辨识的问题,不会遇到。不过,如果程序优化过多,可能在缩小程序大小的同时,也影响其程序的结构。若配合代码级调试使用,还可能会造成一些困难。
相關詞語
[编辑]餛飩式代碼
[编辑]馄饨式代码(Ravioli code)指由许多松散连接的小部份构成的程序。馄饨式代码可以和面条式代码作类比,后者用面条来代表程序的结构,而前者用馄饨(Ravioli)来代表程序中的对象。这种代码虽然满足了低耦合性的要求,但是过度的分离与封装导致过多的调用,使得堆栈容易变得臃肿,从而也增加了代码阅读的难度。
千層麵代碼
[编辑]千層麵代碼(Lasagna code)是指各層都很複雜的軟體。各層彼此相關性強,因此更改某一層时必须同步修改其他層[3]。
參見
[编辑]- 结构化编程:程序中不使用
GOTO
,只使用像 Loop, For 及其他的流程控制指令。 - 国际C语言混乱代码大赛:一个设法写出让人难以理解的 C 语言代码的比赛。
- 组合子逻辑
- 柯里化
- λ演算
- 极小化求值
- 求值策略
参考文献
[编辑]- ^ William J. Brown, Raphael C. Malveau, Hays W. "Skip" McCormick, Thomas J. Mowbray (1998). AntiPatterns: refactoring software, architectures, and projects in crisis.(1st ed.). Wiley. ISBN 0471197130.
- ^ J. Stanley Warford (2009). Computer Systems.(4th ed.). Jones & Bartlett Publishers. ISBN 0763771449.
- ^ Tomov, Latchezar; Ivanova, Valentina. Teaching Good Practices In Software Engineering by Counterexamples. Computer Science and Education in Computer Science. October 2014, (1): 397–405 [5 March 2018].
本條目部分或全部内容出自以GFDL授權發佈的《自由線上電腦詞典》(FOLDOC)。