Service Objects for Good

Service objects are a handy tool to use in any ruby application, that has complex logic that needs to be extracted out of a controller or model. There are some nice benefits to extracting complex things into a more testable interface. To avoid providing a contrived example, I will use similar code to how uploads on rubyfm are handled. class UploadService attr_reader :user, :logger, :upload def initialize(user, options = {}) @user = user @logger = options[:logger] || NullObject.new @errors = {} end def start(params) @upload = build_from_params(params) unless @upload.save logger.error { 'failed to save the upload' } # more logging info on why return false end unless transcode logger.error { 'failed to transcode upload' } return false end true end def transcode AmazonTranscodeService.new(@upload).start end end And the UploadsController that utilizes the UploadService with the following. ...

April 18, 2018

Ruby Mixins

Mixins are a bit of a touchy spot for me. I am in a love hate relationship when it comes to them. In some cases, they work brilliantly and in other cases they hide complexity. I have a few rules that I try to follow when I am considering using mixins. Does it hide complexity / indirection? Will it benefit the code base to share code? Will it override methods or will methods need to be overriden? Moving methods into mixins to just move them is not sufficient enough to warrant the need for mixins. It is something that should be used to refactor once a pattern is established. Mixins should only be used for adding abilities to classes. ...

January 17, 2015

A Ruby Yukata

Let me introduce you to my new library called Yukata. It is a light weight Ruby attribute library that is configurable and extendable. Virtus has been a huge inspiration for this library. I enjoyed the DSL it offered, while allowing me to have a quick way to make data objects. Here is an example on how to utilize Yukata: class Person < Yukata::Base attribute :first_name, String attribute :last_name, String attribute :born_on, DateTime attribute :married, Boolean, default: -> { false } end The #attribute method is straight forward with its meaning. It is dynamically creating both getter and setter methods for the object. It can be thought of as a fancy attr_accessor but with a few extra features. It provides a fast way to discover what data type can be expected for that attribute. ...

March 7, 2014

Responding With Errors in Rails

As I work on API projects I find myself having to track down status codes and ensuring a consistent response code for any given error. Keeping these status codes consistent throughout the application starts to become a hassle. A solution that I stumbled upon happened to be something very simple. # /lib/errors/unauthorized_access_error.rb module Errors class UnauthorizedAccessError def status 403 end def message 'unauthorized access' end def to_hash { meta: { code: status, message: message } } end def to_json(*) to_hash.to_json end end end In my controller I would do the following: ...

October 18, 2013

Test Spies

Test spies are a wonderful tool to utilize in the RSpec testing environment. When used in moderation and with care. Test spies require that a called method be stubbed so that it can be checked to see how it was invoked. I have put together a really simple class to demonstrate a test spy. class NotifyUser attr_reader :user def initialize(user) @user = user end def execute(params={}) mailer.notify({ message: params[:message] }) end def mailer SomeMailer.new(user) end end Notice in the test below that a test spy follows a pattern. There is a mock up section, an excercise section, and a verification section. Each of these are important and I always put a space in between the sections. It’s much easier to see what is happening in the test. ...

October 1, 2013

Command Objects

In any Unix based OS the command line reigns supreme. Commmands are predictable, and return zero for success and non-zero for failures. Rules The same principles can be applied to programming with some minor rule alterations. Class name must be in a similar format to VerbNoun (ex. CreateResource). Instance must have an #execute method. It can accept arguments. The only instance method that should be accessed is the #execute method. The return type for #execute must be a Boolean. Example A basic command object will look like the following: ...

July 10, 2013

State Machines

A state machine is an interesting design pattern. The state_machine gem is a great library. It provides a nice structure to declare states and transitions. It also provides nice callback hooks that can be utilized to run specific actions before or after a transition happens. It has hooks into ActiveRecord and saves the model when the transition from one state to another is successful. The gem also works just fine with plain old ruby objects as well. Here is a simple example of a state machine. ...

July 9, 2013

Dumb Data Objects

As a Rails application grows and evolves. Fat models often become rampant in the application. ActiveRecord callbacks are used and models start interacting with other models in ways they should not. Enter the idea of “dumb data objects”. It is nothing more than a simple data structure. It holds state and that is it. Only methods that display data or modify the internal state should be on the model. ...

July 7, 2013

Services and Pub Sub

The Publish-Subscribe pattern is a great way to make code modular and decoupled from the rest of the architecture. It also has a nice side-effect of making testing easier and classes smaller. In a pub-sub pattern, publishers don’t know anything about its subscribers and subscribers don’t know anything about who is publishing to it. Subscribers are simply listening for specific messages and handling them accordingly and publishers are simply broadcasting messages. ...

July 3, 2013

Null Objects

Rails is a wonderful library. It’s a framework that is opinionated and requires some footwork on the developers part. One such issue is returning nil when the return type is an object. Returning nill doesn’t provide the view enough information about what actions to take and leads to complex whack-a-mole scenarios. The solution to this problem is to introduce a NullObject into the application. There are null object libraries already available, but they are so dead simple to write that it’s not necessary to use one. For example, it would be trivial to declare this basic NullObject. ...

June 24, 2013