10x series: не кодимо, а дизайнимо

Vadym Barylo
DoneDOneSoft
Published in
6 min readJan 4, 2023

--

Що таке гарний код?

Як добре, що все ще немає детермінованої градації гарного і поганого коду. Адже наявність такої шкали одразу зменьшить нашу можливість нав’язувати свої рішення навіть попри їх слабкість, просто ветуючи merge-request фразою “Code seems violates SOLID”, “it looks not very clean”, “it looks very tangled”.

Цієї фрази достатньо, щоб принизити партнера, звеличити себе в очах інших, заблокувати будь-які розумні рішення без жодного адекватного аргументу. Робота — мрія.

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

Гарний код — це простий інтуітивно зрозумілий код.

Гарний клас — це маленький клас описаний красивим кодом який виконує одну функцію.

Гарний модуль — це організація тотожних (сильно згуртованих) гарних класів у правильну ієрархію зі зрозумілою взаємодією між ними.

Гарний проект — це організація тотожних (сильно згуртованих) гарних модулів у правильну ієрархію зі зрозумілою взаємодією між ними.

Гарний продукт — це гарно задокументована інтеграція слабо зв’язаних гарних проектів.

Ще можна погратися в термінологію “якісного”:

Якісний код — це гарний код, який виконує задану задачу максимально швидко і без сайд-ефектів.

Якісний клас — це клас, який відповідає своїм вказаним специфікаціям, написаний якісним кодом.

Якісний модуль — це високорівнева конструкція, що автоматизує рішення задач окремої частини доменної моделі.

Якісний проект — це високорівнева конструкція, що ефективно автоматизує рішення всіх задач вказаних замовником в окремому сегменті.

Якісний продукт — це комплекс проектів для ефективного вирішення всіх задач замовника окремого домену.

Simple and elegant

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

Метрики якісного коду

І тут виникає питання — а як зрозуміти що код простий і якісний, якщо він не самодостатній для рішення конкретної проблеми кінцевого користувача?

З перевіркою простоти все легко — це з’ясовується на етапі ревью, оскільки в собі ця перевірка не несе ніякого іншого функціонального навантаження і з’ясування коректності виконання. Це хоч і не бінарний критерій і не повністю детермінований (скільки людей стільки і думок; скільки проявів ego, стільки і конфліктних ситуацій), але більш менш просто вирішується в результаті адекватного і професійного ревью.

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

Для чого тоді специфікації?

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

Тому важливо мати індикатори бінарними, тобто просто сигналами чи та чи інша специфікація виконується. Абсолютно не важливо причина, важливий сам факт. Система буде знаходиться в життездатному стані, коли всі індикатори всіх атомарних конмпоненитів сигналізують про успішність перевірки конкретної специфікації.

Race car aerodynamics

При чому тут 10x?

Для швидкого руху, що може включати болючі зміни існуючого функціоналу, дуже важливо мати потужну систему індикаторів на існуючий код для швидкого виявлення відхилення системи в конкретному місці від узгодженої специфікації (від норми).

Це і є принцип TDD/BDD, коли тест стає першим користувачем нашого нового функціоналу, а система тестів є бінарною метрикою на відповідність коду специфікації.

Car checklist

Але дуже важливий момент тут, що тест\індикатор — це запрограмований користувач, який має використувати компонент по принципу чорного ящика, коли деталі імплементації тієї чи іншої поведінки невідомі.

Є велика проблема “підлаштування під поведінку” — знаючи як система працює з середини, ми ненавмистно можемо перенести в специфікацію точну копію імплементації, включаючи потенційни проблеми. Іншими словами — знаючи як виглядає велосипед, дуже важко описати пристрій на 2 колесах, щоб він виглядав не як ЦЕЙ велосипед.

Тест і є специфікацією?

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

Саме тому тести можуть і мають слугувати тими самими специфікаціями, а їх виконання і є бінарний результат перевірки.

Саме тут TDD/BDD якнайкраще входить в гру. Ще до потатку опису поведінки ми впроваджуємо набір специфікацій для цієї поведінки і виконавців цих перевірок. І ця система буде максимально динамічною, дозволяючи створювати і модифікувати специфікації в процесі побудови системи від високорівневих модулів до елементарних компонентів.

Testing count operator in RxJS

Специфікація є узгодженим обмеженням системи

Тепер ми маємо максимальну передбачуванність в поведінці системи, адже всі обмеження описані і перевіряються. І найголовніше — вони в симбіозі з імплементацією поведінки. Якщо ми хочемо змінити поведінку в процесі еволюції — ми маємо описати зміни до специфікації, що в свою чергу може призвести до змін в залежних специфікаціях.

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

Car manufacturing speed limit

Інші індикатори якісного коду

Benchmark

Компонент є елементом цілісного механізму. Це шестерня робочого елементу, тому не лише важливо що вона крутиться, а чи крутиться вона достатньо швидко, щоб не сповільнити весь механізм. Тому додатковими індикаторами мають бути benchmark-тести продуктивності окремих (особливо критичних) елементів системи під навантаженням.

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

Документація

Документація — важливий елемент якості коду, оскільки спрощує інтеграцію і взаємодію компонента з іншими сторонніми модулями, спрощує використання іншими розробниками. Наявність документації легко перевіряється автоматично (lint, sonar), якість — це вже досить суб’єктивна складова, тому вирішується через рев’ю іншим інженером.

RxJS every operator

Логування

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

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

Потреба логування є частиною специфікації компонента і має бути описана і провалідована.

Підсумок

Особливості 10x інженера в тому, що на навіть для низькорівневих конструкцій (клас, модуль) використовуються всі ті практики, що і для систем в цілому — збір і декларування специфікацій, перевірка поведінки під навантаженням, документація, логування і моніторинг і т.д. Різниця тільки, що системи загалом обсуговуються цілими командами, тоді як нижчі конструкції в тому ж об’ємі одним інженером. Як результат — це вибудовує необхідні цінності і дисципліну, що потім використовується як модель для більших систем і організації команд.

Тому 10x — це все ж більше система цінностей, ніж швидкість написання коду. А правильна система цінностей неминуче призводить до багаторазового збільшення продуктивності.

--

--