Спагетти-код
Вообще-то это группы объектов, написанные для конкретного бизнес-процесса, но не предназначенные для использования в другом. На практике это скопипащенные куски кода, которые в плюс-минус одинаковом виде встречаются раз так 5–10 минимум в разных модулях.
Симптомы
- Хаотичный поток управления: много
goto, глубокие вложенности, выходы из середины. - Один и тот же фрагмент встречается в нескольких местах с мелкими правками.
- Изменение в одном месте требует ручных правок в пяти других.
Пример
Пример спагетти-кода из Linux SCSI driver (с небольшими изменениями) начала нулевых:
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#, */
«Хороший» вариант: то же самое, но с явными функциями и без goto:
static int wait_ready(unsigned int port) {
for (int n = 0; n < 0x30000; n++) {
if ((inb(port) & 0x80) != 0) /* bsy ? */
return wait_io_done(port);
}
return TCM_SYNC;
}
Почему возникает
Что надо знать: хотя бы принципы функционального программирования. А в идеале — ООП и архитектурные принципы типа DDD.
Это тот самый код, который имеет очень яркую региональную принадлежность, и если вы аутсорсите, например, в Индию, то встречаться с ним придётся довольно часто.
Как исправить
- Разбивать большие функции на маленькие с одним уровнем абстракции.
- Устранять
gotoи глубокие вложенности. - Выделять повторяющиеся фрагменты в функции и методы.
- Добавлять характризационные тесты до рефакторинга.