5 серпня 2021 р.

Ніндзя код

Навчання без міркування – даремне, міркування без навчання – небезпечне

Конфуцій (Судження і бесіди)

Ніндзя-програмісти минулого використовували деякі хитрощі, щоб загострити розум тих, хто буде підтримувати їх код.

Гуру, що перевіряють код, шукають їх у тестових завданнях.

Початківці іноді викорустовують їх краще за ніндзя-програмістів.

Уважно перечитайте ці хитрощі і вирішіть хто ви є — ніндзя, початківець, чи може гуру перевірки коду?

Обережно, іронія!

Багато тих, хто намагався піти шляхом ніндзя. Мало тих, кому це вдалося.

Стислість – сестра таланту

Пишіть якомога коротший код. Покажіть, наскільки ви розумні.

Нехай стислі та неочевидні можливості мови стануть вам посібником.

Наприклад, розглянемо таке застосування тернарного оператора '?':

// взято з добре відомої javascript бібліотеки
i = i ? i < 0 ? Math.max(0, len + i) : i : 0;

Круто, правда? Якщо ви напишете подібне, розробник, який натрапить на цей рядок і намагатиметься зрозуміти, яке ж значення має i, пізнає неабияку радість. І врешті-решт, прийде до вас за відповідю.

Скажіть йому, що коротше – це завжди краще. Допоможіть і йому стати на шлях ніндзя.

Однолітерні змінні

Дао безсловесне. Ім’я, яке можна назвати, не є постійним ім’ям.

Лао-цзи (Дао де цзін)

Ще один спосіб писати код швидше — використовувати однолітерні змінні. Наприклад: a, b або c.

Коротка змінна зникає у коді наче ніндзя у лісі. Ніхто не зможе знайти її використовуючи “пошук” редактора. І навіть, якщо її знайдуть, вони не зможуть “розшифрувати” за що саме змінні a чи b відповідають.

…Але є одне виключення з правил. Справжній ніндзя ніколи не використовуватиме i у якості лічильника в циклі "for". Де завгодно, тільки не тут! Озерніться – є багато інших екзотичних літер. Наприклад, x або y.

Екзотична змінна у якості лічильника особоливо доречна, коли тіло циклу займає одну-дві сторінки (чим більше, тим краще). У такому випадку, ті, хто зануриться глибоко у код циклу, не зможуть швидко здогадатись, що змінна x насправді є лічильником.

Використовуйте абревіатури

Якщо правила, встановлені командою, не дозволяють вам використовувати однолітерні змінні або абстрактні імена, тоді скоротшуйте їх.

Наприклад:

  • listlst.
  • userAgentua.
  • browserbrsr.
  • …тощо.

Тільки обрані, що мають розвинену інтуіцію, зможуть зрозуміти такі імена. Намагайтесь скоротшувати все. Тільки достойні повинні мати змогу підтримувати ваш код.

Будьте абстрактними

Великий квадрат не має кутів,
Великий глек довго ліпиться,
Великий звук не можна почути,
Великий образ неозорий.

Лао-цзи (Дао де цзін)

Обираючи ім’я, намагайтесь використовувати найбільш абстрактне слово. Прикладом може бути obj, data, value, item, elem тощо.

  • data є ідеальним варіантом для назви змінної. Використовуйте його всюди, де зможете. І справді, кожна змінна має дані, правильно?

    …Що робити, якщо назва data вже зайнята? Спробуйте value – вона також універсальна. Врешті-решт, змінна отримує якесь значення.

  • Підбирайте ім’я змінним згідно з їх типом: str, num

    Спробуйте. Щойно ставший на шлях ніндзя може засумніватись, чи вони дійсно такі корисні? Авжеж!

    Так, ім’я змінної дещо означає. Це дає зрозуміти, що ми використовуємо: рядок, число чи щось ще. Проте коли сторонні люди намагатимуться зрозуміти код, вони будуть здивовані, що інформація про те, що саме містить змінна, відсутня. У результаті вони не зможуть змінити ваш добре обміркований код.

    Тип змінної досить легко знайти під час налаштування. Але що означає назва змінної? Яку саме строку/число вона зберігає?

    Жодного шансу дізнатись про це без тривалої медитації!

  • …Але що робити коли і такі імена закінчились? Просто додайте число: data1, item2, elem5

Перевірка уваги

Тільки дуже уважний програміст повинен мати змогу зрозуміти ваш код. Проте як це перевірити?

Один із способів – використання схожих імен змінних, наприклад date і data.

Змішуйте їх всюди, де це можливо.

Швидко прочитати такий код неможливо. А якщо виникла друкарська помилка… Мммм… Це надовго, час випити чаю.

Хитрі синоніми

Істина, яка може бути виражена словами, не є правдива істина. Ім’я, яке може бути названо, не є правдиве ім’я.

Лао-цзи (Дао де цзін)

Використання схожих імен для однакових речей зробить ваше життя цікавішим і покаже рівень вашої креативності публіці.

Наприклад, роглянемо префікси функцій. Якщо функція показує повідомлення на екрані – почніть назву з display…, наприклад, displayMessage. І коли інша фукція показуватиме щось ще на екрані (скажімо, ім’я користувача), почніть її назву з show… (наприклад, showName).

Тобто натякніть, що є деяка тонка різниця між цими функціями, хоча насправді її немає.

Домовьтесь зі своїми ніндзя-колегами, що якшо Іван починає називати функції, що показують щось, використовуючи display..., тоді Петро може використовувати render.., а Ганна – paint.... Зауважте, наскільки цікавим та різноманітним став наш код.

…А тепер коронний прийом!

Для функцій, у яких дійсно є важлива різниця, використовуйте однаковий префікс!

Наприклад, функція printPage(page) використовуватиме принтер. А printText(text) виводитеме текст на екран. Нехай люди неосвічені у вашому коді здогадуються з приводу схожої функції printMessage: “Куди буде виведено повідомлення? На принтер чи на екран?”. Для збільшення ефекту неочікуваності, функція printMessage(message) повинна вивести повідомлення в нове вікно!

Використовуйте імена повторно

При встановленні порядку
з’явилися імена.
Оскільки виникли імена,
потрібно знати межу їх використання.

Лао-цзи (Дао де цзін)

Додавайте нову змінну тільки тоді коли це вкрай необхідно.

Замість цього, використовуйте повторно існуючі змінні. Просто записуйте у них нові значення.

У функції намагайтесь використовувати лише змінні, що були передані у якості параметрів.

Це суттєво ускладнить розуміння того, що саме знаходиться у змінній зараз, і звідки воно там. Метою цих дій є розвиток інтуіції та пам’яті людини, котра прочитає цей код. Людина зі слабкою інтуіцією аналізуватиме такий код рядок за рядком і слідкуватиме за змінами у кожному блоці коду.

Продвинутим варіантом такого підходу є непомітна (!) заміна значення змінної на щось дуже схоже всередині циклу або функції.

Наприклад:

function ninjaFunction(elem) {
  // 20 рядків коду, що використовують elem

  elem = clone(elem);

  // ще 20 рядків, які тепер використовують клон elem!
}

Програміст, в якого буде бажання використати elem у другій частині коду буде здивований… Тільки під час налагодження, після розбору коду він зрозуміє, що працює з клоном!

Таке трапляється доволі часто. Ефективний прийом навіть проти досвічених ніндзя.

Підкреслення задля розваги

Ставьте підкреслення _ та __ перед іменами змінних. Наприклад, _name або __value. Краще буде, якщо тільки ви будете знати їх значення. А ще краще, щоб значення не було зовсім, додавайте їх задля розваги. Або використовуйте різні значення у різних місцях.

Ви вбиваєте двох зайців одним пострілом. По-перше, код стає довшим і менш зрозумілим, і по-друге, колега-розробник зможе витратити час з’ясовуючи сакральне значення вашого підкреслення.

Проворний ніндзя використовує підкреслення в одній частині коду і уникає їх в іншій. Це робить код ще більш вразливим і підвищує можливість виникнення помилок у майбутньому.

Покажіть свою любов

Нехай усі бачать, наскільки величні ваші сутності! Читач обов’язково зрадіє таким іменам, як superElement, megaFrame та niceItem.

Справді, з одного боку, дещо все ж таки написано: super.., mega.., nice... Але з іншого боку – це не роз’яснює нічого. Той, хто читатиме ваш код, витратить не одну годину свого оплаченого робочого часу на медитацію і пошук прихованого значення цих слів.

Перекриття зовнішніх змінних

Перебуваючи на світлі, не можна нічого побачити в темряві.
Перебуваючи ж у темряві, побачиш все, що знаходиться на світлі.

Ґуань Їнь-цзи

Використовуйте ті ж самі імена змінних всередені функцій, що й за її межами. Це просто. Ніяких зусиль для винаходу нових імен.

let user = authenticateUser();

function render() {
  let user = anotherValue();
  ...
  ...багато рядків...
  ...
  ... // <-- програміст захоче використати тут 'user' і...
  ...
}

Програмісти, що читатимуть код функції render ймовірно не помітить, що локальна змінна user перекриває глобальну.

Тоді вони спробують працювати з user, як з зовнішньою змінною, що має вернути результат authenticateUser()… Пастка закрилася! Привіт, налагоджувач…

Побічні ефекти всюди!

Є функції, які начебто нічого не змінюють. Наприклад, isReady(), checkPermission(), findTags()… Припускається, що такі функції виконують обчислення та повертають результат без впливу на те, що знаходиться за межами функції. Іншими словами, без “побічних ефектів”.

Дійсно гарним прийомом є додавати “корисну” дію до них, окрім їх основної задачі.

Вираз приголомшеного подиву на обличчі вашого колеги, коли він побачить, що функція з ім’ям is.., check.. чи find... щось змінює, неодмінно розширить межі його розуму.

Іншим способом здивувати є повернення нестандартного реультату.

Покажіть своє оригінальне мислення! Нехає виклик функції checkPermission поверне не true/false, а складний об’єкт з результатом перевірки.

Розробники, що намагатимуться написати if (checkPermission(..)), будуть цікавитись, чому воно не працює. Скажіть їм: “Читайте документацію!”. І дайте їм почитату цю статтю.

Могутні функції!

Вічне Дао пронизує Собою все.
Воно є і праворуч, і ліворуч.

Лао-цзи (Дао де цзін)

Не треба обмежувати алгоритм функції лише тим, що пов’язано з її ім’ям. Мисліть ширше.

Наприклад, функція validateEmail(email) може (окрім, перевірки адреси електронної пошти на відповідність правилам) показувати повідомлення про помилку та пропонувати ввести нову адресу.

Додаткові дії не повинні бути зрозумілими з імені функції. Справжній ніндзя розробник зробить їх також неочевидними і в самому коді.

Поєднання декількох дій в одну захищає ваш код від повторного використання.

Уявіть собі, що інший розробник захоче тільки перевірити адресу електроної пошти без виводу жодних повідомлень. Ваша функція validateEmail(email) робить обидві ці дії, а значить не підійде йому. Тому вони не потурбують вас під час медитації питаннями з приводу цієї функції.

Підсумки

Всі “поради”, зазначені вище, взяті з реального коду… Який іноді писали навіть досвідчені розробники. Можливо навіть досвідченіші за вас ;)

  • Дотримуйтесь їх – і ваш код буде мати повно несподіванок.
  • Дотримуйтесь їх усіх, і ваш код буде дійсно вашим — ніхто не захоче його читати, і тим паче — змінювати.
  • Дотримуйтесь їх усіх – і ваш код стане цінним уроком для молодих розробників, які шукають просвітлення.
Навчальна карта

Коментарі

прочитайте це, перш ніж коментувати…
  • Якщо у вас є пропозиції, щодо покращення підручника, будь ласка, створіть обговорення на GitHub або одразу створіть запит на злиття зі змінами.
  • Якщо ви не можете зрозуміти щось у статті, спробуйте покращити її, будь ласка.
  • Щоб вставити код, використовуйте тег <code>, для кількох рядків – обгорніть їх тегом <pre>, для понад 10 рядків – використовуйте пісочницю (plnkr, jsbin, codepen…)