Пара вопросов про анемик
От: snaphold  
Дата: 11.04.11 14:48
Оценка:
Прочитал здесь про liabilities anemic
и не понял пункт

"It also means that domain model's objects cannot guarantee their correctness at any moment, because their validation and mutation logic is placed somewhere outside (most likely in multiple places)."


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

также не понял вот этот пункт


Necessitates a global access to internals of shared business entities increasing coupling and fragility.


как это проявляется повышение связанности сущностей?
Re: Пара вопросов про анемик
От: dimgel Россия https://github.com/dimgel
Дата: 11.04.11 15:02
Оценка:
Здравствуйте, snaphold, Вы писали:

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


Лично я использую immutable entities...
Re: Пара вопросов про анемик
От: AndrewJD США  
Дата: 11.04.11 15:29
Оценка: 2 (1) +3 -1
Здравствуйте, snaphold, Вы писали:

S>Прочитал здесь про liabilities anemic


Лучше поискать другой источник иформации, чем эта статья в wiki.
ИМХО, она не адекватна


Liabilities
Logic cannot be implemented in a truly object-oriented way unless wrappers are used, which hide the anemic data structure.

Что такое "truly object-oriented"? Есть какая-то формальная метрика определяющая насколько код есть труъ object-oriented?

Violation of the encapsulation and information hiding principles.

Это не соотвествует действительности.

Necessitates a separate business layer to contain the logic otherwise located in a domain model.

Ничего плохого в отделении мух от котлет я не вижу

It also means that domain model's objects cannot guarantee their correctness at any moment, because their validation and mutation logic is placed somewhere outside (most likely in multiple places).

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



Necessitates a global access to internals of shared business entities increasing coupling and fragility.

С точностью наоборот. Анемик модель значительно уменьшает связность. Поскольку в обьектах нет бизнес логики, в анемик модели легко использовать "Single responsibility principle".

Facilitates code duplication among transactional scripts and similar use cases, reduces code reuse.

Конечно, использование универсальных всемогутеров увеличивает повторное использование кода, а маленькие без лишних зависимостей уменьшает
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Re: Пара вопросов про анемик
От: snaphold  
Дата: 11.04.11 16:16
Оценка:
Здравствуйте, snaphold, Вы писали:

Подскажите, где можно посмотреть несложный пример с использованием анемика?
Re: Пара вопросов про анемик
От: Nick Sergeev Россия  
Дата: 11.04.11 18:31
Оценка:
Сегодня был приятно удивлен, отношением Фаулера к anemic'у. Он называет его анти-паттерном.
http://www.martinfowler.com/bliki/AnemicDomainModel.html

Но лично я не представляю rich или DDD аппликэйшн в современных энерпрайз решениях. Везде и всегда анемик.
Re[2]: Пара вопросов про анемик
От: Аноним  
Дата: 12.04.11 04:49
Оценка:
NS>Но лично я не представляю rich или DDD аппликэйшн в современных энерпрайз решениях. Везде и всегда анемик.

Тогда уж скорее сценарий транзакций(Transaction Script).
Re[3]: Пара вопросов про анемик
От: Nick Sergeev Россия  
Дата: 12.04.11 07:54
Оценка:
Здравствуйте, Аноним, Вы писали:

NS>>Но лично я не представляю rich или DDD аппликэйшн в современных энерпрайз решениях. Везде и всегда анемик.


А>Тогда уж скорее сценарий транзакций(Transaction Script).


Нет, не Transaction Script, потому что ему вообще доменная модель не нужна. И с таким мне бы не хотелось работать.
Все же если по Фаулеру, то я хотел сказать, что в энтерпрайз решениях преобладает Domain Model, но она везде и всегда анемик.

А вот рич я к сожалению не встречал в энтерпрайзе. И мне сложно представить как бы все это выглядело. То есть чтобы ВСЯ логика была в домене. Не в домене только инфраструктура и тонкая прослойка, типа фасада, которая бы раздавал доменным объекты команды. DDD в общем.
Re: Пара вопросов про анемик
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.04.11 08:41
Оценка:
Здравствуйте, snaphold, Вы писали:

S>Прочитал здесь про liabilities anemic

S>и не понял пункт

S>

S>"It also means that domain model's objects cannot guarantee their correctness at any moment, because their validation and mutation logic is placed somewhere outside (most likely in multiple places)."


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


А ты не передаватй изменяющиеся объекты туда-сюда. Пусть сервис БЛ получает от PL идентификаторы объектов или критерии выборки, внутри себя изменяет все что надо и сохраняет объеты.

Rich

Controller:
//...
var order = ordersRep.Get(orderId);
var product = productRep.GetProduct(productId);
order.AddLine(new OrderLine(product, quantity));
ordersRep.Save(order);
//...


Domain:
class OrderLine
{
    public OrderLine(Product product, int quantity)
    {
        this.Product = product;
        this.Quantity = quantity;
        this.Price = product.Price; //Тип сложная БЛ
    }
    //....    
}

class Order
{
    public void AddLine(OrderLine line)
    {
        var sum = this.Lines.Sum(l => l.Price * l.Quantity);
        if(sum+line.Product.Price > 10000) //Типа валидация
        { 
            throw new Exception("Order is too large"); 
        }
        this.Lines.Add(line);
    }
}


Anemic
//...
orderService.AddLineToOrder(orderId, productId, quantity);
//...



class OrderService
{
    orderService.AddLineToOrder(int orderId, int productId, int quantity)
    {
        var productPrice = (from p in productRep.Items
                            where p.Id == productId
                            select p.Price).First();
        var sum = (from ol in orderLinesRep.Items
                   where ol.OrderId == orderId
                   select l.Price * l.Quantity).Sum();
        if(sum+productPrice > 10000) //Типа валидация
        { 
            throw new Exception("Order is too large"); 
        }
        
        orderLinesRep.Add(new OrderLine {Orderid = orderId, ProductId = productId, Price = productPrice } );
    }
}


Вроде код похож, НО
1)В Rich логика конкретного действия размазана по нескольким классам
2)Чтобы логика в Rich работала нужен зачатую LazyLoad, который очень губителен для быстродействия

S>также не понял вот этот пункт

S>

S>Necessitates a global access to internals of shared business entities increasing coupling and fragility.

S>как это проявляется повышение связанности сущностей?

Вообще-то никак.
Re[3]: Пара вопросов про анемик
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.04.11 08:44
Оценка:
Здравствуйте, Аноним, Вы писали:

NS>>Но лично я не представляю rich или DDD аппликэйшн в современных энерпрайз решениях. Везде и всегда анемик.


А>Тогда уж скорее сценарий транзакций(Transaction Script).


Transaction Script — херня придуманная фаулером и им же обосранная. Реально так никто не пишет и видимо никогда не писал. Люди используют обычные функции для декомпозиции логики, это собственно и есть anemic: функции и данные.
Re[4]: Пара вопросов про анемик
От: Аноним  
Дата: 12.04.11 09:24
Оценка:
G>Transaction Script — херня придуманная фаулером и им же обосранная. Реально так никто не пишет и видимо никогда не писал. Люди используют обычные функции для декомпозиции логики, это собственно и есть anemic: функции и данные.
Тогда что за патерн такой когда вся бизнеслогика в БД, а коде только вызовы процедур + немного логики по отображению во View?
Domain Model?
Re[2]: Пара вопросов про анемик
От: Аноним  
Дата: 12.04.11 10:11
Оценка: -1
>1)В Rich логика конкретного действия размазана по нескольким классам
Нет это SRP. А что ты сделаешь если нужно переопределить поведение для кого-нибудь особенного ордера, скажем изменить валидацию?
В Rich просто создашь подкласс SuperOrder и переопределишь поведение. А в анемике у тебя появятся или ветвления в методе или создашь 2 полиморфных метода для каждого типа. А когда дабавиться еще какой-нибудь подтип и кто-то обязательно забудет дополнить код в сервисе.
Re[5]: Пара вопросов про анемик
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.04.11 13:12
Оценка:
Здравствуйте, Аноним, Вы писали:

G>>Transaction Script — херня придуманная фаулером и им же обосранная. Реально так никто не пишет и видимо никогда не писал. Люди используют обычные функции для декомпозиции логики, это собственно и есть anemic: функции и данные.

А>Тогда что за патерн такой когда вся бизнеслогика в БД, а коде только вызовы процедур + немного логики по отображению во View?
А>Domain Model?

Это может быть и то и другое. Rich и Anemic — о способе структурирования кода, а не том где будут запросы.
Re[3]: Пара вопросов про анемик
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.04.11 13:19
Оценка: 4 (1)
Здравствуйте, Аноним, Вы писали:

>>1)В Rich логика конкретного действия размазана по нескольким классам

А>Нет это SRP.
Где там SRP, если в Rich вся валидация и БЛ лежит внутри класса? Это как раз Anti-SRP.

А>А что ты сделаешь если нужно переопределить поведение для кого-нибудь особенного ордера, скажем изменить валидацию?

Добавлю условие в метод, если таких правил образуется множество, то сделаю инъекцию правил в сервис формирования ордеров.

А>В Rich просто создашь подкласс SuperOrder и переопределишь поведение.

А если тип ордера меняется в время его жини что тогда? (а вероятнее всего так и будет, заранее ты не скажешь)

А>А в анемике у тебя появятся или ветвления в методе или создашь 2 полиморфных метода для каждого типа. А когда дабавиться еще какой-нибудь подтип и кто-то обязательно забудет дополнить код в сервисе.

Не-а, см выше.

В случае изменяющегося набора правил что с ними делать в Rich? Инжектить в domain object? Когда инжектить? А если сериализация используется?
Ну его нафиг, Rich очень быстро превращается в неподьемного монстра при увеличении сложности.
Re[2]: Пара вопросов про анемик
От: -VaS- Россия vaskir.blogspot.com
Дата: 12.04.11 13:46
Оценка:
NS>Но лично я не представляю rich или DDD аппликэйшн в современных энерпрайз решениях. Везде и всегда анемик.

Ну так DDD не есть особенно объектно-ориентированная. Чисто процедурный подход — гоняем голые данные между процедурами, скруппированными в "сервисы". Это и не плохо, и не хорошо, ибо для энтерпрайза сегодня это едва ли не единственно подходящее решение.
Re[3]: Пара вопросов про анемик
От: AndrewJD США  
Дата: 12.04.11 14:45
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Нет это SRP. А что ты сделаешь если нужно переопределить поведение для кого-нибудь особенного ордера, скажем изменить валидацию?

А>В Rich просто создашь подкласс SuperOrder и переопределишь поведение.
А>А в анемике у тебя появятся или ветвления в методе или создашь 2 полиморфных метода для каждого типа.
В анемике я бы сделал иерархию валидаторов.
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Re[6]: Пара вопросов про анемик
От: Аноним  
Дата: 12.04.11 14:45
Оценка:
G>Это может быть и то и другое. Rich и Anemic — о способе структурирования кода, а не том где будут запросы.

Если БЛ весь в процедурах, то ни какой домен тебе не нужен, что в нем будет?
Если взять твой пример, то на Transaction Script будет примерно такой код:
class OrderService
{
    orderService.AddLineToOrder(int orderId, int productId, int quantity)
    {
        //намеренно опускаю абстракцию доступа данных
        //вызываем хранимку, которая выполняет всю логику по добавлению.
        exec("AddLineToOrder",orderID,productId,quantity);
    }
}


Я не агитирую за такой подход, но большинство web приложений и приложений работающих под большой нагрузкой (сотни транзакций в секунду) работают именно на TS.
Re[7]: Пара вопросов про анемик
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.04.11 14:52
Оценка:
Здравствуйте, Аноним, Вы писали:

G>>Это может быть и то и другое. Rich и Anemic — о способе структурирования кода, а не том где будут запросы.


А>Если БЛ весь в процедурах, то ни какой домен тебе не нужен, что в нем будет?

Смотря какие процедуры, многие ORM вполне спокойно мапят CRUD для сущностей на процедуры.

А>Если взять твой пример, то на Transaction Script будет примерно такой код:

А>
А>class OrderService
А>{
А>    orderService.AddLineToOrder(int orderId, int productId, int quantity)
А>    {
А>        //намеренно опускаю абстракцию доступа данных
А>        //вызываем хранимку, которая выполняет всю логику по добавлению.
А>        exec("AddLineToOrder",orderID,productId,quantity);
А>    }
А>} 
А>

Возможно, но я так не пишу. И не знаю никого кто так пишет.

А>Я не агитирую за такой подход, но большинство web приложений и приложений работающих под большой нагрузкой (сотни транзакций в секунду) работают именно на TS.

stackoverflow работает под большой нагрузкой, но использует Linq2SQL
То что ты пишешь было правдой 15 лет назад.
Re[4]: Пара вопросов про анемик
От: Аноним  
Дата: 12.04.11 14:58
Оценка:
G>Где там SRP, если в Rich вся валидация и БЛ лежит внутри класса? Это как раз Anti-SRP.
БЛ да, а валидациию можно убрать в другой объект, примеров масса. Об этом можно долго спорить.

А>>А что ты сделаешь если нужно переопределить поведение для кого-нибудь особенного ордера, скажем изменить валидацию?

G>Добавлю условие в метод, если таких правил образуется множество, то сделаю инъекцию правил в сервис формирования ордеров.

Вот уже пошли классы, классы...См: http://rsdn.ru/forum/design/4230324.1.aspx
Автор: gandjustas
Дата: 12.04.11

G>Вроде код похож, НО
G>1)В Rich логика конкретного действия размазана по нескольким классам

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


А>>В Rich просто создашь подкласс SuperOrder и переопределишь поведение.

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

А>>А в анемике у тебя появятся или ветвления в методе или создашь 2 полиморфных метода для каждого типа. А когда дабавиться еще какой-нибудь подтип и кто-то обязательно забудет дополнить код в сервисе.

G>Не-а, см выше.
Вот-вот.

G>В случае изменяющегося набора правил что с ними делать в Rich? Инжектить в domain object? Когда инжектить? А если сериализация используется?

G>Ну его нафиг, Rich очень быстро превращается в неподьемного монстра при увеличении сложности.
Можно пример.
Re[5]: Пара вопросов про анемик
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.04.11 15:19
Оценка:
Здравствуйте, Аноним, Вы писали:

G>>Где там SRP, если в Rich вся валидация и БЛ лежит внутри класса? Это как раз Anti-SRP.

А>БЛ да, а валидациию можно убрать в другой объект, примеров масса. Об этом можно долго спорить.
Ну так если все убрать, то и получится anemic.

Было

class SomeDomainObject
{
    void SomeDomainMethod()
    {
        SomeValidation();
        SomeLogic();
    }
}

class Cotroller
{
    void SomeAction()
    {
        var o = repo.Get(id);
        o.SomeDomainMethod();
        repo.Save(o);
    }
}


Выносим валидацию и БЛ:
class SomeDomainObject
{
    void SomeDomainMethod()
    {
        validationService.SomeValidation(this);
        bllService.SomeLogic(this);
    }
}

class Cotroller
{
    void SomeAction()
    {
        var o = repo.Get(id);
        o.SomeDomainMethod();
        repo.Save(o);
    }
}


Убираем лишний уровень косвенности
class Cotroller
{
    void SomeAction()
    {
        var o = repo.Get(id);
        validationService.SomeValidation(o);
        bllService.SomeLogic(o);
        repo.Save(o);
    }
}


После этого оптимизируем запросы, чтобы не поднимать целые объекты из базы, а только необходимое.
Для целей реюза кода делаем extract method, сходные методы группируем в классы. Получили anemic.

Я всегда говорил что правильный rich — это anemic

А>>>А что ты сделаешь если нужно переопределить поведение для кого-нибудь особенного ордера, скажем изменить валидацию?

G>>Добавлю условие в метод, если таких правил образуется множество, то сделаю инъекцию правил в сервис формирования ордеров.

А>Вот уже пошли классы, классы...См: http://rsdn.ru/forum/design/4230324.1.aspx
Автор: gandjustas
Дата: 12.04.11

G>>Вроде код похож, НО
G>>1)В Rich логика конкретного действия размазана по нескольким классам
А>И в твоем случае,если логика становится немного сложнее код размазывается по классам.
Если ситуация когда правила часто меняются и вызывающий код не может делать предположений о структуре правил, то это нормальный tradeoff.
А что делать в случае Rich?


А>>>В Rich просто создашь подкласс SuperOrder и переопределишь поведение.

G>>А если тип ордера меняется в время его жини что тогда? (а вероятнее всего так и будет, заранее ты не скажешь)
А>Сказать не могу, но если такое поведение возможно, то есть замечательный патерн state. Используя его я могу менять поведение объекта.
То есть у тебя будет один класс, который в зависимости от некоторого предиката будет вызывать некоторый код BL.
У меня будет тоже самое, только вызов будет идти не через domain object, а сразу из сервиса (контроллера).


G>>В случае изменяющегося набора правил что с ними делать в Rich? Инжектить в domain object? Когда инжектить? А если сериализация используется?

G>>Ну его нафиг, Rich очень быстро превращается в неподьемного монстра при увеличении сложности.
А>Можно пример.
Лениво писать, ты же выше привел свои мысли по моим рассуждениям о выносе правил из метода, сделай тоже самое в случае rich.
Re[8]: Пара вопросов про анемик
От: Аноним  
Дата: 12.04.11 15:26
Оценка:
G>Смотря какие процедуры, многие ORM вполне спокойно мапят CRUD для сущностей на процедуры.
Ты не ответил на вопрос, что будет в коде, если весь БЛ в процедурах.

G>Возможно, но я так не пишу. И не знаю никого кто так пишет.

Я тебя удивлю, но очень многие.


А>>Я не агитирую за такой подход, но большинство web приложений и приложений работающих под большой нагрузкой (сотни транзакций в секунду) работают именно на TS.

G>stackoverflow работает под большой нагрузкой, но использует Linq2SQL
G>То что ты пишешь было правдой 15 лет назад.
Посмотри на http://ormeter.net/ и увидишь разницу в материализации с ORM и без.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.