помогнете на разработчиците да напишат по-чист код

Често сме в ситуация, в която знам, че всеки ред код прави, но нямам представа какво прави програмата. Много пъти трябва да сглобим много редове код, за да разберем как се държи кодът. Дори понякога поради твърде много редове код е невъзможно да се получи пълната представа какви са бизнес правилата. Поради тези нечисти кодове производителността на разработчиците значително пада. Но възможно ли е да се напише код, който е лесен за читателите, така че да не е необходимо да изпълняват кода в мозъка си, за да разберат поведението на кода? Възможно ли е да се напише код, който съдържа само информацията за бизнес правилата (как се държи) вместо императивните контролни потоци (как работи)? Възможно ли е да напишете код, който е точно като бизнес документ?

Отговорът е ДА. И аз правя това от много години. Това, от което се нуждаем, е непрекъснато да извличаме модели и да ги съставяме, за да изразим бизнес логиката.

В тази поредица от статии ще опиша някои основни модели на програмиране, които помагат на разработчиците да започнат пътуването, за да декларират бизнес логиката и да премахнат императивните контролни потоци от кода. Може би вече сте забелязали, че става дума за декларативна парадигма на програмиране. Вярно е и ще се съсредоточа върху показването на връзката между „императивното програмиране“ и декларативното програмиране и защо последното е по-добър вариант за софтуерни приложения.

Кратка версия на тази статия

По същество причината, поради която имаме нужда от цикли, е да получим резултат чрез сгъване на елементи от колекция. По този начин можем да използваме функция fold като по-чист начин от циклите за внедряване на бизнес логика.

Забележка: примерите в тази статия са написани на Kotlin.

Примки

Циклите са един от най-често срещаните контролни потоци в програмните езици за повтаряне на определен код, докато не бъде изпълнено конкретно условие. Той е и основата на други модели. Нека погледнем.

Често използван пример за илюстриране на цикли е да се добавят числа от 0 до n (n ≥ 0). Използва се главно в останалата част от тази статия. Ще видите как кодът се развива и получава все по-добри версии на функцията sum.

Отивам

Преди десетилетия използването на goto изрази беше много обичайно за контролиране на повтарящ се поток. Проверете следния код:

int s = 0;
int i = 0;
loop:
  s += i++;
  if(i <= n) {
    goto loop;
  }
return s;

Този код е труден за четене, защото обхватът на цикъла не е ясен. За да се подобри това, може да се въведе while.

Докато

Преди много години операторите while бяха най-популярната алтернатива за заместване на goto. Проверете кода по-долу:

Условието и обхватът на цикъл са много по-ясни от goto. Въпреки това, той все още не е достатъчно лесен за четене, тъй като ключовата променлива i на цикъла се използва на 3 места. Така for се въвежда, за да ни позволи да декларираме i в обхвата на цикъла и да отделим цикъла от правилата за изчисление.

За

В много популярни езици операторите for все още се използват често. Проверете следния код (не в Kotlin, тъй като не поддържа традиционния оператор for):

int s = 0;
for (i = 0; i <= n; i++) {
    s += i;
}
return s;

Той е много по-добър от while, защото разделя логиката от цикъла. Обаче преминаването през числата от 0 до n също е част от логиката, която все още е част от цикъла for. За да ги разделим напълно, можем да създадем диапазон от 0 до n, след което да повторим всеки елемент в диапазона, за да ги добавим заедно. Проверете кода:

0..n представлява диапазон от 0 до n (включително). Тази версия отново е по-ясна от предварителния. Но 0..n все още е част от цикъла. За хората не е естествено да четат, тъй като обикновено сканираме отляво надясно. Алтернатива за замяна на израза for, за да стане по-естествен:

Досега сме направили много подобрения. Но все още трябва да прочетем 4 реда, за да разберем поведението. Има ли по-добри начини?

Рекурсия

Рекурсивна функция в програмирането е функция, която извиква сама себе си. Така че една функция се повтаря като други цикли. За да приложим sum с рекурсия, можем да мислим, че sum(n) = sum(n-1) + n .

Имаме нужда и от условие за изход. В този случай това е sum(0) = 0 . Ето кода:

Рекурсивните функции се повтарят и натрупват резултатите, докато не бъде изпълнено определено условие. Това е декларативен начин за внедряване на цикли. В този случай можем да премахнем всички императивни контролни потоци и остава само правилото за изчисление. Въпреки това, много езици не поддържат добре recusions, така че имаме нужда от повече начини за деклариране на логиката.

колекция

Досега сме виждали много начини за прилагане на цикли. Причината да имаме нужда от цикли е, че има колекция от елементи (0 to n) и искаме да приложим някаква логика към всеки елемент. Ето още един пример:

Ако сравним цикли с цикли, ще открием, че много цикли са основно модел, който дава първоначално състояние и натрупва всеки елемент в колекция от първия до последния или от последния до първия.

Както виждаме, те имат много общи неща. Кодът е точно като сгъване на елементи заедно. Така че нека наречем шаблона fold.

Сгънете

Общият fold метод изглежда така:

Повечето езици вече са имплементирали метода (може да се нарича по различен начин, като reduce в Javascript). Важно е обаче да разберем, че същността на метода е цикъл, за да можем да го използваме правилно. Например методът sum:

Тази версия отново е по-ясна от преди.

Сгънете надясно

Това е подобно на сгъване, но в обратна посока.

fold и foldRight са два много основни модела, които могат да се използват за замяна на for цикли в повечето случаи. Те също така са в основата на всички други фундаментални модели на събиране, които ще представя в следващите си статии.

Резюме

Цикълът е един от най-често използваните модели за подпомагане на изразяването на бизнес логиката, като трансформиране на данни, разделяне или сливане на данни, изчисляване на данни и т.н. Самият цикъл обаче няма стойност, той трябва да се комбинира с други код (като sum += i), за да бъде ценен. Като го заменим с fold, можем да декларираме поведението като цяло, така че читателите да могат лесно да го разберат.