Summary
What app components should be in the lib/[app_name]
directory? I propose that the mailers
and repositories
directories be relocated outside of the “core business rules” directory.
Discussion
First, I would like to express how excited I am at the recent progress on Hanami 2. I am stoked at the possibility of using Hanami on a new business project, and I don’t think I will be able to restrain myself from jumping in once 2.1beta1 drops. Thank you all for your excellent work!
Please bear with me in the following discussion. I want to be complete, at the risk of being pedantic–and a lot of this stuff frankly is new to me.
Hanami 1.x App Structure (for context and comparison)
In Hanami 1.x, multiple “apps” could be created in the apps
directory, containing their constituent actions, views, and templates, etc. Meanwhile, the lib
directory in the standard Bookshelf
project, for example, would look like this:
$ tree lib
lib
├── bookshelf
│ ├── entities
│ ├── mailers
│ │ └── templates
│ └── repositories
└── bookshelf.rb
5 directories, 1 file
I recently built a couple of test projects in 1.3.5 to get my feet wet in anticipation of Hanami 2. In this process, it struck me as strange to have mailers and repositories inside the “core business logic” directory. Following the canonical “clean architecture” pattern, I would only expect to see interactors and entities in this directory (or whatever other organizational pattern you choose, thanks to Hanami’s flexibility!).
Hanami 2.0 App Structure
In the Hanami 2.0beta1 announcement, a slightly modified app structure was introduced (although not fully fleshed out). For simplicity, the default “slice” is removed. Instead, the app
directory will directly contain an actions
directory (and presumably views
and templates
), until such time as the app requires further breakdown into slices.
$ tree app
├── app
│ ├── action.rb
│ └── actions
Now, in addition to the bookshelf
directory (continuing this example), the lib
directory will contain tasks
for rake
tasks. No mention is made of the proposed locations for mailers or repositories.
$ tree lib
├── lib
│ ├── bookshelf
│ │ └── types.rb
│ └── tasks
Reasoning & Proposals
My interest in this question follows the logic of “clean architecture,” as described by Robert C. Martin. For me, this pattern is best summarized in the following diagram, taken from one of his talks.
The goal of these boundaries is to isolate the business logic from from all of the ‘implementation’ details. In my mind, mailers and repositories should definitely fall outside of the business logic boundary.
So . . . what to do? I can think of two proposals, but neither seem ideal. The first, is to move mailers
and repositories
to the app
folder, at the same level as actions
(and, later, the various slices). Like so:
$ tree app
├── app
│ ├── action.rb
│ ├── actions
│ ├── mailers
│ └── repositories
The second proposal is to promote mailers
and repositories
within the lib
directory to the same level as bookshelf
and tasks
. Like so:
$ tree lib
├── lib
│ ├── bookshelf
│ │ └── types.rb
│ ├── mailers
│ └── repositories
│ └── tasks
I have to admit that neither of these proposals feels immediately natural or correct to me. I realize that entity
objects are imported from the ROM-RB library, but I don’t think that should dictate the location of the directories. On the other hand, while mailers and repositories are “implementation” details, putting them in app
feels a little weird, especially if the app evolves into slices.
Ideas???
So, I would love to hear what others on the community think about this issue, especially since the app structure for Hanami 2.1 has not been established as of yet. What say you all? I look forward to hearing your thoughts!
Post Script
One of the reasons that I am interested in this question is the influence that DDD has had on my recent thinking. What would it look like to split a Hanami application into “bounded contexts”? I am thinking more along the lines of a “modular monolith,” such as Vaughn Vernon and others describe, than separately deployed microservices.
It seems likely that these bounded contexts might be sheared along different lines than the slices in Hanami 2. That is, I don’t think there will be a 1:1 conceptual correspondence between slices and bounded contexts, since they server fundamentally different purposes.
Where would repositories be placed in such an architecture? I’m skeptical of having them intermingled with the business rules directly, but they are coupled to some extent with their entity objects, and would conceivably be “bundled” into whatever container is created for the various bounded contexts.
For now I am going to focus on Uncle Bob’s clean architecture style (interactors and entities) and hope that Hanami offers me a pathway to a more modular approach by the time that I need it.
Thank you again for all of your wonderful work!