Спагетти-статья о спагетти-коде
Самый простой способ для эпитета утратить свое первоначальное значение — это стать чрезмерно широким, начать означать чуть больше, нежели просто “мне это не нравится”. Речь идет о термине “спагетти-код”, который люди часто используют как синоним к понятию “плохой код”. Проблема в том, что не всякий плохой код является спагетти-кодом. Спагетти-код — это особенно опасный и специфический вид плохого кода, и его особое зло заключается в самом способе разработки нами программного обеспечения. Почему? Потому что отдельно взятые люди редко пишут спагетти-код самостоятельно. Скорее, определенный стиль в разработке делает его все более распространенным со временем. Для того, чтобы понять это, нужно рассмотреть первоначальный контекст, в котором было определено понятие “спагетти-код” — ужасное (и в основном архаичное) использование оператора goto.
Оператор goto — это простой и мощный механизм управления потоком выполнения программы: переход к другой точке кода. Это то, что на самом деле делает скомпилированная программа на ассемблере для того, чтобы передать управление, даже если исходный код написан с использованием более современных структур, таких как циклы и функции. Используя goto, каждый может реализовать любой контроль потока выполнения, который только понадобится. Сложно также не согласится, что на данный момент goto является неуместным для исходного кода более современных программ. Исключения для этого правила существуют, но они крайне малы. Более современные языки даже не имеют этого оператора.
Оператор goto делает код трудночитаемым, потому что, если управление программой может перескакивать с одного места в другое, то нельзя с уверенностью сказать в каком состоянии находится программа при выполнении конкретного участка кода. Основанные на goto программы не могут быть легко разбиты на составные части, потому что любая точка в коде может быть кротовой норой к любой другой части кода. В итоге такой код превращается во “все везде” и для понимания даже отдельной части кода, нужно уже разбираются во всей этой путанице, и в последствии это становится невозможным для больших программ. Это можно легко сравнить с миской спагетти, где извлечение даже одной макаронины включает в себя навигацию через большой клубок макарон. Вы не можете просто посмотреть в тарелку и понять какая макаронина с какой спутана, вместо этого приходится кропотливо распутывать весь клубок.
Спагетти-код — это код, где “все везде”, и ответить на такие вопросы, как (а) где реализуется определенная часть функционала, (б) где создается экземпляр объекта и как это происходит и (в) как определить критическую секцию для исправления. Просто назвав пару простых вопросов, уже хочется взглянуть на код, что потребует понимания всей программы. То есть, необходима постоянная диагностика исходного кода, чтобы иметь возможность ответить на простейшие вопросы. Это код, который останется загадкой для тех, у кого не хватит дисциплины проследовать по каждой макаронине от начала и до конца. Это и есть спагетти-код.
Что делает спагетти-код опасным, так это то, что в отличии от других видов плохого кода, этот стал общим побочным продуктом энтропии программного обеспечения. Если код имеет правильную модульную структуру, но некоторые модули низкого качества, люди исправляют плохой код, если это важно для них. Плохой, ошибочный или медленный код, может быть исправлен без изменения интерфейсов. Честно говоря, намного проще определить ошибку в небольших, независимых функциях, нежели в гигантском комке кода, который спроектирован для решения слишком многих задач. Спагетти-код является злом, потому что (а) это очень распространенный подвид плохого кода, (б) его практически невозможно исправить не изменяя функционал, что будет равносильно краху, если есть люди, зависящие от старой модели поведения программы и (г) по причинам, к которым я доберусь немного позже, появление такого кода не может быть предотвращено путем типичных процессов проверки кода.
Причина, по которой я считаю важным отделять понятие “спагетти-код” от более широкого понятия “плохой код”, состоит в том, что многое из того, что делает код плохим, является слишком субъективным. Много конфликтов и грубостей в программном обеспечении совместной работы (или при его отсутствии) являются результатом преимущественно мужской тенденции к высмеиванию неквалифицированной креативности (или ее восприятии, и касательно кода это очень часто предвзятое восприятие): бить претендента по альфа статусу до тех пор, пока он не перестанет приставать к нам со своими некомпетентными идеями. Проблема этой модели поведения заключается в том, что она бесполезна и редко делает человека лучше в том, чем он пытается заниматься. Также есть много отвратительных людей, которые определяют хороших и плохих программистов на основе визуальной составляющей, так что их определение “хорошего кода” сводится к “код, который выглядит так, как и написанный мной”. Я чувствую, что проблема спагетти-кода лучше определена по масштабам, нежели большая, но слишком субъективная проблема “плохого кода”. Мы никогда не достигнем консенсуса в вопросе “пробелы или табуляция”, но все мы сходимся на мысли, что спагетти-код непонятный и бесполезный. Более того, так как спагетти-код является наиболее распространенной и разрушительной разновидностью плохого кода, то большинство причин и предостережений, касающихся этого подтипа, могут быть распространены на другие категории плохого кода.
Люди обычно используют понятие “плохой код” подразумевая “отвратительный код”, но если есть возможность определить почему они считают кусок кода плохим и отвратительным и выяснить возможные пути его исправления, то это уже намного лучше от бОльшей части спагетти-кода. Спагетти-код непонятный и часто совсем неисправимый. Если Вы знаете, почему ненавидите определенный кусок кода, то этот код уже выше по качеству, нежели спагетти-код, так как последний является лишь безликим бредом.
Какие причины появления спагетти-кода? Некоторое время основной причиной спагетти-кода являлся оператор goto, но он потерял популярность и до сих пор пребывает в забвении, поскольку перестал быть значимым. Сейчас причиной служит совсем другое, а именно современная быдлоизация объектно-ориентированного программирования. Особенную роль здесь играет наследование, и, как результат, не продуманные абстракции: использование параметризации, характерной для определенного класса, подразумевая единственный сценарий использования, или добавление ненужных параметров. Я признаю, что утверждение, что ООП, в том виде, в каком оно сейчас практикуется — это спагетти-код, не является неоспоримой точкой зрения. Так же, как в свое время, неоспоримой не считалась вредность использования оператора goto.
Одна из самых больших проблем программного обеспечения для проведения сравнений (будь то сравнение подходов, техник, языков или платформ) является то, что большинство сравнений сосредотачивается на простых примерах. На двадцати строках кода не возможно выявить ничего зловещего, если только эти строчки не написаны с преднамеренным подлым умыслом. Программа в двадцать строк написанная с использованием goto, как правило, вполне приемлема, и может оказаться даже проще, чем написанная без его использования. На двадцати строках набор пошаговых инструкций с некоторой явной передачей управления является очень естественным способом представления программы. Для статических программ (например, платонической формы, которая никогда не будет изменена и не получит технического обслуживания), которые можно прочитать в один присест, такая структура может быть просто отличной. Но уже на двадцати тысячах строк программы с goto становятся более чем непонятными. На двадцати тысячах строк программы с goto поддаются такому количеству хаков, расширений и оптимизаций, что первоначальное видение построения вещей попросту теряется. И тот факт, что программа может оказаться в любой части кода “из откуда угодно” означает, что для безопасного изменения кода требуется уверенное знания числа этих “из откуда угодно”. Все везде. Это не только делает код трудным для понимания, но и означает, что каждая модификация кода, скорее всего, сделает его еще хуже, в связи с непредвиденными последствиями. С течением времени, программное обеспечение становится “биологическим”. Под этим термином я подразумеваю, что оно развивает модель поведения, в которой все компоненты независимы, но некоторые модули могут иметь скрытую связь.
Оператор goto не состоялся в качестве конструкции языка программирования, потому что порождал массу проблем связанных с постоянной диагностикой программы, написанной с его использованием. Большую благосклонность получили менее мощные, но более узко специализированные структуры, такие как процедуры, функции и четко определенные структуры данных. Для единственного случая, где люди нуждались в глобальном управлении потоком (обработка ошибок), были разработаны исключения. Это был переход от крайней универсальности и абстракции программ, написанных с использованием goto, к конкретности и специфичности частей (таких, как процедуры) решения конкретных проблем. В неструктурном программировании, Вы можете написать Большую Программу, которая делает множество вещей: добавляет новые возможности на любой вкус и изменяет ход вещей так, как вам нужно. Она не должна решать какую-то “проблему” (ведь это так скучно. ), но может быть мета-фреймворком с встроенным интерпретатором. Структурное программирование призывает людей разбивать свои программы на специфические части, которые занимаются решением одной проблемы, и, по возможности, делать эти части пригодными для повторного использования. Этот принцип стал базой для философии Unix систем (сделай одну вещь, и сделай ее хорошо) и функционального программирования (добейся простоты определения точной математической семантики, избегая глобальных состояний).
Другая вещь, которую я хочу сказать про оператор goto, это то, что он редко необходим, как примитив уровня языка. Можно добиться того же эффекта, используя цикл while — переменная-счетчик, объявленная вне цикла и используемая конструкцией switch-case, либо увеличивается (шаг), продолжая цикл, либо обнуляется (goto). Это может, если пожелаете, быть расширено в одну гигантскую программу, которая будет работать как один такой цикл, но такой код никогда не пишется. То, что это почти никогда не делается, указывает на тот факт, что использование goto требуется редко. Тем самым структурное программирование указывает на безумие, к которому некоторые опускаются при попытке управления сильно нелокальными потоками.
Тем не менее, было время, когда отказ от goto был крайне спорным вопросом, и все эти идеи структурного программирования выглядели ерундой. Возражение звучало приблизительно так: зачем использовать функции и процедуры, если оператор goto намного мощнее?
Аналогично, почему использовать ссылочно прозрачные функции и неизменяемые записи если объекты намного мощнее? Объект в конце концов может иметь метод run или call или apply, поэтому он может быть функцией. Также он может иметь статические или константные поля и являться записью. Но в то же время он может делать намного больше: объект может иметь инициализаторы и финализаторы и открытые рекурсии и пятьдесят методов, если кто-то примет такое решение. Так в чем же суета вокруг этого бессмысленного структурного программирования, которое подразумевает, что люди будут создавать свои программы из конструкций, которые намного менее мощные, таких как записи, чьи поля никогда не изменяются и чьи классы не содержат магии инициализации?
Ответ в том, что наличие мощности не всегда хорошо. Мощность в программировании — это преимущество для того, кто пишет код, а не для того, кто его потом читает, а обслуживание (например, необходимость понять код) начинается приблизительно с 2000 строк или с шести недель, а объективно на проекте более одного разработчика. На реальных проектах, никто не будет заниматься только написанием кода. Зачастую нам приходиться читать как собственный код, так и код других людей. Нечитабельный код просто неприемлем, и допускается только из-за того, что его очень много, а также потому, что “лучшие практики” ООП, принятые во многих софтверных компаниях, порождают его. Более “мощная” абстракция является более общей и, следовательно, менее конкретной, а это означает, что тем, кто читает такой код, трудно определить, для чего именно она используется. Но люди, которые единолично пишут код, зачастую остаются довольно прямолинейны — мощная абстракция может иметь 18 возможных способов использования, но только один из них на самом деле задействован. В этом случае имеет место своеобразное индивидуальное видение (хотя обычно не задокументированное), которое помогает избежать путаницы. Опасность возникает тогда, когда человек, не посвященный в это видение, начинает модифицировать код. Часто, эти модификации являются хаками, которые не явно подразумевают еще один, из оставшихся 17 способов использования. Это, как правило, приводит к противоречиям, а они в свою очередь к ошибкам. К сожалению, люди, ответственные за исправление этих багов, имеют еще меньшее представление об изначальном видении, которое скрывается за кодом, и их модификации добавляют еще больше хаков. Местами исправления могут иметь место, но общее качество кода снижается. Это процесс “спагеттификации” кода. Никто вот так просто не садится и не начинает писать для себя спагетти-код. Это происходит путем постепенного “растяжения” процесса и почти всегда за это ответственны несколько разработчиков. В программном обеспечении “крутые склоны” действительно реальны и падение может быть очень внезапным.
Объектно-ориентированное программирование, первоначально разработанное для предотвращения спагетти-кода, стало (из-за использование без полного понимания “паттернов проектирования”) одним из худших его источников. “Объект” может спокойно совмещать в себе код и данные, имея при этом любое количество интерфейсов, в то же время класс может свободно порождать подклассы по всей программе. Объектно-ориентированное программирование таит в себе большую мощь, и при дисциплинированном использовании, оно может быть очень эффективно. Но большинство программистов не могут с этим справиться, и со временем их код превращается в спагетти.
Одной из проблем спагетти-кода является то, что он формируется постепенно, что делает его трудно выявляемым в процессе проверки кода, потому что каждое изменения, которое приводит к “спагеттизации”, вне общей картины может выглядеть чисто позитивным. Плюс в том, что изменения в которых нуждался менеджер или клиент “еще вчера”, появляются в коде, и с другой стороны, все это выглядит как умеренное количество дополнительных трудностей. Даже в Темные Времена goto никто не садился и не говорил: “Я собираюсь написать совершенно непонятную программу с 40 операторами goto, указывающими в одну точку кода.” Беспорядок накапливался постепенно, в то время как разработка программы передавалось от одного человека к другому. То же самое справедливо и для объектно-ориентированного спагетти. Здесь нет конкретной точки перехода от чистого первоначального дизайна к непонятному спагетти-коду. Это происходит с течением времени, когда люди злоупотребляют мощью ООП, чтобы протолкнуть непонятные хаки, в каких бы не было необходимости, если бы все понимали как работают программы, которые они модифицируют, и если бы более ясные (хоть и менее мощные) абстракции были использованы. Все это означает, что вина за “спагеттизацию” лежит на всех и не на ком одновременно: любой отдельно взятый разработчик сможет с уверенностью заявить, что это не его изменения отправили код прямиком в ад. Вот почему крупные производители программного обеспечения (на противовес минималистической философии Unix-систем), как правило, придерживаются следующей политики: никто не знает, кто на самом деле виноват в чем то.
Дополнительные проверки кода отлично подходят для выявления очевидно плохих практик, таких как смешивание пробелов и табуляций, или слишком длинных строк. Поэтому более косметические аспекты “плохого кода” менее интересны (используя определение “интересные” как синоним к “тревожные”) нежели спагетти-код. Мы уже знаем, как бороться с ними с помощью дополнительных проверок кода. Мы даже можем настроить наши серверы непрерывной интеграции на то, чтобы они отклоняли этот код. Что касается спагетти-кода, у которого нет четкого определения, то это не так просто сделать, если вообще не невозможно. Для его определения предназначена полная проверка всего программного кода, но я видел очень мало компаний, готовых инвестировать время и ресурсы, необходимые для таких проверок. В долгосрочной перспектива (10 и более лет) я думаю, что это почти невозможно, за исключением команд, которые разрабатывают жизненно- или критически-важное программное обеспечение, что обеспечивает высокий уровень дисциплины на неограниченный срок.
Ответ, как мне кажется, в том, что Большой Код просто не работает. Динамическая типизация “падает” в больших программах, а статическая типизация дает сбои другим способом. Все это справедливо для объектно-ориентированного программирования, императивного программирования, и в меньшей, но все же заметной степени для функционального программирования (проявляется в увеличении параметров размещенных в потоках). Проблемы с “goto” не было, так как его природа позволяла коду становиться Большим Кодом очень быстро. Но жестокая реальность такова, что Большой Код не является “серебряной пулей”. Большие программы просто становятся непонятными. Сложность и большой размер не “иногда не желательны”, наоборот — они всегда опасны. Такие люди, как Стиве Йегге давно это поняли.
Вот почему я считаю философию Unix систем по своей сути правильной: программы не должны быть неясными болотистыми вещами, которые разрастаются в масштабах и никогда не становятся законченными. Программа должна решать одну проблему и делать это хорошо. Если она становится большой и громоздкой, ее нужно разбирать на отдельные части: библиотеки и скрипты, исполняемые файлы и данные. Амбициозные программные проекты не должны иметь структуру в стиле “все-или-ничего”, как отдельные программы, потому что каждая парадигма программирования или набор инструментов просто ломается на этом. Вместо этого, такие проекты должны быть структурированы как системы и этому нужно уделять большое внимание. Это значит, что нужно уделить внимание отказоустойчивости, взаимозаменяемости частей и протоколам связи. Это требует больше дисциплины, нежели разработка случайно разрастающейся большой программы, но оно того стоит. В дополнение к очевидным преимуществам чистого, более удобного кода, добавляется то, что люди действительно читают этот код, а не бездумно добавляют хаки, не понимая что он на самом деле делает. Это означает, что они совершенствуются как разработчики со временем и качество их кода становится лучше в долгосрочной перспективе.
По иронии судьбы, ООП первоначально было предназначено поощрять нечто похожее на минималистическую программную разработку. Изначальное видение ООП не подразумевало, что люди должны садиться и писать огромные, сложные объекты, но имелось ввиду, что они должны использовать ООП именно когда сложность неизбежна. Примером успешного использования в этой области являются базы данных. Люди нуждаются в реляционных базах данных с точки зрения целостности транзакций, долговечности, доступности, параллелизма и производительности, так что сложность просто необходима. Базы данных невероятно сложные, и я могу с уверенностью сказать, что компьютерному миру понадобились десятилетия, чтобы добиться их достойной реализации, не взирая на огромные финансовые стимулы для того, чтобы сделать это быстрее. Но в то же время, когда база данных может быть сложной (по необходимости), интерфейс для ее использования намного проще (SQL). Вы не указываете, какую поисковую стратегию должна использовать база данных, Вы просто пишете SELECT (описываете то, что именно пользователь хочет получить, а не как это получить) и пусть уже оптимизатор запросов заботится об этом.
Отмечу, что базы данных являются своего рода исключением в моей неприязни к Большому Коду. Их сложность — это хорошо понятная необходимость, и есть люди, готовые посвятить свою карьеру исключительно их изучению. Но люди не должны разменивать свою карьеру на понимание типичных бизнес-приложений. И они не будут. Они откажутся от этого, и передадут код в другие руки, ускорив тем самым его спагеттизацию.
Почему Большой Код? Почему он существует, не смотря на свои подводные камни? И почему программисты так поспешно начинают использовать инструменты ООП, не спрашивая, нужна ли на самом деле их мощь и сложность? Я думаю, что есть несколько причин. Одной из них является лень: люди отдадут предпочтение изучению одной большой абстракции общего назначения, нежели потратят время на освоение сильно специфических абстракций и ситуаций, при которых их нужно применять. Зачем кому-то изучать связанные списки и массивы или все эти непонятные структуры, такие как деревья, если у нас уже есть ArrayList? Зачем знать, как программа использует ссылочно прозрачные функции, если объекты могут делать ту же самую работу (и даже намного больше)? Зачем учится использовать командную строку, если современные IDE могут защитить вас от возможности хоть еще раз в жизни увидеть эту чертову штуку? Зачем осваивать новые языки программирования, если Java уже является полным по Тьюрингу? Большой Код возникает от преобладания следующей позиции: зачем разбивать большую программу на модули, если современные компиляторы с легкостью справляются с сотнями тысяч строк кода? Если компьютерам все равно, когда они сталкиваются с Большим Кодом, то почему мы должны об этом заботится?
Тем не менее, если ближе к сути, то я считаю, что все это есть не что иное, как высокомерие с небольшим количеством жадности. Большой Код появляется от убеждения, что программный проект будет настолько востребованным и успешным, что люди стерпят его сложность — идеи на манер того, что собственный предметно-ориентированный язык программирования (DSL) будет столь колоссальным как C или SQL. Он также появляется из-за отсутствия готовности признать проблему решенной, а программу законченной даже тогда, когда значимая часть работы уже завершена. Он также появляется из заблуждений о том, что на самом деле являет собой программирование. Вместо того, чтобы решить существующие четко определенные проблемы и сойти с дистанции, как делают программы, спроектированные за минималистической методологией, программы с Большим Кодом делают намного больше чем нужно. Такие проекты зачастую всеохватывающие и с нецелесообразным “видением”, которое подразумевает создание программного обеспечения ради программного обеспечения. Это привносит беспорядок, потому как “видение” в корпоративной среде, как правило, быстро становится политикой. Программы с Большим Кодом всегда являются отражением среды, которая их породила (закон Конвея), и они всегда больше похожи на сборник пародий и специфического юмора, нежели на универсальный язык математики и информатики.
Существует еще одна проблема в этой пьесе. Менеджеры просто обожают Большой Код, потому что, когда отношение программист-программа становится много-к-одному вместо один-ко-многим, усилия могут быть отслежены и “численность персонала” может быть определена. Минималистические программные методологии превосходны, но они требуют проявлять доверие к программистам в их возможности распределять свое время надлежащим образом для решения более чем одной задачи, и большинство управленцев-тираннозавров чувствуют себя не комфортно, делая это. Большой Код действительно не работает, но он дает менеджерам ощущение контроля над распределением технических усилий. Он также сопутствует смешиванию величины и успеха, чем менеджеры часто и занимаются (о чем свидетельствует вопрос на собеседовании для руководителей “Сколько подчиненных у Вас было?”). Долгосрочная спагеттификация, которая является результатом Большого Кода, редко становится проблемой для таких менеджеров. Они не видят, как это происходит, и зачастую уходят из проекта до того, как это становится проблемой.
Подводя итоги, можно с уверенностью сказать, что спагетти-код — это плохой код, но не весь плохой код является спагетти-кодом. Спагетти-код — это продукт промышленного программирования, которое зачастую (но не всегда) является результатом прохождения кода через большое количество рук, и неизбежным следствием методологии разработки больших программных продуктов и результатом быдлоизации объектно-ориентированного программирования, которая возникла из дефективных управленческих процессов. Противоядие против спагетти-кода — это агрессивный и активный рефакторинг и прикладывание усилий по сохранению программы компактной, эффективной, с чистым исходным кодом и, самое главное, последовательной.
От переводчика: Статья довольно обширная, поэтому буду благодарен, если сообщите в ЛС на неточности или ошибки.
Код спагетти — Spaghetti code
Код спагетти — это уничижительное выражение для неструктурированных и трудных для- поддерживать исходный код. Спагетти-код может быть вызван несколькими факторами, такими как непостоянные требования проекта, отсутствие правил стиля программирования и недостаточные способности или опыт.
- 1 Значение
- 2 История
- 3 Связанные фразы
- 3.1 Код равиоли
- 3.2 Код лазаньи
Значение
Код, в котором чрезмерно используются операторы GOTO, а не конструкции структурного программирования, что приводит к запутанным и неподдерживаемым программам, часто называют спагетти-кодом. Такой код имеет сложную и запутанную структуру управления , в результате чего поток программы концептуально похож на миску со спагетти, скрученную и запутанную. В публикации 1980 года Национального бюро стандартов США фраза программа спагетти использовалась для описания старых программ, имеющих «фрагментированные и разбросанные файлы». Спагетти-код также может описывать антишаблон, в котором объектно-ориентированный код написан в процедурном стиле, например, путем создания классов, методы которых слишком длинные и беспорядочные, или отказа от объекта. ориентированные концепции, такие как полиморфизм. Присутствие этой формы спагетти-кода может значительно снизить понятность системы.
История
Неясно, когда фраза «спагетти-код» вошла в обиход; однако в 1977 г. появилось несколько ссылок, в том числе «Макароны лучше, чем спагетти» Стила, опубликованные в Трудах симпозиума 1977 г. по искусственному интеллекту и языкам программирования. В книге 1978 года «Учебник по дисциплинированному программированию с использованием PL / I, PL / CS и PL / CT» Ричард Конвей использовал этот термин для описания типов программ, которые «имеют такую же чистую логическую структуру, как тарелка со спагетти». повторяется в 1979 году в книге «Введение в программирование», которую он написал в соавторстве с Дэвидом Грайсом. В статье 1988 года «Спиральная модель разработки и усовершенствования программного обеспечения» этот термин используется для описания старой практики модели «код и исправления», которой не хватало планирования и которая в конечном итоге привела к разработке водопадной модели. В книге 1979 года «Структурированное программирование для программиста на COBOL» автор Пол Нолл использует фразы «спагетти-код» и «крысиное гнездо» как синонимы для описания плохо структурированного исходного кода.
На конференции Ada — Europe ’93, Ada был описан как вынуждающий программиста «создавать понятный, а не спагетти-код» из-за его ограничивающего механизма распространения исключений.
В 1981 году в издании Michigan Technic под названием «ОСНОВНО. FORTRAN bytes !! », автор описал FORTRAN, заявив, что« он полностью состоит из спагетти-кода ».
Ричард Хэмминг описал в своих лекциях этимологию этого термина в контексте ранних программирование в двоичном коде:
Если при исправлении ошибки вы хотели вставить несколько пропущенных инструкций, вы взяли непосредственно предыдущую инструкцию и заменили ее переносом в какое-то пустое место. Там вы вставляете инструкцию, которую только что написали, добавляете инструкции, которые хотите вставить, а затем переходите обратно в основную программу. Таким образом, программа вскоре превратилась в последовательность переходов элемента управления в странные места. Когда, как это почти всегда бывает, в исправлениях были ошибки, вы снова использовали тот же трюк, используя другое доступное пространство. В результате путь управления программой через хранилище вскоре стал похож на банку спагетти. Почему бы просто не вставить их в инструкции? Потому что тогда вам придется просмотреть всю программу и изменить все адреса, относящиеся к любой из перемещенных инструкций! Что угодно, только не это!
Связанные фразы
Код Равиоли
Код Равиоли — термин, характерный для объектно-ориентированного программирования. Он описывает код, который включает хорошо структурированные классы, которые легко понять по отдельности, но трудно понять в целом.
Код лазаньи
Код лазаньи относится к коду слои которого настолько сложны и переплетены, что внесение изменений в один слой потребует изменений во всех других слоях.
Примеры
Здесь следует то, что можно было бы считать тривиальным примером кода спагетти в ОСНОВНОЙ. Программа выводит на экран каждое из чисел от 1 до 100 вместе с квадратом. Отступы не используются для различения различных действий, выполняемых кодом, и что операторы программы GOTO полагаются на номера строк. Переход от одной области к другой предсказать сложнее. Реальные случаи появления спагетти-кода более сложны и могут значительно увеличить затраты на обслуживание программы.
1 i = 0 2 i = i + 1 3 PRINT i; "squared squared /wiki/For_loop">для циклов и функции обеспечивают управление потоком тогда как оператор goto поощряет произвольное управление потоком. Хотя этот пример невелик, реальные программы состоят из многих строк кода и их трудно поддерживать, если они написаны в виде спагетти-кода.
Вот еще один пример кода спагетти со встроенными операторами GOTO.
INPUT «Сколько чисел сортировать?»; T DIM n (T) FOR i = 1 TO T PRINT "NUMBER:"; i INPUT n (i) NEXT i 'Расчеты: C = T E180: C = INT (C / 2) IF C = 0 ТО НАХОДИТСЯ C330 D = T - CE = 1 I220: f = E F230: g = f + C ЕСЛИ n (f)>n (g) ТО ЗАМЕНИТЬ n (f), n (g) f = f - C ЕСЛИ f>0 ТО НАХОДИТСЯ F230 E = E + 1 ЕСЛИ E>D ТО НАХОДИТСЯ E180 НАЙТИ I220 C330: ПЕЧАТЬ "Отсортированный список:" FOR i = 1 TO T PRINT n (i) NEXT i
См. Также
- Портал компьютерного программирования
- Инженерный портал
- Большой комок грязи, часть программного обеспечения без видимой архитектуры
- Международный конкурс запутанного кода C, соревнование по созданию приятно неясного кода C
- язык только для записи, язык с таким причудливым синтаксисом, что полученный код непонятен
- Технический задолженность
Ссылки
Внешние ссылки
- Перейти к заявлению, признанному вредным. Классический отказ от спагетти-кода, автор Эдсгер Дейкстра
- Мы не знаем, куда ПЕРЕЙТИ, если мы не знаем, откуда мы ПРИШЛИ. Автор Р. Лоуренс Кларк из DATAMATION, декабрь 1973 г.
- Рефакторинг Код Java спагетти в код Java Bento, разделяющий тазу, полную кода, из одного класса на семь классов
- Объекты и рамки - Шаг назад Брайан Ринальди
- Программирование макаронных изделий - Спагетти, лазанья, Код равиоли и макарон
- Теория программирования макаронных изделий
- Код спагетти: понимание жизни и работы с мудростью программиста (английское издание)
Что такое спагетти-код и как его исправить
Спагетти-код — это сложный и запутанный код, который состоит из множества одинаковых кусков. Выглядят они так, словно их копировали с помощью Ctrl+C и Сtrl+V, но разбавили разными цифрами и данными.
Вот пример такого спагетти-кода:
import readlineSync from 'readline-sync'; import calcCond, greeting > from './index.js'; export default () => const name = greeting(); console.log('What is the result of the expression?'); let i = 0; while (i 2) const generator1 = Math.floor(Math.random() * 100); const generator2 = Math.floor(Math.random() * 10); const signsArr = ['+', '-', '*']; const signsArrRand = Math.floor(Math.random() * signsArr.length); const summ = generator1 + generator2; const subtract = generator1 - generator2; const mult = generator1 * generator2; const question = `Question: $generator1> $signsArr[signsArrRand]> $generator2> `; console.log(question); const answer = readlineSync.question('Your answer: '); if (((question[13] || question[12]) === '+') && answer === summ.toString()) console.log('Correct!'); > else if (((question[13] || question[12]) === '-') && answer === subtract.toString()) console.log('Correct!'); > else if (((question[13] || question[12]) === '*') && answer === mult.toString()) console.log('Correct!'); > if (answer === '') return console.log(`No answer.\nLet's try again, $name>!`); > if ((answer !== summ.toString()) && ((question[13] || question[12]) === '+')) return calcCond(answer, summ, name); > if ((answer !== subtract.toString()) && ((question[13] || question[12]) === '-')) return calcCond(answer, subtract, name); > if ((answer !== mult.toString()) && ((question[13] || question[12]) === '*')) return calcCond(answer, mult, name); > i += 1; if (i === 3) console.log(`Congratulations, $name>!`); > > return null; >;
Этот спагетти-код написал наш студент, выполняя один из проектов профессии «Фронтенд-разработчик».
В таком коде куски путаются и дублируют друг друга. В спагетти-коде сложно найти ответы даже на самые простые вопросы. Например, где реализуется эта функциональность, где создается экземпляр объекта, когда и какое вложенное условие сработает и какой кусок нужно исправить, чтобы починить программу. Файл с кодом похож на тарелку с пастой: все запутано настолько, что непонятно, где начало и конец у каждой макаронины.
Спагетти-код — большая проблема для любого разработчика. С программой, состоящей из спагетти-кода, трудно работать: в нее нельзя добавлять новые функции и исправлять элементы. В ней постоянно что-то ломается, но чинить баги сложно, так как приходится следовать за каждым элементом с начала и до конца.
Как избавиться от спагетти-кода
Если в работе вам встретился спагетти-код, не опускайте руки — его можно исправить. Вот что предстоит сделать:
- Разобраться с функциональностью проекта: проверить, какие участки кода за что отвечают.
- Написать тесты, которые проверяют основные сценарии.
- Начать поэтапный рефакторинг — процесс улучшения кода, то самое «распутывание спагетти».
- Структурировать код по модулям. У каждого из них должна быть своя цель, не зависящая от остальной логики кода — только так удастся избавить от запутывающих код зависимостей.
- На важные или сложные части кода написать модульные тесты — они помогут защитить продукт от внезапных поломок, когда из-за рефакторинга вдруг перестанет работать вся система.
Распутать спагетти-код непросто: это долгий и сложный процесс, в который будет вовлечена вся команда. Неважно, кто вы — начинающий или опытный разработчик. Главным правилом должен стать чистый код, который важно сразу писать хорошо. Или хотя бы не забывать перерабатывать его, если сначала пришлось написать черновик.
Откуда берется спагетти-код и как появился этот термин
Есть несколько причин, почему программисты невольно продолжают писать спагетти-код:
- Нужно быстро написать код и протестировать, работает он или нет. Скопировать готовые куски кода проще, чем тратить время на выстраивание красивой логики. Поэтому программисты пишут спагетти-код, чтобы потом, когда будет время, исправить. Времени, конечно, всегда не хватает.
- Ход программы не продуман заранее. Если логики нет, ее пытаются настроить в процессе с помощью множества вложенных условных операторов (if). Правда, потом разработчики сталкиваются с тем, что добавить новую функциональность или что-то переписать будет уже невозможно.
- Программу пишут разные команды разработчиков. У каждой из них нет времени и ресурсов распутывать клубок, созданный предыдущими программистами: проще использовать те же самые методы и сказать, что это «они первые начали».
- У разработчика мало опыта. Он даже не догадывается, что что-то делает неправильно и не трогает код, который работает.
Сегодня термин «спагетти-код» используют применительно к любому плохому коду. Но на самом деле не каждый плохой код — спагетти. Исторически этот термин использовали в ситуации, когда разработчик создавал запутанную, сложную для запоминания структуру за счет избыточного оператора goto .
Если представить день из жизни как программу, то, предположим, последовательность действий будет такая: выпить кофе, проехать в метро, зайти в офис. Оператор goto позволит изменить эту последовательность в любом направлении: скажем, сначала мы выпьем кофе, потом зайдем в офис, а затем проедем в метро. Или наоборот: метро, кофе — а далее окажемся в той части дня, где мы на дне рождения у троюродной тети.
Фрагмент спагетти-кода с оператором goto с сайта Stack Overflow :
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 TCM_SYNC; TCM_SYNC: /* . */
Goto есть во многих языках программирования. Но в высокоуровневых языках — Python, JavaScript — использование этого оператора ограничено. Среди разработчиков применение оператора и вовсе считается плохим тоном. Goto может основательно испортить код: сделать его беспорядочным и запутать ход выполнения программы.
Goto не используется повсеместно примерно с 70-х годов XX века — именно тогда вышла статья нидерландского ученого Эдсгера Дейкстры « Доводы против оператора GOTO », которая стала «началом конца» для оператора. Но спагетти-код никуда не исчез и по-прежнему остается актуальной проблемой.
Как избежать спагетти в коде
- Напишите спецификацию или ТЗ к коду. Продумайте основные сценарии использования программы и распишите, какие части кода за что будут отвечать. Изучите логику проекта, посмотрите, какие методы и стили уже используются или будут использоваться в нем. Это поможет лучше понять структуру кодовой базы и начать сразу писать красивый чистый код.
- Пишите тесты до создания самого кода. Тогда вы начнете задумываться об интерфейсах программы, и дальше будет легче рефакторить код. Для сложных частей программы можно создать модульные тесты — они изолируют кусок кода и проверяют корректность его работы на промежуточном этапе, задолго до финального релиза. Чем больше таких тестов, тем выше вероятность того, что удастся очистить код от лишних элементов.
- Изучите, как пишут код другие разработчики. Посмотрите на код в опенсорс-проектах, почитайте про нейминг. Изучите, как другие разработчики борются с побочными эффектами.
- Проводите код-ревью. Это поможет обнаружить признаки спагетти-кода до того, как программа уйдет в релиз. Если же вы работаете в одиночку, то просто старайтесь не усложнять код — в любом языке программирования сейчас доступны фреймворки и библиотеки, которые помогут реализовать сотни функций парой строк.
- Если в код пришлось добавить комментарии, то пишите их правильно. Так всем членам команды — этой и последующих — будет гораздо проще разобраться, за что отвечает конкретный кусок кода.
- Больше практикуйтесь. Во время работы с кодом чаще задавайте себе вопрос: «А не сделал ли я спагетти?». Также читайте статьи на Хекслете под названием «Совершенный код» и смотрите видеолекции Кирилла Мокевнина.
Продолжайте учиться: На Хекслете есть несколько больших профессий, интенсивов и треков для джуниоров, мидлов и даже сеньоров: они позволят не только узнать новые технологии, но и прокачать уже существующие навыки
Спагетти-код
Спагетти-код — плохо спроектированная, слабо структурированная, запутанная и трудная для понимания программа, особенно содержащая много операторов GOTO (особенно переходов назад), исключений и других конструкций, ухудшающих структурированность [1] . Самый распространённый антипаттерн программирования.
Спагетти-код назван так, потому что ход выполнения программы похож на миску спагетти, то есть извилистый и запутанный. Иногда называется «кенгуру-код» (kangaroo code) из-за множества инструкций jump.
В настоящее время термин применяется не только к случаям злоупотребления GOTO, но и к любому «многосвязному» коду, в котором один и тот же небольшой фрагмент исполняется в большом количестве различных ситуаций и выполняет очень много различных логических функций [1] .
Спагетти-код обычно возникает:
- от неопытности разработчиков;
- от серьёзного прессинга по срокам, как установленного руководством (например, в принятой в компании системе мотивации на работу быстрее), так и установленного разработчиком самому себе (желание все сделать наиболее быстрым способом).
Спагетти-код может быть отлажен и работать правильно и с высокой производительностью, но он крайне сложен в сопровождении и развитии [1] . Правка спагетти для добавления новой функциональности иногда несет такой огромный потенциал внесения новых ошибок, что рефакторинг (главное лекарство от спагетти) становится неизбежным.
Пример
Ниже приводится пример спагетти-кода на Бейсике, выполняющего простое действие — печать чисел от 1 до 10 и их квадратов. Реальные примеры спагетти-кода гораздо более сложные и создают большие проблемы при сопровождении программ.
10 i = 0 20 i = i + 1 30 IF i 10 THEN GOTO 70 40 IF i > 10 THEN GOTO 50 50 PRINT "Программа завершена." 60 END 70 PRINT i; " квадрат sy0">* i 80 GOTO 20
FOR i = 1 TO 10 PRINT i; " квадрат sy0">* i NEXT i PRINT "Программа завершена."
Тот же код в функциональном стиле с использованием метода итерации, написанный на языке Ruby:
(1..10).each |i| puts "#\t квадрат = #"> puts "Программа завершена."
См. также
Примечания
- ↑ 123John Vlissides, Kyle Brown, Gerard Meszaros AntiPatterns: The Survival Guide. Spaghetti code.
Ссылки
- О вреде оператора Go To — статья Эдсгера Дейкстры.
- Spaghetti code // FOLDOC.
- Анти-паттерны
- Программистский сленг
- Стандарт оформления кода
Wikimedia Foundation . 2010 .
Полезное
Смотреть что такое "Спагетти-код" в других словарях:
- Спагетти (значения) — Готовые спагетти. Спагетти макаронное изделие из длинных и тонких нитей. В переносном смысле, спагетти может обозначать что то переплетённое, сложное или запутанное: многоуровневую транспортную развязку со множеством длинных эстакад,… … Википедия
- Антипаттерн — Возможно, эта статья содержит оригинальное исследование. Добавьте ссылки на источники, в противном случае она может быть выставлена на удаление. Дополнительные сведения могут быть на странице обсуждения. (25 мая 2011) … Википедия
- Раздувание программного обеспечения — (англ. software bloat, bloatware) тенденция новых программ быть больше по объёму и требовать больше системных ресурсов по сравнению со старыми[источник не указан 267 дней]. Никлаус Вирт в 1996 году написал статью… … Википедия
- Раздувание ПО — Раздувание программного обеспечения (англ. software bloat, bloatware) тенденция новых программ быть больше по объёму и требовать больше системных ресурсов по сравнению со старыми. В результате у многих людей появляется ощущение, что рост… … Википедия
- Функция для галочки — Раздувание программного обеспечения (англ. software bloat, bloatware) тенденция новых программ быть больше по объёму и требовать больше системных ресурсов по сравнению со старыми. В результате у многих людей появляется ощущение, что рост… … Википедия
- Стандарт оформления кода — (стандарт кодирования, стиль программирования) (англ. coding standards, coding convention или programming style) набор правил и соглашений, используемых при написании исходного кода на некотором языке программирования. Наличие общего… … Википедия
- Шаблоны проектирования GRASP — GRASP (англ. General Responsibility Assignment Software Patterns (общие образцы распределения обязанностей)) паттерны, используемые в объектно ориентированном проектировании для решения общих задач по назначению обязанностей классам и объектам. В … Википедия
- GRASP — (англ. General Responsibility Assignment Software Patterns общие образцы распределения обязанностей) паттерны, используемые в объектно ориентированном проектировании для решения общих задач по назначению обязанностей классам и… … Википедия
- Список серий мультсериала «Закусочная Боба» — Список и краткое описание эпизодов мультсериала «Закусочная Боба» (англ. Bob s Burgers). Для удобства серии сгруппированы по сезонам. Содержание 1 Список эпизодов 1.1 Первый сезон : 2011 … Википедия
- Парадигма — (Paradigm) Определение парадигмы, история возникновения парадигмы Информация об определении парадигмы, история возникновения парадигмы Содержание Содержание История возникновения Частные случаи (лингвистика) Управленческая парадигма Парадигма… … Энциклопедия инвестора
- Обратная связь: Техподдержка, Реклама на сайте
- Путешествия
Экспорт словарей на сайты, сделанные на PHP,
WordPress, MODx.- Пометить текст и поделитьсяИскать в этом же словареИскать синонимы
- Искать во всех словарях
- Искать в переводах
- Искать в ИнтернетеИскать в этой же категории