Найти тему
Журнал «Код»

Убираем спагетти-код

Оглавление

Два под­хо­да к упо­ря­до­чи­ва­нию хао­са

Когда мы дела­ли свой Трелло-планировщик из Бут­стра­па и наше­го спис­ка задач, у нас появил­ся спагетти-код. Это зна­чит, что для про­сто­ты и ско­ро­сти реше­ния мы ско­пи­ро­ва­ли оди­на­ко­вые кус­ки кода, кото­рые дела­ют почти одно и то же. У них внут­ри оди­на­ко­вая логи­ка, но раз­ные вход­ные дан­ные, и мы их про­сто скопировали-вставили.

У тако­го под­хо­да к про­грам­ми­ро­ва­нию есть несколь­ко про­блем:

  • под­дер­жи­вать такой код слож­но, пото­му что нуж­но посто­ян­но про­ве­рять, во всех ли местах мы внес­ли нуж­ные изме­не­ния;
  • рас­ши­рять функ­ци­о­наль­ность слож­но, так как лег­ко запу­тать­ся, какую имен­но часть кода мы рас­ши­ря­ем или опти­ми­зи­ру­ем;
  • читать такой код труд­но, пото­му что один и тот же код встре­ча­ет­ся мно­го раз.

Един­ствен­ное, когда мож­но исполь­зо­вать такой под­ход — если нуж­но что-то быст­ро про­те­сти­ро­вать и понять, рабо­та­ет оно или нет. Если не рабо­та­ет — зна­чит, мы сэко­но­ми­ли вре­мя и не ста­ли тра­тить его на неудач­ное реше­ние. А если всё рабо­та­ет как нуж­но, зна­чит, наста­ло вре­мя пере­пи­сать код в нор­маль­ном виде. Для это­го нам пона­до­бит­ся неко­то­рое подо­бие объ­ек­та, но не на осно­ве клас­са, а создан­ное вруч­ную.

Для это­го нам пона­до­бит­ся неко­то­рое подо­бие объ­ек­та, но не на осно­ве клас­са, а создан­ное вруч­ную.

Мы хоте­ли ООП, но не смог­ли
Изна­чаль­но мы хоте­ли на этом при­ме­ре пока­зать силу клас­сов и объ­ек­тов в объектно-ориентированном про­грам­ми­ро­ва­нии. Но, разо­брав­шись, поня­ли, что клас­сы толь­ко всё услож­нят, не при­не­ся нам суще­ствен­ной поль­зы.
Поэто­му мы будем исполь­зо­вать объ­ек­ты, но без клас­сов. А силу клас­сов мы пока­за­ли в игре на Питоне — посмот­ри­те, вам понра­вит­ся.

Новый тип переменной: объект

У пере­мен­ной типа «объ­ект» есть одна отли­чи­тель­ная осо­бен­ность: она состо­ит как бы из двух частей — свой­ства и зна­че­ния. Мы про это гово­ри­ли в ста­тье про объ­ек­ты в ООП, и здесь всё то же самое — у объ­ек­та меня­ют­ся толь­ко зна­че­ния свойств. Пояс­ним на при­ме­ре язы­ка JavaScript.

Сде­ла­ем переменную-объект, у кото­рой будет два свой­ства — имя и воз­раст:

var person = {
name: "Миша",
age: 35
}

Что­бы поме­нять имя, нуж­но напи­сать назва­ние пере­мен­ной и через точ­ку ука­зать назва­ние свой­ства, кото­рое хотим изме­нить:

person.name = "Илья";
person.age = 31;

Свойств у объ­ек­та может быть сколь­ко угод­но:

var person = {
name1: "Миша",
name2: "Саша",
name3: "Лена",
age1: 35,
age2: 21,
age3: 19
}

Но если у объ­ек­та полу­ча­ет­ся мно­го одно­тип­ных свойств, мож­но сде­лать их мас­си­вом и обра­щать­ся к ним по номе­рам. А если эле­мен­ты мас­си­ва тоже сде­лать объ­ек­та­ми с оди­на­ко­вы­ми назва­ни­я­ми свойств, полу­чит­ся вот такая магия:

Смот­ри­те, так как у каж­до­го эле­мен­та мас­си­ва оди­на­ко­вое назва­ние свойств, то, меняя про­сто номер эле­мен­та, мы можем запо­ми­нать раз­ные свой­ства у оди­на­ко­вых по сути эле­мен­тов. Это нам при­го­дит­ся на сле­ду­ю­щем шаге.

Собираем дубли

Прой­дём­ся по наше­му ста­ро­му коду из про­шлой ста­тьи и собе­рём все оди­на­ко­вые пере­мен­ные, кото­рые отли­ча­ют­ся толь­ко циф­ра­ми:

  • List(1,2,3,4)
  • Mask(1,2,3,4)
  • element_Id_(1,2,3,4)
  • number_Id_(1,2,3,4)

Пер­вые две пере­мен­ные зада­ют ссыл­ку на объ­ект и мас­ку для срав­не­ния эле­мен­тов, а вто­рые две отве­ча­ют за коли­че­ство задач в колон­ках.

Свер­нём эти 16 пере­мен­ных в один боль­шой объ­ект:

Теперь, зная толь­ко номер колон­ки, мы можем обра­тить­ся к объ­ек­ту, мас­ке и коли­че­ству задач в колон­ке. Сна­ча­ла это может пока­зать­ся гро­мозд­ким, но на самом деле сокра­ща­ет наш финаль­ный объ­ём про­грам­мы в 4 раза.

Что­бы изба­вить­ся от дуб­лей в коде, исполь­зу­ют цик­лы или выно­сят повто­ря­ю­щий­ся код в отдель­ную функ­цию. На самом деле вари­ан­тов боль­ше, но основ­ные — эти.

Используем цикл

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

Сде­ла­ем то же самое в цик­ле, исполь­зуя нашу боль­шую переменную-объект. Для это­го мы орга­ни­зу­ем цикл от 0 до 3 (пото­му что нуме­ра­ция эле­мен­тов мас­си­ва начи­на­ет­ся с нуля) и по оче­ре­ди про­ве­ря­ем все зна­че­ния:

Код сокра­тил­ся в 4 раза, читать ста­ло про­ще, и всё меня­ет­ся в одном месте. Кра­со­та.

Делаем отдельную функцию

У нас есть вот такой огром­ный кусок кода, кото­рый дела­ет одно и то же, толь­ко с раз­ны­ми эле­мен­та­ми.

Здесь 4 раза зада­ёт­ся обра­бот­чик нажа­тия кла­виш в поле вво­да у каж­дой колон­ки. Оче­вид­но, что про­ще выне­сти повто­ря­ю­щий­ся код в отдель­ную функ­цию и вызы­вать её по мере необ­хо­ди­мо­сти:

ОПТИМИЗИРОВАННЫЙ КОД СКРИПТА

Что дальше

Мы толь­ко что убра­ли почти весь спагетти-код из наше­го про­ек­та. Почти — пото­му что у нас оста­лось два неопрят­ных фраг­мен­та:

  • Когда мы 4 раза под­ряд объ­яв­ля­ем колон­ки, кото­рые отли­ча­ют­ся толь­ко номе­ром и назва­ни­ем.
  • У нас оста­лись 4 обра­бот­чи­ка нажа­тий, кото­рые дела­ют оди­на­ко­вые вещи — вызы­ва­ют одну и ту же функ­цию с раз­ны­ми пара­мет­ра­ми.

Оба фраг­мен­та мож­но опти­ми­зи­ро­вать, напри­мер, с помо­щью jQuery.

Попро­буй­те сде­лать это сами, пока это не сде­ла­ли мы 🙂

Подписывайтесь на наш канал, чтобы ваш код был идеальным!