Что такое паттерны проектирования
Как разработчику упростить код с помощью шаблонов.
Можно ли писать код так, чтобы его понимал только автор — разработчик? Да, если он же — единственный заказчик, создатель и пользователь продукта. Иначе это дурной тон.
Вячеслав Щупак более 15 лет разрабатывает ПО и управляет проектами в IT. Последние 3 года он отвечает за бэкенд в компании Sportradar, которая занимается сбором и обработкой спортивной аналитики. А ранее консультировал разработчиков программы Дія, создавал программу для переводчиков 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-сессий.