I just realised that I rarely define attributes in my classes (the dependency injection references are exceptions) and I’m passing everything as a parameter. So instead of this:
class Foo
attr_accessor :list
def do_something
@list = []
action_1
action_2
end
private
def action1
@list[2] = "a"
end
def action_2
@list[1] = "b"
end
end
I have this:
class Foo
def do_something
list = []
action_1(list)
action_2(list)
end
private
# self. means that this is a class level method (static in Java)
def self.action_1(list)
list[2] = "a"
end
def self.action_2(list)
list[1] = "b"
end
end
Similarly to my spike workflow I realised what I’m unintentionally doing after actually having done it. I switched to this method because of the Unix philosophy: “The Unix philosophy emphasizes building short, simple, clear, modular, and extendable code that can be easily maintained and repurposed by developers other than its creators.”
More precisely: I switched to this method because I was struggling with the Unix philosophy. When I’m writing code I don’t know what the shortest and simplest entity in my code is so I put everything into a class and when it is done, I may refactor it into smaller classes. This refactoring work is very hard when I have tightly coupled methods, but when I have methods that are not coupled by attributes (except dependency injection references) then it is easy. In the code above I can simply move action_1
and action_2
anywhere I want:
class Foo
# I have an attribute here: @actions
def initialize(actions)
@actions = actions
end
def do_something
list = []
@actions.action_1(list)
@actions.action_2(list)
end
end
# ----
class Actions
def action_1(list)
list[2] = "a"
end
def action_2(list)
list[1] = "b"
end
end
The action_1
and action_2
methods are no longer class level methods (no .self
) because it is easier to code dependency injection with object level methods.
I do this even if my class has an actual “state”:
class Foo
attr_accessor :last_element
attr_accessor :list
def do_iterate
last_element = action_1(@last_element, @list)
end
private
def self.action_1(last_element, list)
list[2] = "a"
last_element = 2
return last_element
end
end
Anyway, this is the first time a large refactoring is no longer a difficult and long process. Furthermore, there are no more surprises in my methods: I know what is going to happen just by looking at the method definition.
comments powered by Disqus