The logic layer: Dry-RB
This course evaluates two Dry-rb libraries against the service objects of a real Rails application. It starts from the Data.define Result objects with a success boolean that most services already use, and names their costs, such as an eight-field failure helper that pads empty values. It then covers Success and Failure from dry-monads, fmap and bind, Do notation, and dry-validation contracts with schemas and rules. It shows how to connect a contract to a service and closes by judging, service by service, whether adoption is worth it.
What you'll learn
- ✓How Success and Failure replace a success boolean with two distinct types
- ✓When to use fmap and when to use bind to chain steps that can fail
- ✓How Do notation keeps a multi-step service flat and stops at the first Failure
- ✓Writing dry-validation contracts with params schemas and rules
- ✓Loading the monads extension so to_monad connects a contract to a service
- ✓Judging, service by service, whether a gem removes a cost the code already has
The Result object this app already has
In September 2026, app/services in this application held 65 Ruby files. Forty-nine of them declare a result type with a line shaped like this one, copied from app/services/auth/authenticate_user_service.rb:
Read the full lesson free →Curriculum
7 lessonsThe Result object this app already has
Surveys the Data.define Result objects in this app and the padding and dead success fields they carry.
Success and Failure as values
Replaces the success boolean with Success and Failure classes, and shows how value! fails loudly on a Failure.
fmap and bind: composing without if
Explains fmap for functions that cannot fail and bind for functions that return their own Result.
Do notation: the flat service object
Uses Do notation so yield unwraps each Success and leaves the method at the first Failure.
Contracts: schema and rules
Builds dry-validation contracts with params schemas and rules, including the rule skipped when the schema fails.
Wiring a contract into a service
Loads the monads extension so to_monad turns a contract result into a first yield inside a service.
Should this app adopt Dry-RB?
Weighs adoption per service, concluding most need nothing new and CompleteLessonService's padding can be fixed without a gem.