Чистый микроблог. Обработчик
Итак, у нас есть данные нашего микроблога, мы уже разработали команду для публикации поста и событие, которым мы изменим мир. Настала пора написать обработчик, чем сейчас и займемся.
Для начала надо понять, что значит выполнить команду "Опубликуй пост". Мне кажется, обработчик должен сохранить пост где-то и сообщить миру о том, что "Пост опубликован". И все.
Полагаю, мы хотим хранить где-то посты пользователей - в каком-то абстрактном репозитории.
from abc import ABC, abstractmethod
class AbstractRepository(ABC):
    @abstractmethod
    def save_post(self, post: Post) -> Post:
        "Creates post in repository"
     @abstractmethod
     def __enter__(self):
         "We need to initiate session with our repository"
      @abstractmethod
      def __exit__(self, *args):
          "We need to close our session and rollback uncommited changes"
      @abstractmethod
      def commit(self):
          "We want to commit changes into repository"
      @abstractmethod
      def rollback(self):
          "We want to rollback changes sometimes"
Сразу добавил методов из реального мира. Репозиторий обычно это какой-то движок базы данных, и нам надо открывать-закрывать соединение, запускать транзакции и т.д. Для обучающих целей достаточно было и первого метода, но чтобы никто не говорил "да это не будет работать" - сразу добавил и остальные. Будет.
Кроме того, нам нужна еще какая-то абстракция, которая будет публиковать сообщения. Для обработки нашей команды совершенно неважно где именно.
from abc import ABC, abstractmethod
class AbstractPublisher(ABC):
    @abstractmethod
    def publish(self, message: Message):
        "Publish message somewhere"
Ну и теперь наш обработчик. Он обрабатывает команду, знает о данных, о событии, но не зависит от реализации наших абстракций.
def publish_post_handler(command: PublishPost,
                         repo: AbstractRepository,
                         publisher: AbstractPublisher):
    with repo: 
        post = Post()
        post.id = command.id
        post.text = command.text
        post.customer_id = command.customer_id
        event = PostPublished(**vars(command))
        repo.create_post(post)
        repo.commit()
        publisher.publish(event)
Вот так вот получилось. В контексте репозитория мы создаем из команды пост, подготавливаем итоговое событие, сохраняем пост в репозитории, подтверждаем изменения и публикуем события.
Мне в этом коде непонятен только один момент: почему, когда я предлагаю писать вот так, никто не соглашается?