Mixins anti-patterns in Ruby on Rails
“Template methods”
Suppose we have the following setup
module M1
included do
def m1_method1
building_block1
end
def building_block1
implementation1
end
end
end
class C1
include M1
def building_block1
override_implmentation1
end
end
C1.m1_method1
Problems with this setup
- Often
building_block1
has a generic name. As a result, RubyMine and VSCode are not able to find definitions or references precisely. They return a giant list of methods with the same name instead. - Ideally, template method interface is abstract. A concrete
implementation1
misleads me on the runtime behavior, espeically when the I find the definition throughC1.m1_method1
- What if I take out the
M1.building_block1
orimplementation1
? Then we expect the classing mixining M1, e.g., C1, should implement or overridebuilding_block1.
, but there is no class or method signature to enforce this expectation. You can imagine my frustration when I find this during the runtime
- What if I take out the
Override mixin’s constant
module M1
STATE = "m1_state"
included do
def m1_method1
process(STATE)
end
end
end
class C1
include M1
STATE = 'c1_state'
end
C1.m1_method1
This setup frustrates the code reader. Imagine the sequence of actions:
- The user finds the defintion of
C1.m1_method1
- The code runs, but
STATE
inm1_method1
is different from the definition in the same class. - The user finds the reference of the
STATE
, and the IDE returns 20 different places with 3 different overrides.
Stateless mixins that are not utils
module M1
included do
def m1_method1
end
end
end
module M2
included do
def m2_method2
m1_method1
end
end
end
module M3
included do
def m3_method3
m1_method1
end
end
end
class C1
include M2
include M3
end
C1.m3_method3
C1.m2_method2
- Hard to navigate through layers of definitions, especially if any name is generic. Often IDEs are not able to resolve the method precisely
- I prefer just merging stateless mixins