Що таке патерни проєктування

Що таке патерни проєктування

Як розробнику спростити код за допомогою шаблонів.

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

В’ячеслав Щупак понад 15 років розробляє ПЗ та керує проєктами в IT. Останні 3 роки він відповідає за бекенд у компанії Synergy Sports Technology, яка займається збором та обробкою спортивної аналітики. А раніше консультував розробників програми Дія, створював програму для перекладачів Trados та мобільні застосунки для Київської міськадміністрації й контактного центру «1551», а також працював із Big Data.

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

Що таке патерн

Патерн (шаблон) проєктування — це іменований опис проблеми та її розв’язання, яке можна використовувати у розробці інших систем. Таке визначення дає у своїй книзі «Застосування UML і шаблонів проєктування» (Applying UML and Patterns) Крег Ларман — фахівець із гнучкої методології та ітеративної розробки.

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

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

Хоч би якою мовою не писав програміст — йому потрібні інструменти, щоби спрощувати складні конструкції. Патерни проєктування — один із таких інструментів.

Коли використовують патерни

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

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

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

class Order
{
    public void calculate(){ ... }
    public void addItem(Product product){ ... }
    public List<Product> getItems(){ ... }
    ...
    public void load(){ ... }
    public void save(){ ... }
    public void print(){ ... }
}
class Order
{
    public void calculate();
    public void addItem(Product product){ ... }
    public List<Product> getItems(){ ... }
} 
class OrderRepository
{
    public Order load(int orderId){ ... }
    public void save(Order order){ ... }
} 
class OrderPrinter
{
    public void print(Order order){ ... }
}
  • SOLID: ключові принципи об’єктно-орієнтованого програмування, які допомагають оптимізувати код та створювати гнучке програмне забезпечення. SOLID — це абревіатура від п’яти основних принципів:
    • Single responsibility — Принцип єдиного обов’язку
    • Open-closed — Принцип відкритості/закритості
    • Liskov substitution — Принцип підстановки Барбари Лісков
    • Interface segregation — Принцип поділу інтерфейсу
    • Dependency inversion — Принцип інверсії залежностей
  • Event Sourcing: архітектурний шаблон, який дозволяє виконувати та зберігати зміни в застосунку в однаковій послідовності.
  • Алгоритми та структури даних: інструменти, що допомагають упорядковувати, зберігати та працювати з даними оптимальним способом.
  • Test Driven Development: техніка розробки програмного забезпечення, заснована на повторенні коротких циклів.

Ці та інші інструменти ми вивчаємо на моєму курсі «Чистий код та патерни проєктування».

Навіщо застосовувати патерни

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

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

Патерни — це універсальна мова розробників. Кожен патерн передбачає знання певної схеми. Але програмістам не потрібно описувати їх — достатньо сказати «Фабрика» чи «Компоновник». Як, наприклад, ми говоримо «Я зателефоную [телефоном]» замість «Я використовую засіб зв’язку за допомогою радіохвиль, передачі даних, дискретизації, фазового кодування та шифрування».

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

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

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

Які патерни використовують найчастіше

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

Приклади графічних анотацій для деяких популярних патернів

Наприклад, я працював у компанії SDL — у команді розробників відомої системи автоматизованого перекладу Trados. Складність завдання полягала в тому, що в оригінальних файлах часто є не тільки текст, а й таблиці, картинки, інші елементи. Плюс система підтримує понад 40 форматів — Word, Excel, PDF, html та десятки інших. У своїй роботі ми найчастіше використовували два патерни:

  • «Компоновник» (Composite) — об’єднує групи об’єктів у деревоподібну структуру, схожу на меню з пунктами, і дозволяє працювати як з окремими об’єктами, так і з групами.
  • «Відвідувач» (Visitor) — використовується, коли є багато об’єктів різних класів та інтерфейсів і потрібно виконувати дії над кожним із них.

Майже всі сучасні застосунки використовують під'єднання до серверів та баз даних. У цій операції застосовується патерн «Об’єктний пул» (Object Pool).

Патерн «Прототип» (Prototype) дозволяє створювати об’єкти на основі вже наявних (по суті, копіювати їх). Вбудований у мову програмування JavaScript та її похідні (такі як TypeScript).

Шаблонний метод (Template method) визначає основу алгоритму та допомагає спадкоємцям змінювати кроки без змін загальної структури. Використовується у мовах програмування, де є абстрактні класи (Java, C#, C++ тощо).

Патерн «Ітератор» (Iterator) покращує навігацію колекцією об’єктів.

Патерн «Об’єкт-Значення» (Value Object) використовується для зберігання простих величин (наприклад, таких як гроші або дати).

Сучасні системи часто використовують ліниву ініціалізацію (Lazy initialization) — підхід у програмуванні, коли складна дія виконується «на вимогу». Наприклад, «Фабричний метод» (Factory Method) передбачає, що базовий клас доручає створення об’єктів класам-спадкоємцям. Завдяки цьому не потрібно багаторазово описувати створення об’єкта та вносити зміни до різних підкласів (це робиться один раз).

З новими технологіями постійно з’являються нові патерни. Наприклад, популярність мікросервісів призвела до необхідності патернів Database per Service, External Configuration, Service Discovery та Circuit Breaker. Потреба розуміти стан розподілених систем — до необхідності патернів Log Aggregation, Distributed Tracing та Health Check. Акцент сучасних систем на маркетингу в тому числі сприяв популярності патерну Blue-Green Deployment.

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

В інтернеті є безліч матеріалів на тему патернів — їх навіть занадто багато, щоби відстежувати все. На курсі «Чистий код та патерни проєктування» ми розберемо найпопулярніші патерни, навчимося застосовувати шаблони проєктування на практиці та вивчимо кожну деталь під час livecoding-сесій.

Ще статті
Що алгоритми дозволяють робити з кодом і чому розробнику потрібно бути креативним.
Віктор Шитюк, Lead Data Engineer з 12 річним досвідом у IT сфері, про робочу рутину інженера даних, must-have інструменти та перспективи професії.