Makers Week 2: A week of fulfilment

Self-led learning is a rewarding practice

Image for post
Image for post
Source: Pixabay

London, Shoreditch

The 2nd week at Makers felt much longer than it was, mainly because I didn’t take a proper rest during the weekend in week 1. I was joking with my cohort that we’re just going to continue with day 8 following up to day 7 (Sunday) of week 1, and day 9, day 10, etc. But to be honest, I started to feel settled and grasped so much this week!

Some high-level overview:

  • A deepening into Objected-oriented programming relationships: polymorphism, forwarding, delegation
  • More about ruby language: extracting a class, predicate methods, self in ruby
  • Test, test, test: variations of doubles (verifying doubles), RSpec syntax (let statement, before/after clause, predicate matcher, message order)

If you compare my targets above to the Makers week 2 curriculum, you might find that they are some slight nuances between the 2. That’s because more self-led learning this week!

While I feel happy to follow the Makers curriculum and go through all the requirements of the week, I found it more rewarding to have more self-led learning time allocated to some specific topics appeared during my coding practice. This is because if I don’t dive into these topics and solve them now, I can always confront them anytime in the future, and these small problems will start to compounding. In the end, I will end up with spending more time to crack them than just 1 hour for each of them earlier! I call this my “learning refactor”, as similar to code refractor, I just need to spend a small amount of time each time, but the positive cumulative effect is huge in future.

I also found it more rewarding to go a bit further than what is listed in the curriculum. For example, we were given a generic request to understand deeper about test doubles and stubs. But I taught myself about verifying doubles(a more secure version of normal doubles) and some advanced RSpec syntax like message order during the week, and they are proved to be useful also in my weekend challenge.

So into the debrief:

  • I really enjoyed exploring the other OO relationships (polymorphism, forwarding, delegation) other than inheritance, SPR from last week. They did seem confusing at the beginning, but I quickly found that they are twisted and embedded with each other! So delegation is also about inheritance, and you can find forwarding and delegation in polymorphism as well, most likely, they all involve SPR (Single Responsibility Principle).
  • A bit chunk of concept we’ve been revisiting this week is extracting a class. Obviously as the code base gets heavier, it’s impossible to have one class holding everything you want (A god class we call), so that’s where splitting and extracting come in.
  • I like it. I found it more about logical thinking than real coding skills (well you can argue everything is about logical thinking and analytical mind in coding). What I found a bit challenging is not about building the new class, it’s about how to make the new class interact with the old class. As you need to think about accessibility especially not to oppose everything of the new class to the old one. I documented down my approach below in weekly highlights, let me know if you have any comments!
  • The last bit is about testing (in RSpec). It took me quite some time to get around with variations of doubles (doubles, stubs, mocks, spies, verifying doubles, etc.). I started to use mocks more when I want to test a certain method within a test object(can be another method) is called and there’s no output (return, puts, etc.) from this calling. I also started to use verifying doubles when I want to validate a stubbed method does exist in the real class. Some syntax sugar comes in handy like the let statement and the before and after clause to help set the test premise and make the code more succinct. But I’m still on my way to fully grasp doubles in RSpec.

That’s all for this week. Wish me good luck next week:).

==========Highlights of the Week=============

A. Object-oriented Programming

Polymorphism

I know we’ve talked about Polymorphism last week. So this week is more about practical application. First, remember that the root of polymorphism is defined as “being able to use different things in the same way”.

Here’s an example code that moves planes and cars:

def move_200(thing)
if thing.is_a?(Car)
thing.drive(200)
elsif thing.is_a?(Plane)
thing.fly(200)
end
end

This code isn’t polymorphic. It treats different things differently. (car can drive, plane can fly). But imagine if you refactored the Car, Plane to all have a move method. You could rewrite move_200 as:

def move_200(vehicle)
vehicle.move(200)
end

The Car, Plane are now treated polymorphicly as just "vehicle”.

Forwarding

Meaning call method from another Class. So it’s basically encapsulation. There seem to be two clear ‘groups’ of methods. We can separate these up like this:

class Diary
def initialize
@contents = "Eric Cantona is the best footballer"
end
def read
@contents
end
end
class SecretDiary
def initialize
@diary = Diary.new #To make ins_var of SecretDiary an ins_var of Diary
@unlocked = false
end
def unlock
@unlocked = true
end
def lock
@unlocked = false
end
def read
return "Go away!" unless @unlocked
@diary.read #The same as call .read on ins_var of Diary
end
end

See how SecretDiary forwards methods on to Diary.

The behaviours of ‘locking/unlocking’ and ‘diary keeping’ are now in separate classes. This is a better way of organising our code.

Delegation

In delegation, one class tells another class to do something and the other class encapsulates how to do it.

A classic example is below, like in a company hierarchy, CEO needs to save money, however, instead of doing himself, he delegates it to the COO, who then delegates to Hr, who then passes down to the employees.

If there’s a template I can extract from this, is to using dependency injection to inject a class/instance of the class, and assign it to an instance variable. Then you are free to delegate by calling method on the 3rd party class through the instance variable (Like @coo.find_company_savings below).

class Ceo
def initialize(coo = Coo.new)
@coo = coo
end
def make_company_efficient
@coo.find_company_savings
end
end
class Coo
def initialize(hr_manager)
@entertainment_budget = 1000
@hr_manager = hr_manager
end
def find_company_savings
reduce_entertainment_budget
@hr_manager.reduce_payroll
end
privatedef reduce_entertainment_budget
@entertainment_budget -= 200
end
end
class HrManager
def initialize(employees)
@employees = employees
end
def reduce_payroll
@employees
.select { |employee| employee.performance < 7 }
.each(&:fire)
end
end
class Employee
def fire
@fired = true
end
def performance
rand(1..10)
end
end
employees = [Employee.new, Employee.new]
hr_manager = HrManager.new(employees)
coo = Coo.new(hr_manager)
ceo = Ceo.new(coo)
ceo.make_company_efficient

B. Ruby Specific

Extract Class

This is another thing I’ve focused on this week. Obviously, as the code base grows bigger, it becomes impossible to maintain the Single Responsibility Principle with just one class. That’s why you have to extract classes from current class to independent ones.

Single-responsibility classes are more reliable and tolerant of changes. For example, say that you have a class responsible for ten different things. When you change this class to make it better for one thing, you risk breaking it for the nine others.

Below are steps to work on extracting classes:

  • Create a new class to contain the relevant functionality.
  • Create a relationship between the old class and the new one. Optimally, this relationship is unidirectional.
  • Go through each field and method that you have decided to move to the new class.
  • After moving, take one more look at the resulting classes. You may need to rename or refractor to adjust the change.
  • Think about accessibility to the new class from the outside. You can hide the class from the client entirely by making it private, managing it via the fields from the old class. Alternatively, you can make it a public one by allowing the client to change values directly.

Predicate Methods

A method that returns true or false is called a “predicate method”. In Ruby, there is a naming convention where predicate methods end with a question mark.

class TruthyInvoice
attr_accessor :paid_at
def paid?
@paid_at
end
end
invoice = TruthyInvoice.new
invoice.paid? # nil
invoice.paid_at = Time.now
invoice.paid? # 2012-03-24 20:45:59 -0400

The above implementation of paid? will work fine in conditionals.

However, the intent of the paid? method is to tell you if the invoice has been paid, yet it is returning an instance of Time. This is confusing. The method would better represent the author's intent if it always returned a boolean. The most common way to ensure that a method returns true or false is to use the not operator (!) twice. This is read "not not" and would be used as follows:

class Invoice
attr_accessor :paid_at
def paid?
!!@paid_at
end
end
invoice = Invoice.new
invoice.paid? # false
invoice.paid_at = Time.now
invoice.paid? # true

Using “not not” only requires two more keystrokes and it more closely matches the intent of the method.

Self in Ruby

self is a special variable that points to the object that "owns" the currently executing code. Ruby uses self everwhere:

Inside of an instance method: In the code below, reflect is an instance method. It belongs to the object we created via Ghost.new. So self points to that object.

class Ghost
def reflect
self
end
end
g = Ghost.new
g.reflect == g # => true

Inside of a class method: For this example, reflect is a class method of Ghost. With class methods, the class itself "owns" the method. self points to the class.

class Ghost
def self.reflect
self
end
end
Ghost.reflect == Ghost # => true

It works the same with “class” methods inside of modules. For example:

module Ghost
def self.reflect
self
end
end
Ghost.reflect == Ghost # => true

Remember, classes and modules are treated as objects in Ruby. So this behavior isn’t that different from the instance method behavior we saw in the first example.

C. Ruby Test

Test private method?

Whether and how to test private methods is my other concern this week. Well, obviously I know that a“private” method just means it’s an implementation detail that is outside of my current API. If I am aiming to test the behavior of my API like a what a proper test should be, then I shouldn’t care about implementation details.

I googled and found that I have a few options:

  1. Make the method public in the object you are testing
  2. Make the method public in the test case
  3. Don’t test the method
  4. Use send or (send) to call it. (ignore the technical implementation here)
  5. Refactor private methods to a new object, and make the methods
    public in that object.

In real life, I found most of those options not optimal — as usually it represents
a design flaw (you are doing too much in class). So the approach I adopt is: if I can test it implicitly, e.g. through testing a public method with an embedded private method, I will not try to test it explicitly.

Let

According to Relish documentation, I can use let statement to define a memoized helper method. The value will be cached across multiple calls in the same example but not across examples.

An important note is that let is lazy-evaluated: it is not evaluated until the first time the method it defines is invoked. What this mean?

So what that means is that if you call let multiple times in the same example, it evaluates the let block just once (the first time it’s called). See the example below:

describe GetTime do
let(:current_time) { Time.now } #Thing in {}is the thing to be returned
it "gets the same time over and over again" do
puts current_time # => 2018-07-19 09:35:29 +0300
sleep(3)
puts current_time # => 2018-07-19 09:35:29 +0300
end
it "gets the time again" do
puts current_time # => 2018-07-19 09:35:32 +0300
end
end

As we can see, in the first example (i.e., the first it block), even though there is a three-second delay between the two calls to current_time, the value returned is the same.

That is because the first time current_time is called, its return value is cached. Then, for all subsequent calls inside that same example block, the cached value is returned.

In other words, { Time.now } is evaluated only once per example block.

However, when we call it again in the second it block, the { Time.now } block gets re-evaluated. And, as before, the value is cached for all the subsequent calls inside that second block.

Before/After Clause

describe Thing do
before(:each) do
@thing = Thing.new
end
describe Thing do
before(:all) do
@thing = Thing.new
end
after(:all) do
puts "after all ran"
end
after(:each) do
puts "after each ran"
end

Verifying double:

These are a powerful tool when I want more control and validation of my “fake” double. I focused mainly on class double and instance double, as I found other kinds like object double are a bit too far ahead from my current level. Will revisit this topic in the next few weeks!

RSpec.describe Account dodescribe "regular double" do
it "calls #name" do
account = double(name: "Joe")
expect(account.name).to eq("Joe")
end
end
describe "verifying instance double" do
# This one will fail since the name method doesn't exist in the
# Account instance
it "calls #name" do
account = instance_double("Account", name: "Joe")
expect(account.name).to eq("Joe")
end
end
describe "regular class double" do
it "calls .birthday" do
account = double("Account", birthday: "01/01/1970")
expect(account.birthday).to eq("01/01/1970")
end
end
describe "verifying class double" do
# This one will fail since the birthday method doesn't exist on the
# Account class
it "calls .birthday" do
account = class_double("Account", birthday: "01/01/1970")
expect(account.birthday).to eq("01/01/1970")
end
end
end

instance_double method, which checks if the method we are calling on the instance double is also available on the Account class as an instance method.

Similarly, we have created a class double with the use of RSpec’s class_double method, which checks if the method we are calling on the class double is also available on the Account class as a class method.

Message Order

You can use ordered to constrain the order of multiple message expectations.

RSpec.describe "Constraining order" do
it "passes when the messages are received in declared order" do
collaborator_1 = double("Collaborator 1")
collaborator_2 = double("Collaborator 2")
expect(collaborator_1).to receive(:step_1).ordered
expect(collaborator_2).to receive(:step_2).ordered
expect(collaborator_1).to receive(:step_3).ordered
collaborator_1.step_1
collaborator_2.step_2
collaborator_1.step_3
end
end

If the argument list is the same every time:

expect(object).to receive(:foo).with('argument').and_return('response 1', 'response 2')

If the argument list differs between invocations:

expect(object).to receive(:foo).with('argument 1').ordered.and_return('response 1')
expect(object).to receive(:foo).with('argument 2').ordered.and_return('response 2')

Predicate Matcher

Corresponding to the predicate methods, Rspect gives you a corresponding matcher. Simply prefix the method with be_ and remove the question mark. Examples:

expect(7).not_to be_zero       # calls 7.zero?
expect([]).to be_empty # calls [].empty?
expect(x).to be_multiple_of(3) # calls x.multiple_of?(

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store