What app components should be in the
lib/[app_name] directory? I propose that the
repositories directories be relocated outside of the “core business rules” directory.
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.
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!).
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
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
rake tasks. No mention is made of the proposed locations for mailers or repositories.
$ tree lib ├── lib │ ├── bookshelf │ │ └── types.rb │ └── tasks
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
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
repositories within the
lib directory to the same level as
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.
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!
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!