16 Aug 2019
Note: The sample code in this post is from Feathersā book Working Effectively With
Legacy Code which iām trying to read through and summarize my knowledge.
Sometimes your design shows it could use improvement if you notice itās hard to test. When
itās hard to test your code, you eventually wonāt even bother.
A common thing that occurs is when you try to put a class under test it
has dependencies/collaborating classes which need to be created. Below
the Sale class depends on a ArtR56Display class.
public class Sale {
public void scan() {
ArtR56Display display = new ArtR56Display();
display.showLine();
}
}
}
First, we need to use dependency injection on the display object. One
easy way to do this is by passing it through the constructor. Typically instantiating objects
inside another class will highlight dependencies you need to overcome
(although there are exceptions e.g. basic value model objects).
public class Sale {
private ArtR56Display display;
public Sale(ArtR56Display display) {
this.display = display;
}
public void scan() {
display.showLine();
}
}
}
Now we want to test our sale class. We create a test which will
instantiate a ArtR56Display but suprise, itās connected to a physical
cash register. Itās not very convenient to write unit tests that rely on
this sort of external dependency just to run. Other typical dependencies
such as DB connections also suffer from this issue.
So the solution here is to extract the display to an interface which has
the side effect of promoting loose coupling and replaceability. It
allows the Sale class to be extended but not modified. So in the future
our Sale class can be hooked up to any other type of display.
public interface Display
{
void showLine(String line);
}
public class Sale
{
private Display display;
public Sale(Display display) {
this.display = display;
}
public void scan() {
...
String itemLine = item.name() + " " + item.price().asDisplayText();
display.showLine(itemLine);
}
}
At this point we could create a FakeDisplay that implements showLine().
In our tests now we can inject our FakeDisplay and still test the scan
method to ensure it still sends the right text to the display when the
Sale class is used without depending on the physical cash register.
public class FakeDisplay implements Display {
private String lastLine = "";
public void showLine(String line) {
lastLine = line;
}
public String getLastLine() {
return lastLine;
}
}
As a side note most Mocking libraries can handle most of this stuff for us
by creating a proxy class for any interfaces we would like to
fake and configuring it to execute dummy behavior.
28 Jun 2017
Iām learning how to write games in Elm and there does not seem to be
very many resources updated for Elm 0.18. The old Graphics module has
been moved out of elm-lang/core and into evancz/elm-graphics which might
cause some confusion/compilation errors when looking at older examples.
The elm-graphics package gives us modules that interface with HTML 5
Canvas API. So lets see how we can draw something basic to the browser.
In my later posts we will continue to build upon this program.
Make sure you have the required packages installed in your project
directory:
elm package install elm-lang/html
elm package install evancz/elm-graphics
Summary:
We learned how to render a ācanvasā on the screen by using
Element.toHtml which takes an Element created by Collage.collage.
While the Collage mainly deals with free form graphics, the Element and
Text Modules can help you plug in various other types of graphics into
your collage once converted into a form. I recommend checking out the
elm-graphics
documentation to see what other Forms you can create in your collages.
So far, drawing graphics to the screen may seem somewhat tedious as it is
in most other libraries. Elmās architecture will start to shine in its
simplicity in how updates and events are handled in your app.
13 Apr 2017
You may hear many developers groan at working on a legacy code base out
of control versus a greenfield project. However, I believe working in a
large legacy codebase provides a wonderful opportunity to improve your refactoring
skills.
This will be a series of connected blog posts on refactoring real world
code at my current job. Iāve attempted to obfuscate the code to make it
more generic and not tied to my company but the spirit should be the same.
Hopefully you are able to notice these issues in your own code and improve it.
So the first thing I did was run the flog gem(it essentially scores an
ABC metric: Assignments, Branches, Calls) on my app/ folder and
tackled the highest rated file which not suprisingly, was a controller:
91.1: flog total
91.1: flog/method average
91.1: RaterController#index app/controllers/rater_controller.rb:3-2
I will go ahead and make the commentary before you look at the wall of
abomination. At first glance the code is so dense that it is not clear
at all what weāre trying to do in the index action.
I hope this can convince you on the importance of having cleanly formatted code right off
the bat. While itās a very small file, it contains immense complexity.
The code smells I wanted to refactor in this first attempt:
1) Long method
Itās a 24 line index action method. Cannot tell at
glance what itās doing.
2) Single Responsibility Principle violation
While itās reasonable to have a controller to delegate rating
different objects, it can get out of control to put that logic directly
in the controller. We could at first just perform Extract Method but
that would just be shuffling complexity within the file and does not let
us take advantage of fixing the next issue.
3) Case statement that type checks and Open/Close Principle Violation
We observe an if-else block that kept getting piled on as more domain
objects were needed to be rated
class RaterController < AuthenticatedUserController
def index
@title = I18n.t 'rater.title'
@active_rating = manager_selection_is_self? ? params[:employee_rating ] : params[:manager_rating]
@inactive_rating = manager_selection_is_self? ? params[:manager_rating] : params[:employee_rating ]
@fullscreen_form_action = ''
if params[:rated_item_type] == 'movies'
movie = Movie.find(params[:id])
@rated_item = MoviePresenter.new movie
@fullscreen_form_action = rate_movie_path(id: movie.id, is_self: manager_selection_is_self?)
elsif params[:rated_item_type] == 'books'
book = Book.find(params[:id])
ratee = manager_selection_is_self? ? current_user.id : selected_user.id
rater = current_user.id
@fullscreen_form_action = rate_book_path(id: Book.id, rater:rater, ratee: ratee, manager_rating: params[:manager_rating], employee_rating:params[:employee_rating])
@rated_item = BookPresenter.new Book, selected_user_id: @selected_user_id
elsif params[:rated_item_type] == 'restaurants'
@fullscreen_form_action = rate_restaurants_path(id: selected_user.id, is_self: manager_selection_is_self?, rater_id: current_user.id, old_employee_rating: params[:employee_rating], old_manager_rating: params[:manager_rating])
@rated_item = RestaurantRating.new(selected_user)
end
render layout: 'fullscreen_form_dialog'
end
end
You probably didnāt even bother to try and understand what was going on
above, huh? Here is the refactored code with changes in comments
class RaterController < AuthenticatedUserController
def index
@title = I18n.t 'rater.title'
@active_rating = active_rating?
@inactive_rating = inactive_rating?
@fullscreen_form_action = ''
# Extracted logic to object_rater method to do all the work
@fullscreen_form_action, @rated_item = object_rater
render layout: 'fullscreen_form_dialog'
end
private
# Use a rater "factory" to instantiate specific raters
# Note we are using convention over configuration here:
# We assume that we have classes with name DomainItemRate
def object_rater
object_rater_class.new(rating_params).call
end
# The if-else can be removed now since we have a factory
# that knows how to instantiate itself based off item type.
# This takes advantage of Ruby's dynamic dispatching instead
# instead of needing to type check.
def object_rater_class
"#{params[:rated_item_type]}Rate".classify.constantize
end
# Instantiate a Parameter Object to pass to rater
def rating_params
"#{rating_type_rating}".classify.constantize.new(params)
end
# Remaining methods are helpers to parse params
def active_rating?
# return active rating check based on user
end
def inactive_rating?
# return inactive rating check based on user
end
def id
params['id'].to_i
end
def employee_rating
params[:employee_rating]
end
def manager_rating
params[:manager_rating]
end
def ratee
# return the ratee
end
def rater
# return the rater
end
end
We donāt have to modify the index action at all now and have a nice
convention for maintaining new Rater types. We simply just implement a
Rater class that āduck typesā what the index action wants returned so we
can maintain Open/Close principles.
Example Rater Class:
class BookRater
def initialize(args)
@id = args[:id].to_i
@is_self = args[:is_self]
end
def call
fullscreen_form_action = rate_book_path(id: book.id,
is_self: @is_self)
rated_item = BookPresenter.new book
[fullscreen_form_action, rated_item]
end
private
def book
Book.find(id)
end
end
Summary:
We broke out the rating logic for each domain type into plain old Ruby
objects(POROs) . We were able to instantiate these on the fly and remove
the if-else type checking by utilizing a factory pattern to dynamically dispatch to
our POROs.
04 Feb 2017
Although Iāve been focusing learning functional programming through Elixir
and Elm these days, itās interesting to go back to the first programming
language I love to see what it can do.
These are some examples of Rubyās functional programming abilities taken from
HackerRankās Ruby challenges.
Ruby can support higher-order functions i.e. can take and pass functions as
arguments through several mechanisms: Blocks, Procs, and Lambdas. Iām not going
to go into super detail as there are plenty
good posts
already out there on the topic. But a basic primer goes as follows:
Passing a Block to a function as nameless method:
def calculate(a,b)
yield(a, b)
end
puts calculate(15, 10) {|a, b| a - b} # 5
Assigning a Proc to a variable. Procās are like a āsavedā block:
def foo(a, b, my_proc)
my_proc.call(a, b)
end
add = proc {|x, y| x + y}
puts foo(15, 10, add) # 25
Very similar to Procs but differing how they return (see link mentioned beginning
of post) out of a function call is Rubyās lambda.
# the -> keyword is Ruby >= 1.9's lambda syntax
area = ->(a, b) { a * b }
x = 10.0; y = 20.0
area_rectangle = area.(x, y)
area_triangle = 0.5 * area.call(x, y)
puts area_rectangle #200.0
puts area_triangle #100.0
Letās dig into an interesting example where we show partial function applications
def factorial(n)
(1..n).inject(:*) || 1
end
combination = -> (n) do
-> (r) do
factorial(n) / (factorial(r) * factorial(n-r))
end
end
#How many combinations in 52 card deck when taking 5 cards?
n = gets.to_i # Let's enter 52
r = gets.to_i # Let's enter 5
nCr = combination.(n) # returns a lambda object
puts nCr.(r) # call our lambda with 2nd argument to be applied, result is 2,598,960
So similar to partial function applications is the concept of currying.
Currying is converting a single function of n arguments into n functions with a
single argument each.
power_function = -> (x, z) {
(x) ** z
}
base = gets.to_i
raise_to_power = power_function.curry.(base)
power = gets.to_i
puts raise_to_power.(power)
29 Dec 2016
This is my answer to one of the questions from Quora I stumbled upon concerning how to judge a good JS dev.
āJavaScript is a functional programming language. Give me an example of how you can use higher order functions in JavaScript to iterate over and apply a function to every element in an array. Do not use a for or while loop.ā
I didnāt find that this particular challenge noted much advance knowledge of JS. But some key things it does touch on are adding prototype functions, loss of functional scope of āthisā, and basic idea of how recursion works. Note: I am using some ES6 features and wrote it via a Jasmine test.
describe("map recursive implementation", () => {
it("applies function over array", () => {
// Let's add our function directly to all Array's via prototype
// So we can make calls like [1,2,3].myMap(...)
Array.prototype.myMap = function myMap(callback) {
// function implicitly binded to the original calling object
// i.e. [1,5,10,15].myMap(...)
// therefore 'this' is equal to the array
// so we can save this to a new variable called arr
let arr = this;
let newArray = [];
function map(arr) {
if(arr.length === 0) {
console.log("DONE processing, new array is " + newArray)
console.log(newArray.length);
return newArray;
}
else {
//process the head first
console.log("processing head of array: " + arr[0])
console.log("pushing: " + callback(arr[0]))
newArray.push(callback(arr[0]))
//process the rest of the list
arr.shift()
console.log("processing rest of list: " + arr)
//recursive call here
//we pass the new array which removed first processed item
return map(arr, callback);
}
}
return map(this);
}
let doubles = [1,5,10,15].myMap(function(x) {
return x * 2;
});
expect(doubles).toEqual([2,10,20,30])
})
})