Skip to content

Instantly share code, notes, and snippets.

@coop
Created December 11, 2012 08:19
Show Gist options
  • Save coop/4256846 to your computer and use it in GitHub Desktop.
Save coop/4256846 to your computer and use it in GitHub Desktop.

When building highly decoupled classes I often run into the problem of how to piece it all together. I have an understanding of how each piece is supposed to interact but I'm not sure how the functionality should co-exist. I have included some sample code below.

class Project
attr_accessor :name
end
class Deploy
def initialize options = {}
@branch = options.fetch(:branch, 'master')
@cli = options.fetch(:cli, Capistrano::CLI)
end
def run
@cli.parse(args).execute
end
end
class Repo
def initialize project, vendor_path = Rails.root.join('vendor', 'repos')
@project = project
@vendor_path = vendor_path
end
def path
@vendor_path.join project.name
end
def pull
git.pull
end
private
def git
@git ||= Grit::Git.new path
end
attr_writer :git
end
class DeployPreparation
def initialize repo
@repo = repo
end
def prepare
Dir.chdir @repo.path
@repo.pull
end
end

So now I have these highly decoupled classes but I am at a loss which is the best way to invoke this functionality. My immediate guess is create a helper method on Project that exposes what I'm after:

class Project
  # ...

  def deploy options
    options ||= {}

    repo = Repo.new self
    DeployPreparation.new(repo).prepare
    Deploy.new(options).run
  end
end

Or should I bundle up all this functionality into another class? It would be nice to be able to invoke 1 method and have a deployment run. A side benefit of bundling it up into another class would be that I could tie in backgrounding the entire process without effecting each individual part:

class DeployCoordinator
  def initialize project, options
    @project = project
    @options = options
  end

  def deploy
    DeployPreparation.new(repo).prepare
    Deploy.new(options).run
  end
  alias :perform :deploy

  def repo
    repo = Repo.new @project
  end
end

class Project
  # ...

  def deploy options
    options ||= {}
    DeployCoordinator.new(project, options).deploy
  end
end

I guess it really comes down to what feels best to you as a developer, but I often find myself not knowing which is the best approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment