25 вересня 2023 р.

Ніндзя-код

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

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

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

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

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

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

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

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

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

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

Нехай неочевидні особливості мови направляють вас.

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

// взято з добре відомої 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…)