Thursday, April 19, 2007

RevolutionHealth Officially Launched!

Its been 3 months since we launched our preview site, and today I am proud to say we've launched the new and improved RevolutionHealth!

I look forward to our folks sharing some of the details behind our products in the near future.

Also, a big thank to the rails community. There is no way we could have done this without Rails, the community, and all the great plugins/blogs/articles out there.



Aside from a full redesign, we have some great new products such as:

KnowYourRisk - "Give us 10 minutes, we'll give you 10 years": A state-of-the-art assessment pioneered by BioSignia. In just 10 minutes, by confidentially entering basic health information, the KnowYourRisk(TM) proprietary program can calculate a user's risk of contracting one of the nine most common diseases – and can provide personalized information on actions to help reduce that risk and live longer.

Medicine Chest - A tool to find drugs and treatments, as well as rate and share your experience with others. This service is in its infancy, but our philosophy is that if millions of people participate, it will emerge as a useful tool for people as they consider their treatment options.



Revolution Pages - Now people can create and customize their own health pages, including their top-rated articles, tools and resources, as well as photos and personal stories. This sophisticated self-publishing capability encompasses Web 2.0's promise of creating customized health content: patients and families dealing with health issues can share the benefit of their experiences with others -- and learn from others, too. See some examples: Sneezing, Type II Diabetes, or Bad Knees.


These are along with many of the awesome products we launched in late January.

Thank you!

Sunday, April 15, 2007

[PLUGIN RELEASE] ActsAsReadonlyable

Introduction

ActsAsReadonlyable adds support of multiple read-only slave databases to ActiveRecord models. When a model is marked with acts_as_readonlyable, some of AR finders are overridden to run against a slave DB. The supported finders are find, find_by_sql, count_by_sql, find_[all_]by_*, and reload.

Finders can be forced to fall back to a default DB by passing the :readonly flag set to false.

Disclaimer

As our blog post points out, we wrote this plugin in preparation to using slave DBs but we are not going to have those until May 2007. So even though the code is covered with tests (see svn://rubyforge.org/var/svn/acts-as-with-ro/trunk/test/unit/read_write_model_test.rb), it has not been used outside of those. We would have a discovery period in May when the code is likely to be improved so for now you can use is at your own risk. Meanwhile, we would be happy to fix any issue revealed. Drop us a line at rails-trunk [ at ] revolution DOT com.

Using this plugin should not be your first step in application optimization/scaling or even the second one. Before installing it make sure you understand the implication of leveraging multiple DBs (for example, the potential for cross DB joins).

Usage

Add acts_as_readonlyable to your models backed up by slave DBs. If you want to apply ActsAsReadonlyable to all models, add this or similar code at the end of config/environment.rb:


class << ActiveRecord::Base

def read_only_inherited(child)
child.acts_as_readonlyable :read_only
ar_inherited(child)
end

alias_method :ar_inherited, :inherited
alias_method :inherited, :read_only_inherited

end


Example

Sample DB Config


dbs:

database: master_db
host: master-host

read_only:
database: slave_db
host: slave-host


Note: There is no need for more than one read-only database configuration in your database.yml since you can leverage traditional load balancing solutions. If you still want to use database.yml to spread the load, define multiple entries there and use acts_as_readonlyable [:first_read_only, :second_read_only].


Sample Model

class Fruit < ActiveRecord::Base
acts_as_readonlyable :read_only
end


Usage

r = Fruit.find(:first) # executes against the read-only db
r.field = 'value'
r.save! # executes against the read/write db

r.reload # executes against the read-only db
r.reload(:readonly => false) # executes against the read/write db


Installation

As plugin:
script/plugin install svn://rubyforge.org/var/svn/acts-as-with-ro/trunk/vendor/plugins/acts_as_readonlyable


License

ActsAsReadonlyable released under the MIT license.


Support

The plugin RubyForge page is http://rubyforge.org/projects/acts-as-with-ro

Saturday, April 14, 2007

ActsAsWithReadonly to support read-only DB slave databases

Update: Released as ActsAsReadonlyable

In his latest post, DHH comments on scaling issues Twitter's team had with their rails application. One of the frequent mentioned problems with ActiveRecord is a weak support of multiple read-only slave databases. We were told by our DBAs some time ago that we needed to think how our rails application would utilize slaves DBs after the official release of our portal . Back then our teammate, Jeffrey Damick, came up with an idea of having an 'acts_as' plugin to support that. We have not yet started using slave DBs but some code has been written. We are releasing it on Rubyforge as soon as the project is approved.

The basic idea behind the plugin is that when an ActiveRecord model is marked with acts_as_with_readonly, most of AR finders are overloaded to run against a slave DB. It allows to do all reads from a read-only farm while saving updates to the read-write DB.

An example of usage:

*** database.yml


production:

database: master_db
host: master-host

read_only:
database: slave_db
host: slave-host


*** Sample Model

class ReadWriteModel < ActiveRecord::Base
acts_as_with_readonly :read_only
end


*** Code

record = ReadWriteModel.find(:first) # against slave_db
record.field = 'new value'
record.save! # against master_db

Saturday, March 31, 2007

[PLUGIN RELEASE] - Facade

Due to a slew of interesting runtime dependencies, we needed to be able to quickly mock out thorny pieces of our architecture.

  • I might not want to run a huge MOA stack to develop software that touches some arcane piece of our application that happens to use messaging.
  • I might want to hit a fully-functional mock (e.g. built in Active Record) instead of hitting live services that we don't own or might cost money.
  • I might want to crank out a naive implementation of a particular data source/sink with the intent of putting in a more 'industrial' solution if the product is a success.

Facade is a library for modeling objects that delegate some or all of their behavior to a surrogate class. It's essentially a DSL for describing a delegation arrangement, as well as a mechanism to bind a particular implementation to those delegator models. It's a little bit of dependency injection mixed with a little bit of IDL.

It also was a relatively enjoyable exercise in Ruby metaprogramming; this would have been quite painful in a few other languages.

Don't worry, it sounds much worse (and Java-esque) than it really is. Actual usage is pretty straightforward and doesn't create a lot of senseless abstraction.

Here's a little self-explanatory peek into the three pieces of the puzzle (the configuration, the facade model, and the implementation model(s).)

Facade model:

class Foo < Facade::Base
backend_class_method :delegated_class_method, :delegated_returns_a_collection_of_self
backend_instance_method :delegated_instance_method
def local_method
puts 'I do stuff that is indepenent of implmentation of delegated stuff'
end
end


Mock delegatee:

class Mock::Foo
def delegated_instance_method
puts 'I performed a mock implementation of my_instance_method'
end
def self.delegated_class_method
puts 'I performed a mock implementation of my_class_method'
end
def self.delegated_returns_a_collection_of_self
return [self.new, self.new]
end
end


Live delegatee:

class Live::Foo
def delegated_instance_method
puts 'I performed a live implementation of my_instance_method'
end
def self.delegated_class_method
puts 'I performed a live implementation of my_class_method'
end
def self.delegated_returns_a_collection_of_self
return [self.new, self.new]
end
end


Config file:

development:
foo:
backed_by: mock
production:
foo:
backed_by: live


The mock/live distinction isn't important--you could just as well have two mock implementations or three live implementations. It's just the name of the module that holds the implementation.

The unique thing about Facade (vis-a-vis other mocking solutions) is its autoboxing support. This allows delegatees to return instances of the delegator without even being aware that its a delegatee (in fact, the delegatee may be a class that you didn't even write.) Whenever instances of the delegatee are returned from a delegated method, an instance of the delegator is returned to the invoker instead. The reason we chose autoboxing over duck-typing is that you want to keep a bulk of the functionality in the implementation-agnostic facade model, and those methods would not be available if we simply returned references to the delegatee whenever the delegatee returned references of itself.

Example: If model Foo contains lots of AR-agnostic business logic but happens to delegate a couple of methods to its AR-backed delegatee--say, for persistence support--we want the results of those ActiveRecord finders to be instances of Foo < Facade::Base, not instances of ArModels::Foo < ActiveRecord::Base, or else we won't be able to invoke Foo's instance methods on the objects in the collection.

Here's a little console session that illustrates the usage of the models shown above:


epf-lap:/tmp/facade_hello_world $ ruby script/console
Loading development environment.
>> Foo
=> Foo
>> Foo.my_class_method
I performed a mock implementation of my_class_method
=> nil
>> foo = Foo.new
=> #<Foo:0x27bb584 @facade_backend=#<Mock::Foo:0x27bb55c>>
>> foo.my_instance_method
I performed a mock implementation of my_instance_method
=> nil

epf-lap:/tmp/facade_hello_world $ ruby script/console
Loading development environment.
>> foo = Foo.new
=> #<Foo:0x27c370c @facade_backend=#<Mock::Foo:0x27bf1c0>>
>> foo.delegated_instance_method
I performed a mock implementation of my_instance_method
=> nil
>> foo.local_method
I do stuff that is indepenent of implmentation of delegated stuff
=> nil
>> Foo.delegated_class_method
I performed a mock implementation of my_class_method
=> nil
>> Foo.delegated_returns_a_collection_of_self
=> [#<Foo:0x27ac64c @facade_backend=#<Mock::Foo:0x27ac728 @my_facade_model=#<Foo:0x27ac64c ...>>>, #<Foo:0x27ac50c @facade_backend=#<Mock::Foo:0x27ac714 @my_facade_model=#<Foo:0x27ac50c ...>>>]
>> ret_foo = Foo.delegated_returns_a_collection_of_self.first
=> #<Foo:0x279c454 @facade_backend=#<Mock::Foo:0x279cbe8 @my_facade_model=#<Foo:0x279c454 ...>>>
>> ret_foo.class
=> Foo
>> ret_foo.delegated_instance_method
I performed a mock implementation of my_instance_method
=> nil
>> ret_foo.local_method
I do stuff that is indepenent of implmentation of delegated stuff
=> nil


epf-lap:/tmp/facade_hello_world $ ruby script/console production
Loading production environment.
>> # notice it's using the other implementation now that we're in prod mode
>> Foo.delegated_class_method
I performed a live implementation of my_class_method
=> nil
>> # and you can dynamically change the implementation, complete with autobox
?> Foo.reset_backend(Mock::Foo)
=> Mock::Foo
>> Foo.delegated_class_method
I performed a mock implementation of my_class_method
=> nil
>> Foo.delegated_returns_a_collection_of_self.first.class
=> Foo
>> Foo.delegated_returns_a_collection_of_self.first.delegated_instance_method
I performed a mock implementation of my_instance_method


Check out the README for information on installation (it's simple!) and getting started.

Readme: svn cat \
svn://rubyforge.org/var/svn/facade/trunk/vendor/plugins/facade/README
Repository: svn checkout \
svn://rubyforge.org/var/svn/facade/trunk/vendor/plugins/facade
Rubyforge: http://rubyforge.org/projects/facade/

Installation:

ruby script/plugin install \
svn://rubyforge.org/var/svn/facade/trunk/vendor/plugins/facade

ruby script/plugin install \
svn://rubyforge.org/var/svn/config-loader/trunk/vendor/plugins/configuration_loader

Friday, March 16, 2007

[PLUGIN RELEASE] Configuration Files Loader v1.0.0

Configuration Files Loader can be used as a gem or a Rails plugin to load various config files.

It finds config file fragments in a Rails config directory and in config directories of plugins and dependent gems. It then tries to merge them in the following order: gem<-plugin<-application. This allows overrides of global (gem/plugin) configs by individual applications. The supported types for merging are String, Hash, and Array. It caches the content of files by default. ConfigurationLoader is RoR environment aware and provides a shortcut (load_section) to load a section of a config file corresponding to RAILS_ENV. It is being used in another method provided by ConfigurationLoader - load_db_config. It loads a section from config/database.yml providing a convenient method for placing secondary DB entries in a code as seen here:

establish_connection ConfigurationLoader.load_db_config['secondary_db']

See the DRYing Up Configuration Files post in our team blog for additional details.


Setup

Installation

To install Configuration Files Loader as a gem:

Use gem install configuration_loader or download the gem file from the project page and install it.

To install it as a Rails plugin:

ruby script/plugin install svn://rubyforge.org/var/svn/config-loader/trunk/vendor/plugins/configuration_loader


Usage

require 'configuration_loader'

ConfigurationLoader.load_db_config # gets the RAILS_ENV section from database.yml

ConfigurationLoader.load('cfg.yml') # loads a YAML-processed config file

ConfigurationLoader.load('cfg.yml', :erb => true) # loads a ERB+YAML-processed config file

ConfigurationLoader.load('cfg.yml', :section => RAILS_ENV) # loads a current RAILS_ENV section from a YAML-processed config file

ConfigLoader.load('cfg.yml', :cache => false) # loads an uncached copy of a YAML-processed config file


License

Configuration Files Loader is released under the MIT license.

Update by Sean (6/20/2008)
This is now available on github as a gem.

To install:
gem install revolutionhealth-config_loader -s http://gems.github.com

Or simply add the following to your Rails 2.1-compatible application:
config.gem 'revolutionhealth-config_loader', :lib => 'config_loader', :source => 'http://gems.github.com'