2014-11-21 4 views
7

Здесь краткое описание моего домена:Как смоделировать систему голосования/подобной системы в проекте DDD/CQRS/EventSourced?

У меня есть статья, которая в основном похожа на любую статью (название, резюме и тело).

Мне нужно разрешить голосование по моим статьям, голоса будут поданы анонимными пользователями (регистрация не требуется, но сессия будет хранить голоса, пожалуйста, не сосредотачивайтесь на этом).

В этом домене Article является моим агрегированным корнем.

я не могу найти способ моделирования мои голоса с учетом следующих требований:

голосования может быть либо мне нравится или не нравится, он должен быть изменяемым (оно может быть изменено в течение долгого времени или даже отменен)

Гость, связанный с сеансом связи, может подавать только один голос за статью.

Итак, должен ли Голосовать быть агрегатом самостоятельно?

что-то вроде

Class Vote { public function cast(ArticleId id, GuestSessionToken token, VoteValue value); }

Но в этом случае, как я должен проверить единственность? Используя Eventual Consistency (кажется, хорошо, потому что у меня нет дубликатов, насколько они редки).

Потому что, если я добавлю метод голосования в свою совокупность статей, мне придется переиздавать историю для каждого голоса, которое будет исполнено, что звучит довольно медленно (учитывая факт, что я могу иметь 100 тысяч голосов за статьи).

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

Любое из вас уже что-то подобное делало раньше?

+0

Я ответил на аналогичный вопрос здесь: http://stackoverflow.com/a/38259448/225022 – Bishoy

ответ

-1

Я бы выделил объект Vote из объекта VoteCast.

VoteCast - это событие, оно может иметь значение Up, Down или Cancel. Существует также объект Vote, который обновляется с VoteCasts.

При расчете голосов вам не нужно воспроизводить трансляции, просто подсчитывайте голоса. Вы можете поместить Голосов в коллекции в статью (вверх, вниз) и просто вернуть счетчик коллекции. VoteCast будет изменять, какая коллекция принадлежит Голосам.

+0

У вас может даже быть «пересчет» для повторного применения VoteCasts к голосам :-) –

7

Голосование - это совокупный корень самостоятельно. Если мы думаем об ассоциациях, «в статье много голосов», то мы применяем реляционный подход, и это заставляет нас склоняться к столь критическому большому совокупному подходу, согласованному сообществом DDD. Вместо этого мы хотим сосредоточиться на поведении. Мы уже знаем, что статья не будет содержать набор голосов. Поскольку для голосования необходим собственный жизненный цикл, он будет иметь свою собственную глобальную идентичность и, следовательно, собственный репозиторий. Статья по мнению пользователей, это хороший подход, чтобы дать семантику нашей модели предметной области, так играть с экспертами в предметной области семантики мы могли бы сказать, «статья голосует пользователь»

anArticle.votedBy(aReader); 

Помните, что пользователь играет роль читателя в этом ограниченном контексте. Метод votedBy является заводским методом, который находится в состоянии создания голосования.Его реализация будет:

Article.votedBy(aReader) { 
    return new Vote(this, aReader); 
} 

Всегда помнить, что в конце голосования будут иметь концептуальные идентификаторы статьи и читатель, продвигая отключенные модели вместо того чтобы держать фактические ссылки на другие совокупные корни. Таким образом, служба домена будет самой читающей. Предположим, что вы смоделировали интерфейс отдыха

RestInterface.voteArticle(articleId) { 
    reader = new Reader(articleRepository); 
    reader.vote(articleId); 
} 

Reader.vote(anArticleId) { 
    article = articleRepository.get(anArticleId); 
    vote = article.votedBy(this); 
    voteRepository.add(vote); 
} 

Вы должны проверить уникальный (убедившись, что пользователь голосует статью только один раз), помещая составленное уникальное ограничение на уровне базы данных. Это наименее навязчивый способ проверить это, иначе вы должны добавить еще одну модель домена, которая модерирует голоса. Возможно, этот новый объект имеет больше смысла, когда создаются различные бизнес-правила голосования, но для того, чтобы убедиться, что читатель голосует только один раз, когда достаточно статьи, и я думаю, что это наиболее упрощенное решение (то есть для размещения ограничения DB). DDD является процессом обучения и, как мы узнаем что-то новое о домене мы понимаем, что пользователь может разорвавшийся или кнопка Больше не нравится на статье, так что мы думаем о рефакторинге, что мы делали до сих пор немного:

Article.likedBy(aReader) { 
    return Vote.positiveByOn(aReader, this); 
} 

Article.dislikedBy(aReader) { 
    return Vote.negativeByOn(aReader, this); 
} 

где обе реализации являются:

class Vote { 

    readerId 
    articleId 
    typeId 

    Vote(aReaderId, anArticleId, aType) { 
    readerId = aReaderId 
    articleId = anArticleId 
    type = aType 
    } 

    public Enum VoteType { POSITIVE, NEGATIVE } 

    Vote static positiveByOn(aReader, anArticle) { 
    return new Vote(aReader.id, anArticle.id, POSITIVE); 
    } 

    Vote static negativeByOn(aReader, anArticle) { 
    return new Vote(aReader.id, anArticle.id, NEGATIVE); 
    } 
} 

Кроме того, так как фабричный метод likedBy/dislikedBy на статьи AR является создание голосов вы можете разместить ограничение говоря статья не может быть признан более чем N раз, или любой другой бизнес-сценария.

Надеется, что это помогает,

Себастьяна.

+0

По ограничению DB вы имеете в виду во время операции сохранения хранилища? А что, если мы не будем использовать базу данных? –