DDD - как бороться с логи "получить или создать" c на уровне приложений? - PullRequest
1 голос
/ 02 марта 2020

У меня есть DailyReport сущность в моем доменном слое. В этом объекте есть несколько полей:

  • reportId
  • userId
  • date
  • tasks - Коллекция вещи, которые пользователь делал в данный день;
  • mood - как пользователь себя чувствовал в течение всего дня;

Кроме того, в моей службе приложений есть несколько методов:

  • DailyReportService::addTaskToDailyReport
  • DailyReportService::setUserMoodInDailyReport

Дело в том, что оба эти метода требуют, чтобы DailyReport было создано ранее или создано во время выполнения функции. Как справиться с этой ситуацией?

Я нашел 2 решения:

1 Создайте новый объект DailyReport перед отправкой метода и после этого передайте им reportId:

//PHP, simplified
public function __invoke() {
    $taskData = getTaskData();

    /** @var $dailyReport DailyReport|null **/
    $dailyReport = $dailyReportRepository->getOneByDateAndUser('1234-12-12', $user);

    //there were no report created today, create new one
    if($dailyReport === null) {
        $dailyReport = new DailyReport('1234-12-12', $user);
        $dailyReportRepository->store($dailyReport);
    }

    $result = $dailyReportService->addTaskToDailyReport($taskData, $dailyReport->reportId);

    //[...]

}

Для этого требуется добавить больше бизнес логи c на мой контроллер, чего я хочу избежать.


2 : проверить в методе что DailyReport существует, и создайте новый, если необходимо:

//my controller method
public function __invoke() {
    $taskData = getTaskData();
    $result = $dailyReportService->addTaskToDailyReport($taskData, '1234-12-12', $user);

    //[...]
}


//in my service:

public function addTaskToDailyReport($taskData, $date, $user) {

    //Ensure that daily report for given day and user exists:
    /** @var $dailyReport DailyReport|null **/
    $dailyReport = $dailyReportRepository->getOneByDateAndUser();

    //there were no report created today, create new one
    if($dailyReport === null) {
        $dailyReport = new DailyReport($date, $user);
        $dailyReportRepository->store($dailyReport);
    }

    //perform rest of domain logic here
}

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


Может быть, этот пример больше CRUD-i sh, чем DDD, но я хотел показать один из моих вариантов использования более простым способом.

Какое решение следует использовать, когда в этом случае? Есть ли лучший способ обработать логи get-or-create c в DDD?


EDIT 2020-03-05 16:21:

a 3 пример, это то, о чем я говорю в своем первом комментарии к Savvas Ответ:


//a method that listens to new requests 
public function onKernelRequest() {
    //assume that user is logged in

    $dailyReportService->ensureThereIsAUserReportForGivenDay(
        $userObject,
        $currentDateObject
    );
}


// in my dailyReportService:
public function ensureThereIsAUserReportForGivenDay($user, $date) {
    $report = getReportFromDB();

    if($report === null) {
        $report = createNewReport();
        storeNewReport();
    }


    return $report;
}



//in my controllers 
public function __invoke() {

    $taskData = getTaskData();

    //addTaskToDailyReport() only adds the data to summary, does not creates a new one
    $result = $dailyReportService->addTaskToDailyReport($taskData, '1234-12-12', $user);

    //[...]
}

Это будет выполнено только тогда, когда пользователь войдет в первый раз / пользователь вошел в систему вчера но это его первая просьба в новый день. В моей бизнес-логике будет меньше сложности c, мне не нужно постоянно проверять службы / контроллеры, если есть отчет, созданный, потому что он был выполнен ранее в тот же день.

1 Ответ

2 голосов
/ 02 марта 2020

Я не уверен, что этот ответ вы хотите услышать, но в основном я думаю, что вы сталкиваетесь со случайной сложностью и пытаетесь решить не ту проблему.

Прежде чем продолжить, я 'd настоятельно предлагает вам рассмотреть следующие вопросы:

  1. Что произойдет, если кто-то представит один и тот же отчет дважды
  2. Что произойдет, если кто-то представит отчет два раза , но во втором он немного отличается?
  3. Каково влияние фактического хранения одного и того же отчета от одного и того же человека дважды?

Ответы на вышеуказанные вопросы должны помочь ваше решение.

ВАЖНО : Кроме того, обратите внимание, что оба приведенных выше метода имеют небольшое окно, в котором два одновременных запроса на сохранение повторного отчета будут выполнены успешно.

От личного Опыт, который я хотел бы предложить:

  1. Если наличие дубликатов не является большой проблемой (например, у вас может быть скрипт, который вы запускаете вручную или автоматизировать Как правило, это удаляет дубликаты), затем следуйте вашему варианту 1. Это не так уж и плохо, и ошибки человеческого масштаба должны работать хорошо.
  2. Если дубликаты представляют собой проблему, запустите процесс, который выполняется асинхронно после Отчеты отправляются, и пытается найти дубликаты. Затем разберитесь с ними в соответствии с тем, как хотят эксперты вашего домена (например, возможно, удаляются дубликаты, если один из них более новый, либо удаляется старый, либо помечается для человеческого решения)
  3. Если это является частью ограничения уровня инварианта в бизнесе (хотя я очень сомневаюсь, учитывая, что мы говорим об отчетах), и в любой момент времени если когда-либо будет два отчета, тогда должна быть совокупность на месте, чтобы обеспечить это. Может быть, это UserMonthlyReport или что-то еще, и вы можете применить это во время выполнения. Конечно, это более сложно и потенциально намного больше работы, но если для инварианта есть экономическое обоснование, то это то, что вы должны сделать. (опять же, я сомневаюсь, что это необходимо для отчетов, но я пишу это здесь, в отчетах по уходу были использованы в качестве примера или для будущих читателей).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...