dgamidov
Domain Driven Design diagram for Umbrella app
Hi all!
I am working on umbrella app now - 4 apps in it.
Being impressed with Controller Control: Designing Domains for Web Applications - Gary Rennie and Episode @057: Educating in Elixir with Dave Thomas @pragdave I have started to think about my application design.
I have started to learn these books:
Martin Fowler - Patterns of Enterprise Application Architecture
InfoQ: Domain Driven Design Quickly
Also, @Gazler recommended:
ElixirConf 2016 - Building Umbrella Project by Wojtek Mach and
github:acme_bank by @wojtekmach
Based on it, I have made a diagram:
How can I improve it?
Most Liked
hlx
I’m trying out the following structure
umbrella
├── core (Elixir)
├── web (Phoenix)
└── api (GraphQL)
├── config
│ ├── config.exs
│ ├── dev.exs
│ ├── prod.exs
│ └── test.exs
├── lib
│ ├── core
│ │ ├── checkout
│ │ │ ├── (...)
│ │ ├── account
│ │ │ ├── authorizers
│ │ │ │ ├── organization_authorizer.ex
│ │ │ │ ├── sales_channel_authorizer.ex
│ │ │ │ ├── shop_authorizer.ex
│ │ │ │ └── user_authorizer.ex
│ │ │ ├── models
│ │ │ │ ├── domain.ex
│ │ │ │ ├── organization.ex
│ │ │ │ ├── sales_channel.ex
│ │ │ │ ├── shop.ex
│ │ │ │ ├── tax_setting.ex
│ │ │ │ ├── theme.ex
│ │ │ │ └── user.ex
│ │ │ ├── repositories
│ │ │ │ ├── organization_repository.ex
│ │ │ │ ├── sales_channel_repository.ex
│ │ │ │ ├── shop_repository.ex
│ │ │ │ ├── theme_repository.ex
│ │ │ │ └── user_repository.ex
│ │ │ ├── organization_service.ex
│ │ │ ├── sales_channel_service.ex
│ │ │ ├── shop_service.ex
│ │ │ ├── theme_service.ex
│ │ │ └── user_service.ex
│ │ ├── inventory
│ │ │ ├── authorizers
│ │ │ │ ├── collection_authorizer.ex
│ │ │ │ ├── permalink_authorizer.ex
│ │ │ │ ├── variant_authorizer.ex
│ │ │ │ └── product_authorizer.ex
│ │ │ ├── models
│ │ │ │ ├── collection.ex
│ │ │ │ ├── image.ex
│ │ │ │ ├── permalink.ex
│ │ │ │ ├── price.ex
│ │ │ │ ├── product.ex
│ │ │ │ ├── stock.ex
│ │ │ │ └── variant.ex
│ │ │ ├── repositories
│ │ │ │ ├── collection_repository.ex
│ │ │ │ ├── permalink_repository.ex
│ │ │ │ ├── variant_repository.ex
│ │ │ │ └── product_repository.ex
│ │ │ ├── uploaders
│ │ │ │ └── image_uploader.ex
│ │ │ ├── collection_service.ex
│ │ │ │── permalink_service.ex
│ │ │ │── variant_service.ex
│ │ │ └── product_service.ex
│ │ ├── relation
│ │ │ └── models
│ │ │ ├── collection_permalink.ex
│ │ │ ├── product_collection.ex
│ │ │ ├── product_image.ex
│ │ │ ├── product_permalink.ex
│ │ │ ├── product_price.ex
│ │ │ ├── product_shop.ex
│ │ │ ├── product_stock.ex
│ │ │ ├── shop_organization.ex
│ │ │ ├── user_organization.ex
│ │ │ ├── variant_image.ex
│ │ │ ├── variant_permalink.ex
│ │ │ ├── variant_price.ex
│ │ │ └── variant_stock.ex
│ │ ├── application.ex
│ │ ├── authorizer.ex
│ │ ├── definitions.ex
│ │ └── repo.ex
│ └── core.ex
├── priv
│ └── repo
│ ├── migrations
│ │ ├── (...)
│ └── seeds.exs
├── test
│ └── (...)
├── README.md
└── mix.exs
In web and api I use the core package like:
{:ok, shop} = MyApp.Core.Account.ShopService.get(1)
{:ok, shop} = MyApp.Core.Account.ShopService.update(shop, params)
defmodule MyApp.Core.Account.ShopService do
alias MyApp.Core.Account.{ShopAuthorizer,ShopRepository,Shop}
def update(%Shop{} = shop, params) when is_map(params) do
with :ok <- ShopAuthorizer.authorize(:update, shop),
do: ShopRepository.update(shop, params)
end
end
peerreynders
Pardon my ignorance but is there a technical reason for for adopting this type of organization:
inventory
├── authorizers
│ ├── collection_authorizer.ex
│ ├── permalink_authorizer.ex
│ ├── variant_authorizer.ex
│ └── product_authorizer.ex
├── models
│ ├── collection.ex
│ ├── image.ex
│ ├── permalink.ex
│ ├── price.ex
│ ├── product.ex
│ ├── stock.ex
│ └── variant.ex
├── repositories
│ ├── collection_repository.ex
│ ├── permalink_repository.ex
│ ├── variant_repository.ex
│ └── product_repository.ex
├── uploaders
│ └── image_uploader.ex
├── collection_service.ex
│── permalink_service.ex
│── variant_service.ex
└── product_service.ex
rather than something like this
inventory
├── collection_service
│ ├── collection.ex
│ ├── collection_authorizer.ex
│ ├── collection_repository.ex
│ └── collection_service.ex
│── permalink_service
│ ├── permalink.ex
│ ├── permalink_authorizer.ex
│ ├── variant_repository.ex
│ └── permalink_service.ex
│── variant_service
│ ├── variant.ex
│ ├── variant_authorizer.ex
│ ├── variant_repository.ex
│ └── variant_service.ex
└── product_service
├── product.ex
├── product_authorizer.ex
├── product_repository.ex
└── product_service.ex
Seems the organizing principle is to put “like” things into the same place rather than “putting everything to deal with subject area X” into the same place. One of the starting points described by the article that I linked to earlier - Bring clarity to your monolith with Bounded Contexts - is to “Invert folder structures into a flat domain-oriented grouping”.
The organizing principle of “putting like things into the same place” that ultimately is responsible for “a Rails app always looking like a Rails app” (and not communicating the actual intent behind the web app) is what inspired Architecture: The Lost Years (Ruby Midwest 2011 Keynote). That type of organization is rarely helpful in revealing the emerging (context) boundaries as the application matures (Evans, DDD p.48: “…crucial discoveries always emerge during the design/implementation effort”).
FYI: for anyone interested: Eric Evans: DDD Reference (PDF 2011)
kelvinst
Well, I have a very close setup to yours, the only difference is the “infrastructure layer” you have and I don’t. In my case, the plugs stay on the application layer (because they have web specific logic, like session control and etc), and the service and the repo go to the domain layer, which does not have any kind of web logic, just business logic.
I’m happy with my structure for now, and it’s a pretty clear separation of concerns. My next step, I guess, is to separate the domain layer in more pieces, by resources and features and not by a specific layer itself. Something I learned with CBRA (Component Based Rails Applications) your application is a big box, and big boxes tend to become a mess if you don’t separate into mor boxes, and label them correctly.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









