Transcript for:
MVC Паттерн в Разработке

всем привет сегодня хочу поговорить про mvc Почему mvc Потому что это самый важный паттерн н разработчика Начну с того откуда пошла идея И какую проблему решают покажу пару примеров на схемах расскажу про минусы покажу структуру настоящего проекта жизненного проекта в котором есть mvc также приложу ссылки на книги и доклады где темы которые я [музыка] затрагивает уровня до jor включительно те кто учат Java но не обязательно потому что те же самые идеи они применимы и для других языков особенно о языков таких как Прежде всего это лекция для тех кто пишет проекты моего род мапа Чего сегодня не будет это примеры примеры кода и примеры конкретных проектов цель лекции дать вам такой материал чтобы Вы самостоятельно его применили на практике во время работы над проектами а начну со сст архитектуры и того как mvc к ней относится когда мы пишем приложение нам неизбежно нужно заниматься разными вещами работать с интерфейсом работать с данными работать с логикой Если писать всё это в одном классе то он начнёт очень быстро расти И затрагивать множество разных сфер ответственности поэтому ради изоляции слоёв друг от друга изоляции контекста пришла идея делить приложение можно считать это применением либо развитием принципа Single responsibility из Solid вторая цель этой идеи - это понятный предсказуемый рецепт э расширения расширения проектов допустим что вы работаете в команде И вам нужно написать вам нужно написать новый функционал если структура проекта понятная И очевидная вам легко будет догадаться Каким образом структурировать вашу работу и командная разработка упрощается потому что все вы действуете в рамках одних и тех же идей таким образом сст архитектура стала основой многих фреймворков и фреймворков графической разработки например фреймворки для Android приложений десктопных приложений Spring у них у всех есть внутри в том либо ином виде слоистой архитектуры Если на практике посмотреть как это выглядит то обычно слоёв от трёх до пяти и их можно расположить вертикально Допустим что мы пишем Android приложение У нас есть э UI есть бизнес логика и есть данные стрелочки показывают направление импортом направление всегда идёт сверху вниз Это значит что бизнес логика никогда не зависит от юя а данные никогда не зависят от бизнес логики что нам даёт такое направление импортом нам намного нам намного проще переиспользовать классы нижних слоёв в каком-то другом контексте например мы можем тот же самый слой логики переиспользовать где-то в другой форме интерфейса где-то ещё и не нужно будет ничего переписывать через направление импортом мы достигаем изоляцию слоёв друг от друга и изменения в Верхних слоях никак не не влияют на Нижние слои стрелочка справа показывает что иногда какие-то слои могут быть пропущены допустим если у нас какая-то Элементарная работа с данными прочитать и отобразить То никакой бизнес логики нет слой не нужен и UI может напрямую обращаться к данным тоже самое часто случается и в н приложениях слоистая архитектура никак не формализуются Какие конкретно в ней слои но она формализуются главные принципы это разделение на слои у каждого слоя конкретная ответственность и направление импортом mvc берёт эту идею и немножко её сложнее немножко её формализуются более конкретно в mvc появляются названия главных слоёв и примерный список ответственности этих слоёв а для примера я нарисовал простую схему приложение допустим что это веб-приложение с веб-интерфейс в котором мы можем выставить таймер запустить таймер остановить его там сбросить допустим что это приложение на JavaScript который открывается в браузере допустим человек открывает нашу страницу видит таймер он может его запустить то есть совершает действия действие совершается на View там нажатие кнопки это действие приводит к тому что вызывается какой-то метод контроллера контроллер содержит себе логику и общается с хранилищем допустим что на VI мы нажали кнопку нажать таймер запустить этот метод обработал и создал новый таймер сохранил его в хранилище и запустил какую-то логику например каждую секунду таймер обновляется там 1на секунда 2Т и так далее логика происходит в контроллере контроллер фиксирует какое-то изменение данных и отправляет его в модель чтобы модель как-то Сохрани и отвеча за то в каком виде дан сохраняются в приложении в данном случае у нас веб-приложение и допустим что данные у нас сохраняются в в Session Stage браузера допустим то есть есть модель таймера она в какой-то Stage его записывает и и держит его там таким образом View совершает действия контроллер фиксирует изменения данных и передаёт в модель модель держит в себе состояние данных отдаёт его в контроллер контролер с помощью View визуализирует данные это три таких главных слоя которые присутствуют в том или в том или ином виде в каждом э в каждом В каждой вариации mvc когда я говорю про вариации mvc э Я хочу сказать что существует множество разных подвидов этой идеи они все называются по-своему например в Android разработке есть паттен mvvm есть паттерн mvp и так далее э как правило сам фреймворк на котором вы пишите подталкивает вас к использованию той либо иной вариации э конкретной ээ mvc и редко вам нужно что-то писать с нуля поэтому самое главное что стоит делать при использовании фреймворка это довериться ему и следовать тем гайдлайны которые к которым он вас склоняет я буду в основном говорить про джаву и про backend Поэтому мои схематичные примеры будут в контексте jav бэнда также забыл упомянуть пару книг для слоистой архитектуры есть хорошая книга от or называется Software architecture patterns это больше брошюра чем книга она доступна бесплатно вот по этой ссылке которую я заметки опубликую там будет эта ссылка СМИ все главные архитектурные паттерны в том числе слои архитектура и по mvc книгу которую я советую Это Design там глава ближе к концу не помню Д или ри которая посвящена составным паттерном прежде всего MC Так теперь перейдём к более прикладному приме в Конте приложение Java backend приложение Допустим что мы пишем на Java E на сервлета и хотим реализовать rest API а работаем над серле Том регистрации пользователя А который доступен по адресу SL User и пост запрос передаёт данные для регистрации и нам нужно запрос обработать и либо зарегистрировать пользователя либо вернуть какую-либо ошибку э схема вот эта визуализирует слои и порядок взаимодействия стрелочка показывает взаимодействие зелёный прямоугольник показывает некое наполнение этого взаимодействия например например параметр запроса дто объект модель что угодно если прямоугольник есть значит у этого взаимодействия есть какое-то наполнение так допустим к в браузере кликает на зарегистрироваться он заполнил форму заполнил email и пароль нажал sign Up при нажатии происходит пост запрос в теле запроса передаётся email и пароль первым слоем который встречает запрос является селет Обычно он называется контроллер но так как у нас контекст это Java и то этот обрабатывает принимает запрос и отвечает за ри вещи это валидация данных допустим нужно проверить что это а не просто строка нужно проверить что пароль нужной длины Допустим что мы требуем ше символов а если там пять нужно ответить с ошибкой это первое За что отвечает се второе - это составление объектов и выв за сам процесс регистрации и он не знает В каком контексте мы его используем то есть что это веб-приложение или консольное приложение он не должен знать и зависеть от того В каком контексте будем его использовать поэтому мы не можем передать в сервис напрямую объекты нашего там КСТ Квеста или какие-то другие объекты которые зависят напрямую от от слоя взаимодействия средств поэтому мы передаём в каком-то сыром виде данные либо передаём их как просто параметры например строки либо что более обычно красиво оборачиваем их в дто объект про который я поговорю чуть позднее и передаём третья ответственность селета - это получить резуль рабо Серви и сформировать успешный результат либо ошибочный Я уже сказал прото это некий Объект который нужен для передачи данных либо между слоями либо в приложение или Извне приложения чтобы продемонстрировать Что такое дто например это объект который сет передаёт сервиса у него есть два атрибута это email и пароль те самые email и пароль которые нам пришли в пост запросе dto объект представляет из себя просто набор атрибутов из без бизнес логики это по факту просто самый простой объект ээ с полями и без методов единственные методы которые там могут быть - это сеттеры и геттеры э чтобы преобразовывать э одни дто в другие либо дто преобразовывать в модели есть такие инструменты как мапе я поговорю про них чуть позднее но суть в том что часто у объектов повторяются поля и чтобы не нужно было вручную переносить эти поля мы можем пользоваться маппера чтобы автоматизировать Итак селе принял Запрос сформировал дото который называется US registration и передал его сервису сервис теперь должен совершить процесс регистрации как я уже сказал сервис не знает кто его использует поэтому он никак не завязан на вопросы он не знает там ни о кодах ответа ничего ни о запросах он получает дто и отдаёт модель либо дто Таким образом мы изолируем контекст от какого-то сетевого слоя оставляем только слой логики ВРТ бизнес логика регистрации допустим что это значит вставить пользователя в базу данных И если всё было успешно Отправить ему какое-то подтверждение на почту и проинициализировать какие-то его данные допустим если мы регистрируемся в банк-клиенте нужно создать ему аккаунт счета баланс если мы регистрируемся в игре какой-то нужно создать ему там персонажа и так далее за все такие вещи отвечают отвечает сервис Это всё что касается именно происходящего в нашем приложении с точки зрения бизнес логики если бизнес логики никакой нет то как я уже говорил сервис Может селет может напрямую обращаться к слою работы с данными и сервис ради одной строчки вызова вставки в базу можно не писать поэтому сервис нужен только тогда когда есть логика следующий слой - это модель даже это не слой А это промежуточный этап жизненного цикла данных модель - это объект который описывает атрибуты таблицы из базы данных в данном случае у нас есть таблица users это пользователи там у нас у каждого У пользователя есть ID есть email и есть пароль ВТО объекте который мы получили был email и пароль мы с помощью маппера или вручную D объект Превращаем в модель User до того как модель вставлена в базу данных запись будет выложена да до того как модель вставлена в базу данных У пользователя нету идентификатора поэтому у свежей модели свежего пользователя ID email и пароль Мы Мы переносим также пароль часто происходит пароль часто претерпевает какие-то преобразования например хэширующая таким образом допустим у нас оставляет у нас остаётся Свобода менять реализацию хранилища или вообще подменять там SQL базу на другую И если мы хорошо изолировали слои друг от друга то при подобном изменении в приложении код сервиса никак не изменится в этом как раз ценность изоляции слоёв друг от друга Итак мы сформировали модель отправили его в слой Да что делает да это слой который можно расшифровать как Data aus object он занимается инкапсуляции работы с базой данных допустим в самом простом варианте это составить SQL запрос исполнить его и получить результат но под капотом слоя Да может быть целое семейство разных инструментов разных библиотек для работы с БД от от простых до полновесный orm таких как hibernate или Spring Data dao принимает экземпляры модели и возвращает то есть после вызова метода например сохранить пользователя он возвращает модель того же самого пользователя но у которого уже есть какой-то ID вот мы вставили пользователя у него id1 например и вернули модель у которого это ID заполнено под капотом да работает с базой данных на моей схеме формируется insert запрос и мы получаем э получаем qu RAL берём из него ID и возвращаем модель пользователя у которого есть ID э в реальности вместо голых SQL запросов может быть orm или какая-нибудь библиотека работы с базы данных после того как слой Да вернул модель пользователя а мы попадаем в сервис сервис получает эту модель и формирует э из неё дто э чтобы вернуть только то что нужно знать слою контроллера или сервлета на конкретно на примере Мы хотим в нашем контроллере вернуть результат регистрации но для этого не нужно Не нужно знать пароль вообще пароль довольно приватные данные и стоит как можно меньше о нём распространяться поэтому факт существования пароля Он дальше сервиса не идёт сервис получил модель убрал всё лишнее с помощью маппера создал р D и эти данные вернул сету сервлет получив данные сформировал http ответ например чаще всего это представление полученного объекта и в результате работы мы получим J обк с полями ID и email например id1 а [email protected] Таким образом мы видим всю весь порядок циркуляции данных получили запрос сец обернули в дто передали в сервис в сервисе сделали работу передали в Да модель Да прол операцию вставки получил результат обновил ID в модели модель передал в сервис сервис обернулась в сер сет вернул ответ полный цикл полный цикл показан на этой схеме О чём хочется сказать поподробнее не слишком ли много здесь раз разных дто объектов то есть раз дто объекта и е и модель ском много будет классов у которых зачастую повторяются повторяются поля иногда можно использовать модель как и дто вместе например с помощью аннотации какой-нибудь заигрывать поле пароль чтобы оно не попадало в J представление объекта на мой вкус лучше больше классов и больше кода но понятнее и очевиднее если класс используются только в одном контексте его проще менять его проще поддерживать его проще понимать поэтому количество дто объектов является наверное минусом Но это меньшее зло и если есть выбор переиспользовать одну модель или один объект двух в двух контекстах э либо создать новый Дато Объект который отличается всего одним полем я обычно склоняюсь ко второму варианту так а на вопросы Я отвечу Ближе ближе к концу Э что хочется посоветовать ээ посмотреть более подробно есть отличный доклад Андрея Беляева про дто там рассказано подробно про мапперы И вообще про то как выбирать конкретный маппер и как его использовать э ссылка будет в заметках в заметках к стриму и вторая полезная ссылка которую я считаю важной приложить - это отличие Дао от репозитория слой работы с данными иногда называют Дао иногда называют репозиторием по факту это две формы почти что одного и того же и отличаются они скорее конвенциями конвенции именования методов и того как мы Обращаемся к этим методам э как правило фреймворк сам нас склоняет к тому либо к тому либо иному варианту Но если вам интересна конкретная разница то почитать можно вот здесь а Схема этого примера показала такой успешный кейс когда всё пошло по плану и проблем не возникло но достаточно частым источником проблем Особенно для начинающих является обработка ошибок ээ в mvc э паттерне Что делать если Если наша работа пошла не по плану Что делать если в базе возникла ошибка как мы эту ошибку обработаем и как это повлияет на цепочку взаимодействий давайте рассмотрим тот же самый пример э только теперь ошибка э возникла ошибка регистрации пользователя потому что допустим email в запросе не уникальный э vas @gmail.com э уже существует в нашей базе и при повторной регистрации мы уже не сможем вернуть успешный ответ поэтому как конкретно в рамках mvc мы сможем эту ситуацию обработать вся та же самая схема начинается с пост запроса создали то объект передали в сервис в сервисе создали модель передали в Да в Да делаем ирт получаем ошибка на уров базы есть база говорит у вас нарушение индекса поле email И вы вставляете не уникальное значение что происходит так как с базой работает объект из слоя dao Exception обработает Exception понимается там что нам с ним делать очень важным моментом является перебросить Exception из конкретного в какой-то понятный сервису сервис напоминаю не знает о том что на с SQL и сервис не должен об этом знать не хочет этого знать поэтому сервису не нужно давать поймать типа который является эпм специфическим для SQ поэтому важно в Да объекте поймать специфичный Exception и перебросить его в Понятно Серви в данном случае сервису нен который сразу очевидно говорит о том что произошло таким образом допустим е если мы в будущем перепишем dao на работу с другим хранилищем либо с чем-то я не знаю вообще с внешним сервисом который доступен по rest API то сервис об этом не узнает мы возбуждая User EX Exception илом ловим его там где хотим в моём примере в сервисе мы его не ловим потому что незачем ловим напрямую в сервлет и в сервлет можем с помощью TR cch либо другого синтаксиса доступного нам ну этот пример в рамках Java там особо ничего не доступно поэтому мы ловим в Try Catch и в секции cch формируем ответ с ошибкой допустим это особый ренс код допустим 429 Conflict который часто использует для такой ситуации и формируем JS представление дото объекта с ошибкой допустим это сообщение об ошибке такой Юзер уже существует и какой-то код ошибки для фронтенда Таким образом мы показали альтернативный вариант исполнения этого кода э успешный вариант я заблюрить не отработают возникнет Exception мы его поймали перебросили и потом в сервлет обработали сформировали ошибку такой вариант переброс низкоуровневого низкоуровневого эксепшн в эксепшн понятный сервисом и контроллером является самым частым подходом к обработке к обработке ошибок а Итак пойдём к следующему примеру следующий пример Да кстати хотел заметить что хоть это хоть это mvc но можно заметить что слоя VI тут нет то есть никакого представления нет потому что в рамках нету интерфейса в рамках н приложения и это нормально когда сам набор слоёв и их количество подстраивается под контекст mvc - Это скорее набор базовых принципов и правил а конкретные слои и их ответственность зависит от того что мы пишем поэтому мой сдуй пример в другом контексте для того чтобы показать больше разных вариантов опять мы пишем регистрацию Но в данном случае уже на спринг Буте и у нас есть представление это веб-страница отрендерить же поля email пароль и подтверждение пароля так как обычно происходит на сайтах всё очень похоже принимаем пост запрос отличаются только поля контроллер отвечает за валидацию и допустим он Валиди ет то что пароль и подтверждение пароля совпадают если Они совпадают дальше нет смысла тащить с собой подтверждение пароля это не нужно ни сервису ни базе данных поэтому объект для регистрации пользователя опять же содержит только email и только пароль дальнейшие слои полностью повторяет предыдущий пример оборачиваем в модель с помощью Spring dat репозитория например Spring J сохраняем получаем результат оборачиваем в дто возвращаем в контроллер и новый элемент этой схемы это представление контроллер теперь вместо того чтобы сформировать и вернуть или получить от сервиса и вернуть его в виде использую какой-то для рендеринга допустим чтобы на шаблоне тафа отрендерить результат регистрации допустим это mail.com Поздравляем с успешной регистрацией Я выде то что на этой смеется от щего приме ВН место слоя dao слой repository потому что мы пользуемся сприн и Spring даёт уже нам из коробки Spring Data свои репозитории поэтому мы не не запрета велосипед а пользуемся тем что нам доступно и используем этот jp repository И также у нас есть появился View который отвечает за рендеринг страницы для пользователя те же самые главные слои но контекст поменялся и поэтому изменились некоторые детали и что я хочу показать этими примерами это то что базовые принципы остаются а нюансы меняются и Не стоит искать какую-то супер жёсткую формулу mvc для всех ваших проектов и переиспользовать его а скорее стоит понять базовые принципы и применять эти базовые принципы гибко подстраиваясь что эти примеры смогли данную иде что вы всегда имеете контроль над нюансами Но идея остаётся неизменной теперь хочется перейти к минусам mvc и главному минусу который я вижу в mvc - это структура пакетов как обычно выглядят пакеты в jav приложении кото которые построе на принципах mvc допустим у нас есть четыре сущности в приложении это пользователи мы пишем приложение для бронирования авиабилетов У нас есть пользователи есть бронирование есть билеты и есть полёты вот у нас есть четыре таких главных сущностей и мы начинаем писать пакеты у нас пакеты контроллер сервис репозиторий Model и мы в каждом пакете по создавали по классу User Controller B Controller и так далее такая плоская горизонтальная структура довольно плохо подходит для проектов любого размера кроме самого маленького эти папки начнут очень быстро пухнуть если у нас не четыре сущности а 15 сущностей или 20 и они будут очень очень большие и очень плоские более того такая группировка напрямую нарушает принципы Low cing и High cision что эти принципы значат сама идея модулей - это сгруппировать классы так чтобы количество связей между классами одного модуля было максимально А количество связей между модулями было минимально и этот принцип напрямую нарушен потому что контроллеру нужно знать о сервисе поэтому ркон импорт сервис из пакета сервис Таким образом у нас есть очень много связи между модулями но почти нет связей внутри модуля Что в принципе противоречит вообще идее того как нужно строить модули но в рамках простых приложений такой подход в целом приемлем и Нет проблемы если у нас например три либо четыре либо пять сущностей а что же делать если у нас больше сущностей и наш проект растёт Давайте посмотрим на реальный пример и как это обычно там выглядит э допустим у нас то же самое приложение пользователи бронирования полёты и билеты но оно стало расти и как же мы будем работать с его структурой э главный и первый шаг наверное который часто делается - это поменять структуру с горизонтальной как вот здесь на вертикальную Э что значит вертикальная структура это то что пакеты теперь не по слоям а по сущностям либо по каким-то доменным э по доменам нашего приложения доменом может считаться какая-то область приложения например работа с билетами работа с авиалиниями с чем-то ещё какие-то независимые друг от друга части допустим что для юзеров у нас отдельный пакет и контроллер связан с сервисом сервис связан с репозиторием репозиторий связан с пользователем тоже самое для пакетов бунг полёты и билеты какие-то конечно классы разных пакетов будут друг с другом связаны но тем не менее в рамках подобного дизайна намного чище достигать достигается принцип максимизации связи внутри пакета и минимизации связей между пакетами и сама работа с пакетами становится более э более близкой к тому вообще как это должно быть второй очень важный момент не получается никогда весь проект структурировать единообразно то есть допустим что для юзера букинга и полётов мы смогли применить такую вертикальную структуру и везде Она работает одинаково хорошо но что делать с какими-то классами которые абсолютно независимые например есть классы которые отвечают за работу с базой данных с базой с базами данных либо классы которые отвечают за какие-то там соединения или что угодно какие-то изолированные независимые классы для таких классов обычно хорошо выделить отдельный пакет назвать его допустим у tils и туда складировать подобные классы тут есть две стороны монеты если таких классов мало Это нормально если их становится 10 возможно нужно из них что-то уже выделить какой-то из них отдельный пакет и как-то его структурировать более красиво чем просто нагромождение классов это второй пример структуры третий пример структуры - это какие-то общие классы которые являются наследниками для слоёв наших самых главных пакетов допустим у нас все наши репозитории User репозитории бун репозитории Flight репозитории наследуется от какого-то общего семейства репозиториев который начинается с jp ри и потом от него наследуется кру репозиторий и уже ОТК репозиторий мы наследуем User booking и Flight репозитории куда положить эти базовые классы часто лучшим решением является какой-то отдельный пакет под эту цель и можно назвать его comms например то есть нечто общее для других пакетов и в этом пакете в его под пакетах сформировать структуру уже по слоям то есть вот здесь у нас была вертикальная структура А в рамках пакета commands у нас внутри горизонтальная структура по слоям репозитория и по слоям controllers контроллер может быть базовым контроллером например для всех контроллеров пользователей букинга flights и так далее на данном примере Я хочу продемонстрировать не однородной структуры здесь она вертикальная здесь она горизонтальная здесь некая нагромождение последняя часть этой схемы - это билеты допустим что бизнес логика билетов при росте проекта стала усложняться сначала там было всё просто просто билеты и всё а потом у нас появились групповые билеты А потом появились промо билеты Привет Влад кстати потом у нас появился айд билетов или отмена билетов валидация билетов и бизнес логика начала нарастать А что с этим делать вертикальная схема уже не подходит горизонтальная схема тоже уже не подходит в такой ситуации внутрь mvc обычно внедряется некая другая архитектура которая уже отвечает тем вызовам которые у нас есть в данном конкретном примере таким примером может являться например Дод Design который служит архитектурой для создания классов и структуры пакетов для сложных бизнес доменов эту схему сложной нельзя назвать тут всего тут не знаю 10 классов и я не ставил целью нарисовать полноценную схему классов обычно десятки может быть сотни главная це этой что mvc как есть уже не может описать просто и в полной мере образова образовываются структуру поэтому mvc остаётся такой супер структурой пакета тикет там тоже есть контроллер тоже есть сервис тоже есть репозитории и модель но какие-то вкрапления других пакетов другой структуры уже следует новым правилам например правим в прини здесь как некая суперструктура этого пакета здесь как вертикальная структура А в ко Как горизонтальна как же принять решение о том как вообще стоит структурировать пакеты Я думаю что самый главный и самый важный совет здесь это структура должна постоянно эволюционировать и вы не долж придумать заранее [музыка] ваши Пакеты будут выглядеть то есть структура в каж в каждый момент времени должна отвечать тем требованиям которые у вас есть сейчас Вы не должны думать сильно на будущее и добавление каждого Нового класса это Повод задуматься над тем как пакеты должны под это изменение подстроиться то есть допустим вы начали с абсолютно валютного варианта это плоская структура как зде вы поняли что сущностей становится слишком много и Пора менять структуру на вертикальную вы сделали вертикальную потом поняли что какие-то части являются общими для всех вертикальных пакетов вы вы вынесли что-то в консы что-то вынесли в утилс потом функционал стал нарастать и вы поняли что бизнес логика билетов становится всё сложнее и вместо нагромождения классов внутри Паке Кет вы структурировать пакетам допустим в соответствии с принципами до дизайна и вот как-то так в реальности и и получается никогда не пытайтесь думать на будущее просто рутинное рефакторинга структуры своего проекта так Также хочу отметить что MC совместим со многими другими архитектурными подходами например микросервисами или EV driven подходом mvc часто является либо суперструктура либо каким-то частным случаем структуры проектов в рамках любых вообще подходов то есть микросервисы допустим каждый микросервис может быть внутри структурирован с помощью mvc если у нас EV driven то не знаю он может он может быть завязан на какие-то классы в рамках mbc слоёв в чистом виде mbc конечно не бывает но он такой набор принципов который нам позволяет формировать структуру для любых по сути приложений что я хочу посоветовать почитать на тему вот структуры приложений хороший Хорошая точка входа в эту тему это обсуждение на Overflow на вопрос который называется horizontal and vertical Split horizontal Split - это плоский подход vertical Split - это вертикальный тут в ответе на вопрос описаны те же самые идеи которые я рассказывал и приложено много хороших ссылок которые раскрывают эту тему намного намного глубже чем Я раскрыл её сейчас если говорить про книги то сама идея главная идея Low cing High cision сформулирована и раскрыта в книге экан dom Design там есть отдельная глава про модули и то как модули должны группировать классы и как раз оттуда оттуда растут Ноги вот всех вот этих идей которые я рассказал на второй схеме показал на второй схеме и чтобы не бояться рефакторинга и понимать как его эффективно делать полезно прочитать книгу Мартина фаулера refactoring improving Design of existing Code Как раз эта книга про то что любое изменение требований либо сложности проекта всегда должно являться триггером для рефакторинга рефакторинг не стоит откладывать на на будущее это часть работы добавляем класс думаем над тем В какой пакет его положить если пакета хорошего нет думаем над тем как нужно пакеты перестук не стоит этот процесс откладывать стоит делать его абсолютно неотъемлемой частью работы над над вашим проектом Так теперь я отвечу на вопросы э Всегда ли летят ошибки в контроллер или возможны варианты возможны варианты допустим в случае регистрации если мы бы хотели на ошибку регистрации как-то отреагировать по-особому например уведомить администратора что у нас какие-то проблемы с регистрацией либо что-то ещё в таком случае при наличие таких требований мы бы ловили ошибку в сервисе что-то с ней делали и потом если хотим дать знать о ней контроллеру то кидаем её в контроллер если не хотим то просто её ловим на слой сервиса и оставляем её там так следующий вопрос нахожусь на стадии изучения спрингалд так Ну я бы начинал со спрингалд mvc у меня сервисы протекали друг в друга Бывает такое что сервисов много допустим там не знаю пять штук да три и они начинают вызывать друг друга я не вижу в этом проблемы Главное чтобы сло не протекали друг в друга вертикально то есть главное чтобы сервис не начинал отвечать за то что должен отвечать сервлет Но если такое горизонтальное протекание становится повсеместным возможно паттерна BC стоит как-то усложнить для соответствия конкретно вашим требованиям также как я здесь усложнил пакет Кет возможно слой сервисов стоит структурировать с использовани других подходов чтобы подстроиться под ваши требования могут ли разные команды разрабатывать разные слои Ну в теории могут но скорее всего одна команда будет отвечать за какой-то какую-то часть приложения и в рамках этой части приложения отвечать за все слои Я не думаю что есть большой смысл и прикладная ценность того что разные команды делают разные слои Ну какая-то команда может делать что-то общее там например базовый слой каких-то супер сложных репозиториев которые работают с какой-то конкретной базы данных которую там не поддерживает Spring например может мы пишем интеграцию с с какой-то новой БД и тогда отдельная команда будет делать эту интеграцию и давать нам слой репозиториев А мы будем её использовать уже в наших сервисах и в наших контроллерах так какую логику можем писать в контроллере и Какую нужно переносить из контроллера в сервис в контроллере по-хорошему вообще не должно быть логики если она сложнее чем одна строчка то есть контроллер не делает логики если он вызывает сервис это Окей если у нас например вставка не знаю товара в систему это просто вставка вбд и всё тогда писать сервис ради одной строчки смысла нет и можем э просто проигнорировать сервисы и напрямую пробросить взаимодействие от контроллера в репозитории ээ Но если такой строчки больше чем одна то уже имеет смысл создавать сервис Как убедить команду Фактори система пакетов Ну если Лит не видит в этом необходимости и не отвечает за это то это конечно проблема можно предложить это исходя из своей инициативы сделать какой-то рефакторинг и сделать реквест и постараться донести до команды пользу этого дела Но конечно такие проблемы должны решаться с головы со стороны Лида и вы как разработчик тут конечно не отвечаете за всё целиком Но главное уметь это делать В целом поэтому иметь привычку это делать рефакторинг сложная Тема и довольно сложно продать её менеджменту как задача которая требует исполнения и времени и иногда немного лениво этому уделять время но я советую считать рефакторинг неотъемлемой частью написания кода так на вопросы ответил Подводя итоги мы обсудили С чего начинается mvc и куда ноги растут и из слоистой архитектуры э какую проблему решает mvc на простом примере с таймером более прикладные примеры для Java Back разработки на сервлета регистрация пользователя ошибка регистрации пользователя тот же самый пример в контексте springboot приложения и веб интерфейса на лифе и структура пакетов плоская и близкая к реальной Подводя итоги хочу сказать что эта лекция является частью моих материалов для Java род Map по изучению разработки на Java самого начала до трудоустройства путём написания практических проектов если Вам эта тема интересна то мой rmap содержит в себе семь проектов от jav корда микросервисной студенты уже написали 250 реализаций к ним к ним сделано 80 80 открытых ревью Поэтому если вам интересно развиваться в рамках jav разработки пожалуйста Рассмотрите мои ресурсы и кроме юба У меня есть Telegram канал и сообщество студентов где можно общаться обсуждать учёбу технологии любые Автопик темы и трудоустройства также на моём канале В тубе есть лекции на другие темы поддержать если хотите Можно на бусте Надеюсь что сегодняшняя лекция была вам полезна и Спасибо всем кто Кто пришёл будем на связи и до свидания