<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	>

<channel>
	<title>Citrusbyte Blog &#124; Web Development &#38; Web Strategy</title>
	<atom:link href="http://blog.citrusbyte.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.citrusbyte.com</link>
	<description>The Official Citrusbyte Blog</description>
	<pubDate>Fri, 21 May 2010 16:26:21 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Fixing Resque</title>
		<link>http://blog.citrusbyte.com/2010/05/21/fixing-resque/</link>
		<comments>http://blog.citrusbyte.com/2010/05/21/fixing-resque/#comments</comments>
		<pubDate>Fri, 21 May 2010 15:21:53 +0000</pubDate>
		<dc:creator>Michel Martens</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.citrusbyte.com/?p=369</guid>
		<description><![CDATA[Since redis-rb 2.0.0 came out, a lot of Resque users realized that redis-namespace (a Resque dependency) was incompatible with the most recent Redis client. It didn&#8217;t come as a surprise: I even notified Chris Wanstrath (author of Resque and redis-namespace) about this issue when we were rolling release candidates. At that time, his proposed solution [...]]]></description>
			<content:encoded><![CDATA[<p>Since <a href='http://blog.citrusbyte.com/2010/05/14/redis-rb-200/'>redis-rb 2.0.0 came out</a>, a lot of <a href='http://github.com/defunkt/resque'>Resque</a> users realized that <a href='http://github.com/defunkt/redis-namespace'>redis-namespace</a> (a Resque dependency) was incompatible with the most recent Redis client. It didn&#8217;t come as a surprise: I even notified Chris Wanstrath (author of Resque and redis-namespace) about this issue when we were rolling release candidates. At that time, his proposed solution was to lock Resque to redis-rb 1.0.x. I also hinted that once Redis 2 comes out, the old client would no longer work because of a change in the protocol.</p>
<p>For some background, Resque is a Redis-backed Ruby library for creating background jobs, placing those jobs on multiple queues, and processing them later. It uses redis-namespace, a 187 sloc gem that adds a Redis::Namespace class which can be used to namespace Redis keys.</p>
<p>Yesterday, a discussion took place in <a href='irc://irc.freenode.net/redis'>#redis</a> regarding redis-namespace compatibility with redis-rb 2.0.0. There even was a suggestion to incorporate redis-namespace into redis-rb, so all libraries could profit from that solution. Even if I opposed that move (I consider redis-namespace the wrong solution to a simple problem), the underlying issue was not with redis-namespace, but with Resque itself. None of the participants in that discussion were direct redis-namespace users: they only wanted Resque to work with redis-rb 2.0.0.</p>
<p>Not being a Resque user myself, I had not bothered looking at its code before. Turns out I was able to make Resque 100% compatible with redis-rb 2.0.0 by replacing redis-namespace with&#8230; nothing. It wasn&#8217;t needed at all, and the namespacing functionality is now handled by an attr_accessor called namespace.</p>
<p>This code lives at my <a href='http://github.com/soveran/resque/tree/without-redis-namespace'>without-redis-namespace</a> branch. I sent a pull request yesterday, I hope it will be incorporated soon to the main repository.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.citrusbyte.com/2010/05/21/fixing-resque/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Redis-rb 2.0.0</title>
		<link>http://blog.citrusbyte.com/2010/05/14/redis-rb-200/</link>
		<comments>http://blog.citrusbyte.com/2010/05/14/redis-rb-200/#comments</comments>
		<pubDate>Sat, 15 May 2010 01:39:56 +0000</pubDate>
		<dc:creator>Michel Martens</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.citrusbyte.com/?p=355</guid>
		<description><![CDATA[After a few weeks with very stable release candidates, we have just pushed version 2.0.0. Here&#8217;s a quick rundown on what&#8217;s new with the Ruby client for Redis:
Explicit &#62; Implicit
The previous version of the client relied on method_missing to execute commands against Redis. While this was great for quickly putting together a simple client, it [...]]]></description>
			<content:encoded><![CDATA[<p>After a few weeks with very stable release candidates, we have just pushed version 2.0.0. Here&#8217;s a quick rundown on what&#8217;s new with the <a href='http://rubygems.org/gems/redis'>Ruby client for Redis</a>:</p>
<h4 id='explicit__implicit'>Explicit &gt; Implicit</h4>
<p>The previous version of the client relied on <code>method_missing</code> to execute commands against Redis. While this was great for quickly putting together a simple client, it proved insufficient for more advanced commands like pub/sub, blocking pop, etc. Plus, relying on this technique lead to longer and more branched methods as new features were added to Redis.</p>
<p>The new version explicitly defines each command as a method in the <code>Redis</code> class. We strongly believe that explicit beats implicit. This way it&#8217;s much easier to follow what is going on for each command. We did leave <code>method_missing</code> in there because it&#8217;s a nice way of being able to run simple commands that are not yet known to the client, but we&#8217;ll keep adding new commands as needed.</p>
<p>A nice consequence of this change is that the complexity of the code was reduced drastically. Many branches were removed in favor of separate, smaller methods (this is something that could only be done with an explicit method for each command).</p>
<h4 id='new_protocol'>New protocol</h4>
<p>This version uses the new protocol only. It means people running a Redis version older than 1.2 will be stuck with the 1.0 branch. This multi-bulk protocol is binary safe and will be the only one available once Redis 2.0 is released, for which a release candidate is expected soon.</p>
<h4 id='faster'>Faster!</h4>
<p>One of our concerns when refactoring was the impact on performance this decoupling would bring. We agreed that a good goal would be to have the new version performing at least as fast as the old one. To our surprise &#8211;and probably because of the removal of branches, hash look-ups and by avoiding <code>method_missing</code>&#8211; the new version performed even better.</p>
<p>Before:</p>
<pre><code>$ ruby -Ilib benchmarking/speed.rb
7.88 Kops</code></pre>
<p>After:</p>
<pre><code>$ ruby -Ilib benchmarking/speed.rb
8.79 Kops</code></pre>
<p>The higher the number, the better. It means that the new version executes almost a thousand operations more per second.</p>
<h4 id='redisdistributed'>Redis::Distributed</h4>
<p>The old client shipped with DistRedis, which included a hashring algorithm and supported a small subset of operations. As it wasn&#8217;t tested or documented, we started by defining all the test cases and proceeded to implement them. Some operations are impossible in a distributed scenario, but we would cover a lot of interesting cases and it is now a very reliable tool. Check the <a href='http://github.com/ezmobius/redis-rb/blob/master/test/distributed_test.rb'>testing suite</a> to see the range of commands that are now possible.</p>
<h4 id='supportbugshelp'>Support/Bugs/Help</h4>
<p>Jump to IRC if you need instant help. We are most of the time available at #redis-rb on Freenode. If nobody can help you there, try #redis. You can also <a href='http://github.com/ezmobius/redis-rb/issues'>create an issue</a> on GitHub, or fork the project and send a patch directly.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.citrusbyte.com/2010/05/14/redis-rb-200/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Ohm, now using Redis Hashes</title>
		<link>http://blog.citrusbyte.com/2010/05/10/ohm-now-using-redis-hashes/</link>
		<comments>http://blog.citrusbyte.com/2010/05/10/ohm-now-using-redis-hashes/#comments</comments>
		<pubDate>Tue, 11 May 2010 04:05:48 +0000</pubDate>
		<dc:creator>Michel Martens</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.citrusbyte.com/?p=342</guid>
		<description><![CDATA[Redis 2.0.0 is around the corner, but many of us are already using 1.3.x even in production. The new version has a lot of goodies, and of special interest for libraries that map objects to Redis is the hash data type.
By using hashes, Ohm is able to squeeze all the object attributes in a single [...]]]></description>
			<content:encoded><![CDATA[<p>Redis 2.0.0 is around the corner, but many of us are already using 1.3.x even in production. The new version has a lot of goodies, and of special interest for libraries that map objects to Redis is the hash data type.</p>
<p>By using hashes, <a href='http://ohm.keyvalue.org'>Ohm</a> is able to squeeze all the object attributes in a single key instead of using one key per attribute, a common pattern in key/value datastores (for some history, check the article that inspired Ohm almost one year ago: <a href='http://code.google.com/p/redis/wiki/TwitterAlikeExample'>case study for a Twitter clone</a>).</p>
<p>This release candidate uses <a href='http://github.com/ezmobius/redis-rb/'>Redis-rb 2.0.0.rc3</a>, the new client that is faster, binary safe and no longer relies on method_missing for building the commands.</p>
<h2 id='upgrading_your_database'>Upgrading your database</h2>
<p>You will need to migrate your database if you want to use <a href='http://github.com/soveran/ohm'>Ohm 0.1.0</a>. It comes with a helper just for that, <a href='http://gist.github.com/396791'>follow the example code to upgrade</a>.</p>
<p>You will also need Redis 1.3.10 or newer, grab it from <a href='http://github.com/antirez/redis'>http://github.com/antirez/redis</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.citrusbyte.com/2010/05/10/ohm-now-using-redis-hashes/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Citrusbyte delivers last minute Sony Facebook tab for 180LA</title>
		<link>http://blog.citrusbyte.com/2010/05/07/citrusbyte-delivers-last-minute-sony-facebook-tab-for-180la/</link>
		<comments>http://blog.citrusbyte.com/2010/05/07/citrusbyte-delivers-last-minute-sony-facebook-tab-for-180la/#comments</comments>
		<pubDate>Fri, 07 May 2010 23:01:37 +0000</pubDate>
		<dc:creator>PaulAllen</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[180la]]></category>

		<category><![CDATA[facebook]]></category>

		<category><![CDATA[results]]></category>

		<category><![CDATA[rush]]></category>

		<category><![CDATA[sony]]></category>

		<guid isPermaLink="false">http://blog.citrusbyte.com/?p=315</guid>
		<description><![CDATA[180LA engaged Citrusbyte to deliver a simple Facebook tab showcasing Sony Electronic&#8217;s new iSweep Panorama digital camera technology.  While not a technically challenging project, 180LA needed a product representative of the Sony brand quality and they needed it as soon as possible.
Within a day of the request, Citrusbyte had the new frame up and running [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-317" title="180 logo" src="http://blog.citrusbyte.com/wp-content/uploads/2010/05/180-logo.jpg" alt="180 logo" width="85" height="75" />180LA engaged Citrusbyte to deliver a simple Facebook tab showcasing Sony Electronic&#8217;s new iSweep Panorama digital camera technology.  While not a technically challenging project, 180LA needed a product representative of the Sony brand quality and they needed it as soon as possible.</p>
<p>Within a day of the request, Citrusbyte had the new frame up and running on the <a href="http://www.facebook.com/sonyelectronics?v=app_4949752878">Official Sony Electronics Facebook</a> page.  Take a look for yourself:</p>
</p>
<div class="mceTemp" style="text-align: center;">
<dl id="attachment_314" class="wp-caption  alignnone" style="width: 310px;">
<dt class="wp-caption-dt"><a title="Sony Electronics iSweep Panorama Facebook Tab" href="http://www.facebook.com/sonyelectronics?v=app_4949752878"><img class="size-medium wp-image-314" title="Sony iSweep Panorama Facebook Application" src="http://blog.citrusbyte.com/wp-content/uploads/2010/05/screen-shot-2010-05-07-at-34252-pm-300x284.png" alt="Sony iSweep Panorama Facebook Page" width="300" height="284" /></a></dt>
</dl>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.citrusbyte.com/2010/05/07/citrusbyte-delivers-last-minute-sony-facebook-tab-for-180la/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Monk updated to use Sinatra 1.0</title>
		<link>http://blog.citrusbyte.com/2010/04/13/monk-updated-to-use-sinatra-10/</link>
		<comments>http://blog.citrusbyte.com/2010/04/13/monk-updated-to-use-sinatra-10/#comments</comments>
		<pubDate>Tue, 13 Apr 2010 17:43:36 +0000</pubDate>
		<dc:creator>Michel Martens</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.citrusbyte.com/?p=307</guid>
		<description><![CDATA[Monk&#8217;s default skeleton now ships with Sinatra 1.0 and the latest versions of Webrat and Ohm.
It also includes tasks for starting and stopping Redis, and overall should provide more hints about what to configure and where.
To try it, just run monk init myapp, then cd myapp and monk to check the available options.
If you never [...]]]></description>
			<content:encoded><![CDATA[<p><a href='http://monkrb.com'>Monk</a>&#8217;s default skeleton now ships with <a href='http://www.sinatrarb.com/one-oh-faq'>Sinatra 1.0</a> and the latest versions of <a href='http://github.com/brynary/webrat'>Webrat</a> and <a href='http://ohm.keyvalue.org'>Ohm</a>.</p>
<p>It also includes tasks for starting and stopping <a href='http://code.google.com/p/redis'>Redis</a>, and overall should provide more hints about what to configure and where.</p>
<p>To try it, just run <code>monk init myapp</code>, then <code>cd myapp</code> and <code>monk</code> to check the available options.</p>
<p>If you never installed Monk, run <code>sudo gem install monk</code>. If you already have it, there&#8217;s no need to update the gem.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.citrusbyte.com/2010/04/13/monk-updated-to-use-sinatra-10/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Mixing Ohm with ActiveRecord, DataMapper and Sequel</title>
		<link>http://blog.citrusbyte.com/2010/04/12/mixing-ohm-with-activerecord-datamapper-and-sequel/</link>
		<comments>http://blog.citrusbyte.com/2010/04/12/mixing-ohm-with-activerecord-datamapper-and-sequel/#comments</comments>
		<pubDate>Mon, 12 Apr 2010 16:08:48 +0000</pubDate>
		<dc:creator>Michel Martens</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.citrusbyte.com/?p=301</guid>
		<description><![CDATA[There&#8217;s one nice side effect in the way Ohm and Sequel find records: they use [](id), which is also a way to call procs in Ruby.
So, how would you declare a reference to a DataMapper model or a set of ActiveRecord instances within Ohm?
class User &#60; ActiveRecord::Base
  def posts
    Post.find(user: self)
 [...]]]></description>
			<content:encoded><![CDATA[<p>There&#8217;s one nice side effect in the way <a href='http://ohm.keyvalue.org'>Ohm</a> and <a href='http://sequel.rubyforge.org/rdoc/classes/Sequel/Model/ClassMethods.html#M000238'>Sequel</a> find records: they use <code>[](id)</code>, which is also a way to call procs in Ruby.</p>
<p>So, how would you declare a reference to a DataMapper model or a set of ActiveRecord instances within Ohm?</p>
<pre><code>class User &lt; ActiveRecord::Base
  def posts
    Post.find(user: self)
  end
end

class Comment
  include DataMapper::Resource

  property :id,          Serial
  property :body,        String
end

class Post &lt; Ohm::Model
  attribute :body
  reference :user, lambda { |id| User.find(id) }
  list      :comments, lambda { |id| Comment.get(id) }
end</code></pre>
<p>Each time Ohm needs to refer to User, it will call the lambda the way it calls other Ohm models.</p>
<pre><code>&gt;&gt; user = User.create :name =&gt; &quot;foo&quot;
&gt;&gt; post = Post.create :user =&gt; user, :body =&gt; &quot;bar&quot;

&gt;&gt; post.user.name
=&gt; &quot;foo&quot;

&gt;&gt; comment = Comment.new
&gt;&gt; comment.attributes = { :body =&gt; &quot;baz&quot; }
&gt;&gt; comment.save
=&gt; true

&gt;&gt; post.comments &lt;&lt; comment
&gt;&gt; post.comments.first.body
&gt;&gt; &quot;baz&quot;</code></pre>
<p>And what about Sequel? Because Sequel behaves exactly like Ohm, there&#8217;s no need for a lambda. You can mix them directly.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.citrusbyte.com/2010/04/12/mixing-ohm-with-activerecord-datamapper-and-sequel/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Guide to porting Facebook games and apps to the MySpace platform</title>
		<link>http://blog.citrusbyte.com/2010/03/15/porting_facebook_games_apps_myspace/</link>
		<comments>http://blog.citrusbyte.com/2010/03/15/porting_facebook_games_apps_myspace/#comments</comments>
		<pubDate>Mon, 15 Mar 2010 19:58:18 +0000</pubDate>
		<dc:creator>PaulAllen</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[facebook]]></category>

		<category><![CDATA[myspace]]></category>

		<category><![CDATA[tools]]></category>

		<category><![CDATA[tutorials]]></category>

		<guid isPermaLink="false">http://blog.citrusbyte.com/?p=295</guid>
		<description><![CDATA[You didn’t have to attend the GDC last week in San Francisco to know that social games like Farmville are revolutionizing the gaming industry.  But what does this mean for developers who rely upon Facebook as the sole social network platform for their businesses?  It means its time to diversify.
In a recent Forbes [...]]]></description>
			<content:encoded><![CDATA[<p>You didn’t have to attend the GDC last week in San Francisco to know that social games like Farmville are revolutionizing the gaming industry.  But what does this mean for developers who rely upon Facebook as the sole social network platform for their businesses?  It means its time to diversify.</p>
<p>In <a href="http://blogs.forbes.com/velocity/2010/03/10/social-games-look-to-outgrow-facebook/">a recent Forbes article</a> Brian Reynolds, chief designer of Zynga, said his company was &#8220;platform agnostic,” stating Zynga “just [wants] to be on whatever platforms enable good experiences.  We&#8217;re also on MySpace, and we&#8217;ve done iPhone stuff. It&#8217;s all about which platform allows it to be most social.&#8221;</p>
<p>Today, Citrusbyte announces <a href="http://developer.myspace.com/wordpress/wp-content/themes/myspace/FB_TO_MS_convertion/guide.html">tools</a> to help your Facebook game be just a bit more platform agnostic with only a few minor code tweaks.</p>
<p>Commissioned by MySpace, Citrusbyte developed <a href="http://developer.myspace.com/wordpress/wp-content/themes/myspace/FB_TO_MS_convertion/guide.html">a reference toolkit for porting any Facebook app to the MySpace platform</a>. The document goes through Facebook’s Authentication and RESTful APIs, noting their MySpace equivilent or providing code snippets whenever necessary.   The document concludes with a step-by-step example of how to port one Facebook app to the MySpace platform, including before and after code.</p>
<p>Following this guide, Facebook game developers can quickly and easily bring their apps to the MySpace platform, accessing over 100 million additional active users.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.citrusbyte.com/2010/03/15/porting_facebook_games_apps_myspace/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Superfluous DSLs</title>
		<link>http://blog.citrusbyte.com/2009/12/15/superfluous-dsls/</link>
		<comments>http://blog.citrusbyte.com/2009/12/15/superfluous-dsls/#comments</comments>
		<pubDate>Tue, 15 Dec 2009 18:21:03 +0000</pubDate>
		<dc:creator>Michel Martens</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.citrusbyte.com/?p=255</guid>
		<description><![CDATA[You are given the task of validating that no two users register with the same name.
In ActiveRecord it can be implemented like this:
validates_uniqueness_of :name
You may now add an index to your database and consider your task done, but it&#8217;s also true that you can improve the user experience by using a better error message:
validates_uniqueness_of :name, [...]]]></description>
			<content:encoded><![CDATA[<p>You are given the task of validating that no two users register with the same name.</p>
<p>In ActiveRecord it can be implemented like this:</p>
<pre>validates_uniqueness_of :name</pre>
<p>You may now add an index to your database and consider your task done, but it&#8217;s also true that you can improve the user experience by using a better error message:</p>
<pre>validates_uniqueness_of :name, :message =&gt; &quot;The name {{value}} is taken. &lt;a href=&quot;/login&quot;&gt;Log in&lt;/a&gt; instead?&quot;</pre>
<p>Did you see the use of <code>{{value}}</code> in there? That&#8217;s because ActiveRecord&#8217;s DSL for validations operates on a class level, and that means that when you are declaring the validation, you don&#8217;t have access to the instance you will be dealing with. Note also that there&#8217;s HTML in the error message. It&#8217;s nice to point the user in the right direction, and here it only makes sense to send the user to the login page. But HTML in the models is wrong in many levels, not to mention that the URL helpers are not available there.</p>
<p>It would make much more sense to declare the validations at the instance level, something ActiveRecord allows with the <code>validate</code> method. If we had <code>validates_uniqueness_of</code> as an instance method, this would be possible:</p>
<pre>def validate
  validates_uniqueness_of :name, :message =&gt; &quot;The name #{name} is taken. &lt;a href=&quot;/login&quot;&gt;Log in&lt;/a&gt; instead?&quot;
end</pre>
<p>A detail here is that we can build the message with Ruby interpolations instead of the <code>{{value}}</code> macro. The HTML is still there, but I will deal with that in another post.</p>
<h3>Code smells in redundant DSLs</h3>
<p>Another example of why a class level DSL for validations is a bad code smell:</p>
<pre>validates_presence_of :card_number, :if =&gt; :paid_with_card?

def paid_with_card?
  payment_type == &quot;card&quot;
end</pre>
<p>What&#8217;s wrong here? The validations DSL is reimplementing Ruby functionality, but not because it&#8217;s an improvement but because it&#8217;s operating on the <strong>wrong scope</strong>. Returning to the instance level approach, this is how it would look:</p>
<pre>def validate
  validates_presence_of :card_number if paid_with_card?
end</pre>
<p>There are two other examples in the <a href='http://guides.rails.info/activerecord_validations_callbacks.html#conditional-validation'>Rails guides</a>, which I reproduce here:</p>
<pre>validates_presence_of :surname, :if =&gt; &quot;name.nil?&quot;</pre>
<p>As you may know, this evaluates the string within the instance. Needless to say, it&#8217;s another case where <strong>the DSL reinvents the wheel for no good reason</strong>. The counter example:</p>
<pre>def validate
  validates_presence_of :surname if name.nil?
end</pre>
<p>And now the proc approach:</p>
<pre>validates_confirmation_of :password,
  :unless =&gt; Proc.new { |a| a.password.blank? }</pre>
<p>The counter example:</p>
<pre>def validate
  validates_confirmation_of :password unless password.blank?
end</pre>
<p>As you can see, these solutions are shorter and make the DSL look superfluous. It means that the DSL is unnecessary.</p>
<p>When you count the lines of code of your models, you should take into account how much code you are injecting. Your models could be hundreds of lines shorter if irrelevant DSLs like this one were removed.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.citrusbyte.com/2009/12/15/superfluous-dsls/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Ohm&#8217;s persistence strategy</title>
		<link>http://blog.citrusbyte.com/2009/12/11/ohms-persistence-strategy/</link>
		<comments>http://blog.citrusbyte.com/2009/12/11/ohms-persistence-strategy/#comments</comments>
		<pubDate>Fri, 11 Dec 2009 15:22:15 +0000</pubDate>
		<dc:creator>Michel Martens</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.citrusbyte.com/?p=243</guid>
		<description><![CDATA[I had a very interesting conversation with Fictorial about how Ohm treats sets, lists and counters differently than normal attributes.
From the documentation (updated after the conversation):

The attributes declared with attribute are only persisted after calling save. If the object is in an invalid state, no value is sent to Redis (see the section on Validations [...]]]></description>
			<content:encoded><![CDATA[<p>I had a very interesting conversation with <a href='http://twitter.com/fictorial'>Fictorial</a> about how <a href='http://ohm.keyvalue.org'>Ohm</a> treats sets, lists and counters differently than normal attributes.</p>
<p>From the <a href='http://ohm.keyvalue.org'>documentation</a> (updated after the conversation):</p>
<blockquote>
<p>The attributes declared with attribute are only persisted after calling save. If the object is in an invalid state, no value is sent to Redis (see the section on Validations below).</p>
</blockquote>
<blockquote>
<p>Operations on attributes of type list, set and counter are possible only after the object is created (when it has an assigned id). Any operation on these kinds of attributes is performed immediately, without running the object validations. This design yields better performance than running the validations on each operation or buffering the operations and waiting for a call to save.</p>
</blockquote>
<p>The idea of buffering the operations and waiting for a save is from Fictorial, who is porting Ohm to <a href='http://nodejs.org'>Node.js</a>. Here is what he does:</p>
<blockquote>
<p>What I did in NOM is make changes to the local/client-side object while at the same time buffer (in the same order) the commands needed to realize the local changes remotely in Redis. For instance, a List object has a push method. This is JS so the local object is an Array which is updated with the corresponding .push. At the same time, I buffer a &#8220;RPUSH key length\r\nvalue\r\n&#8221;. Then, if the validation passes, I send the buffered commands.</p>
</blockquote>
<p>I know from my experience with Ohm that I&#8217;m comfortable with the current approach, and if I need to check for validity before operating on lists, sets or counters, I can use <a href='http://ohm.keyvalue.org'>the pattern described in the docs</a>.</p>
<p>Thoughts?</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.citrusbyte.com/2009/12/11/ohms-persistence-strategy/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Sharespost Launches!</title>
		<link>http://blog.citrusbyte.com/2009/06/19/sharespost-launches/</link>
		<comments>http://blog.citrusbyte.com/2009/06/19/sharespost-launches/#comments</comments>
		<pubDate>Fri, 19 Jun 2009 20:51:24 +0000</pubDate>
		<dc:creator>will</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.citrusbyte.com/?p=233</guid>
		<description><![CDATA[
Ok we&#8217;re a few days late, but http://www.sharespost.com has just launched. Citrusbyte helped the company get to an internal beta in only 6 weeks with a lean team of two. We then ramped in their new internal developer who pushed the site to live.
Check out more about the company here: http://www.crunchbase.com/company/sharespost
And the press: http://www.sharespost.com/pages/press
SharesPost makes [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://farm4.static.flickr.com/3659/3642214154_9622bfedfb.jpg?v=0" width="300px" style="float:left;margin:15px;"/></p>
<p>Ok we&#8217;re a few days late, but <a href="http://www.sharespost.com">http://www.sharespost.com</a> has just launched. Citrusbyte helped the company get to an internal beta in only 6 weeks with a lean team of two. We then ramped in their new internal developer who pushed the site to live.</p>
<p>Check out more about the company here: <a href="http://www.crunchbase.com/company/sharespost">http://www.crunchbase.com/company/sharespost</a></p>
<p>And the press: <a href="http://www.sharespost.com/pages/press">http://www.sharespost.com/pages/press</a></p>
<p>SharesPost makes private equity liquid by efficiently matching buyers, sellers of private company stock and giving them the information, tools and process to make transactions easy and safe. At SharesPost you can download research reports and corporate documents for hundred’s of private companies, including Facebook, Twitter and LinkedIn. Plus, see prices from previous transactions. When you’re ready, connect directly with buyers and sellers of private company shares without brokers or their commissions. SharesPost provides you with automated contracts and integrated e-signature and escrow services to handle transfer restrictions like company rights of first refusal and help process your transaction.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.citrusbyte.com/2009/06/19/sharespost-launches/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
