Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос нашим менторам. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете

Архитектура

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

Не существует единственного верного подхода при организации вашего приложения. Известные подходы — всего лишь видение конкретных людей для конкретных ситуаций и конкретных стеков (язык + инструментарий). Любая хорошая архитектура базируется на фундаментальных законах и принципах. Большую часть из них вы уже знаете:

  • Изоляция побочных эффектов;
  • Хорошая абстракция (абстракция данных, композиция, разделение);
  • Сильные барьеры (между абстракциями);
  • Слабые связи (возможность замены/независимого развития).

Из популярного можно выделить следующие словосочетания:

  • The Clean Architecture
  • Onion Architecture
  • Hexagonal Architecture

Все эти архитектуры сводятся так или иначе к тому, что наше приложение представляет из себя набор слоёв (тех самых абстракций), которые связаны друг с другом определённым образом и отвечают за определённые аспекты системы. Лучше всего начать анализ с красивой картинки:

architecture

Начать стоит с того, что: Фреймворк — это не ваше приложение. Остановитесь на секундочку и хорошо обдумайте фразу. В типичных веб-приложениях фреймворк определяет вообще всё. Приложение на 100% переплетается с ним и становится его частью. Программист начинает мыслить в рамках возможностей фреймворка и его ограничений, и в его голове появляются несуществующие причинно-следственные связи.

Да, конечно, сложно (и не нужно) делать абсолютную изоляцию, но и всегда нужно проводить чёткую грань между приложением и тем фреймворком, который вы используете.

Домен

Первым и базовым слоем в приложении является Домен. Это реализация вашей модели предметной области. Чистая бизнес-логика без намёка на инфраструктуру.

Вот что обычно характеризует домен:

  • Чистый код (pure)
  • Plain Old X Object (POXO)
  • Бизнес-логика
  • Валидация

POXO - это обобщённое название, которое в каждом конкретном языке приобретает своё собственное имя. В Java POJO, в Ruby PORO, и так далее. Этой аббревиатурой описывают объекты, которые построены исключительно на возможностях самого языка, без дополнительных абстракций. Так подчёркивается, что домен не использует внешних библиотек, которые влияют на его организацию. Не надо фанатично относиться к этой идее. В некоторых языках сформировались свои правила, и они идут в разрез с общими концепциями.

Персистентность

Реализовать логику только половина дела. В конце концов нужно сохранить наши изменения. Казалось бы, что эта часть должна быть самой простой, но нет. Состояние, его изменение и поддержка целостности настолько сложная история, что придуманы огромные и сложные фреймворки, называемые ORM. Обычно они построены вокруг двух самых распространённых паттернов:

  • ActiveRecord
  • DataMapper

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

Репозиторий

Репозиторий — это хранилище однотипных сущностей. Позволяет как делать выборки, так и сохранять сущности внутри себя. Для простоты в нашем приложении репозитории будут хранить все данные в памяти.

const film = new Film(name, duration);
repository = new FilmRepository();
repository.save(film);

repository.find(film.id); // film
repository.find(unknownId); // Boom!

Инфраструктура

Именно в эту категорию попадает фреймворк, UI и вообще любая прикладная история. На картинке этот слой находится на самой внешней стороне. Из него происходит отправка электронных писем, смс, и выполняется так называемая логика приложения. Например, перенаправление на определённую страницу после создания какой-то сущности.

Сервисы

Помните диаграмму вариантов использования? Вот именно эти варианты и являются единственным способом изменения состояния вашего приложения. Ваш домен обрастает слоем так называемых сервисов. Каждый сервис представляет собой набор функций, имитирующих бизнес-сценарии, например, "добавить в друзья", "поставить лайк".

class CinemaService {
  createFilm(name, duration) {
    const film = new Film(name, duration);
    this.FilmRepository.save(film);
    return film;
  }
}

Инфраструктурный слой является главным пользователем вашего слоя сервисов. Сервисы могут вызываться в ui, в контроллерах, в асинхронных обработчиках. Слой сервисов настолько важен сам по себе, что Мартин Фаулер описывает его как шаблон проектирования Service Layer

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

Входными данными в функции сервиса не могут быть сущности предметной области. Причина такого правила очень проста. Сервисы – слой поверх предметной области, он инкапсулирует в себе все сценарии. Если сущности окажутся снаружи, то логика становится размазанной между слоями (потекла абстракция), пропадает изоляция. Но так сделать не всегда возможно. Иногда это связано с устройством конкретных фреймворков, которые не дают нормально абстрагировать предметную область от инфраструктуры. В такой ситуации не стоит бороться насмерть за концептуальную чистоту, идите на компромиссы.

То же самое касается выходных данных. В теории, отдавать наружу сущности нельзя по той же причине, по которой нельзя ими оперировать вне сервисов. Так как после возврата крайне просто начать ей оперировать, что сразу повлечёт за собой размазывание логики по слоям. Вместо сущности, как правило, отдают специальный "Data Transfer Object". В отличие от сущности он не содержит поведения и используется исключительно как контейнер для чтения.

DTO - Используется для передачи данных между подсистемами приложения. DTO, в отличие от business object, не должен содержать какого-либо поведения

  • Неизменяемый
  • Просто данные

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

И последнее по списку, но не последнее по важности, не вызывайте сервисы из сервисов. Если появляется общий код, то выносите общую функциональность, но не позволяйте самому сервису начинать мешаться с доменом. Последнее означает то, что если сервисы начинают использовать внутри себя сервисы (тот же или другие), то с большой вероятностью происходит нарушение принципа одного уровня абстракции. Сервисы — слой поверх домена, а это значит, что на одном уровне нельзя использовать и домен, и сервис.


<span class="translation_missing" title="translation missing: ru.web.courses.lessons.mentors.mentor_avatars">Mentor Avatars</span>

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят менторы из команды Хекслета или другие студенты.

Для полного доступа к курсу нужна профессиональная подписка

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

Получить доступ
115
курсов
892
упражнения
2241
час теории
3196
тестов

Зарегистрироваться

или войти в аккаунт

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 115 курсов, 2000+ часов теории
  • 800 практических заданий в браузере
  • 250 000 студентов

Нажимая кнопку «Зарегистрироваться», вы даёте своё согласие на обработку персональных данных в соответствии с «Политикой конфиденциальности» и соглашаетесь с «Условиями оказания услуг». Защита от спама reCAPTCHA «Конфиденциальность» и «Условия использования».

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Rambler
Логотип компании Bookmate
Логотип компании Botmother

Есть вопрос или хотите участвовать в обсуждении?

Зарегистрируйтесь или войдите в свой аккаунт

Нажимая кнопку «Зарегистрироваться», вы даёте своё согласие на обработку персональных данных в соответствии с «Политикой конфиденциальности» и соглашаетесь с «Условиями оказания услуг». Защита от спама reCAPTCHA «Конфиденциальность» и «Условия использования».