Component-Driven Development

Component-Driven Development

  • 7 серпня
  • читати 20 хв
Володимир Шайтан
Володимир Шайтан Senior Full Stack Developer у UKEESS Software House, Викладач Комп'ютерної школи Hillel.

Колись я почув слова, що компоненти — це нові примітиви нашого часу. І знаєте що я думаю з цього приводу? Так і є.

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

Реальність трохи інша, але колись буде і так, я вірю в це (майже).

Отже, компоненти.

Компоненти — це основа всього. Це фундамент, цегла, із якої будують будинки (проєкти). Різниця тільки в тому, що компоненти потім можна дістати, відредагувати і поставити на місце. Зручно? Зручно.

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

Компоненти — це та штука, яка допомагає бізнесу масштабуватись, оптимізовуватися, поліпшуватися.

ТАК ЩО Ж ТАКЕ CDD?

Розробка, керована компонентами (Component-driven development) — це такий підхід до розробки програмного забезпечення, який описує процес створення модульних і повторно використовуваних компонентів, які можуть просто інтегруватись у різні частини проєкту. Коротко кажучи, на виході це будуть слабозвʼязані між собою незалежні компоненти.

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

Давайте окремо розглянемо кожен із них:

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

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

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

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

ЯКЩО ВИ ХОЧЕТЕ НАВЧИТИСЯ

Зараз є безліч платформ, де ви можете створювати, зберігати та звідки можна брати компоненти для використання. Одна з найпопулярніших платформ — це Bit.

За допомогою Bit розробники можуть створювати компоненти та ділитися ними, документувати їх, тестувати їх, що дуже спрощує сам процес розробки тих універсальних компонентів. Також Bit підтримує всім відомі технології JavaScript, React, Angular, Vue.js та інші. Тобто проблем із цим у процесі створення і шерингу компонентів не буде.

ПЕРЕВАГИ ТА НЕДОЛІКИ CDD

Серед явних переваг — легка масштабованість.

У контексті Component-Driven Development (CDD), масштабованість означає здатність системи, побудованої на основі компонентів, ефективно зростати й адаптуватися до збільшення складності, обсягу користувачів або функціональних вимог.

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

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

Недоліки, само собою, також є, куди без них. Почнемо.

Для того, аби з самого початку правильно спроєктувати всю архітектуру проєкту, який побудований за CDD, потрібні неабиякі знання, я вам скажу. Бо обовʼязково потрібно продумати як саме правильно ізолювати компоненти, де будуть межі компонентів, як саме вони будуть звʼязані один з одним, або інтегровані один в одного. Це навіть звучить архітектурно нелегко, але зробити це необхідно, бо інакше неможливо правильно використовувати компоненти як сутності. Також для такого підходу часто потрібні досвідчені розробники, які зможуть грамотно цим усім керувати й оптимізовувати.

Тепер хочу навести приклад, який має вигляд цей ідеально ізольований, ідеально звʼязаний з іншими компонент із чіткими межами. Дивимося:

// alert.js

class Alert {
  constructor(message) {
    this.message = message;
    this.element = null;
  }

  create() {
    // Создаём сообщение
    this.element = document.createElement('div');
    this.element.className = 'alert';
    this.element.textContent = this.message;

    const closeButton = document.createElement('span');
    closeButton.className = 'alert-close';
    closeButton.textContent = '×';
    closeButton.addEventListener('click', () => this.close());

    this.element.appendChild(closeButton);

    return this.element;
  }

  close() {
    // Удаляем сообщения с DOM
    if (this.element) {
      this.element.remove();
      this.element = null;
    }
  }
}

export default Alert;

Как мы интегрируем этот компонент в другой компонент:

// main.js

import Alert from './alert.js';

// Создаём новое сообщение
const alert = new Alert('This is an alert message.');

// Добавляем сообщение в документ
document.body.appendChild(alert.create());

// Закрываем сообщение через некоторое время
setTimeout(() => {
  alert.close();
}, 5000);

Пояснюю чому весь код вище — еталонний в CDD.

  • Чітко визначені межі компонента:
    - компонент Alert відповідає тільки за створення і закриття повідомлення,
    - має публічні методи create і close, які чітко визначають як взаємодіяти з компонентом.
  • Мінімальні залежності:
    - компонент не має залежностей від будь-яких інших компонентів або зовнішніх ресурсів.

Звісно, за приклад також може бути компонент кнопки, модального вікна і таке інше.

Також маю згадати, що в JavaScript є нативна підтримка компонентів. Зараз я маю на увазі вебкомпоненти.

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

  • Custom Elements (Користувацькі елементи) дозволяють розширювати HTML, створюючи власні елементи. Це дає змогу визначити нові HTML-теги з власними функціями й поведінкою.
  • Shadow DOM (Тіньовий DOM) дозволяє створювати інкапсульовані області в межах HTML-елементів. Це забезпечує ізоляцію стилів і скриптів, що унеможливлює їх вплив на решту документа.
  • HTML Templates (HTML Шаблони) дозволяють визначати шаблони HTML, які не рендеряться до того, як їх не буде явно вставлено в DOM. Це корисно для створення повторно використовуваних частин інтерфейсу.

Додаю невеликі приклади для кожного з пунктів:

Custom Elements:

// custom-element.js

class MyElement extends HTMLElement {
  constructor() {
    super();
    this.innerHTML = `<p>Hello from MyElement!</p>`;
  }
}

customElements.define('my-element', MyElement);

Использование:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Custom Element Example</title>
  <script src="custom-element.js" defer></script>
</head>
<body>
  <my-element></my-element>
</body>
</html>

Shadow DOM:

// shadow-dom.js

class ShadowElement extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
      <style>
        p { color: red; }
      </style>
      <p>This is inside the Shadow DOM</p>
    `;
  }
}

customElements.define('shadow-element', ShadowElement);

Использование:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Shadow DOM Example</title>
  <script src="shadow-dom.js" defer></script>
</head>
<body>
  <shadow-element></shadow-element>
</body>
</html>

HTML Templates:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>HTML Template Example</title>
</head>
<body>
  <template id="my-template">
    <style>
      p { color: green; }
    </style>
    <p>This is a template example.</p>
  </template>

  <script>
    class TemplateElement extends HTMLElement {
      constructor() {
        super();
        const template = document.getElementById('my-template').content;
        this.attachShadow({ mode: 'open' }).appendChild(template.cloneNode(true));
      }
    }

    customElements.define('template-element', TemplateElement);
  </script>

  <template-element></template-element>
</body>
</html>

ПРО ФРЕЙМВОРКИ

Поняття композиції та декомпозиції — це дуже важливі поняття для будь-якого фреймворку, і це також повʼязано з CDD.

Пояснюю:
Композиція і декомпозиція дозволяють створювати масштабовані та легко підтримувані додатки шляхом розбиття складних систем на дрібні компоненти (декомпозиція) й об’єднання цих компонентів для створення складніших систем (композиція).

Коли ви пишете код на React, Vue, Angular, то ви постійно цим користуєтеся, навіть якщо ще не знаєте цього.

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

Декомпозиція:

// header.js
class HeaderComponent extends HTMLElement {
  constructor() {
    super();
    this.innerHTML = `<header>Header Content</header>`;
  }
}
customElements.define('header-component', HeaderComponent);

// footer.js
class FooterComponent extends HTMLElement {
  constructor() {
    super();
    this.innerHTML = `<footer>Footer Content</footer>`;
  }
}
customElements.define('footer-component', FooterComponent);

// main-content.js
class MainContentComponent extends HTMLElement {
  constructor() {
    super();
    this.innerHTML = `<main>Main Content</main>`;
  }
}
customElements.define('main-content-component', MainContentComponent);

Композиция:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Component Composition Example</title>
  <script src="header.js" defer></script>
  <script src="footer.js" defer></script>
  <script src="main-content.js" defer></script>
</head>
<body>
  <header-component></header-component>
  <main-content-component></main-content-component>
  <footer-component></footer-component>
</body>
</html>

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

А от у прикладі з композицією ми створили так само три компоненти, які обʼєднані в повний інтерфейс користувача.

ВИСНОВОК

Ми з вами в цій статті тільки почали «загравати»‎ з CDD. Загалом, це потужний інструмент для розробки програмного забезпечення, у якого є свої переваги й недоліки, які неодмінно варто враховувати.

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

На це знадобиться, вірогідно, великий бюджет, багато зусиль і години й години в гуглі, видивляючись, як же правильно то все писати :)

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

До зустрічі у наступній статті!

Рекомендуємо публікації по темі