Clutch

How to structure your code in Ruby

How to structure your code in Ruby
Average rating: 0
(0 votes)

As the agency which took Ruby as the language of choice, Syndicode always tracks the best practices and useful materials on this topic. Last time we told you about The Template Method in Ruby. And today we’re going to share with you an information on how to structure your code in Ruby. 

There are three approaches to structure your code in Ruby we’ll review today.

Inheritance

The first one and the easiest one is inheritance. But in object-oriented languages like Ruby inheritance could lead to the structural complexity. An inheritance tree will grow every time the client asks for the new features or an improvement.

When you face this problem, instead of reducing code duplication, you can end up with having the same logic in many places. There is even a Wikipedia article describing this phenomenon.

But we can avoid code duplication with mixins and composition.

Mixins

Mixins are usually the first thing comes to the minds of Ruby programmers when they notice that the inheritance is not a solution.  Basically, mixins are modules with a set of methods that can be included into a class and become an indistinguishable part of it. We can use them to extract any common logic and avoid code duplication.

Pros

We need to create those modules that we’ll include later on. Then we can define specific classes and include the mixins, that we’ve created. This way no code is duplicated and we can add any level of specialization and easily build whatever we want with all the features we need. Mixins might work well when you want to define meta-behavior of a class like logging, authorization or validation. The good thing is that they keep the code clean and small.

Cons

There are still some problems though. When you look at this class you’re not sure how the included behavior is used. A mixin adds a couple of new methods but it’s not immediately obvious what they are, how does the class interfere with them and how does it affect the execution flow. If by any chance two modules contain methods with the same name, you’re gonna run into problems – one module will silently use the method from the other one. In the same way, a module can mess up the code in your own class.

They’re fine as long as you trust their implementation and know that they don’t break any other logic.

Composition

How does the composition work? Instead of trying to share the same behavior between classes, you should identify what kind of concepts are these things that differ, name them, extract into separate classes and then compose into your final object.

If inheritance is about is-a relationship, then the composition is about has-a. Therefore we’ve got to change the structure of our problem in order to leverage the composition. We need to identify our concepts.

After defining the main class we need we need to create the implementation of our concepts and put everything together.

Pros

There are no problems with conflicting names. Each class does exactly one thing (satisfying the single responsibility principle). Therefore you can easily test each of them by checking how well do they do this only thing. We also achieve high cohesion (keeping the same logic together) maintaining low coupling (making classes loosely dependent on each other) at the same time. With the composition, we can easily change the code without changing the interface.

Cons

It tends to make the code longer, especially when it comes to injecting all the dependencies into the final object. You have to write additional boilerplate in order to store references, setup delegations and enforce correct execution flow. As a remedy, you can use one of many creational patterns, like Factory or Builder.

 

So, what we have?

Inheritance is the first choice for many programmers but it makes code complicated and hard to maintain.
Mixins seem like a smart and more powerful replacement but they are just a way to achieve implicit multi-base inheritance.
The composition is the most straightforward and clear approach to maintain dependencies between classes.

As always, you have to choose depending on your project and experience.

Based on How to avoid inheritance in Ruby? article by Michal Konarski. In his original article, you can find code examples.

If you want to find more interesting information, subscribe to our weekly newsletter!

Rate this article, if you like it

Thanks! You’ve rated this material!

Got a project? Let's discuss it!

*By submitting this form you agree with our Privacy Policy.

Mailing & Legal Address

Syndicode Inc. 340 S Lemon Ave #3299, Walnut CA, 91789, USA

Visiting & Headquarters address
Kyiv Sofiivska 1/2a, 01001, Kyiv, Ukraine
Dnipro Hlinky 2, of. 1003, 49000, Dnipro, Ukraine
Email info@syndicode.com
Phone (+1) 9035021111