Skip to content

Instantly share code, notes, and snippets.

@replaid
Last active March 23, 2023 02:19
Show Gist options
  • Save replaid/e4ea69c1707b30b2d426 to your computer and use it in GitHub Desktop.
Save replaid/e4ea69c1707b30b2d426 to your computer and use it in GitHub Desktop.
A Rails directory tree that expresses DDD layers and bounded contexts.
components/
my_bounded_context/
app/
presentation/ # This is called the "UI" layer in DDD literature, but it is also
# where things like JSON interfaces live -- any kind of presentation
# or handshake to anything outside. So "presentation" rather than "ui".
assets/
helpers/
mailers/
views/
operation/ # Would be named "application" if we weren't already in an "app" directory
controllers/
listeners/ # Wisper plumbing. These should traffic in Domain Events.
services/ # Application services, as distinct from domain services.
# http://gorodinski.com/blog/2012/04/14/services-in-domain-driven-design-ddd/
workers/ # Thin Sidekiq shells that delegate to domain services.
domain/
my_bounded_context/
my_first_aggregate/
repository.rb
my_first_aggregate_root_entity_name.rb
another_entity_in_this_aggregate.rb
an_event_about_this_stuff.rb
value_object_only_in_this_aggregate.rb
a_relevant_factory.rb
a_relevant_service.rb
another_aggregate/
repository.rb
another_aggregate_root_entity_name.rb
second_entity_in_this_other_aggregate.rb
another_event.rb
a_domain_topic_that_is_not_an_aggregate/
a_service_here.rb
perhaps_an_event.rb
and_a_value_object.rb
infrastructure/
persistence/ # ActiveRecords
# This will frequently get broken out as its own component
# that depends on the domain.
my_bounded_context/
whatever_record.rb
whatever_record_repository.rb # gets registered as the provider for the domain repository
# TODO what else in infrastructure? I'm not clear on how anything other than persistence is
# distinguished from application ("operations") logic.
# Perhaps simply promote persistence a level instead?
@replaid
Copy link
Author

replaid commented Mar 21, 2015

@jdickey Many thanks for all of this! I'll definitely check out Trailblazer and Growing Rails Applications in Practice.

I've seen you describing CBRA difficulties in Gitter, too, but am not clear on what specific issues you've encountered with it. I'm using it with a client and it has been working as advertised; both the client and I are pretty enthused so far. I'd be grateful for any details you'd be willing to share. What makes an unbuilt dependency for smaller gems a dead end?

My tree is intended to be a little unrealistic. Its purpose is a sketch pad to rough out a whole set of ideas I have around guiding the organization of the code. There are lots of ideas embedded in here, but the immediate problem I'm solving for is that as I try ideas on for size I might create something called a FooForm or a FooListener or what have you. This client's impulse (as primary developer of the code base) is to go in and arrange that single file into a brand new app/forms or app/listeners directory. I am wanting to illustrate ways to make organizing by concept closer to the first order of organization, with other organization secondary to that. CBRA components are allowing us to realize Bounded Context boundaries in the organization of the code. By introducing the layers of Layered Architecture as the next level of organization, I feel that Ruby modules can serve as DDD Modules and we arrive at an organization that is both logical and useful.

Answering your question #1: code that is shared between aggregates/operations can itself be a peer with those aggregates/operations, or another component—again, interested in what challenges you've found with that approach.

To your question #2: I intend for the domain and infrastructure directories to get promoted to their own components or gems (that lack operation and presentation directories) quite early in the process, much as Ben Smith describes in his CBRA talk. I have trouble imagining such a major transition with anything but the domain surviving—and I envision everything that would be independent of Rails vs. e.g. RubyMotion being modeled somehow in the domain. No?

Yes, I'm pretty solidly in the Uncle Bob school. The challenge I face is finding the best fit for communicating through code to others. Rails provides a hammer and all problems look like nails when looking at the setup it provides. I'm trying to bring the richer DDD etc. concepts to the forefront in the structure of the tree.

@jdickey
Copy link

jdickey commented Mar 21, 2015

@replaid Rails provides a 20kg sledgehammer and we're etching glass. A very neat trick when you can pull that off more than once. The tools, however, do not tilt the odds in your favour. One of my favourite quotes from Nick Sutterer's Trailblazer book is

For every Rails project, there is exactly two outcomes. Either someone in the team’s an experienced architect and leads the software to an advanced design with service layer, view components, maybe forms, and so on. Or, and that’s the classy way, the project strictly follows the Rails Way and will end up as a code disaster.

Having and heeding an architect is no guarantee of avoidance of disaster, but the converse is as reliably true as death and taxes. Or, as I've been putting it half a dozen times over the last two years, when your architect/lead developer/chief engineer puts double-digit percentages of her or his effort into mitigating Rails, let alone my current more than half, you have an existential threat to the success of your project, wrapped beautifully in what you've sold yourself and your other stakeholders as the solution to your project.

I don't think we're in Kansas anymore, Toto. The sky is falling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment