I actually wonder why is that needed? With HANAMI_ENV set, settings will load .env
and then .env.#{env_name}
if present. This means that default settings will be overridden by env-specific settings.
but what if we want to change more than just .env
based settings, like insert additional middlewares etc?
@solnic What @parndt said: there is more than just settings based configurations that you may want to apply.
I think this speaks to the importance of finding the right terminology to clearly separate app settings (the user-defined settings loaded from .env*
files) from app configuration (the framework defined settings for controlling its built-in behaviours).
In fact, you can actually use the former to configure the latter, e.g.
module MyApp
class Application < Hamami::Application
# In this context:
# - `settings` are the app _settings_ (user-defined)
# - `config` is the app _configuration_ (framework-defined)
config.sessions = :cookie, {
key: "my_app.session",
secret: settings.session_secret,
#### ^ App setting being used as an app configuration value!
expire_after: 60*60*24*365
}
Am definitely open to ideas from the community about clarifying the naming here.
@parndt @jodosha OK I still want to challenge this but I donβt consider it to be important for 2.0.0 final
I think itβs gonna boil down to clear documentation. Itβs in-line with dry-configurable terminology too, so at least thereβs that. Settings
as a concept doesnβt exist in Rails though so folks coming from Rails might be confused
I disagree here, the benefits are greater than the effort to make this to work.
def environment(env, hanami_env: Hanami.env)
yield if env == hanami_env
end
module MyApp
class Application < Hanami::Application
config.environment(:production) do
config.use(ExceptionTrackerRackMiddleware)
end
end
end
@solnic Youβre right - but some gems could not for example provide in-memory adapters for testing. In that case, it could make sense to skip the configuration at all.
But on the other hand, I can just have a dedicated logging file and keep the configuration simple.
Also rename the CsrfProtection => CSRFProtection - with zeitwerk configured so it recognizes classes named this way.
Letβs Unify folders:
slices/main/lib/main/views
slices/main/lib/main/view
Into single:
slices/main/lib/main/views
It would be much more clean to have: Views::Base,
Views::Show
. For me it seems confusing a bit to have two identical folders next to each other, one in singular one i plural, but both responsible for the same building block of the system
Flatten slices structure:
Current:
β‘ tree slices/main
slices/main
βββ assets
β βββ public
β βββ entry.js
β βββ index.css
β βββ index.js
βββ lib
β βββ main
β βββ action.rb
β βββ actions
β β βββ home
β β βββ show.rb
β βββ entities
β βββ entities.rb
β βββ repository.rb
β βββ view
β β βββ base.rb
β β βββ parts
β β βββ parts.rb
β βββ views
β βββ home
β βββ show.rb
βββ web
βββ templates
βββ home
β βββ show.html.slim
βββ layouts
βββ application.html.slim
15 directories, 12 files
Proposed:
β‘ tree slices/main
slices/main
βββ action.rb
βββ actions
β βββ home
β βββ show.rb
βββ assets
β βββ javascripts
β β βββ entry.js
β β βββ index.js
β βββ stylesheets
β βββ index.css
βββ entities
βββ entity.rb
βββ lib
βββ repository.rb
βββ templates
β βββ home
β β βββ show.html.slim
β βββ layouts
β βββ application.html.slim
βββ view.rb
βββ views
βββ home
β βββ show.rb
βββ parts
βββ parts.rb
13 directories, 12 files
Suggested changes:
- Remove
slices/main/lib/main
, as itβs redundant IMO - Keep
slices/main/lib
(with.gitkeep
) for custom logic. - Move at the root of the slice the default base types:
action.rb
,entity.rb
,repository.rb
,view.rb
(e.g.slices/main/action.rb
to defineMain::Action
). - Move at the root of the slice the corresponding directories:
actions
,entities
,repositories
,views
. - Remove
slices/main/web
. - Move templates under
slices/main/templates
- Move view parts under
slices/main/views/parts
andslices/main/views/part.rb
for the base part. - BONUS: create
slices/assets/{javascripts/stylesheets}
and removeslices/assets/public
@solnic Iβm not sure itβs the right change.
Struct
Definition by Ruby doc:
A Struct is a convenient way to bundle a number of attributes together, using accessor methods [β¦]
Definition by Wikipedia:
A struct in the C programming language (and many derivatives) is a composite data type (or record) declaration that defines a physically grouped list of variables under one name in a block of memory, allowing the different variables to be accessed via a single pointer or by the struct declared name which returns the same address. The struct data type can contain other data types so is used for mixed-data-type records such as a hard-drive directory entry (file length, name, extension, physical address, etc.), or other mixed-type records (name, address, telephone, balance, etc.).
Definition by TechTerms:
A struct (short for structure) is a data type available in C programming languages, such as C, C++, and C#. It is a user-defined data type that can store multiple related items. A struct variable is similar to a database record since it may contain multiple data types related to a single entity.
[emphasis is mine]
Struct is a data (struct)ure.
Entity
Definition by The Java EE 5 Tutorial:
An entity is a lightweight persistence domain object. Typically an entity represents a table in a relational database, and each entity instance corresponds to a row in that table. The primary programming artifact of an entity is the entity class, although entities can use helper classes.
The persistent state of an entity is represented either through persistent fields or persistent properties. These fields or properties use object/relational mapping annotations to map the entities and entity relationships to the relational data in the underlying data store.
Definition by Wikipedia DDD article (which is taken from the book):
An object that is not defined by its attributes, but rather by a thread of continuity and its identity.
Definition by DDD Book (pp. 91):
An object defined primarly by its identity is called an ENTITY.
[emphasis not mine]
Entity is a data structure that represents a database row and has the concept of identity (database primary key).
How this applies to Hanami?
We have repositories that expose database operations. Each of those operations accept data as input and return an object as output.
For bulk operations (e.g. read with filtering), we return a collection of those objects.
Each object represents a database table row (or database document). Each object has the identity semantic (the database primary key).
IMO we should call these objects Entities.
Thanks for all the links, itβs very helpful to have such context. I think this deserves a completely separate thread though. Long story-short is that it is not true that these objects are always identified by a primary key. This makes me think that in rom 6.0 we should introduce a dedicated class that represents such a concept because a result of users.by_pk(5).one
is different than user.by_pk(5).select(:name, :email).one
- the latter returns an instance of a different class (unlike AR).
This is a pretty fundamental difference and something that the docs should explain clearly.
I still think βstructsβ is a better name, itβs more flexible. βEntitiesβ word comes with too much baggage and various assumptions, the PK/identity being the biggest one. This all can be configurable but it would be good to come up with defaults that we can all agree to.
What are you thinking for Hanami::Operation
? I like the name
Would it be built on dry-transaction
, or dry-monad
, or Hanami::Interactor
? (Maybe renaming dry-transaction
, since thereβs overlap with dry-monad
's Do
notation, could work). For reference: Plans for 1.0.0 Β· Issue #127 Β· dry-rb/dry-transaction Β· GitHub
It seems I re-implemented it in for Hanami 2 a couple of years ago.
@cllns I was just thinking to take the code from the app template and move it into hanami
.
I had a look at dry-system
and hanami
, itβs much easier to expose a method Hanami.shutdown
to be used in Puma before_fork
.
# config/puma.rb
before_fork do
Hanami.shutdown
end
The implementation should hook into Dry::System::Container#shutdown!
which iterates for each registered bootable component and triggers the stop
block.