Pull to refresh
0
0
adler @Adler

Solutions Architect

Send message
Мои немецкие коллеги объясняли, что если я еду на велосипеде с работы напрямую домой, то за это отвечает рабочая страховка, если же по пути с работы домой заехал в магазин, то это уже моя страховка. Еще коллеги прикалывались, что рабочая страховка не покрывает травмы, полученные в туалете на работе, то есть идешь в туалет — застрахован, дошел — уже нет :) Или если я спускаюсь по ступенькам дома, чтобы пойти на работу, и поскальзываюсь на последней ступеньке — то это моя страховка, а если уже прошел все ступеньки — то это путь на работу и рабочая страховка.
DDD отчасти диктует более логичную структуру приложения, где бизнес логика находится на по возможности на самых низких слоях. То есть определенный код будет в любом случае присутствовать, вопрос только — где именно.

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

2. Для этого есть Queries, как говорится не репозиторием единым…

3. В таких случаях можно делать определенные методы internal и доступными только сервисам, а методы сервисов, которые проверяют права доступа — доступными извне. Опять же, код тот же, просто немного по-другому структурирован.

5. Я не сильный фанат EntityFramework, но DbContext уже реализует паттерн UnitOfWork и большинство ORM поддерживает TransactionScope. Одна из идей репозитория в DDD, что он сохраняет Aggregation Root, то есть UnitOfWork мало нужен. Для случаев, когда нужно сохранить несколько Aggregation Root, есть Transaction Scope и UnitOfWork тоже мало нужен.

6. Это зло на продакшене, но такие ошибки должны всплывать раньше и на проде такой код теоретически даже не будет вызываться. Это просто способ не думать о том, откуда пришел NullPointer :)
Копипаст — это зло, тут я с вами соглашусь. Есть много методов не копипастить — выносить код можно разными способами, один из которых — то, что вы описали.

В чем я с вами не соглашусь, так это что валидация логики и данных — это разные вещи. Я смотрю на это как на логику домена (тот факт, что возраст может быть между 10 и 120 годами адекватен в рамках данного конкретного домена, но не типа Age в общем).

То, что легко перепутать местами параметры, тут я тоже соглашусь. В последнее время я часто задаю имена параметров явно — это решает проблему и имхо это более прагматичный подход, чем создавать объект каждый раз. Если вы посмотрите на swift, то там это стандартный подход и он нужен для читабельности (первых попавшийся пример из интернета):

repeatThis("swift", andDoItThisManyTimes: 3)


И сложно согласиться с аргументом по поводу Value Object — я привел цитату Eric Evans из первоисточника по DDD. Что в этой цитате наводит вас на сделанные выводы о поведении Value Object, кроме названия?
То же самое спокойно реализуется таким образом:
public class Person
{
    public Person(string name, int age)
    {
        SetName(name);
        SetAge(age);
    }

    public int Id { get; private set; }
    public string Name { get; private set; }
    public int Age { get; private set; }

    public bool SetName(string newName)
    {
        // validation rules here
    }

    public bool SetAge(int newAge)
    {
        // validation rules here
    }
}


При работе с ORM можно добавить конструктор «protected Person()», поменять private на protected, добавить virtual, и т.д. Это уже выбор между прагматичностью и «идеальной» архитектурой.

И насчет ValueObjects, я не знаю, откуда взято то, что они immutable. Идем к первоисточникам (Domain Driven Design by Eric Evans):

An object that represents a descriptive aspect of the domain with no conceptual identity is called a VALUE OBJECT. VALUE OBJECTS are instantiated to represent elements of the design that we care about only for what they are, not who or which they are.


И хороший пример, который показывает, что все зависит от контекста приложения:

Is “Address” a VALUE OBJECT? Who's Asking?
  • In software for a mail-order company, an address is needed to confirm the credit card, and to address the parcel. But if a roommate also orders from the same company, it is not important to realize they are in the same location. Address is a VALUE OBJECT.
  • In software for the postal service, intended to organize delivery routes, the country could be formed into a hierarchy of regions, cities, postal zones, and blocks, terminating in individual addresses. These address objects would derive their zip code from their parent in the hierarchy, and if the postal service decided to reassign postal zones, all the addresses within would go along for the ride. Here, Address is an ENTITY.
  • In software for an electric utility company, an address corresponds to a destination for the company's lines and service. If roommates each called to order electrical service, the company would need to realize it. Address is an ENTITY. Alternatively, the model could associate utility service with a “dwelling,” an ENTITY with an attribute of address. Then Address would be a VALUE OBJECT.

спасибо, именно это. для ссылочного типа нужно дописать ограничение:

public void Save<T>(T argObject)
    where T : class
{
  var collection = db.GetCollection<T>();
  collection.Save(argObject);
}
… съелось. хотел написать

public void Save<T>(T obj)...
Идея, конечно, интересная, но разве не проще сделать следующие сигнатуры?

Database… public void Save(T obj) { db.GetCollection… }

и вызов

new Database().Save(myObj), где тип определяется без всякой магии

Information

Rating
Does not participate
Location
München, Bayern, Германия
Date of birth
Registered
Activity