Dry-rb

http://dry-rb.org

Saw a post about dry-rb on reddit. I’ll admit that my first reaction was to roll my eyes. It reminded me a lot of the “containers everywhere” approach that was popular when I was a java developer. This is totally unfair of me, so I’m curious what others think.

Are some of you already using these gems? What problems do they help you solve?

dry-validation

Powerful data validation based on predicate logic

dry-types

Flexible type system with many built-in types

dry-transaction

Business transaction DSL

dry-container

Simple and thread-safe IoC container

dry-auto_inject

Container-agnostic constructor injection mixin

dry-equalizer

Simple mixing providing equality methods

dry-component

Organize your code into reusable components

dry-configurable

Thread-safe configuration mixin

1 Like

I’m with you. I have unfair feelings towards it.

1 Like

I don’t use any of those gems…

Hi kofno,

Thank you for taking an interest in dry-rb.

I think your point regarding “containers everywhere” applies specifically to dry-container. I created dry-container in an attempt to make dependency injection easier to use in Ruby. From what I’ve seen in Ruby, people seem to promote good practices such as code to an interface (in the form of duck-typing), favour composition over inheritance etc. But judging by the Ruby code that I’ve seen, those practices seem to be ignored when it comes to implementation for the sake of aesthetics of code, for example:

class CreateUserCommand
  include UserValidator

  attr_reader :repository

  def initialize(repository = UserRepository.new)
    @repository = repository
  end

  def call(user)
    repository.create(user) if validate(user)
  end
end

Obviously things are done this way because passing four(insert number here) different dependencies to #initialize would make the class awkward to use, so instead we hard-code the dependency and/or widen the interface of the object with inheritance (whether it be direct inheritance or module inclusion), however, using a container we can configure this behaviour before-hand:

class Container
  extend Dry::Container

  namespace('user') do
    register('validator') { UserValidator.new }
    register('repository') { UserRepository.new }
  end
end

Injector = Dry::AutoInject(Container)

class CreateUserCommand
  include Injector['user.validator', 'user.repository']

  def call(user)
    repository.call(user) if validator.call(user).errors.empty?
  end
end

This allows us to keep our interfaces narrow and stick to SRP without hard-coding dependencies or littering our codebase with four argument intializer calls.

With regards to some of the other gems, dry-types was developed due to the lack of an existing general purpose coercion library, for example, Piotr Solnica created another coercion library called Virtus, however, it is specifically geared towards coercing object attributes, is included as a module - so an object is coerced when it is initialized and it is quite slow in comparison to dry-types.

dry-validation (also created by Piotr) was created for much the same reason, as we know there are existing validation libraries out there, but from what I’ve seen, they seem to again be geared towards validating objects, are used as mixins - meaning that an object is responsible for validating itself, and they all lack a concise DSL.

dry-rb has very different philosophies to many existing libraries in the Ruby ecosystem, we try to minimise global namespace pollution (very little is introduced into the global namespace besides the Dry module), avoid mutable state where possible - and make use of mutexes appropriately where not, compose our applications of small, dedicated objects that concentrate on performing one task and doing it well and minimise coupling.

Further reading:

4 Likes

@AMHOL
Thanks for your comment
I a a bit interested in using dry-types & dry-validation for my forms (validate / filter input)
Are those 2 gems enough?
I am not using any form gem.

1 Like

Hi PikachuEXE,

Yeah, those two are definitely enough, in fact using dry-validation’s Dry::Validation.Form will automatically infer types from your validation rules and use dry-data’s form coercions to coerce the data for you.

This is actually the main use-case for dry-types and dry-validation, coercing and validating data at the point of entry into your system. If you decide to use them please feel free to join us on Gitter and let us know how you get on/ask any questions you might have.

1 Like

I don’t think the practices are being ignored. They’ve simply chosen one compromise over another.

My experience with highly decoupled, container managed systems is that, as system complexity increases, the code actually becomes harder to understand. Context is lost. My experience has been largely negative, which informs my dislike of this pattern.

The validator and types gems are more interesting to me. Several years ago I built a system that combined types and validation. We used it to back UIs in a rails app. The entire app was driven from a few templates and helpers that introspected the types and then rendered the view. It was very cool.

Also, it looks like a lot of effort and thought went into these. Bravo! How extensively are you using them?

1 Like

Yeah, a bad choice of words on my part there.

I’ve had similar experiences myself, which is why I started the dry-rb organisation, managing complexity is no easy feat and I feel that the tools being developed under dry-rb make managing complexity easier.

Yeah, dry-validation and dry-types seem to be the gems people find most attractive, I think these problems have existed for a long time and a lot of developers have been aware of them, so it’s nice to finally see a couple of libraries that handle these concerns nicely. I would love to see your implementation and I’m sure Piotr would too, perhaps there is something we could learn from it and use that knowledge to make dry-validation and dry-types better, is it open source?

Thank you, we’ve all put a lot of work into this (especially Piotr) so it’s nice to hear, as for usage, I have only personally used dry-container in one small production app (a micro-service using Roda), so it wasn’t all that complex, however, I know Piotr and Tim Riley have used most of the gems from dry-rb in Rodakase applications, with what they consider to be great success. Piotr is also writing a book about his experiences using these patterns with Rodakase, probably worth looking out for if it’s something that interests you.

2 Likes

Unfortunately, it’s not open source. There are definitely times I wish I had access to it :frowning:

I’ll keep an eye out for that book.

1 Like

Hi @AMHOL, I like what your project’s overall goal is. But, have you seen Thinning controllers for easier unit testing and separation of concerns ?

I like dry ideal goal :slight_smile:

1 Like