Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Shmj Ниоткуда  
Дата: 26.09.17 12:44
Оценка:
По сути код работает со структирированными данными. Назовем бизнес-объекты.

Практически в каждом проекте эти данные используются для 4-5 вещей:

1. Для внутреннего потребления, т.е. вы некие классы передаете/принимаете в своих методах и что-то с ними делаете.

2. Для сохранения. Как правило ORM позволяет сохранять сами эти структуры данных. Но так просто не получается -- их нужно либо наделить атрибутами либо кодогенерацией (ну или XML-описанием).

3. Эти же структуры данных иногда приходится сохранять на диск в неком формате без ORM. К примеру для сохранения в xlsx-файл.

4. Эти же структуры вам нужно отдавать через REST/SOAP-API внешним пользователям.

5. Эти же структуры вам нужно получать из внешнего API, от которого уже вы зависите.

Главное неудобство вижу в том, что по стуи очень похожие структуры в каждом из этих 5 случаев нужно копировать одну в другую. Потому что они хотя и похожи, порой на 90%, но все же отличаются. К примеру в одном случае требуется обязательное наличие set-еров, иначе библиотека отказывается работать с данными (к примеру, стандартная XML-сериализация требует чтобы у списка был set-ер). Но наличие set-еров противоречит внутренней парадигме.

Видите ли вы проблему в том что по сути одни и те же данные по многу раз приходится копировать из одной структуры в другую лишь по той причине, что они применяются в разных слоях (но по стуи одинаковые сущности)?
Отредактировано 26.09.2017 12:45 Shmj . Предыдущая версия .
Re: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Mihas  
Дата: 26.09.17 13:06
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Видите ли вы проблему в том что по сути одни и те же данные по многу раз приходится копировать из одной структуры в другую лишь по той причине, что они применяются в разных слоях (но по стуи одинаковые сущности)?

Я считаю нормальным, что одни и те же данные видоизменяют свое представление в зависимости от задачи.
А сталкивался обратной с проблемой. Варианты представления одних и тех же данных рассматривались как независимые друг от друга. И обработчики имели независимые. В результате, приходилось одни и те же правки вносить в разных участках кода.
Re[2]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Shmj Ниоткуда  
Дата: 26.09.17 13:18
Оценка:
Здравствуйте, Mihas, Вы писали:

M>Я считаю нормальным, что одни и те же данные видоизменяют свое представление в зависимости от задачи.


Что вы имеете в виду под представлением? То что для каждого случая вы создаете на 90% совпадающие классы?

M>А сталкивался обратной с проблемой. Варианты представления одних и тех же данных рассматривались как независимые друг от друга. И обработчики имели независимые. В результате, приходилось одни и те же правки вносить в разных участках кода.


Если создаете классы для каждого из 5 случаев -- то при изменении структуры данных правки придется вносить везде.
Re: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Kolesiki  
Дата: 26.09.17 13:22
Оценка: 2 (1) -1
Здравствуйте, Shmj, Вы писали:

S> Но наличие set-еров противоречит внутренней парадигме.


Вот с этого и надо начинать. Если некая свежепровозглашённая шиза не вписывается в практичную логику, это не "парадигма", а сферический конь в вакууме.

S>Видите ли вы проблему в том что по сути одни и те же данные по многу раз приходится копировать


Разумеется! Поэтому я делаю проще — создаю комбинированные классы.
1. В них есть все поля, чётко ложащиеся на поля СУБД.
2. Поля не для СУБД помечаем как SqlIgnore — это те самые полезные "бизнес-проперти".
3. Сериализация в JSON у нас используется во всю ширь, поэтому так же как с СУБД, что не надо — помечаем JsonIgnore.

В результате, один и тот же класс СПОКОЙНО вращается в бизнес логике, прыгает в сторидж и обратно, сериализуется для внешних API и радует прогера безо всяких вырвиглазных MVVM/MVC и т.п.
Re[2]: Про бизнес-объекты: для сохранения, для API, для внут
От: Shmj Ниоткуда  
Дата: 26.09.17 13:32
Оценка:
Здравствуйте, Kolesiki, Вы писали:

K>Вот с этого и надо начинать. Если некая свежепровозглашённая шиза не вписывается в практичную логику, это не "парадигма", а сферический конь в вакууме.


Ну почему шиза? Вы читали Guidelines https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/guidelines-for-collections ?
Те же коллекции не должны иметь set-еров по этим рекомендациям. А для XML-сериализации/десериализации, к примеру, они обязательны.


С коллекциями ошибся, оказывается и без сетеров сериализация работает. Но как быть с другими свойствами? Если один объект для всего, то вообще нельзя создавать только get-свойства. Получается если передали объект в метод -- нет гарантий что он там не подвергнется изменениям.
Отредактировано 26.09.2017 18:00 Shmj . Предыдущая версия .
Re[3]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Mihas  
Дата: 26.09.17 13:38
Оценка:
Здравствуйте, Shmj, Вы писали:


M>>Я считаю нормальным, что одни и те же данные видоизменяют свое представление в зависимости от задачи.

S>Что вы имеете в виду под представлением?
Под представлениями я понимаю перечисленное в стартовом посте:
1. Для внутреннего потребления
2. Для сохранения через ORM
3. для сохранения в xlsx-файл.
4. В структуре REST/SOAP-API
Один и тот же элемент данных (например, описание товара) нужно представлять в той или иной структуре.


M>>А сталкивался обратной с проблемой. Варианты представления одних и тех же данных рассматривались как независимые друг от друга. И обработчики имели независимые. В результате, приходилось одни и те же правки вносить в разных участках кода.

S>Если создаете классы для каждого из 5 случаев -- то при изменении структуры данных правки придется вносить везде.
Что-то обязательно можно вынести в общую часть.
Re[4]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Shmj Ниоткуда  
Дата: 26.09.17 14:14
Оценка:
Здравствуйте, Mihas, Вы писали:

S>>Если создаете классы для каждого из 5 случаев -- то при изменении структуры данных правки придется вносить везде.

M>Что-то обязательно можно вынести в общую часть.

То есть вы предлагаете использовать наследование?
Re[5]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Sharov Россия  
Дата: 26.09.17 14:52
Оценка:
Здравствуйте, Shmj, Вы писали:

S>То есть вы предлагаете использовать наследование?


Для 1-3 -- наследование, подвязанное к ORM. 4-5 -- dto с трасфорамацией в бизнес объекты.
Кодом людям нужно помогать!
Re[3]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: rameel https://github.com/rsdn/CodeJam
Дата: 26.09.17 16:03
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Те же коллекции не должны иметь set-еров по этим рекомендациям. А для XML-сериализации/десериализации, к примеру, они обязательны.


Поправочка: если это коллекция (ICollection<T>, IDictionary<TKey,TValue>, ISet<T> или их наследники), то сеттер не нужен, все и так работает, если
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Re[6]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Shmj Ниоткуда  
Дата: 26.09.17 16:32
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Для 1-3 -- наследование, подвязанное к ORM. 4-5 -- dto с трасфорамацией в бизнес объекты.


А конкретно. Вы создаете объекты в EF DB-First/Model-First а потом наследуетесь от них? Т.е. вся ваша архитектура гвоздями прибита к EF?
Re[2]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Shmj Ниоткуда  
Дата: 26.09.17 16:53
Оценка:
Здравствуйте, Kolesiki, Вы писали:

K>В результате, один и тот же класс СПОКОЙНО вращается в бизнес логике, прыгает в сторидж и обратно, сериализуется для внешних API и радует прогера безо всяких вырвиглазных MVVM/MVC и т.п.


Вот в идеале хотелось бы такое, чтобы 1 класс создавался на одну сущность. Ну или в крайнем случае наследование.

Но есть два минуса:

1. Если используете тот же EF CodeFirst, то нужно помечать атрибутами поля. А это значит что библиотека ваших контрактов будет иметь зависимость на конкретную ORM.

2. Все поля должны быть get и set, даже если по вашей внутренней логике объект не мутабельный. Фактически любой ваш объект может быть изменен в любом слое, вы не можете этого запретить.
Re[6]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Shmj Ниоткуда  
Дата: 26.09.17 16:54
Оценка:
Здравствуйте, Sharov, Вы писали:

S>4-5 -- dto с трасфорамацией в бизнес объекты.


И еще. Как выполняете трансоформацию? С помощью рефлексии или вручную?
Re[4]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Shmj Ниоткуда  
Дата: 26.09.17 17:11
Оценка:
Здравствуйте, rameel, Вы писали:

R>Поправочка: если это коллекция (ICollection<T>, IDictionary<TKey,TValue>, ISet<T> или их наследники), то сеттер не нужен, все и так работает, если


А вот:

https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/property

✓ DO create get-only properties if the caller should not be able to change the value of the property.
Keep in mind that if the type of the property is a mutable reference type, the property value can be changed even if the property is get-only.


По вашей схеме вообще не будет никакой возможности сделать get-only свойства. Вообще никак. Все должны быть и get и set.

А что если ваш объект требует неизменности? Вы его передаете и должна быть гарантия что метод его не изменит. Что тогда?
Re[7]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Sharov Россия  
Дата: 26.09.17 17:17
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Здравствуйте, Sharov, Вы писали:


S>>Для 1-3 -- наследование, подвязанное к ORM. 4-5 -- dto с трасфорамацией в бизнес объекты.


S>А конкретно. Вы создаете объекты в EF DB-First/Model-First а потом наследуетесь от них? Т.е. вся ваша архитектура гвоздями прибита к EF?


У меня сценарий проще, поэтому всюду использую сгенерированные orm объекты (у меня telerik openaccess). В случае передачи объектов между сервисами,
использую трансформацию в dto, которую для меня тот же orm уже сгенерировал. Трансформация выполняется копированием полей+какая-то специфичная бизнес логика.
Кодом людям нужно помогать!
Re: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: bnk СССР http://unmanagedvisio.com/
Дата: 26.09.17 17:38
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Видите ли вы проблему в том что по сути одни и те же данные по многу раз приходится копировать из одной структуры в другую лишь по той причине, что они применяются в разных слоях (но по стуи одинаковые сущности)?


Нет тут никакой проблемы.
Определяешь 5 разных классов, и все. Если попытаешься переиспользовать один — все закончится кашей (перемешиванием разных модулей и слоев)
Копируешь автомаппером например (самая распространенная либа для этого на .net) — обеспечивает гибкое эффективное копирование "похожих" объектов.
Re[5]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: rameel https://github.com/rsdn/CodeJam
Дата: 26.09.17 17:54
Оценка:
Здравствуйте, Shmj, Вы писали:

Я ответил на вот это вот:
S> А для XML-сериализации/десериализации, к примеру, они обязательны.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Re[2]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Shmj Ниоткуда  
Дата: 26.09.17 17:55
Оценка:
Здравствуйте, bnk, Вы писали:

bnk>Нет тут никакой проблемы.

bnk>Определяешь 5 разных классов, и все. Если попытаешься переиспользовать один — все закончится кашей (перемешиванием разных модулей и слоев)
bnk>Копируешь автомаппером например (самая распространенная либа для этого на .net) — обеспечивает гибкое эффективное копирование "похожих" объектов.

Не ясно почему обязательно получится "каша".

А про копирование. Ведь есть такое понятие как конструктор и он вызвается при создании класса. Там указываются обязательные поля. А ваш automapper знает про конструкторы и обязательные поля?

Или вы предлагаете отказаться от концепции конструкторов, оставлять его всегда пустым и просто использовать метод VilidateInstance для проверки установлены ли обязательные поля?
Re[6]: Про бизнес-объекты: для сохранения, для API, для внут
От: Shmj Ниоткуда  
Дата: 26.09.17 17:57
Оценка:
Здравствуйте, rameel, Вы писали:

R>Я ответил на вот это вот:

S>> А для XML-сериализации/десериализации, к примеру, они обязательны.

Да, для коллекций оказывается не обязательны.

Но по предложенной выше парадигме с использованием единого класса для всего -- вообще все свойства будут имет обязательно и get и set. А что если объект не подразумевает возможность изменений?
Отредактировано 26.09.2017 17:58 Shmj . Предыдущая версия .
Re[7]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: rameel https://github.com/rsdn/CodeJam
Дата: 26.09.17 18:02
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Но по вашей парадигме вообще все свойства будут имет обязательно и get и set. А что если объект не подразумевает возможность изменений?


Какой парадигме?! Я вообще-то один раз только написал, указать, что для стандартной XML (де)сериализации коллекции не обязательно наличии сеттера.

Вопрос я думаю адресуется не ко мне, я в дискуссии не учавствовал
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Re[7]: Про бизнес-объекты: для сохранения, для API, для внут
От: rameel https://github.com/rsdn/CodeJam
Дата: 26.09.17 18:07
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Но по предложенной выше парадигме с использованием единого класса для всего -- вообще все свойства будут имет обязательно и get и set. А что если объект не подразумевает возможность изменений?


Здесь я с тобой согласен, если что. Если объект не подразумевает изменений, то и класс проектируется соответствуюшим образом
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Re[3]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: bnk СССР http://unmanagedvisio.com/
Дата: 26.09.17 18:24
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Здравствуйте, bnk, Вы писали:


bnk>>Нет тут никакой проблемы.

bnk>>Определяешь 5 разных классов, и все. Если попытаешься переиспользовать один — все закончится кашей (перемешиванием разных модулей и слоев)
bnk>>Копируешь автомаппером например (самая распространенная либа для этого на .net) — обеспечивает гибкое эффективное копирование "похожих" объектов.

S>Не ясно почему обязательно получится "каша".


Ясно почему — аттрибуты сериализации в базу полезут в Web API, и наоборот.
Данные, нужные только для UI, нужно будет маркировать "не сохранять", "не экспортировать", ну и т.д.
Типы данных будет покорежены — возьмем например enum. В базе нужет int, в UI — string. Что делаем?

S>А про копирование. Ведь есть такое понятие как конструктор и он вызвается при создании класса. Там указываются обязательные поля. А ваш automapper знает про конструкторы и обязательные поля?

S>Или вы предлагаете отказаться от концепции конструкторов, оставлять его всегда пустым и просто использовать метод VilidateInstance для проверки установлены ли обязательные поля?

Нафик конструкторы. Бесполезная вещь в данном случае. Данные проверяются строго на пользовательском вводе, и больше нигде. А там WebAPI и всякие [Required], заботиться не о чем.
Все равно в таких классах как правило дофигищи полей, не засовывать же их все в параметры конструктора?
Re[4]: Про бизнес-объекты: для сохранения, для API, для внут
От: Shmj Ниоткуда  
Дата: 26.09.17 20:27
Оценка:
Здравствуйте, bnk, Вы писали:

bnk>Ясно почему — аттрибуты сериализации в базу полезут в Web API, и наоборот.


А чем они мешают на практике?

bnk>Данные, нужные только для UI, нужно будет маркировать "не сохранять", "не экспортировать", ну и т.д.


Правильно, пометить что те или иные не нужно экспортировать. Это разве не логично и правильно? Пометил -- а система разберется.

bnk>Типы данных будет покорежены — возьмем например enum. В базе нужет int, в UI — string. Что делаем?


Так это по отдельности указывается с помощью атрибутов или Fluent

bnk>Нафик конструкторы. Бесполезная вещь в данном случае. Данные проверяются строго на пользовательском вводе, и больше нигде. А там WebAPI и всякие [Required], заботиться не о чем.


Данные поступают не только от пользователя. Идея такая -- нельзя создать объект класса без обязательных полей. Зачем тогда вообще конструкторы с параметрами нужны? Или вы их вообще не используете никогда, отказались от концепции конструктора как такового?

bnk>Все равно в таких классах как правило дофигищи полей, не засовывать же их все в параметры конструктора?


Но не все же из них обязательные?
Отредактировано 26.09.2017 20:47 Shmj . Предыдущая версия .
Re[5]: Про бизнес-объекты: для сохранения, для API, для внут
От: bnk СССР http://unmanagedvisio.com/
Дата: 26.09.17 21:00
Оценка: 11 (3) +1
Здравствуйте, Shmj, Вы писали:

bnk>>Данные, нужные только для UI, нужно будет маркировать "не сохранять", "не экспортировать", ну и т.д.

S>Правильно, пометить что те или иные не нужно экспортировать. Это разве не логично и правильно? Пометил -- а система разберется.

Ну конечно :) А атрибуты где определены? В слое данных (EF?) Добавляем референс на него, ага.
Дальше, атрибуты для WCF? Конечно, добавляем референс на него тоже. Дальше, что там, WebAPI, JSON, XML? да, еще референсы.
Потом нужно передать пару дополнительных флажков для UI, и пару списков для комбобоксов? Конечно, добавляем поля и помечаем их всем чем нужно, для всех модулей не забыв.
Для JSON-сервиса понадобился штамп времени? Добавляем...

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

bnk>>Типы данных будет покорежены — возьмем например enum. В базе нужет int, в UI — string. Что делаем?


S>Так это по отдельности указывается с помощью атрибутов или Fluent


То есть сделать int/enum? а потом типа навешивать гроздьями атрибуты-конвертеры в строку для WCF или API? или сделать строкой?

bnk>>Нафик конструкторы. Бесполезная вещь в данном случае. Данные проверяются строго на пользовательском вводе, и больше нигде. А там WebAPI и всякие [Required], заботиться не о чем.


S>Идея такая -- нельзя создать объект класса, чтобы в нем не было обязательных полей. Зачем тогда вообще конструкторы с параметрами нужны? Или вы их вообще не используете никогда, отказались от концепции конструктора как такового?


Если больше одного-двух-трех — нет, в лес. Делаем проперти. Для DTO — да, никаких конструкторов.
Отредактировано 26.09.2017 21:14 bnk . Предыдущая версия . Еще …
Отредактировано 26.09.2017 21:05 bnk . Предыдущая версия .
Re[6]: Про бизнес-объекты: для сохранения, для API, для внут
От: Shmj Ниоткуда  
Дата: 26.09.17 21:59
Оценка:
Здравствуйте, bnk, Вы писали:

bnk>Ну конечно А атрибуты где определены? В слое данных (EF?) Добавляем референс на него, ага.

bnk>Дальше, атрибуты для WCF? Конечно, добавляем референс на него тоже. Дальше, что там, WebAPI, JSON, XML? да, еще референсы.

Доля истины в этом есть. Но многие атрибуты, к примеру Table, Key, Required, Display, NotMapped и пр. определены в системной сборке System.ComponentModel.DataAnnotations. Т.е. нет привязки к конкретной ORM, к примеру. Index, ForeignKey и пр. можно добавить с помощью Fluent API.

Если у вас во главе стоят бизнес-объекты, то ничего плохого в атрибутах нет.

Или же можно сделать их в виде интерфейсов. Но и там без атрибутов некоторых не обойтись...

bnk>Потом нужно передать пару дополнительных флажков для UI, и пару списков для комбобоксов? Конечно, добавляем поля и помечаем их всем чем нужно, для всех модулей не забыв.


А вы даже интерфейсы не определяете, просто делаете разные классы? Ни базового ни интерфейсов общих?

bnk>В общем я к чему — в результате получится класс данных, который "знает" все обо всех. Слишком много знает.


Оно и так и не так. В теории все атрибуты должны быть в System.ComponentModel.DataAnnotations. Но на практике не совсем так.

С другой стороны раз вы определили конкретные классы, а не контракты, то они и должны знать где их будут использовать. Или же тогда определять в виде контрактов-интерфейсов.

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

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

Да, соглашусь.

S>>Идея такая -- нельзя создать объект класса, чтобы в нем не было обязательных полей. Зачем тогда вообще конструкторы с параметрами нужны? Или вы их вообще не используете никогда, отказались от концепции конструктора как такового?


bnk>Если больше одного-двух-трех — нет, в лес. Делаем проперти. Для DTO — да, никаких конструкторов.


А зачем тогда вообще конструкторы с параметрами нужны? Может сразу запретить конструкторы с параметрами и всем станет проще жить?
Re[7]: Про бизнес-объекты: для сохранения, для API, для внут
От: bnk СССР http://unmanagedvisio.com/
Дата: 26.09.17 22:14
Оценка:
Здравствуйте, Shmj, Вы писали:

S>А вы даже интерфейсы не определяете, просто делаете разные классы? Ни базового ни интерфейсов общих?


Ничего. Ни общего базового класса, ни интерфейсов. Просто разные классы с одинаково названными полями.

bnk>>Если больше одного-двух-трех — нет, в лес. Делаем проперти. Для DTO — да, никаких конструкторов.


S>А зачем тогда вообще конструкторы с параметрами нужны? Может сразу запретить конструкторы с параметрами и всем станет проще жить?


Ну речь же про DTO. Вот для DTO — не нужны. А вообще — бывает удобно. using сделать, эксепшен бросить, зависимости проинициализировать.. Для DI например.
Последнее кстати исключение — может быть больше аргументов. Но тут уже чисто технические ограничения используемого фреймворка.

Речь не только про конструктор. Вообще, зачем в фунцию передавать много аргументов? Если надо — обернул в объект, передал.
А то сделают конструктор типа
new UserInfo(string domain, string username, string gender, string title, string password)
— поди не перепутай аргументы при вызове
Отредактировано 26.09.2017 22:15 bnk . Предыдущая версия .
Re[3]: Про бизнес-объекты: для сохранения, для API, для внут
От: Kolesiki  
Дата: 27.09.17 16:15
Оценка:
Здравствуйте, Shmj, Вы писали:

S> Но как быть с другими свойствами? Если один объект для всего, то вообще нельзя создавать только get-свойства. Получается если передали объект в метод -- нет гарантий что он там не подвергнется изменениям.


По какой причине нельзя создавать get-only??
Re[3]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Kolesiki  
Дата: 27.09.17 16:21
Оценка:
Здравствуйте, Shmj, Вы писали:

S>1. Если используете тот же EF CodeFirst, то нужно помечать атрибутами поля.


А если не используете, то не надо. Сугубо фишка EF.

S> А это значит что библиотека ваших контрактов будет иметь зависимость на конкретную ORM.


Ну и что? Вы много меняли ОРМов в одном и том же проекте? ОРМ — это не то, чтобы фундаментальная вещь, но всё же пишется не на один год (в отличии от JS библиотек). Да, у классов некоторые поля будут со специфичными атрибутами. Вам они жмут?


S>2. Все поля должны быть get и set


Ваще не так. С чего это? Хочешь — заводи поля, хочешь — проперти (любого вида доступа). Главное — чтобы объект умел отдавать поля, нужные для базы и записывать те, которые берутся из базы (а это могут быть разные наборы).

S>Фактически любой ваш объект может быть изменен в любом слое, вы не можете этого запретить.


А зачем мне что-то "запрещать" в собственном коде?? Ради чьей-то парадигмы? Это ты пишешь код — ты и решаешь, что изменять.
Re[4]: Про бизнес-объекты: для сохранения, для API, для внут
От: Shmj Ниоткуда  
Дата: 27.09.17 16:55
Оценка:
Здравствуйте, Kolesiki, Вы писали:

S>> Но как быть с другими свойствами? Если один объект для всего, то вообще нельзя создавать только get-свойства. Получается если передали объект в метод -- нет гарантий что он там не подвергнется изменениям.


K>По какой причине нельзя создавать get-only??


Если у вас один объект для всего, то в одном слое может требоваться set, а в другом только get. И дабы была универсальность вам везде нужно будет проставить и get и set.
Re[4]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Shmj Ниоткуда  
Дата: 27.09.17 17:43
Оценка:
Здравствуйте, Kolesiki, Вы писали:

K>А если не используете, то не надо. Сугубо фишка EF.


То есть ваше решение не совместимо с EF?

S>> А это значит что библиотека ваших контрактов будет иметь зависимость на конкретную ORM.


K>Ну и что? Вы много меняли ОРМов в одном и том же проекте? ОРМ — это не то, чтобы фундаментальная вещь, но всё же пишется не на один год (в отличии от JS библиотек). Да, у классов некоторые поля будут со специфичными атрибутами. Вам они жмут?


Как уже сказали выше, ваш слой контрактов будет знать обо всем. Кроме того, атрибуты могут и конфликтовать -- для одного слоя нужна сериализация а для другого нет.

S>>2. Все поля должны быть get и set


K>Ваще не так. С чего это? Хочешь — заводи поля, хочешь — проперти (любого вида доступа). Главное — чтобы объект умел отдавать поля, нужные для базы и записывать те, которые берутся из базы (а это могут быть разные наборы).


А если в одном из слоев вы не хотите разрешать запись в свойство, в которое база должна уметь писать?

S>>Фактически любой ваш объект может быть изменен в любом слое, вы не можете этого запретить.

K>А зачем мне что-то "запрещать" в собственном коде?? Ради чьей-то парадигмы? Это ты пишешь код — ты и решаешь, что изменять.

А что другие ваш код не используют? Ну если чисто для себя -- согласен.
Re[3]: Про бизнес-объекты: для сохранения, для API, для внут
От: Vladek Россия Github
Дата: 27.09.17 22:45
Оценка: -2
Здравствуйте, Shmj, Вы писали:

S>Здравствуйте, Kolesiki, Вы писали:


K>>Вот с этого и надо начинать. Если некая свежепровозглашённая шиза не вписывается в практичную логику, это не "парадигма", а сферический конь в вакууме.


S>Ну почему шиза? Вы читали Guidelines https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/guidelines-for-collections ?

S>Те же коллекции не должны иметь set-еров по этим рекомендациям. А для XML-сериализации/десериализации, к примеру, они обязательны.


S>С коллекциями ошибся, оказывается и без сетеров сериализация работает. Но как быть с другими свойствами? Если один объект для всего, то вообще нельзя создавать только get-свойства. Получается если передали объект в метод -- нет гарантий что он там не подвергнется изменениям.


Просто потому что описанное — не ООП. Это не объекты и методы, а структуры данных и процедуры, существующие порознь.

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



Тебе не хватает выделенного.
Re: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Doc Россия http://andrey.moveax.ru
Дата: 28.09.17 05:21
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Видите ли вы проблему в том что по сути одни и те же данные по многу раз приходится копировать из одной структуры в другую лишь по той причине, что они применяются в разных слоях (но по стуи одинаковые сущности)?


Если одинаковый на вид код имеет разное назначение, это разный код. )
В данной ситуации IMHO предпочтительнее собственные классы внутри слоев, решающие конкретные задачи, а не один класс, собирающий все что можно в кашу.
Re[5]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Kolesiki  
Дата: 29.09.17 10:44
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Здравствуйте, Kolesiki, Вы писали:


K>>А если не используете, то не надо. Сугубо фишка EF.


S>То есть ваше решение не совместимо с EF?


Т.е. моему решению пофиг, что за ОРМ используется — вешай атрибуты от любого!


S>Как уже сказали выше, ваш слой контрактов будет знать обо всем.


И что в этом плохого? Напомню, мы говорим про ОДИН объект на всё. Для каждого слоя объект имеет нужные атрибуты и проперти. А слоёв у нас — три.

S> Кроме того, атрибуты могут и конфликтовать -- для одного слоя нужна сериализация а для другого нет.


Глупости, это не "конфликт", а небольшой оверхэд. Какому слою надо, тот и сериализует (находя нужные именно ему атрибуты).


S>А если в одном из слоев вы не хотите разрешать запись в свойство, в которое база должна уметь писать?


Ну так а кто в этом слое полезет в проперть?? Нельзя писать — пометь комментом и не пиши!

S>А что другие ваш код не используют? Ну если чисто для себя -- согласен.


Вы так муторно заворачиваете всю эту проблему, будто у программиста только и головной боли, что "а кто в том слое хочет изменить мою бесценную проперть?!". Возможно, в каше слишком много разных круп — пересмотрите котелок.

Бизнес объект — это не какая-то недотрога, которую надо охранять — это данные, ваш бизнес-код должен ими оперировать и только. Где там взяться "чужому коду"?? А если и появляются "чужаки", так для этого (специфичного случая) специально надо архитектуру затачивать! Но уверяю, это не общий случай.
Пару раз у меня были моменты, когда некие данные не должны были быть видимы. Сделал элементарнейший метод клонирования, который в копию передавал только видимые данные и отправлял объект другому модулю — всего делов-то!
Был ещё момент, когда некие данные категорически нельзя перезаписывать (в базе). Моё решение: из базы считываю ОРМ-объект, перезаписываю свежие данные тлько нужных пропертей, сохраняю обратно. Таким образом ты можешь коверкать проперти, но они никогда не испортят систему.

Короче, специфичные бизнес-случаи, которые вовсе не обязательно тащить на уровень архитектуры. Бонусом послужил простой, поддерживаемый код — первоочередное свойство у интыпрайзных решений. А если у меня на каждый слой/модуль/свистелку будет свой набор классов... ё-моё... я повешусь поддерживая это в консистентном состоянии! Таблицы — они не то, чтоб часто менялись, но их изменения не должны превращаться в недельный аудит кода "где я тут проперть делал ридонли??". Нафик, чем проще — тем понятнее.
Re: Вижу: DRY, копипаста
От: igor-booch Россия  
Дата: 08.10.17 14:00
Оценка:
По сути несколько классов с похожей структурой это копипаста со всеми вытекающими последствиям.
Добавление поля требует изменений не в одном классе, а в нескольких. И попробуй ошибись. А если изменения более сложные чем добавление поля (изменились связи между классами)?
Между тем в старпапе изменения структуры данных вполне нормальная вещь. Да, клиенты не знают чего хотят или знают но не могут объяснить, с этим нужно смириться. И при этом готовый к продакшену продукт нужно получить в кратчайшие сроки. Поэтому по возможности я делаю универсальные классы.
Отвечайте на это сообщение, только если у Вас хорошее настроение и в Вашем ответе планируются только конструктивные вопросы и замечания
http://rsdn.ru/Info/rules.xml
Re: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: rm822 Россия  
Дата: 08.10.17 14:25
Оценка:
S>Видите ли вы проблему в том что по сути одни и те же данные по многу раз приходится копировать из одной структуры в другую лишь по той причине, что они применяются в разных слоях (но по стуи одинаковые сущности)?
Да, это проблема, когда объектов становится >1млн. И в чем вопрос?
Re[2]: Вижу: DRY, копипаста
От: Shmj Ниоткуда  
Дата: 09.10.17 01:09
Оценка:
Здравствуйте, igor-booch, Вы писали:

IB>По сути несколько классов с похожей структурой это копипаста со всеми вытекающими последствиям.

IB>Добавление поля требует изменений не в одном классе, а в нескольких. И попробуй ошибись. А если изменения более сложные чем добавление поля (изменились связи между классами)?

А как вы смотрите на использование интерфейсов в качестве основы/скелета бизнес-объектов для всех слоев?
Re[2]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: Shmj Ниоткуда  
Дата: 09.10.17 02:16
Оценка:
Здравствуйте, rm822, Вы писали:

S>>Видите ли вы проблему в том что по сути одни и те же данные по многу раз приходится копировать из одной структуры в другую лишь по той причине, что они применяются в разных слоях (но по стуи одинаковые сущности)?

R>Да, это проблема, когда объектов становится >1млн. И в чем вопрос?

А если 10 тыс. -- то не проблема?
Re[3]: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: rm822 Россия  
Дата: 09.10.17 06:16
Оценка:
S>А если 10 тыс. -- то не проблема?
как правило — нет, мало...
Re[3]: Вижу: DRY, копипаста
От: igor-booch Россия  
Дата: 09.10.17 10:21
Оценка:
S>А как вы смотрите на использование интерфейсов в качестве основы/скелета бизнес-объектов для всех слоев?

Я не уверен, что правильно понимаю Вашу технологию интерфейсов. Допустим есть слой доступа к данным. Есть web приложение и десктоп приложение. Web приложение и десктоп приложение умеют сохранять заказ, используя при этом слой доступа к данным. Какие где будут классы и интерфейсы?
Отвечайте на это сообщение, только если у Вас хорошее настроение и в Вашем ответе планируются только конструктивные вопросы и замечания
http://rsdn.ru/Info/rules.xml
Re[4]: Вижу: DRY, копипаста
От: Shmj Ниоткуда  
Дата: 10.10.17 03:00
Оценка:
Здравствуйте, igor-booch, Вы писали:

IB>Я не уверен, что правильно понимаю Вашу технологию интерфейсов. Допустим есть слой доступа к данным. Есть web приложение и десктоп приложение. Web приложение и десктоп приложение умеют сохранять заказ, используя при этом слой доступа к данным. Какие где будут классы и интерфейсы?


1. Выделяете слой сервисов, реализация которых не зависит от GUI. Создаете контракты для каждого сервиса. К примеру, будет интерфейс IOrderService. А в нем метод CreateOrder(IOrder order). Так вот IOrder -- тоже интерфейс, но уже для бизнес-объекта.

2. В реализации сервиса IOrderService делаете класс OrderService, который реализует метод CreateOrder. А так же в реализации сервисов делаете класс бизнес-объекта Order, который реализует IOrder (делается одной кнопкой). И у этого класса уже проставляете нужные вам поля.

3. Web-приложение и десктоп-приложение работают не с сервисом OrderService, а с контрактами IOrderService. Конкретную реализацию подключаете с помощью IoC (есть готовые либы типа Unity и пр.).

4. Web-приложение делает свой класс-реализацию IOrder. Причем может добавлять доп. поля и доп. атрибуты, которые нужны ему. Соответственно десктоп-приложение делает то же самое -- свои доп. поля и атрибуты.

5. Если вы измените какое-либо поле в контракте или добавите новое -- компилятор сразу же сообщит об этом, т.е. не забудете исправить во всех слоях.
Отредактировано 10.10.2017 3:51 Shmj . Предыдущая версия .
Re[5]: Вижу: DRY, копипаста
От: igor-booch Россия  
Дата: 10.10.17 08:34
Оценка:
S>5. Если вы измените какое-либо поле в контракте или добавите новое -- компилятор сразу же сообщит об этом, т.е. не забудете исправить во всех слоях.

Это весомое преимущество. Конечно я за интерфейсы. Какие еще Вы видите профиты от интерфейсов в рассматриваемом сценарии? Я вижу следующее преимущество: можно навесить логику на интерфейс IOrder (например, в виде экстеншен методов), поместить её в сборку вместе интерфейсом IOrder и использовать эту логику в десктопе и веб приложении (десктоп и веб приложение ссылаются на сборку с интерфейсом).

В случае если с десктопа и с веб приложения был бы допустим прямой доступ к БД, я бы сделал проще.
Слой доступа к данным (имеющий прямой доступ к БД) реализуем в сборке. Десктоп и веб приложение просто ссылаются на эту сборку.
Если веб приложению понадобятся доп. свойства у Order,
в сборке веб приложения создаем наследника WebOrder : Order. Аналогично для десктопа.
В этом случае интерфейс IOrder не нужен. Вернее он может понадобиться, но только как часть бизнес модели, но не как технический интерфейс для обеспечения инфраструктуры слоёв (скелета бизнес объектов, как Вы сказали).
Если кому-то понадобился непрямой доступ к БД (через сервис), оборачиваем ту же сборку доступа к данным в сервис, и тогда технический интерфейсы для обеспечения инфраструктуры слоёв становятся нужны. Но в этом случае логику на инфраструктурный интерфейс IOrder уже не навесишь (как я выше написал), так как она уже в классе Order присутствует.
Но я сторонник прямого доступа к БД с десктопа (с веб приложения тем более). Да, надо поработать над безопасностью, правами доступа пользователей на уровне БД, SSL соединением клиента С БД, но дело того стоит. Не надо создавать сервис доступа к БД, только для того чтобы не возиться с её настройками безопасности.

S>3. Web-приложение и десктоп-приложение работают не с сервисом OrderService, а с контрактами IOrderService. Конкретную реализацию подключаете с помощью IoC (есть готовые либы типа Unity и пр.).

Несколько различных реализаций IOrderService кроме тестирования может ещё для чего-то понадобиться?
Отвечайте на это сообщение, только если у Вас хорошее настроение и в Вашем ответе планируются только конструктивные вопросы и замечания
http://rsdn.ru/Info/rules.xml
Отредактировано 10.10.2017 15:17 igor-booch . Предыдущая версия . Еще …
Отредактировано 10.10.2017 10:12 igor-booch . Предыдущая версия .
Отредактировано 10.10.2017 10:10 igor-booch . Предыдущая версия .
Отредактировано 10.10.2017 9:34 igor-booch . Предыдущая версия .
Отредактировано 10.10.2017 9:00 igor-booch . Предыдущая версия .
Отредактировано 10.10.2017 8:59 igor-booch . Предыдущая версия .
Отредактировано 10.10.2017 8:36 igor-booch . Предыдущая версия .
Re: Про бизнес-объекты: для сохранения, для API, для внутреннего
От: vmpire Россия  
Дата: 10.10.17 19:13
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Практически в каждом проекте эти данные используются для 4-5 вещей:


S>1. Для внутреннего потребления, т.е. вы некие классы передаете/принимаете в своих методах и что-то с ними делаете.

S>2. Для сохранения. Как правило ORM позволяет сохранять сами эти структуры данных. Но так просто не получается -- их нужно либо наделить атрибутами либо кодогенерацией (ну или XML-описанием).
S>3. Эти же структуры данных иногда приходится сохранять на диск в неком формате без ORM. К примеру для сохранения в xlsx-файл.
S>4. Эти же структуры вам нужно отдавать через REST/SOAP-API внешним пользователям.
S>5. Эти же структуры вам нужно получать из внешнего API, от которого уже вы зависите.

S>Главное неудобство вижу в том, что по стуи очень похожие структуры в каждом из этих 5 случаев нужно копировать одну в другую. Потому что они хотя и похожи, порой на 90%, но все же отличаются. К примеру в одном случае требуется обязательное наличие set-еров, иначе библиотека отказывается работать с данными (к примеру, стандартная XML-сериализация требует чтобы у списка был set-ер). Но наличие set-еров противоречит внутренней парадигме.


S>Видите ли вы проблему в том что по сути одни и те же данные по многу раз приходится копировать из одной структуры в другую лишь по той причине, что они применяются в разных слоях (но по стуи одинаковые сущности)?

Краткий ответ на этот вопрос такой:
— Если приложение небольшое (скажем, до 100000 строк) и с небольшим временем жизни (год-два) — делайте комбинированный класс для всех целей сразу, отключая ненужное в каждом случае при сериализациях.
Потому что зачем повторять одно и то же в нескольких местах?
В одном объекте можно атрибутами задать и правида сериализации в XML (ну, по крайней мере, до тех пор, пока такой формат только один) и мэппинг на базу и всё что там ещё нужно.

— Если приложение среднее или большое или планируется к долгой жизни — не поленитесь создать отдельные классы.
Потому, что экономия на одном классе вместо пяти в масштабе проекта будет мизерной, а вот проблемы от того, что нужно, например, изменить использование класса во внешнием API, а структура прибита гвоздями и к базе и к JavaScript (где почти никогда нет дотошных тестов, проверяющих все варианты использования всех полей) — будут вполне реальными.
Плюс постоянно будут скрытые ошибки или просто потеря скорости из-за того, что где-то что-то лишнее сериализовалось, либо сериализовалось не в тот тип...
У меня такие случаи со старым кодом встречются регулярно.
Вот как раз совсем недавно был свежий пример: понадобилось изменить тип поля с DateTime на DateTimeOffset для внешнего API, оставив DateTime в остальных случаях.
И как хорошо, что у меня где-то на 80% эти классы уже были выделены.
Иначе бы развалилось довольно много.

Для второго случая нужно заранее продумать схему преобразований. Если она оказывается "все ко всем" — то где-то есть архитектурная проблема.
Обычно получается что-то типа звезды: в центре — бизнес-сущность "для внутреннего потребления", а от неё двунаправленные конвертации в базу, в DTO и т.д.
И нужно понимать, что отдельный формат представлений — это не всегда отдельный класс созданный вручную. Например, для уравня DataAccess этим представлением может быть маппинг для ORM.

То есть, наример, между слоями приложения ходит формат "для внутреннего потребления"
Для сохранения в слой DataAccess приходит та же "для внутреннего потребления". Как DataAccess её сохранит — это его внутреннее дело. Может через мэппинг (если он не прописан в самой основной сущности), а может и созданием промежуточного класса, который будет жить только в DataAccess
Для внешних сервисов и для передачи в браузер создаётся специализированный DTO, который живёт в слое доступа к этим сервисам лио в выделенном service agent, если таковой есть. А приходит в этот service agent вё та же сущность "для внутреннего потребления"
Re[5]: Вижу: DRY, копипаста
От: vmpire Россия  
Дата: 11.10.17 15:02
Оценка:
Здравствуйте, Shmj, Вы писали:

S>1. Выделяете слой сервисов, реализация которых не зависит от GUI.

...
S>3. Web-приложение и десктоп-приложение работают не с сервисом OrderService, а с контрактами IOrderService. Конкретную реализацию подключаете с помощью IoC (есть готовые либы типа Unity и пр.).
А зачем нужны несколько реализаций для разных GUI, если реализация не зависит от GUI?
Re[6]: Вижу: DRY, копипаста
От: Shmj Ниоткуда  
Дата: 11.10.17 18:49
Оценка:
Здравствуйте, vmpire, Вы писали:

S>>3. Web-приложение и десктоп-приложение работают не с сервисом OrderService, а с контрактами IOrderService. Конкретную реализацию подключаете с помощью IoC (есть готовые либы типа Unity и пр.).

V>А зачем нужны несколько реализаций для разных GUI, если реализация не зависит от GUI?

Для тестирования.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.