<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0"><id>tag:blogger.com,1999:blog-25066620</id><updated>2012-09-05T20:11:33.190-05:00</updated><category term="sapir-whorf" /><category term="goebbels" /><category term="books" /><category term="collaboration" /><category term="development" /><category term="ranges" /><category term="coworking" /><category term="perforce" /><category term="rubyonrails" /><category term="array" /><category term="splat" /><category term="code generators" /><category term="activewarehouse" /><category term="darcs" /><category term="gnomevfs" /><category term="business analysis" /><category term="git" /><category term="configuration" /><category term="uk" /><category term="rails" /><category term="turbogears" /><category term="web2" /><category term="outsource" /><category term="nosql" /><category term="greatbritain" /><category term="serendipity" /><category term="jee" /><category term="bdd" /><category term="closures" /><category term="c++" /><category term="anti-patterns" /><category term="fraud" /><category term="code generation" /><category term="sin" /><category term="agile process" /><category term="illinilist" /><category term="reading" /><category term="metafusion" /><category term="agile practices" /><category term="CSS" /><category term="java" /><category term="Javascript" /><category term="kaizen" /><category term="restful" /><category term="cdbaby" /><category term="django" /><category term="concurrency" /><category term="cowboy monkey" /><category term="gedit" /><category term="monkey" /><category term="opinion" /><category term="mac" /><category term="power" /><category term="dsl" /><category term="benchmarking" /><category term="rbehave" /><category term="agile software" /><category term="specifications" /><category term="project" /><category term="chicken" /><category term="j2ee" /><category term="cjug" /><category term="datamapper" /><category term="stupid" /><category term="json" /><category term="svn" /><category term="subversion" /><category term="google" /><category term="gay marriage" /><category term="activewarehouse-etl" /><category term="pig" /><category term="ruby" /><category term="activerecord" /><category term="blocks" /><category term="ruby expressions" /><category term="==" /><category term="cryptography" /><category term="ETL" /><category term="messaging" /><category term="quote" /><category term="github" /><category term="merb" /><category term="SOA" /><category term="source control management" /><category term="mda" /><category term="think" /><category term="opensource" /><category term="neo4j" /><category term="illinois" /><category term="source control" /><category term="tdd" /><category term="ruby idioms" /><category term="productivity" /><category term="graph databases" /><category term="currying" /><category term="math" /><category term="dry" /><category term="liberty" /><category term="election" /><category term="Google Wave" /><category term="jug" /><category term="Cloud Computing" /><category term="smalltalk" /><category term="urbana" /><category term="scm" /><category term="basecamp" /><category term="dhh" /><category term="web services" /><category term="champaign urbana" /><category term="seo" /><category term="propaganda" /><category term="friendship" /><category term="ruby on rails" /><category term="energy" /><category term="scrum" /><category term="presenter" /><category term="paypal" /><category term="clearcase" /><category term="domain specific language" /><category term="twitter" /><category term="equal?" /><category term="rubyforge" /><category term="mathematics" /><category term="higher order messaging" /><category term="coffee" /><category term="project management" /><category term="conventions" /><category term="datawarehouse" /><category term="beautiful code" /><category term="reliable-msg" /><category term="engines" /><category term="warehouse" /><category term="erlang" /><category term="Feeds" /><category term="autotest" /><category term="commercial" /><category term="tony blair" /><category term="predictions" /><category term="BarCamp" /><category term="open source" /><category term="outsourcing" /><category term="HTTP" /><category term="psychology" /><category term="RSS" /><category term="web 2.0" /><category term="ROA" /><category term="champaign" /><category term="performance" /><category term="search engine optimization" /><category term="pradipta" /><category term="future" /><category term="xml" /><category term="fastcgi" /><category term="scala" /><category term="entrepreneur" /><category term="scalability" /><category term="===" /><category term="aesthetics" /><category term="arrays" /><category term="security" /><category term="blackle" /><category term="rails generators" /><category term="models" /><category term="language" /><category term="idioms" /><category term="equality" /><category term="Jabber" /><category term="user" /><category term="rspec" /><category term="editor" /><category term="looping" /><category term="libertarian" /><category term="coding" /><category term="agile methods" /><category term="testing" /><category term="release" /><category term="scam" /><category term="jms" /><category term="plugins" /><category term="prime minister" /><category term="test driven" /><category term="design patterns" /><category term="search engines" /><category term="beck" /><category term="apple" /><category term="illini" /><category term="twitter twitter4r" /><category term="enumerations" /><category term="hitler" /><category term="gnome" /><category term="ruby ranges" /><category term="england" /><category term="agile" /><category term="python" /><category term="consulting" /><category term="chicago" /><category term="great britain" /><category term="joseph goebbels" /><category term="range" /><category term="windows" /><category term="layout" /><category term="Alan Turing" /><category term="Service Oriented Architecture" /><category term="buddha" /><category term="tonyblair" /><category term="beauty" /><category term="database" /><category term="linux" /><category term="twitter4r" /><category term="software requirements" /><category term="oss" /><category term="cvs" /><category term="blair" /><category term="britain" /><category term="linguistics" /><category term="codegenie" /><category term="REST" /><category term="php" /><category term="loops" /><category term="patterns" /><category term="information leaks" /><category term="politics" /><category term="kent beck" /><category term="chambana" /><category term="XMPP" /><category term="expression" /><category term="YUI" /><category term="jvm" /><category term="book" /><category term="config" /><category term="jee5" /><category term="enumerable" /><category term="sapir whorf" /><category term="web2.0" /><category term="inject" /><category term="oo" /><category term="cowboy" /><category term="orm" /><category term="natural language" /><category term="functional programming" /><category term="ruby forwardable" /><category term="vote" /><category term="safir-whorf" /><category term="eql?" /><category term="model" /><category term="capistrano" /><category term="data" /><category term="conductor" /><title type="text">Ruby, Javascript, Erlang blog: Snakes, Gems &amp; Coffee</title><subtitle type="html">&lt;p&gt;Topics already covered in this blog: &lt;a href="http://snakesgemscoffee.blogspot.com/search/label/idioms"&gt;Ruby Idioms&lt;/a&gt;, &lt;a href="http://snakesgemscoffee.blogspot.com/search/label/rails"&gt;Ruby on Rails&lt;/a&gt;, &lt;a href="http://snakesgemscoffee.blogspot.com/search/label/restful"&gt;RESTful design&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Going forward you will see a lot of posts about: &lt;a href="http://snakesgemscoffee.blogspot.com/search/label/merb"&gt;Merb&lt;/a&gt;, Ruby 1.9, Server benchmarks, performance, tuning.&lt;/p&gt;</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://geek.susanpotter.net/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default?start-index=26&amp;max-results=25" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>123</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/SnakesGemsCoffee" /><feedburner:info uri="snakesgemscoffee" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>SnakesGemsCoffee</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><entry><id>tag:blogger.com,1999:blog-25066620.post-7391614450100476192</id><published>2010-04-03T11:37:00.001-05:00</published><updated>2010-08-16T12:21:35.572-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="neo4j" /><category scheme="http://www.blogger.com/atom/ns#" term="nosql" /><category scheme="http://www.blogger.com/atom/ns#" term="graph databases" /><title type="text">DRAFT: Why proponents of marriage equality should love graph databases, Part 2: A Reply to 'The Database Engineering Perspective'</title><content type="html">So &lt;a href="http://geek.susanpotter.net/2010/03/why-proponents-of-marriage-equality.html" target="_blank"&gt;in part 1&lt;/a&gt; I provided an &lt;a href="http://geek.susanpotter.net/2010/03/why-proponents-of-marriage-equality.html" target="_blank"&gt;overview of problems relational databases (&lt;acronym title="Relational Database Management Systems"&gt;RDBMS&lt;/acronym&gt;) have with modelling relationships&lt;/a&gt; as well as &lt;a href="http://geek.susanpotter.net/2010/03/why-proponents-of-marriage-equality.html" target="_blank"&gt;entities that have datasets that are only partially structured in structure and definition&lt;/a&gt; based on my experiences.&lt;br /&gt;
&lt;br /&gt;
This post will:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;introduce new concepts utilized in graph databases and specific terminology for Neo databases&lt;/li&gt;
&lt;li&gt;review the most flexible schemas that accommodate both same-sex and opposite-sex marriages alike that were presented in the blog post I am responding to, &lt;a href="http://qntm.org/gay" target="_blank"&gt;&lt;em&gt;'Gay Marriage: The Database Engineering Perspective'&lt;/em&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;describe how graph databases could overcome the relational database shortcomings&lt;/li&gt;
&lt;li&gt;finally I will present a snippet of code (not meant for production use, but merely to demonstrate how we can use Neo4J) that makes it more natural to represent richer relationships between entities (or nodes as Neo4J calls them) that have substance to them (i.e. attributes in this case)&lt;/li&gt;
&lt;/ol&gt;&lt;br /&gt;
&lt;h4&gt;New Concepts in Graph Databases&lt;/h4&gt;Before I can explain how graph databases on a conceptual level can overcome most if not all (for most of the time anyway) of the relational databases (&lt;acronym title="relational database management systems"&gt;RDBMS&lt;/acronym&gt;) shortcomings mentioned in the previous post, we need to be introduced to new concepts and terminology.&lt;br /&gt;
There are two basic classes of objects in a graph database, they are:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Nodes:&lt;/strong&gt; a &lt;em&gt;node&lt;/em&gt; is basically an entity as RDBMS people (like probably you and I) are familiar with.  A &lt;em&gt;node&lt;/em&gt; could represent a person, customer, blog post, photograph, video or tweet.  It isn't always true, nor is it a good idea to think of graph database concepts only in terms of RDBMS concepts, but we could consider most tables that do not represent an actual &lt;em&gt;relationship&lt;/em&gt; or association between other tables as an entity.  It is a simplification, so use only in this initial learning phase cautiously.  A &lt;em&gt;node&lt;/em&gt; can have zero or more properties.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Relatioships:&lt;/strong&gt; a &lt;em&gt;relationship&lt;/em&gt; is the concept of an association between two &lt;em&gt;node&lt;/em&gt;s that needs to be represented in your data store somehow.  A &lt;em&gt;relationship&lt;/em&gt; can also have zero or more properties, just like a &lt;em&gt;node&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
The third concept in graph databases is that of a &lt;em&gt;property&lt;/em&gt;.  It unifies &lt;em&gt;node&lt;/em&gt;s and &lt;em&gt;relationship&lt;/em&gt;s as both first class citizens of the data store, which is quite unlike relational databases.  &lt;br /&gt;
&lt;br /&gt;
In a relational database we try to either reduce an association between two entities/tables to a small handful of cases, which might use references (if supported by that particular vendor and version of RDBMS), create "join tables" or we might force a natural relationship to become a table itself so that we are able to capture pertinent attributes for it.  There is no other way of handling relationships.  In many cases it might not be an issue to reduce the problem in these ways, however, the more and more interconnected our &lt;em&gt;entities&lt;/em&gt; become with new types of relationships it seems (to me) that this method of modelling data quickly becomes problematic.&lt;br /&gt;
&lt;br /&gt;
The following are other useful terms that the Neo graph database family uses, but conceptually most of these will also have a synonym in other graph databases:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Traversers:&lt;/strong&gt; in graph databases "querying" for specific data is not done via declarative query statements and clauses like SQL.  Rather we define &lt;em&gt;traversers&lt;/em&gt; that are composed of the following elements:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;the starting node&lt;/li&gt;
&lt;li&gt;the relationship types needing to be traversed&lt;/li&gt;
&lt;li&gt;the stop criteria&lt;/li&gt;
&lt;li&gt;the selection criteria&lt;/li&gt;
&lt;li&gt;traversing order (e.g. breadth first, etc.)&lt;/li&gt;
&lt;/ul&gt;We need to know the starting node so the graph database knows where to start the traversal. The &lt;em&gt;traverser&lt;/em&gt; will then only move along relationships of the types given by the second element of a &lt;em&gt;traverser&lt;/em&gt;, evaluate the selection criteria to know which nodes are relevant tot he "query", then evaluate whether the stop criteria applies to know when traversing should stop.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Indexers:&lt;/strong&gt; In Neo4J there are several indexing utilities backed by a Lucene backend that make it easy to index actual nodes, full text and based on timelines.  This allows us to look up relevant starting nodes for traversing.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;h4&gt;How can graph databases overcome relational database shortcomings?&lt;/h4&gt;Now we will have a quick peak at how the new concepts and ideas from graph databases can resolve the complaints I had about relational databases:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;In response to &lt;em&gt;A lot of real world data isn't highly structured (only partially)&lt;/em&gt;: with graph databases we only need to set the properties a specific node actually has.  We do not need to fill in lots of &lt;code&gt;nulls&lt;/code&gt; in attributes that aren't relevant like we do in RDBMSes.  Our graph database "model" interface might be able to add any constraints that are necessary.  While, in situations where highly structured data sets really do occur, I prefer having two sets of constraints - those on the relational database level and those in the "model" (application tier) - however, it can quickly become hard to manage when two sets of constraints that should be identical are defined in vastly different ways (languages).&lt;/li&gt;
&lt;li&gt;In response to &lt;em&gt;Object to relational mapping (ORM) constraints and disjoints&lt;/em&gt;: using nodes and relationships conceptually on the graph database layer you have little if any translation between 'objects' that represent nodes or relationships.&lt;/li&gt;
&lt;li&gt;In response to &lt;em&gt;Weak and inefficient "traversal" support&lt;/em&gt;: this isn't a problem with graph databases.  Traversing data is much more relevant when dealing with data that is naturally in a network or graph formation already.  Relational databases cannot handle networks or graph-like data sets without a lot of workarounds.&lt;/li&gt;
&lt;li&gt;In response to &lt;em&gt;Maintaining and evolving relational schemas&lt;/em&gt;: when the data sets you are dealing with are not highly structured and densely populated evolving strict data schemas do not need to be maintained and with Neo4J's flexible attribute setting/getting, data structures can be flexibly evolved when the data itself changes, however, this raises another issue of application code being able to read the old attributes in the graph database, but I will talk about that in Part 3.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;h4&gt;Gay marriage: the graph database solution&lt;/h4&gt;&lt;script src="http://gist.github.com/354659.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/7391614450100476192/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=7391614450100476192" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/7391614450100476192" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/7391614450100476192" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/UvGp3jyLmnM/draft-why-proponents-of-marriage.html" title="DRAFT: Why proponents of marriage equality should love graph databases, Part 2: A Reply to 'The Database Engineering Perspective'" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>4</thr:total><feedburner:origLink>http://geek.susanpotter.net/2010/04/draft-why-proponents-of-marriage.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-3872035431659546966</id><published>2010-03-13T10:28:00.003-06:00</published><updated>2010-04-03T20:58:56.047-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="neo4j" /><category scheme="http://www.blogger.com/atom/ns#" term="nosql" /><category scheme="http://www.blogger.com/atom/ns#" term="gay marriage" /><title type="text">Why proponents of marriage equality should love graph databases, Part 1: A Reply to 'The Database Engineering Perspective'</title><content type="html">This is a response to the excellent &lt;a href="http://qntm.org/gay" target="_blank"&gt;Gay marriage: the database engineering perspective&lt;/a&gt; blog post from November 2008 by Sam Hughs.  The only discussion that didn't happen in his blog post was offering a NOSQL alternative to the gay marriage database problem, but I will not hold it against Sam Hughs because it was a comprehensive look at relational database schema designs for modelling marriage!&lt;br /&gt;
&lt;br /&gt;
This response is a little dabble (i.e. not as thorough as the original post) into how graph databases could model monogamous same sex marriages without much problem and also allow for polyamorous marriages quite naturally.  My goal here is to demonstrate how graph databases provide a great amount of flexibility without very much work at all, especially when the data application is just as concerned with connections between entities (aka records in RDBMS or nodes in graph databases) than just the entities themselves.&lt;br /&gt;
&lt;br /&gt;
First off I want to look at the inherent problems with modelling real world data in relational databases and how the approach of graph databases can overcome many, if not all, of these problems.  Then I will launch into a specific snippet of code to demonstrate modelling marriages that can be between any two consenting adults rather than just one man and one woman.  Then I hope to outline how this could be extended to model poly amorous (including polygamous) relationships without much more work.  Near the end I will also include a section at the end that discusses shortcomings of the graph database approach as well for completeness.  My discussion will be focused on using &lt;a href="http://neo4j.org/" target="_blank"&gt;Neo4J&lt;/a&gt; as it is the only comprehensive graph database I am aware of that is open source.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Update (2010-03-13):&lt;/strong&gt; Boris (in the comments) mentioned that there is another open source graph database called &lt;a href="http://www.kobrix.com/hgdb.jsp" target="_blank"&gt;HyperGraphDB&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Update (2010-04-03):&lt;/strong&gt; Johannes (via email) told me about &lt;a href="http://infogrid.org/" target="_blank"&gt;InfoGrid&lt;/a&gt;, which looks like a very interesting alternative to Neo4J with a slightly different way of doing things.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;What is wrong with relational databases?&lt;/h3&gt;For the last 14 years I have been using, designing, maintaining and administering relational databases in some capacity as a software programmer, developer, engineer and now as an applications architect.    During that time I have found the following problems with using relational databases:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;strong&gt;A lot of real world data isn't highly structured (only partially):&lt;/strong&gt; this is probably the biggest problem with using relational databases (for everything) the way they are supposed to be.  Sure you can add a blob, clob or text field to a table and add an arbitrary structure of data that depends on the record, which can be parsed by the application, but that would be a violation of all things relational and you would be paying a heavy price for doing this in a relational database depending on how big these "blobs" generally are.  Not to mention you miss out on query-ability, which is something relational databases do well on highly structured datasets with the relevant indexes defined and a decent attempt at normalization.  &lt;em&gt;Note: I think relational databases are a fine thing when utilized to model data that truly is highly structured in the wild where the entities, not the relationships matter the most.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Object to relational mapping (ORM) constraints and disjoints:&lt;/strong&gt; For almost a decade I have been using ORM libraries such as TOPLink (Java), Persistence (C++), Hibernate (Java), ActiveRecord (Ruby), DataMapper (Ruby), SQLObject (Python) and others.  They each had their own specific problems at times, but they also possessed a set of common problems that resulted in creating a far from seamless integration between the object oriented layer (that a vast number of business systems and web applications are currently written with today) and the distinct properties of a relational database.  These common object to relational constraints and disjointedness is not an &lt;abbr title="Object-Relational Mapper"&gt;ORM&lt;/abbr&gt; tool issue, rather it is a problem of trying to shove a round pin into a square hole (paraphrasing a comment made in page 3 of &lt;a href="http://dist.neo4j.org/neo-technology-introduction.pdf" target="_blank"&gt;'The Neo Database: A Technology Introduction'&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Weak and inefficient "traversal" support:&lt;/strong&gt; When I first started writing rich domain models in the nineties (that is last century for all you whipper-snappers) the focus of design was on the actual &lt;em&gt;entities&lt;/em&gt; not relationships between the entities.  Sure occasionally you had to model a relationship as an "entity", but for the most part you could do your best to reduce your domain relationships as much as possible to a combination of &lt;em&gt;contain a(n)&lt;/em&gt; (aka &lt;code&gt;belongs_to&lt;/code&gt; in ActiveRecord), &lt;em&gt;contained by&lt;/em&gt; (aka &lt;code&gt;has_one&lt;/code&gt; in ActiveRecord), &lt;em&gt;one-to-many&lt;/em&gt; (aka &lt;code&gt;has_many&lt;/code&gt; in ActiveRecord) and/or &lt;em&gt;many-to-many&lt;/em&gt; (aka &lt;code&gt;has_and_belongs_to_many&lt;/code&gt; in ActiveRecord) as much as possible because you can't attach attributes to relationships in a relational database unless you attempt to make it an entity.  If you are interested in deep and/or rich object graphs, however, you have to pay the penalty in any &lt;abbr title="Relational Database Management Systems"&gt;RDBMS&lt;/abbr&gt; with multiple joins, which are an expensive operation.  Even with all the right indices defined and queries optimized you will find more than three levels of indirection (aka &lt;code&gt;JOIN&lt;/code&gt;s) will take a while on even a medium sized dataset.  So as application developers, we are forced to add lazy loading and/or customized eager loading logic into our rich object domain layer for a number cases where performance matters, which in my view pollutes business logic and makes the code less maintainable going forward.  This is far from ideal.  It is also not ideal that data set traversal patterns change with new the introduction of new features, so often you will need to fork lazy loading logic in the business logic layer to satisfy you new requirements.  Adding a lot more complexity to manage in the application tier.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maintaining and evolving relational schemas:&lt;/strong&gt; modifying relational database schemas has always been a little tricky at best.  Today I take advantage of using ActiveRecord's "migrations" that loosely orders (by creation timestamp) a set of relational schema modifications to run (and we wrote a simple extension to wrap them in a transaction to save our sanity - why wasn't that the default to begin with? anyway...).  Even though there is a method to the madness now, it is still a little crazy, especially when it comes time to run these migrations on the production server.  I always miss a heart beat or two when I run the &lt;code&gt;rake db:migrate RAILS_ENV=production&lt;/code&gt; command (yes, even after taking a snapshot).&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
It has been fun thinking out loud, but I have stuff to do today.  Hey, I sometimes have a life, honest!:)  So I have made an outline of what is to come in the next parts of this topic.  I have already written some (bad) Java code to model same-sex and opposite-sex marriages consistently using a graph database (in this case Neo4J), but I plan on offering a Python snippet too, since I really can't stand the look of Java any more and the API doesn't make the case of Graph Databases for those coming from more terser feeling languages like Python, Ruby, Haskell, Erlang, Javascript (well if you use sane APIs like jQuery at least).&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;What is coming in Part 2?&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;How can graph databases overcome relational database shortcomings?&lt;/li&gt;
&lt;li&gt;Gay marriage: the graph database solution&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;h3&gt;What is coming in Part 3?&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Poly amorous marriage using a graph database&lt;/li&gt;
&lt;li&gt;Graph databases: problems to watch out for&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/3872035431659546966/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=3872035431659546966" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/3872035431659546966" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/3872035431659546966" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/M_PCnsPFfHM/why-proponents-of-marriage-equality.html" title="Why proponents of marriage equality should love graph databases, Part 1: A Reply to 'The Database Engineering Perspective'" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://geek.susanpotter.net/2010/03/why-proponents-of-marriage-equality.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-5314403100358772015</id><published>2010-01-30T21:27:00.015-06:00</published><updated>2010-01-30T22:27:16.565-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="agile software" /><category scheme="http://www.blogger.com/atom/ns#" term="agile" /><category scheme="http://www.blogger.com/atom/ns#" term="agile methods" /><category scheme="http://www.blogger.com/atom/ns#" term="agile process" /><category scheme="http://www.blogger.com/atom/ns#" term="agile practices" /><title type="text">How agile practices improve code review</title><content type="html">&lt;p&gt;On a mailing list recently someone posed a question about how to incorporate code reviews into an "agile methodology".  While I had questions about the way the question was posed it got me thinking about how agile practices make code review happen more often, more organically and more transparently.  Having different members of the team review code at different times during the development process on agile projects is both explicit, but also implicit.&lt;/p&gt;
&lt;h4&gt;Values&lt;/h4&gt;
&lt;p&gt;Let us back up a little here.  First off &lt;em&gt;agile&lt;/em&gt; is at its core a set of four ideals.  Prefer:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;strong&gt;individuals and interactions&lt;/strong&gt; &lt;em&gt;over&lt;/em&gt; processes and tools&lt;/li&gt;&lt;li&gt;&lt;strong&gt;working software&lt;/strong&gt; &lt;em&gt;over&lt;/em&gt; complete documentation&lt;/li&gt;&lt;li&gt;&lt;strong&gt;customer involvement&lt;/strong&gt; &lt;em&gt;over&lt;/em&gt; contract negotiation&lt;/li&gt;&lt;li&gt;&lt;strong&gt;adapting to changing needs&lt;/strong&gt; &lt;em&gt;over&lt;/em&gt; completing a stale plan&lt;/li&gt;&lt;/ul&gt;
&lt;h4&gt;Principles/Tenets&lt;/h4&gt;
&lt;p&gt;From these ideals there are about 10 or so principles or tenets that are most commonly discussed among agile practitioners from most of the main camps.  This is where it starts getting controversial as some agile camps acknowledge some of these principles and others do not necessarily, so here are just a few that I want to talk about in relation to increasing code review on agile projects:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Collective team ownership of product:&lt;/strong&gt; meaning everyone on the team owns the product and nobody on the team is exclusive to just one or a couple of components of the product.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Embracing change:&lt;/strong&gt; instead of continuing down a set path determined long ago that no longer applies, the team needs to adapt to customer's changing requirements at set (and regular) intervals (these might be called iteration planning meetings/negotiations, for example).  This has various implications throughout the iteration/sprint.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Verify expectations continuously:&lt;/strong&gt; meaning whenever possible, without impeding development, verify that customer expectations will be satisfied and no new additions have negative impacts.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Customers set priorities:&lt;/strong&gt; instead of technical staff or outsourcing companies specifying technical priorities, customers specify business/feature priorities.&lt;/li&gt;&lt;/ul&gt;
&lt;h4&gt;Practices&lt;/h4&gt;
&lt;p&gt;This is the point where we start seeing the translation into agile &lt;em&gt;practices&lt;/em&gt;, many of while you will start to recognize:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Pair programming&lt;/strong&gt; which arose from both &lt;em&gt;collective team ownership&lt;/em&gt; and &lt;em&gt;embracing change&lt;/em&gt; tenets.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Test-first&lt;/strong&gt; practice came about mostly to satisfy &lt;em&gt;embracing change&lt;/em&gt;, but also &lt;em&gt;verify expectations continuously&lt;/em&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Assigning new stories independently of previous ones&lt;/strong&gt;. This means that no developer or pair has a niche component or product area and is used to satisfy the first tenet listed above.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Continuous integration&lt;/strong&gt; that helps satisfy the &lt;em&gt;verify expectations continously&lt;/em&gt; principle.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;No fear refactoring&lt;/strong&gt;, which is only advisable if your test/spec suite has good enough coverage,.  This means you will likely revise poorly constructed code on agile projects vs non-agile projects more often and have the chance to do it more often too.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Obviously with the pair programming practice that some agile methods promote, you have another set of eyes reviewing code as it is written.  This catches errors closer to the time it was written, which is a big time (and money) saver.&lt;/p&gt;
&lt;p&gt;Applying a test-first approach means that you start out defining custom expectations of the code first before writing the actual code.  This is reviewing, perhaps not code in the traditional way, but the requirements, which in my view is even more productive usually.&lt;/p&gt;
&lt;p&gt;When a project manager assigns new stories to a developer or a pair without confining him/her/them to specific areas of the codebase, this increasing the transparency of the codebase and exposes hidden dragons to be exposed before too long and hopefully before being launched into production (but you never know).  Again this increasing the number of eye balls on parts of the codebase.&lt;/p&gt;
&lt;p&gt;With continuous integration you can incorporate metric tools to capture some metrics of the code so that parts of the code that are obviously in need to technical refactoring get highlighted earlier rather than later.  Increasing transparency of the codebase, which is always a goal of code reviews.&lt;/p&gt;
&lt;p&gt;Hopefully you can see where I am going with this and not think about code reviews in the traditional top-down way where every month or quarter a piece of code is reviewed from each developer in a formal way.&lt;/p&gt;
&lt;p&gt;There are a number of different agile (and common) software practices that could be used, I can think of 4 more off the top of my head that improves codebase visibility across more of the team.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/5314403100358772015/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=5314403100358772015" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/5314403100358772015" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/5314403100358772015" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/TGsxkMuJE0A/how-agile-practices-improve-code-review.html" title="How agile practices improve code review" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>4</thr:total><feedburner:origLink>http://geek.susanpotter.net/2010/01/how-agile-practices-improve-code-review.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-3163473251174310759</id><published>2010-01-17T18:37:00.006-06:00</published><updated>2010-01-17T19:05:04.199-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="ruby on rails" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="rubyonrails" /><title type="text">So Long, Farewell, Auf Wiedersehen, Goodbye...to Ruby &amp; Rails (sort of)</title><content type="html">&lt;p&gt;It's been obvious to many of my close geek comrades that for the last 18-22 months I have been getting more and more frustrated with the Ruby community and the "quality" of products in this space.  The quality of people in the Ruby field has been tending towards the average PHP developer (PHP is a gateway drug for programming - i.e. not something to aspire to) and the recent Ruby mindset (as a whole though some dark corners still look interesting) has not been about doing things differently, but rather blending in with mainstream ideas.  For some that is exciting as it means not fighting management just to get to use Ruby in the enterprise.  &lt;strong&gt;I understand, I really do.&lt;/strong&gt;  Fighting management on technical platform is never fun.&lt;p&gt;

&lt;p&gt;I think it is safe to say the direction of the major libraries and frameworks that are prominent in the Ruby landscape will suffer from very similar conceptual limitations as the Java, J2EE and JEE frameworks that DHH once ridiculed (for good reason).  Of course, this is all to be expected in the usage lifecycle of a programming language.  In fact, I believe I predicted that I would get bored of Ruby in a blog post in 2006 within the next few years though it doesn't make this any easier.&lt;p&gt;

&lt;h4&gt;Thanks mates!&lt;/h4&gt;
&lt;/p&gt;I wish all friends in the Ruby and Rails worlds luck (I think you'll need it) and I thank (ex-)coworkers and project collaborators that have taught me something new for all the intellectual stimulation you have provided me.  I am sad to be saying goodbye to those of you.&lt;/p&gt;

&lt;h4&gt;But...&lt;/h4&gt;
&lt;p&gt;I look forward to grazing new pastures.  I will be working on my next generation financial products using the right tool for each primary job.  Currently most of the &lt;strong&gt;Finsignia Platform&lt;/strong&gt; is quite back-end and different pieces could take advantage of Haskell's concurrency and/or Erlang distribution.  Yet there will inevitably need to be (at some point) rich web applications for UI, so (J)Ruby and Rails I might come knocking on your door again, but for now, &lt;em&gt;adiós&lt;/em&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/3163473251174310759/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=3163473251174310759" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/3163473251174310759" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/3163473251174310759" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/YmZo_y_RD0w/so-long-farewell-auf-wiedersehen.html" title="So Long, Farewell, Auf Wiedersehen, Goodbye...to Ruby &amp; Rails (sort of)" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://geek.susanpotter.net/2010/01/so-long-farewell-auf-wiedersehen.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-649821935183669240</id><published>2009-09-29T21:59:00.007-05:00</published><updated>2009-09-29T22:18:34.152-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="business analysis" /><category scheme="http://www.blogger.com/atom/ns#" term="Cloud Computing" /><title type="text">Cloud Computing, Part 2: Law, Privacy &amp; Maturity</title><content type="html">At the CEO roundtable event I mentioned in my previous blog post about in &lt;a href="http://geek.susanpotter.net/2009/09/cloud-computing-part-1-delivery-models.html" target="_new"&gt;Cloud Computing, Part 1&lt;/a&gt; the other major business consideration that came up was how to protect your business' (and/or customers') assets properly.  Ultimately anyone that wants to build a solid foundation for their business needs to tackle this well to be successful long-term.

One person asked the speaker to elaborate about a recent case where a UK bank used servers in datacenters inside India where a datacenter employee stole customer information and used it to effectively steal money from these people's accounts for his own benefit.  This could happen in any country, however, in this case this datacenter employee actually didn't break any laws inside of India (or broke one very minor law that had a very limited penalty).  Ultimately this lack of relevant law and regulation in a foreign country is the major risk for a business using offshore datacenter resources.

Unfortunately I didn't hear the name of the bank involved to be able to find a news article about this incident, however, the speaker had heard about this incident (it wasn't just a figment of the questioners imagination) and his response (I am paraphrasing here) was:
&lt;blockquote&gt;Countries with the most mature infrastructure, laws, regulations and standards regarding data and information law (as well as privacy) will probably be the places that larger firms will invest in for sensitive and mission critical systems of their organization despite the likely higher cost of building.&lt;/blockquote&gt;

As you determine whether you are going to be a cloud consumer or provider in the future, make sure to keep an eye on these risk factors as some executives seem to only focus on the raw bottom line without conducting a thorough risk analysis to see if the cost savings are really worth the higher risks.  Choose the best cloud computing partners for all your cost trimming AND risk mitigation needs.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/649821935183669240/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=649821935183669240" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/649821935183669240" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/649821935183669240" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/86J1WL5TAL8/cloud-computing-part-2-law-privacy.html" title="Cloud Computing, Part 2: Law, Privacy &amp; Maturity" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://geek.susanpotter.net/2009/09/cloud-computing-part-2-law-privacy.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-3272923407562795826</id><published>2009-09-11T21:10:00.011-05:00</published><updated>2009-09-11T22:39:26.005-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Cloud Computing" /><title type="text">Cloud Computing, Part 1: Delivery Models</title><content type="html">&lt;p&gt;Today I went to a regional CEO Roundtable lunch talk given by &lt;a href="http://cs.illinois.edu/people/faculty/roy-campbell" target="_new"&gt;Professor Roy Campbell at &lt;acronym title="University of Illinois at Urbana-Champaign"&gt;UIUC&lt;/acronym&gt;&lt;/a&gt; on Cloud Computing and why executives of any kind of business should care.&lt;/p&gt;
&lt;p&gt;While I am not new to the concepts of cloud computing and multi-tenancy SaaS, since I have consumed various cloud services and designed multi-tenant architectures for two previous clients.  However, there was one particular "overview" slide that Professor Campbell showed that got me thinking a little.  It was titled Delivery Models.&lt;/p&gt;
&lt;p&gt;It was a text slide with bullets, but I think a diagram (or two) could have communicated to the higher-level audience more than most of the first half of his presentation could have (see below and let me know if it is more effective).&lt;/p&gt;
&lt;p&gt;I especially liked Professor Campbell's categorization of the Delivery Models.  Until this lunch time I had really only considered there to be two cloud delivery models: &lt;acronym title="Software as a Service"&gt;SaaS&lt;/acronym&gt; and &lt;acronym title="Platform as a Service"&gt;PaaS&lt;/acronym&gt;.  I wasn't making a distinction between Amazon services like S3 and EC2 and that of Google's AppEngine.  On reflection, I am glad I took two hours out of my busy Friday if only to consider the distinction made in this talk.&lt;/p&gt;
&lt;p&gt;In a nutshell the slide has three major bullets:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Software as a Service&lt;/li&gt;
  &lt;li&gt;Platform as a Service&lt;/li&gt;
  &lt;li&gt;Infrastructure as a Service&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nice!  Google AppEngine, essentially being an application container (that supports various frameworks now), is a platform, whereas S3 and EC2 provide infrastructure on demand.&lt;/p&gt;
&lt;p&gt;Now unfortunately this is where Campbell left it.  For those of us not unfamiliar with cloud computing, we can see the importance of this distinction so that we can develop a more solid business plan (for those of us that might be interested in using the cloud to generate revenue from).  It may also help technically savvy people that aren't familiar with the cloud.&lt;/p&gt;
&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_YUkA0L0Czls/SqsNB413zaI/AAAAAAAAAIw/_iJREHeogXs/s1600-h/CloudComputing-DeliveryModel.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 283px; height: 400px;" src="http://4.bp.blogspot.com/_YUkA0L0Czls/SqsNB413zaI/AAAAAAAAAIw/_iJREHeogXs/s400/CloudComputing-DeliveryModel.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5380408505913560482" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hope this helps people make a choice between container services like AppEngine or Heroku (platform) and those such as S3 and EC2 (infrastructure) from a consumer side and perhaps those devising business models to focus on their core competencies.&lt;/p&gt;
&lt;p&gt;Next time I want to talk about privacy, legal and compliance issues surrounding Cloud Computing as well as how business should weigh the risk of outsourcing their data handling (however that happens) to countries will less mature laws, regulation and oversight.  Perhaps &lt;em&gt;cloud governance&lt;/em&gt; would be the most appropriate term?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/3272923407562795826/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=3272923407562795826" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/3272923407562795826" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/3272923407562795826" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/vvwNEFg-tL4/cloud-computing-part-1-delivery-models.html" title="Cloud Computing, Part 1: Delivery Models" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_YUkA0L0Czls/SqsNB413zaI/AAAAAAAAAIw/_iJREHeogXs/s72-c/CloudComputing-DeliveryModel.png" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://geek.susanpotter.net/2009/09/cloud-computing-part-1-delivery-models.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-915986941225105528</id><published>2009-09-10T21:42:00.007-05:00</published><updated>2009-09-10T21:52:46.752-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Alan Turing" /><title type="text">Alan Turing Can Now Rest In Peace</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.number10.gov.uk/wp-content/uploads/number10door474-300x254.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 300px; height: 254px;" src="http://www.number10.gov.uk/wp-content/uploads/number10door474-300x254.jpg" border="0" alt="" /&gt;&lt;/a&gt;
&lt;p&gt;
While I am by no means the biggest fan of the New Labour government in my homeland (mostly due to Blair's sociopathic reign), I have to give Gordon Brown props (or at least his aids) for giving credit to Alan Turing and saying Britain, as a country, fucked up big time (sorry, I really couldn't think of another phrase that matched the intensity - I'll replace it if you suggest a good alternative).
&lt;/p&gt;
&lt;p&gt;
You can read the Downing Street blog post here:&lt;br/&gt;
&lt;a href="http://www.number10.gov.uk/Page20571" target="_new"&gt;Treatment of Alan Turing was “appalling” - PM&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
Thanks from this particular graduate from University of the Manchester's Mathematics department who now works as a software engineer who also happens to be gay!&lt;/p&gt;
&lt;p&gt;"Ta luv", as the Manc locals would say.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/915986941225105528/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=915986941225105528" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/915986941225105528" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/915986941225105528" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/lMLA8uUKPdE/alan-turing-can-now-rest-in-peace.html" title="Alan Turing Can Now Rest In Peace" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://geek.susanpotter.net/2009/09/alan-turing-can-now-rest-in-peace.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-5096397482927613381</id><published>2009-09-09T19:07:00.012-05:00</published><updated>2009-09-10T08:09:41.452-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="data" /><category scheme="http://www.blogger.com/atom/ns#" term="ruby on rails" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><title type="text">Faker, Ruby on Rails Snippet &amp; Generator</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_YUkA0L0Czls/SqhxBu4ZNzI/AAAAAAAAAIo/33EMivvSZsw/s1600-h/twitter-screenshot.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 218px;" src="http://2.bp.blogspot.com/_YUkA0L0Czls/SqhxBu4ZNzI/AAAAAAAAAIo/33EMivvSZsw/s400/twitter-screenshot.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5379674029472429874" /&gt;&lt;/a&gt;

Hey blog readers (if there are any left),

I know it has been a while, and I know I have left you high and dry, so today I decided I will share some code and software development thoughts with you.

I am moving to a more snippet oriented blog posting style from now on.  Previously I preferred &lt;a href="http://geek.susanpotter.net/2007/06/java-dogma-and-downfall.html" target="_new"&gt;long ramblings about the political ideology of programming languages&lt;/a&gt; and even &lt;a href="http://geek.susanpotter.net/2007/10/democratic-debate-ann-coulter-and.html" target="_new"&gt;how Ann Coulter was _more_ comprehensible when I used my Metafusion Crypto library&lt;/a&gt; on her words (actually that was a marketing lie - she sounded just as incomprehensible using &lt;a href="http://github.com/mbbx6spp/metafusion/tree/master/crypto"&gt;Metafusion Crypto&lt;/a&gt; as she did when not using it).  Of course, this was all in 2006-2007 when blogging was all about spewing small tidbits that taught the reader nothing, so I had to be different and attempt to find a reason for things.  Now things are swinging so I am trying to do the opposite from the norm again.

Ok, on with it.

Over the last week I have been using the Rails 2.3.4 "seed" mechanism, which in essence attempts to provide 80% of seed-fu's features inside Rails core.  In addition on my personal projects I have been using machinist as my factory framework of choice (although I am forced to use factory_girl for my clients), through which I was introduced to faker.  A beautiful gem indeed.

So to cut a long story short, I have found myself doing the following a hell of a lot in my brand new Rails 2.3.4 projects this week:
&lt;code class="ruby"&gt;
# in db/seeds.rb
def load_seed_files!
  seed_files = Dir["#{RAILS_ROOT}/db/seeds/all/*.rb"] + Dir["#{RAILS_ROOT}/db/seeds/#{RAILS_ENV}/*.rb"]
  seed_files.each do |file|
    puts "Loading seed file: #{file}"
    load(file)
  end
end

load_seed_files!
# When I add files to the db/seeds/all directory it seed ALL environments
# When I add files to the db/seeds/{development,staging,test,production} directories it seeds 
# for only that environment.
&lt;/code&gt;
Note: I wouldn't recommend using seeds in just staging, test or production generally.  If you need seed data in these environments you _probably_ need them in all environments OR (in the case of the test environment) you need to use a factory framework like machinist or factory_girl.

Now where is faker?  Well it's what I use inside these .rb files where faker comes into play:
&lt;code&gt;
# Faking a company name
&gt;&gt; Faker::Company.name
=&gt; "King-Ruecker"
&gt;&gt; Faker::Company.name
=&gt; "Cartwright, Prosacco and Smith"
&gt;&gt; Faker::Company.name
=&gt; "Pagac, Adams and Barrows"
&gt;&gt; Faker::Company.name
=&gt; "Satterfield and Sons"
&gt;&gt; Faker::Company.name
=&gt; "Blick-Deckow"

# Faking a person's name
&gt;&gt; Faker::Name.first_name
=&gt; "Ruthe"
&gt;&gt; Faker::Name.first_name
=&gt; "Jameson"
&gt;&gt; Faker::Name.first_name
=&gt; "Avery"
&gt;&gt; Faker::Name.first_name
=&gt; "Jordan"
&gt;&gt; Faker::Name.first_name
=&gt; "Ruthe"
&gt;&gt; Faker::Name.first_name
=&gt; "Winona"
&gt;&gt; Faker::Name.last_name
=&gt; "Brown"
&gt;&gt; Faker::Name.last_name
=&gt; "Hayes"
&gt;&gt; Faker::Name.last_name
=&gt; "Jerde"
&gt;&gt; Faker::Name.last_name
=&gt; "Lindgren"
&gt;&gt; Faker::Name.last_name
=&gt; "Considine"
&gt;&gt; Faker::Name.last_name
=&gt; "Rodriguez"
&gt;&gt; Faker::Name.last_name
=&gt; "Turner"
&gt;&gt; Faker::Name.name
=&gt; "Mekhi Lebsack"
&gt;&gt; Faker::Name.name
=&gt; "Esteban Brown"
&gt;&gt; Faker::Name.name
=&gt; "Velma Crona"
&gt;&gt; Faker::Name.name
=&gt; "Rollin Zemlak"
&gt;&gt; Faker::Name.name
=&gt; "Casper Sanford"

# My favorite is coming up with BS (yes, BS is what you think it is):
&gt;&gt; Faker::Company.bs
=&gt; "redefine ubiquitous e-commerce"
&gt;&gt; Faker::Company.bs
=&gt; "synergize viral e-business"
&gt;&gt; Faker::Company.bs
=&gt; "innovate real-time experiences"
&gt;&gt; Faker::Company.bs
=&gt; "aggregate scalable systems"
&gt;&gt; Faker::Company.bs
=&gt; "e-enable back-end functionalities"
&gt;&gt; Faker::Company.bs
=&gt; "implement 24/365 models"
&lt;/code&gt;
So the point of faker, if you haven't already figured out is that it generates data the way you would probably have in production so you are generating meaningful data in your development environment(s) where you want to show your client what the interface will look like with data inside.

&lt;b&gt;Now a word of caution:&lt;/b&gt; I would not advise you to use this in an end-user facing test environment.  I sometimes call that staging or qa, but ultimately it is an environment where real end-users or clients test out the features in a stable environment (not development or continuous integration environment) so they can sign off on your stories.  In these environments you should let the user create the data themselves using the admin forms or whatever UI you provide them because you want to see how they will break the system (and we all know they will somehow).  It gives you a much better indication of how things will end up working in production, which is very important.

Thanks for reading and let me know if this is yet again too rambly?  How does it happen?  I have the best intentions to just blurt out tidbits with no nuance, yet I always end up rambling on about things and give it a thought process (well sort of).  Anyone want to be my editor to strip out all thought and insight so I can be just blog brainless "tip" blog posts like everyone else in the Rails community that wanted to be a micro celebrity (trust me I couldn't handle that kind of paparazzi attention and I don't even have a Macbook Pro to sling over my shoulder in a fashionable messenger bag)?  I can't pay you anything, but you could share in my measely $0.63 that Google Adsense pays me each month (actually they don't actually pay until a threshold is met).  You could buy one third of an MP3 from iTunes each month.  Any takers?  What an awesome deal!  No really!

PS Coming soon a simple generator and Rails application template (or applate as I like to call them) that will set you up with this so you don't have to copy and paste all the time.  It'll be on GitHub.com/mbbx6spp.  Ta ta.

&lt;b&gt;Update:&lt;/b&gt; As Damien in the comments pointed out indirectly, I really didn't do Faker justice.  Please read the &lt;a href="http://faker.rubyforge.org/rdoc/" target="_new"&gt;Faker RDocs&lt;/a&gt; for more information.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/5096397482927613381/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=5096397482927613381" title="7 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/5096397482927613381" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/5096397482927613381" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/KKAeRf4yRKw/faker-ruby-on-rails-snippet-generator.html" title="Faker, Ruby on Rails Snippet &amp; Generator" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_YUkA0L0Czls/SqhxBu4ZNzI/AAAAAAAAAIo/33EMivvSZsw/s72-c/twitter-screenshot.png" height="72" width="72" /><thr:total>7</thr:total><feedburner:origLink>http://geek.susanpotter.net/2009/09/faker-ruby-on-rails-snippet-generator.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-5982449507200889600</id><published>2009-07-03T10:05:00.006-05:00</published><updated>2009-07-03T10:44:46.751-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="design patterns" /><title type="text">Design Patterns Book Club</title><content type="html">I just discovered that &lt;a href="http://www.ustream.tv/channel/hashrocket" target="_new"&gt;Hashrocket has a video book club&lt;/a&gt; where people can join in the conversation with a live videocast on USTREAM or watch older episodes on their own schedule.  They are currently going through &lt;a href="http://www.amazon.com/Design-Patterns-Ruby-Addison-Wesley-Professional/dp/0321490452/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1246633743&amp;sr=8-1&amp;tag=supo-20"&gt;Russ Olson's Design Patterns in Ruby&lt;/a&gt;.

This is a great idea, kudos to Hashrocket.

I watched the latest episode on the &lt;a href="http://www.ustream.tv/recorded/1700942" target="_new"&gt;Strategy pattern&lt;/a&gt; and had a couple of thoughts I would love Desi and the rest of Hashrocket to consider for subsequent episodes:
&lt;ul&gt;&lt;li&gt;I liked that this specific episode wasn't very long (I know you were a little worried)&lt;/li&gt;&lt;li&gt;I think discussing anti-patterns that could be solved with this pattern you are discussing the episode is very valid (as the person sitting next to Desi said).  Perhaps that could be explored more.  Note: I have only seen that one episode so perhaps you do this in other episodes much more, but if you don't please consider it, because I feel that anti-patterns are very important to identify.  &lt;strong&gt;&lt;em&gt;Think of the design patterns as the treatment or medicine and the anti-patterns as the symptoms.  Physicians need to be acutely aware of the symptoms and symptom combinations to be effective at prescribing the best course of treatment or medication.  Therefore we should be teaching software engineers in the same way.&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Also please consider putting the name of the design pattern under discussion in the title of the video for archival purposes.&lt;/li&gt;&lt;/ul&gt;
Thanks goes to Hashrocket for the great idea and work of putting it together!  It's about time the Ruby community starts to mature w.r.t. language-neutral concepts and these efforts will hopefully help those that came into software development from a less formal software engineering education path (I used to be one of them and had to learn from scratch myself) with a little more assistance. It was pretty lonely bookwork and experimental projects for me to learn this stuff when I first started out.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/5982449507200889600/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=5982449507200889600" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/5982449507200889600" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/5982449507200889600" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/p40r110hrVM/design-patterns-book-club.html" title="Design Patterns Book Club" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://geek.susanpotter.net/2009/07/design-patterns-book-club.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-5308617635880711251</id><published>2009-05-29T13:00:00.013-05:00</published><updated>2009-06-02T10:16:47.337-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Jabber" /><category scheme="http://www.blogger.com/atom/ns#" term="SOA" /><category scheme="http://www.blogger.com/atom/ns#" term="HTTP" /><category scheme="http://www.blogger.com/atom/ns#" term="Google Wave" /><category scheme="http://www.blogger.com/atom/ns#" term="Service Oriented Architecture" /><category scheme="http://www.blogger.com/atom/ns#" term="web services" /><category scheme="http://www.blogger.com/atom/ns#" term="google" /><category scheme="http://www.blogger.com/atom/ns#" term="XMPP" /><title type="text">Google Wave is not the answer, XMPP is!</title><content type="html">Since yesterday afternoon (my time) all over the Twittersphere (and blogosphere) I kept hearing a ton of great reviews of the Google Wave API/protocol and how it will revolutionize communication and collaboration on the web.

This morning I watched the Google Wave demonstration from yesterday and I have to say I am completely underwhelmed considering everyone else's reactions were ridiculously positive and had nothing measured or thoughtful to say about it.

You can find my initial reaction of it, &lt;a href="http://tumblelog.susanpotter.net/post/114911182/google-wave-is-just-a-simple-xmpp-extension-shrink"&gt;&lt;em&gt;"Google Wave is just a simple &lt;acronym title="Extensible Messaging and Presence Protocol"&gt;XMPP&lt;/acronym&gt; extnesion"&lt;/em&gt;, on my tumblelog&lt;/a&gt;.

As someone that has had to write &lt;acronym title="Extensible Messaging and Presence Protocol"&gt;XMPP&lt;/acronym&gt; extensions for clients and my own internal apps, servers, API interfaces (mostly distributed monitoring of services, but a few more for media processing) I am saddened that anyone would think the current Google Wave protocol (which is just an &lt;acronym title="Extensible Messaging and Presence Protocol"&gt;XMPP&lt;/acronym&gt; extension) is extraordinarily ground breaking.  There have been a number of existing extensions that tried to do VERY VERY similar things already and specific features of Google Wave were already exactly defined.

What made the demonstration of Google Wave yesterday &lt;em&gt;appear&lt;/em&gt; so impressive were the applications: the wave client and the web embedding.  The responsiveness of the web application really made it stand out, NOT the underlying Google Wave protocol/API.

For those who have never really gotten their hands dirty with &lt;acronym title="Extensible Messaging and Presence Protocol"&gt;XMPP&lt;/acronym&gt; in any real technical way, I expected they would not really know what it already provided in &lt;acronym title="Extensible Messaging and Presence Protocol"&gt;XMPP&lt;/acronym&gt;.  Many &lt;em&gt;"geeks"&lt;/em&gt; hyping up Google Wave seemed to think &lt;acronym title="Extensible Messaging and Presence Protocol"&gt;XMPP&lt;/acronym&gt; only supported instant messaging.  That just happened to be the most popular and apparent &lt;acronym title="Extensible Messaging and Presence Protocol"&gt;XMPP&lt;/acronym&gt; extension, which many people call Jabber.  &lt;acronym title="Extensible Messaging and Presence Protocol"&gt;XMPP&lt;/acronym&gt; itself is a lot more far reaching than just an instant messaging protocol and the fact that Google Wave was based on top of &lt;acronym title="Extensible Messaging and Presence Protocol"&gt;XMPP&lt;/acronym&gt; should tell you how flexible it is.  Yes that is right, Google may not have really made a big deal about it (why would they if they can get extra credit when it isn't due), but Google Wave &lt;strong&gt;is&lt;/strong&gt; just an &lt;acronym title="Extensible Messaging and Presence Protocol"&gt;XMPP&lt;/acronym&gt; extension and compared to other extensions I have had to interface with, not a particularly complicated one.

Sure the &lt;strong&gt;&lt;em&gt;applications&lt;/em&gt;&lt;/strong&gt; that Google demonstrated as part of the Google Wave presentation were nifty for personal communication, but are they really ground breaking, multipurpose, or ubiquitous?  No, it is only as ground breaking, multipurpose and ubiquitous as it's applications make it.

Let us all now return to earth for a moment and praise Google for the things they do really well like web applications, but let us not pretend that Google is the mover and shaker in terms of the visionary of future underlying protocols.  They still advocate developing &lt;acronym title="HyperText Transfer Protocol"&gt;HTTP&lt;/acronym&gt; applications for the future.

HyperText Transfer Protocol (&lt;acronym title="HyperText Transfer Protocol"&gt;HTTP&lt;/acronym&gt;) is virtually on every digital device made by man today, but does it really lend itself to providing the distributed service oriented architecture we should be striving for and the protocol of the &lt;em&gt;future&lt;/em&gt;?  REST is not about the &lt;acronym title="HyperText Transfer Protocol"&gt;HTTP&lt;/acronym&gt; protocol.  RESTful APIs can be creating in a number of ways and through a lot of different protocols.

My take is (from a technical level) &lt;acronym title="Extensible Messaging and Presence Protocol"&gt;XMPP&lt;/acronym&gt; ought to be the protocol of the future, NOT &lt;acronym title="Extensible Messaging and Presence Protocol"&gt;XMPP&lt;/acronym&gt; on just the back-end and then adding tons of bloatware in between the client and the service just so that we can create an API or UI on top of an antiquated protocol (&lt;acronym title="HyperText Transfer Protocol"&gt;HTTP&lt;/acronym&gt;) that has seen better days.

Anyone want to create a truly modular &lt;acronym title="Extensible Messaging and Presence Protocol"&gt;XMPP&lt;/acronym&gt; "browser" for the new &lt;em&gt;"web"&lt;/em&gt; with me?  Email &lt;code&gt;me&lt;/code&gt; at &lt;code&gt;susanpotter&lt;/code&gt; dot &lt;code&gt;net&lt;/code&gt; if you want to join the future.  

UPDATE: Please subscribe to the &lt;a href="http://groups.google.com/group/jointhefuture" target="_new"&gt;"Join the Future" Google Group&lt;/a&gt; if you want to get involved in the XMPP browser project.

&lt;h4&gt;Related Links&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://xmpp.org/" target="_new"&gt;XMPP Standards Foundation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://xmpp.org/protocols/" target="_new"&gt;XMPP Protocols&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://xmpp.org/extensions/" target="_new"&gt;XMPP Open Extensions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/5308617635880711251/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=5308617635880711251" title="12 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/5308617635880711251" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/5308617635880711251" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/OSee13OPVFM/google-wave-is-not-answer-xmpp-is.html" title="Google Wave is not the answer, XMPP is!" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>12</thr:total><feedburner:origLink>http://geek.susanpotter.net/2009/05/google-wave-is-not-answer-xmpp-is.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-9189369663339915909</id><published>2009-05-20T16:13:00.004-05:00</published><updated>2009-05-20T16:53:58.937-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="functional programming" /><category scheme="http://www.blogger.com/atom/ns#" term="currying" /><category scheme="http://www.blogger.com/atom/ns#" term="erlang" /><title type="text">Erlang doesn't support currying? News to me!</title><content type="html">I keep seeing developers who only glance at Erlang and think that &lt;strong&gt;currying&lt;/strong&gt; isn't supported.  &lt;strong&gt;Nothing could be further from the truth...&lt;/strong&gt;&lt;em&gt;unless you are defining &lt;strong&gt;currying&lt;/strong&gt; support only in terms of specific syntactic sugar in a language for currying.&lt;/em&gt;

So let us step back and define what currying support really means:
&lt;blockquote&gt;
Currying is the process of transforming a function that takes multiple arguments into a function that takes just a single argument and returns another function if any arguments are still needed.
&lt;cite&gt;&lt;a href="http://www.haskell.org/haskellwiki/Currying" target="_new"&gt;http://www.haskell.org/haskellwiki/Currying&lt;/a&gt;&lt;/cite&gt;
&lt;/blockquote&gt;

Let us look at a simple (but hopefully not too contrived, albeit it _slightly_ contrived) example:
&lt;pre&gt;&lt;code&gt;
%% currying_example.erl
-module(currying_example).

-compile([export_all]).

multiply(X, Y) -&gt; X*Y.
doubler() -&gt; fun(X) -&gt; multiply(2, X) end.
&lt;/code&gt;&lt;/pre&gt;
In your erl shell try the following:
&lt;pre&gt;&lt;code&gt;
1&gt; c(currying_example).
{ok,currying_example}
2&gt; D = currying_example:doubler().
#Fun&lt;currying_example.0.96239340&gt;
3&gt; D(6).
12
4&gt; q().
ok
&lt;/code&gt;&lt;/pre&gt;

As you can see in the module code above, Erlang supports what is called &lt;em&gt;anonymous functions&lt;/em&gt; (e.g. fun (X) -&gt; somePredefineFunction(OtherVarOrConst, X) end), which then allows us to manufacture single argument functions in a way that is clear and expressive in the code IMO.

For those that haven't been following the functional programming debates over the last week or two around the blogosphere, please see the following blog posts (some are pretty funny and will make you smile at least twice with their intended absurdity):
&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://enfranchisedmind.com/blog/posts/scala-not-functional/" rel="nofollow" target="_new"&gt;Scala is not a functional programming language&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.reddit.com/goto?id=8krbo" rel="nofollow" target="_new"&gt;Erlang is not a programming language&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://conal.net/blog/posts/the-c-language-is-purely-functional/" rel="nofollow" target="_new"&gt;The C language is purely functional&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://12monkeys.co.uk/2009/05/16/erlang-is-pragmatic.html" rel="nofollow" target="_new"&gt;Erlang is pragmatic&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

Previous posts on this blog that are related are:
&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://geek.susanpotter.net/2009/04/scala-vs-erlang-debate-part-1-managers.html"&gt;Scala vs Erlang Debate, Part 1: Manager's Overview&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://geek.susanpotter.net/2009/04/scala-vs-erlang-debate-part-2-geek-off.html"&gt;Scala vs Erlang Debate, Part 2: Geek Off&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

I will try to put together a few snippets on currying support in Python, Javascript and Ruby tonight after my Greek class (which I am late for now) if I have time as a quick exercise:)&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/9189369663339915909/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=9189369663339915909" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/9189369663339915909" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/9189369663339915909" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/Eg5UrbGiCQY/erlang-doesnt-support-currying-news-to.html" title="Erlang doesn't support currying? News to me!" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://geek.susanpotter.net/2009/05/erlang-doesnt-support-currying-news-to.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-4349350825811956698</id><published>2009-05-18T12:16:00.005-05:00</published><updated>2009-05-18T12:39:49.008-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="open source" /><category scheme="http://www.blogger.com/atom/ns#" term="oss" /><category scheme="http://www.blogger.com/atom/ns#" term="twitter twitter4r" /><category scheme="http://www.blogger.com/atom/ns#" term="REST" /><category scheme="http://www.blogger.com/atom/ns#" term="twitter4r" /><category scheme="http://www.blogger.com/atom/ns#" term="twitter" /><category scheme="http://www.blogger.com/atom/ns#" term="opensource" /><title type="text">Twitter4R 0.3.1 and the future</title><content type="html">Hi Twitter4R users,

I know I have been rather absent in terms of my Twitter4R contributions and ongoing development, but despite my absence I have &lt;em&gt;_finally_&lt;/em&gt; officially released 0.3.1 with a lot more new features and a few bug fixes more than I initially expected to release 0.3.1 with.

Some of the goodies included in the official 0.3.1 release are:
&lt;ul&gt;&lt;li&gt;Added &lt;em&gt;raw&lt;/em&gt; Twitter Search API support.  Meaning you can use any of the HTTP parameters the Twitter HTTP-based Search API will expect.  E.g. &lt;code&gt;twitter.search(:to =&gt; "twitter4r", :rpp =&gt; 10)&lt;/code&gt; or &lt;code&gt;twitter.search(:q =&gt; "twitter4r", :rpp =&gt; 15, :geocode =&gt; "40.112186,-88.207592,250km")&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Profile, theme API coverage on Twitter REST API.&lt;/li&gt;&lt;li&gt;Social Graphing API. E.g. &lt;code&gt;twitter.graph(:friends, user)&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Added "reply" support at all levels (low-level to model-level)&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Bugfix:&lt;/strong&gt; the infamous &lt;code&gt;URI.encode&lt;/code&gt; to &lt;code&gt;CGI.escape&lt;/code&gt; change.&lt;/li&gt;&lt;li&gt;Rate limit information (still needs to be able to support the HTTP header method, which I actually suggested to Twitter developers some time back, but they only recently added it when my bandwidth for OSS contribution was minimal) :(&lt;/li&gt;&lt;li&gt;&lt;a href="http://wiki.github.com/mbbx6spp/twitter4r/twitter4r-0-3-1-development-release"&gt;much more&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;

Now the future of the Twitter4R project.  I have made a LOT of mistakes with this Twitter4R OSS project venture, so I am going to try to fix a bunch of these things:
&lt;ul&gt;&lt;li&gt;Create a new set of Git repos on GitHub that separates the education portions (screencast, etc.) from the core source code of the project so that people do not need to download ridiculous amounts of data to their local drive just to fork Twitter4R on GitHub as it required at present.  &lt;strong&gt;Announcements about this will be coming soon!&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Have a consistent issue tracking system for Twitter4R.  Previously it has appeared inconsistent to users of the Twitter4R library where to submit defect reports or new feature requests to.  So I have had to field these requests from the Google Groups mailing list to personal emails and also @twitter4r replies on Twitter.  &lt;strong&gt;I plan on using GitHub's new issue tracking system for this as it seems a logical extension.&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;I plan on documenting things a little more obviously on the official website from now one.  It appears many users did not want to go to the RDoc unless specifically pointed to it, even though a large majority of the library is fairly well documented in the RDocs.&lt;/li&gt;&lt;/ul&gt;

Please be patient while I fix these process/marketing/workflow issues of the project and in the mean time I will also be &lt;strong&gt;tackling OAuth support&lt;/strong&gt; as well.

Again thanks for your patience thus far and tweet me on twitter at either &lt;a href="http://twitter.com/SusanPotter" target="_new"&gt;@SusanPotter&lt;/a&gt; or &lt;a href="http://twitter.com/twitter4r" target="_new"&gt;@twitter4r&lt;/a&gt; if you have suggestions or questions about the direction.  If you have specific queries on using the actual API, please join the twitter4r-users Google Groups mailing list and search the archives for a solution first and then if you can't find a solution, please post a message giving the group members your environment details and the version of Twitter4R you are using.

Thanks!
Susan
Twitter4R Developer&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/4349350825811956698/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=4349350825811956698" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/4349350825811956698" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/4349350825811956698" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/n8S63x40eqA/twitter4r-031-and-future.html" title="Twitter4R 0.3.1 and the future" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>6</thr:total><feedburner:origLink>http://geek.susanpotter.net/2009/05/twitter4r-031-and-future.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-5726300406977243992</id><published>2009-04-20T15:47:00.028-05:00</published><updated>2010-02-11T23:08:24.198-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="functional programming" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="erlang" /><category scheme="http://www.blogger.com/atom/ns#" term="scalability" /><category scheme="http://www.blogger.com/atom/ns#" term="scala" /><category scheme="http://www.blogger.com/atom/ns#" term="jvm" /><category scheme="http://www.blogger.com/atom/ns#" term="concurrency" /><title type="text">The Scala vs Erlang Debate, Part 2: The Geek Off</title><content type="html">In the &lt;a href="http://geek.susanpotter.net/2009/04/scala-vs-erlang-debate-part-1-managers.html"&gt;first part of The Scala vs Erlang Debate&lt;/a&gt; article series, I discussed various ways to go about adopting either Scala or Erlang and in what scenarios it made sense to go with one over the other from the manager's perspective.    In summary the major advantage of Scala is that it runs on the &lt;acronym title="Java Virtual Machine"&gt;JVM&lt;/acronym&gt; so it can access pre-existing Java libraries your enterprise has already developed.  This is also Scala's major disadvantage because it makes a rather large assumption (which in my opinion would be incorrect the majority of the time) that the Java libraries being used are thread-safe.  Erlang on the other hand doesn't allow you to integrate in the same OS process with Java libraries, because Erlang was built from the ground up with scalability and fault-tolerence in mind and ideally you shouldn't put Java into the run-time stack because it compromises Erlang's fault-tolerance features significantly.  Instead the preferred approach when writing the biggest bottlenecks of your system in Erlang and integrating with pre-existing Java libraries/system is to use &lt;acronym title="Service Oriented Architecture"&gt;SOA&lt;/acronym&gt; to create separate, but integrated systems that are easy to swap out and upgrade at a later point.  In my view, you should be refactoring your enterprise architecture by defining services anyway, since this will decouple systems and remove a great deal of headaches in IT maintenance and deployment.  Today I wanted to geek out and differentiate the two environments on a more technical level for the middle/technical managers.&lt;h4&gt;Scala: Technical Overview&lt;/h4&gt;Scala is an objected oriented, statically typed language with many functional programming capabilities built-in.  However, it must be noted (because few Scala documents do this) that Scala is hybrid actor programming language and therefore a number of assumptions cannot be made.  So by being a hybrid functional language it losses some of the benefits.  As well as it's Java run-time support on the &lt;acronym title="Java Virtual Machine"&gt;JVM&lt;/acronym&gt; it is also supported in Microsoft's Common Language Runtime (&lt;acronym title="Common Language Runtime"&gt;CLR&lt;/acronym&gt;) so .NET integration, in theory, is a breeze.  Again this also assumes that the .NET libraries you use from Scala are thread-safe.  On a related topic, .NET also has F# available, which is Microsoft's attempt at a &lt;em&gt;hybrid&lt;/em&gt; functional programming language also.  I have no comment on F# myself, since I have zero experience with it.  Please chime in on the comments section if you have experience with F# and are able to contrast it with Scala.  &lt;h4&gt;Erlang: Technical Overview&lt;/h4&gt;Erlang on the other hand is a dynamic, purer functional programming language that supports light-weight processes in its own run-time environment (separate from &lt;acronym title="Operating System"&gt;OS&lt;/acronym&gt; processes), which send messages to each other asynchronously.  One major side effect of being purer in its actor treatment is that there is virtually &lt;strong&gt;not state&lt;/strong&gt;.  There is no way to pass "state" around (a couple of minor exceptions), but there is a &lt;em&gt;lambda calculus&lt;/em&gt; optimization that can be taken advantage of that will ease away our troubles called &lt;em&gt;tail-recursion&lt;/em&gt;.  Tail-recursion only partially works in Scala.  For many developers that only have experience in procedural and Object-Oriented (&lt;acronym title="Object Oriented"&gt;OO&lt;/acronym&gt;) programming languages like Java, Python, Ruby, C++, C, Perl, C# this sounds completely &lt;em&gt;insane&lt;/em&gt;.  Two years ago I may have agreed with you, but today life is much simpler without state in my Erlang travels than when I had to write thread-safe Java code and I wish I had discovered this concept earlier.  I will not pretend this notion didn't take some getting used to but today I see things a lot clearer and I am thankful for that clarity.  &lt;h4&gt;Scala: Concurrency&lt;/h4&gt;Concurrency in Scala is modeled using a concept of &lt;em&gt;actors&lt;/em&gt;, except there are two types of &lt;em&gt;actors&lt;/em&gt;: thread-based and event-based actors.  Since Scala was implemented on top of the &lt;acronym title="Java Virtual Machine"&gt;JVM&lt;/acronym&gt;, which is stack-based, Scala had to compromise on Erlang's one actor approach.  This is because native threads, which the &lt;acronym title="Java Virtual Machine"&gt;JVM&lt;/acronym&gt; uses for concurrency support, are much heavier-weight than Erlang's lightweight processes thus reducing the number of thread-based actors that could be launched inside one &lt;acronym title="Java Virtual Machine"&gt;JVM&lt;/acronym&gt;.  So Scala created this concept of a very peared down event-based actor, which does not have all the functionality of thread-based actors but does not incur the penalty of needing to be backed by a native thread.  To be as complete as I can be in this section I should also note that Scala treats everything as an object, even though it has these two types of actors.  Actors in Scala are just objects.  In turn this may create duplication between objects and actors.  &lt;h4&gt;Erlang: Concurrency&lt;/h4&gt;The Erlang &lt;acronym title="Virtual Machine"&gt;VM&lt;/acronym&gt; was built from the bottom up with lightweight processes (a.k.a. actors), therefore it is stackless and much better at lightweight concurrency.  Erlang also has a built-in mechanism for load balancing these lightweight processes across all available CPU cores.  This means Erlang has a massive advantage over JVM based functional programming languages at getting the most out of multi-core hardware, which is at the crux of the problem domain that software needs to address going forward.  &lt;h4&gt;Scala vs. Erlang: Performance&lt;/h4&gt;In terms of linear performance (sequential) Scala has been shown to beat Erlang in certain cases.  However, concurrent performance consistently shows Erlang beating Scala, sometimes by wide margins on multi-core hardware.  Not surprising considering what we learned in the concurrency sections above.  When considering the problem we are trying to overcome - optimizing software on multi-core hardware - it seems clear which of these benchmarks are more important! :)  &lt;h4&gt;Conclusion&lt;/h4&gt;I think it is clear, which side of this debate I firmly stand, but I have tried to demonstrate both good and bad traits of each programming language from a technical perspective that might translate into a business case or reason for choosing one over the other in your organization.  If I have time I might do a part 3, which will talk a little about syntax and DSL support.  This might round out the argument since it could be argued that Scala wins in the third part by a hair, but all is not lost for Erlang if the underlying problem you need to solve is related to optimizing software for modern hardware and building robust systems at the same time.  My vote still goes to Erlang despite the lack of built-in features that make designing &lt;acronym title="Domain Specific Language"&gt;DSL&lt;/acronym&gt;s easier, but it is not difficult to build your own &lt;acronym title="Domain Specific Language"&gt;DSL&lt;/acronym&gt; engine in Erlang either.  &lt;h4&gt;Limitations of this series:&lt;/h4&gt;There are quite a few topics I left out of this post that might be of interest for some applications or services.  Namely: &lt;ul&gt;&lt;li&gt;&lt;strong&gt;Hot swapping:&lt;/strong&gt; Erlang has great hot swapping capabilities for production environments that minimizes or possibly eliminates downtime of systems.  This feature in Scala is not close in capability or reliability at this point.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Garbage collection:&lt;/strong&gt; without getting into too many details Erlang probably wins this section by a hair (not significant to write home about).  Long sweeps will not be a problem in Erlang and only a problem in JVM languages on rare occasions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Distributed nodes:&lt;/strong&gt; The clear winner here would be Erlang because built-in to the environment are all the multi-node features that make distributed systems a breeze.  Scala on the other hand has different frameworks and libraries to facilitate distributing nodes of logic on different hosts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[Added Nov-2009] Frameworks:&lt;/strong&gt; As far as I know, Scala doesn't have an OTP killer, not even a contender to compete with Erlang's Open Telephony Platform (OTP).  Sure it will take some time, even Haskell, which has been around much longer than Scala is slightly jealous of OTP (I saw the way Don Stewart looked at me when I asked him if Haskell had framework similar to OTP;) ).  Supervision trees along make it stand out as the best thing since sliced bread, at least for this particular software engineer.&lt;/li&gt;
&lt;/ul&gt;&lt;h4&gt;Resources:&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://geek.susanpotter.net/2009/04/scala-vs-erlang-debate-part-1-managers.html"&gt;The Scala vs Erlang Debate, Part 1: The Manager's Overview&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;h4&gt;Corrections (added February 2010):&lt;/h4&gt;&lt;ul&gt;  &lt;li&gt;Erlang is not a pure functional language.  However, it does not have a polluted (impure) treatment of actors like Scala:)  Some think this is a good-enough approach to be able to leverage the JVM, when running on the JVM is really important, perhaps 4 times out of 5 it might be "good enough".  I just wonder if it really matters for most projects that you run on the JVM!?&lt;/li&gt;
  &lt;li&gt;"Scala's lack of tail recursion is entirely due to a trade-off. The JVM doesn't do tail recursion itself. It is possible to add tail recursion on top of the JVM using various tricks, but they are expensive. SISC does its own stack based heap and Kawa uses trampolining." -- James Iry&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/5726300406977243992/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=5726300406977243992" title="26 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/5726300406977243992" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/5726300406977243992" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/-SZI4YxqZ5Y/scala-vs-erlang-debate-part-2-geek-off.html" title="The Scala vs Erlang Debate, Part 2: The Geek Off" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>26</thr:total><feedburner:origLink>http://geek.susanpotter.net/2009/04/scala-vs-erlang-debate-part-2-geek-off.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-9116860869510075065</id><published>2009-04-15T09:37:00.017-05:00</published><updated>2009-04-15T11:36:34.775-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="functional programming" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="erlang" /><category scheme="http://www.blogger.com/atom/ns#" term="scala" /><category scheme="http://www.blogger.com/atom/ns#" term="jvm" /><category scheme="http://www.blogger.com/atom/ns#" term="concurrency" /><title type="text">The Scala vs Erlang Debate, Part 1: The Managers Overview</title><content type="html">&lt;em&gt;Note: The discussion is primarily between Scala and Erlang, but other languages could potentially be substituted in the arguments for and against.  Scala stands for any language that attempts to solve the multi-core issue software developers face with threads and Erlang is a language that has light weight processes which solves the biggest issue of going with a multi-process solution in software.&lt;/em&gt;

The debate started with the realization that Moore's Law died a while ago.  Tomorrow (as we see it now) is destined for multi-cores.

A problem of massive proportions now faces software engineers, since hardware engineers changed the rules on us.  Now I am not giving hardware engineers a hard time, I am simply pointing out that there has been a massive shift in the way hardware is built, which directly affects the performance and reliability of the software which runs on it.  It is not a transparent change that software engineers can ignore.

With that background laid out, as software engineers, we must appreciate the problem we now have to tackle, both server-side and client-side developers alike will need to tackle these issues promptly.  However, this article only considers server-side software as there is where my specialized expertise lies.  This part of the article is the high-level.  I'll get into the specifics in the second part.

So the question now is how do we leverage the advantage given to us by new hardware progress of multi-cores?

There are two fundamentally different problems to solve: software products/projects that already have large complex systems already built in languages that support threads half-decently such as in Java and JVM languages including Scala; but there are also those startups that don't have baggage and can start with a better long-term solution by using a true concurrent language like Erlang.

&lt;h3&gt;The Legacy Enterprise&lt;/h3&gt;
The problem with utilizing JVM threading (whether directly in Java or via other languages built on the JVM such as Scala) is that third party code you use or existing Java/JVM code written isn't necessarily thread-safe.  You might have all your business entities and models defined in Java, but can it really be threaded?

The pain of migrating or porting your existing system from a JVM language to another truly concurrent language like Erlang might be much greater than dealing with threading issues in just a few key bottleneck areas that will increase throughput and CPU utilization &lt;strong&gt;enough&lt;/strong&gt;.  In this case I doubt many pragmatic engineers or architects will advocate starting from scratch in a language you know little (if anything) about.  However, identifying those key pain points might take some time, but will be a necessary cost if you are serious about solving this problem in the near-term using a solution like Scala.

However, what these engineers and architects should stress to management is that this is likely to become a monkey patch.  There will be a tipping point where moving to a pure concurrent language like Erlang would be more beneficial that sticking to the monkey patch and living on the JVM forever, no matter what Sun tries to tell you.

There are hybrid solutions for the medium-term, that depending on the project/enterprise specifics may be a good solution until you are able to fully port the code to a langauge like Erlang (or whatever the trend may be at the time you get to it).  &lt;acronym title="Service Oriented Architecture"&gt;SOA&lt;/acronym&gt; principles can be used to design and define a meaningful architecture that will declutter the system and allow you to tackle just the bottlenecks of the system in an Erlang port/rewrite and still give you (the manager) a low risk &lt;acronym title="Proof of Concept"&gt;PoC&lt;/acronym&gt; project so you can evaluate Erlang in your enterprise.

Having worked on a number of large enterprise projects where &lt;em&gt;upgrading&lt;/em&gt; the "legacy" system was the goal, I know full well that management are likely to prefer the monkey patches (i.e. Scala where the pain of rewriting components in a PoC way doesn't exceed the pain of threading your existing code at the bottlenecks), especially when the middle/technical managers do not highlight the drawbacks of the "solution" adequately.  Three to nine months later the management (especially middle management) are hurting big time, but it is not usually the most appropriate time to do your &lt;em&gt;"I told you so dance"&lt;/em&gt;.  Trust me!:)

The the monkey patch isn't an ideal solution when you are simply trading one complexity of equal of greater value for the other and in 2-5 years the likelihood that there will be many more skilled engineers and architects that truly understand and have solid production experience in a truly concurrent language like Erlang is high in my estimation, so making a move to such a language/environment would not be as risky at that time.  However, for 2-5 years you have been getting little out of your hardware and software together unless you overbuy hardware.  In fact, in the case where legacy code already exists, there is never really an ideal solution.  However, starting out with meaningful &lt;acronym title="Proof of Concept"&gt;PoC&lt;/acronym&gt;s and structuring low risk exit points after conducting objective evaluations of these projects is key to the success of every "legacy solution".  If in doubt and your legacy system isn't showing signs of hurting yet, you might want to wait and beef up on hardware.  This is a transition period and if you are in a conservative IT enterprise this might be a better near-term approach.

&lt;h3&gt;Startups&lt;/h3&gt;
Now for the startups or those starting afresh, there is mixed news: very good news and not-so-bad news.  

Green field projects, in theory, are always the best.  You can get everything right from day one....well at least you can hope to do so (let us pretend for this article).  My advise for your team is to take the plunge to Erlang.  It is actually relatively low risk to do so for the following reasons:
&lt;ul&gt;
  &lt;li&gt;It is a mature language and environment already tested by large and complex real world systems at telcos where reliability and scalability were and are top priorities.&lt;/li&gt;
  &lt;li&gt;There are a few good books out there on that will help you convert to Erlang and Functional Programming (see resources section below), although documentation and education on Erlang, generally, is somewhat lacking.&lt;/li&gt;
  &lt;li&gt;A framework for services has been designed, developed and put into production called OTP, which stands for the Open Telephony Platform and actually nothing specific to Telephony applications in it, it was simply developed by a Telco.&lt;/li&gt;
&lt;/ul&gt;

Erlang's approach to concurrency is interesting and takes some getting used to as it is a pure functional programming language unlike Scala which is a hybrid.  

Now the bad news is that there are very few people that know Erlang (or other pure concurrent languages), you need to hire at least one specialist with Erlang experience to guide your team to avoid the potholes and perhaps even stop you before you get to the edge of a cliff.  They might not be cheap, but starting out it will mitigate project risk significantly.

Another negative on the Erlang side of the argument is that you will not be able to use your Java classes straight from within Erlang (in a meaningful way - I'll cover this in the next part).  The positive about this negative though is that you can encapsulate your Java code in an SOA way so that you can decouple and declutter subsystems within your enterprise, which is an important task to do regardless of which legacy solution you choose.

Finally, good luck and let me know how it goes!

&lt;h4&gt;Resources&lt;/h4&gt;
&lt;h5&gt;&lt;a href="http://www.amazon.com/gp/product/193435600X?ie=UTF8&amp;tag=illinilistn09-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=193435600X"&gt;Programming Erlang: Software for a Concurrent World&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=illinilistn09-20&amp;l=as2&amp;o=1&amp;a=193435600X" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt; by Joe Armstrong&lt;/h5&gt;
&lt;p&gt;This book, for the moment, is the definitive guide for Erlang.  If you have already decided to go the Erlang route then you will not mind (or perhaps not even notice) the "selling" of Erlang throughout the book.  Overall this is an essential book to anyone learning Erlang at this point.&lt;/p&gt;

&lt;h5&gt;&lt;a href="http://www.amazon.com/gp/product/0596514980?ie=UTF8&amp;tag=illinilistn09-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0596514980"&gt;Real World Haskell&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=illinilistn09-20&amp;l=as2&amp;o=1&amp;a=0596514980" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/h5&gt;
&lt;p&gt;While Haskell isn't either Scala or Erlang, if you do not come from a functional programming frame of mind you will need a good book to introduce you gently into the realm of functional programming.  This book does a pretty good job.  While the syntax for Haskell is different to both Erlang and Scala, the hardest part of moving to functional programming isn't the syntax.  Trust me on this one:)&lt;/p&gt;

Also consider me, &lt;a href="http://www.linkedin.com/in/susanpotter"&gt;Susan Potter&lt;/a&gt;, a resource if you need an Erlang software engineer with high-level enterprise architecture background in Java/J2EE/JEE and Ruby/Rails production environments.  I am developing a risk management product in Erlang right now and I am available as a consultant through my consulting firm &lt;a href="http://finsignia.com"&gt;Finsignia&lt;/a&gt;, which mostly works with financial services firms such as investment banks and hedge funds, which is where my business domain expertise lies, but also works on designing, building and deploying reliable and robust server-side solutions for any industry.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/9116860869510075065/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=9116860869510075065" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/9116860869510075065" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/9116860869510075065" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/034c2a7mtmk/scala-vs-erlang-debate-part-1-managers.html" title="The Scala vs Erlang Debate, Part 1: The Managers Overview" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>4</thr:total><feedburner:origLink>http://geek.susanpotter.net/2009/04/scala-vs-erlang-debate-part-1-managers.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-297445119338360086</id><published>2009-04-04T20:13:00.005-05:00</published><updated>2009-04-04T20:34:05.044-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="chambana" /><category scheme="http://www.blogger.com/atom/ns#" term="BarCamp" /><category scheme="http://www.blogger.com/atom/ns#" term="champaign urbana" /><title type="text">CUBarCamp: Champaign-Urbana's Tech Meetup Update</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_YUkA0L0Czls/SdgGQQ9SN4I/AAAAAAAAAHw/wgEm9qlUa_A/s1600-h/CUBarCamp.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 186px;" src="http://2.bp.blogspot.com/_YUkA0L0Czls/SdgGQQ9SN4I/AAAAAAAAAHw/wgEm9qlUa_A/s400/CUBarCamp.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5321009836237928322" /&gt;&lt;/a&gt;

This is just an update blog post to let geeks in and around the Champaign-Urbana area know that the CU BarCamp is now scheduled for April 25th, 2009.  The meetup will start at 2pm CDT and will be located at the Collective Turf Coworking space:
&lt;address&gt;110 W. Main Street
Urbana, IL 61801&lt;/address&gt;

It is right between the Heartland Gallery and Priceless Books and opposite the Urbana Business Association office and Crane Alley.

&lt;h3&gt;Want to participate?&lt;/h3&gt;
If you want to volunteer, present or demo any topics at this BarCamp please update the &lt;A href="http://barcamp.org/CUBarCamp"&gt;CUBarCamp wiki page&lt;/a&gt; and join the &lt;a href="http://groups.google.com/group/cubarcamp"&gt;Google Group for the CU BarCamp event&lt;/a&gt;.

Hope to see you there!&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/297445119338360086/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=297445119338360086" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/297445119338360086" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/297445119338360086" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/ICPaBOXSZyw/cubarcamp-champaign-urbanas-tech-meetup.html" title="CUBarCamp: Champaign-Urbana's Tech Meetup Update" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_YUkA0L0Czls/SdgGQQ9SN4I/AAAAAAAAAHw/wgEm9qlUa_A/s72-c/CUBarCamp.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://geek.susanpotter.net/2009/04/cubarcamp-champaign-urbanas-tech-meetup.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-7094876133553155591</id><published>2009-03-27T18:59:00.005-05:00</published><updated>2009-03-27T19:14:48.886-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="YUI" /><category scheme="http://www.blogger.com/atom/ns#" term="CSS" /><title type="text">YUI MenuBar: A Facebook-like Application Bar</title><content type="html">&lt;p&gt;Below is a snippet of HTML code with embedded Javascript code that will create a top anchored menu bar very similar to what you see at the bottom of the Facebook page:&lt;/p&gt;

&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;!-- Add the following to your HTML/HEAD --&amp;gt;
&amp;lt;link rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; href=&amp;quot;http://yui.yahooapis.com/2.7.0/build/fonts/fonts-min.css&amp;quot;&amp;gt;
&amp;lt;link rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; href=&amp;quot;http://yui.yahooapis.com/2.7.0/build/menu/assets/skins/sam/menu.css&amp;quot;&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;http://yui.yahooapis.com/2.7.0/build/yahoo-dom-event/yahoo-dom-event.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;http://yui.yahooapis.com/2.7.0/build/container/container_core-min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;http://yui.yahooapis.com/2.7.0/build/menu/menu-min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;
YAHOO.util.Event.onDOMReady(function () {
  var oMenuBar = new YAHOO.widget.MenuBar(&amp;quot;menubar&amp;quot;);
  oMenuBar.render();
});
&amp;lt;/script&amp;gt;

&amp;lt;!-- in your HTML/BODY modify the following for your own &amp;quot;Facebook Application Bar&amp;quot; menu --&amp;gt;
&amp;lt;div id=&amp;quot;menubar&amp;quot; class=&amp;quot;yuimenubar&amp;quot;&amp;gt;
  &amp;lt;div class=&amp;quot;bd&amp;quot;&amp;gt;
    &amp;lt;ul class=&amp;quot;first-of-type&amp;quot;&amp;gt;
      &amp;lt;li class=&amp;quot;yuimenubaritem first-of-type&amp;quot;&amp;gt;
        &amp;lt;a class=&amp;quot;yuimenubaritemlabel&amp;quot; href=&amp;quot;#file&amp;quot;&amp;gt;Applications&amp;lt;/a&amp;gt;
        &amp;lt;div id=&amp;quot;file&amp;quot; class=&amp;quot;yuimenu&amp;quot;&amp;gt;
          &amp;lt;div class=&amp;quot;bd&amp;quot;&amp;gt;
            &amp;lt;ul&amp;gt;
              &amp;lt;li class=&amp;quot;yuimenuitem&amp;quot;&amp;gt;
                &amp;lt;a class=&amp;quot;yuimenuitemlabel&amp;quot; href=&amp;quot;#&amp;quot;&amp;gt;Notes&amp;lt;em class=&amp;quot;helptext&amp;quot;&amp;gt;Ctrl + N&amp;lt;/em&amp;gt;&amp;lt;/a&amp;gt;
              &amp;lt;/li&amp;gt;
              &amp;lt;li class=&amp;quot;yuimenuitem&amp;quot;&amp;gt;
                &amp;lt;a class=&amp;quot;yuimenuitemlabel&amp;quot; href=&amp;quot;#&amp;quot;&amp;gt;Links&amp;lt;em class=&amp;quot;helptext&amp;quot;&amp;gt;Ctrl + L&amp;lt;/em&amp;gt;&amp;lt;/a&amp;gt;
              &amp;lt;/li&amp;gt;
              &amp;lt;li class=&amp;quot;yuimenuitem&amp;quot;&amp;gt;
                &amp;lt;a class=&amp;quot;yuimenuitemlabel&amp;quot; href=&amp;quot;#open&amp;quot;&amp;gt;Photos&amp;lt;em class=&amp;quot;helptext&amp;quot;&amp;gt;Ctrl + P&amp;lt;/em&amp;gt;&amp;lt;/a&amp;gt;
                &amp;lt;div id=&amp;quot;open&amp;quot; class=&amp;quot;yuimenu&amp;quot;&amp;gt;
                  &amp;lt;div class=&amp;quot;bd&amp;quot;&amp;gt;
                      &amp;lt;ul class=&amp;quot;first-of-type&amp;quot;&amp;gt;
                        &amp;lt;li class=&amp;quot;yuimenuitem&amp;quot;&amp;gt;
                            &amp;lt;a class=&amp;quot;yuimenuitemlabel&amp;quot; href=&amp;quot;#&amp;quot;&amp;gt;Upload Album&amp;lt;/a&amp;gt;
                        &amp;lt;/li&amp;gt;
                        &amp;lt;li class=&amp;quot;yuimenuitem&amp;quot;&amp;gt;
                            &amp;lt;a class=&amp;quot;yuimenuitemlabel&amp;quot; href=&amp;quot;#&amp;quot;&amp;gt;Browse Albums&amp;lt;/a&amp;gt;
                        &amp;lt;/li&amp;gt;
                      &amp;lt;/ul&amp;gt;            
                  &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;            
              &amp;lt;/li&amp;gt;
            &amp;lt;/ul&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/li&amp;gt;
      &amp;lt;li class=&amp;quot;yuimenubaritem first-of-type&amp;quot;&amp;gt;
        &amp;lt;a class=&amp;quot;yuimenubaritemlabel&amp;quot; href=&amp;quot;#&amp;quot;edit&amp;gt;Something Else&amp;lt;/a&amp;gt;
        &amp;lt;div id=&amp;quot;pim&amp;quot; class=&amp;quot;yuimenu&amp;quot;&amp;gt;
          &amp;lt;div class=&amp;quot;bd&amp;quot;&amp;gt;
            &amp;lt;ul class=&amp;quot;first-of-type&amp;quot;&amp;gt;
              &amp;lt;li class=&amp;quot;yuimenuitem&amp;quot;&amp;gt;
                &amp;lt;a class=&amp;quot;yuimenuitemlabel&amp;quot; href=&amp;quot;#&amp;quot;&amp;gt; Bla 1&amp;lt;/a&amp;gt;
              &amp;lt;/li&amp;gt;
              &amp;lt;li class=&amp;quot;yuimenuitem&amp;quot;&amp;gt;
                &amp;lt;a class=&amp;quot;yuimenuitemlabel&amp;quot; href=&amp;quot;#&amp;quot;&amp;gt; Bla 2&amp;lt;/a&amp;gt;
              &amp;lt;/li&amp;gt;
            &amp;lt;/ul&amp;gt;            
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

For further details about customizing the YUI MenuBar look and feel you should visit the &lt;a href="http://developer.yahoo.com/yui/docs/YAHOO.widget.MenuBar.html"&gt;API documentation&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/7094876133553155591/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=7094876133553155591" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/7094876133553155591" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/7094876133553155591" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/x654Tz-8qxo/yui-menubar-facebook-like-application.html" title="YUI MenuBar: A Facebook-like Application Bar" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://geek.susanpotter.net/2009/03/yui-menubar-facebook-like-application.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-7685492460714769518</id><published>2009-02-24T00:04:00.003-06:00</published><updated>2009-02-24T00:12:43.241-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="urbana" /><category scheme="http://www.blogger.com/atom/ns#" term="champaign" /><category scheme="http://www.blogger.com/atom/ns#" term="chambana" /><category scheme="http://www.blogger.com/atom/ns#" term="BarCamp" /><category scheme="http://www.blogger.com/atom/ns#" term="champaign urbana" /><title type="text">CUBarCamp: Champaign-Urbana's Tech Meetup 4/22 (tentatively)</title><content type="html">Just a quick post to mention that with the assistance of &lt;a href="http://www.exampler.com/"&gt;Brian Marick&lt;/a&gt; and hopefully a few more people in the weeks to come, &lt;a href="http://barcamp.org"&gt;BarCamp&lt;/a&gt; is coming to the &lt;a href="http://barcamp.org/CUBarCamp"&gt;Champaign-Urbana area&lt;/a&gt; and is to be held at the Collective Turf Coworking space in downtown Urbana (110 W. Main Street, Urbana, IL - opposite Crane Alley and above Priceless Books).

To keep updated on the latest developments and participate in the event organizing join the &lt;a href="http://groups.google.com/group/CUBarCamp"&gt;CUBarCamp Google Group&lt;/a&gt;.

Hope to see you there!&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/7685492460714769518/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=7685492460714769518" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/7685492460714769518" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/7685492460714769518" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/tqW3dXmT8GA/cubarcamp-champaign-urbanas-tech-meetup.html" title="CUBarCamp: Champaign-Urbana's Tech Meetup 4/22 (tentatively)" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://geek.susanpotter.net/2009/02/cubarcamp-champaign-urbanas-tech-meetup.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-7527602399441387632</id><published>2009-02-09T15:26:00.006-06:00</published><updated>2009-02-09T17:31:03.766-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="coworking" /><title type="text">Coworking Space in Champaign Urbana (Illinois)</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://twitter.com/SusanPotter/status/1193116121"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 222px;" src="http://1.bp.blogspot.com/_YUkA0L0Czls/SZC4RyhnKcI/AAAAAAAAAHg/Js4nD0qOQ4E/s400/tweet-coworking.png" border="0" alt="Tweet from @SusanPotter about starting a Champaign-Urbana Coworking environment/venue" id="BLOGGER_PHOTO_ID_5300939377175112130" /&gt;&lt;/a&gt;

Since I moved to Champaign-Urbana, IL (aka CU) in 2005 I have been looking for work space that would provide me with a more productive environment and social yet professional outlet to work in since I work primarily on telecommute contracts and lack face time with clients.

Today I decided that I will setup a local &lt;strong&gt;coworking&lt;/strong&gt; space for solo entrepreneurs and freelancers in and around the Champaign-Urbana area to fulfill my needs as a consultant and fulfill my new venture urge of late.

Essentially &lt;strong&gt;coworking&lt;/strong&gt; is defined as the following:
&lt;blockquote&gt;
&lt;strong&gt;Coworking&lt;/strong&gt; is a movement to create cafe-like community/collaboration spaces for developers, writers and independents.
&lt;/blockquote&gt;

This is exactly how I imagined my dream work space since I work a lot in coffee shops all around town throughout the work week and even during the weekend sometimes and find it surprisingly (initially) productive.

I have seen these types of office spaces in larger metro areas and the terminology used tends to be different from place to place.  Some terms used to mean a community of independent professionals sharing office space, facilities and amenities that I have come across on my travels include:
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Coworking&lt;/strong&gt; or Co-working (obviously)&lt;/li&gt;
  &lt;li&gt;Collaborative work environments (not used in the context of a company job description:))&lt;/li&gt;
  &lt;li&gt;Work Space Cooperative (this might be organized at the top levels slightly differently though)&lt;/li&gt;
  &lt;li&gt;Shared Work Space&lt;/li&gt;
  &lt;li&gt;Serviced Office Space&lt;/li&gt;
&lt;/ul&gt;

There are probably some slight variants on the definitions of these as compared to that of &lt;strong&gt;coworking&lt;/strong&gt;, so some places will have more structure and a more formal setting, whereas &lt;strong&gt;coworking&lt;/strong&gt; itself strives to create a more creative and collaborative environment for independent professionals.

If you are in the &lt;acronym title="Champaign-Urbana"&gt;CU&lt;/acronym&gt; (East Central Illinois) area and would be interested in working in such a &lt;strong&gt;coworking&lt;/strong&gt; space, please drop me a line at any of the following locations:
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;twitter:&lt;/strong&gt; &lt;a href="http://twitter.com/SusanPotter"&gt;@SusanPotter&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;email:&lt;/strong&gt; me at susanpotter dot net&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;facebook:&lt;/strong&gt; &lt;a href="http://www.facebook.com/people/Susan-Potter/706880787"&gt;My Profile&lt;/a&gt;&amp;nbsp|&amp;nbsp&lt;a href="http://www.facebook.com/group.php?gid=54723272076"&gt;Champaign-Urbana Coworking Group&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

Are you a freelancer or entrepreneur in another area or region that is part of a coworking environment experience there?  What do you like about your coworking space and why?  What would you change about it if you could?&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/7527602399441387632/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=7527602399441387632" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/7527602399441387632" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/7527602399441387632" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/8nIkHPiyibU/coworking-space-in-champaign-urbana.html" title="Coworking Space in Champaign Urbana (Illinois)" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_YUkA0L0Czls/SZC4RyhnKcI/AAAAAAAAAHg/Js4nD0qOQ4E/s72-c/tweet-coworking.png" height="72" width="72" /><thr:total>4</thr:total><feedburner:origLink>http://geek.susanpotter.net/2009/02/coworking-space-in-champaign-urbana.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-704071610769103721</id><published>2009-01-14T23:54:00.006-06:00</published><updated>2009-01-15T00:19:18.447-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="open source" /><category scheme="http://www.blogger.com/atom/ns#" term="gedit" /><category scheme="http://www.blogger.com/atom/ns#" term="oss" /><category scheme="http://www.blogger.com/atom/ns#" term="opensource" /><title type="text">GEdit Extensions Project</title><content type="html">Just a quick post from a long blogging hiatus to let people know that I launched gedit-extensions where I will maintain a set of commonly used GEdit snippets and eventually plugins and tools that others might find useful.

You can view the snippet source at the &lt;a href="http://github.com/finsignia/gedit-extensions/tree/"&gt;GitHub gedit-extensions repository&lt;/a&gt;.  I plan on adding documentation to the &lt;a href="http://wiki.github.com/finsignia/gedit-extensions"&gt;gedit-extensions wiki&lt;/a&gt; in the next couple of days, but for now see the sneak peak in the Ruby example snippets at the end of the post.  

The name in the comments directly above the example snippet is the shortcut you can use.  Type the first few characters of the shortcut and then &lt;tt&gt;Ctl+Space&lt;/tt&gt; key combination to pull up all shortcuts the characters match so far.  Choose the relevant shortcut from the drop down list.  If the snippet contains variables the first variable will be highlighted for your to fill in, then press &lt;tt&gt;TAB&lt;/tt&gt; to navigate to the next variable to fill in.

As you will see most of the shortcuts so far are Ruby, Rails, RSpec or Cucumber specific since there are a few Python snippets I need to untangle from our in-house code references.

&lt;pre&gt;&lt;span class="comment"&gt;# shebang&lt;/span&gt;
&lt;span class="comment"&gt;#!/usr/bin/env ruby&lt;/span&gt;
&lt;span class="comment"&gt;# absrequire&lt;/span&gt;
&lt;span class="ident"&gt;require&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;join&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;dirname&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;__FILE__&lt;/span&gt;&lt;span class="punct"&gt;),&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;config&lt;/span&gt;&lt;span class="punct"&gt;",&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;enviornment&lt;/span&gt;&lt;span class="punct"&gt;")&lt;/span&gt;

&lt;span class="comment"&gt;# habtm&lt;/span&gt;
&lt;span class="ident"&gt;has_and_belongs_to_many&lt;/span&gt; &lt;span class="symbol"&gt;:idiots&lt;/span&gt;
&lt;span class="comment"&gt;# unique&lt;/span&gt;
&lt;span class="symbol"&gt;:unique&lt;/span&gt; &lt;span class="punct"&gt;=&gt;&lt;/span&gt; &lt;span class="constant"&gt;true&lt;/span&gt;
&lt;span class="comment"&gt;# habtmthru&lt;/span&gt;
&lt;span class="ident"&gt;has_and_belongs_to_many&lt;/span&gt; &lt;span class="symbol"&gt;:idiots&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:through&lt;/span&gt; &lt;span class="punct"&gt;=&gt;&lt;/span&gt; &lt;span class="symbol"&gt;:village&lt;/span&gt;

&lt;span class="comment"&gt;# belongsto&lt;/span&gt;
&lt;span class="ident"&gt;belongs_to&lt;/span&gt; &lt;span class="symbol"&gt;:village&lt;/span&gt;

&lt;span class="comment"&gt;# createtable&lt;/span&gt;
&lt;span class="ident"&gt;create_table&lt;/span&gt; &lt;span class="symbol"&gt;:sessions&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
  &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;column&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:string&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:limit&lt;/span&gt; &lt;span class="punct"&gt;=&gt;&lt;/span&gt; &lt;span class="number"&gt;34&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;column&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:description&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:string&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:limit&lt;/span&gt; &lt;span class="punct"&gt;=&gt;&lt;/span&gt; &lt;span class="number"&gt;255&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="comment"&gt;# addindex&lt;/span&gt;
&lt;span class="ident"&gt;add_index&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:sessions&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:name&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="comment"&gt;# changecolumn&lt;/span&gt;
&lt;span class="ident"&gt;change_column&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:sessions&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:limit&lt;/span&gt; &lt;span class="punct"&gt;=&gt;&lt;/span&gt; &lt;span class="number"&gt;70&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

&lt;span class="comment"&gt;# removecolumn&lt;/span&gt;
&lt;span class="ident"&gt;remove_column&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:sessions&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:name&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="comment"&gt;# irreversible&lt;/span&gt;
&lt;span class="keyword"&gt;raise&lt;/span&gt; &lt;span class="constant"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;IrreversibleMigration&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;the reason the migration is irreversible&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;

&lt;span class="comment"&gt;# resource&lt;/span&gt;
&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;PersonResource&lt;/span&gt; &lt;span class="punct"&gt;&lt;&lt;/span&gt; &lt;span class="constant"&gt;ActiveResource&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Base&lt;/span&gt;
  &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;site&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;http://domain.com:8080/&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;
  &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;element_name&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;contacts&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;
  &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;prefix&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;v1_0&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;
  &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;user&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;supo&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;
  &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;password&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;geditrocks&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;
  &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;timeout&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;60&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="comment"&gt;# describe&lt;/span&gt;
&lt;span class="ident"&gt;describe&lt;/span&gt; &lt;span class="constant"&gt;PersonResource&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
  &lt;span class="ident"&gt;before&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:each&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
    &lt;span class="attribute"&gt;@resource&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;mock&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;PersonResource&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;it&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;should bla&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
    
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;after&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:each&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
    &lt;span class="attribute"&gt;@resource&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;nil&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="comment"&gt;# specmodelerror&lt;/span&gt;
&lt;span class="ident"&gt;it&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;should have an error on name&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
  &lt;span class="attribute"&gt;@user&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="ident"&gt;have&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;errors_on&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:name&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="comment"&gt;# specmodelrecords&lt;/span&gt;
&lt;span class="ident"&gt;it&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;should have 50 records&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
  &lt;span class="attribute"&gt;@states&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="ident"&gt;have&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;50&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;records&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="comment"&gt;# spectemplaterendered&lt;/span&gt;
&lt;span class="ident"&gt;it&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;should render 'common/user' on get '/user'&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
  &lt;span class="ident"&gt;get&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;/user&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
  &lt;span class="ident"&gt;response&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;should&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;render_template&lt;/span&gt;&lt;span class="punct"&gt;("&lt;/span&gt;&lt;span class="string"&gt;common/user&lt;/span&gt;&lt;span class="punct"&gt;"))&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="comment"&gt;# specresponsetext&lt;/span&gt;
&lt;span class="ident"&gt;it&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;should return text 'You were signed out.' in response to post on '/signout'&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
  &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;/signout&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
  &lt;span class="ident"&gt;response&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="ident"&gt;have_text&lt;/span&gt;&lt;span class="punct"&gt;("&lt;/span&gt;&lt;span class="string"&gt;You were signed out.&lt;/span&gt;&lt;span class="punct"&gt;")&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="comment"&gt;# specresponseredirect&lt;/span&gt;
&lt;span class="ident"&gt;it&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;should redirect to action 'index' on post '/users'&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
  &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;/users&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
  &lt;span class="ident"&gt;response&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="ident"&gt;redirect_to&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:action&lt;/span&gt; &lt;span class="punct"&gt;=&gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;index&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="comment"&gt;# specroutefor&lt;/span&gt;
&lt;span class="ident"&gt;it&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;should map #index to '/users'&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
  &lt;span class="ident"&gt;route_for&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:controller&lt;/span&gt; &lt;span class="punct"&gt;=&gt;&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;users&lt;/span&gt;&lt;span class="punct"&gt;",&lt;/span&gt; &lt;span class="symbol"&gt;:action&lt;/span&gt; &lt;span class="punct"&gt;=&gt;&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;index&lt;/span&gt;&lt;span class="punct"&gt;").&lt;/span&gt;&lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;/users&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="comment"&gt;# specparamsfrom&lt;/span&gt;
&lt;span class="ident"&gt;it&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;should generate params for #update&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
  &lt;span class="ident"&gt;params_from&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:put&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;/users/1&lt;/span&gt;&lt;span class="punct"&gt;").&lt;/span&gt;&lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;span class="symbol"&gt;:controller&lt;/span&gt; &lt;span class="punct"&gt;=&gt;&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;users&lt;/span&gt;&lt;span class="punct"&gt;",&lt;/span&gt; &lt;span class="symbol"&gt;:action&lt;/span&gt; &lt;span class="punct"&gt;=&gt;&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;update&lt;/span&gt;&lt;span class="punct"&gt;",&lt;/span&gt; &lt;span class="symbol"&gt;:id&lt;/span&gt; &lt;span class="punct"&gt;=&gt;&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;"}&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="comment"&gt;# spectagexists&lt;/span&gt;
&lt;span class="ident"&gt;response&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="ident"&gt;have_tag&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;ul.menu#sidebar&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;

&lt;span class="comment"&gt;# specnestedtagexists&lt;/span&gt;
&lt;span class="ident"&gt;response&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="ident"&gt;have_tag&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;ul.menu&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
  &lt;span class="ident"&gt;with_tag&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;li&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;my menu item&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
  &lt;span class="comment"&gt;# specchildtagexists&lt;/span&gt;
  &lt;span class="ident"&gt;with_tag&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;li&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;my second menu item&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="comment"&gt;# specblocktagexists&lt;/span&gt;
&lt;span class="ident"&gt;response&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:sidebar&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="ident"&gt;have_tag&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;ul#sidebar&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;

&lt;span class="comment"&gt;# mockviewhelper&lt;/span&gt;
&lt;span class="ident"&gt;template&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;should_receive&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:curent_user&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;and_return&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;mock&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;))&lt;/span&gt;

&lt;span class="comment"&gt;# specsuccess&lt;/span&gt;
&lt;span class="ident"&gt;response&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="ident"&gt;be_success&lt;/span&gt;

&lt;span class="comment"&gt;# specredirect&lt;/span&gt;
&lt;span class="ident"&gt;response&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="ident"&gt;be_redirect&lt;/span&gt;

&lt;span class="comment"&gt;# feature&lt;/span&gt;
&lt;span class="constant"&gt;Feature&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="constant"&gt;Search&lt;/span&gt; &lt;span class="constant"&gt;Jobs&lt;/span&gt;
  &lt;span class="constant"&gt;In&lt;/span&gt; &lt;span class="ident"&gt;order&lt;/span&gt; &lt;span class="ident"&gt;to&lt;/span&gt; &lt;span class="ident"&gt;find&lt;/span&gt; &lt;span class="ident"&gt;relevant&lt;/span&gt; &lt;span class="ident"&gt;jobs&lt;/span&gt;
  &lt;span class="constant"&gt;As&lt;/span&gt; &lt;span class="ident"&gt;a&lt;/span&gt; &lt;span class="constant"&gt;Job&lt;/span&gt; &lt;span class="constant"&gt;Seeker&lt;/span&gt;
  &lt;span class="constant"&gt;I&lt;/span&gt; &lt;span class="ident"&gt;need&lt;/span&gt; &lt;span class="ident"&gt;to&lt;/span&gt; &lt;span class="ident"&gt;find&lt;/span&gt; &lt;span class="ident"&gt;jobs&lt;/span&gt; &lt;span class="ident"&gt;relevant&lt;/span&gt; &lt;span class="ident"&gt;to&lt;/span&gt; &lt;span class="ident"&gt;me&lt;/span&gt;

  &lt;span class="constant"&gt;Scenario&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="constant"&gt;Location&lt;/span&gt; &lt;span class="constant"&gt;Search&lt;/span&gt;
    &lt;span class="constant"&gt;Given&lt;/span&gt; &lt;span class="ident"&gt;a&lt;/span&gt; &lt;span class="ident"&gt;search&lt;/span&gt; &lt;span class="ident"&gt;form&lt;/span&gt;
    &lt;span class="constant"&gt;When&lt;/span&gt; &lt;span class="constant"&gt;I&lt;/span&gt; &lt;span class="ident"&gt;enter&lt;/span&gt; &lt;span class="ident"&gt;my&lt;/span&gt; &lt;span class="ident"&gt;zip&lt;/span&gt; &lt;span class="ident"&gt;code&lt;/span&gt;
    &lt;span class="constant"&gt;Then&lt;/span&gt; &lt;span class="constant"&gt;I&lt;/span&gt; &lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="ident"&gt;see&lt;/span&gt; &lt;span class="ident"&gt;all&lt;/span&gt; &lt;span class="ident"&gt;jobs&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="keyword"&gt;and&lt;/span&gt; &lt;span class="ident"&gt;around&lt;/span&gt; &lt;span class="ident"&gt;my&lt;/span&gt; &lt;span class="ident"&gt;zip&lt;/span&gt; &lt;span class="ident"&gt;code&lt;/span&gt;
  &lt;span class="comment"&gt;# scenario&lt;/span&gt;
  &lt;span class="constant"&gt;Scenario&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="constant"&gt;Skills&lt;/span&gt; &lt;span class="constant"&gt;Search&lt;/span&gt;
    &lt;span class="constant"&gt;Given&lt;/span&gt; &lt;span class="ident"&gt;a&lt;/span&gt; &lt;span class="ident"&gt;search&lt;/span&gt; &lt;span class="ident"&gt;form&lt;/span&gt;
    &lt;span class="constant"&gt;When&lt;/span&gt; &lt;span class="constant"&gt;I&lt;/span&gt; &lt;span class="ident"&gt;enter&lt;/span&gt; &lt;span class="ident"&gt;skill&lt;/span&gt; &lt;span class="ident"&gt;keywords&lt;/span&gt;
    &lt;span class="constant"&gt;Then&lt;/span&gt; &lt;span class="constant"&gt;I&lt;/span&gt; &lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="ident"&gt;see&lt;/span&gt; &lt;span class="ident"&gt;all&lt;/span&gt; &lt;span class="ident"&gt;job&lt;/span&gt; &lt;span class="ident"&gt;descriptions&lt;/span&gt; &lt;span class="ident"&gt;that&lt;/span&gt; &lt;span class="ident"&gt;mention&lt;/span&gt; &lt;span class="ident"&gt;those&lt;/span&gt; &lt;span class="ident"&gt;keywords&lt;/span&gt;
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/704071610769103721/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=704071610769103721" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/704071610769103721" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/704071610769103721" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/46r9Y3cN_Nk/gedit-extensions-project.html" title="GEdit Extensions Project" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://geek.susanpotter.net/2009/01/gedit-extensions-project.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-4336889545077205436</id><published>2008-11-03T10:50:00.008-06:00</published><updated>2008-11-03T11:03:10.239-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="coffee" /><category scheme="http://www.blogger.com/atom/ns#" term="election" /><category scheme="http://www.blogger.com/atom/ns#" term="merb" /><category scheme="http://www.blogger.com/atom/ns#" term="vote" /><title type="text">Free Coffee for Voting</title><content type="html">As if anyone needs any more enticement to vote this election season, Starbucks has decided to reward people who cast their vote Tuesday November 4th, 2008 with a free Tall coffee.  I do not believe you have to vote for anyone in particular:)  Just go and vote.

&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/a2J8KJDsqqY&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x3a3a3a&amp;color2=0x999999"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/a2J8KJDsqqY&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x3a3a3a&amp;color2=0x999999" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;

While you are enjoying your free coffee at Starbucks, perhaps explore the latest Merb 1.0 release candidate.  To install simply do the following:
&lt;pre&gt;&lt;code&gt;$ sudo gem update --system
$ gem --version # make sure it is at least 1.2.0
$ sudo gem install merb&lt;/code&gt;&lt;/pre&gt;
Now to create a new Merb application do the following:
&lt;pre&gt;&lt;code&gt;$ merb-gen app your-app-name-here
$ cd your-app-name-here
# now start editing the files you need to edit for you app.
# I promise more tutorials will be coming once I have 
# free time&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/4336889545077205436/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=4336889545077205436" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/4336889545077205436" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/4336889545077205436" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/AqF0bw2UZzs/free-coffee-for-voting.html" title="Free Coffee for Voting" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://geek.susanpotter.net/2008/11/free-coffee-for-voting.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-6483095180237787444</id><published>2008-09-27T21:52:00.020-05:00</published><updated>2008-09-28T11:03:24.220-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="agile" /><category scheme="http://www.blogger.com/atom/ns#" term="ruby on rails" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="books" /><category scheme="http://www.blogger.com/atom/ns#" term="rubyonrails" /><category scheme="http://www.blogger.com/atom/ns#" term="capistrano" /><category scheme="http://www.blogger.com/atom/ns#" term="consulting" /><category scheme="http://www.blogger.com/atom/ns#" term="book" /><title type="text">Book Shelf Clearing</title><content type="html">In an effort to reorganize my office, I am clearing off space on my bookshelves and selling books (on Amazon marketplace) that I have already read.  Since they are all software development related I thought I would list the most relevant below in case any blog readers are looking for books on the subject for cheap:
&lt;ul&gt;&lt;li&gt;&lt;strong&gt;[SOLD]&lt;/strong&gt; &lt;strike&gt;Deploying Rails Applications: A Step-by-Step Guide (Facets of Ruby)&lt;/strike&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=illinilistn09-20&amp;amp;l=ur2&amp;amp;o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt; (&lt;a href="http://www.amazon.com/gp/redirect.html?ie=UTF8&amp;location=http%3A%2F%2Fwww.amazon.com%2FDeploying-Rails-Applications-Step-Step%2Fdp%2F0978739205&amp;tag=illinilistn09-20&amp;linkCode=ur2&amp;camp=1789&amp;creative=9325" target="_blank"&gt;buy it new&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=illinilistn09-20&amp;amp;l=ur2&amp;amp;o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt; or &lt;a href="http://www.amazon.com/gp/redirect.html?ie=UTF8&amp;location=http%3A%2F%2Fwww.amazon.com%2Fgp%2Foffer-listing%2F0978739205%2F&amp;tag=illinilistn09-20&amp;linkCode=ur2&amp;camp=1789&amp;creative=9325" target="_blank"&gt;used&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=illinilistn09-20&amp;amp;l=ur2&amp;amp;o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;)&lt;br/&gt;Very good for the beginner or intermediate Capistrano recipe writer.  It also contains some good pointers at the end of the book on benchmarking.  Released relatively recently (within 3 months I think?)&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/gp/redirect.html?ie=UTF8&amp;location=http%3A%2F%2Fwww.amazon.com%2Fgp%2Foffer-listing%2F0596529554%3Fseller%3DA2GY6CQ7Y4MII2&amp;tag=illinilistn09-20&amp;linkCode=ur2&amp;camp=1789&amp;creative=9325" target="_blank"&gt;SOA in Practice: The Art of Distributed System Design (Theory in Practice)&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=illinilistn09-20&amp;amp;l=ur2&amp;amp;o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt; (Published Aug 2007)&lt;br/&gt;This book is more for the unRESTful SOA types than the RESTful folk like me.  The author obviously has some old-time experience, so if you are into old school SOA standards (WSDL, SOAP, UDDI) then this would provide a lot of good architect-level areas to consider, which are often ignored including: service lifecycle, versioning, security, service management and more.  One gripe I had with the book is in the versioning section.  Let's just say his preference for naming is definitely NOT my style:)  Otherwise this contains good reading material for the architect just getting into SOA in an enterprise setting.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/gp/redirect.html?ie=UTF8&amp;location=http%3A%2F%2Fwww.amazon.com%2Fgp%2Foffer-listing%2F0596527314%3Fseller%3DA2GY6CQ7Y4MII2&amp;tag=illinilistn09-20&amp;linkCode=ur2&amp;camp=1789&amp;creative=9325" target="_blank"&gt;Rails Cookbook (Cookbooks (O'Reilly))&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=illinilistn09-20&amp;amp;l=ur2&amp;amp;o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;br/&gt;Great for starting Rails projects with limited Ruby on Rails experience.  It covers Rails 1.2, but most recipes will only require minor changes.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/gp/redirect.html?ie=UTF8&amp;location=http%3A%2F%2Fwww.amazon.com%2Fgp%2Foffer-listing%2F0596527675%3Fseller%3DA2GY6CQ7Y4MII2&amp;tag=illinilistn09-20&amp;linkCode=ur2&amp;camp=1789&amp;creative=9325" target="_blank"&gt;The Art of Agile Development&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=illinilistn09-20&amp;amp;l=ur2&amp;amp;o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;br/&gt;Covers all aspects of agile development from planning to delivery.  If you aren't already an agile development ninja, this is in my top three agile books.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/gp/redirect.html?ie=UTF8&amp;location=http%3A%2F%2Fwww.amazon.com%2Fgp%2Foffer-listing%2F1593271204%3Fseller%3DA2GY6CQ7Y4MII2&amp;tag=illinilistn09-20&amp;linkCode=ur2&amp;camp=1789&amp;creative=9325" target="_blank"&gt;Webbots, Spiders, and Screen Scrapers: A Guide to Developing Internet Agents with PHP/CURL&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=illinilistn09-20&amp;amp;l=ur2&amp;amp;o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;br/&gt;Last year I had to work (for a short while) with PHP in the crawling/bot arena.  This book contained got me developing bots and crawlers in no time in PHP.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/gp/redirect.html?ie=UTF8&amp;location=http%3A%2F%2Fwww.amazon.com%2Fgp%2Foffer-listing%2F0596527446%3Fseller%3DA2GY6CQ7Y4MII2&amp;tag=illinilistn09-20&amp;linkCode=ur2&amp;camp=1789&amp;creative=9325" target="_blank"&gt;Ajax on Rails&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=illinilistn09-20&amp;amp;l=ur2&amp;amp;o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;br/&gt;This would be a decent book for Rails developers that aren't believers in Unobtrusive Javascript (UJS).  I have to purge this book from my bookcase now that I am a big UJS convert:)  I hope you understand.  I got this when it first came out, before I had seen the light.  Seriously though, if you don't care about UJS principles, this book covers good ground on using AJAX Rails helpers.  You should realize that the book was written pre-2.0 (Rails release that is).&lt;/li&gt;&lt;/ul&gt;
Also those wanting to branch out on their own as a consultant, the following books might be for you as I found both very helpful when first starting my software consulting practice in 2001:
&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/gp/redirect.html?ie=UTF8&amp;location=http%3A%2F%2Fwww.amazon.com%2Fgp%2Foffer-listing%2F0471384550%3Fseller%3DA2GY6CQ7Y4MII2&amp;tag=illinilistn09-20&amp;linkCode=ur2&amp;camp=1789&amp;creative=9325" target="_blank"&gt;Getting Started in Consulting&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=illinilistn09-20&amp;amp;l=ur2&amp;amp;o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;br/&gt;If I could only recommend one of these two consulting books it would be this one hands down, since this is more about general consulting principles and practices and the second book might be slightly dated in the initial chapters, because both were written before the software outsourcing/offshoring mania.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/gp/redirect.html?ie=UTF8&amp;location=http%3A%2F%2Fwww.amazon.com%2Fgp%2Foffer-listing%2F0471348139%3Fseller%3DA2GY6CQ7Y4MII2&amp;tag=illinilistn09-20&amp;linkCode=ur2&amp;camp=1789&amp;creative=9325" target="_blank"&gt;Getting Started in Computer Consulting&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=illinilistn09-20&amp;amp;l=ur2&amp;amp;o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/li&gt;&lt;/ul&gt;
PS I have been using &lt;a href="http://www.amazon.com/gp/subs/primeclub/signup/extmain.html?
ref=prime_assoc_bt&amp;tag=illinilistn09-20" rel="nofollow" target="_blank"&gt;Amazon Prime&lt;/a&gt; for two months now and love it.  You can &lt;a href="http://www.amazon.com/gp/redirect.html?ie=UTF8&amp;location=http%3A%2F%2Fwww.amazon.com%2Fgp%2Fsubs%2Fprimeclub%2Fsignup%2Fextmain.html%3Fref%3Dprime%5Fassoc%5Fbt&amp;tag=illinilistn09-20&amp;linkCode=ur2&amp;camp=1789&amp;creative=9325" rel="nofollow" target="_blank"&gt;try Amazon Prime FREE for one month&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=illinilistn09-20&amp;amp;l=ur2&amp;amp;o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt; if you like too.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/6483095180237787444/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=6483095180237787444" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/6483095180237787444" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/6483095180237787444" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/USZSKVos1Pw/book-shelf-clearing.html" title="Book Shelf Clearing" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://geek.susanpotter.net/2008/09/book-shelf-clearing.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-3163567399148266115</id><published>2008-09-22T10:20:00.041-05:00</published><updated>2008-09-22T12:58:37.970-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="entrepreneur" /><category scheme="http://www.blogger.com/atom/ns#" term="ruby on rails" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><title type="text">Tips to Enterpreneurs Hiring Ruby on Rails Consulting Firms</title><content type="html">I know I am taking a break from my DataMapper/Merb series of posts today, but I have seen enough fakers out there in the Ruby on Rails world that I just have to get a few things off my chest:

Below is a list of things to avoid when hiring a Ruby on Rails consulting firm:
&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Overexcited marketing speak.&lt;/strong&gt;  Drop any firm that has something like the following on their website: &lt;em&gt;"We believe Ruby on Rails is the most elegant, powerful programming language on the planet"&lt;/em&gt;.  These people might know a thing or two about configuring WordPress or Drupal or perhaps only Photoshop, but definitely no serious Object Oriented development of large scale Ruby server applications.  Basically anyone that calls "Ruby on Rails" as a whole a programming language has an inadequate skill set to build a non-trivial web application.  In addition anyone that knows more than three non-similar programming languages will know Ruby is not &lt;strong&gt;&lt;a href="http://www.opensourcery.com/services/custom-software"&gt;"the most powerful programming language on the planet"&lt;/a&gt;&lt;/strong&gt;.  Sorry I had to find a quote on the web to prove I wasn't exaggerating.  There are many more fakers on the web too, so look out!  Remember you aren't looking for people using the most powerful programming language, you want results.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agile this, agile that, agile everywhere.&lt;/strong&gt;  Beware of firms using the word &lt;strong&gt;agile&lt;/strong&gt; like there is no tomorrow.  Some use is fine, but ask them what they mean by agile.  And what benefits you, the client, will receive from an agile team.  Don't get me wrong if a web application is built in an iterative fashion with lots of client involvement and sign off, with lots of useful automated tests/specs that are run often then this is almost certainly a great thing for the project.  However, beware of the firms or freelancers that are using &lt;em&gt;agile&lt;/em&gt; simply as a buzzword.  (Note: some firms like mine use agile a lot in web page titles for SEO purposes, so not all firms that use agile a lot in titles are faking.  So make sure to ask firms what they mean by the word agile when they use it).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Why Rails?&lt;/strong&gt;  If any firm tells you that a web application written using Django, TurboGears, Merb or other web frameworks will never be as good as a Rails web application, then drop them off your consideration list immediately.  The same is true if the converse is said.  If they answer with something more measured and sensible like "our engineers have found developing applications in Rails to be more productive than X, Y and Z, which we previously used, and it provides us with the right amount of control/flexibility without us needing to worry about all configuration than previous frameworks" then at least they aren't misleading you just to get a sale.  Of course, you might be looking for other points in the answer (other attributes of a web framework that would make &lt;em&gt;business&lt;/em&gt; sense like active community, skillset, etc.).  Also in general you should look for measured answers to all your questions, not answers that lack insight and promise they can do EVERYTHING under the sun for you in 2 weeks time.  You will be disappointed if you hire that firm or freelancer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Expert in everything, expert in nothing.&lt;/strong&gt;  Consulting firms and/or freelancers need to choose a specific set of technical competencies so they can be experts in those areas.  Beware of consulting firms or freelancers that claim to be experts in every framework, programming language and operating system.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ubiquitous buzzwords.&lt;/strong&gt;  Beware of too many buzzwords.  Even if you know what a buzzword means, ask the person using too much jargon to clarify so you can evaluate whether they really know what they are saying.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Everything AJAX.&lt;/strong&gt;  I previously worked through a consulting firm on the west coast (I'll not name names).  The consulting manager who led project management functions on all the firms' projects was convinced that if we just put an AJAX form in here and there it would solve all our problems.  My experience with this firm wasn't overly positive.  I like the people on a personal level, but their work quality and focus tended to create hard to use web applications.  Beware of people who think AJAX is the answer to everything.  It has its place, but don't go overboard.  PS Make sure the people you hire write unobtrusive Javascript rather than embedded Rails Prototype helpers.  &lt;acronym title="Unobtrusive JavaScript"&gt;UJS&lt;/acronym&gt; has many benefits including graceful degradation (benefiting those that do not have Javascript enabled), avoiding browser incompatibilities and improved code organization (separation of concerns).  Users of your web application will appreciate the forethought and your developers can be more productive!:)  Win-win.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Novice.has_many :problems&lt;/strong&gt;  Look for previous Object Oriented modeling experience for the engineers on the project team.  Even though ActiveRecord (the default Ruby on Rails Object Relational Mapping framework) provides a higher level of abstraction for &lt;acronym title="Object Relational Mapping"&gt;ORM&lt;/acronym&gt; associations than other frameworks, don't be fooled into thinking anyone can model your business domain correctly without experience and/or know-how.  Many developers who are used to using Hibernate or TOPLink (as only two examples) before in Java or Smalltalk respectively will have likely done a lot of &lt;acronym title="Object Oriented"&gt;OO&lt;/acronym&gt; modeling.  Ask them about the most complex business domain they have modeled previously to be able to guage their skill level and experience in this area.  This point is most important in applications that have more complex business domains.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Why should I care about your data?  Look at my cool Photoshop spinning logo.&lt;/strong&gt;  Rails consulting firms and/or freelancers should have a good understanding of the importance of data modeling.  Even if they do not have specific data modeling expertise they should at least know that indexing appropriate columns and defining column size limits where appropriate can save not just storage space, but also shave time off queries (depending on the query and usage scenario).  That way when your application gets to the point where the database needs to be fine tuned, the data architect you hire will have an easier job than if your schema was designed by a PHP weekender that thinks the Drupal or WordPress database schema is finely tuned (sorry, it's horrendous and yes you should know that anyway).  This is a very important consideration if your application is supposed to hold a considerable amount of data and/or if you have strong reporting requirements.  As a side note, make sure to ask them if different database schemas are sometimes needed for querying large data sets (classical reporting requirements) versus &lt;acronym title="Create-Read-Update-Delete"&gt;CRUD&lt;/acronym&gt; usages.  The answer should be yes and you should ask them to explain this a little to see how much they really &lt;strong&gt;understand&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;I can design, develop, deploy and manage perfectly.&lt;/strong&gt;  Usually firms and freelancers are much better in one or two areas than all equally.  Some are better at graphic design and got into development to earn $20/hr extra.  That's fine, but you should know what you are getting yourself into.  Ask what their strengths and weaknesses are.  For example, I am excellent at developing and very good at deploying and systems engineering.  I can use Photoshop and Illustrator (just like graphic designers can copy Rails code from forums and paste it into their editor), but ask me to create a visually stunning logo that encapsulates your company's image and I am lost (just like the graphic designers that can't write original code themselves).  Know what is most important for your application needs and hire the appropriate people.  Usually outsourcing graphic design to a design firm and hiring a flexible developer that can work with external teams well, gets you the best value for money.  Throw away the firms and people that don't have any weaknesses.  They are lying.&lt;/li&gt;&lt;/ul&gt;
One point I would like to make to round this piece off is that if you find a young, eager engineer with higher than average aptitude, he/she can really do a lot for your project.  However, you should expect them to make a few mistakes.  Nobody is perfect and without prior experience with large scale server applications it is virtually impossible for someone not to make mistakes.  If you can afford a few mistakes here and there, then this might be the way to go.  Give them an equity stake if capital is an issue for you, they are more likely to take a risk with you than a seasoned consultant with a mortgage to pay or spouse and children to feed.  However, never hire someone who claims to be a Ruby/Rails expert at a high rate if they simply copy and paste sample code from Ruby/Rails forums online (you would be surprised how many there are out there).  It's a terrible waste of your capital and frankly it takes work away from better firms and/or freelancers out there and you will end up with badly written software that runs poorly.

As a final note, hire a firm, freelancer or in-house engineer that has similar energy level and compatible personality to yours.  Or at a minimum hire a firm or freelancer that you can trust and has been recommended, but not just through popularity contests like those at WorkingWithRails.com (I know three freelancers who are excellent Ruby engineers with only have 1 recommendation on the site and I have worked with one person that has more than ten recommendations and consider them subpar to most Ruby/Rails developers I know).&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/3163567399148266115/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=3163567399148266115" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/3163567399148266115" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/3163567399148266115" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/vk9OSCFbZ7g/tips-to-enterpreneurs-hiring-ruby-on.html" title="Tips to Enterpreneurs Hiring Ruby on Rails Consulting Firms" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://geek.susanpotter.net/2008/09/tips-to-enterpreneurs-hiring-ruby-on.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-1104836026982398911</id><published>2008-09-04T10:13:00.015-05:00</published><updated>2008-09-11T19:22:45.427-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="orm" /><category scheme="http://www.blogger.com/atom/ns#" term="datamapper" /><category scheme="http://www.blogger.com/atom/ns#" term="database" /><title type="text">DataMapper: Flexibility of mapping model attributes to table columns</title><content type="html">I know an esteemed ex-colleague of mine (even if he is an Apple zombie now - yes, becoming a fan of Apple on Facebook deserves some heckling;)) has reservations about the apparent unDRY-ness of DataMapper with migrations.  I used to share his reservations before I wrote two applications using DataMapper.  Neither Merb application was particularly spectacular, but both had to work with legacy database schemas.  Oh the joys of crazy DBA naming conventions!

Let's look at a brief example of DBA naming madness (some names were changed, but the conventions used are the same):
&lt;pre&gt;
ordersTable:
  - uid_int: int (PK)
  - acc_id_int: int
  - amt_int: int
  - ref_code_string: varchar(64) natural key
  - desc_string: varchar(128)
  - entered_dt: datetime
  - changed_dt: datetime
&lt;/pre&gt;
In another table managed by a different group we had:
&lt;pre&gt;
Account:
  - ID: int (PK)
  - Balance: int
  - UserID: int (FK)
  - EnteredDateTime: datetime
  - ChangedDateTime: datetime
&lt;/pre&gt;

I kid you not.  Two different conventions, both relatively unreadable as Ruby attributes as they both violate popular coding conventions in some way.

In ActiveRecord you would be left doing non-trivial coding to hide the ugly column names in the model and map Ruby-friendly names to the appropriate column.

In DataMapper this is not so.  Lending from the design pattern's primary purpose - to explicitly map model attributes to database columns to decouple the two - we can write something like the following using DM:
&lt;pre&gt;
&lt;code&gt;
class Order
  include DataMapper::Resource
  set_table_name("ordersTable") #ridiculous name really, but what can you do if other older applications rely on this already?

  has(1, :account, :child_key =&gt; 'acc_id_int', :repository =&gt; repository(:accounts))
  property(:id, Integer, :serial =&gt; true, :field =&gt; 'uid')
  property(:amount, Integer, :field =&gt; 'amt_int')
  property(:reference, String, :field =&gt; 'ref_code_string', :key =&gt; true)
  property(:description, String, :field =&gt; 'desc_string')
  property(:created_at, DateTime, :field =&gt; 'entered_dt')
  property(:changed_dt, DateTime, :field =&gt; 'changed_dt')
end

class Account
  include DataMapper::Resource
  set_table_name('Account')

  property(:id, Integer, :serial =&gt; true, :field =&gt; 'ID')
  property(:balance, Integer, :field =&gt; 'Balance')
  property(:created_at, DateTime, :field =&gt; 'EnteredDateTime')
  property(:updated_at, DateTime, :field =&gt; 'ChangedDateTime')
end
&lt;/code&gt;
&lt;/pre&gt;
This way we can write readable Ruby code with the model.

Next time we can look at lazy loading: how to switch it on and off and when to use it for greater effect.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/1104836026982398911/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=1104836026982398911" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/1104836026982398911" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/1104836026982398911" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/pXuXmeTvDIM/datamapper-flexibility-of-mapping-model.html" title="DataMapper: Flexibility of mapping model attributes to table columns" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://geek.susanpotter.net/2008/09/datamapper-flexibility-of-mapping-model.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-2198880354566669059</id><published>2008-09-04T09:27:00.007-05:00</published><updated>2008-09-04T10:03:06.203-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="datamapper" /><category scheme="http://www.blogger.com/atom/ns#" term="merb" /><title type="text">DataMapper does have migrations</title><content type="html">I wanted to bust a myth out there that DataMapper does not have regular migrations, just the auto migrations.  At least in post 0.9 versions DataMapper has both.

In other blogs about the topic I found quotes like: "DataMapper migrations pull your database structure directly from the Ruby code for your models, so there’s no need to write separate migration files...".  This, in my opinion, gives the wrong impression to those that are worried about non-trivial schema migrations.  The author of that quote appears to have never moved one column into multiple or vice versa (a non-trivial schema change), among other schema changes where a DataMapper auto migration would not work in a production environment.  

In merb you can just create a new DM migration with the following:
&lt;code&gt;$ merb-gen migration name_of_your_migration&lt;/code&gt;
(Assuming you have set the &lt;code&gt;use_orm&lt;/code&gt; setting to &lt;code&gt;:datamapper&lt;/code&gt; in config/init.rb.)

A simple DataMapper migration might look something like:
&lt;pre&gt;
&lt;code&gt;
migration 1, :create_orders  do
  up do
    create_table(:orders) do
      column(:id, Integer, :serial =&gt; true)
      column(:amount, Integer)
      column(:completed, Boolean)
      column(:description, String, :size =&gt; 255)
      column(:created_at, DateTime)
      column(:updated_at, DateTime)
    end
  end

  down do
    drop_table(:orders)
  end
end
&lt;/code&gt;
&lt;/pre&gt;
If you have problems with &lt;code&gt;Boolean&lt;/code&gt; not being recognized, throw in the line:
&lt;code&gt;include DataMapper::Types&lt;/code&gt; 
to the top of the migration (yes, this needs some finessing obviously).

Hope that helps a few people that may have been mislead by some blog posts inadvertently.  Migrations are needed for many cases I come across where auto migrations just will not cut it without losing data in production (not a good thing if data matters in your application:)).

BTW A minor annoyance of mine in Merb is that for DM migrations you need to use this ugly Rake task: &lt;code&gt;dm:db:migrate&lt;/code&gt; to migrate to latest version.  To rollback migrations you need to use this ugly thing: &lt;code&gt;dm:db:migrate:down[version]&lt;/code&gt;.  Where those using AR in Merb just keep using &lt;code&gt;db:migrate&lt;/code&gt; and &lt;code&gt;db:rollback&lt;/code&gt;.  This is an area that needs cleaning up to promote ORM agnosticism the way Merb is supposed to do.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/2198880354566669059/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=2198880354566669059" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/2198880354566669059" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/2198880354566669059" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/jKyuW4YUewI/datamapper-does-have-migrations.html" title="DataMapper does have migrations" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://geek.susanpotter.net/2008/09/datamapper-does-have-migrations.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-25066620.post-1749384692716695241</id><published>2008-08-30T08:34:00.012-05:00</published><updated>2009-02-17T15:39:54.334-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="RSS" /><category scheme="http://www.blogger.com/atom/ns#" term="xml" /><category scheme="http://www.blogger.com/atom/ns#" term="Feeds" /><title type="text">Next Generation Syndication and Publishing</title><content type="html">For the last year or so, I have been focusing on implementing RSS, Atom publishing and related standards for a particular client in the podcasting industry.  Both RSS and (to a lesser extent due to its standard being finalized much later) Atom are being heavily used not just for blogs, podcasts, videos and multimedia content, but also used heavily for web 2.0 (or social media) activity "watching".

Most people should be familiar with FriendFeed by now (if not, where have you been?  really!).  This month (August 2008) FriendFeed came out with their Simple Update Protocol (SUP) which sits on top of RSS/Atom publishing to make it easier for content consumers (very self-serving for FriendFeed, but at least they are coming up with some kind of "solution" instead of just bitching about the status quo) to identify feeds that have changed before they make a timed request for the feed every X minutes regardless of whether the feed has changes or not.

In a nutshell, SUP requires a meta JSON &lt;strong&gt;feed&lt;/strong&gt; that notifies consumers of newly updated feeds to publish data.  The first time an RSS/Atom feed is subscribed to, the consuming agent (e.g. FriendFeed) will strip out the SUP-ID and the SUP feed URL from the &lt;tt&gt;xpath:channel/link&lt;/tt&gt; element and associate this information with the relevant user/account or whatever.  Then using the identifier for a feed returned by the meta JSON feed, the consumer knows the URL associated with that ID for feeds they need to be updated by.

While this might solve some problems, it really does feel very much like a monkey patch.  On the flip side I do understand to some extent why they took this path of monkey patching as opposed to coming up with something more revolutionary.  Revolutionaries tend to get killed and only the second wave settlers reap the benefits of their blood, sweat and tears.

However, I did want to mention SixApart's efforts to broadcast frequently updating consumable data in what should be a much more obvious way for former enterprise MOM developers like myself.

The Six Apart Update Stream broadcasts over HTTP new public updates/posts as they happen.  It's an interesting idea and much closer to the XMPP ideal that companies like Twitter have attempted.

Any other former enterprise architects merely see this new trend in web [defacto] standards in publishing and consuming data as just another message oriented middleware (MOM)?  And I am hopeful that finally the web has found a MOM in XMPP that can stand the test of public scrutiny.&lt;div class="blogger-post-footer"&gt;2006-2008 Copyright (c) Susan Potter [http://susanpotter.net].  All rights reserved.&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://geek.susanpotter.net/feeds/1749384692716695241/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=25066620&amp;postID=1749384692716695241" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/1749384692716695241" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/25066620/posts/default/1749384692716695241" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SnakesGemsCoffee/~3/yGxo5uDAF-k/next-generating-syndication-and.html" title="Next Generation Syndication and Publishing" /><author><name>S. Potter</name><uri>http://www.blogger.com/profile/17341145424164713662</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://geek.susanpotter.net/2008/08/next-generating-syndication-and.html</feedburner:origLink></entry></feed>
