slashdotdash / conduit

RealWorld example backend implementing the CQRS/ES pattern in Elixir and Phoenix
MIT License
353 stars 67 forks source link

Gratitude and questions #3

Closed kokjinsam closed 7 years ago

kokjinsam commented 7 years ago

Hello Ben, I just wanna thank you for putting this repo up. As a beginner in Elixir and ES, it has been tremendously useful for me. I will soon start a new project based on what I learned from this repo and can't wait to buy your book when it's done!

Questions

  1. Do you think that it's a good idea to have modules folder for aggregates, etc and schema folder for Ecto schema?
/conduit
  /modules      <----------- new
    /accounts
      /aggregates
      /commands
      /events
      /projectors
      /queries
      /validators
      /schema     <----------- new
      accounts.ex
      notifications.ex
      supervisor.ex
    /auth
    /blog
  /validation
  1. How would you do cross context validation? For example, I have Users and Players contexts. I want to make sure that User exists when inserting a new Player. Based on my readings, I should create a workflow that listens to events from Users context and calls register_player in Players context. But what if I need to call register_player independently without listening to events? One thing that I thought of doing was to create a global Vex validator to validate the existence of a user. However, that doesn't feel right as Players context is now depending on Users context.

  2. Would you recommend mixing non-ES stuffs (such as CRUD only APIs, etc.) within context?

  3. Would it be possible to an example of using Process Manager?

Once again, thank you very much for this repo!

slashdotdash commented 7 years ago

@sammkj Thanks for the feedback, glad to hear you're finding it useful.

Do you think that it's a good idea to have modules folder for aggregates, etc and schema folder for Ecto schema?

I'm not sure you need the modules folder, instead I would probably either move validation into a conduit_support folder up one level, or separated out into it's own library (as it's supporting code for the app, rather than domain specific functionality). I'm considering making this change to the project, but it means going back and rewriting the corresponding sections in the book!

Then the folders inside lib/conduit are all your contexts. Here's a possible folder structure:

Using a folder for all of the schemas within each context is a good idea. I've considered using that approach too, but decided to keep all of the public modules within the context root. The trade off with that decision is the increased clutter. Keeping schema modules inside their own folder alleviates that.

How would you do cross context validation?

As long as you use the public API of your context there's no problem with accessing one context inside a validator from another context. You can do cross context validation this way. The rationale is that any public function exposed by the context module is for external consumption by: a Phoenix controller, an iex console session, or another context.

You can write a validator for your register player command in the Platers context that calls the User context (e.g. Users.get_user) to verify a user exists.

Would you recommend mixing non-ES stuffs (such as CRUD only APIs, etc.) within context?

No, I'd use only one approach (CQRS/ES or CRUD style) within a single context, but not both. It's reasonable to use CRUD for non-core domains (contexts), such as user authentication and registration, and only apply domain-driven design to your core business domains in an app. I wouldn't mix the two styles in a single context.

Would it be possible to an example of using Process Manager?

I plan to include at least on process manager in this example app. Otherwise there is a very basic process manager in the test domain for Commanded: TransferMoneyProcessManager