Попробую на маленьком примере показать откуда берётся запутанный код.
Получаем задание от менеджера, для простоты это будет просто логическая функция. И пытаемся написать лучший код.
Для упрощения написания маленькая буква будет означать что условие ложно, а большая - что истинно.
Представляем функцию в виде карты Карно, чтобы оптимизировать всё что можно:
aaAA
bBBb
cd 1101
cD 1101
CD 0000
Cd 1101
СДНФ:
a&c|b&c|a&d|b&d
(14 знаков)Самый неоптимизированный вариант выглядел бы так, далее будем назвать это спагетти-кодом:
a&b&c&d|a&B&c&d|A&b&c&d|a&b&c&D|a&B&c&D|A&b&c&D|a&b&C&d|a&B&C&d|A&b&C&d
(71 знак)
Естественно, пишем первый вариант.
А потом прибегает менеджер и говорит что нужно изменить самую малость, случай abcd = 0. Отражаем на карте:
aaAA
bBBb
cd 0101
cD 1101
CD 0000
Cd 1101
Если бы задание сразу было таким, то мы написали бы другой совершенный код:
СДНФ:
a&B&c|a&D&c|A&b&c|a&C&d|A&b&C&d
(31 знак) больше, чем в начале, но перейти от начального кода к этому сложно! Нужно внести изменения практически везде.Так как переписывать всё не хочется, делаем костыль к изначальному СДНФ:
(a&c|b&c|a&d|b&d)&(A|B|C|D)
(27 знаков). Немного изменений, меньше тестировать, но потеряна структура. Но не сильно. Я бы так и сделал.А в спагетти-коде было бы изменить проще всего, даже короче станет:
a&B&c&d|A&b&c&d|a&b&c&D|a&B&c&D|A&b&c&D|a&b&C&d|a&B&C&d|A&b&C&d
(63 знака).
Снова приходит менеджер. Условие C не нужно, его случайно добавили. Убираем половину карты:
aaAA
bBBb
d 0101
D 1101
Совершенный код был бы таким, если бы мы знали заранее:
-
СДНФ:
a&B|a&D|A&b
(11 знаков)Но у нас уже есть код, и менять его весь не хочется:
Нужно идти по всему коду и из каждого условия убирать условия c и C. Второй костыль к изначальной СДНФ:
(a|b|a&d|b&d)&(A|B|D)
(21 знак), в основном пришлось удалять, структура не вернулась, но изменение не было сложным.Спагетти-код:
a&B&d|A&b&d|a&b&D|a&B&D|A&b&D
(29 знаков) пришлось выкинуть пол-программы, внести изменения в каждый блок (!)
Снова менеджер. Ещё одно изменение, ABd = 1, и можно отдавать заказчику:
aaAA
bBBb
d 0111
D 1101
СДНФ:
a&B|A&b|A&d|a&D
(15 знаков).Третий костыль к изначальной СДНФ:
(a|b|a&d|b&d)&(A|B|D)|A&B&d
(27 знаков) эх, всё дальше от идеала. По размеру уже между минимальной формой и спагетти-кодом.Спагетти-код:
a&B&d|A&b&d|a&b&D|a&B&D|A&b&D|A&B&d
(35 знаков) дописали условие, основную часть не трогаем.
Итог
Что хотел клиент: a&B|A&b|A&d|a&D
Что передано клиенту: (a|b|a&d|b&d)&(A|B|D)|A&B&d
Конечно, никто не написал бы такой код сразу. И ругался бы, увидев такой в проекте. Но как видим, пришлось написать именно так чтобы минимизировать трудозатраты.
Выводы
Какой бы ни был у вас код, всегда найдётся изменение, которое испортит всю его структуру. И именно с этим изменением к вам и придут.
Есть случаи для которых спагетти-код самое подходящее решение.
Чем больше оптимизирован код, тем больше придётся менять.
Всегда задним числом понятно, какой код надо было написать.
Если бы не изменения в уже работающем коде, можно было написать сразу хорошо.
Костыли приближают вас к спагетти-коду, но достичь его одними костылями сложно.
evgenyk
А почему не сделать таблицу? На питоне это будет словарь, значения - вызовы функций, ключи - логические выражения. Тогда при изменениях, просто добавляем или удаляем выражения в словарь.
Лично я для чуть более-менее сложных логических выражений всегда делаю таблицу. Конечно это очень по старинному, но ведь работает, и хорошо.
Sau Автор
Логическая функция тут как наглядный пример, программный код занял бы много места, ничего не добавив по сути. К тому же сложность восприятия программного кода сложнее оценить.
Вариант с таблицей для логических функций поддерживаю.