什么是意大利面条代码?

时间:2008-10-12 14:04:49

标签: terminology anti-patterns

你能发一个真实的,过度的意大利面条代码的简短例子,可能会说它有什么作用?你能告诉我一个小调试器的噩梦吗?

我不是指IOCCC代码,即科幻小说。我的意思是发生在你身上的真实例子......

更新

重点从“发布一些意大利面条代码”变为“什么正好意大利面条代码?”。从历史的角度来看,目前的选择似乎是:

  • 旧的Fortran代码,大量使用compute gotos
  • 使用ALTER语句的旧Cobol代码

13 个答案:

答案 0 :(得分:18)

对我而言,意大利面条代码的一个更强大的现代示例是当你有20个dll并且每个DLL以某种方式相互引用时。你的依赖图看起来像一个巨大的blob,你的代码在没有真正顺序的地方跳过。一切都是相互依赖的。

答案 1 :(得分:14)

还有Ravioli Code,这是相反的。漂亮的小块功能,干净的界面整齐地包裹着肉质的美味,都坐在一个漂亮的框架酱。

答案 2 :(得分:12)

我不会把它从脑子里拉出来。这是我必须使用的,虽然简化了。让我们说基本上你有一个需要枚举的程序:

enum {
   a, b, c;
} myenum;

但我们拥有的是

HashTable t;
t["a"] = 0;
t["b"] = 1;
t["c"] = 2;

但是当然,没有哈希表的实现是足够好的,所以有一个哈希表的本地实现,其中包含的代码大约是平均开源实现的10倍,其中一半的功能和错误数量加倍。 HashTable实际上是虚拟定义的,并且有一个工厂HashTableFactory来创建HashTables的实例,但是HashTableFactory模式也是虚拟的。为了防止虚拟类的infite级联,有一个函数

HashTableFactory *makeHashTableFactor();

因此,代码需要 myenum 的所有地方都会引用HashTable和HashTableFactory的实例,以防你想要制作更多的HashTable。但等等,这不是全部!这不是哈希表的初始化方式,而是通过编写读取XML的代码来完成的:

<enum>
  <item name="a" value="0"/>
  <item name="b" value="1"/>
  <item name="c" value="2"/>
</enum>

并插入哈希表。但代码是“优化的”,因此它不会读取ascii文件myenum.xml,而是有一个编译时脚本生成:

const char* myenumXML = [13, 32, 53 ....];
来自myenum.xml的

和哈希表由函数初始化:

void xmlToHashTable(char *xml, HashTable *h, HashTableFactory *f);

被称为:

HashTableFactory *factory = makeHashTableFactory();
HashTable *t = facotry.make();
xmlToHashTable(myenumXML, t, f);

好的,我们有很多代码来获取枚举结构。它基本上用在一个函数中:

void printStuff(int c) {
   switch (c) {
   case a: print("a");
   case b: print("b");
   case c: print("c");
   }
}

并在以下情况下调用:

void stuff(char* str) {
   int c = charToEnum(str);
   printStuff(c);
}

所以我们实际拥有的不是

void stuff(char *str) {
   printf(str);
}

我们已经生成了数千行代码(私有新的,错误的,复杂的,哈希表的实现,以及xml阅读器和编写器)来代替上面的3个。

答案 3 :(得分:9)

从Linux SCSI驱动程序(它应保持无名以保护有罪):

wait_nomsg:
        if ((inb(tmport) & 0x04) != 0) {
                goto wait_nomsg;
        }
        outb(1, 0x80);
        udelay(100);
        for (n = 0; n < 0x30000; n++) {
                if ((inb(tmport) & 0x80) != 0) {        /* bsy ? */
                        goto wait_io;
                }
        }
        goto TCM_SYNC;
wait_io:
        for (n = 0; n < 0x30000; n++) {
                if ((inb(tmport) & 0x81) == 0x0081) {
                        goto wait_io1;
                }
        }
        goto TCM_SYNC;
wait_io1:
        inb(0x80);
        val |= 0x8003;          /* io,cd,db7  */
        outw(val, tmport);
        inb(0x80);
        val &= 0x00bf;          /* no sel     */
        outw(val, tmport);
        outb(2, 0x80);
TCM_SYNC:
/* ... */
small_id:
        m = 1;
        m <<= k;
        if ((m & assignid_map) == 0) {
                goto G2Q_QUIN;
        }
        if (k > 0) {
                k--;
                goto small_id;
        }
G2Q5:                   /* srch from max acceptable ID#  */
        k = i;                  /* max acceptable ID#            */
G2Q_LP:
        m = 1;
        m <<= k;
        if ((m & assignid_map) == 0) {
                goto G2Q_QUIN;
        }
        if (k > 0) {
                k--;
                goto G2Q_LP;
        }
G2Q_QUIN:               /* k=binID#,       */

我是如何找到这颗宝石的?

find /usr/src/linux -type f -name \*.c | 
while read f
do 
    echo -n "$f "
    sed -n 's/^.*goto *\([^;]*\);.*/\1/p' $f | sort -u | wc -l
done | 
sort +1rn |
head

输出是一系列行,列出按照不同标签的数量排序的文件,如下所示:

kernel/fork.c 31
fs/namei.c 35
drivers/infiniband/hw/mthca/mthca_main.c 36
fs/cifs/cifssmb.c 45
fs/ntfs/super.c 47

答案 4 :(得分:9)

真正的意大利面条代码是在COBOL中完成的,并使用了ALTER语句。

这是一个example,虽然列出了一个“幽默”,但我已经看到了这种事情。因为注意到任何带有Alter声明的程序显然都处于犯罪状态,所以几乎被解雇了一次。我拒绝“维护”该程序,更换它比理解它更快。

答案 5 :(得分:8)

别忘了提到面向对象的意大利面条。 这是当你尝试使用书中的所有设计模式时,即使它们没有意义。这导致概念层面的意大利面条代码,这比传统的基于goto的意大利面条代码更不利于质量。

答案 6 :(得分:7)

你已经要求了,你会得到它:

这是播放蓝色多瑙河华尔兹的DOS .com文件的来源。可执行文件的大小只有176个字节。代码重新用作数据,反之亦然。

.286
.model tiny

g4 equ 55-48           ; removed note-decoding !
a4 equ 57-48           ; now: storing midi-notes for octaves 0..2 and convert
h4 equ 59-48           ; to 4..6 with a simple add 48.

c5 equ 60-48
d5 equ 62-48
e5 equ 64-48
g5 equ 67-48
h5 equ 71-48

c6 equ 72-48
d6 equ 74-48
e6 equ 76-48
g6 equ 79-48           ; = 00011111b

pp  equ 0              ;  c4 is not used in the walz, using it as play-pause.
EOM equ 1              ; c#4 is also available... End Of Music
                       ; warning: experts only beyond this point !

pau1 equ 00100000b     ; bitfield definitions for note-compression
pau2 equ 01000000b     ; you can or a pau to each note!
pau3 equ 01100000b

;rep1 equ 01000000b    ; rep1 is history (only used once).
;rep3 equ 11000000b    ; rep3 was never used.

rep2 equ 10000000b     ; or a rep2 to a note to play it 3 times.

drumsize equ 5

.code
org 100h

start:
                mov  ah,9
                mov  dx,offset msg
                int  21h                    ; print our headerstring

                mov  dx,0330h               ; gus midi megaem -port
                mov  si,offset music_code   ; start of music data

mainloop:

    ; get new note (melody)

                xor  bp,bp                  ; bp= repeat-counter

                lodsb                       ; get a new note
                cmp  al, EOM                ; check for end
                jne  continue
                ret

continue:
                jns  no_rep2                ; check for rep2-Bit
                inc  bp
                inc  bp                     ; "build" repeat-counter

no_rep2:
                push ax                     ; save the note for pause

    ; "convert" to midi-note

                and  al,00011111b
                jz   skip_pp                ; check pp, keep it 0
                add  al,48                  ; fix-up oktave

skip_pp:
                xchg ax,bx                  ; bl= midi-note

play_again:
                mov  cl,3
                push cx                     ; patch program (3= piano)
                push 0c8h                   ; program change, channel 9

    ; wait (cx:dx) times

                mov  ah,86h                 ; wait a little bit
                int  15h

    ; prepare drums

                dec  di                     ; get the current drum
                jns  no_drum_underflow
                mov  di,drumsize

no_drum_underflow:

    ; play drum

                push dx                     ; volume drum
                push [word ptr drumtrk+di]  ; note   drum
                mov  al,99h
                push ax                     ; play channel 10

    ; play melody

                push dx                     ; volume melody
                push bx                     ; note   melody

                dec  ax                     ; replaces dec al :)

                push ax                     ; play channel 9

    ; send data to midi-port

                mov  cl,8                   ; we have to send 8 bytes

play_loop:
                pop  ax                     ; get the midi event
                out  dx,al                  ; and send it
                loop play_loop

    ; repeat "bp" times

                dec  bp                     ; repeat the note
                jns  play_again

    ; check and "play" pause

                xor  bx,bx                  ; clear the note, so we can hear
                                            ; a pause
    ; decode pause value

                pop  ax
                test al,01100000b
                jz   mainloop               ; no pause, get next note

    ; decrement pause value and save on stack

                sub  al,20h
                push ax
                jmp  play_again             ; and play next drum

; don't change the order of the following data, it is heavily crosslinked !
music_code      db pp or rep2

                db g4 or rep2 or pau1
                db h4 or pau1, d5 or pau1, d5 or pau3
                db d6 or pau1, d6 or pau3, h5 or pau1, h5 or pau3

                db g4 or rep2 or pau1
                db h4 or pau1, d5 or pau1, d5 or pau3
                db d6 or pau1, d6 or pau3, c6 or pau1, c6 or pau3

                db a4 or rep2 or pau1
                db c5 or pau1, e5 or pau1, e5 or pau3
                db e6 or pau1, e6 or pau3, c6 or pau1, c6 or pau3

                db a4 or rep2 or pau1
                db c5 or pau1, e5 or pau1, e5 or pau3
                db e6 or pau1, e6 or pau3, h5 or pau1, h5 or pau3

                db g4 or rep2 or pau1
                db h4 or pau1, g5 or pau1, g5 or pau3
                db g6 or pau1, g6 or pau3, d6 or pau1, d6 or pau3

                db g4 or rep2 or pau1
                db h4 or pau1, g5 or pau1, g5 or pau3
                db g6 or pau1, g6 or pau3, e6 or pau1, e6 or pau3

                db a4 or rep2 or pau1
                db c5 or pau1, e5 or pau1, e5 or pau3, pp or pau3
                db c5 or pau1, e5 or pau1, h5 or pau3, pp or pau3, d5 or pau1

                db h4 or pau1, h4 or pau3
                db a4 or pau1, e5 or pau3
                db d5 or pau1, g4 or pau2

;                db g4 or rep1 or pau1
; replace this last "rep1"-note with two (equal-sounding) notes
                db g4
                db g4 or pau1

msg             db EOM, 'Docking Station',10,'doj&sub'
drumtrk         db 36, 42, 38, 42, 38, 59  ; reversed order to save some bytes !

end start

答案 7 :(得分:6)

真正的意大利面条代码需要大量的非本地色彩。遗憾的是,使用大多数现代语言是不可能的。

编辑:有人建议将例外和longjmp作为GOTO的替代品。但这些有限且结构化,因为它们只允许您返回callstack。真正的GOTO允许你跳转到程序中任何 行,这是创建真正的意大利面条所必需的。

答案 8 :(得分:6)

简单来说,意大利面条代码是任何编程语言中的任何代码,在这些代码中,无法跟踪下一个执行帖子,或者至少很难确定下一个点在一个操作的响应中的位置。

答案 9 :(得分:4)

这是我前一段时间写过的MIDI解析器。这是一个快速而肮脏的概念证明,但是,我将承担其丑陋的责任:4级嵌套条件加上可怕的多重回报。此代码用于比较2个MIDI事件,以便在写入文件时按优先级对它们进行排序。虽然很丑陋,但它确实做得不错。

internal class EventContainerComparer : IComparer {

    int IComparer.Compare(object a, object b) {
        MIDIEventContainer evt1 = (MIDIEventContainer) a;
        MIDIEventContainer evt2 = (MIDIEventContainer) b;

        ChannelEvent chanEvt1;
        ChannelEvent chanEvt2;

        if (evt1.AbsoluteTime < evt2.AbsoluteTime) {
            return -1;
        } else if (evt1.AbsoluteTime > evt2.AbsoluteTime) {
            return 1;
        } else {    
            // a iguar valor de AbsoluteTime, los channelEvent tienen prioridad
            if(evt1.MidiEvent is ChannelEvent && evt2.MidiEvent is MetaEvent) {
                return -1;
            } else if(evt1.MidiEvent is MetaEvent && evt2.MidiEvent is ChannelEvent){
                return 1;
            //  si ambos son channelEvent, dar prioridad a NoteOn == 0 sobre NoteOn > 0
            } else if(evt1.MidiEvent is ChannelEvent && evt2.MidiEvent is ChannelEvent) {

                chanEvt1 = (ChannelEvent) evt1.MidiEvent;
                chanEvt2 = (ChannelEvent) evt2.MidiEvent;

                // si ambos son NoteOn
                if( chanEvt1.EventType == ChannelEventType.NoteOn 
                    && chanEvt2.EventType == ChannelEventType.NoteOn){

                    //  chanEvt1 en NoteOn(0) y el 2 es NoteOn(>0)
                    if(chanEvt1.Arg1 == 0 && chanEvt2.Arg1 > 0) {
                        return -1;
                    //  chanEvt1 en NoteOn(0) y el 2 es NoteOn(>0)
                    } else if(chanEvt2.Arg1 == 0 && chanEvt1.Arg1 > 0) {
                        return 1;
                    } else {
                        return 0;
                    }
                // son 2 ChannelEvent, pero no son los 2 NoteOn, el orden es indistinto
                } else {
                    return 0;
                }
            //  son 2 MetaEvent, el orden es indistinto
            } else {
                return 0;
            }
        }
    }
}

答案 10 :(得分:3)

以下是Duff's Device,来自Matt对this question的回答:

int n = (count + 7) / 8;
switch (count % 8) {
case 0: do { *to = *from++;
case 7:      *to = *from++;
case 6:      *to = *from++;
case 5:      *to = *from++;
case 4:      *to = *from++;
case 3:      *to = *from++;
case 2:      *to = *from++;
case 1:      *to = *from++;
           } while (--n > 0);
}

答案 11 :(得分:1)

意大利面条代码:起源于意大利60年代早期,作为某些意大利面食的替代配方,意大利面条代码由一位餐馆企业家烹饪,他们试图自动创建一个防呆的主菜。由于缺乏完成设计的时间,工程师/厨师偷工减料,这在早期引入了配方中的问题。在一个疯狂的尝试,以纠正一个好主意变坏,各种香料迅速添加到混合物,因为配方失去控制。结果是一连串,曲折,但可能是美味的文本堆,后来成为世界各地的开发人员所珍视的实践。

答案 12 :(得分:0)

您是否曾查看过Flex / Bison扫描仪和生成器生成的代码?过多的标签和预处理器指令。

绝对不可能理解里面是什么......并且绝对不可能遵循程序的流程。

这是定义意大利面条代码。