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 = "a" end def action_2 @list = "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 = "a" end def self.action_2(list) list = "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_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 = "a" end def action_2(list) list = "b" end end
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 = "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