Разбираемся, почему иногда разработчики пишут непонятный код, что с этим делать и при чем тут макароны.
Вы читаете обновленную и улучшенную версию нашей старой статьи
Спагетти-код — это сложный и запутанный код, который состоит из множества одинаковых кусков. Выглядят они так, словно их копировали с помощью 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;
};
Этот спагетти-код написал наш студент, выполняя один из проектов профессии «Фронтенд-разработчик».
В таком коде куски путаются и дублируют друг друга. В спагетти-коде сложно найти ответы даже на самые простые вопросы. Например, где реализуется эта функциональность, где создается экземпляр объекта, когда и какое вложенное условие сработает и какой кусок нужно исправить, чтобы починить программу. Файл с кодом похож на тарелку с пастой: все запутано настолько, что непонятно, где начало и конец у каждой макаронины.
Спагетти-код — большая проблема для любого разработчика. С программой, состоящей из спагетти-кода, трудно работать: в нее нельзя добавлять новые функции и исправлять элементы. В ней постоянно что-то ломается, но чинить баги сложно, так как приходится следовать за каждым элементом с начала и до конца.
Если в работе вам встретился спагетти-код, не опускайте руки — его можно исправить. Вот что предстоит сделать:
Распутать спагетти-код непросто: это долгий и сложный процесс, в который будет вовлечена вся команда. Неважно, кто вы — начинающий или опытный разработчик. Главным правилом должен стать чистый код, который важно сразу писать хорошо. Или хотя бы не забывать перерабатывать его, если сначала пришлось написать черновик.
Читайте также: Как правильно читать чужой код
Есть несколько причин, почему программисты невольно продолжают писать спагетти-код:
Сегодня термин «спагетти-код» используют применительно к любому плохому коду. Но на самом деле не каждый плохой код — спагетти. Исторически этот термин использовали в ситуации, когда разработчик создавал запутанную, сложную для запоминания структуру за счет избыточного оператора 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», которая стала «началом конца» для оператора. Но спагетти-код никуда не исчез и по-прежнему остается актуальной проблемой.
Продолжайте учиться: На Хекслете есть несколько больших профессий, интенсивов и треков для джуниоров, мидлов и даже сеньоров: они позволят не только узнать новые технологии, но и прокачать уже существующие навыки