DDD и проверка уникальности в базе

Обсуждаем, как правильно строить приложения
Ответить
archfor
Сообщения: 3
Зарегистрирован: 2017.05.15, 12:28

DDD и проверка уникальности в базе

Сообщение archfor »

Здравствуйте

Задача:
1. Есть сущность "Организация", которая включает в себя "Документы"
2. "Документ" - это файл + мета данные
3. В рамках "Организация" должен быть метод "Добавление документа". Метод добавлять только уникальные для данной организации файлы.
4. Файлы могут быть общего характера. Т.е. в целом документ может легко встречаться в рамках нескольких организаций.
5. Количество файлов на организацию не ограничено. Для конкретных цифр есть 2млн. Часть данных парсится автоматически, документы постоянно добавляются, число растет.
6. В рамках метода добавления документа есть еще действия связанные с самим документом (в примерах они через троеточие)

Реализация с нарушением слоев и всего что можно (просто для показа задачи, если непонятно выше):

Код: Выделить всё

class Company {
    ...
    public function addDocument($document) {
        ...
        if(!$this->documentStorage
                     ->hash($document->md5File())
                     ->companyId($this->getId())
                     ->exists()) {
            ...
            $this->documentStorage->add($document);
            ...
            $this->persist();
        }
        ...
    }
}
Реализация как "хочется"

Код: Выделить всё

class Company {
    ...
    public function addDocument($document) {
        ...
        if(!$this->documentsCollection->exists($document)) {
            ...
            $this->documentSCollection->add($document);
            ...
        }
        ...
    }
}
...
$company->addDocument($document);
$em->persist($company);
...
Проблемы:
Естественно всю коллекцию документов грузить в память нельзя. Там просто падает или memory limit или 30s timeout

Опробованные схемы:
1. Не делать метод добавления документы в рамках "Организация" а сделать его сразу в сервисе или в сервисе + репозиторий, например.
2. Сделать в репозитории отдельно методы add, findByHash, а также трейт,
где метод add будет реализован не выходя за рамки вызова методов, описанных в интерфейсе.
3. При выборке "Организация" из репозитория заменять "Коллекцию документов" на прокси и там обернуть исходный метод addDocument.
4. Отдельно делать часть помеченную тут троеточием в методе addDocument, отдельно делать сохранением в хранилище через репозиторий.

Проблемы схем:
1. Часть правил в сервисах, часть в моделях.
2. При использовании нужно помнить и про интерфейс и про трейт + 1 проблема из 1.
3. Получаем по факту почти тоже самое, что и без соблюдения слоев + требуем реализацию прокси
4. Тоже что и в 1. Можно не вызвать один из методов и либо не сохранить в хранилище, либо не выполнить нужные действия.

Хранилище:
Если вдруг понадобится, то хранилище - это mysql + файловые сервера
Т.е. exists - это упрощенно SELECT * FROM files WHERE content_md5='{$file_md5}' AND company_id={$company_id}
А add - это отправка в API удаленного сервера файла, ожидание успешного ответа, занесение в базу.

Упустил варианты или лучше вообще не так сделал?
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: DDD и проверка уникальности в базе

Сообщение zelenin »

Код: Выделить всё

public function addDocument($document) {
        ...
        if(!$this->uniqueFileValidator->isValid(...)) {            ...
            $this->documentStorage->add($document);
            ...
            $this->persist();
        }
        ...
    }
в домене интерфейс валидатора, в инфраструктуре - реализация через репозиторий, или что там у вас.
archfor
Сообщения: 3
Зарегистрирован: 2017.05.15, 12:28

Re: DDD и проверка уникальности в базе

Сообщение archfor »

Спасибо за ответ.
Обернуть в валидатор да, лучше.
Но, тут же в любом случае получился практически самый первый вариант с прямым использованием хранилища документов?
Или я что-то не понимаю? Т.е. мы в рамках сущности делаем storage->add и persist и в данном случае это нормально?
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: DDD и проверка уникальности в базе

Сообщение zelenin »

а, я неправильно понял вопрос. Ну вынеси все добавление в доменный сервис.
archfor
Сообщения: 3
Зарегистрирован: 2017.05.15, 12:28

Re: DDD и проверка уникальности в базе

Сообщение archfor »

Т.е. что-то вроде такого?

Код: Выделить всё

class AddDocument {
    ...
    public function run(Company $company, Document $document) {
        if($this->uniqueFileValidator->isValid(...)) {
            $this->documentStorage->add($document, function() use ($document) {
                $company->addDocument($document);
            });
        }
    }
    ...
}
Я верно тогда понимаю, что разнесение бизнес логики между сущностью и сервисом - это норма?
И это лучше чем из самой сущности стучаться в хранилище? Или и так тоже норма?

Естественно хранилище, репозитории и т.д. в доменной модели только в виде интерфейсов.
anton_z
Сообщения: 483
Зарегистрирован: 2017.01.15, 15:01

Re: DDD и проверка уникальности в базе

Сообщение anton_z »

И то хорршо и это хорошо, зависимости только правильно заинжектить. Главное о консистентности не забывать. Документ добавился в хранилище, транзакция зафейлилась. Получили бесхозный документ. У вас это разруливается?
Ответить