Project Ramon

A learning journey from a Ruby noob perspective

TicTacToe: Refactor Friday

tictactoe_refactor_header_img

Hello and happy Friday!

Today’s post will cover a refactor of a TicTacToe game in Ruby. Our refactor was performed  last Friday by Marek Publicewicz, who’s code you can take a look at here. Lets get started.

Make Classes with a Single Responsibility

A class with more than one responsibility is more difficult to reuse than a class with only one responsibility. To determine if our classes contain behavior that belong elsewhere we can ask each one of the class’ methods a question.

Take a look at my TicTacToe class:

Even with a quick glance over this TicTacToe class, we can see that there are pretty clear violations of the Single Responsibility principle littered throughout. The only method that deals with a TicTacToe game is play.

winner? does have to do with determining a game winner, but it is composed of rules for defining a victory but not game play. Marek’s advice was to place these methods in their own class that has the single responsibility of defining a TicTacToe game’s winning rules.

Now our TicTacToe class has no understanding of how our new WinningRules class calculates a winner from a series of 3 or more plays. We can of course, wrap the behavior of WinningRules inside of a method in our TicTacToe class.

Our @winning_rules instance variable in the constructor method on line:9 has some flexibility in it that I didn’t understand at first. Essentially, its going to return a @rules object from our WinningRules class, and in the event that there is no object, @winning_rules will have a new object assigned to it with WinningRules.new.

Using the options hash def initialize(options = {}) in our constructor as an argument will give us flexibility whenever we create a TicTacToe object because we can hide the parameter names behind the hash name until we decide to pass in actual arguments as pseudo-named value pair arguments like options[:rules] on line:9.

Composed Method Pattern

Here is an excerpt that can be found here about the composed method pattern:

This is a pattern from Smalltalk Best Practice Patterns by Kent Beck:

Divide your program into methods that perform one identifiable task. Keep all of the operations in a method at the same level of abstraction. This will naturally result in programs with many small methods, each a few lines long.

When you use ExtractMethod a bunch of times on a method the original method becomes a ComposedMethod.

We can see examples of this here,

where winner?(moves) is comprised of the horizontal?, vertical? and diagonal? private methods.

We can see another example of the composed method pattern here,

where winner? delegates the implementation of calculating a game winner off to the class responsible for checking our players moves against a set of rules.

Methods: Compactly Doing Something

When looking to refactor our instance methods, we can follow Obie Fernandez’ guidance. Methods should have two things going for them, they should be short and they should actually be doing something. In his book Eloquent Ruby, he states that its typically easier for developers of my caliber to remember the ‘short’ part, while adhering to the ‘coherency’ part takes more practice.

Lets see if we can go through our TicTacToe class and decompose our play(x, y) instance method.

I found this refactoring cheat-sheet online, and there are a couple of things that stand out to me.

I would almost look to abstract out the conditional that displays puts "Player #{@current_player} wins!", but I’m unsure if that would be good since we already have a winner? method that delegates declaring a winner elsewhere.

What I would like to abstract into its own method is the @current_player = ((@current_player == 'X') ? 'O' : 'X') on line:19. Here’s how I would implement this decomposition:

So we added a switch_player private instance method that will change our player from X to O unless our winner? returns true in which case we would prefer our program to initiate our conditional puts "Player #{@current_player} wins!" anyways.

Here are my two classes after all is said and done.

and

Next week I’ll be getting primed to start my third AirPair project.

Stay tuned!
 

Advertisements

Categories: AirPair, Newbie, Ruby

Tags: ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s