Assigns attributes in constructor using Dry::Initializer
It is so common to write constructors and attributes in Ruby like so:
class FormatHeader
include ApplicationService::Config
attr_reader :parsed_content, :skip_frozen_string_literal
def initialize(parsed_content:, skip_frozen_string_literal: false)
@parsed_content = parsed_content
@skip_frozen_string_literal = skip_frozen_string_literal
end
# ...
end
If Ruby is your day-to-day language, such code probably seems too routine for you.
class RunShell
include ApplicationService::Config
attr_reader :command, :debug
def initialize(command:, debug: false)
@command = command
@debug = debug
end
# ...
end
Also, it is so annoying to make accidental typos, when you are already tired, but you still have some stuff to complete.
For example, the word command
is typed 4 times in the example above, so there are 4 opportunities to make an automatic mistake.
Please, don't even tell that your IDE handles that for you.
When the whole team is feeling the same annoyance.
All of the members really believe in the benefits of the removal of such repeatable code.
You may consider to utilizing the Dry::Initializer integration that the AssignsAttributesInConstructor::UsingDryInitalizer plugin provides.
module ApplicationService
module Config
include ConvenientService::Concern
included do |service_class|
service_class.class_exec do
include ConvenientService::Standard::Config
# ...
concerns do
use ConvenientService::Plugins::Common::AssignsAttributesInConstructor::UsingDryInitalizer::Concern
end
end
end
end
end
Thus, FormatHeader
and RunShell
can be reduced in the following way:
class FormatHeader
include ApplicationService::Config
option :parsed_content
option :skip_frozen_string_literal, default: -> { false }
# ...
end
class RunShell
include ApplicationService::Config
option :command
option :debug, default: -> { false }
# ...
end
Dry::Initializer does NOT call super
in its initialize implementation.
If it causes problems for you, try to place AssignsAttributesInConstructor::UsingDryInitalizer closer to the top in the concerns stack.
See insert_before.
Introduce new libraries to the projects only when you have strong arguments and complete ideas about why to do so.
In fast-paced enterprise projects, with a poor onboarding process, simplicity is almost always a better choice.
The simplicity in a sense, that the tech stack should be familiar to the people, who maintain the project for years.
Since you probably won't have a chance to talk with the "one-task" developers while they remember the initial reasoning behind their code.
Moreover, that code is frequently left without any diagrams, documentation, or even tests 😐.