Не будуй стійких стосунків зі своїми компонентами.

Примітка: деякі приклади коду будуть базуватися на React. Однак концепції та патерни універсальні і не прив’язані до конкретного фреймворку.

Нічого не триває вічно

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

Ранні етапи

Для вирішення цієї проблеми можна взяти як приклад простий і широко використовуваний компонент під назвою Input. На початку проекту наш клієнт повідомляє, що компонент матиме два варіанти: стандартний та з обводкою, а також текст як placeholder. Як розумні фронтенд-розробники, ми, ймовірно, створимо щось подібне:


На даному етапі наш Input задовольняє всі вимоги і здається простим у використанні на будь-якій сторінці додатку. За допомогою не більше ніж 5 рядків коду, ми маємо функціональний компонент.

Тепер клієнт хоче, щоб іконка пошуку з'являлася зліва всередині інпуту в деяких областях додатку. Це здається не надто складним; ми можемо додати новий пропс, який вказуватиме, яку іконку використовувати, і компонент сам з цим впорається:


Добре, це вирішує нашу проблему, і клієнт задоволений.

Після презентації продукту дизайнери розуміють, що деякі інпути мають вказувати валюту з ярликом праворуч, наприклад USD. Щоб вирішити це, ми можемо додати новий пропс для вказівки валюти.


Ще одна проблема вирішена.

Збільшення складності

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

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

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


Здається, що це працює, і те, чого UI не розуміє, не може завдати шкоди, правда?

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

Уявімо, наприклад, що на новій сторінці нам потрібно використовувати Input тільки як інпут для пароля. Що ми робимо з усіма іншими пропсами, які ми не будемо використовувати? Ми можемо просто їх ігнорувати, але компонент має бути готовий до таких випадків і належно обробляти кожну взаємодію.

Трохи пізно

Уявімо, що наступна вимога — іконка в Input повинна адаптуватися під вибрану валюту.
Отже, якщо я вибираю EUR, я маю очікувати, що символ “€” з'явиться на початку інпуту.

Чи слід передавати символи для кожної валюти через окремий пропс і відображати їх залежно від вибраної валюти?

А як щодо іконки “search.svg”, яку ми інтегрували на початку?

На цьому етапі, з новими вимогами, ми стикаємося з такими варіантами:

  • Спробувати інтегрувати селектор і оновити іконку в одному компоненті (це включатиме багато умов та складну логіку).
  • Відокремити Input від інших типів інпутів, назвавши його InputCurrencySelector. Це призведе до дублювання стилістичної логіки в різних частинах додатку.
  • Повністю відмовитися від компонента Input і створити новий — NewInput.

У кожному з цих випадків ми вводимо технічний борг, і крива входження росте.

Що сталося по ходу?

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

Як і в будь-яких токсичних стосунках, ми маємо відпустити його.

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

Компонент Input повинен фокусуватися саме на цьому, без турбот щодо іконок чи селекторів.

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

Вміст Input не повинен визначатися через пропси. Якби ми зберегли основні обов'язки елемента HTML інпуту, структура нашого Input була б зовсім іншою.


Примітка: ми залишили variant як він є, як це визначено в самому компоненті.

Якщо нам потрібно додати іконку (неважливо, яка саме), ми можемо зробити це незалежно від нашого компонента Input.




Якщо нам також потрібен селектор, ми можемо працювати над ним в окремому компоненті.



  setSelectedCurrrency(currency)}  
 />  

Таким чином, ми розділяємо обов'язки кожного компонента і зводимо їх до їхніх основних завдань:

  • Icon відображає іконку
  • CurrencySelector лише відповідає за повернення вибраної валюти
  • Input обробляє введені користувачем дані

Додатково, ми можемо додати елемент `` для правильного розташування елементів.

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

Якщо любите їх, відпустіть

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

Перекладено з: Don’t build lasting relationships with your components

Leave a Reply

Your email address will not be published. Required fields are marked *