DEV Community

Discussion on: Ruby devs, how do you work?

Collapse
 
tadman profile image
Scott Tadman

It's odd you say "things like dependency injection are not really a thing" and link to an article talking about how someone made a DSL-type dependency injection system. Ruby does a lot of things through dependency injection, it's a fairly common pattern. Many different behaviours can be layered on using that approach and you see it in various forms in different Ruby projects.

One good example is Rails Engines, a way of completely encapsulating a component of a Rails application in a way that's modular. You can plug in an Engine and have new models, views, controllers, and all the supporting code for that Engine, and also a clean way to remove it if it becomes obsolete or unnecessary.

When it comes to finding out about definitions, many modern editors, Visual Studio Code included, have a fairly capable method discovery and backtracking system. This is done through tools like Solargraph that can dig into your Ruby code and make a map of method definitions.

This ties into your question about method arguments. Solargraph can parse out documentation that's in the source and show you how to use any given method. If you write comments in a form Solargraph understands, which is also useful when automatically exporting documentation, it'll give you all the help you need.

As for testing, that's something of an art more than a science. When working on Ruby code you should be aware of the contract that method is fulfilling, implied or express, and work to avoid violating that. This generally means if a method accepts data in a particular form you continue to accept that form, you don't arbitrarily change the rules, and if it emits results in a particular form or forms you commit to do the same.

A good way to verify that this continues to be the case is unit tests, but these can only test so much. If you want to be a sneaky jerk, intentionally or unintentionally, you can change how the method works in a subtle, yet important way. Like you might mangle your arguments with in-place modifiers like gsub! or delete that the test might not notice, but which is against the spirit of the original "contract" where you normally do not "own" arguments you're given, you must treat them gently and with respect, unless you've made it clear in the documentation that you're assuming control of them.

A lot of Ruby boils down to the "Duck Typing" principle, and by extension, the "Duck Method" principle. If your method does exactly what it says on the tin, reliably and predictably, under all the advertised use cases, then it's a valid implementation. It doesn't matter how you do things internally, there's a lot of latitude there. You just need to pay attention to your obligations and work to adhere to those boundaries.

Collapse
 
hiddewie profile image
Hidde Wieringa

Thank you for your comment.

I meant "DI is not really a thing" as in "in Ruby, DI is often not needed in the form of an entire framework as the backbone of your application".

Solargraph seems interesting, I will definitely look into that for code analysis!

Collapse
 
tadman profile image
Scott Tadman

Ruby doesn't lean too heavily on the dependency injection pattern, but it's still something you can see occur in many forms.

In other languages with a more formal implementation of this where it occurs is much more obvious, but in Ruby there's a very smooth gradient between light applications of this, like mixin methods from modules, to entire frameworks built around it, like Rails, and everything in-between.

So basically dependency injection is rarely forced on you, but it's there if you need it, and you can do it however you want.