Conversation
17ad6ea to
18a745f
Compare
|
Добрый вечер @f213, @davydovanton. Меня зовут Светлана. Регалась на курсе на email svetlana.temnikova@coinspaid.com. Это дз к первому уроку. Сорри за опоздание. |
|
Привет! все в порядке, я до воскресенья все посмотрю (с большой вероятностью сегодня) |
davydovanton
left a comment
There was a problem hiding this comment.
Привет!
Что бы было проще с неймингом и что бы закрепить различие названий бизнес команд, я описывал что такое бизнес событие в другой домашке, продублирую тут, возможно будет полезно для понимания концепции:
Любое событие - результат выполненного действия. У нас в курсе есть два действия: бизнес логика (команда из ES) и изменение агрегата/ресурса (из этого CUD событие выходит, мол сделали create/update/delete для агрегата/ресурса). Нас интересует бизнес логика в виде команды.
Нам важно описать поведение системы с точки зрения различных пользователей. т.е. описать команды которые могут совершаться пользователями, вместо того, что бы описать, что программа/система должна сделать с технической части. Т.е. мы описываем ожидаемое действие, вместо описания того, как это действие будет выполнено.
Пример тут: закрытие двери. Мы не пишем "приложить силу для разгона двери к стороне противоположной той, что от петель, до состояния когда угол между дверью и стеной составит нуль градусов". Вместо этого, мы пишем "закрыть дверь". С точки зрения software систем, "Create accounting payment log" это такое же описание как и "приложить силу ..."
Если взять пример в виде обычной бутылки для воды (я на разборе его приводил), бизнес логикой будет команда на открытие бутылки, так как мы, как пользователь открываем бутылку. Тут возникает специфика разработки, так как мыслим тем, какую последовательность действия совершить надо, а не то, что делается над нашей системой. В примере с бутылкой, бизнес команда "открыть бутылку" в технической реализации превращается в набор шагов: взять крышку, прокрутить крышку против часовой, убрать крышку. Поэтому важно ловить себя на использовании терминов в духе "провернуть крышку против часовой" и использовать термины которые совершает пользователь над системой "открыть бутылку".
Возвращаясь к бизнес событию, в системе с бутылкой это будет "бутылка открыта", но никак не "крышка взята"/"крышка провернута против часовой стрелки"/"крышка убрана".
Общие вещи, на которые я бы посоветовал обратить внимание:
Технические шаги вместо бизнесовых комманд
Довольно распространненый случай, вместо поведения системы с точки зрения процессов бизнеса (что система делает), описывать технические шаги (как система что-то делает). Об этом выше в примере с открытием бутылки. Примеры которые я нашел в ПР-е
В данном случае, у нас есть бизнесовая команда на добавление задачи в таск трекер. Она состоит из двух технических шагов: сохранить задачу в бд + назначить ей исполнителя. В диаграмме ты указал два технических шага, вместо одной бизнесовой команды
Тут две бизнесовые команды поделились на 5 технических шагов:
- Добавление задачи в таск трекер разбилась на два шага: создание в бд + асайн
- Аплай транзакции на зачисление (зачислить денег) разбилось на три технических шага: запись в аудит таблицу и последующие две каких-то записи связанных с тем, как это работает, а не что происходит
Аналогично и тут, с точки зрения поведения системы мы вызываем команду на закрытие расчетного периода (в нашем случае один день), на результат которой реагирует команда для выплаты денег попугу на карту или куда-либо еще. При этом, нотификация - это часть шага либо выплаты, либо закрытие расчетного периода
А можешь объяснить, зачем эти шаги? Они тоже описывают технические шаги, а не бизнес команду
Бизнес комманда на генерацию цены
В данном случае, мы добавляем задачу в таск трекер (бизнесовая команда). Добавление, с точки зрения бизнеса состоит из нескольких технических шагов. Дальше возникает двойная ситуация:
- Если ты считаешь что цена задачи должна быть в контексте таск трекера и аккаунтинга, то тогда это будет техническим шагом в бизнесовой команде добавлении задачи в таск трекер
- Если ты считаешь, что цена задачи должна быть в только контексте аккаунтинга, то это просто процесс реагирования на стрим события о созданном таске. Т.е. при создании задачи в БД аккаунтинга - ты добавляешь два поля с ценой в таблицу. Т.е. опять же, это не бизнесовая команда
Поэтому логичнее, в любом из случаев, кажется вытащить генерацию на уровень стриминга данных (просто логика на то, как записать задачу в базу данных аккаунтинга). Поэтому в ES ее указывать не стоит. При этом, у тебя аккаунтинг становится овнером информации о цене задачи, поэтому ты можешь стримить изменение цены (CUD события) для цены задачи, которые будут ловиться в системе (например в аккаунтинге).
Работа с деньгами
Я бы предложил попробовать реализацию с событийным биллингом, о которой рассказывал на разборе дз. Основная идея в том, что у тебя каждая опреация с деньгами - это транзакция. Это похоже на то, как работает бансковское приложение, где есть список транзакций, которые формируют баланс. Схемотично выглядит так:
TransactionRepo.new.apply(type: :withdraw, credit: 100, task_id: ..., user_id: ...)
TransactionRepo.new.apply(type: :deposit, debit: 50, task_id: ..., user_id: ...)class TransactionRepo
def apply(payload)
db_transaction do
transactions_table.create(payload)
user = users_table.find(payload[:user_id])
users_table.update(user.id, balance: user.balance + payload[:credit]) # ну или debit в зависимости от транзакции
end
end
endПри этом закрытие билинг цикла это бизнес команда состаящая из нескольких технических шагов:
- в транзакции базы данных поменять статус цикла на закрытый + сделать новую транзакцию на выплату всей сумы (т.е. вычесть всю суму). Таким образом мы обнуляем баланс кошелька и делаем заметку, что все деньги ушли на выплату человеку
- после создании транзакции на выплату запустить процесс выплаты средств, тут детали опускаем, так как уже специфика, которая нам не нужна.
Т.е. вся цепочка может выглядеть как-то так (вариант отличается от разбора дз, это просто возможный вариант реализации):
command CloseBillinCyclePeriud -> event BillingCycleClosed
-> event PayedTransactionApplied -> command PayMoney
Мы отправляем два события из команды на закрытие цикла (можем сделать цепочку из двух команд, тут не принципиально) и потом каждое из событий по своему обрабатываем.





No description provided.