I'm currently working with some code that IMO has abused ruby's mixin features. Given that I'm new to ruby, I wonder if MO in IMO is correct or not.
My primary question is what makes more sense (and if there are any major technical differences between them):
E.g.
1
to create Helper singleton classes (or Modules with class methods) to keep all my "helper" functions.
module Helper
def foo(); p 'foo'; end # instance method
end
class User
include Helper # foo() is now a method of User
def initialize()
foo() # included, invoked on User class object
end
end
------- OR -------
2
create mixin modules that contain these functions and include
them everywhere I need them.
module Helper
def self.foo(); p 'foo'; end # class method
end
class User
def initialize()
Helper.foo() # Invoked on Helper module object
end
end
An example of the way it's abused in my case:
module ComplexMathPerformer
def perform_complex_math(); p 'perform_complex_math()'; end
end
module Renderer
def render_3d_object()
perform_complex_math() # from ComplexMathPerformer, which is NOT included here.
end
end
module Game
include ComplexMathPerformer
include Renderer
def play()
render_3d_object()
end
end
This code works because Game
includes both Renderer
and ComplexMathPerformer
. But is a nightmare for someone who's looking at ComplexMathPerformer
and trying to figure out where the hell is is foo()
defined and how is it accessible in ComplexMathPerformer
.
Logically it makes more sense to include ComplexMathPerformer
but that's skipped because Game
already includes ComplexMathPerformer
(for it's own purposes). Making it a mess.
1 Answer 1
By checking the examples, IMHO, there is no abuse of the mixin feature of Ruby, but coupling between the modules ComplexMathPerformer
and Renderer
.
Mixin abuse is generally felt by developers when too much abstraction exists. Mixins should be used when you need to share behavior between a couple of classes.
Modules are usually used when you need to create functions more as functions (methods without state).
Maybe ComplexMathPerformer
logic should be inside the game, or in another class which the Game consumes and not as a Module in your case.
Explore related questions
See similar questions with these tags.
Helper1 & 2
both have 7-10 related methods each (addressing different responsibilities) with a total of 150-200 LOC so it makes sense to keep them apart.Helper1
methods, but class B does not need those, but only the ones fromHelper2
. The problem I see in the example is coupling betweenHelper1
andHelper2
modules, but not an abuse of mixin (which would be an abuse on abstractions)Helpers
, I updated the example to make a bit more clear.