Как Принцип Единой Ответственности относится к модели анемичного / богатого домена?
В настоящее время мы занимаемся проверкой кода, взятого у другой команды, и сомневаемся в применении SRP и его связи с анемичной или богатой моделью предметной области (по определению Мартина Фаулера). Концепция богатой доменной модели заключается в том, чтобы иметь интеллектуальный объект, который может не только устанавливать / получать свои свойства, но и выполнять более сложную бизнес-логику. Мне интересно, как это вписывается в SRP?
Скажем, у меня есть класс модели, обладающий некоторыми свойствами, которые могут выставлять эти реквизиты и обеспечивать некоторые простые вычисления их свойств. Следующее требование - иметь возможность хранить данные этого объекта в каком-то объекте хранения, который не находится под моим контролем, например:
class MyObject {
// get set
// parse sth
}
Хранить метод в хранилище
storage.store(key, object);
Разве это не нарушает SRP, если MyObject имеет такой метод хранения?
public void store(Storage storage) {
storage.store('keyOne', fieldOne);
storage.store('keyTwo', fieldTwo);
}
С точки зрения этого объекта хорошо бы иметь возможность сохранять его состояние. Другой способ может заключаться в том, чтобы ввести здесь вид сервиса и сделать это так:
public StorageService {
private Storage;
// constructor here
....
public void store(MyObject myobj);
}
Можете ли вы указать мне какие-либо ссылки, которые я могу прочитать об этой проблеме? Я нашел одну тему по SO здесь, но она не отвечает на мой вопрос полностью.
Как это решается в DDD? Модели в DDD по определению богаты и могут рассматриваться как имеющие слишком много обязанностей.
3 ответа
Модель расширенного домена (RDM) означает, что логика, управляющая поведением модели, принадлежит модели, а не обрабатывает модель как данные с помощью методов получения / установки. Это не означает, что все, включая постоянство, безопасность, способ отображения модели в графическом интерфейсе и т. Д., Должно быть внутри модели.
RDM и SRP идут рука об руку, они не конфликтуют друг с другом.
Нарушение SRP/RDM:
Car {
// possibly violates SRP
storeInDatabase();
// smells like anemic domain model
getEngineState();
}
После SRP/RDM:
// usings aspects to remove cross-cutting concerns from the model and follow SRP
@DatabaseSerializable
Car {
// rich domain model encapsulates engine state and exposes behavior
drive();
}
"Модели в DDD по определению богаты и могут рассматриваться как имеющие слишком много обязанностей", - упрощенное толкование DDD. Всегда зависит от того, насколько хороши ваши модели. Вы можете создавать плохие модели, используя DDD (например, создавая объекты со слишком большим количеством ответственности или создавая анемичные модели). DDD и SRP - это тоже две хорошие практики, такие как рефакторинг, TDD и многие другие, но вы должны дополнить их использование своим опытом и суждением (или чьим-либо еще). У всего есть свои плюсы и минусы, не будьте догматичными в применении какой-либо практики.
@Garrett Hall
Я несколько не согласен с вашим утверждением "RDM и SRP идут рука об руку, они не конфликтуют друг с другом". По моему опыту, когда СРП переоценен, это приводит к модели анемичной области."Нет, мы не можем сделать или даже помочь поддержать какое-либо упорство, нет, мы не можем сделать 21-CFR11, нет, мы даже не можем знать, что такое GUI...", и ваш класс в конечном итоге ничего не делает и просто есть анемичная модель предметной области.
И если RDM переоценен (это направление / ошибка, в которую я склонен впадать), то SRP полностью отходит на второй план, и вы в конечном итоге замечаете, что у вашего класса есть сотни методов и явно выполняется слишком много.
Вам нужно найти баланс, счастливую среду, где происходят как RDM, так и SRP. А найти такой баланс сложно, и часто в вашей команде больше интуиции и политики, чем технических навыков или правил.
"Познай себя". Если вы похожи на меня и склонны к чрезмерно сложным занятиям, знайте. И когда вы видите чей-то класс, который выглядит слишком сложным даже для вас, это большой красный флаг. Аналогичным образом, если вы знаете, что вы довольно хардкорный в отношении SRP, и вы видите класс, который выглядит анемичным даже по вашим стандартам, это основной запах кода.
Теперь, немного отвечая на вопрос ОП о Хранилище, я думаю, что многое зависит от того, насколько стабильно, стандартно и абстрактно Хранилище. Если бы Storage был какой-то стандартной абстракцией XML, CSV или RDB, у меня не было бы абсолютно никаких проблем с объектами, знающими, как хранить себя.