×Закрыть

Проектирование трехслойных приложений

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

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

Нужно еще это где то сохранять, кроме озу. Если брать просто отдельное локальное приложение, то это можно привести к простой загрузке всех данных из файла и сохранении туда.

Первый вопрос насчет этого варианта.
Ну вот например есть программа в которой описываются сущности. И надо было как то это хранить на накопителе, взял xml(хотя да на БД это было бы лучше). А стандартный C# сериализатор сериализует только открытые поля и свойства (O_O, это как бы код, хотя и для доступа к данным, но логика немного непонятная), свойства с открытыми геттерами и сеттерами и с конструктором без параметров. Но например мне не нужны открытые сеттеры на поля и конструкторы без параметров. В такой ситуации я решил сделать классы-близнецы для сериализации, то есть они создаются из классов предметной области, сериализуются потом десериализуются, и по ним строятся рабочие классы.
Правильно ли это? Или нужно все что хочу сохранить делать public и работать с таким классом?

Другой вариант с работой с базой данных.
Если брать например ORM метод, то нужно связывать с базой сущности которые содержат поведение из предметной области или аналогично создавать просто классы которые будут создаваться из БД, а уже из них делать нужные сущности?

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

LinkedIn
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Ты думаешь в правильном направлении, гугли в сторону DDD. Тут найдешь ответы на свои вопросы www.amazon.com/...​ughn-Vernon/dp/0321834577, но анализируй, в целом это немного оверинжениринг для большинства задач.

Проще всего делать публичный свойства для объекта и сохранять в document DB.

Со временем посмотри в сторону ActorModel. У актора есть внутренее состояние (как раз тот граф объектов с публичными свойствами, который и сохраняется в куда удобнее) и поведение.

И потом глянть еще на EventSourcing, где состояние объктов восстанавливается из серии предыдущих событий, которые были вызваны изменением его состояния. Вот в кратце,

Ну, и, да, выкинь эти глупости про трехслойные приложения, гугли в сторону архитектуры ports and adapters или hexagon architecture github.com/...​e/ports-adapters-examples. Ну и гугл тоже выдает много промеров по hexagonal architecture example c# github.

EventSourcing

Тогда уже и про CQRS можно почитать

CQRS имеет смысл лишь для высоконагруженных систем, где основная нагрузка это отрисовка ГУИ («запросы» со стороны пользователя) — при этом, лишь время от времени случаются «команды».

Но сама реализация паттерна (без разделения на «Q» и «R» части) полезна и её можно много где увидеть. В общем-то, это мэйнстрим, в том что касается абстрагирования ГУИ от бизнес-логики.

DDD и hexagon architecture — такое, в реальном продакшэне топикстартер едва ли встретит...

DDD

это больше про общение и про понимание предметной области. Тем не менее приниципы нужно понимать особенно если несть необходимость выделять сервисы. Нужно понмать что такое Bounded Context.

hexagon architecture

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

hexagon architecture

Набор простых принципов.

Это не набор простых принципов, а требование реализации приложения, на основе портов-адаптеров.

Но зачем такие сложности? На практике, для тех же целей — вполне достаточно уже давно существующих: 1) чёткого разделения на интерфейсы/реализации 2) зависимости между частями системы лишь по интерфейсам 3) инъектирование зависимостей (желательно, лишь в конструкторах + очень редко в сеттерах, если очень сильно нужно ре-использовать объект) 4) разделение приложения на слои.

А порты-адаптеры — то для бесед на хипстерских тусовках.

Так это же и есть порты и адаптеры, если добавить, что интерфейсами владеет домен, а реализациями инфраструктура :).

CQRS имеет смысл лишь для высоконагруженных систем, где основная нагрузка это отрисовка ГУИ («запросы» со стороны пользователя) — при этом, лишь время от времени случаются "команды".

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

это сильно упрощает архитектуру

Оно усложняет архитектуру. Но 1) полезно при нагрузке 2) поддерживается даже оборудованием (например, большим количеством ДБ-серверов «read-only», с которыми работает «Q» часть + парой-тройкой серверов, в режиме «read-write» с которой работает «R» часть.)

Глянь те статьи, которые я привел dou.ua/...​ign=reply-comment#1223431. Усложнение, разве что, в сравнении с приложением без архитектуры, где вся логика в контроллерах и то пока она не разрослась.

Ок, гляну. :) Но разделение уровня работы с БД на «read-only» и «read-write» части — это очень условное резделение, попахивающие дупликатом/кпипастой. Поскольку нет особых различий в реализации операций CRUD (за исключениме транзакций).
При этом, при раздлении приходится решать кучу проблем, со всякой синхронизацией состояния объектов, полученных из дб итп

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

«R» часть

Что за R часть?)

Ты же сам здесь задвинул паттерн с «R». :)

Вот эта самая часть...

Там просто очепятка. С или Write имеется в виду.

Q = Query (read)
R = Responsibility (insert, update, delete)

П.С. Ок, там похоже действительно „C” — это command (insert, update, delete)
Тогда „C”.

Хмм, можно и так думать, конечно, но в оригинале Command (write, он же insert, update, delete) Query (read) Responsibility Segregation. Типа разделение обязанностей чтения и записи данных.

разделение обязанностей чтения и записи данных.

ну да, я тоже об этом :)

Везде свои камни, при использовании с тем Event Sourcing возникают проблемы, когда вам надо отправить какие-то данные с UI которые обработаются на сервере и получить результат. А так как система «eventually consistent» приходится юзать всякие костыли в виде long polling которые опрашивают query часть.

Эмм, тут дискуссия уже далеко ухидит. Есть много способов достичь read own writes при eventual consistency и long pooling не самый удобный. Но в предыдущем комменте я говорил про неразделение read и write хранилищ, при этом нет никакого eventual consistency.

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

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

Или нужно все что хочу сохранить делать public и работать с таким классом?

Всегда ответ «нет».

Полно информации по тому как делать те или иные вещи отдельно, но не написано как это слепить в кучу, так что бы было удобнее.

msdn.microsoft.com/...​-us/library/ff649690.aspx и другие примеры паттерна Repository.

Модель не має містити поведінки. Модель окремо, поведінка окремо. en.m.wikipedia.org/wiki/Data_model

Не совсем так
В модели могут хранится правила логики поведения и мапинги, которые своего рода тоже правила поведения

Так это же модель данных. Есть ещё модель предметной области и там как раз наоборот. Детальнее тут: www.martinfowler.com/...​ki/AnemicDomainModel.html

Фаулера почитай, Архитектура корпоративных программных приложений.

Трехслойная: клиент-сервер-СУБД, шаблон MVC model-view-controller какая из этих имелась ввиду ?

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

Правильно ли это? Или нужно все что хочу сохранить делать public и работать с таким классом?

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

Прежде чем делать сериализацию построй приложение до уровня DTO/DAO и на уровне DAO уже сделай одну из реализаций сериализацию.

Вопрос об клиент-сервер-СУБД. MVC как я понял это шаблон для организации взаимодействия клиент-сервер.

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

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

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

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

За книгу спасибо!

а сразу после Фаулера, но только после — Эванса. А затем — Clean Architecture только схемку лучше отсюда смотреть — не всем «круги» понятны.

Трехслойная: клиент-сервер-СУБД, шаблон MVC model-view-controller какая из этих имелась ввиду ?

Думаю речь о
en.wikipedia.org/...​ki/Multitier_architecture
, а так подтянуть под нее можно все что хочешь

Простой вопрос: а на кой тебе вообще сдался третий [четвёртый, стопиццотый] слой? Как бы всё это решения вынужденные, и без потребности городить порнографию — значит тупо плодить баги и удорожать проект, в качестве бонуса растягивая его во времени.

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

Элементарнейший пример: список товаров. Надо тебе его собирать в абстрактную модель? IMHO нет. Нужно кеширование — включи его на базе. Хотя по-хорошему, собери правильные индексы и будет тебе счастье. База сама прекрасно держит их в ОЗУ. И собирает временные таблицы под твои абстракции тоже сама. Покуда ты не Цукерберг, выбор «тебе шашечки или ехать» слишком очевиден.

Я понимаю что не нужно делать сложные решения простых проблем. Я спросил что бы узнать как это делается на больших проектах. Да и может в этих техниках есть что то полезное и для своих разработок.

Книжки почитай, одну тебе назвали выше.

Все правильно спрашиваешь! Проекты имеют свойство расти и тогда без разделения на слои будет очень трудно.
Видишь ли, независимо от опыта, к сожалению нет среди программистов четкого единства, каждый толкает свое видение как хочет и считает всех остальных дураками.
3х слойка это классика. Но я рекомендую копнут ьеще и в сторону Onion архитектуры.

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

Есть одно золотое правило хорошего кода: если ты не можешь сказать, что такое твоя абстракция — некуй её клепать. И все хорошие большие проекты не работают на «слоях», скорее они составлены как пазл. А каждый лишний слой — катастрофа для будущих изменений. Хватит даже три слоя раздать трём разным людям, чтобы получить ответ НЕТ даже на самые насущные требования.

Гениально! Говнить все в одном слое!

Для прототипа, если уверен, что он будет переписан с 0 вполне оправдано.

если уверен, что он будет переписан с 0

Ха-ха три раза...

Ну уж и пофантазировать нельзя. И таки да, иногда такое случается.

Пардон, не хотел задеть. Да, случается — вот буквально на днях на работе обсуждали именно такой сценарий. Но, ИМХО — случается гораздо реже, чем хотелось бы.

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

А потом когда общаешься по вакансии и чел тебе говорит: «тут у нас проект из говна и палок, теперь надо переписать нормально» )))

Только сначала пару багов пофиксить, одну фичу добавить, а потом перепишем.

В энтерпрайзе ничего не переписывается, все «живет», даже если переписать месяц, а интегрить говницо — год. По понятным причинам

Якщо трошки англійську знаєш, то глянь курс pluralsight www.pluralsight.com/...​cting-applications-dotnet. Там якраз йдеться про всі архітектурні рівні. Загалом народ для кожного рівня свої сутності використовує а тоді маплять з одного на інший. Так рівні менше один про оден знають, а отже менше залежать. Але в маленькому проекті це може бути overengineering. Я часто в маленьких проектах створював одну структуру і використовував її скрізь, і в DAL і UI. Швидкість розробки висока, код простенький і не треба в купі місць поле додавати при змінах і пробоем з підтримкою не виникало.

Ты сам-то понял что наворотил? И главное — зачем

По вопросу #2 юзай Entity Framework и будет тебе щастья, там все основные решения уже приняли за тебя а тебе осталось только выбрать какой схеме следовать
Вот твои опции:
Model First:
— Good support with EDMX designer
— We can visually create the database model
— EF generates the Code and database script
— Extensible through partial classes
— We can modify the model and update the generated database.

Database First:
— An existing database can be used
— Code can be auto-generated.
— Extensible using partial classes/ T4 templates
— The developer can update the database manually
— There is a very good designer, which sync with the underlining database

Code First:
— There is full control of the model from the Code; no EDMX/designer
— No manual intervention to DB is required
— The database is used for data only

Entity Framework

я как раз и написал что в случае ORM не понятно нужно ли разделять сущности Entity Framework и бизнес логики, или делать их общими. Но там опять же то что я хочу сохранить должно быть public. А если это не очень удобно делать открытым? Или нужно проектировать так что бы public set не могли поломать работу?

Не хочешь делать сетторы пабликами — делай отдельные классы, для работы с дб/прочим персистэнс. Вполне легитимный вариант.

Спасибо, насмешил. Это защита от дурака, не более того. Кто знает подноготную, вообще с гетерами-сетерами не заморачивается, а делает большинство данных public. Просто потому, что фреймворк сам тебе соберёт всю рутину. А с верификацией по-любому придётся играться руками, от логики никуда не денешься, где-то ж она должна прописываться.

а делает большинство данных public.

...потом вылетает даже с формошлёпской работы — и балаболит на форумах. :)

по себе судишь?

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

И получишь Anemic Domain Model а затем лишишь себя полиморфизма. Вот только зачем?

Кто знает подноготную, вообще с гетерами-сетерами не заморачивается, а делает большинство данных public.

Ты себя относишь к этому большинству ?

ты себе сильно усложнишь задачу пытаясь засунуть бизнес рулы в ОРМ обьеты

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

Вот в подтверждение топовые ответы на стековерфлоу по этому же вопросу
Typically, the „best practice” approach would be something like this:

— in your Data layer, you have EF entities that get loaded from and stored back to the database
— in your Business layer, you have your own domain objects (just plain C# classes) that represent the data that your app needs to work on. Those can be more or less identical to a data layer entity, or they can contain several „atomic” entities to make up a business object, or they can be vastly different. To alleviate the need for a lot of left-hand-right-hand-assignment statements (to move property values back and forth between data layer entities and business layer objects), you should check out tools like AutoMapper that make it really easy to set up „mappings” between similar object types and allow you to easily assign those types back and forth
— your UI layer(s) will then visualize and represent Business layer objects to the user for information and/or manipulation

Подписаться на комментарии