Browse Code | Bugs & Patches | Downloads | Introduction | Sample App
The Library
Concierge does for back-end ruby services what Rails does for web MVC. It provides conventions and plumbing to join service implementations with service consumers. Service discovery and configuration are made painless through the use of convention.
In this context, service means "the action of helping or doing work for someone." The "someone" receiving help is typically a collaborating object, a controller in a Rails application, for example. The "someone" offering help may be a payment gateway, a shipping calculator, a legacy application, or whatever else you can dream up.
Installation
The simple way:
$ sudo gem install concierge
Or direct from the repository:
$ svn co svn://rubyforge.org/var/svn/concierge/trunk concierge
Configuration
Concierge needs to know where to look for services and configuration. It also requires that the dependency loader from Active Support be configured correctly. Here's an example:
CodeRhythm::Concierge::Loader.configure do |config|
config.service_config_path = "#{RAILS_ROOT}/config/services"
config.env = RAILS_ENV
end
Dependencies.load_paths.unshift "#{RAILS_ROOT}/lib/services"
You need the Active Support and Open Struct libraries available.
An Annotated Example
A typical Rails application contains code that looks something like this:
authorization = PaymentGateway.authorize(:cc => params[:cc], :amt => params[:amt])
It's not terrible but it is tightly coupled. You now have some object, a controller in this case, which knows exactly how a service (the payment gateway) is implemented. Besides tight coupling, you also have boiler plate code hanging around loading and configuring your service. It might look like this in your development.rb (or test.rb or production.rb):
# This effectively discovers the service.
require 'payment_gateway'
# Now we give the service some config to work with.
PaymentGateway.config.host = 'somehost'
PaymentGateway.config.port = '443'
# ...
Again, not terrible but somewhat sloppy; especially when you have a few of these services in your application.
With Concierge, collaborators (e.g. your controller) declare themselves as such with some meta-programming sugar:
class OrdersController < ApplicationController
consumes_service :payment_gateway
def create
authorization = payment_gateway.authorize(:cc => params[:cc], :amt => params[:amt])
# Do some other stuff
end
We broke the coupling between the PaymentGateway implementation and it's consumer. Decoupling and delegating service discovery and configuration to Concierge enables convention-based goodness such as service discovery from your lib/services directory and service configuration based on yaml files from your config/services directory.
Your lib/services/payment_gateway.rb now looks something like this:
class PaymentGateway < CodeRhythm::Concierge::Provider
provides_service :payment_gateway
def authorize(opts)
# Do the authorization.
# Configuration params are available using self.config (e.g. config.host).
end
end
Your config/services/payment_gateway.yml now looks something like this:
development:
host: devhost
port: 8080
test:
host: testhost
port: 9090
production:
host: prodhost
port: 443
Interested in how Concierge can help you isolate your collaborators during testing? Have a look at the examples/sham_test.rb file.
Chris, this looks great. Glad to see you make this available to other folks.
I believe the biggest gain from using Concierge comes when folks write tests. Perhaps an article working through the creation of a test which uses a service is in order… maybe over at FaithfulCode.com ;)