<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xml:base="http://www.opensourcery.com/blog/rss.xml/4" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title></title>
    <link>http://www.opensourcery.com/blog/rss.xml/4</link>
    <description></description>
    <language>en</language>
          <item>
    <title>We&#039;re WebVisionary award finalists!</title>
    <link>http://www.opensourcery.com/blog/brian-jamison/were-webvisionary-award-finalists</link>
    <description>&lt;p&gt;We&#039;re delighted to hear that the &lt;a href=&quot;https://www.opensourcery.com/portfolio/projects/bonneville-environmental-foundation-solar4rschoolsorg&quot;&gt;Solar4RSchools.org&lt;/a&gt; project is a finalist for a WebVisionary award!&lt;/p&gt;
&lt;p&gt;You can read more about the Solar4RSchools.org project &lt;a href=&quot;https://www.opensourcery.com/portfolio/projects/bonneville-environmental-foundation-solar4rschoolsorg&quot;&gt;here.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://webvisionaryawards.com&quot; target=&quot;new&quot;&gt;&lt;img src=&quot;http://webvisionaryawards.com/images/finalist.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
</description>
     <comments>http://www.opensourcery.com/blog/brian-jamison/were-webvisionary-award-finalists#comments</comments>
 <category domain="http://www.opensourcery.com/tags/awards-webvision-webvisionary-solar4rschools">awards webvision webvisionary solar4rschools</category>
 <pubDate>Thu, 13 May 2010 01:48:26 +0000</pubDate>
 <dc:creator>Brian Jamison</dc:creator>
 <guid isPermaLink="false">447 at http://www.opensourcery.com</guid>
  </item>
  <item>
    <title>DrupalCon San Francisco, departing thoughts</title>
    <link>http://www.opensourcery.com/blog/jonathan-hedstrom/drupalcon-san-francisco-departing-thoughts</link>
    <description>&lt;p&gt;I have just returned from DrupalCon San Francisco 2010, the largest DrupalCon ever. With over 3000 attending, and $72,000 worth of coffee consumed, it was a very lively event. Thanks to the awesome work of those organizing, nearly all of the sessions now have high quality video available on the &lt;a href=&quot;http://sf2010.drupal.org/conference/schedule&quot; target=&quot;_blank&quot;&gt;DrupalCon site&lt;/a&gt;, and on &lt;a href=&quot;http://www.archive.org/search.php?query=subject%3A%22DrupalCon%202010%22&quot; target=&quot;_blank&quot;&gt;Archive.org&lt;/a&gt;. Below are the sessions that really left an impression on me regarding the future direction of Drupal.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;http://sf2010.drupal.org/conference/sessions/advanced-drush&quot;&gt;Advanced Drush&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While there is no video for this as of this writing, the highlight here was the &lt;span class=&quot;geshifilter&quot;&gt;&lt;code class=&quot;geshifilter-bash&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;sudo&lt;/span&gt; drush make-me-a-sandwich&lt;/code&gt;&lt;/span&gt; moment (as well as the Drush core-cli command).&lt;br /&gt;
&lt;a href=&quot;http://www.flickr.com/photos/peterlozano/4540809869/&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.opensourcery.com/sites/all/files/resize/4540809869_636b6097be_o-630x431.jpg&quot; width=&quot;630&quot; height=&quot;431&quot; alt=&quot;Drush: make-me-a-sandwich&quot; title=&quot;Drush: make-me-a-sandwich&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;http://sf2010.drupal.org/conference/sessions/heart-open-atrium-context-purl-and-spaces&quot;&gt;The Heart of Open Atrium: Context, PURL and Spaces&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While we&#039;ve been using context on most projects for quite some time, the work presented here around the &lt;em&gt;spaces presets&lt;/em&gt; has me itching to try integrating them into some upcoming projects.&lt;/p&gt;
&lt;p&gt;&lt;embed type=&quot;application/x-shockwave-flash&quot; width=&quot;640&quot; 	height=&quot;504&quot; 	allowfullscreen=&quot;true&quot; 	allowscriptaccess=&quot;always&quot; 	src=&quot;http://www.archive.org/flow/flowplayer.commercial-3.0.5.swf&quot; 	w3c=&quot;true&quot; 	flashvars=&#039;config={&quot;key&quot;:&quot;#$b6eb72a0f2f1e29f3d4&quot;,&quot;playlist&quot;:[{&quot;url&quot;:&quot;http://www.archive.org/download/TheHeartOfOpenAtriumContextPurlAndSpaces_782/format=Thumbnail?.jpg&quot;,&quot;autoPlay&quot;:true,&quot;scaling&quot;:&quot;fit&quot;},{&quot;url&quot;:&quot;http://www.archive.org/download/TheHeartOfOpenAtriumContextPurlAndSpaces_782/mon_0945_303_edited_512kb.mp4&quot;,&quot;autoPlay&quot;:false,&quot;accelerated&quot;:true,&quot;scaling&quot;:&quot;fit&quot;,&quot;provider&quot;:&quot;h264streaming&quot;}],&quot;clip&quot;:{&quot;autoPlay&quot;:false,&quot;accelerated&quot;:true,&quot;scaling&quot;:&quot;fit&quot;,&quot;provider&quot;:&quot;h264streaming&quot;},&quot;canvas&quot;:{&quot;backgroundColor&quot;:&quot;0x000000&quot;,&quot;backgroundGradient&quot;:&quot;none&quot;},&quot;plugins&quot;:{&quot;audio&quot;:{&quot;url&quot;:&quot;http://www.archive.org/flow/flowplayer.audio-3.0.3-dev.swf&quot;},&quot;controls&quot;:{&quot;playlist&quot;:false,&quot;fullscreen&quot;:true,&quot;gloss&quot;:&quot;high&quot;,&quot;backgroundColor&quot;:&quot;0x000000&quot;,&quot;backgroundGradient&quot;:&quot;medium&quot;,&quot;sliderColor&quot;:&quot;0x777777&quot;,&quot;progressColor&quot;:&quot;0x777777&quot;,&quot;timeColor&quot;:&quot;0xeeeeee&quot;,&quot;durationColor&quot;:&quot;0x01DAFF&quot;,&quot;buttonColor&quot;:&quot;0x333333&quot;,&quot;buttonOverColor&quot;:&quot;0x505050&quot;},&quot;h264streaming&quot;:{&quot;url&quot;:&quot;http://www.archive.org/flow/flowplayer.h264streaming-3.0.5.swf&quot;}},&quot;contextMenu&quot;:[{&quot;View+TheHeartOfOpenAtriumContextPurlAndSpaces_782+at+archive.org&quot;:&quot;function()&quot;},&quot;-&quot;,&quot;Flowplayer 3.0.5&quot;]}&#039;&gt; &lt;/embed&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;http://sf2010.drupal.org/conference/sessions/page-render-drill-down-drupal-7&quot; target=&quot;_blank&quot;&gt;Page render drill down in Drupal 7&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The page rendering system in Drupal 7 waits much later in the process to transform structured data into the relevant output format (which is typically HTML). Practically speaking, what this allows for is &lt;span class=&quot;geshifilter&quot;&gt;&lt;code class=&quot;geshifilter-text&quot;&gt;hook_page_alter&lt;/code&gt;&lt;/span&gt;, which has access to the contents of the entire page, in a structured array. Two highlights:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The block module will no longer be a required module in Drupal 7. Rather, it is simply an optional UI for placing blocks in the page. This means that the Context module in Drupal 7 won&#039;t have to implement weird workarounds to steal block placement from the block module (and as such, should work seamlessly with the i18n module).&lt;/li&gt;
&lt;li&gt;Instead of only having to caching options (page and block level), &lt;em&gt;any part of the page&lt;/em&gt; can be cached. Furthermore, by using the query string and qrguments as the cache key, these caching mechanisms can work with content that is under access control.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;embed type=&quot;application/x-shockwave-flash&quot; width=&quot;640&quot; 	height=&quot;504&quot; 	allowfullscreen=&quot;true&quot; 	allowscriptaccess=&quot;always&quot; 	src=&quot;http://www.archive.org/flow/flowplayer.commercial-3.0.5.swf&quot; 	w3c=&quot;true&quot; 	flashvars=&#039;config={&quot;key&quot;:&quot;#$b6eb72a0f2f1e29f3d4&quot;,&quot;playlist&quot;:[{&quot;url&quot;:&quot;http://www.archive.org/download/PageRenderDrillDownInDrupal7/format=Thumbnail?.jpg&quot;,&quot;autoPlay&quot;:true,&quot;scaling&quot;:&quot;fit&quot;},{&quot;url&quot;:&quot;http://www.archive.org/download/PageRenderDrillDownInDrupal7/tue_1500_306_edited_512kb.mp4&quot;,&quot;autoPlay&quot;:false,&quot;accelerated&quot;:true,&quot;scaling&quot;:&quot;fit&quot;,&quot;provider&quot;:&quot;h264streaming&quot;}],&quot;clip&quot;:{&quot;autoPlay&quot;:false,&quot;accelerated&quot;:true,&quot;scaling&quot;:&quot;fit&quot;,&quot;provider&quot;:&quot;h264streaming&quot;},&quot;canvas&quot;:{&quot;backgroundColor&quot;:&quot;0x000000&quot;,&quot;backgroundGradient&quot;:&quot;none&quot;},&quot;plugins&quot;:{&quot;audio&quot;:{&quot;url&quot;:&quot;http://www.archive.org/flow/flowplayer.audio-3.0.3-dev.swf&quot;},&quot;controls&quot;:{&quot;playlist&quot;:false,&quot;fullscreen&quot;:true,&quot;gloss&quot;:&quot;high&quot;,&quot;backgroundColor&quot;:&quot;0x000000&quot;,&quot;backgroundGradient&quot;:&quot;medium&quot;,&quot;sliderColor&quot;:&quot;0x777777&quot;,&quot;progressColor&quot;:&quot;0x777777&quot;,&quot;timeColor&quot;:&quot;0xeeeeee&quot;,&quot;durationColor&quot;:&quot;0x01DAFF&quot;,&quot;buttonColor&quot;:&quot;0x333333&quot;,&quot;buttonOverColor&quot;:&quot;0x505050&quot;},&quot;h264streaming&quot;:{&quot;url&quot;:&quot;http://www.archive.org/flow/flowplayer.h264streaming-3.0.5.swf&quot;}},&quot;contextMenu&quot;:[{&quot;View+PageRenderDrillDownInDrupal7+at+archive.org&quot;:&quot;function()&quot;},&quot;-&quot;,&quot;Flowplayer 3.0.5&quot;]}&#039;&gt; &lt;/embed&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;http://sf2010.drupal.org/conference/sessions/pubsubhubbub-to-rescue&quot; target=&quot;_blank&quot;&gt;PubSubHubbub to the rescue-- Real-time feeds and the future of social networks&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This talk wasn&#039;t specific to Drupal (yet anyway), but rather, provides a sort of roadmap to the future of Drupal and the social web. By combining 4 rather new protocols (PubSubHubbub, WebFinger, ActivityStreams and Salmon), Brett Slatkin of Google walks through the potential for realtime feeds being used to contect people like never before.&lt;/p&gt;
&lt;p&gt;It would be very powerful if any Drupal site out there were capable of sharing, in real time, at the level Brett outlines in this talk. The Feeds module is already capable of consuming PubSubHubbub, and support for ActivityStreams have a little momentum. Salmon and WebFinger, as well as &lt;em&gt;publishing&lt;/em&gt; to hubs for PubSubHubbub are the pieces that need to be filled in.&lt;/p&gt;
&lt;p&gt;&lt;embed type=&quot;application/x-shockwave-flash&quot; width=&quot;640&quot; 	height=&quot;504&quot; 	allowfullscreen=&quot;true&quot; 	allowscriptaccess=&quot;always&quot; 	src=&quot;http://www.archive.org/flow/flowplayer.commercial-3.0.5.swf&quot; 	w3c=&quot;true&quot; 	flashvars=&#039;config={&quot;key&quot;:&quot;#$b6eb72a0f2f1e29f3d4&quot;,&quot;playlist&quot;:[{&quot;url&quot;:&quot;http://www.archive.org/download/PubsubhubbubToTheRescue--Real-timeFeedsAndTheFutureOfSocialNetworks/format=Thumbnail?.jpg&quot;,&quot;autoPlay&quot;:true,&quot;scaling&quot;:&quot;fit&quot;},{&quot;url&quot;:&quot;http://www.archive.org/download/PubsubhubbubToTheRescue--Real-timeFeedsAndTheFutureOfSocialNetworks/mon_1500_310_2_512kb.mp4&quot;,&quot;autoPlay&quot;:false,&quot;accelerated&quot;:true,&quot;scaling&quot;:&quot;fit&quot;,&quot;provider&quot;:&quot;h264streaming&quot;}],&quot;clip&quot;:{&quot;autoPlay&quot;:false,&quot;accelerated&quot;:true,&quot;scaling&quot;:&quot;fit&quot;,&quot;provider&quot;:&quot;h264streaming&quot;},&quot;canvas&quot;:{&quot;backgroundColor&quot;:&quot;0x000000&quot;,&quot;backgroundGradient&quot;:&quot;none&quot;},&quot;plugins&quot;:{&quot;audio&quot;:{&quot;url&quot;:&quot;http://www.archive.org/flow/flowplayer.audio-3.0.3-dev.swf&quot;},&quot;controls&quot;:{&quot;playlist&quot;:false,&quot;fullscreen&quot;:true,&quot;gloss&quot;:&quot;high&quot;,&quot;backgroundColor&quot;:&quot;0x000000&quot;,&quot;backgroundGradient&quot;:&quot;medium&quot;,&quot;sliderColor&quot;:&quot;0x777777&quot;,&quot;progressColor&quot;:&quot;0x777777&quot;,&quot;timeColor&quot;:&quot;0xeeeeee&quot;,&quot;durationColor&quot;:&quot;0x01DAFF&quot;,&quot;buttonColor&quot;:&quot;0x333333&quot;,&quot;buttonOverColor&quot;:&quot;0x505050&quot;},&quot;h264streaming&quot;:{&quot;url&quot;:&quot;http://www.archive.org/flow/flowplayer.h264streaming-3.0.5.swf&quot;}},&quot;contextMenu&quot;:[{&quot;View+PubsubhubbubToTheRescue--Real-timeFeedsAndTheFutureOfSocialNetworks+at+archive.org&quot;:&quot;function()&quot;},&quot;-&quot;,&quot;Flowplayer 3.0.5&quot;]}&#039;&gt; &lt;/embed&gt;&lt;/p&gt;
&lt;h3&gt;Drupal 7 and the State of Drupal&lt;/h3&gt;
&lt;p&gt;At &lt;a href=&quot;http://sf2010.drupal.org/conference/sessions/state-drupal&quot; target=&quot;_blank&quot;&gt;Dries&#039; keynote&lt;/a&gt;, he showed a best case scenario (June 2010), a worst case scenario (October 2010), and an ideal scenario (lock the 3000 attendees in until it was released at the conference) for the Drupal 7 release.&lt;/p&gt;
&lt;p&gt;&lt;embed type=&quot;application/x-shockwave-flash&quot; width=&quot;640&quot; 	height=&quot;504&quot; 	allowfullscreen=&quot;true&quot; 	allowscriptaccess=&quot;always&quot; 	src=&quot;http://www.archive.org/flow/flowplayer.commercial-3.0.5.swf&quot; 	w3c=&quot;true&quot; 	flashvars=&#039;config={&quot;key&quot;:&quot;#$b6eb72a0f2f1e29f3d4&quot;,&quot;playlist&quot;:[{&quot;url&quot;:&quot;http://www.archive.org/download/Css3TheFutureIsNow/format=Thumbnail?.jpg&quot;,&quot;autoPlay&quot;:true,&quot;scaling&quot;:&quot;fit&quot;},{&quot;url&quot;:&quot;http://www.archive.org/download/Css3TheFutureIsNow/mon_1330_keynote_edited_512kb.mp4&quot;,&quot;autoPlay&quot;:false,&quot;accelerated&quot;:true,&quot;scaling&quot;:&quot;fit&quot;,&quot;provider&quot;:&quot;h264streaming&quot;}],&quot;clip&quot;:{&quot;autoPlay&quot;:false,&quot;accelerated&quot;:true,&quot;scaling&quot;:&quot;fit&quot;,&quot;provider&quot;:&quot;h264streaming&quot;},&quot;canvas&quot;:{&quot;backgroundColor&quot;:&quot;0x000000&quot;,&quot;backgroundGradient&quot;:&quot;none&quot;},&quot;plugins&quot;:{&quot;audio&quot;:{&quot;url&quot;:&quot;http://www.archive.org/flow/flowplayer.audio-3.0.3-dev.swf&quot;},&quot;controls&quot;:{&quot;playlist&quot;:false,&quot;fullscreen&quot;:true,&quot;gloss&quot;:&quot;high&quot;,&quot;backgroundColor&quot;:&quot;0x000000&quot;,&quot;backgroundGradient&quot;:&quot;medium&quot;,&quot;sliderColor&quot;:&quot;0x777777&quot;,&quot;progressColor&quot;:&quot;0x777777&quot;,&quot;timeColor&quot;:&quot;0xeeeeee&quot;,&quot;durationColor&quot;:&quot;0x01DAFF&quot;,&quot;buttonColor&quot;:&quot;0x333333&quot;,&quot;buttonOverColor&quot;:&quot;0x505050&quot;},&quot;h264streaming&quot;:{&quot;url&quot;:&quot;http://www.archive.org/flow/flowplayer.h264streaming-3.0.5.swf&quot;}},&quot;contextMenu&quot;:[{&quot;View+Css3TheFutureIsNow+at+archive.org&quot;:&quot;function()&quot;},&quot;-&quot;,&quot;Flowplayer 3.0.5&quot;]}&#039;&gt; &lt;/embed&gt;&lt;/p&gt;
&lt;p&gt;While we already missed the ideal scenario, the progress made on critical bugs at the conference has the community working at a velocity that should come in closer to the best case scenario. Over the course of the week, thanks to the awesome gatherings at the chx coder lounge, the number of critical bugs dropped from 114 to 94 as of this writing.&lt;/p&gt;
&lt;div class=&quot;field field-type-filefield field-field-images-inline&quot;&gt;
    &lt;div class=&quot;field-items&quot;&gt;
            &lt;div class=&quot;field-item odd&quot;&gt;
                    &lt;img  class=&quot;imagefield imagefield-field_images_inline&quot; width=&quot;640&quot; height=&quot;438&quot; alt=&quot;DrupalCon San Francisco, departing thoughts&quot; src=&quot;http://www.opensourcery.com/sites/all/files/4540809869_636b6097be_o.jpg?1272560293&quot; /&gt;        &lt;/div&gt;
        &lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;field field-type-nodereference field-field-related&quot;&gt;
    &lt;div class=&quot;field-items&quot;&gt;
            &lt;div class=&quot;field-item odd&quot;&gt;
                    &lt;a href=&quot;/blog/jonathan-hedstrom/few-my-favorite-drupalcon-sessions-complete-videos&quot;&gt;A few of my favorite DrupalCon sessions, complete with videos&lt;/a&gt;        &lt;/div&gt;
              &lt;div class=&quot;field-item even&quot;&gt;
                    &lt;a href=&quot;/blog/jonathan-hedstrom/drupalcon-dc-filefields-core-context-spaces-and-other-highlights&quot;&gt;Drupalcon DC: Filefields in core, Context &amp;amp; Spaces, and other highlights&lt;/a&gt;        &lt;/div&gt;
              &lt;div class=&quot;field-item odd&quot;&gt;
                    &lt;a href=&quot;/blog/dylan-tack/drupalcon-highlights-performance-testing-kittens&quot;&gt;Drupalcon Highlights: Performance, Testing, Kittens&lt;/a&gt;        &lt;/div&gt;
              &lt;div class=&quot;field-item even&quot;&gt;
                    &lt;a href=&quot;/blog/jonathan-hedstrom/drupalcon-life-universe-and-everything&quot;&gt;Drupalcon: Life, The Universe, and Everything&lt;/a&gt;        &lt;/div&gt;
        &lt;/div&gt;
&lt;/div&gt;
</description>
     <comments>http://www.opensourcery.com/blog/jonathan-hedstrom/drupalcon-san-francisco-departing-thoughts#comments</comments>
 <category domain="http://www.opensourcery.com/tags/drupal">Drupal</category>
 <category domain="http://www.opensourcery.com/tags/drupalcon">Drupalcon</category>
 <category domain="http://www.opensourcery.com/tags/drupalcon-san-francisco">DrupalCon San Francisco</category>
 <pubDate>Fri, 23 Apr 2010 19:41:38 +0000</pubDate>
 <dc:creator>Jonathan Hedstrom</dc:creator>
 <guid isPermaLink="false">445 at http://www.opensourcery.com</guid>
  </item>
  <item>
    <title>Enabling a multilingual global community for Mercy Corps with Drupal</title>
    <link>http://www.opensourcery.com/blog/brian-jamison/enabling-multilingual-global-community-mercy-corps-drupal</link>
    <description>&lt;p&gt;We&#039;ve just published a write-up of our work for Mercy Corps, where we enabled hundreds of youth organizers worldwide to join together in a global community, including multilingual support in Drupal.  Read all about it here:&lt;br /&gt;
&lt;a href=&quot;http://www.opensourcery.com/portfolio/projects/mercy-corps-globalcitizencorpsorg&quot; title=&quot;http://www.opensourcery.com/portfolio/projects/mercy-corps-globalcitizencorpsorg&quot;&gt;http://www.opensourcery.com/portfolio/projects/mercy-corps-globalcitizen...&lt;/a&gt;&lt;/p&gt;
</description>
     <comments>http://www.opensourcery.com/blog/brian-jamison/enabling-multilingual-global-community-mercy-corps-drupal#comments</comments>
 <category domain="http://www.opensourcery.com/tags/drupal">Drupal</category>
 <category domain="http://www.opensourcery.com/tags/global-community-forums">global community forums</category>
 <category domain="http://www.opensourcery.com/tags/mercy-corps">Mercy corps</category>
 <category domain="http://www.opensourcery.com/tags/multi-lingual">multi-lingual</category>
 <category domain="http://www.opensourcery.com/tags/multilingual">multilingual</category>
 <category domain="http://www.opensourcery.com/tags/right-left">right-to-left</category>
 <category domain="http://www.opensourcery.com/tags/rtl">RTL</category>
 <pubDate>Mon, 19 Apr 2010 23:33:40 +0000</pubDate>
 <dc:creator>Brian Jamison</dc:creator>
 <guid isPermaLink="false">439 at http://www.opensourcery.com</guid>
  </item>
  <item>
    <title>How to write an RFP, part two: How much will it cost?</title>
    <link>http://www.opensourcery.com/blog/brian-jamison/how-write-rfp-part-two-how-much-will-it-cost</link>
    <description>&lt;p&gt;In &lt;a href=&quot;https://www.opensourcery.com/blog/brian-jamison/how-write-rfp-part-one-always-include-budget&quot;&gt;my last post&lt;/a&gt; I talked about how important it is to include a budget in your request for proposal (RFP).  People have since asked, “How do I know how much it will cost?”&lt;/p&gt;
&lt;p&gt;I think that&#039;s the wrong question.  There are two better questions.  The first is, “how much will we get?”  The second is, “how much will we save?”&lt;/p&gt;
&lt;p&gt;&lt;b&gt;How much will we get?&lt;/b&gt;&lt;br /&gt;
If your goal is concrete, say online fundraising or ecommerce, take the net funds currently raised after all costs for a year.  Add your current growth rate and estimate that figure for the next year.  Use real comparable data from similar efforts if you don&#039;t have your own.&lt;/p&gt;
&lt;p&gt;Now multiply that by your goal.  the amount of increased value you expect the site to deliver.  Make your goals realistic and conservative.  Perhaps your goal increased subscriptions of 20%.  Your maximum budget ought to be less than the amount you expect to gain from the new project.&lt;/p&gt;
&lt;p&gt;For example, let&#039;s say our site brought in $1,000,000 in 2010 with $250,000 net after all expenses.  In 2009 that figure was $800,000, so we have a 25% growth rate.  If that trend continues we&#039;d expect $1,250,000 in 2011, or a net of $310,250.  If our goal is to increase our subscriptions by an additional 20%, that gives us $370,500 in the first year.  The difference, $370,500 - $310,250 gives us a maximum budget of $60,250.  If our project costs less than that and delivers on the 20% goal, the project is a success.&lt;/p&gt;
&lt;p&gt;Before I address our second question let&#039;s talk about budgeting when the goals are less measurable.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;How much do we have?&lt;/b&gt;&lt;br /&gt;
In many cases the goal is less concrete.  Awareness campaigns, political movements, and educational organizations fall into this category.  In this case you need to know your budget before you go shopping.&lt;/p&gt;
&lt;p&gt;Identifying a figure in a simple formula is impossible, but most organizations are putting the bulk of their outreach budget into online campaigns because it tends to be the most efficient use of budget.  On top of that, results can be tracked and therefore easily improved, and the time to engage and close your prospect is faster.&lt;/p&gt;
&lt;p&gt;No more than 50% of your budget should go into the entire technology deployment.  At least 50% needs to be held back for staff to do the work – creating content, putting together online marketing campaigns, tracking the results and improving the campaign for the next run.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;How much will we save?&lt;/b&gt;&lt;br /&gt;
This question is one of the most overlooked, least considered aspect of a technology buying decision.  For example, a solid content management system (CMS) like Drupal can save an organization enormous amounts of time and money, particularly when compared to a proprietary closed CMS or a website managed by Dreamweaver.&lt;/p&gt;
&lt;p&gt;The areas where savings can be had in a Drupal CMS fall into over a dozen categories, not all of which will apply to every organization.  Those categories are software licensing, license management, content management, technical management, hardware, hosting, security/reliability, support contracts, development or customization, training, opportunity cost, hardware upgrades, software upgrades, and eventual migration to another system.  Total up actual or projected costs for each of these areas.  The difference between your existing costs over the expected lifetime of the CMS is what you stand to save (or lose).  I&#039;ll cover each of the categories in more detail in future posts.&lt;/p&gt;
&lt;p&gt;For example, your costs to manage a proprietary CMS might be $175,000 per year, and you project costs of $125,000 per year to manage Drupal so $50,000 a year stands to be saved.  If you expect your new Drupal site to last you three years, that savings is $150,000.  Coupled with our prior budget of $60,210 that gives a maximum budget of $210,250.&lt;/p&gt;
&lt;p&gt;Answering these questions should help your organization identify a budget for your project.&lt;/p&gt;
</description>
     <comments>http://www.opensourcery.com/blog/brian-jamison/how-write-rfp-part-two-how-much-will-it-cost#comments</comments>
 <category domain="http://www.opensourcery.com/tags/budgeting-website">budgeting for a website</category>
 <category domain="http://www.opensourcery.com/tags/how-write-rfp">how to write an rfp</category>
 <category domain="http://www.opensourcery.com/tags/request-proposal">request for proposal</category>
 <category domain="http://www.opensourcery.com/tags/request-quotation">request for quotation</category>
 <category domain="http://www.opensourcery.com/tags/rfq">RFQ</category>
 <pubDate>Wed, 03 Feb 2010 18:08:35 +0000</pubDate>
 <dc:creator>Brian Jamison</dc:creator>
 <guid isPermaLink="false">427 at http://www.opensourcery.com</guid>
  </item>
  <item>
    <title>Boosting performance on a permission system with nested roles.</title>
    <link>http://www.opensourcery.com/blog/chad-granum/boosting-performance-permission-system-nested-roles</link>
    <description>&lt;p&gt;We discovered a problem while QA&#039;ing emC against a huge client database. The page which displays who has access to a client would take a full minute to load. This was deemed unacceptable, and a solution was found.&lt;/p&gt;
&lt;p&gt;The elementalclinic permissions system works on the idea that there are clients, personnel (staff members), roles to which personnel are members, and permissions for roles to access clients. Every staff member is given a &#039;primary role&#039; that only they are a member of. Personnel become members of roles when their primary role is added as a member of a system role. This also allows for nested roles where a staff member is a member of system role a, which is a member of system role b.&lt;/p&gt;
&lt;p&gt;Nested roles are useful when you want to share permissions between roles. For instance there is an all_clients role which grants access to all clients. The Admin role, being superuser, should also have access to all clients. With nested roles you simply make admin a member of all_clients. You can then add admins to admins, and non-admins who need all_client access to all_clients.&lt;/p&gt;
&lt;p&gt;The problem with nested roles comes when you need to check if a staff member has permissions to view a specific client. You need to build a list of all roles the staff member is a direct or indirect member of. You then need to check if any of these roles grants access to the client. On the access page this needed to be done for each staff member.&lt;/p&gt;
&lt;p&gt;To solve this problem I decided to leverage postgres. In the initial revision of the permissions system the database simply held the roles, direct memberships, and permissions. Traversing the roles and assessing client permissions for specific users was left entirely to the code. In the new revision I decided the database would maintain a complete map of memberships, both direct and nested. In addition the database would provide several views to simplify obtaining the results we need.&lt;/p&gt;
&lt;p&gt;The focus of the changes is with the table that hold memberships. Initially it&#039;s schema was very simple (Old way):&lt;br /&gt;
&lt;div class=&quot;geshifilter&quot;&gt;&lt;pre class=&quot;geshifilter-text&quot;&gt; 21 CREATE TABLE personnel_role_member(
 22     rec_id        SERIAL NOT NULL PRIMARY KEY,
 23     role_id       INTEGER REFERENCES personnel_role( rec_id ) NOT NULL,
 24     member_id INTEGER REFERENCES personnel_role( rec_id ) NOT NULL,
 25     -- Make sure duplicate memberships do not occur.
 26     UNIQUE( role_id, member_id ),
 27     -- Roles should not be members of themselves.
 28     CHECK( member_id != role_id )
 29 );&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Here is the new schema for tracking role memberships:&lt;br /&gt;
&lt;div class=&quot;geshifilter&quot;&gt;&lt;pre class=&quot;geshifilter-text&quot;&gt; 21 CREATE TABLE role_membership(
 22     rec_id         INTEGER UNIQUE NOT NULL PRIMARY KEY DEFAULT nextval(&#039;role_membership_rec_id_seq&#039;),
 23     role_id        INTEGER NOT NULL REFERENCES personnel_role( rec_id ) ON DELETE CASCADE,
 24     member_id      INTEGER NOT NULL REFERENCES personnel_role( rec_id ) ON DELETE CASCADE,
 25     direct_cause   INTEGER REFERENCES role_membership( rec_id ) ON DELETE CASCADE,
 26     indirect_cause INTEGER REFERENCES role_membership( rec_id ) ON DELETE CASCADE,
 27     -- Roles should not be members of themselves.
 28     CHECK( member_id != role_id ),
 29     CHECK( direct_cause != indirect_cause ),
 30     -- Duplicates are pointless.
 31     UNIQUE( role_id, member_id, direct_cause, indirect_cause )
 32 );&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;The main thing to note in the new schema are the &#039;direct_cause&#039; and &#039;indirect_cause&#039; fields. These reference other entrees in the same table. The point of this change is to track both direct and indirect memberships in one table. When a membership is added a trigger fires which adds an entree for all resulting indirect memberships.&lt;/p&gt;
&lt;p&gt;The trigger code is fairly complicated, so I am posting a simplified psudo-code version. This trigger is fired whenever an insert occurs on the role_membership table. Note: In this psudo-code &#039;us&#039; or &#039;we&#039; refers to the role that is becoming a member.&lt;br /&gt;
&lt;div class=&quot;geshifilter&quot;&gt;&lt;pre class=&quot;geshifilter-text&quot;&gt;  Check for recursive memberships, raise an exception if found.
&amp;nbsp;
  Add memberships to all the roles the role we just became a member of is a member of. Direct cause is the new membership, indirect cause is the existing membership
&amp;nbsp;
  Add memberships to the role we just became a member of to the roles that are members of us. Direct cause is the existing membership, indirect cause is the new membership.&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;This trigger also fires off for any indirect memberships added by the trigger recursively. This trigger results in a table that always has a complete list of both direct and indirect memberships.&lt;/p&gt;
&lt;p&gt;From this table it is a simple matter to create views for just direct or indirect members. Views for which roles have access to which clients is also fairly trivial. We can even create a view that shows client permissions with the reason(membership) that grants them.&lt;/p&gt;
&lt;p&gt;Here are links to the original permissions schema, as well as the migration to the new system.&lt;br /&gt;
&lt;a href=&quot;http://github.com/opensourcery/elementalClinic/blob/master/app/database/schema/437-permissions.sql&quot;&gt;Original&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://github.com/opensourcery/elementalClinic/blob/master/app/database/schema/439-permissions-speed.sql&quot;&gt;Migration&lt;/a&gt;&lt;br /&gt;
And here is some additional documentation&lt;br /&gt;
&lt;a href=&quot;http://github.com/opensourcery/elementalClinic/blob/master/app/database/437-439-PERMISSIONS-SCHEMA-README&quot;&gt;README&lt;/a&gt;&lt;/p&gt;
</description>
     <comments>http://www.opensourcery.com/blog/chad-granum/boosting-performance-permission-system-nested-roles#comments</comments>
 <category domain="http://www.opensourcery.com/tags/access">access</category>
 <category domain="http://www.opensourcery.com/tags/elementalclinic">elementalClinic</category>
 <category domain="http://www.opensourcery.com/tags/groups">groups</category>
 <category domain="http://www.opensourcery.com/tags/performance">performance</category>
 <category domain="http://www.opensourcery.com/tags/permission">permission</category>
 <category domain="http://www.opensourcery.com/tags/permissions">permissions</category>
 <category domain="http://www.opensourcery.com/tags/postgrees">postgrees</category>
 <category domain="http://www.opensourcery.com/tags/postgresql">postgresql</category>
 <category domain="http://www.opensourcery.com/tags/roles">roles</category>
 <category domain="http://www.opensourcery.com/tags/security">security</category>
 <category domain="http://www.opensourcery.com/tags/speed">speed</category>
 <category domain="http://www.opensourcery.com/tags/sql">sql</category>
 <category domain="http://www.opensourcery.com/tags/trigger">trigger</category>
 <category domain="http://www.opensourcery.com/tags/triggers">triggers</category>
 <pubDate>Tue, 29 Dec 2009 16:17:39 +0000</pubDate>
 <dc:creator>Chad Granum</dc:creator>
 <guid isPermaLink="false">405 at http://www.opensourcery.com</guid>
  </item>
  <item>
    <title>Retrofitting a role and permissions system to a large application.</title>
    <link>http://www.opensourcery.com/blog/chad-granum/retrofitting-role-and-permissions-system-large-application</link>
    <description>&lt;h2&gt;The project&lt;/h2&gt;
&lt;p&gt;Recently I was given the task of overhauling the permissions system of eleMentalClinic. We needed a way to specify which clinicians could view which clients. We needed to ensure client security by preventing unauthorized clinicians from viewing certain clients.&lt;/p&gt;
&lt;h2&gt;Background&lt;/h2&gt;
&lt;p&gt;The original eMC permissions system was very simple. In the database there was a list of roles. There was also a table that listed client-&gt;role relations. Roles were identified by name. Roles were only used to verify a clinician had access to a given controller.&lt;/p&gt;
&lt;h2&gt;The plan&lt;/h2&gt;
&lt;p&gt;This refactor was a multi-step process. The first step was to write a new role+permissions system that worked with the controller-access logic, but also allowed for clinician+client associations. The second step was to retrofit security check logic to the application.&lt;/p&gt;
&lt;p&gt;The first step is fairly simple. Creating roles and associations like what we needed for eMC is a common problem with several common solutions. I ended up migrating to a new system where we had system roles, personnel roles, role memberships, and role-client associations. Memberships are all role-role associations.&lt;/p&gt;
&lt;h2&gt;The problem&lt;/h2&gt;
&lt;p&gt;The second step is significantly more difficult, specially when you consider the size and complexity of eMC. One thought is to have the dispatcher intercept the client_id parameter and run a check against the current_user. The problem with this solution comes on pages where multiple clients are displayed, many without a request.&lt;/p&gt;
&lt;p&gt;The next possibly solution is to modify the client object to require authorization in order to build. The problem here is that the current_user is known to the controller, but not globally. Making the current_user a global did not sound like a good idea, in addition this would break a majority of the tests in the eMC test suite, a suite that is 2.9mb. If we had to refactor the client object, and all the resulting test failures, this task could take months.&lt;/p&gt;
&lt;h2&gt;The solution&lt;/h2&gt;
&lt;p&gt;I began toying with the idea of code that could retrofit the permissions into eMC at runtime. A magical module that would be able to provide the security check with all the information it needs. A module that could ensure security without the need to rewrite any of eMC&#039;s existing object code. Enter &lt;a href=&quot;http://search.cpan.org/~exodist/Package-Watchdog-0.08/&quot;&gt;Package-Watchdog&lt;/a&gt;. Package-Watchdog is a Perl module I wrote to do just that.&lt;/p&gt;
&lt;p&gt;With Package-Watchdog you can &#039;watch&#039; subroutines within a specific package, and &#039;forbid&#039; them from using subroutines in another package. The way it works is simple in concept, wrap code around the watched sub that rewrites the forbidden subs. During normal use the forbidden subs act as normal, However once inside a watched sub the forbidden ones are altered. This continues all the way down the stack, you could have a chain of subs as deep as you want, if any of them call the forbidden one the watchdog is triggered.&lt;/p&gt;
&lt;p&gt;By default Package-Watchdog will die when a forbidden sub is invoked within a watched sub. However Package-Watchdog is written so that you can provide a custom reaction subroutine. This custom reaction subroutine is passed all the information relevant to the watch. This includes the names of the subs called, the parameters they were called with, and the watchdog helper objects that manage them.&lt;/p&gt;
&lt;h2&gt;Package-Watchdog in eMC&lt;/h2&gt;
&lt;p&gt;In eMC a watchdog object is instantiated just before the controller. The watchdog is told to watch the controller&#039;s subroutines, and forbid the subroutines in the client object that are used to build it. The watchdog is provided a custom reaction sub. This custom reaction sub gets the controller via arguments, and the current user from the controller. The client_id being loaded is provided via the forbidden arguments. The forbidden sub can then take this information and run a security check. If the check passes the program continues, otherwise it throws a security exception.&lt;/p&gt;
&lt;p&gt;The main goal of the watchdog is to absolutely prevent displaying client information to an unauthorized clinician. The watchdog left the application badly broken, pages such as schedule would always throw security exceptions. This is still considered a win, it means no accidental displaying of client information.Now it becomes a task of fixing the security exceptions, and as an added bonus we can now see where they are so they don&#039;t slip by.&lt;/p&gt;
&lt;p&gt;As one might expect this could slow down an application considerably, and at first it did. I added caching to the permissions system, and also to the security check logic. The application now runs as fast as it always has in my experience.&lt;/p&gt;
&lt;h2&gt;Links&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://search.cpan.org/~exodist/Package-Watchdog-0.08/&quot;&gt;Package-Watchdog on CPAN&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://github.com/exodist/Package-Watchdog&quot;&gt;Package-Watchdog on github&lt;/a&gt;&lt;/p&gt;
</description>
     <comments>http://www.opensourcery.com/blog/chad-granum/retrofitting-role-and-permissions-system-large-application#comments</comments>
 <category domain="http://www.opensourcery.com/tags/package-watchdog">package-watchdog</category>
 <category domain="http://www.opensourcery.com/tags/permissions">permissions</category>
 <category domain="http://www.opensourcery.com/tags/retrofit">retrofit</category>
 <category domain="http://www.opensourcery.com/tags/role">role</category>
 <pubDate>Mon, 12 Oct 2009 17:48:49 +0000</pubDate>
 <dc:creator>Chad Granum</dc:creator>
 <guid isPermaLink="false">399 at http://www.opensourcery.com</guid>
  </item>
  <item>
    <title>Object#let in Ruby</title>
    <link>http://www.opensourcery.com/blog/zack-hobson/objectlet-ruby-0</link>
    <description>&lt;p&gt;
A common construct in functional programming languages is the &lt;tt&gt;let&lt;/tt&gt; macro, used to define lexically-scoped names. The &lt;tt&gt;let&lt;/tt&gt; macro exists in most (all?) Lisp dialects and spiritual descendants, including Clojure. Since it&#039;s possible to define lexically-scoped variables at any time in Ruby, there isn&#039;t much perceived need for a construct like &lt;tt&gt;let&lt;/tt&gt;. However, Ruby&#039;s block syntax makes it particularly easy to experiment with functional programming techniques, and in fact there is already a method in Ruby&#039;s standard library that is maddeningly similar to &lt;tt&gt;let&lt;/tt&gt;, the &lt;tt&gt;tap&lt;/tt&gt; method.
&lt;/p&gt;
&lt;p&gt;
The reason I assert that &lt;tt&gt;tap&lt;/tt&gt; is &quot;maddeningly similar&quot; to &lt;tt&gt;let&lt;/tt&gt; is that &lt;tt&gt;tap&lt;/tt&gt; does not return the result of the block, rather, it always returns the receiver. This makes it possible to take a value or values and create lexically-scoped names referring to them in a block, but there is no way to access the results of that block unless you explicitly stash them in the receiver or (possibly) a global. Even still, &lt;tt&gt;tap&lt;/tt&gt; has its uses, which is why it&#039;s been in the standard library since 1.9.
&lt;/p&gt;
&lt;p&gt;&lt;div class=&quot;geshifilter&quot;&gt;&lt;pre class=&quot;geshifilter-ruby&quot;&gt;&lt;span class=&quot;co1&quot;&gt;# output: up is down&lt;/span&gt;
&lt;span class=&quot;st0&quot;&gt;&amp;quot;down&amp;quot;&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;tap&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;|&lt;/span&gt;up&lt;span class=&quot;sy0&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;st0&quot;&gt;&amp;quot;up is #{up}&amp;quot;&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;
A Ruby implementation of &lt;tt&gt;let&lt;/tt&gt; would be similar to &lt;tt&gt;tap&lt;/tt&gt; in that it would allow you to create a lexical block, but it would differ in that it evaluates to the block result:
&lt;/p&gt;
&lt;p&gt;&lt;div class=&quot;geshifilter&quot;&gt;&lt;pre class=&quot;geshifilter-ruby&quot;&gt;&lt;span class=&quot;co1&quot;&gt;# output: up is down&lt;/span&gt;
&lt;span class=&quot;kw3&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;st0&quot;&gt;&amp;quot;down&amp;quot;&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;|&lt;/span&gt;up&lt;span class=&quot;sy0&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;st0&quot;&gt;&amp;quot;up is #{up}&amp;quot;&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;
In cases where you don&#039;t care about the result of the block you can use either one, but if you care about the block result instead of the receiver then you can use &lt;tt&gt;let&lt;/tt&gt; instead of &lt;tt&gt;tap&lt;/tt&gt;:
&lt;/p&gt;
&lt;p&gt;&lt;div class=&quot;geshifilter&quot;&gt;&lt;pre class=&quot;geshifilter-ruby&quot;&gt;&lt;span class=&quot;co1&quot;&gt;# output: UP IS DOWN&lt;/span&gt;
&lt;span class=&quot;kw3&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;st0&quot;&gt;&amp;quot;down&amp;quot;&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;|&lt;/span&gt;up&lt;span class=&quot;sy0&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;st0&quot;&gt;&amp;quot;up is #{up}&amp;quot;&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;upcase&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;
I find myself wanting to use &lt;tt&gt;tap&lt;/tt&gt; or &lt;tt&gt;let&lt;/tt&gt; in cases when I need to use a calculated value multiple times. I could just create a temporary variable, of course:
&lt;/p&gt;
&lt;p&gt;&lt;div class=&quot;geshifilter&quot;&gt;&lt;pre class=&quot;geshifilter-ruby&quot;&gt;c = some_complex_expression
do_something &lt;span class=&quot;kw1&quot;&gt;if&lt;/span&gt; c
other_method&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;c&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;
Instead I can use &lt;tt&gt;tap&lt;/tt&gt; (or &lt;tt&gt;let&lt;/tt&gt; if it&#039;s available) to achieve the same effect:
&lt;/p&gt;
&lt;p&gt;&lt;div class=&quot;geshifilter&quot;&gt;&lt;pre class=&quot;geshifilter-ruby&quot;&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;some_complex_expression&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;tap&lt;/span&gt; &lt;span class=&quot;kw1&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;|&lt;/span&gt;c&lt;span class=&quot;sy0&quot;&gt;|&lt;/span&gt;
  do_something &lt;span class=&quot;kw1&quot;&gt;if&lt;/span&gt; c
  other_method&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;c&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;kw1&quot;&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;
This is quite useful in ERB templates, where creating temporary variables feels especially wrong.
&lt;/p&gt;
&lt;p&gt;
You can also exploit a feature of Ruby to get multiple lexical names per block. If the receiver is an Array and you provide multiple names in the block arguments, the contents will automatically be broken out. This works with either &lt;tt&gt;tap&lt;/tt&gt; or &lt;tt&gt;let&lt;/tt&gt;:
&lt;/p&gt;
&lt;p&gt;&lt;div class=&quot;geshifilter&quot;&gt;&lt;pre class=&quot;geshifilter-ruby&quot;&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;to_a&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;tap&lt;/span&gt; &lt;span class=&quot;kw1&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;|&lt;/span&gt;one, two, three&lt;span class=&quot;sy0&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;kw3&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;st0&quot;&gt;&amp;quot;one is #{one}&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;kw3&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;st0&quot;&gt;&amp;quot;two is #{two}&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;kw3&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;st0&quot;&gt;&amp;quot;three is #{three}&amp;quot;&lt;/span&gt;
&lt;span class=&quot;kw1&quot;&gt;end&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw3&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;to_a&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;|&lt;/span&gt;one, two, three&lt;span class=&quot;sy0&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;st0&quot;&gt;&amp;quot;one is #{one}&amp;quot;&lt;/span&gt;, &lt;span class=&quot;st0&quot;&gt;&amp;quot;two is #{two}&amp;quot;&lt;/span&gt;, &lt;span class=&quot;st0&quot;&gt;&amp;quot;three is #{three}&amp;quot;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es0&quot;&gt;\n&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;
The implementation of both methods is trivial. It&#039;s not like any developer who wants to use &lt;tt&gt;let&lt;/tt&gt; needs to wait for some Ruby core developer to code it up for him. Here&#039;s the complete implementation of &lt;tt&gt;Object#let&lt;/tt&gt;:
&lt;/p&gt;
&lt;p&gt;&lt;div class=&quot;geshifilter&quot;&gt;&lt;pre class=&quot;geshifilter-ruby&quot;&gt;&lt;span class=&quot;kw1&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;Object&lt;/span&gt;
  &lt;span class=&quot;kw1&quot;&gt;def&lt;/span&gt; let
    &lt;span class=&quot;kw1&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;kw2&quot;&gt;self&lt;/span&gt;
  &lt;span class=&quot;kw1&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;kw1&quot;&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;
The &lt;tt&gt;tap&lt;/tt&gt; method (which is already in the standard library) is about twice as large, weighing in at two trivial lines:
&lt;/p&gt;
&lt;p&gt;&lt;div class=&quot;geshifilter&quot;&gt;&lt;pre class=&quot;geshifilter-ruby&quot;&gt;&lt;span class=&quot;kw1&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;Object&lt;/span&gt;
  &lt;span class=&quot;kw1&quot;&gt;def&lt;/span&gt; tap
    &lt;span class=&quot;kw1&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;kw2&quot;&gt;self&lt;/span&gt;
    &lt;span class=&quot;kw2&quot;&gt;self&lt;/span&gt;
  &lt;span class=&quot;kw1&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;kw1&quot;&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;
To other developers that stumble across this, I pose this question: what techniques and/or idioms do you favor when a scoped temporary variable is called for?
&lt;/p&gt;
</description>
     <comments>http://www.opensourcery.com/blog/zack-hobson/objectlet-ruby-0#comments</comments>
 <category domain="http://www.opensourcery.com/tags/ruby">Ruby</category>
 <pubDate>Fri, 09 Oct 2009 15:25:26 +0000</pubDate>
 <dc:creator>Zack Hobson</dc:creator>
 <guid isPermaLink="false">398 at http://www.opensourcery.com</guid>
  </item>
  <item>
    <title>Roll your own context conditions</title>
    <link>http://www.opensourcery.com/blog/jonathan-hedstrom/roll-your-own-contexts</link>
    <description>&lt;p&gt;The &lt;a href=&quot;http://drupal.org/project/context&quot;&gt;context module&lt;/a&gt; provides great flexibility in terms of the available ways to set a context, but it&#039;s also remarkably straightforward to define custom conditions.&lt;/p&gt;
&lt;p&gt;In order to set arbitrary contexts, hook_context_conditions() is implemented to define values and such. This example will use the value of a CCK field, called &lt;em&gt;field_foo&lt;/em&gt;:&lt;/p&gt;
&lt;p&gt;&lt;div class=&quot;geshifilter&quot;&gt;&lt;pre class=&quot;geshifilter-drupal6&quot;&gt;&lt;span class=&quot;coMULTI&quot;&gt;/**
 * Implementation of hook_context_conditions().
 */&lt;/span&gt;
&lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt; mymodule_context_conditions&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
  &lt;span class=&quot;re0&quot;&gt;$items&lt;/span&gt; = &lt;a href=&quot;http://www.php.net/array&quot;&gt;&lt;span class=&quot;kw3&quot;&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
  &lt;span class=&quot;co1&quot;&gt;// The key used here will be used below when setting the context.&lt;/span&gt;
  &lt;span class=&quot;re0&quot;&gt;$items&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#91;&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#039;mymodule_foo&#039;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#93;&lt;/span&gt; = &lt;a href=&quot;http://www.php.net/array&quot;&gt;&lt;span class=&quot;kw3&quot;&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;
    &lt;span class=&quot;st0&quot;&gt;&#039;#title&#039;&lt;/span&gt; =&lt;span class=&quot;sy0&quot;&gt;&amp;gt;&lt;/span&gt; &lt;a href=&quot;http://api.drupal.org/api/function/t/6&quot;&gt;&lt;span class=&quot;kw5&quot;&gt;t&lt;/span&gt;&lt;/a&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#039;Field Foo Value&#039;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;,
    &lt;span class=&quot;st0&quot;&gt;&#039;#description&#039;&lt;/span&gt; =&lt;span class=&quot;sy0&quot;&gt;&amp;gt;&lt;/span&gt; &lt;a href=&quot;http://api.drupal.org/api/function/t/6&quot;&gt;&lt;span class=&quot;kw5&quot;&gt;t&lt;/span&gt;&lt;/a&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#039;Set this when field_foo has a certain value.&#039;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;,
    &lt;span class=&quot;st0&quot;&gt;&#039;#options&#039;&lt;/span&gt; =&lt;span class=&quot;sy0&quot;&gt;&amp;gt;&lt;/span&gt; &lt;a href=&quot;http://www.php.net/array&quot;&gt;&lt;span class=&quot;kw3&quot;&gt;array&lt;/span&gt;&lt;/a&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;
      &lt;span class=&quot;co1&quot;&gt;// Note, these are hardcoded here for simplicity, but could&lt;/span&gt;
      &lt;span class=&quot;co1&quot;&gt;// easily use something like CCK&#039;s content_allowed_values() api&lt;/span&gt;
      &lt;span class=&quot;co1&quot;&gt;// function for more dynamic population.&lt;/span&gt;
      &lt;span class=&quot;st0&quot;&gt;&#039;value1&#039;&lt;/span&gt; =&lt;span class=&quot;sy0&quot;&gt;&amp;gt;&lt;/span&gt; &lt;a href=&quot;http://api.drupal.org/api/function/t/6&quot;&gt;&lt;span class=&quot;kw5&quot;&gt;t&lt;/span&gt;&lt;/a&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#039;Label 1&#039;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;,
      &lt;span class=&quot;st0&quot;&gt;&#039;value2&#039;&lt;/span&gt; =&lt;span class=&quot;sy0&quot;&gt;&amp;gt;&lt;/span&gt; &lt;a href=&quot;http://api.drupal.org/api/function/t/6&quot;&gt;&lt;span class=&quot;kw5&quot;&gt;t&lt;/span&gt;&lt;/a&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#039;Label 2&#039;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;,
    &lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;,
    &lt;span class=&quot;st0&quot;&gt;&#039;#type&#039;&lt;/span&gt; =&lt;span class=&quot;sy0&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;st0&quot;&gt;&#039;checkboxes&#039;&lt;/span&gt;,
  &lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
  &lt;span class=&quot;kw1&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;re0&quot;&gt;$items&lt;/span&gt;;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;The only other step is to actually fire the code that sets the context somewhere. In the example of setting a context based on the value of a CCK field, this can be done in hook_nodeapi(). But something like hook_init() can also be used.&lt;/p&gt;
&lt;p&gt;&lt;div class=&quot;geshifilter&quot;&gt;&lt;pre class=&quot;geshifilter-drupal6&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt; mymodule_nodeapi&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;re0&quot;&gt;$node&lt;/span&gt;, &lt;span class=&quot;re0&quot;&gt;$op&lt;/span&gt;, &lt;span class=&quot;re0&quot;&gt;$teaser&lt;/span&gt;, &lt;span class=&quot;re0&quot;&gt;$page&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
  &lt;span class=&quot;kw1&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;a href=&quot;http://www.php.net/isset&quot;&gt;&lt;span class=&quot;kw3&quot;&gt;isset&lt;/span&gt;&lt;/a&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;re0&quot;&gt;$node&lt;/span&gt;-&lt;span class=&quot;sy0&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;me1&quot;&gt;field_foo&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#91;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#93;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#91;&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#039;value&#039;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#93;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;  &lt;span class=&quot;re0&quot;&gt;$op&lt;/span&gt; == &lt;span class=&quot;st0&quot;&gt;&#039;view&#039;&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;re0&quot;&gt;$page&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; menu_get_object&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; === &lt;span class=&quot;re0&quot;&gt;$node&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;// Use the same key here as used to define the context condition&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;// above.  Note, this logic would need some re-working if&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;// field_foo allowed multiple values.&lt;/span&gt;
    context_set_by_condition&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#039;mymodule_foo&#039;&lt;/span&gt;, &lt;a href=&quot;http://api.drupal.org/api/function/check_plain/6&quot;&gt;&lt;span class=&quot;kw5&quot;&gt;check_plain&lt;/span&gt;&lt;/a&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;re0&quot;&gt;$node&lt;/span&gt;-&lt;span class=&quot;sy0&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;me1&quot;&gt;field_foo&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#91;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#93;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#91;&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#039;value&#039;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#93;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
  &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;That&#039;s it. Contexts can now be added through the UI or through code that react to the value of &lt;em&gt;field_foo&lt;/em&gt;.&lt;/p&gt;
</description>
     <comments>http://www.opensourcery.com/blog/jonathan-hedstrom/roll-your-own-contexts#comments</comments>
 <category domain="http://www.opensourcery.com/tags/context">Context</category>
 <category domain="http://www.opensourcery.com/tags/drupal">Drupal</category>
 <category domain="http://www.opensourcery.com/tags/drupal-6">Drupal 6</category>
 <pubDate>Wed, 07 Oct 2009 22:39:54 +0000</pubDate>
 <dc:creator>Jonathan Hedstrom</dc:creator>
 <guid isPermaLink="false">397 at http://www.opensourcery.com</guid>
  </item>
  <item>
    <title>How to write an RFP, part one: Always include a budget</title>
    <link>http://www.opensourcery.com/blog/brian-jamison/how-write-rfp-part-one-always-include-budget</link>
    <description>&lt;p&gt;I&#039;m writing this series of blog posts to help improve the response rate on your Requests for Proposals (RFPs) as well as increasing the chance that the right firms will respond.  We receive a number of invitations to respond to RFPs every week, and a surprising number do not contain enough information for us to respond.&lt;/p&gt;
&lt;p&gt;Rule number one, always include a budget in your RFP.  You may be thinking that disclosing your budget is a mistake, that it leaves you open to predatory firms, or price-gouging.  I disagree, and I&#039;ll tell you why.&lt;/p&gt;
&lt;p&gt;RFPs without a budget are perceived as risky to developers.  We wonder -- does the requestor have money set aside for the project?  Is the project even approved?  Is it in too early a stage for the developer to get involved?  Does the requestor understand the complexity required?&lt;/p&gt;
&lt;p&gt;Perhaps more importantly, a developer needs to know that they&#039;re the right fit.  Because of our size, it doesn&#039;t make sense for OpenSourcery to respond to an RFP if the requestor has a budget of $2,500, and it also doesn&#039;t make sense for use to respond to a budget of $5,000,000.  It could be argued that as developers we should know how much a given project will cost.  That may be so, but finding the answer is time consuming and therefore expensive.  Providing that answer is valuable; it requires expertise.  Don&#039;t expect that to be provided for free -- at least, not by people capable of giving an accurate answer.&lt;/p&gt;
&lt;p&gt;Responding to an RFP has real costs.  A developer must dedicate expensive resources; for example it costs my company at least five hundred dollars to respond to an RFP, both in hard and opportunity costs.  It can cost us many thousands.  I need to be convinced that there&#039;s enough profit potential in an RFP to justify the investment, and without a concrete budget I&#039;m forced to guess.  And my guess will always be &quot;not enough.&quot;&lt;/p&gt;
&lt;p&gt;Adding a budget is the most important component to an RFP.  Don&#039;t leave it out.&lt;/p&gt;
&lt;p&gt;If you don&#039;t know how much your project might cost, you need to find that out before you put your RFP out to developers.  I&#039;ll cover techniques for doing that in my &lt;a href=&quot;http://www.opensourcery.com/blog/brian-jamison/how-write-rfp-part-two-how-much-will-it-cost&quot;&gt;next post&lt;/a&gt;.&lt;/p&gt;
</description>
     <comments>http://www.opensourcery.com/blog/brian-jamison/how-write-rfp-part-one-always-include-budget#comments</comments>
 <category domain="http://www.opensourcery.com/tags/how-write-rfp">how to write an rfp</category>
 <category domain="http://www.opensourcery.com/tags/request-proposal">request for proposal</category>
 <pubDate>Mon, 21 Sep 2009 19:37:57 +0000</pubDate>
 <dc:creator>Brian Jamison</dc:creator>
 <guid isPermaLink="false">393 at http://www.opensourcery.com</guid>
  </item>
  <item>
    <title>Achieving success, part three: Stop re-inventing the wheel</title>
    <link>http://www.opensourcery.com/blog/brian-jamison/achieving-success-part-three-stop-re-inventing-wheel</link>
    <description>&lt;p&gt;One of the major reasons I believe in open source is efficiency.  Leveraging open source software should allow you to spend your time and money on customization or innovative new features.&lt;/p&gt;
&lt;p&gt;For example, it doesn&#039;t make sense to build a content management system from scratch when you can leverage the efforts of hundreds of thousands of programmer hours for free.  And yet, developers do this all the time.&lt;/p&gt;
&lt;p&gt;Open source developers aren&#039;t exempt.  And simply using open source tools doesn&#039;t automatically guarantee the wheel isn&#039;t wastefully being re-invented.  You have to leverage an open source &lt;i&gt;project&lt;/i&gt; to do that.&lt;/p&gt;
&lt;p&gt;What&#039;s the difference between tools and projects?&lt;/p&gt;
&lt;p&gt;Tools are just what they sound like; they allow you to build, but they&#039;re not the end product.  PHP and Ruby on Rails are tools.  Projects are finished work and in many cases need nothing more than installation to be useful.  Drupal and Wordpress are examples of open source projects.&lt;/p&gt;
&lt;p&gt;Developers often say, &quot;Don&#039;t worry, I&#039;m using open source tools on this project!&quot; and happily waste hundreds of hours duplicating work that is freely available.&lt;/p&gt;
&lt;p&gt;Why would a developer re-invent the wheel?  I don&#039;t have a good answer for that, but I can speculate.  They&#039;re probably not trying to make a project cost more.  They may underestimate the difficulty, or the complexity involved.  They might not be looking out for your best interests; who will manage the site after they move on, or how will you be able to inexpensively add new features down the road.  They may be unwilling to invest the the hundreds of hours mastering an open source project.  Or they may believe they can do it better; they have a grand vision for turning your contract work into a new open source project.  No problem -- unless you, the client, have to pay for it.&lt;/p&gt;
&lt;p&gt;I have three recent examples.  The names have been changed to protect the re-inventors, but I&#039;ve encountered each within the last two months.&lt;/p&gt;
&lt;p&gt;Case #1&lt;br /&gt;
We were recently asked to evaluate a content management system written from scratch using the open source Ruby on Rails tools.  And while the site looks beautiful, they wasted time and money re-inventing the wheel.  Instead of spending months building the site from scratch, they could have installed Drupal in minutes and invested in useful new features, even better design, or just saved the money.&lt;/p&gt;
&lt;p&gt;Case #2&lt;br /&gt;
A company spent tens of thousands of dollars customizing Drupal to great benefit. They attributed much of the success of their product to the marketing and social functions their site gave them -- features other competitors lack.  Unfortunately they recently hired a junior programmer.  The junior programmer threw the old site away and spent months building a new website from scratch using open source tools, but not re-using any of the prior work.  And while the new site looks great, the old site could have been themed to look exactly the same as the new site in about two days, retaining the sophistication already developed.  As it stands, who will maintain this site once the junior programmer moves on?  Are there unknown but serious security holes in the new system?&lt;/p&gt;
&lt;p&gt;Case #3&lt;br /&gt;
This week I met a web developer who built a new content management system for a client from scratch using PHP.  He wondered whether or not it would be a good business opportunity to sell it to other companies.  I had to tell him that there is simply no way that a new content management system written by two guys will be able to compete in the overcrowded content management space.  Their fresh new system lacks the thousands of free enhancements available, the sophisticated permissions, workflows, solid security and design flexibility that Drupal offers.  And it will never be able to catch up, because hundreds of people are working every day to make Drupal better.&lt;/p&gt;
&lt;p&gt;In each of these cases, tens of thousands of dollars could have been saved or put to better use.  Please don&#039;t re-invent the wheel.  Hold your developers accountable to their design decisions.  Ask them how they intend to leverage existing open source projects to save you money.&lt;/p&gt;
&lt;p&gt;In future blog posts I&#039;ll talk about productizing applications in a niche market, but beware the developer that talks about turning your consulting job into a mainstream product like a content management system.&lt;/p&gt;
</description>
     <comments>http://www.opensourcery.com/blog/brian-jamison/achieving-success-part-three-stop-re-inventing-wheel#comments</comments>
 <pubDate>Fri, 11 Sep 2009 00:46:51 +0000</pubDate>
 <dc:creator>Brian Jamison</dc:creator>
 <guid isPermaLink="false">392 at http://www.opensourcery.com</guid>
  </item>
  </channel>
</rss>
