Архитектура и паттерны проектирования

Дом можно построить без архитектора, а многоэтажку уже нет. С программами так же — чем больше кода, тем важнее его организовывать.

Время чтения: 6 мин

Писать понятный код — сложно.

Каждая строчка кода увеличивает нагрузку на читателя, поэтому много кода читать сложно. С другой стороны, если в коде недостаточно деталей и объяснений, то понять его смысл тоже очень сложно. При написании программ нам надо соблюдать баланс между лаконичностью и полнотой, между абстракциями и конкретикой.

Найти этот баланс нам помогают решения, которые сообщество воспринимает как стандартные, шаблонные. Иногда такие решения получают имена и становятся паттернами или архитектурными подходами.

В этой статье мы проведём краткий обзор архитектурных подходов и паттернов проектирования, которые используют в современном фронтенде.

Кратко

Скопировано

Архитектура приложения — это набор решений о том, как модули приложения будут общаться друг с другом и с внешним миром.

Архитектура включает в себя подходы: ограничения, правила и эвристики, которым надо следовать при написании кода.

Паттерн проектирования — шаблонное решение частой архитектурной проблемы.

Область ответственности паттернов проектирования меньше, чем у архитектуры в целом. Паттерны помогают нам решать проблемы на более «низком уровне», ближе к непосредственно коду. Архитектура же решает проблемы проектирования всей системы в целом.

Архитектура во фронтенде

Скопировано

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

Зачем нужна архитектура

Скопировано

Люди плохо умеют прогнозировать будущее. Нам сложно предсказать, как будет меняться программа или требования к ней. Единственное, что мы знаем точно — требования (а значит, и программа) будут меняться.

Грамотная архитектура помогает спроектировать и развивать систему так, чтобы её было проще и удобнее расширять и изменять.

  • Если общение между модулями регламентировано, их реализацию проще заменить на другую.
  • Если общение с внешним миром регламентировано, меньше шансов для утечки данных.
  • Если код разделён грамотно, программу проще тестировать.
  • Если код организован понятно, уходит меньше времени на добавление новых фич и поиск багов в старых.
  • Если архитектура широко известна, погружение в проект проходит быстрее.

Какие есть архитектурные подходы

Скопировано

Мы можем условно разделить архитектурные подходы по их целям и зоне действия.

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

Самый известный из таких подходов — Model-View-Controller. Он выделяет 3 «типа» задач, в соответствии с которыми назначает модулям роли. Мы подробно говорим об этом подходе и его вариациях в статье «Архитектура: Model View Whatever».

Другие определяют, насколько каждый из модулей близок к бизнес-логике. Таким подходам важно, какая часть кода занимается непосредственно задачей приложения, а какая — инфраструктурными задачами.

Например, в приложении для обработки фотографий бизнес-логикой были бы функции фильтров, а инфраструктурными задачами — обращение к API камеры телефона.

В зависимости от степени близости к бизнес-логике такие подходы делят код на «слои». Самый распространённый подход среди таких — это трёхслойная архитектура.

Третьи управляют потоками данных в приложении. Они определяют, как модули общаются друг с другом: напрямую, опосредованно или с помощью специальных сервисов типа шины событий.

Во фронтенде самый, наверное, известный подход — это Flux и его самая распространённая реализация — Redux. Это пример однонаправленного потока данных.

Кроме него используют двунаправленный поток, например, реактивные обновления данных. Мы подробно говорим о каждом в статье «Архитектура: потоки данных».

Другие подходы определяют компоновку приложения. Будет это одна большая программа (монолит) или набор нескольких программ поменьше (микросервисов).

В чём минусы архитектуры

Скопировано

Создание, организация и следование архитектуре всегда требует ресурсов: времени, денег, умственных затрат. Выбор следует делать после сравнения издержек и выгод каждого из подходов-кандидатов.

Паттерны проектирования

Скопировано

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

Например, сервер присылает нам данные в виде:

        
          
          {  some_data: ["Name", "Lastname"]}
          {
  some_data: ["Name", "Lastname"]
}

        
        
          
        
      

А мы хотим их видеть такими:

        
          
          {  someData: "Name Lastname"}
          {
  someData: "Name Lastname"
}

        
        
          
        
      

Для решения такой проблемы есть паттерн «Адаптер». Он делает несовместимое стороннее API подходящим для нашего приложения.

        
          
          function serverToClientAdapter(data) {  return {    someData: data.some_data.join(" "),  }}
          function serverToClientAdapter(data) {
  return {
    someData: data.some_data.join(" "),
  }
}

        
        
          
        
      

Таких стандартных решений много. Мы можем разделить их на несколько групп.

Порождающие

Скопировано

Порождающие паттерны помогают решать задачи с созданием сущностей или групп похожих сущностей. Они убирают лишнее дублирование, делают процесс создания объектов короче и прямолинейнее.

Среди порождающих паттернов мы можем выделить:

  • «Фабрику»;
  • «Фабричный метод»;
  • «Абстрактную фабрику»;
  • «Строителя».

Структурные

Скопировано

Структурные паттерны помогают решать задачи по совмещению и сочетанию сущностей. Они заботятся о том, как сущности могут использовать друг друга.

Среди структурных паттернов можем выделить:

  • «Адаптер»;
  • «Декоратор»;
  • «Фасад»;
  • «Прокси».

Поведенческие

Скопировано

Поведенческие паттерны распределяют ответственность между модулями и определяют, как именно будет происходить общение.

Среди поведенческих паттернов можем выделить:

  • «Цепочку ответственности»;
  • «Стратегию»;
  • «Команду»;
  • «Наблюдателя».

Архитектура и паттерны — не цель

Скопировано

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

Иногда решение без сложной архитектуры будет проще и быстрее. Например, при разработке прототипа архитектура зачастую не нужна.

Архитектурные подходы и паттерны — это инструменты. Мы советуем приносить инструменты в проект по мере необходимости и сравнив выгоды и издержки каждого.