Practical Object-Oriented Design in Ruby
All of code snippets below are examples from POODR and come from this repository.
Best time for Design decisions
When to take design decisions? If cost of doing nothing is the same now and in future, postpone design decision until more information comes. On the other hand if there is chance that sub-optimal architecture will be reused by someone or replicated, it should be fixed early. A tension exists between improving now and improving later.
Determining if a class has a single responsibility
We need to interrogate this class, ask it questions and see if it makes sense:
Mr Gear, what is your ratio? is fine, but
Mr Gear, what is your tire (size)? is obviously not.
Another way is to try describing in one sentence what it does, without “or”/”and”.
Removing argument order dependencies
Remove argument order dependencies by using
We can do
def initialize(chainring, cog, wheel). But if we use
args, we can instantiate this class with any order of arguments.
Inject dependencies in order to decouple code.
Gear doesn’t know that
Wheel class exists, its instance was injected.
Isolate dependencies when dependency injection can’t be achieved.
Wheel dependency to separate method is a good way to isolate it.
Call method with dependent arguments to reverse dependencies.
This example shows how to reverse dependencies. Now
Gear doesn’t know anything about
Classes should depend on things that change less often than they do.
Use inheritance when object has a switch/if based on type/category variable and tries to determine what methods send to self based on that.
Recognizing hidden ducks
Coding patterns that indicate hidden ducks:
casethat switch on class
This gist shows how to handle hidden ducks. Instead of switching through preparers and calling methods on parts of trip, we let them do the hard work instead and encapsulate this logic where it belongs - in preparers.
Duck type with shared behaviour
module can be used instead of duck type with shared behaviour/role.
This snippet shows how to use modules in situations when we have a duck type (
schedule - can be swapped thanks to
and shared behaviour.
Law of Demeter
Objects should talk only to their immediate neighbours. Avoid “train wrecks” like
comment.post.blog.author. Doing so reduces
code coupling and amount of dependencies.
Composition over inheritance
Use composition when having choice. Composition matches more
Composition allows objects to have structural independence at the cost of explicit message delegation. Inheritance gives you message delegation for free at the cost of maintaining a class hierarchy.
Each of the topics I mentioned in this post is very broad and each of them could be described in detail in a separate blog post. But the idea here was to gather notes that are essence of POODR and that help me in my day-to-day work. If they helped you as well, don’t hesitate to share them.
You can find Part 2 of those notes here