Главная | Все статьи | Код

Что такое спагетти-код и как его исправить

Без стека Время чтения статьи ~8 минут 21
Что такое спагетти-код и как его исправить главное изображение

Разбираемся, почему иногда разработчики пишут непонятный код, что с этим делать и при чем тут макароны.

Вы читаете обновленную и улучшенную версию нашей старой статьи

Что такое спагетти-код

Спагетти-код — это сложный и запутанный код, который состоит из множества одинаковых кусков. Выглядят они так, словно их копировали с помощью 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;
};

Этот спагетти-код написал наш студент, выполняя один из проектов профессии «Фронтенд-разработчик».

В таком коде куски путаются и дублируют друг друга. В спагетти-коде сложно найти ответы даже на самые простые вопросы. Например, где реализуется эта функциональность, где создается экземпляр объекта, когда и какое вложенное условие сработает и какой кусок нужно исправить, чтобы починить программу. Файл с кодом похож на тарелку с пастой: все запутано настолько, что непонятно, где начало и конец у каждой макаронины.

Спагетти-код — большая проблема для любого разработчика. С программой, состоящей из спагетти-кода, трудно работать: в нее нельзя добавлять новые функции и исправлять элементы. В ней постоянно что-то ломается, но чинить баги сложно, так как приходится следовать за каждым элементом с начала и до конца.

Как избавиться от спагетти-кода

Если в работе вам встретился спагетти-код, не опускайте руки — его можно исправить. Вот что предстоит сделать:

  1. Разобраться с функциональностью проекта: проверить, какие участки кода за что отвечают.
  2. Написать тесты, которые проверяют основные сценарии.
  3. Начать поэтапный рефакторинг — процесс улучшения кода, то самое «распутывание спагетти».
  4. Структурировать код по модулям. У каждого из них должна быть своя цель, не зависящая от остальной логики кода — только так удастся избавить от запутывающих код зависимостей.
  5. На важные или сложные части кода написать модульные тесты — они помогут защитить продукт от внезапных поломок, когда из-за рефакторинга вдруг перестанет работать вся система.

Распутать спагетти-код непросто: это долгий и сложный процесс, в который будет вовлечена вся команда. Неважно, кто вы — начинающий или опытный разработчик. Главным правилом должен стать чистый код, который важно сразу писать хорошо. Или хотя бы не забывать перерабатывать его, если сначала пришлось написать черновик.

Читайте также: Как правильно читать чужой код

Откуда берется спагетти-код и как появился этот термин

Есть несколько причин, почему программисты невольно продолжают писать спагетти-код:

  • Нужно быстро написать код и протестировать, работает он или нет. Скопировать готовые куски кода проще, чем тратить время на выстраивание красивой логики. Поэтому программисты пишут спагетти-код, чтобы потом, когда будет время, исправить. Времени, конечно, всегда не хватает.
  • Ход программы не продуман заранее. Если логики нет, ее пытаются настроить в процессе с помощью множества вложенных условных операторов (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», которая стала «началом конца» для оператора. Но спагетти-код никуда не исчез и по-прежнему остается актуальной проблемой.

Как избежать спагетти в коде

  • Напишите спецификацию или ТЗ к коду. Продумайте основные сценарии использования программы и распишите, какие части кода за что будут отвечать. Изучите логику проекта, посмотрите, какие методы и стили уже используются или будут использоваться в нем. Это поможет лучше понять структуру кодовой базы и начать сразу писать красивый чистый код.
  • Пишите тесты до создания самого кода. Тогда вы начнете задумываться об интерфейсах программы, и дальше будет легче рефакторить код. Для сложных частей программы можно создать модульные тесты — они изолируют кусок кода и проверяют корректность его работы на промежуточном этапе, задолго до финального релиза. Чем больше таких тестов, тем выше вероятность того, что удастся очистить код от лишних элементов.
  • Изучите, как пишут код другие разработчики. Посмотрите на код в опенсорс-проектах, почитайте про нейминг. Изучите, как другие разработчики борются с побочными эффектами.
  • Проводите код-ревью. Это поможет обнаружить признаки спагетти-кода до того, как программа уйдет в релиз. Если же вы работаете в одиночку, то просто старайтесь не усложнять код — в любом языке программирования сейчас доступны фреймворки и библиотеки, которые помогут реализовать сотни функций парой строк.
  • Если в код пришлось добавить комментарии, то пишите их правильно. Так всем членам команды — этой и последующих — будет гораздо проще разобраться, за что отвечает конкретный кусок кода.
  • Больше практикуйтесь. Во время работы с кодом чаще задавайте себе вопрос: «А не сделал ли я спагетти?». Также читайте статьи на Хекслете под названием «Совершенный код» и смотрите видеолекции Кирилла Мокевнина.

Продолжайте учиться: На Хекслете есть несколько больших профессий, интенсивов и треков для джуниоров, мидлов и даже сеньоров: они позволят не только узнать новые технологии, но и прокачать уже существующие навыки

Посмотреть предложения Хекслета

Аватар пользователя Евгения Зейналова
Евгения Зейналова 01 февраля 2023
21
Рекомендуемые программы
профессия
от 25 000 ₸ в месяц
Разработка фронтенд-компонентов для веб-приложений
10 месяцев
с нуля
Старт 28 ноября
профессия
от 25 000 ₸ в месяц
Разработка веб-приложений на Django
10 месяцев
с нуля
Старт 28 ноября
профессия
от 14 960 ₸ в месяц
Ручное тестирование веб-приложений
4 месяца
с нуля
Старт 28 ноября
профессия
от 25 000 ₸ в месяц
Разработка приложений на языке Java
10 месяцев
с нуля
Старт 28 ноября
профессия
от 24 542 ₸ в месяц
новый
Сбор, анализ и интерпретация данных
9 месяцев
с нуля
Старт 28 ноября
профессия
от 25 000 ₸ в месяц
Разработка веб-приложений на Laravel
10 месяцев
с нуля
Старт 28 ноября
профессия
от 28 908 ₸ в месяц
Создание веб-приложений со скоростью света
5 месяцев
c опытом
Старт 28 ноября
профессия
от 39 525 ₸ в месяц
Разработка фронтенд- и бэкенд-компонентов для веб-приложений
16 месяцев
с нуля
Старт 28 ноября
профессия
от 25 000 ₸ в месяц
Разработка бэкенд-компонентов для веб-приложений
10 месяцев
с нуля
Старт 28 ноября
профессия
новый
Автоматизированное тестирование веб-приложений на JavaScript
8 месяцев
c опытом
Старт 28 ноября