<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title /><link>http://info.rjmetrics.com/blog/</link><description>RSS feeds for </description><ttl>60</ttl><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/rjmetrics/metricsystem" /><feedburner:info uri="rjmetrics/metricsystem" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item><comments>http://info.rjmetrics.com/blog/bid/52753/Our-Living-Style-Guide-Writing-maintainable-HTML-CSS#Comments</comments><slash:comments>1</slash:comments><title>Our Living Style Guide (Writing maintainable HTML/CSS)</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/9xl6m9wQBXw/Our-Living-Style-Guide-Writing-maintainable-HTML-CSS</link><description>&lt;p&gt;There's a lot of talk about scaling apps for growth. Scaling server architecture, writing code that will handle millions of requests etc. but I rarely hear about scaling HTML/CSS. By this I don't mean &lt;em&gt;performance&lt;/em&gt;, I mean &lt;em&gt;maintainability&lt;/em&gt;. Let's take a look at this fact:&amp;nbsp;Facebook currently has &lt;a href="http://www.slideshare.net/stubbornella/our-best-practices-are-killing-us" rel="nofollow" title="6498 color declarations" target="_blank"&gt;6498 color declarations&lt;/a&gt;! You don't get there unless there wasn't a plan for maintainable markup from the beginning.&amp;nbsp;Since that sounds like a big ol' mess, I'm dedicated to avoiding that problem at RJ.&lt;/p&gt;
&lt;p&gt;The solution, quite simply, is to start forming a set of rules, nomenclature and workflow to form an architecture.&lt;/p&gt;
&lt;h3&gt;The Goals:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Create a worflow for creating and understanding new markup.&lt;/li&gt;
&lt;li&gt;Give developers who aren't experts in CSS, a logical and consistent way to markup HTML without having to ask a designer.&lt;/li&gt;
&lt;li&gt;Impose markup standards within a growing organization.&lt;/li&gt;
&lt;li&gt;Make it obvious when something strays from being consistent with an organization's style, and publicly shame us into correcting it. It's an experiment, and hopefully generates feedback.&lt;/li&gt;
&lt;li&gt;Save time, and thus, save $ for beer.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&amp;nbsp;The Strategy:&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1. Break UI components into objects conceptually.&lt;/strong&gt; (Buttons, notices, pickers, etc)&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Address those components in a unified stylesheet:&amp;nbsp;&lt;/strong&gt;&lt;a href="https://dashboard.rjmetrics.com/v2/sass/common.scss" rel="nofollow" title="common.scss" target="_blank"&gt;common.scss&lt;/a&gt;&amp;nbsp;(We use &lt;a href="http://sass-lang.com/" rel="nofollow" title="Sass" target="_blank"&gt;Sass&lt;/a&gt; with &lt;a href="http://compass-style.org/" rel="nofollow" title="Compass" target="_blank"&gt;Compass&lt;/a&gt;, and it's pretty awesome).&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Drop common.css into the app and play whack a mole with the style inconsistencies that crop up.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This part ended up being WAY easier than I anticipated. The reason being that there wasn't much semantic markup. Nearly everything was a div or span with a class on it. I love semantic markup, but this was a case where a lack of it had an unintended positive outcome. This alone deserves its own post. The biggest issue actually ended up being typography since there were so many declarations. We're still sorting this out.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Isolate more objects and add&lt;/strong&gt;&lt;strong&gt;&amp;nbsp;them to common.css until all commonly used objects reside in one place.&lt;/strong&gt; I like to think of common.css eating the other style sheets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Create a &lt;a href="http://style.rjmetrics.com/" rel="nofollow" title="living style guide" target="_blank"&gt;living style guide&lt;/a&gt; that outlines what each object looks like, its class structure, and its markup.&lt;/strong&gt; It's using the same common.css that's deployed in our app, so if it works in the style guide, it will work in the app.&lt;/p&gt;
&lt;p&gt;Take adding a notice for example. All the developer needs to do is go to the style guide, copy the HTML, add the classes they need, and paste into the app. They can even add classes that don't exist yet, and have someone like me go back and add the CSS later.&lt;/p&gt;
&lt;img id="img-1329500274397" src="http://info.rjmetrics.com/Portals/17916/images/Screen Shot 2012-02-17 at 12.21.30 PM-resized-600.png" border="0" alt="scalable app design" /&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The style guide was inspired by and is based on Kyle Neath's &lt;a href="https://github.com/kneath/kss" title="KSS" target="_self"&gt;KSS&lt;/a&gt; and more recently takes a play from &lt;a href="http://pea.rs/" title="Pea.rs" target="_self"&gt;Pea.rs&lt;/a&gt; by &lt;a href="http://simplebits.com/" rel="nofollow" title="SimpleBits" target="_self"&gt;SimpleBits&lt;/a&gt;. Nomenclature and organization are inspired by Nicole Sullivan's &lt;a href="https://github.com/stubbornella/oocss/wiki" title="OOCSS" target="_self"&gt;OOCSS&lt;/a&gt; and Jonathan Snook's &lt;a href="http://smacss.com/" title="SMACSS" target="_self"&gt;SMACSS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://style.rjmetrics.com/" title="Check it out" target="_self"&gt;Check it out&lt;/a&gt;, and let us know what you think.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; If you've got an opinion on this, maybe you'd like to work with us! &lt;a href="http://rjmetrics.theresumator.com/apply/EOY21i/UIUX-Developer.html" rel="nofollow" title="Apply here" target="_blank"&gt;Apply here&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/9xl6m9wQBXw" height="1" width="1"/&gt;</description><dc:creator>Matt Monihan</dc:creator><pubDate>Mon, 20 Feb 2012 15:47:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:52753</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/52753/Our-Living-Style-Guide-Writing-maintainable-HTML-CSS</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/52877/Pinterest-Data-Analysis-An-Inside-Look#Comments</comments><slash:comments>11</slash:comments><title>Pinterest Data Analysis: An Inside Look</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/m5etiF1usbA/Pinterest-Data-Analysis-An-Inside-Look</link><description>&lt;p&gt;Pinterest is the hottest young site on the internet. &amp;nbsp;In the past six months, the social sharing tool has gone from effectively non-existent to one of the top 100 sites on the web (and is &lt;a href="http://www.alexa.com/siteinfo/pinterest.com" title="on track" target="_blank"&gt;on track&lt;/a&gt; to break into Alexa&amp;rsquo;s Top 50).&lt;br /&gt;&lt;br /&gt;Pinterest&amp;rsquo;s &lt;a href="http://siteanalytics.compete.com/pinterest.com/" title="traffic charts" target="_blank"&gt;traffic charts&lt;/a&gt; aren&amp;rsquo;t hockey sticks-- they&amp;rsquo;re rocket ships. &amp;nbsp;In our experience, when traffic is growing that sharply there is often something even more amazing going on under the hood. We wanted to see if the usage and engagement numbers for Pinterest were as remarkable as its traffic and gain insights into exactly what was driving growth. Unfortunately, the company has kept very quiet when it comes to its data.&lt;br /&gt;&lt;br /&gt;Tired of waiting, we took things into our own hands using some clever scripting and our secret sauce for &lt;a href="http://www.rjmetrics.com/" title="analytics" target="_blank"&gt;analytics&lt;/a&gt;: RJMetrics. &amp;nbsp;A full report is below, but here a few highlights from our findings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Pinterest is retaining and engaging users as much as 2-3x as efficiently as Twitter was at a similar time in its history.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pins link to a tremendously large universe of sites. &amp;nbsp;Etsy is the most popular source of pin content, but it only represents about 3% of pins.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Over 80% of pins are re-pins, demonstrating the tremendous virality at work in the Pinterest community. &amp;nbsp;To contrast, a study done at a similar time in Twitter&amp;rsquo;s history showed that only about 1.4% of tweets were retweets.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The quality of the average new user &lt;span&gt;(as defined by their level of engagement and likelihood to remain active)&lt;/span&gt;&amp;nbsp;is high but declining. &amp;nbsp;Users who have joined in recent months are 2-3x less active during their first month than the users that came before them.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&amp;nbsp;
&lt;h2&gt;How We Did It&lt;/h2&gt;
&lt;p&gt;We wrote some simple scripts to identify random users who joined at varying times in the company&amp;rsquo;s history and download their complete history of pins to conduct &lt;a href="http://info.rjmetrics.com/blog/bid/44977/Cohort-Analysis-in-RJMetrics" title="cohort analysis" target="_blank"&gt;cohort analysis&lt;/a&gt;. &amp;nbsp;We also pulled several hundred thousand additional pins from the general user population. &amp;nbsp;All told, we ended up with a database of nearly one million pins. &amp;nbsp;&lt;br /&gt;&lt;br /&gt;Thanks to our old friend the &lt;a href="http://en.wikipedia.org/wiki/Central_limit_theorem" title="central limit theorum" target="_blank"&gt;central limit theorem&lt;/a&gt;, we&amp;rsquo;re confident that our sizable random samples are representative of the greater population they were pulled from. &amp;nbsp;We should caveat, however, that there is always a risk of sampling bias. &amp;nbsp;Since Pinterest doesn&amp;rsquo;t use auto-incrementing IDs, we had to get creative about identifying random users and pins. &amp;nbsp;We identified user names based on common dictionary words and then expanded to general-population pins by guessing at ID numbers in numeric proximity to the pins of those core users.&lt;br /&gt;&lt;br /&gt;We loaded this raw data into RJMetrics and were able to conduct the following analysis in about 15 minutes. &amp;nbsp;If you&amp;rsquo;d like to give it a try with your own company&amp;rsquo;s data, &lt;a href="https://rjmetrics.com/pricing" title="RJMetrics is offering free 30-day trials for a limited time" target="_blank"&gt;RJMetrics is offering free 30-day trials for a limited time&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Content: What&amp;rsquo;s Being Pinned?&lt;/h2&gt;
&lt;p&gt;On Pinterest, every pin ties back to an external link. &amp;nbsp;We used RJMetrics to extract the top-level domain of those links for the pins in our sample. &amp;nbsp;What we found was a pretty tremendous long-tail effect. &amp;nbsp;In our sample of about a million pins, over 100,000 distinct source domains existed. &amp;nbsp;The twenty most prominent are shown below by percent of pins.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://info.rjmetrics.com/Portals/17916/images/source_domains.jpg" border="0" alt="source domains" /&gt;&lt;br /&gt;&lt;br /&gt;The most popular domain was Etsy.com, which powered just over 3% of pins. &amp;nbsp;Close behind was google.com, although almost all Google links point to Google Image Search, which is technically misattributed content from other 3rd party domains. &amp;nbsp;Flickr (2.5%), Tumblr (1.1%), and weheartit.com (1.0%) round out the top 5, after which no domain represents more 1% of pins.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2&gt;Virality: Re-Pins and Tools&lt;/h2&gt;
&lt;p&gt;We were able to break out the population of pins based on how those pins were posted to Pinterest. &amp;nbsp;We were expecting a high percentage from pinmarklet, a browser bookmarklet that allows users to pin content from any website with one click. &amp;nbsp;However, what we found was astonishing.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://info.rjmetrics.com/Portals/17916/images/methods.jpg" border="0" alt="methods" /&gt;&lt;br /&gt;&lt;br /&gt;Remarkably, over 80% of pins are re-pins. &amp;nbsp;This is evidence of the impressive level of virality at work in the Pinterest community. &amp;nbsp;Pinterest is truly an ecosystem of sharing. &amp;nbsp;To contrast, a &lt;a href="http://blog.hubspot.com/Portals/249/sotwitter09.pdf" title="study" target="_blank"&gt;study&lt;/a&gt; done by Hubspot at a similar point in Twitter&amp;rsquo;s history showed that only about 1.4% of tweets were retweets.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2&gt;User Engagement: Cohort Analysis&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://info.rjmetrics.com/blog/bid/44977/Cohort-Analysis-in-RJMetrics" title="Cohort Analysis" target="_blank"&gt;Cohort Analysis&lt;/a&gt; is a powerful tool that allows us to study different groups of users at identical points in time in their lifecycles, regardless of when they actually joined the site. &amp;nbsp;It&amp;rsquo;s a great way of getting an &amp;ldquo;apples to apples&amp;rdquo; look at newer vs. older users to see how their engagement stacks up.&lt;br /&gt;&lt;br /&gt;In the chart below, each line represents a cohort and each cohort is a group of customers who made their first pin in a specific month. &amp;nbsp;For example, the June 2011 cohort consists of users who made their first pin in June 2011. &amp;nbsp;The line itself shows the &amp;ldquo;average cumulative pins made per cohort member.&amp;rdquo; So, the &amp;ldquo;Month 1&amp;rdquo; data point for the June 2011 cohort shows us how many items were pinned in June 2011 by users who joined in June 2011. &amp;nbsp;The &amp;ldquo;Month 2&amp;rdquo; data point on that same line shows us how many pins had been made by the average user in that cohort by the end of July 2011, and so on.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://info.rjmetrics.com/Portals/17916/images/monthly_cohort.jpg" border="0" alt="monthly cohort" /&gt;&lt;br /&gt;&lt;br /&gt;For most companies, even highly successful ones, cohort charts like these show lines that steadily decay toward a more horizontal slope over time. &amp;nbsp;This happens because there is some natural attrition rate with which users simply stop using the site, causing the incremental engagement of the average user to drop off. &amp;nbsp;&lt;br /&gt;&lt;br /&gt;That is definitely not the case with Pinterest.&lt;br /&gt;&lt;br /&gt;These lines show little to no decay whatsoever. Their slopes remain consistent, indicating a net attrition rate of close to 0%. &amp;nbsp;This either means that no one who starts using Pinterest ever stops or-- more likely-- that users who continue to use Pinterest become so much more engaged over time that their activities fully make up for those of any users who leave.&lt;br /&gt;&lt;br /&gt;To explore which of these two scenarios is playing out, we changed a few options in RJMetrics and ran the cohort analysis below:&lt;br /&gt;&lt;br /&gt;&lt;img id="img-1328680569497" src="http://info.rjmetrics.com/Portals/17916/images/cohort_weekly_distinct.jpg" border="0" alt="cohort weekly distinct" /&gt;&lt;br /&gt;&lt;br /&gt;This weekly cohort analysis shows the percentage of distinct users from some recent cohorts who come back to pin again in each of the first 8 weeks of their life cycle. &amp;nbsp;As you can see, between 40% and 60% of users are still actively pinning even as far out as week 8. &amp;nbsp;This may seem like a steep drop-off, but for a consumer internet business it&amp;rsquo;s exceptionally good.&lt;br /&gt;&lt;br /&gt;To provide some context, I want to compare this data to &lt;a href="http://techcrunch.com/2009/10/05/twitter-data-analysis-an-investors-perspective-2/" title="a similar analysis I conducted on Twitter in 2009" target="_blank"&gt;a similar analysis I conducted on Twitter in 2009&lt;/a&gt;. &amp;nbsp;Twitter was at a similar point in its life cycle (growing tremendously and about a year into its existence). &amp;nbsp;See the chart below:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://info.rjmetrics.com/Portals/17916/images/TWITTER1.jpg" border="0" alt="TWITTER" /&gt;&lt;br /&gt;&lt;br /&gt;Twitter&amp;rsquo;s decay rate was twice that of Pinterest, with user activity (measured by tweets) rapidly plummeting to around 20% before stabilizing. &amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2&gt;Growing Pains: Quality Decay&lt;/h2&gt;
&lt;p&gt;With every fast-growing consumer startup I&amp;rsquo;ve profiled, an increase in media coverage inevitably corresponds to a huge spike in the number of registered users and a drop-off in the quality of the average user (as defined by their level of engagement and likelihood to remain active). &amp;nbsp;Pinterest is no exception.&lt;br /&gt;&lt;br /&gt;&lt;img id="img-1328728915484" src="http://info.rjmetrics.com/Portals/17916/images/30dayactive.jpg" border="0" alt="30dayactive" /&gt;&lt;br /&gt;&lt;br /&gt;As shown above, the average new user who has joined Pinterest in the past few months is using the site substantially less than their counterparts from months in the past. &amp;nbsp;I speculate that this is caused by flocks of curious onlookers who are outside of Pinterest&amp;rsquo;s core audience registering accounts and failing to get engaged. &amp;nbsp;In the long-term, this could potentially represent a challenge to the company maintaining the remarkable engagement metrics we&amp;rsquo;ve seen so far.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Pinterest demonstrates some of the strongest user engagement, retention, and virality metrics I have ever seen in an online business. &amp;nbsp;The company has found tremendous success among its core demographic, and the potential reach of its appeal will be tested in the coming months as attention from broader audiences continues to increase.&lt;br /&gt;&lt;br /&gt;If the company&amp;rsquo;s performance to date is any indication, however, it will surely be a start-up to watch in 2012 and beyond.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/m5etiF1usbA" height="1" width="1"/&gt;</description><dc:creator>Robert Moore</dc:creator><pubDate>Wed, 15 Feb 2012 21:52:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:52877</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/52877/Pinterest-Data-Analysis-An-Inside-Look</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/52774/Lessons-learned-in-error-tracking#Comments</comments><slash:comments>0</slash:comments><title>Lessons learned in error tracking</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/8abiSJz-bAM/Lessons-learned-in-error-tracking</link><description>&lt;p&gt;Here at &lt;a href="http://www.rjmetrics.com" title="RJMetrics" target="_blank"&gt;RJMetrics&lt;/a&gt;&amp;nbsp;we pride ourselves on providing one of the leading hosted solutions in business analytics. One of our product's highlights is the ability to replicate and warehouse client's data in our data servers. Replication is not an easy task. It is driven by a set of very complex algorithms spanning across a number of different modules. Such algorithms are prone to latent bugs and vulnerabilities. They are hidden away in edge cases, just waiting for the right time to reveal themselves.&lt;/p&gt;
&lt;p&gt;&lt;img id="img-1328564863813" src="http://info.rjmetrics.com/Portals/17916/images/87910.strip.gif" border="0" alt="error tracking" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why logging is not enough&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;No matter how good of a developer you are, bugs are inevitable and the best way to deal with them is to always expect them. That is why every good software engineer should always provide some means of error tracking. Traditionally this is achieved through logging, also known as&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Tracing_(software)" title="tracing" target="_blank"&gt;tracing&lt;/a&gt;. Logging has the benefit of allowing the development team to go back at any given time and trace back the exact code path an operation took.&lt;/p&gt;
&lt;p&gt;Logging is not a silver bullet though, and for it to be useful an alert system has to be in place to make it obvious to the development team that something is wrong and someone has to attend to it. Without a good reporting mechanism, bugs in fundamental areas of the system are never discovered and resolved, and any further enhancements to it are made on the false assumption that the core of the system is reliable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The problem with email alerts&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Usually development teams handle error reporting by injecting email alerts whenever an exception is caught. These emails often go to a single recipient, or to a mailing list. The problem with email alerts going to a single person is simply NO transparency. The rest of the team will have no clue about these issues unless they are forwarded/delegated to the rest of the team.&lt;/p&gt;
&lt;p&gt;Email alerts are not any more useful if they are sent to a set of developers because it provides no accountability. Everyone in that mailing list will just expect everyone else to attend to them. Furthermore such email alerts will eventually get lost in someone's inbox with no good way of going back to them or tracking them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Our take on error reporting&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The same exact scenario was playing when I first started working here. One of the first assignments I was tasked with was to replace all of the annoying, at best, emails with a much better system that would allow us to be more aggressive and proactive in resolving bugs. The initial solution was:&lt;/p&gt;
&lt;p&gt;1. Provide a web interface through which at any time we could see any errors that occurred in the replication process&lt;/p&gt;
&lt;p&gt;2. The interface would include detailed information along with a full stack trace, exception messages, as well as the frequency at which an issue has been happening&lt;/p&gt;
&lt;p&gt;3. Reporting would occur for every distinct combination of replication job type and construct.&lt;/p&gt;
&lt;p&gt;You might rightfully say, "how was that a better solution than emailing everyone in the team!". It wasn't much different, but it allowed us to make our error reporting even more useful by just taking small incremental steps with no significant effort from our development team.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Our next step was to dedicate one person in every sprint cycle to attend to all the issues being reported, and to make sure that any false positives are filtered out and any critical issues are resolved. This was obviously already working much better that the email alert system but it was still not providing enough transparency to the rest of the team. Unless we all took the time to check, we wouldn't know how many errors got generated and how many of them got resolved.&lt;/p&gt;
&lt;p&gt;The solution was to integrate our error tracking and reporting mechanism with fogbugz. New tickets get created when replication job errors occur, and they are handled just like any other high priority tickets in our sprint. We can now track replication job errors through our familiar ticket tracking system and even get to use our own product to make a more intelligent analysis of bugs in our system.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In just a few sprint cycles we were able to bring down the number of replication job errors from affecting around 20 clients close to none at any given time. We were able to uncover and resolve some really obscure bugs and we can now be confident that when something goes wrong we will be addressing it at a timely manner and before it affects any of our clients.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/8abiSJz-bAM" height="1" width="1"/&gt;</description><dc:creator>Yiannis Nicolaou</dc:creator><pubDate>Wed, 08 Feb 2012 16:22:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:52774</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/52774/Lessons-learned-in-error-tracking</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/52842/RJMetrics-Now-Offering-Free-Trials-Limited-Time-Only#Comments</comments><slash:comments>0</slash:comments><title>RJMetrics Now Offering Free Trials (Limited Time Only)</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/xDoRc-a79Sc/RJMetrics-Now-Offering-Free-Trials-Limited-Time-Only</link><description>&lt;p&gt;Today, we're to announcing an exciting limited-time promotion: We are offering 30-day trials of RJMetrics, including implementation and training, at absolutely no charge.&lt;/p&gt;
&lt;p&gt;This is more than a just a proof-of-concept. &amp;nbsp;It's the same full-featured experience that would normally cost you $500 or more for your first month's subscription. &amp;nbsp;And, since RJMetrics is a month-to-month subscription service with no long-term commitments, there is now absolutely no risk or cost associated with giving RJMetrics a test run with your own data.&lt;/p&gt;
&lt;p&gt;Why Are We Doing This? &amp;nbsp;Well, as you might have guessed, we are huge fans of data. Recently, our data has been telling us something very exciting: once our customers start using RJMetrics, they don't want to stop. &amp;nbsp;This makes us comfortable enough to make a bet on ourselves.&lt;/p&gt;
&lt;p&gt;By introducing free trials, we'll be giving away thousands of dollars of business intelligence software, our time, and our insights as a way of spreading the word about what we have to offer. &amp;nbsp;We're treating this as a limited time "experiment" as a way of determining what free trials would mean for our business. &amp;nbsp;We hope you'll take advantage of this amazing offer while it lasts.&lt;/p&gt;
&lt;p&gt;As always, you can use our website to &lt;a href="https://www.rjmetrics.com/signup" title="contact us to learn more about RJMetrics" target="_blank"&gt;contact us to learn more about RJMetrics&lt;/a&gt; or &lt;a href="https://www.rjmetrics.com/demo" title="try a live demo" target="_blank"&gt;try a live demo&lt;/a&gt; featuring a fictional company's data.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/xDoRc-a79Sc" height="1" width="1"/&gt;</description><dc:creator>Robert Moore</dc:creator><pubDate>Tue, 07 Feb 2012 23:09:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:52842</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/52842/RJMetrics-Now-Offering-Free-Trials-Limited-Time-Only</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/52545/The-Human-Element-in-Automated-Software-Testing#Comments</comments><slash:comments>1</slash:comments><title>The Human Element in Automated Software Testing</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/7Im1wgl49Lw/The-Human-Element-in-Automated-Software-Testing</link><description>&lt;div&gt;As with any startup, the excitement of improving and adding to our current product often overshadows more mundane aspects of software development, such as automated software testing. &amp;nbsp;In response to this, here at &lt;a href="http://www.rjmetrics.com" title="RJMetrics" target="_self"&gt;RJMetrics&lt;/a&gt;&amp;nbsp;we have recently been examining our current suite of automated tests and reevaluating our strategy towards testing. &amp;nbsp;There are already lots of great blog posts about unit testing philosophy and best practices, so instead I'd like to share some of our personal experiences navigating the human elements of automated software testing.&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Testing can be a divisive issue.&lt;/strong&gt; Each developer subscribes to his or her own philosophy of software development, and this includes testing. &amp;nbsp;You will never get everyone to agree on these issues and could spend hours debating the goals and merits of testing, so my best advice is to decide upon and document a team philosophy early on. &amp;nbsp;This includes how your team defines the basic terms such as unit and integration test, and classifying the types of tests that are important for your product. &amp;nbsp;You should also clarify the main goals of your tests (to catch bugs, aid in refactoring, etc), as this affects how tests are written and what is tested. &amp;nbsp;Once this is in place and everyone is on the same page, you can move forward with more meaningful discussions.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A smaller number of thoughtful unit tests is infinitely better than a large number of poorly written unit tests.&lt;/strong&gt; &amp;nbsp;In addition to failing to catch real bugs, bad unit tests break as a result of unrelated code changes. Fixing such tests slows down product development by taking time away from other projects, and it takes an even worse psychological toll on the team. &amp;nbsp; Spending minutes or hours debugging a failing unit test is enough to turn the most avid supporter sour on testing. &amp;nbsp;To avoid such tests, everyone should be familiar with unit testing "best practices" and any testing pitfalls specific to your codebase should be addressed as early on as possible.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;People are more likely to write and run unit tests if its easy to do.&lt;/strong&gt; Try to simplify the process as much as possible by providing a collection of helper functions and objects that will allow developers to focus on testing the code at hand. For us, this means providing a set of "stock" objects, ready to be used in a test.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;Bearing in mind the experiences above, we are moving forward to improve and simplify our automated testing. &amp;nbsp;There is still much more for us to learn and we will periodically reevaluate and keep everyone posted on the success of our testing initiative in catching bugs, refactoring old code and aiding in new code development. &amp;nbsp;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/7Im1wgl49Lw" height="1" width="1"/&gt;</description><dc:creator>Cathy Lennon</dc:creator><pubDate>Tue, 31 Jan 2012 23:03:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:52545</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/52545/The-Human-Element-in-Automated-Software-Testing</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/52535/Data-Driven-Hiring-Hiring-an-Assistant#Comments</comments><slash:comments>3</slash:comments><title>Data Driven Hiring: Hiring an Assistant</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/1xGdjOTDi0k/Data-Driven-Hiring-Hiring-an-Assistant</link><description>&lt;p&gt;As a start-up focused on capital efficiency, the idea of an assistant always seemed frivolous. After all, what self-respecting entrepreneurs can't answer their own phones? &amp;nbsp;&lt;br /&gt;&lt;br /&gt;As we recently learned, that strategy is all well and good until the phones &lt;em&gt;&lt;strong&gt;really&lt;/strong&gt;&lt;/em&gt; start ringing. Or your staff grows large enough that you have to choose between keeping the kitchen stocked or doing code reviews. &amp;nbsp;For us, it was finally time to hire some help-- two weeks ago we posted a job opening for an Administrative Assistant. &amp;nbsp;&lt;br /&gt;&lt;br /&gt;As everyone knows, the job market is not great right now. &amp;nbsp;The day we posted the Administrative Assistant job, we got close to 100 applicants. &amp;nbsp;The number grew to 200 by the end of that week.&lt;br /&gt;&lt;br /&gt;With our time more precious than ever and (obviously) no administrative support to manage the process, we were at risk of burning far too much time choosing an applicant. &amp;nbsp;But that's not our style. &amp;nbsp;We hired the most outstanding candidate with under 8 hours of total work. &amp;nbsp;Here's how.&lt;/p&gt;
&lt;h2&gt;From 200 to 100: WMYU?&lt;/h2&gt;
&lt;p&gt;At the beginning of every job application, we make a simple request: &amp;ldquo;In 150 characters or less, tell us what makes you unique.&amp;rdquo; &amp;nbsp;We got this idea from &lt;a href="http://www.theresumator.com/" title="The Resumator" target="_blank"&gt;The Resumator&lt;/a&gt;, which is the awesome system we use to track applicants. &amp;nbsp;The &amp;ldquo;WMYU&amp;rdquo; question is a great opportunity for the applicant to showcase their personality. &amp;nbsp;It also turned out to be a great way to rapidly filter out unqualified candidates.&lt;br /&gt;&lt;br /&gt;Don&amp;rsquo;t get the wrong idea -- no one was rejected based on what they said. &amp;nbsp;It was how they said it that caught our eye. &amp;nbsp;As it turned out, half of our applicants could not provide a single-sentence answer without also including a grammar, spelling, or punctuation mistake. &amp;nbsp;For a job where the top requirement was &amp;ldquo;excellent written communication skills,&amp;rdquo; this kind of mistake was a deal-breaker. &amp;nbsp;(Note: we happily allowed Twitter-like abbreviations and other understandable/creative quirks.)&lt;br /&gt;&lt;br /&gt;Some of the more ridiculous responses are shared below to give you a sense of what we were dealing with...&lt;/p&gt;
&lt;p&gt;&lt;img id="img-1327887428397" src="http://info.rjmetrics.com/Portals/17916/images/commun.png" border="0" alt="commun" width="393" height="46" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The triple threat: spelling mistake, capitalization mistake, incomplete sentence.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;br /&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;img id="img-1327887498800" src="http://info.rjmetrics.com/Portals/17916/images/furthermore.png" border="0" alt="describe the image" width="600" height="56" /&gt;&lt;br /&gt;Furthermore, if you paste into a 150-character box it will cut off your answer.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;img id="img-1327887586660" src="http://info.rjmetrics.com/Portals/17916/images/illiterate.png" border="0" alt="illiterate" width="600" height="68" /&gt;&lt;br /&gt;Computer illiteracy wasn't one of the job requirements.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;img id="img-1327948907329" src="http://info.rjmetrics.com/Portals/17916/images/na.png" border="0" alt="na" width="250" height="50" /&gt;&lt;br /&gt;Multiple people did this. &amp;nbsp;If uniqueness is not applicable to you, you're going to be looking for a job for a while.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;From 100 to 50: Cover Letters&lt;/h2&gt;
&lt;p&gt;All applicants were required to submit a cover letter as part of their application. &amp;nbsp;These letters gave us a good sense of the long-form writing skills possessed by the remaining applicants. Again, writing letters and e-mails is a major piece of this job, so any glaring mistakes were grounds for elimination.&lt;br /&gt;&lt;br /&gt;Here again, it was much more about the quality of the writing than the actual content of the message.&lt;/p&gt;
&lt;h2&gt;From 50 to 25: Resumes&lt;/h2&gt;
&lt;p&gt;At this point, the experience and other qualifications of the applicant started coming into play. This is where we stopped looking for reasons to reject and started looking for good applicants to move forward. &amp;nbsp;Ambition, education, experience, and an interest in technology made 25 applicants stand out from the rest.&lt;/p&gt;
&lt;h2&gt;From 25 to 12: Project Completion&lt;/h2&gt;
&lt;p&gt;At this point, every single applicant was perfect on paper: outstanding qualifications, impeccable writing skills, and a genuine interest in the job. &amp;nbsp;So, now what? &amp;nbsp;Interviewing all 25 of them would have been overwhelming. &amp;nbsp;We needed to get creative.&lt;br /&gt;&lt;br /&gt;So, we decided to test who was really willing to go the extra mile. &amp;nbsp;I sent a bulk bcc e-mail to the 25 remaining applicants.&lt;br /&gt;&lt;br /&gt;The e-mail began with key information about the job: salary, benefits, working hours, vacation policy, etc. &amp;nbsp;&lt;br /&gt;&lt;br /&gt;Next, it asked them to complete a special project as soon as possible. &amp;nbsp;Applicants were asked to reply to the e-mail and attach a ZIP file that contained two PDFs: a writing sample and a set of e-mail templates that we could use in response to specific situations. &amp;nbsp;These situations ranged from simple (scheduling a call) to more complex (dealing with a dissatisfied customer).&lt;br /&gt;&lt;br /&gt;My e-mail ended with this paragraph: &amp;ldquo;Once you have replied to this e-mail with the ZIP file attached, please call my cell phone and leave me a short voicemail to let me know that the e-mail has been sent and explaining why you feel RJMetrics is a good fit for you. &amp;nbsp;I have intentionally not included my cell phone number here. &amp;nbsp;Someone as resourceful as you should be able to track it down easily (hint: it starts with 856).&amp;rdquo;&lt;br /&gt;&lt;br /&gt;This e-mail accomplished many things at once:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It ensured that any applicant choosing to move forward was comfortable with the exact compensation and expectations of the job. &amp;nbsp;This would save us from negotiations, confusion, or other time-consuming hiring issues later.&lt;/li&gt;
&lt;li&gt;It served as a further test of the applicant&amp;rsquo;s writing skills.&lt;/li&gt;
&lt;li&gt;It tested the basic technical competency of the applicant (creating PDFs, creating ZIP files).&lt;/li&gt;
&lt;li&gt;It provided us with a voice recording of each applicant to test their verbal communication skills.&lt;/li&gt;
&lt;li&gt;It assessed their willingness to be creative and conduct online research to track down information (in case you&amp;rsquo;re wondering how hard that was, googling &amp;ldquo;robert moore rjmetrics 856&amp;rdquo; reveals my phone number in about a dozen places).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Only about half of the applicants completed the project.&lt;/p&gt;
&lt;h2&gt;From 12 to 6: Project Results&lt;/h2&gt;
&lt;p&gt;The results of the project were extremely telling. &amp;nbsp;We could immediately identify the applicants who knew how to follow instructions, had good insights and written tact, and were excited about this specific job for reasons that made them likely to thrive here.&lt;/p&gt;
&lt;p&gt;Half of the responses stood out as both flawless and indicative of a good fit.&lt;/p&gt;
&lt;h2&gt;From 6 to 2: Phone Interviews&lt;/h2&gt;
&lt;p&gt;At this point, conducting 30-minute phone interviews was a practical thing to do. &amp;nbsp;We spoke to each of the remaining applicants about their specific experience, their interest in our company and the space in which we operate, and their interest in the job.&lt;br /&gt;&lt;br /&gt;To be honest, all of these applicants were outstandingly qualified and any one of them would have done a great job. &amp;nbsp;At this point, it was about their ability to contribute to our specific company&amp;rsquo;s unique needs and their likelihood to come in every day and enjoy the work they were doing and the people they were doing it with.&lt;br /&gt;&lt;br /&gt;Jake and I each spoke with 3 applicants and selected one each to make it to the next round.&lt;/p&gt;
&lt;h2&gt;From 2 to 1: In-Person Interviews&lt;/h2&gt;
&lt;p&gt;We brought the two top applicants into our office to meet us face-to-face. &amp;nbsp;They were obviously both exceptionally well qualified, which left us with a very difficult decision to make. &amp;nbsp;After some thoughtful analysis, we made our final decision and our applicant accepted the offer on the spot. &amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;For anyone out there applying for a job in this environment, please keep in mind that every little detail of your application may be scrutinized, and employers may be on the lookout for reasons to reject you before they start looking for reasons to hire you. &amp;nbsp;&lt;br /&gt;&lt;br /&gt;For those out there looking to make a hire in this environment, you are in the fortunate position of having many options. Don&amp;rsquo;t get intimidated by them-- if you employ a disciplined approach to narrowing the field, you will end up feeling good about having made the right hire.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/1xGdjOTDi0k" height="1" width="1"/&gt;</description><dc:creator>Robert Moore</dc:creator><pubDate>Tue, 31 Jan 2012 15:57:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:52535</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/52535/Data-Driven-Hiring-Hiring-an-Assistant</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/52415/3-Reasons-to-Consider-Working-at-a-Startup#Comments</comments><slash:comments>0</slash:comments><title>3 Reasons to Consider Working at a Startup</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/tSs0o028_LQ/3-Reasons-to-Consider-Working-at-a-Startup</link><description>&lt;p&gt;Prior to working at RJMetrics, I worked at Wells Fargo Bank. I had positive experiences there and learned a lot, but I wanted more. I made a list of attributes that the optimal job would have for me and found a match with RJMetrics. I am loving my experience and I have tried to pick out the top three reasons others working in a more traditional job should consider working at a startup.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://info.rjmetrics.com/Portals/17916/images/startup-sign-resized-600.png" border="0" alt="3 reasons to consider working at a startup" class="alignCenter" style="display: block; margin-left: auto; margin-right: auto;" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Rapid growth and how it will impact you and the company&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;As a startup, one of our main goals is to grow constantly and exponentially. It takes a wide range of skills that span across many disciplines and departments to successfully achieve the goals of a company. RJMetrics aims to achieve its goals with a small, dedicated team. I have found that my learning curve here is incredibly steep because I want to get better every day. I know that if I get better, there is a higher probability that we succeed and I know that all of my team members feel the same way. &lt;br /&gt;&lt;br /&gt;I have been working here for a little over five months and have been involved in projects that span across marketing, sales, law, technology development, product management, UI design, SEO, social media, client relationship management, and the list goes on and on. Sometimes my role is very client facing and at other times it focuses on our internal needs. The range of skills I develop here is much broader than any previous job. It is an opportunity to reach my full potential, uncover talents that I didn&amp;rsquo;t know that I had and then strive to reach my full potential in those areas as well. I can&amp;rsquo;t think of a more fulfilling experience when it comes to an employment opportunity than the growth of the company and the expansion of your own personal skillset growing together.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Know what you are doing and why you are doing it&amp;nbsp;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I understand our value and I am aligned with our vision. I didn&amp;rsquo;t walk in on day one with the full understanding but through my involvement in a broad range of projects, these things became apparent quickly. I believe in what we are doing, and this allows me to play a part in determining what my contributions should be and to accurately evaluate what kind of impact they are having. This level of understanding and transparency coupled with the ability and freedom to expand my skillset as needed makes me a highly effective team member. It makes us all highly effective. &lt;br /&gt;&lt;br /&gt;It is obvious on a day-to-day basis that we are all working towards the same goals, and this establishes a high level of trust between us. I am much more willing to take the time out to share something with another team member because I know that that person is going to use that information to make a valuable contribution. The company is willing to invest in me because they know it is a sound investment, and in turn I am willing to invest more into the company. This makes us capable of achieving what it would take a much larger team to achieve whose members were not aligned with the vision of the company.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Constant communication&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Communication is key and I have never been in a professional setting where it was as easy to do it as it is here. No red tape. No bureaucracy. Nobody is out of reach. Whether it be a complex question, a product improvement suggestion, a process recommendation, telling a joke or just yapping about something you find interesting everyone is accessible and ready to listen. The exchange of ideas, knowledge and insights is so easy that you can come in with an idea in the morning and be executing by the afternoon, having already vetted it with your team members. We are empowered by the ability to gain the knowledge that we need quickly and to put it to use to solve problems, to innovate and to become more efficient.&lt;/p&gt;
&lt;p&gt;I give kudos to my colleagues here for putting together a team of talented individuals who have found common ground in wanting to see their company succeed and in their own continuous development professionally and as individuals. We are lucky in that RJMetrics is allowing us to achieve all of these goals simultaneously. If you think this is something you want to try out, you can learn a little more &lt;a href="http://www.rjmetrics.com/about-us" rel="nofollow" title="about us" target="_self"&gt;about us&lt;/a&gt;, a little more about our &lt;a href="http://info.rjmetrics.com/blog/bid/51367/RJMetrics-Raises-1-2-Million-From-Leading-Early-Stage-Investors" title="recent funding" target="_self"&gt;recent funding&lt;/a&gt;, &lt;a href="http://info.rjmetrics.com/blog/bid/50397/Why-Our-Startup-is-Doubling-Down-on-Philadelphia" title="why we call Philly our home" target="_self"&gt;why we call Philly our home&lt;/a&gt;, &amp;nbsp;or check out our &lt;a href="http://www.rjmetrics.com/jobs" rel="nofollow" title="available positions" target="_self"&gt;available positions&lt;/a&gt;.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Perhaps my experience is unique, I would be interested in hearing others&amp;rsquo; experiences whether they be good or bad so feel free to comment away.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/tSs0o028_LQ" height="1" width="1"/&gt;</description><dc:creator>Gaston Burthey</dc:creator><pubDate>Thu, 26 Jan 2012 15:09:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:52415</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/52415/3-Reasons-to-Consider-Working-at-a-Startup</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/51890/PHPUnit-Tips-Stubs-vs-Mocks#Comments</comments><slash:comments>0</slash:comments><title>PHPUnit Tips: Stubs vs Mocks</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/bnjNdoDgX_8/PHPUnit-Tips-Stubs-vs-Mocks</link><description>&lt;p&gt;I recently spent some time digging into the PHPUnit mocking framework to clarify my own understanding and better decide how we can improve our unit testing tools. I've found the &lt;a href="http://www.phpunit.de/manual/3.0/en/mock-objects.html" title="PHPUnit documentation on the subject" target="_blank"&gt;PHPUnit documentation on the subject&lt;/a&gt; to be inadequate for anything but the most basic use cases. (The full API documentation does not include the mocking framework, as far as I can tell.) I'll try to clarify the one aspect of this that confused me the most and caused me to lose the most time.&lt;/p&gt;
&lt;h3&gt;Stubs vs. Mocks&lt;/h3&gt;
&lt;p&gt;This is touched on in the documentation, but I'm not a fan of the way it's described. "Mocks" are objects which have some of their methods replaced by stubs (methods with no behavior). "Stubs" are objects which have stubs for all methods, with expectations optionally placed on certain methods. As far as I can tell, the distinction between a mock and a stub comes when you provide a list of explicit methods to stub, or not. When you provide a list of methods like so:&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1608200.js"&gt;&lt;/script&gt;
&lt;p&gt;$mock will defer to the original class's methods for all method calls except for "methodOne" and "methodTwo". These methods will always result in successful calls, but will not return any values.&lt;/p&gt;
&lt;p&gt;When you don't provide any methods, you get a stub with no functionality. This object has the ability to act in place of the mocked class wherever it is used, but has no functionality on its own. Once you create this object, you can add expectations and return values to force it to behave in ways that are useful to you:&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1608203.js"&gt;&lt;/script&gt;
&lt;p&gt;This strategy allows you to build piecemeal mocks that build functionality you need as you go. I find this the most useful way to use PHP object mocking. If you're creating objects which need to be "partially mocked" in order to test, you might want to reevaluate the structure of your objects--possibly moving those partially mocked methods into another component, which can then be fully stubbed.&lt;/p&gt;
&lt;p&gt;At RJMetrics, I've been experimenting with a mock dependency container which will provide stubs for all our objects. This will give us the greatest flexibility in terms of being able to add units of functionality needed for a specific test, while still maintaining internal consistency with all of our dependent objects.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/bnjNdoDgX_8" height="1" width="1"/&gt;</description><dc:creator>Derek Mansen</dc:creator><pubDate>Wed, 18 Jan 2012 22:53:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:51890</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/51890/PHPUnit-Tips-Stubs-vs-Mocks</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/51652/Lexical-vs-Dynamic-Scope-in-Clojure#Comments</comments><slash:comments>7</slash:comments><title>Lexical vs Dynamic Scope in Clojure</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/n8R_CHtjqtU/Lexical-vs-Dynamic-Scope-in-Clojure</link><description>&lt;p&gt;Here at&amp;nbsp;&lt;a href="http://www.rjmetrics.com" title="RJMetrics" target="_blank"&gt;RJMetrics&lt;/a&gt;&amp;nbsp;we recently added&amp;nbsp;&lt;a href="http://info.rjmetrics.com/blog/bid/51373/Getting-Lazy-With-My-10-Time-Simple-PHP-Lazy-Load" title="10% time" target="_blank"&gt;10% time&lt;/a&gt;&amp;nbsp;to our development cycle. I decided to do my project in clojure because I needed easy concurrency and I wanted to learn a new skill. Since I have never worked in a&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Lisp_(programming_language)" title="lisp" target="_blank"&gt;lisp&lt;/a&gt;-&lt;span&gt;based language before, I found the fact that clojure has two ways to resolve a symbol's scope to be a little confusing at first. &lt;span&gt;I found many posts that helped explain the difference, but few took a beginner&amp;nbsp;approach.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;I hope this post will clear up any confusion that new clojurians may have.&lt;/p&gt;
&lt;img id="img-1326152711802" src="http://info.rjmetrics.com/Portals/17916/images/clojure-icon-resized-600.gif" border="0" alt="clojure" class="alignCenter" style="border-style: initial; border-color: initial; font-size: 13px; display: block; margin-left: auto; margin-right: auto;" /&gt;
&lt;div&gt;&lt;span style="font-size: x-small;"&gt;&lt;br /&gt;&lt;/span&gt;
&lt;h2&gt;Background&lt;/h2&gt;
&lt;p&gt;A "&lt;strong&gt;scope&lt;/strong&gt;" in computer science is a context that is created to encapsulate the values of variables (or symbols in clojure) to smaller pieces of code. Without any scopes, every variable would be global. Can you imagine if every time you used the variable &lt;em&gt;x&lt;/em&gt; or &lt;em&gt;i&lt;/em&gt; you had to worry about interfering with another piece of code? Luckily, most sane languages provide a means of creating and restricting the scope of variables. Some languages (eg. Clojure, Common Lisp, Perl) have two means of controlling scope, lexically (aka static) and dynamically.&lt;/p&gt;
&lt;h2&gt;Clojure Terminology&lt;/h2&gt;
&lt;p&gt;These are a few basic clojure terms you will need to know to understand the rest of this post.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;symbol&lt;/strong&gt; is similar to an identifier in other languages. Symbols are used to associate values with common names. In an imperative language like PHP you might say something like "$x = 5;". Now the variable $x equals 5, in clojure semantics I would say the symbol &lt;em&gt;x&lt;/em&gt;&amp;nbsp;is associated with the value 5. Clojure has an&amp;nbsp;&lt;a href="http://clojure.org/state" title="opinionated philosophy" target="_blank"&gt;opinionated philosophy&lt;/a&gt; on separating identities and values.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;value&lt;/strong&gt;&amp;nbsp;is just actual data, such as a number, string, function (code is data), vector, object, etc..&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;var&lt;/strong&gt;&amp;nbsp;is a way of tying a symbol to a potenitally changing value; they are created using the &lt;em&gt;def&lt;/em&gt;&amp;nbsp;macro. This will be covered in more depth when I cover dynamic scope.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Lexical Scoping&amp;nbsp;&lt;/h2&gt;
&lt;p&gt;The &lt;strong&gt;lexical&amp;nbsp;scope&lt;/strong&gt; of a symbol is the "textual region" (aka code block) where the symbol definition occurs, plus all child code blocks. You can imagine your code creating a tree of code blocks that the compiler can traverse. What defines a code block is dependent on the language. Lexical scoping is by far the most common amongst all modern&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/ALGOL" title="ALGOL" target="_blank"&gt;ALGOL&lt;/a&gt;-influenced languages (C, Java, etc). When the compiler is trying to resolve a reference&amp;nbsp;to a variable, it will first look in the inner-most scope and continue up the levels of scope (code blocks) until it finds its declaration. Lexical scope is sometimes called static scope since &lt;strong&gt;all symbol references can be resolved at compile-time&lt;/strong&gt;, as opposed to dynamic scope which needs runtime information. In this C example below the variable &lt;em&gt;i&lt;/em&gt;&amp;nbsp;is available within the for and while loops, because the while loop is &lt;em&gt;below&lt;/em&gt; the for loop. However, &lt;em&gt;i&amp;nbsp;&lt;/em&gt;is not available outside of the for loop since that is &lt;em&gt;above&lt;/em&gt;&amp;nbsp;the scope in which the variable was defined.&amp;nbsp;&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1584073.js?file=lexical.c"&gt;&lt;/script&gt;
&lt;p&gt;This is the scope you will be using in clojure the vast majority of the time. The main difference is the scope blocks are declared explicitly by the programmer in clojure rather than by the syntax of the language. In clojure, a lexical scope region is defined by a&amp;nbsp;&lt;a href="http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/let" title="let" target="_blank"&gt;let&lt;/a&gt;&amp;nbsp;block. In the code example below, &lt;em&gt;x, y, &lt;/em&gt;and &lt;em&gt;add&lt;/em&gt;&amp;nbsp;are all symbols that are associated with the values 3, 5, and a function that adds all of its arguments, respectively (remember functions are first-class values).&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1584073.js?file=lexcial1.clj"&gt;&lt;/script&gt;
&lt;p&gt;The lexical environment is encapsulated by the parentheses (aka parens) surrounding the &lt;em&gt;let&lt;/em&gt; block, which means as soon as I close the &lt;em&gt;let&lt;/em&gt; statement, those symbols go back to their original values. Here's a more complex example:&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1584073.js?file=lexical2.clj"&gt;&lt;/script&gt;
&lt;p&gt;The&amp;nbsp;&lt;a href="http://clojure.org/special_forms#Special Forms--(def symbol init?)" title="def" target="_blank"&gt;def&lt;/a&gt;&amp;nbsp;statement on the first line creates a new global&amp;nbsp;&lt;a href="http://clojure.org/vars" title="var" target="_self"&gt;var&lt;/a&gt;&amp;nbsp;with the value 2 and associates it with the symbol &lt;em&gt;z&lt;/em&gt;, which is similar to how constants would be used in other languages. In this example, we defined a new &lt;em&gt;let&lt;/em&gt; block within the previous one. Remember, when the compiler tries to resolve a symbol it will recursively go up each scope block until it finds the first symbol definition that matches. In the inner &lt;em&gt;let&lt;/em&gt; block we used the symbol &lt;em&gt;z&lt;/em&gt;, which already had a global definition. In this case, &lt;em&gt;z&lt;/em&gt; is being &lt;em&gt;shadowed&lt;/em&gt; by the value 10. As soon as we exit the &lt;em&gt;let&lt;/em&gt; block, the value of &lt;em&gt;z&lt;/em&gt; will return to its global definition. So by using &lt;em&gt;let&lt;/em&gt; blocks to declare your local symbols, you never have to worry about overwriting some global value like you would in PHP or JavaScript. One thing to remember about lexical scoping is that it only deals with the &lt;em&gt;text&lt;/em&gt; inside of the &lt;em&gt;let&lt;/em&gt; block. So even though I called&amp;nbsp;&lt;em&gt;add-3-to-z&lt;/em&gt; while the local value of &lt;em&gt;z&lt;/em&gt; is 10, the text defining the function &lt;em&gt;add-3-to-z&lt;/em&gt; is outside of the &lt;em&gt;let&lt;/em&gt; block so it defers to the global value of &lt;em&gt;z&lt;/em&gt;.&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1584073.js?file=lexical3.clj"&gt;&lt;/script&gt;
&lt;p&gt;In this last example, while inside a &lt;em&gt;let&lt;/em&gt; block, I create and return a function that takes 1 argument and adds it to the value of &lt;em&gt;x&lt;/em&gt;. Since the code that created the function was within a &lt;em&gt;let&lt;/em&gt; block, the value of &lt;em&gt;x&amp;nbsp;&lt;/em&gt;is 1 even if the function is called outside of the &lt;em&gt;let&lt;/em&gt;. Due to the fact this function retains its scope at the time of creation, it is said to "close" over the lexical environment. This type of function can be referred to as a lexical closure, or just &lt;a href="http://en.wikipedia.org/wiki/Closure_(computer_science)" title="closure" target="_blank"&gt;closure&lt;/a&gt;&amp;nbsp;for short (this is where clojure gets its name).&lt;/p&gt;
&lt;h2&gt;Dynamic Scope&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Dynamic scope&lt;/strong&gt; is another method of resolving symbol names. A dynamic scope environment is created using the&amp;nbsp;&lt;a href="http://clojuredocs.org/clojure_core/clojure.core/binding" title="binding" target="_blank"&gt;binding&lt;/a&gt;&amp;nbsp;macro, which syntactically looks like &lt;em&gt;let&lt;/em&gt;, but has some big differences:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You can't create new symbols. Every symbol has to be associated with a previously initialized&amp;nbsp;var.&lt;/li&gt;
&lt;li&gt;The initialized&amp;nbsp;vars also have to be defined as "dynamic".&lt;/li&gt;
&lt;li&gt;The new bindings affect the entire call stack, not just the immediate text region.&lt;/li&gt;
&lt;li&gt;The bindings that are created are pushed onto a thread-local stack and cannot be shared between multiple threads.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;We can't make up new symbols, so we have to&amp;nbsp;&lt;em&gt;shadow&lt;/em&gt;&amp;nbsp;existing vars. This seems like a restricted version of &lt;em&gt;let&lt;/em&gt; initially, but after a few examples the purpose of dynamic scope will hopefully be made clear.&amp;nbsp;We already know we can make new vars using &lt;em&gt;def&lt;/em&gt;, which, as I mentioned before, act like constants. The exception to that rule is when they are defined as dynamic. Functions defined with &lt;em&gt;defn&lt;/em&gt;&amp;nbsp;are stored in a var, and so they can also be declared as dynamic (the &lt;em&gt;defn&lt;/em&gt; macro uses &lt;em&gt;def &lt;/em&gt;internally).&amp;nbsp;A var can be defined as dynamic simply by adding ":dynamic true" to its metadata. Let's take a look at this next example:&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;em&gt;[NOTE: Before clojure 1.3 all vars were implicitly dynamic, which means there is a lot of broken code on the internet (including the official clojure website at the time of this writing)]&lt;/em&gt; &lt;br /&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1584073.js?file=dynamic2.clj"&gt;&lt;/script&gt;
&lt;/div&gt;
&lt;p&gt;The vars &lt;em&gt;x, y, &lt;/em&gt;and &lt;em&gt;sum-of-squares&lt;/em&gt;&amp;nbsp;are all declared to be dynamic at the top of the file. &amp;nbsp;The function &lt;em&gt;sum-of-squares-for-x-and-y&lt;/em&gt;&amp;nbsp;calculates the sum of squares for the &lt;em&gt;vars&lt;/em&gt;&amp;nbsp;associated with the symbols &lt;em&gt;x&lt;/em&gt;&amp;nbsp;and &lt;em&gt;y. &lt;/em&gt;Remember &lt;em&gt;x,&amp;nbsp;&lt;/em&gt;&lt;em&gt;y, &lt;/em&gt;and &lt;em&gt;sum-of-squares&lt;/em&gt;&amp;nbsp;refer to&amp;nbsp;&lt;em&gt;vars&lt;/em&gt;&amp;nbsp;and not &lt;em&gt;values&lt;/em&gt;, the &lt;em&gt;value&lt;/em&gt;&amp;nbsp;of the &lt;em&gt;var &lt;/em&gt;is looked up every time this function is run. When the clojure runtime encounters a &lt;em&gt;var, &lt;/em&gt;it first checks for any thread-local bindings, if it can't find any it will return the root value of the &lt;em&gt;var&lt;/em&gt;&amp;nbsp;which is shared by all threads. So in the above example when we first call &lt;em&gt;sum-of-squares-for-x-and-y,&lt;/em&gt;&amp;nbsp;all of the &lt;em&gt;vars&lt;/em&gt;&amp;nbsp;referenced in the function definition defer to their root binding. Next, we push new bindings on to our thread-local stack and call the same function, and now the function uses these new values and returns a different result. The key point here is the entire call stack below the binding point is affected, not just the text within the binding block. Once we end the binding block, the values get popped off the stack and return to their root value.&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1584073.js?file=dynamic3.clj"&gt;&lt;/script&gt;
&lt;p&gt;In the above example, we have a function that returns an adder function for the &lt;em&gt;var&lt;/em&gt;&amp;nbsp;x just like we did earlier using a &lt;em&gt;let&lt;/em&gt; block. Since &lt;em&gt;x&lt;/em&gt;&amp;nbsp;is a &lt;em&gt;var&lt;/em&gt;, the value is determined at the time the function is run, not when it is created. You &lt;strong&gt;cannot close over a dynamic scope!&lt;/strong&gt;&amp;nbsp; In the example below I got around this by lexically&amp;nbsp;&lt;em&gt;shadowing&lt;/em&gt;&amp;nbsp;the &lt;em&gt;var x&lt;/em&gt;&amp;nbsp;with its current dynamic value.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1584073.js?file=dynamic4.clj"&gt;&lt;/script&gt;
&lt;p&gt;So why would you ever want to use dynamic scope over lexical? Let's take a look at how dynamic vars are being used in the core clojure library. The stdin and stdout file handles, which many core I/O functions use (eg. println, read), are defined by the dynamic vars *in* and *out* (by naming convention, dynamic vars are wrapped in asterisks (aka earmuffs)). Maybe you want your application to print its output to some log file instead of stdout. We can simply dynamically re-bind the *out* var at the base of our application.&amp;nbsp;&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1584073.js?file=dynamic5.clj"&gt;&lt;/script&gt;
&lt;p&gt;Now the println function (and any other function that uses *out*) will print to log.txt. Let's try something a little more complicated. Say we have a multi-threaded application and we don't want the print output from each thread to be intertwined with each other. One way we could accomplish this is to have each thread print to its own log file. Since each thread maintains its own stack of bindings, this is trivial to do.&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1584073.js?file=dynamic6.clj"&gt;&lt;/script&gt;
&lt;p&gt;Now each threads' print statements will go in to their own files. Note that it is rare to directly make java threads like this in clojure since clojure already has more expressive concurrency primitives (agents, futures, pmap, etc). However, since those all use threads internally these same binding rules apply which can lead to unexpected results. Some other use cases of dynamic scope include the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can debug function calls by dynamically overriding that function to print every time it gets called. Checkout&amp;nbsp;&lt;a href="https://github.com/clojure/tools.trace" title="clojure/tools.trace" target="_blank"&gt;clojure/tools.trace&lt;/a&gt;&amp;nbsp;for the excellent dotrace macro.&lt;/li&gt;
&lt;li&gt;The&amp;nbsp;&lt;a href="https://github.com/clojure/java.jdbc" title="clojure/java.jdbc" target="_blank"&gt;clojure/java.jdbc&lt;/a&gt;&amp;nbsp;library uses a dynamic var *db* so that you don't have to pass in a database connection to every function call. You can just use the with-connection macro to bind *db* to the database you want to use, and then perform any database queries within the body of the macro.&lt;/li&gt;
&lt;li&gt;It allows you to mock functions that have side-effects to make them more unit-testable.&lt;/li&gt;
&lt;li&gt;If you look at the clojure core library you will find a lot of other use cases. For example, the current namespace is stored in *ns* and you can use the in-ns macro to temporarily bind that to some other namespace and dynamically add functions to the newly bound namespace.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In general, when you think you need a dynamic var you probably don't. Lexical scope is easier to understand because the programmer can determine the resolution of the symbols by looking at the code. Using dynamic vars also breaks&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Referential_transparency_(computer_science)" title="referential transparency" target="_blank"&gt;referential transparency&lt;/a&gt;, which greatly reduces code readability and testability. However, clojure is a practical language that allows the programmer to come up with creative and expressive solutions to problems, and recognizes that sometimes using dynamic scope might be the most straightforward way to solve a problem.&lt;/p&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/n8R_CHtjqtU" height="1" width="1"/&gt;</description><dc:creator>Chris McBride</dc:creator><pubDate>Wed, 11 Jan 2012 19:04:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:51652</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/51652/Lexical-vs-Dynamic-Scope-in-Clojure</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/51257/Language-Oriented-API-Design#Comments</comments><slash:comments>1</slash:comments><title>Language-Oriented API Design</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/c_hPGrK-z2g/Language-Oriented-API-Design</link><description>&lt;p&gt;&lt;br /&gt;&lt;img id="img-1325866254097" src="http://info.rjmetrics.com/Portals/17916/images/cover-cropped.png" border="0" alt="language-oriented API design" class="alignCenter" style="display: block; margin-left: auto; margin-right: auto;" /&gt;&lt;/p&gt;
&lt;p&gt;As programmers, we create code and libraries for others to use. There's no getting around this fact: if nobody else ever reads your code, you probably aren't going to get very far. This gives rise to a question: how can we tell if the code we've designed is useful for others, and also ourselves? The classic text &lt;em&gt;Structure and Interpretation of Computer Programs&lt;/em&gt; (&lt;a href="http://mitpress.mit.edu/sicp" rel="nofollow" title="http://mitpress.mit.edu/sicp/" target="_blank"&gt;http://mitpress.mit.edu/sicp/&lt;/a&gt;) spends a lot of time delving into this issue. The first section of Chapter 4 contains a few sentences that I can safely say have had a bigger impact on how I write code than anything I've ever encountered. The text reads:&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;&lt;em&gt;Metalinguistic abstraction -- establishing new languages -- plays an important role in all branches of engineering design. It is particularly important to computer programming, because in programming not only can we formulate new languages but we can also implement these languages by constructing evaluators. An evaluator (or interpreter) for a programming language is a procedure that, when applied to an expression of the language, performs the actions required to evaluate that expression.&lt;/em&gt;&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;&lt;em&gt;It is no exaggeration to regard this as the most fundamental idea in programming:&lt;/em&gt;&lt;/p&gt;
&lt;p style="padding-left: 60px;"&gt;&lt;em&gt;The evaluator, which determines the meaning of expressions in a programming language, is just another program.&lt;/em&gt;&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;&lt;em&gt;To appreciate this point is to change our images of ourselves as programmers. We come to see ourselves as designers of languages, rather than only users of languages designed by others.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Admittedly, this is very general and abstract! Your eyes might have glazed over at the phrase "metalinguistic abstraction", but try to bear with me. How can we take this idea and use it in our day-to-day work? The next paragraph offers an example from earlier in the text:&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;&lt;em&gt;In fact, we can regard almost any program as the evaluator for some language. For instance, the polynomial manipulation system of section 2.5.3 embodies the rules of polynomial arithmetic and implements them in terms of operations on list-structured data.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Ah, so what they're saying can apply to any program you write! This takes a shift in mindset to appreciate, but once you make that shift, you'll find that your programs are clearer and more helpful. If you follow these principles, your code will give you the ability to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Work &lt;em&gt;with&lt;/em&gt; the code instead of having it work against you.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Solve problems in new and interesting ways that you couldn't fathom when you did your initial design work.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;How does this apply to your domain?&lt;/h2&gt;
&lt;p&gt;You might be thinking: "This is fine for somebody creating small systems that are obviously reusable, like mathematics packages. However, &lt;em&gt;my&lt;/em&gt; application in &amp;lt;&lt;em&gt;your domain here&lt;/em&gt;&amp;gt; doesn't facilitate that kind of reusable design!" Let's consider a practical example: the RJMetrics application. This is a large system created for gathering data and performing analytics on it to provide useful business knowledge to our clients.&lt;/p&gt;
&lt;p&gt;I'm going to propose a different separation of concerns. Instead of only creating an application for people to use and analyze their business data, we should design a language for solving business analytics problems, and then build an application on that foundation. You can do this for any domain--of course, the previous sentence can always be rewritten to include your problem domain instead of business analytics.&lt;/p&gt;
&lt;p&gt;An example will probably help to clarify what I mean. One of the fundamental building blocks of our system is the "structure" of a client's database. Assume, for the sake of this example, that this system only supports relational databases (though this is not the case for the RJMetrics platform). This is made up of your standard database objects: tables, columns, schemata, etc. Now, what happens when you decide you no longer want to support only relational databases? You want to move into the NoSQL realm, so you need ways of representing the structure of a NoSQL store that can be used in the same fashion as your current structure building blocks. We should be able to assemble the existing pieces (or introduce new ones transparently) so that NoSQL data stores can be manipulated and used in the same fashion--you certainly don't want to reimplement your fundamental building blocks to accomodate a new way of structuring data. If this is an easy task (and you'll know when you go to implement it if that's the case!), you might have designed your system in a language-oriented way.&lt;/p&gt;
&lt;p&gt;Note I'm using the word "language" in a different sense than we usually mean when discussing code: I don't mean a programming language, and I'm certainly not advocating that you implement a new programming language for your specific problem domain! Rather, I'm talking about the API you use to build the application--and if you consider these API design principles, it will be much harder for you to end up with a poorly-designed interface.&lt;/p&gt;
&lt;h2&gt;How can you tell if your platform has these qualities?&lt;/h2&gt;
&lt;p&gt;This is a difficult problem, but here are some thought exercises to make it easier. Try considering this: assume that tomorrow, you're leaving the application business and want to focus solely on creating a platform for others to use and create their own solutions. First, would people be able to comprehend the language you've provided for them? Do the primitives and means of combination make sense? Second, if somebody comes up with a new way of using your platform, are your current tools going to work with their new ideas, or are they going to break? On a more implementation-specific level, any side effects in the code will make this impossible--someone will inevitably call a function with side effects at the wrong time and it will blow up in their face. Functional solutions are the only option here.&lt;/p&gt;
&lt;p&gt;Or, to put it more succinctly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Could you open source your platform tomorrow?&amp;nbsp;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Would you be embarrassed by what people saw?&amp;nbsp;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The RJMetrics codebase isn't there yet (personally, I've seen very few production codebases that are), but as we consistently refactor and notice patterns, the language evolves and becomes more useful. A nice side effect is that these changes stack on top of each other: every incremental change makes it easier and easier to improve it even further.&lt;/p&gt;
&lt;p&gt;On that note, this is the most difficult part of getting to this point with your code: you can never neglect refactoring. No codebase gets it right the first time, so you have to be willing to find patterns and exploit them. That's the only way you can ever evolve your platform to the level of a reusable language.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/c_hPGrK-z2g" height="1" width="1"/&gt;</description><dc:creator>Derek Mansen</dc:creator><pubDate>Fri, 06 Jan 2012 19:11:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:51257</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/51257/Language-Oriented-API-Design</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/51373/Getting-Lazy-With-My-10-Time-Simple-PHP-Lazy-Load#Comments</comments><slash:comments>0</slash:comments><title>Getting Lazy With My 10% Time -- Simple PHP Lazy Load</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/JAFYLMlrqR4/Getting-Lazy-With-My-10-Time-Simple-PHP-Lazy-Load</link><description>&lt;p&gt;Here at RJMetrics, we like to experiment -- especially with ideas that have proven successful for other companies. For this reason, like many startups before us, we have adopted Google's 20% time policy. Huzzah! Because this is an experiment, we defined a fixed trial period of three months. We also cut it down from 20% to 10%. This fits well with our 10 day sprint cycles, and seemed like a good way to get started. After three months, we will assess the results and decide where to go from there.&lt;/p&gt;
&lt;h3&gt;What is 20% time?&lt;/h3&gt;
&lt;p&gt;In case you haven't heard:&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;Google engineers are encouraged to spend 20% of their work time on projects that interest them. Some of Google's newer services, such as Gmail, Google News, Orkut, and AdSense originated from these independent endeavors. (&lt;a href="http://en.wikipedia.org/wiki/Google" title="Wikipedia" target="_blank"&gt;Wikipedia&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Although big, amazing things are always a possibility, I don't expect any of us to develop the next Gmail (RJmail?). I do expect lots of little, amazing things to come from this, such as small improvements and optimizations of our code and simple utilities that solve daily annoyances.&lt;/p&gt;
&lt;h3&gt;What did I do with my 10% time?&lt;/h3&gt;
&lt;p&gt;I experimented with implementing a general lazy loading solution in PHP for properties of model objects that reference other objects. Nothing I did was groundbreaking. But these are the sort of optimizations that can easily be overlooked in a fast-paced development environment where there are many competing priorities. That is, until 10% time comes along with a respite from the team todo list.&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;What's the problem?&lt;/h3&gt;
&lt;p&gt;As you might expect, our codebase contains many class definitions for model objects, and by that I mean, objects whose primary purpose is to hold data and map roughly to a record in a database table. Given our business, an obvious example is the Chart object. It has some simple scalar properties such as name, time range and color scheme. But Charts also have relationships to other models, such as:&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the user who owns the chart&lt;/li&gt;
&lt;li&gt;the client whose data is displayed by the chart&lt;/li&gt;
&lt;li&gt;the trend that provides the data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The question is: does the Chart object have a property that directly references each of these related model objects? And if so, does that mean we must load and construct each of these objects in order to build a Chart object? These questions are answered by the implementation details of our Data Access Objects (DAO, pronounced &amp;ldquo;Day-O&amp;rdquo;, like in Harry Belafonte's Banana Boat song). &lt;br /&gt;&lt;br /&gt; &lt;iframe frameborder="0" height="315" src="http://www.youtube.com/embed/PMigXnXMhQ4" width="420"&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Data Access Objects (or &amp;ldquo;mappers&amp;rdquo;, as we affectionately call them at RJMetrics) handle the process of constructing model objects from the data in our database, and also saving the data back to the database. If one model object relates to another we might load them at the same time, which allows us to do this:&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1555855.js?file=example1.php"&gt;&lt;/script&gt;
&lt;p&gt;But, this can be expensive. Imagine we want to display a list of Charts. We might be loading many, many Charts and only using the 'name' property for each. In this scenario, also loading up each of the user, client and trend model objects is unnecessary and may introduce undesirable delays.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;If we have implemented our mappers to not load related objects with the Chart object initially, but we are in a situation where we do need these objects, we might end up with code like this:&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1555855.js?file=example2.php"&gt;&lt;/script&gt;
&lt;p&gt;Look at all those mappers! What a mess. The previous code example is much cleaner. Can I please have my cake and eat it too? Probably!&lt;/p&gt;
&lt;p&gt;There are corresponding changes that need to be made both in the model objects and mappers, but the core of this solution is stupid simple. Here's the PHP:&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1555855.js?file=LazyLoader.php"&gt;&lt;/script&gt;
&lt;p&gt;What is going on here? &lt;a href="http://en.wikipedia.org/wiki/Memoization" title="Memoization" target="_blank"&gt;Memoization&lt;/a&gt;! I dislike saying this word almost as much as I love the concept. The above example defines a class that encapsulates a single property which is either a value or a closure that provides a value. If it is a closure, the first time the LazyLoader is invoked, the result is memoized, stored in memory for later reuse. The closure is discarded and never called again. This is fine as long as we don't expect updates to the database record to automatically propagate to this property.&lt;/p&gt;
&lt;h3&gt;How do we use it?&lt;/h3&gt;
&lt;p&gt;To enable lazy loading for a property, we must make some simple changes to the model object and corresponding mapper. Here's an absurdly simple example:&amp;nbsp;&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1555855.js?file=exampleChart.php"&gt;&lt;/script&gt;
&lt;p&gt;Above we have a simplified Chart class with two public properties, &amp;ldquo;name&amp;rdquo; and &amp;ldquo;user&amp;rdquo;, with getters and setters for each. This demonstrates the difference between a typical property implementation and a lazy one. Instead of storing a value, we store a LazyLoader object and it handles the details of memoization for us.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt; The other end of our modifications lie in the DAO, the ChartMapper class.&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1555855.js?file=exampleChartMapper.php"&gt;&lt;/script&gt;
&lt;p&gt;We've hidden away the call to the userMapper in the closure that is passed to the LazyLoader by the Chart object. Now this object is loaded on demand without having to mess with additional mappers in the calling code. Success! We can enjoy eating our cake that we still have.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt; Things get more fun when you realize the power of stringing lazily-loaded property calls together.&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1555855.js?file=oneLiner.php"&gt;&lt;/script&gt;
&lt;p&gt;The line of code above might be used to get a list of all the users a given chart could be shared with. Incidental complexity has been stripped away. Who knows how many mappers are involved in the line above? Not me. That's a detail that need not concern me as long as the line is functioning and performing well.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/JAFYLMlrqR4" height="1" width="1"/&gt;</description><dc:creator>Bill Piel</dc:creator><pubDate>Wed, 04 Jan 2012 13:00:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:51373</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/51373/Getting-Lazy-With-My-10-Time-Simple-PHP-Lazy-Load</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/51367/RJMetrics-Raises-1-2-Million-From-Leading-Early-Stage-Investors#Comments</comments><slash:comments>2</slash:comments><title>RJMetrics Raises $1.2 Million From Leading Early-Stage Investors</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/RmWg82VvU78/RJMetrics-Raises-1-2-Million-From-Leading-Early-Stage-Investors</link><description>&lt;div&gt;Today, we are proud to announce that RJMetrics has closed a $1.2 Million financing round from a syndicate of world-class technology investors. &amp;nbsp;Our new investors include &lt;a href="http://www.softtechvc.com/" title="SoftTech VC" target="_blank"&gt;SoftTech VC&lt;/a&gt;, &lt;a href="http://www.lererventures.com/" title="Lerer Ventures" target="_blank"&gt;Lerer Ventures&lt;/a&gt;, &lt;a href="http://www.crunchbase.com/financial-organization/sv-angel" title="SV Angel" target="_blank"&gt;SV Angel&lt;/a&gt;, &lt;a href="http://www.zelkovavc.com/" title="Zelkova Ventures" target="_blank"&gt;Zelkova Ventures&lt;/a&gt;, &lt;a href="http://site.upstageventures.com/" title="Upstage Ventures" target="_blank"&gt;Upstage Ventures&lt;/a&gt;, &lt;a href="http://www.redswan.vc/" title="Red Swan Ventures" target="_blank"&gt;Red Swan Ventures&lt;/a&gt;,&amp;nbsp;Venture Capitalist Jon Anderson, Wharton Professor Kartik Hosanagar, &lt;a href="http://duckduckgo.com/" title="DuckDuckGo" target="_blank"&gt;DuckDuckGo&lt;/a&gt; CEO &lt;a href="http://www.gabrielweinberg.com/" title="Gabriel Weinberg" target="_blank"&gt;Gabriel Weinberg&lt;/a&gt;, and &lt;a href="http://fab.com/" title="Fab.com" target="_blank"&gt;Fab.com&lt;/a&gt; CEO &lt;a href="http://betashop.com/" title="Jason Goldberg" target="_blank"&gt;Jason Goldberg&lt;/a&gt;. &amp;nbsp;Jason Goldberg has also joined our Board of Directors.&lt;br /&gt;&lt;br /&gt;As a fully-bootstrapped and profitable company, the decision to raise capital was not an obvious one. &amp;nbsp;Jake and I both worked as VCs prior to founding RJMetrics, and that experience taught us the benefits of waiting as long as possible to raise capital. &amp;nbsp;We agreed from day-one that we would only take on investors when we were certain that it would generate positive returns. &amp;nbsp;&lt;br /&gt;&lt;br /&gt;I&amp;rsquo;m happy to share why that day finally came.&lt;br /&gt;&lt;br /&gt;
&lt;h2 dir="ltr"&gt;Why We Did It&lt;/h2&gt;
&lt;strong&gt;Opportunity.&lt;/strong&gt; &amp;nbsp;In 2009, Jake and I emerged from my attic with a minimum viable prototype of our hosted business intelligence product. &amp;nbsp;Jake hammered the phones and we got our first few customers. &amp;nbsp;By 2010, we had enough revenue to make our first hire. &amp;nbsp;We improved our processes and product by leaps and bounds. &amp;nbsp;Word started to spread and more customers arrived.&lt;br /&gt;&lt;br /&gt;By the end of 2010, we had grown the team to four people and moved into a real office in Center City Philadelphia. &amp;nbsp;In 2011, our customer count exploded, our headcount tripled, and our product got even better.&lt;br /&gt;&lt;br /&gt;We got efficient. &amp;nbsp;We added automated marketing with Hubspot, CRM with SalesForce.com, customer support management with Zendesk, code control with Github, product management with FogBugz, and (of course) robust analytics with RJMetrics.&lt;br /&gt;&lt;br /&gt;Thanks to our own product, we were seeing compelling data about customer lifetime value and retention. &amp;nbsp;This led to the conclusion that the only thing between us and even faster growth was more rapidly iterating on our product and getting in front of even more people. &amp;nbsp;Raising money was the key to going after this this huge opportunity as aggressively as possible.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Amazing Investors.&lt;/strong&gt; &amp;nbsp;We knew that the right investors could contribute far more than capital. &amp;nbsp;We spoke to a number of institutional investors and angels, and ultimately decided on an angel syndicate because of the speed, flexibility, terms, value-add, and diversity they were able to provide.&lt;br /&gt;&lt;br /&gt;We were fortunate to be oversubscribed almost immediately. &amp;nbsp;This gave us an opportunity to be selective about the partners we chose. &amp;nbsp;Naturally, everyone is well-connected, smart, and experienced. &amp;nbsp;If you look closely, however, everyone who invested also falls into at least one of these categories:
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Actual RJMetrics Users:&lt;/strong&gt;&lt;/em&gt; Almost 100% of this round came from firms or individuals who have used our product extensively. &amp;nbsp;From Jason Goldberg (Fab.com) to Ben Lerer (Thrillist/Lerer Ventures) to Andy Dunn (Bonobos/Red Swan), these investors had done their product diligence without even knowing it. &amp;nbsp;They will bring practical, in-depth insights to our product development strategy from day-one.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Stellar West-Coast Investors:&lt;/strong&gt;&lt;/em&gt; Silicon Valley is underrepresented in our customer base, and we see that as a huge market for us in the coming year. &amp;nbsp;Funds like SV Angel and SoftTech VC give us a west-coast presence and bring credibility, strong networks, and valuable regional expertise to the table.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;SaaS and Lean Startup Experience:&lt;/strong&gt;&lt;/em&gt; Raising money doesn&amp;rsquo;t mean we&amp;rsquo;re going to abandon our mantra of capital efficiency. &amp;nbsp;Investors like Mark Wachen (Upstage Ventures) and Gabe Weinberg have personally built and exited technology companies without depending on outside investors to survive. &amp;nbsp;Their expansion-stage experience will be invaluable as we take things to the next level.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;h2 dir="ltr"&gt;Why We&amp;rsquo;re Excited&lt;/h2&gt;
&lt;strong&gt;We Love Doing This.&lt;/strong&gt; &amp;nbsp;Every day, we learn something new, interact with the smartest group of people we&amp;rsquo;ve ever known, and build something that changes the way people think. &amp;nbsp;There is much, much more that we can do and nothing makes us more excited than working to turn those dreams into reality. This funding is only going to make that happen faster.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;We Love Philadelphia.&lt;/strong&gt; &amp;nbsp;&lt;a href="http://info.rjmetrics.com/blog/bid/50397/Why-Our-Startup-is-Doubling-Down-on-Philadelphia" title="As we detailed earlier this month" target="_blank"&gt;As we detailed earlier this month&lt;/a&gt;, we are proud to call Philadelphia our home and we&amp;rsquo;re excited about the emerging start-up culture here. &amp;nbsp;We are also proud to be bringing brand-name capital from both coasts into the Philadelphia technology community. &amp;nbsp;These dollars will be spent on cultivating local talent, creating jobs, and growing our hometown brand on the global stage.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;We&amp;rsquo;re Just Getting Started.&lt;/strong&gt; &amp;nbsp;Raising a round of capital is not the finish line-- it&amp;rsquo;s the starting pistol. &amp;nbsp;We&amp;rsquo;ve been working on this company for three years now, but we continue to start each day hungrier than ever. &amp;nbsp;So, don&amp;rsquo;t say &amp;ldquo;congrats.&amp;rdquo; &amp;nbsp;Say &amp;ldquo;good luck.&amp;rdquo; &amp;nbsp;And stay tuned.&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/RmWg82VvU78" height="1" width="1"/&gt;</description><dc:creator>Robert Moore</dc:creator><pubDate>Tue, 03 Jan 2012 13:14:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:51367</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/51367/RJMetrics-Raises-1-2-Million-From-Leading-Early-Stage-Investors</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/51180/2011-What-We-Learned#Comments</comments><slash:comments>0</slash:comments><title>2011: What We Learned</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/955TLSOQfNA/2011-What-We-Learned</link><description>&lt;p&gt;Here at RJMetrics, 2011 was full of growth: we went from a few employees to a dozen, and more than tripled our customer base. We moved into our new Center City, Philadelphia office on January 1st, and promptly outgrew the space. We&amp;rsquo;ve hired developers, analysts and designers, and although we&amp;rsquo;re far from a big company, we aren&amp;rsquo;t a couple of guys in an attic anymore either. Over the course of the year, we evolved a handful of traits in response to problems caused by this growth. These are a handful of the lessons we&amp;rsquo;ve learned:&lt;/p&gt;
&lt;h3&gt;Email is not an organization tool&lt;/h3&gt;
&lt;p&gt;E-mail was always our default medium for getting feedback from our customers and product. Customer has a problem? E-mail our support team. Code ran into an unusual exception? Send an automated e-mail to warn the dev team.&lt;/p&gt;
&lt;p&gt;This approach has a number of problems. E-mails don&amp;rsquo;t have an owner so much as a number of contributors - how do we know who is responsible for this support request? How can we see all of the pending requests? Automated e-mails inevitably lead to a filtering problem - once I receive three automated e-mails with the exact same information, I ignore them going forward.&lt;/p&gt;
&lt;p&gt;We have been transitioning our e-mail based processes onto more suitable platforms. Zendesk allows us to assign requests to team members, see all outstanding requests at a glance, and maintain a knowledge base of answers to commonly asked questions. Instead of e-mailing the team when our code does something unexpected, we automatically generate high priority Fogbugz tickets for our development team to investigate further.&lt;/p&gt;
&lt;h3&gt;Anything we can do, our customers can do better&lt;/h3&gt;
&lt;p&gt;In the early versions of RJMetrics, customers were unable to edit anything beyond the level of charts and dashboards - modifications to the actual data set had to be performed by an RJMetrics analyst. The stated reason for this was that the tools we had to perform these changes were powerful and confusing, a mix that we were afraid might lead customers to make irreversible changes accidentally.&lt;/p&gt;
&lt;p&gt;But, as our customer base has matured, we have felt more demand for data warehouse management tools, and as our product development team has matured, we have recognized that the above reasons are really just lame excuses. We can build tools that aren&amp;rsquo;t confusing, and we can build in protections for reversing accidental changes - and that&amp;rsquo;s what we&amp;rsquo;re going to do. In 2011 we began by exposing a Trend editor, restriction set editor, and connection manager into the settings page, and we are planning to continue to continue to build out this tool set in 2012.&lt;/p&gt;
&lt;h3&gt;Bug tracking != Product Management&lt;/h3&gt;
&lt;p&gt;Just about a year ago we started using 2 week long sprints to organize development tasks and track progress. As our team and backlog grew, though, there was also a growing disconnect between small implementation tasks and our higher level goals for the product and company. Too often we would prioritize one or two of the most urgent tasks across dozens of projects into the sprint, and then feel disappointed when we didn&amp;rsquo;t have much tangible forward progress to show at the end.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;To address this we created a road map of prioritized projects and categorized every task by project. Now we plan sprints by looking at the highest priority projects, and allocating enough time for each project to hit its predetermined milestones.&lt;/p&gt;
&lt;h3&gt;We are our own best critics&lt;/h3&gt;
&lt;p&gt;The most important change we made in 2011 was to introduce processes for giving ourselves feedback. Our code review system now ensures that poor programming practices are squeezed out, and best practices dispersed through our development team.&lt;/p&gt;
&lt;p&gt;More generally, every month we conduct mini-review sessions to encourage our team to step back from their day-to-day work and discuss what they think is and isn&amp;rsquo;t working at RJMetrics on a strategic level. In fact, most of the changes listed above came out of these review sessions. This feedback mechanism will help us evolve and face the new problems that will arise as the team and company continue to grow.&lt;br /&gt; &lt;br /&gt;These are a few of the most valuable lessons we learned this year - what did your company learn in 2011? &amp;nbsp;Happy holidays from the RJMetrics team.&lt;/p&gt;
&lt;p&gt;&lt;img id="img-1325085538183" src="http://info.rjmetrics.com/Portals/17916/images/2011 RJMetrics Company Photo-resized-600.JPG" border="0" alt="2011 RJMetrics Company Photo resized 600" class="alignCenter" style="display: block; margin-left: auto; margin-right: auto;" /&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/955TLSOQfNA" height="1" width="1"/&gt;</description><dc:creator>Chris Merrick</dc:creator><pubDate>Wed, 28 Dec 2011 15:35:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:51180</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/51180/2011-What-We-Learned</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/50909/Charity-Metrics#Comments</comments><slash:comments>0</slash:comments><title>Charity Metrics</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/xEP1H8Tx9ho/Charity-Metrics</link><description>&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;a href="http://www.smiletrain.org/" target="_blank"&gt;&lt;img id="img-1324486438345" src="http://info.rjmetrics.com/Portals/17916/images/Smile Train.jpg" border="0" alt="Smile Train" class="alignLeft" style="float: left;" /&gt;&lt;/a&gt;Since my first internship in college, I have made an annual donation of $5,000 or 10% of my post tax income, whichever is greater, to a charity called the &lt;a href="http://www.smiletrain.org/" title="Smile Train" target="_blank"&gt;Smile Train&lt;/a&gt;. The Smile Train performs corrective surgery on children born with cleft lips and cleft palates in developing countries. &amp;nbsp;The surgery costs about $250 per person, and it makes a huge difference in the life of the people born with clefts. Uncorrected clefts result in lifelong problems eating, speaking, and breathing. &lt;br /&gt;&lt;br /&gt;Smile Train had &lt;a href="http://www.nytimes.com/2011/02/24/business/24smile.html?pagewanted=all" title="some drama" target="_blank"&gt;some drama&lt;/a&gt; this year when they announced (and later reverted) plans to merge with another cleft charity. &amp;nbsp;I don&amp;rsquo;t know if this impacted Smile Train&amp;rsquo;s effectiveness, but the shakeup motivated me to re-evaluate my choice of charity, something I had been planning to do for a while. &amp;nbsp;&lt;br /&gt;&lt;br /&gt;I wanted to base my decision on charity &lt;a href="http://rjmetrics.com" title="metrics" target="_self"&gt;metrics&lt;/a&gt;. &amp;nbsp;Using my fixed charitable budget, I want to get the highest possible return in terms of lives saved or drastically improved. &amp;nbsp;I don&amp;rsquo;t give weight to the gender, ethnicity, or location of the recipients. I&amp;rsquo;m also not interested in spreading it around. &amp;nbsp;I want to pick the best charity and give 100% of my donation to it. (For an explanation of the rationale behind donating to a single charity, &lt;a href="http://www.slate.com/articles/arts/everyday_economics/1997/01/giving_your_all.html" title="read this article" target="_blank"&gt;read this article&lt;/a&gt; by the economist Stephen Landsburg.) &lt;br /&gt;&lt;br /&gt;One metric that I knew not to use, or at least not exclusively, is &amp;lsquo;efficiency&amp;rsquo;. &amp;nbsp;This is the percentage of budget that goes to program expenses, and it's used by a number of charity rankings like &lt;a href="http://www.forbes.com/2004/11/23/04charityland.html" title="Forbes' annual charity list" target="_blank"&gt;Forbes' annual charity list&lt;/a&gt;. &amp;nbsp;While the efficiency ratio is useful for ruling out charities where much of the budget goes into management's pockets, it does not account for the big differences in return-on-donation between different charities. &amp;nbsp;&lt;br /&gt;&lt;br /&gt;Like any self respecting nerd, I tried to come up with a formula and make a spreadsheet. &amp;nbsp;I wanted to compare charities on an apples to apples basis in order to figure out where my dollars would have the biggest impact. &amp;nbsp;My initial attempt was based on the following variables:&lt;br /&gt;&lt;br /&gt;U = cost per unit &amp;nbsp;(For the Smile Train, this is a surgery on one person)&lt;br /&gt;L = number of required lifetime units (An operation might be done once, medication may be require many doses over a lifetime)&lt;br /&gt;E = efficiency (Percentage of the budget goes to the actual cause as opposed to overhead)&lt;br /&gt;S = Odds of improving and/or dramatically improving a life (Vaccines are given to some people that would not have caught the disease anyway)&lt;br /&gt;&lt;br /&gt;Cost per person helped &amp;nbsp;= S * U * L / E &lt;br /&gt;&lt;br /&gt;For the Smile Train, This worked out to be 1 * $250 * 1 / .822 = $304. &amp;nbsp;&lt;br /&gt;&lt;br /&gt;I ran into two problems with this formula. First, I could not find a scalable way to get inputs for large numbers of charities. The second issue is that a crucial variable was missing from my formula. &amp;nbsp;What&amp;rsquo;s the difference in impact between preventing blindness versus increasing school attendance versus fixing a cleft palate? &amp;nbsp;My formula treated all afflictions as equally detrimental. While that didn&amp;rsquo;t seem right to me, I wasn&amp;rsquo;t sure how to capture the differences. &amp;nbsp;&lt;br /&gt;&lt;br /&gt;While I was researching the inputs to my formula, I found two fantastic resources for optimizing charitable giving, both of whom had done much of the leg work already. &amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.givingwhatwecan.org/" target="_blank"&gt;&lt;img id="img-1324486583787" src="http://info.rjmetrics.com/Portals/17916/images/Giving what we can.jpg" border="0" alt="Giving What We can" class="alignLeft" style="float: left;" /&gt;Giving What We Can&lt;/a&gt; (GWWC) was started by a philosophy professor at the University of Oxford named Toby Ord . GWWC makes charitable recommendations by trying to optimize a &amp;nbsp;metric called &lt;a href="http://en.wikipedia.org/wiki/Disability-adjusted_life_year" title="disability adjusted life years" target="_blank"&gt;disability adjusted life years&lt;/a&gt;, or DALY. &amp;nbsp;This is a much better version of what I was trying to get at with my spreadsheet. &amp;nbsp;&amp;nbsp;DALY is an increasingly popular metric to compare the burdens of disease and various treatments. It&amp;rsquo;s used by the &amp;nbsp;&lt;a href="http://www.who.int/healthinfo/global_burden_disease/metrics_daly/en/" title="World Health Organization" target="_blank"&gt;World Health Organization&lt;/a&gt;, World Bank, and others. &amp;nbsp;&amp;nbsp;GWWC also provides a &lt;a href="http://www.givingwhatwecan.org/resources/how-rich-you-are.php" title="wealth calculator" target="_blank"&gt;wealth calculator&lt;/a&gt; to give you a sense of where you stand in terms of wealth compared to most of the rest of the world. &amp;nbsp;If you&amp;rsquo;re reading this, I bet you are richer than you think.&lt;br /&gt;&lt;br /&gt;GWWC has determined the best charitable bangs for your buck are from curable and preventable diseases in the third world. &amp;nbsp;&amp;nbsp;Their three recommended charities are:
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www3.imperial.ac.uk/schisto" title="Schistosomiasis Control Initiative" target="_blank"&gt;Schistosomiasis Control Initiative&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.dewormtheworld.org/" title="Deworm the World" target="_blank"&gt;Deworm the World&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.againstmalaria.com/default.aspx" title="Against Malaria Foundation" target="_blank"&gt;Against Malaria Foundation&lt;/a&gt; &amp;nbsp;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;&lt;a href="http://www.givewell.org/" target="_blank"&gt;&lt;img id="img-1324486741107" src="http://info.rjmetrics.com/Portals/17916/images/GiveWell-1.jpg" border="0" alt="GiveWell 1" class="alignLeft" style="float: left;" /&gt;&lt;/a&gt;The other resource I found is &lt;a href="http://www.givewell.org/" title="GiveWell.org" target="_blank"&gt;GiveWell.org&lt;/a&gt;. GiveWell was started by two former financial analysts named Holden Karnofsky and Elie Hassenfeld. GiveWell also uses DALY, but takes a somewhat more nuanced view to the charity optimization problem. &amp;nbsp;&lt;br /&gt; &amp;nbsp;&lt;br /&gt;GiveWell uses DALY to filter down to the set of best philanthropic investments, but considers the error bars on DALY estimates to be too high to make a precise ordering. Once the universe of potential charities has been winnowed down to the highest-return organizations, GiveWell does proprietary research in order to attempt to forecast changes in the effectiveness of incremental donations. &amp;nbsp;They interview management teams and find out about the projects they will fund if their budget increases. &amp;nbsp;GiveWell reevaluates its top charities each year, requests updated information and interviews from the respective organizations, and updates its recommended charities list.&lt;br /&gt;&lt;br /&gt;While there are differences in the methodologies of these two organizations, they come to similar conclusions. &amp;nbsp;GiveWell&amp;rsquo;s two recommended charities both show up in GWWC&amp;rsquo;s list. In fact, GWWC recently updated their site based on research that GiveWell conducted. &amp;nbsp;&amp;nbsp;GiveWell&amp;rsquo;s top two recommendations are:&lt;ol&gt;
&lt;li&gt;Against Malaria Foundation&lt;/li&gt;
&lt;li&gt;Shistosomiasis Control Initiative&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;I decided to make my annual donation to the Against Malaria Foundation. GiveWell&amp;rsquo;s methodology of attempting to forecast the biggest DALY payoff for incremental dollars invested is, in my opinion, the optimal way to choose a charity. Shortly before posting this article, I funded my donation to AMF. &amp;nbsp;I&amp;rsquo;m extremely happy to report that I will be responsible for the distribution of over 1,200 mosquito nets. &amp;nbsp;&lt;br /&gt;&lt;br /&gt;I encourage you to apply metrics to your charitable donations as you would for a financial investment. &amp;nbsp;Or, take my word for it and &lt;a href="http://www.againstmalaria.com/jakestein" title="donate to the AMF now" target="_blank"&gt;donate to the AMF now&lt;/a&gt;.&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;a href="http://www.againstmalaria.com/jakestein" target="_blank"&gt;&lt;img id="img-1324486154324" src="http://info.rjmetrics.com/Portals/17916/images/againstmalaria.jpg" border="0" alt="Against Malaria Foundation" class="alignCenter" style="margin-left: auto; margin-right: auto; display: block;" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/xEP1H8Tx9ho" height="1" width="1"/&gt;</description><dc:creator>Jake  Stein</dc:creator><pubDate>Wed, 21 Dec 2011 19:34:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:50909</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/50909/Charity-Metrics</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/50397/Why-Our-Startup-is-Doubling-Down-on-Philadelphia#Comments</comments><slash:comments>3</slash:comments><title>Why Our Startup is Doubling Down on Philadelphia</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/9JXxOrthCnQ/Why-Our-Startup-is-Doubling-Down-on-Philadelphia</link><description>&lt;div&gt;&lt;span&gt;2011 has been an outstanding year for RJMetrics. &amp;nbsp;We&amp;rsquo;ve &lt;a href="http://www.rjmetrics.com/about-us" title="tripled our headcount" target="_blank"&gt;tripled our headcount&lt;/a&gt;, creating eight new high-tech jobs in Philadelphia and filling our Center City office to capacity. &amp;nbsp;We&amp;rsquo;re proud to have done this profitably and without the use of any outside capital.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;Today, we signed a new lease that will significantly expand our office space in &lt;a href="http://maps.google.com/maps?q=the+philadelphia+building+1315+walnut+street&amp;amp;hl=en&amp;amp;hnear=1315+Walnut+St,+Philadelphia,+Pennsylvania+19107&amp;amp;gl=us&amp;amp;t=m&amp;amp;z=16&amp;amp;vpsrc=0" title="The Philadelphia Building" target="_blank"&gt;The Philadelphia Building&lt;/a&gt; at 13th and Walnut. &amp;nbsp;This was not a decision that Jake or I took lightly. &amp;nbsp;2011 brought with it a number of strategic opportunities, including offers that would have involved moving our company to New York or Silicon Valley. &lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;We turned down those offers and we&amp;rsquo;re doubling-down on Philadelphia. &amp;nbsp;Not because it is the path of least resistance, but because it is the right path. &amp;nbsp;We believe that Philadelphia is the best possible home for our start-up. &amp;nbsp;Here are five reasons why.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;h2&gt;&lt;span&gt;1. Philadelphia is a Lean Startup&amp;rsquo;s Paradise&lt;/span&gt;&lt;/h2&gt;
&lt;div&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;We&amp;rsquo;re huge fans of Eric Ries&amp;rsquo;s "&lt;a href="http://www.startuplessonslearned.com/" title="Lean Startup" target="_blank"&gt;Lean Startup&lt;/a&gt;"&amp;nbsp;approach to building products and companies. &amp;nbsp;If you&amp;rsquo;re not familiar with this entrepreneurial philosophy, it involves moving as quickly as possible to collect actionable information, acting on that information, and then iterating. &amp;nbsp;It&amp;rsquo;s not about being cheap-- it&amp;rsquo;s about being fast. &lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;From day one, we were able to acquire actionable information faster in Philadelphia than we could have elsewhere. &amp;nbsp;How is this possible? &amp;nbsp;It&amp;rsquo;s simple math: time is money and it costs less to do business here. &amp;nbsp;Rent is lower. &amp;nbsp;Beer is cheaper. &amp;nbsp;I live comfortably on a salary that would have me sleeping in a broom closet in New York. &amp;nbsp;With a fixed budget, we&amp;rsquo;ve been able to conduct more tests, iterate more frequently, and get smarter faster -- all without prematurely raising capital.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;This effect is amplified when you remember that we sell a hosted product in a world that gets flatter by the day. &amp;nbsp;RJMetrics has customers on five continents, but our physical location has no bearing on what we charge them for our product and what it costs to deliver. &amp;nbsp;This leads to higher margins and more money invested back into growth.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;On a budget that would be razor-thin in many other cities, we can provide our employees with a world-class working environment, top-notch benefits, and some of the most compelling personal development opportunities in the region. &amp;nbsp;This is helping us create&amp;nbsp;&lt;a href="http://www.rjmetrics.com/jobs" title="Philly Startup Jobs" target="_blank"&gt;Philly software jobs&lt;/a&gt; that tap into our city's tremendous pool of local talent.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h2&gt;&lt;span&gt;2.&amp;nbsp;Philadelphia is Rich with Talent&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;I&amp;rsquo;ve heard peers complain about a talent shortage in Philly. &amp;nbsp;I agree that one exists, but a shortage of technology talent is not a Philadelphia problem. &amp;nbsp;It&amp;rsquo;s a national one. &amp;nbsp;We know startups in every corner of this country and the complaint is the same everywhere: demand outweighs supply, prices climb, and cash-rich companies like Google monopolize the top talent. &lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;Yes, there are a higher number of talented developers in New York and Silicon Valley than in Philadelphia. &amp;nbsp;But it&amp;rsquo;s important to remember that competition for those developers is proportional&amp;mdash;big companies will open their doors anywhere they can find clusters of talented people. &amp;nbsp;For example, I wasn&amp;rsquo;t surprised to see &lt;a href="http://techcrunch.com/2011/12/02/facebook-to-open-engineering-office-in-nyc/" title="Facebook's recent decision" target="_blank"&gt;Facebook's recent decision&lt;/a&gt; to open a development office in New York (although I said a prayer for my friends who are running startups there and already competing with each other, the banks, and Google for new hires).&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;There are plenty of excellent developers in Philadelphia, but it is admittedly a smaller pond than other major tech cities. &amp;nbsp;Developers do not gravitate here, but there are a lot of them here for personal or circumstantial reasons. &amp;nbsp;We have found that population to be rich with ambitious, talented people.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;Our proximity to leading universities like UPenn, Princeton, Drexel, and Villanova also allow local companies direct access to top-notch engineering grads. &amp;nbsp;Many of these talented engineers are "in play" every year. &amp;nbsp;As we&amp;rsquo;ve grown, we&amp;rsquo;ve seen an increasing level of success with university recruiting.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;There are also a number of large technology companies in the area (from Comcast to Oracle to SAP) who have sizable technology teams. &amp;nbsp;Professional recruiters are proactive about syphoning candidates out of these larger companies, and many startups like us have had success tapping into this pool of talent directly as well. &lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;Overall, I would say that the caliber of talent in the Philadelphia area is strong and the landscape of candidates is proportionally lower-volume and lower-competition than in other cities. &amp;nbsp;In other words, the inputs look a little different but the absolute yield is comparatively attractive. &amp;nbsp;We are building a world-class technology team here and see plenty of runway ahead of us.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h2&gt;&lt;span&gt;3. Philadelphia&amp;rsquo;s Startup and Technology Communities are Thriving&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;div&gt;When we moved to Philly in 2008 to start RJMetrics, the startup community was fledgling. &amp;nbsp;An organization called &lt;a href="http://phillystartupleaders.org/" title="Philly Startup Leaders" target="_blank"&gt;Philly Startup Leaders&lt;/a&gt; was picking up steam and we&amp;rsquo;d often bump into talented freelancers who spent their days at a coworking space called &lt;a href="http://indyhall.org/" title="Indy Hall" target="_blank"&gt;Indy Hall&lt;/a&gt;.&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;In just a few short years, these groups have flourished into nationally-recognized organizations with hundreds of members. &amp;nbsp;We&amp;rsquo;ve seen events like &lt;a href="http://phillytechweek.com/" title="Philly Tech Week" target="_blank"&gt;Philly Tech Week&lt;/a&gt; and the &lt;a href="http://www.meetup.com/philly-tech/" title="Philly Tech MeetUp" target="_blank"&gt;Philly Tech MeetUp&lt;/a&gt; surge into a successful existence. &amp;nbsp;We've also recently gained exposure to some amazing mentoring organizations that exist for later-stage companies. &lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;In my opinion, the diversity of the organizations in the Philly tech community is a great thing. &amp;nbsp;They allow a widespread population of technologists to each find a voice that works for them. &amp;nbsp;For the most part, these groups peacefully co-exist and share the common goal of making Philly a more awesome place for tech and business.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;As these organizations continue to evolve and collectively impact the local economy, I think the pieces are moving into place for a coalition of tech players to exercise greater influence on local politics and work together on initiatives to raise outside awareness of the broader Philadelphia tech community. &amp;nbsp;Today's &lt;a href="http://technicallyphilly.com/2011/12/13/former-boomi-ceo-bob-moul-appointed-president-of-philly-startup-leaders" title="election of Bob Moul" target="_blank"&gt;appointment of Bob Moul&lt;/a&gt; to the presidency of Philly Startup Leaders is evidence of this progress. &amp;nbsp;Stay tuned.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;h2&gt;&lt;span&gt;4. Philadelphia Companies Have Capital and Strategic Options&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;div&gt;One of the many lessons Jake and I took away from our previous jobs in VC is this: there are awesome companies everywhere and, if your company kicks ass, it doesn&amp;rsquo;t matter where it&amp;rsquo;s located. &amp;nbsp;You will have no problem raising money and you will have no shortage of options when the timing is right for an exit.&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;As we&amp;rsquo;ve grown, this truth has become increasingly clear. &amp;nbsp;Any venture firm that invests in New York or Boston companies will gladly invest in a Philadelphia company. &amp;nbsp;These include funds on both coasts.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;And doing business from Philly is easy. &amp;nbsp;We have a major US Airways hub that provides easy access to the west coast and Europe. &amp;nbsp;We also have extremely close proximity to New York, Washington DC, and the rest of the the eastern seaboard.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;Recently, Philly has seen big exits like &lt;a href="http://techcrunch.com/2010/06/03/google-confirms-invite-media/" title="Invite Media" target="_blank"&gt;Invite Media&lt;/a&gt; (to Google), &lt;a href="http://techcrunch.com/2010/11/02/heres-the-cloud-computing-company-dell-is-buying-boomi/" title="Boomi" target="_blank"&gt;Boomi&lt;/a&gt; (to Dell), and &lt;a href="http://techcrunch.com/2011/07/20/facebook-for-latinos-quepasa-buys-myyearbook-for-100-million-in-cash-and-stock/" title="MyYearbook" target="_blank"&gt;MyYearbook&lt;/a&gt; (to Quepasa). &amp;nbsp;We have also seen major investments made into companies like &lt;a href="http://techcrunch.com/2011/08/04/monetate-raises-15-million-for-simple-ad-testing-and-targeting-platform/" title="Monetate" target="_blank"&gt;Monetate&lt;/a&gt; (from First Round &amp;amp; Openview) and &lt;a href="http://techcrunch.com/2011/10/13/union-square-ventures-invests-in-alternative-search-engine-duckduckgo/" title="DuckDuckGo" target="_blank"&gt;DuckDuckGo&lt;/a&gt; (from Union Square). &amp;nbsp;Don&amp;rsquo;t be surprised to see more announcements like these soon.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;h2&gt;&lt;span&gt;5. We Love It Here&lt;/span&gt;&lt;/h2&gt;
&lt;div&gt;Philadelphia is an awesome city. &amp;nbsp;It&amp;rsquo;s rich with history, has one of the best restaurant scenes in the country, and is full of great people. &amp;nbsp;The arts scene is incredible. &amp;nbsp;We have great sports teams and even better cheesesteaks.&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;We are proud to call it our home. &amp;nbsp;Stop by anytime.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/9JXxOrthCnQ" height="1" width="1"/&gt;</description><dc:creator>Robert Moore</dc:creator><pubDate>Tue, 13 Dec 2011 17:36:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:50397</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/50397/Why-Our-Startup-is-Doubling-Down-on-Philadelphia</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/49753/Announcing-Our-Chart-Data-Export-API-with-Geckoboard-Support#Comments</comments><slash:comments>0</slash:comments><title>Announcing Our Chart Data Export API (with Geckoboard Support)</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/1IA03tugWOk/Announcing-Our-Chart-Data-Export-API-with-Geckoboard-Support</link><description>&lt;p&gt;We are excited to announce that clients can now use our &lt;a href="http://support.rjmetrics.com/forums/229638-api" title="API" target="_blank"&gt;API&lt;/a&gt; to access the data from any of their RJMetrics charts.&amp;nbsp; This will allow users to more easily integrate RJMetrics data into spreadsheets and other third-party tools.&amp;nbsp; Data can currently be downloaded in CSV, JSON, and Geckoboard formats.&lt;/p&gt;
&lt;p&gt;Many clients are already taking advantage of this new feature by displaying their charts in &lt;a href="http://www.geckoboard.com/" title="Geckoboard" target="_blank"&gt;Geckoboard&lt;/a&gt;, a live status board that can be used to display important company statistics. &amp;nbsp;Geckoboard offers a &lt;a href="http://support.geckoboard.com/entries/274940-custom-chart-widget-type-definitions" title="Custom Chart Widget" target="_blank"&gt;Custom Chart Widget&lt;/a&gt; which displays JSON-encoded charts. You can incorporate your RJMetrics charts into your Geckoboard dashboard in two ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Export the data in Geckoboard format, which outputs the chart data in a specialized JSON format that can be directly loaded into Geckoboard using their &lt;a href="http://support.geckoboard.com/entries/274940-custom-chart-widget-type-definitions" title="highcharts widget" target="_blank"&gt;highcharts widget&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Export the data in JSON format. This&amp;nbsp;outputs the chart's data as a JSON encoded list that you can load into a custom script that formats a Geckoboard chart to your exact specifications.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;The result is an RJMetrics-powered chart like the one below available directly on your company's Geckoboard!&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;img id="img-1322885317775" src="http://info.rjmetrics.com/Portals/17916/images/gecko screenshot-resized-600.png" border="0" alt="An RJMetrics chart on Geckoboard." class="alignCenter" style="display: block; margin-left: auto; margin-right: auto;" /&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;To learn more about how to use the new chart export API and how to integrate with Geckoboard, check out the &lt;a href="http://support.rjmetrics.com/forums/229638-api" title="API help center" target="_blank"&gt;RJMetrics API reference&lt;/a&gt;.&lt;/div&gt;
&lt;br /&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/1IA03tugWOk" height="1" width="1"/&gt;</description><dc:creator>Cathy Lennon</dc:creator><pubDate>Mon, 05 Dec 2011 17:06:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:49753</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/49753/Announcing-Our-Chart-Data-Export-API-with-Geckoboard-Support</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/48373/Come-See-RJMetrics-at-NOAH-2011#Comments</comments><slash:comments>0</slash:comments><title>Come See RJMetrics at NOAH 2011</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/kf5fWzMz83A/Come-See-RJMetrics-at-NOAH-2011</link><description>&lt;p&gt;If you're in London this week, be sure to stop by Old Billingsgate to meet our co-founders at the &lt;a href="http://www.noah-conference.com/" title="NOAH 2011 Conference" target="_blank"&gt;NOAH 2011 Conference&lt;/a&gt;.&amp;nbsp; We are in the expo hall at booth 14.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://info.rjmetrics.com/Portals/17916/images/noah-conference.png" border="0" alt="noah conference" /&gt;&lt;/p&gt;
&lt;p&gt;To set up a meeting, e-mail Jake Stein at &lt;a href="mailto:jstein@rjmetrics.com" rel="nofollow" title="jstein@rjmetrics.com" target="_self"&gt;jstein@rjmetrics.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hope to see you there!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/kf5fWzMz83A" height="1" width="1"/&gt;</description><dc:creator>Robert Moore</dc:creator><pubDate>Wed, 09 Nov 2011 10:36:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:48373</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/48373/Come-See-RJMetrics-at-NOAH-2011</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/44861/Import-A-CSV-Into-Your-Database#Comments</comments><slash:comments>0</slash:comments><title>Import A CSV Into Your Database</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/tgPX3VmskAc/Import-A-CSV-Into-Your-Database</link><description>&lt;p&gt;We are happy to announce big improvements to our file upload and CSV import functionality. This will make it much easier to analyze data that reside outside of your database and are not yet integrated into our data warehouse.&lt;/p&gt;
&lt;p&gt;Users can now upload files into their &lt;a href="http://www.rjmetrics.com/" target="_blank"&gt;RJMetrics&lt;/a&gt; data warehouse directly from their web browser and have the data directly imported into our database. Data can be uploaded in either Microsoft Excel or CSV format. When the data format changes or new attributes need to be added those changes can be made right from the file upload page.&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;img src="http://info.rjmetrics.com/Portals/17916/images/ETL.png" alt="Import A CSV Into Your database" /&gt;&lt;/p&gt;
&lt;p&gt;This feature:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Expedites the process of importing CSV and Excel files into our data warehouse&lt;/li&gt;
&lt;li&gt;Allows for analysis on new data sets quickly, efficiently, and on an ad hoc basis&lt;/li&gt;
&lt;li&gt;Eases the process of combining multiple data sources into one coherent picture&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also check out the &lt;a href="http://info.rjmetrics.com/blog/bid/44864/Changes-coming-to-your-RJMetrics-dashboards"&gt;changes coming to the RJMetrics dashboard&lt;/a&gt; and our &lt;a href="http://info.rjmetrics.com/blog/bid/44865/New-and-improved-settings-page"&gt;new settings page&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/tgPX3VmskAc" height="1" width="1"/&gt;</description><dc:creator>Gaston Burthey</dc:creator><pubDate>Fri, 02 Sep 2011 14:27:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:44861</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/44861/Import-A-CSV-Into-Your-Database</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/44862/We-re-Hiring-a-UI-and-UX-Engineer#Comments</comments><slash:comments>0</slash:comments><title>We're Hiring a UI and UX Engineer</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/R6iH5DVSz4w/We-re-Hiring-a-UI-and-UX-Engineer</link><description>&lt;p&gt;RJMetrics is looking for an exceptional user interface and user experience engineer to join our growing team &lt;a href="http://www.rjmetrics.com/jobs" target="_blank"&gt;apply here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you come in for an interview, we'll give you a free iPad or $500 cash (your choice). This is not for the person who referred you and it's not contingent on you getting a job offer. It's our gift to you for considering a career at RJMetrics. Prior to an in-person interview, you'll speak with a member or two from our team to make sure we'd be good fits for each other.&lt;/p&gt;
&lt;p&gt;RJMetrics is a fast-growing database analytics and business intelligence software company. Our product helps e-commerce, social media, and software as a service companies understand their users and businesses through data analysis and visualization.&lt;/p&gt;
&lt;p&gt;You will be THE expert on UI and UX at our company. You know great design when you see it, and you can explain why it's great, even if you didn't create it. You will help us establish and implement a consistent aesthetic throughout our product that users will find both appealing and easy to use. You will juggle multiple projects and provide design insight to different members of our engineering and marketing teams. In addition to wire-framing and Photoshopping, you will consistently contribute production PHP, HTML, and JavaScript (jQuery + Backbone.js) code to our codebase.&lt;/p&gt;
&lt;p&gt;You will recognize weaknesses in our organization and won't hesitate to tell us what we are doing wrong and why. You will occasionally pitch in with whatever needs to get done (blog posts, testing, cabinetmaking, etc.). Finally, you will help us hire more people just like you as our company continues to grow.&lt;/p&gt;
&lt;p&gt;In return, you will get to enjoy the perks of working at a fast-growing technology startup. You will get to build your own working environment with whatever hardware, software and furniture you need to be most effective. You will be given a stake in the company's success through stock options, along with a competitive salary. You will get medical, dental, and vision insurance, all paid for by the company. If you're here late, we'll even throw in dinner. Most importantly, you will help define the future of a promising company.&lt;/p&gt;
&lt;p&gt;Requirements&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Experience with or ability to learn object-oriented programming and SQL databases&lt;/li&gt;
&lt;li&gt;B.S. degree in Computer Science or a related field&lt;/li&gt;
&lt;li&gt;Must have built or contributed to something awesome that we can try out&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is a full time position located on site. We are located in the heart of Center City Philadelphia. We also occasionally speak at conferences, guest post on TechCrunch, get on the front page of Digg, and rap about business intelligence (seriously, search for RJMetrics on YouTube).&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;a href="http://www.rjmetrics.com/jobs" target="_blank"&gt;&lt;img src="http://info.rjmetrics.com/Portals/17916/images/apply-now.png" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/R6iH5DVSz4w" height="1" width="1"/&gt;</description><dc:creator>Gaston Burthey</dc:creator><pubDate>Wed, 24 Aug 2011 14:34:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:44862</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/44862/We-re-Hiring-a-UI-and-UX-Engineer</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/44863/Designing-a-Database-Schema#Comments</comments><slash:comments>0</slash:comments><title>Designing a Database Schema</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/OWHllvDMP4E/Designing-a-Database-Schema</link><description>&lt;p&gt;We&amp;rsquo;ve seen the databases of hundreds of online companies and we have determined that a well designed database schema can make all the difference in the quality of your database analytics. If you are not storing the most useful data as you possibly can, you may be diminishing the value of your business intelligence and this can have a negative impact on your bottom line.&lt;/p&gt;
&lt;p&gt;We have organized our knowledge into a white paper that is an informative and succinct evaluation of the most common mistakes that businesses make in schema design and data storage.&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;img src="http://info.rjmetrics.com/Portals/17916/images/untitled.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;This white paper discusses mistakes that can, for example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make it harder to analyze your business performance&lt;/li&gt;
&lt;li&gt;Stand in the way of actionable insight&lt;/li&gt;
&lt;li&gt;Prevent you from understanding key business metrics such as customer lifetime value, retention, and the payback period of various marketing sources&lt;/li&gt;
&lt;li&gt;Slow down your analytics significantly&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We encourage you to read this white paper so that you can become aware of these mistakes and gain a better understanding of how to realize the maximum value of your database analytics. Put yourself ahead of the competition today.&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;a href="http://info.rjmetrics.com/learn-the-5-biggest-mistakes-in-data-storage-for-analytics?hsCtaTracking=091c6f00-fe21-411f-a2bc-e90e77d85db7%7C7faf1f23-4bc8-40ff-992b-06ffca4bd1d4"&gt; &lt;img src="http://info.rjmetrics.com/Portals/17916/images/download-our-whitepaper.png" alt="download-whitepaper-5-biggest" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/OWHllvDMP4E" height="1" width="1"/&gt;</description><dc:creator>Gaston Burthey</dc:creator><pubDate>Wed, 17 Aug 2011 14:44:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:44863</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/44863/Designing-a-Database-Schema</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/44864/Changes-coming-to-your-RJMetrics-dashboards#Comments</comments><slash:comments>0</slash:comments><title>Changes coming to your RJMetrics dashboards</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/LVHuWsdxvdw/Changes-coming-to-your-RJMetrics-dashboards</link><description>&lt;p&gt;Following up on the &lt;a href="http://info.rjmetrics.com/blog/bid/44865/New-and-improved-settings-page"&gt;new settings page&lt;/a&gt;, we are hard at work on improvements to the dashboards and charts in RJMetrics. We wanted to outline a few of the changes ahead of time so that you know what to expect. We are focused on making RJMetrics the best way for online businesses to get &lt;a href="http://www.rjmetrics.com" target="_blank"&gt;actionable insight&lt;/a&gt; from their data, and the new features reflect that. We are also going to retire two of our lesser-used features so that we can put more focus on the areas that matter most.&lt;/p&gt;
&lt;h3&gt;Improvements&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Easier ad hoc analysis - see the impact of your changes right away, no need to save or press preview&lt;/li&gt;
&lt;li&gt;Single page chart editor - view all of your chart configuration settings at once&lt;/li&gt;
&lt;li&gt;Eliminating the need for composite charts - anything that you need a composite chart for today will be doable with the new version of the standard chart editor&lt;/li&gt;
&lt;li&gt;Drag and drop chart creation and editing - start viewing your data without configuration and get moving fast&lt;/li&gt;
&lt;li&gt;Micro-editor for quick changes - no need to open the full chart editor for changes to the date range&lt;/li&gt;
&lt;li&gt;Improved visualizations - easier to read and powered by javascript rather than flash&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Retired features&lt;/h3&gt;
&lt;p&gt;We will continue to support both of the features below until September 15. After that, charts that use either will be removed from the dashboards. As a reminder, you can export the visualizations or data behind your charts if you want to hold on to this data.&lt;/p&gt;
&lt;p&gt;Twitter - Social media tracking is valuable, but it was never our focus. We have gotten feedback from clients that Twitter alone is not very useful, and adding other social media services is not in our road map. We recommend checking out &lt;a href="http://argylesocial.com/" target="_blank"&gt;Argyle Social&lt;/a&gt;, &lt;a href="http://totally.awe.sm/" target="_blank"&gt;Awe.sm&lt;/a&gt;, &lt;a href="http://www.radian6.com/" target="_blank"&gt;Radian6&lt;/a&gt;, and &lt;a href="http://www.ubervu.com/" target="_blank"&gt;uberVU&lt;/a&gt; as great options for tracking and analyzing your influence through social media. For managing your various social media accounts, you can&amp;rsquo;t beat our client &lt;a href="http://hootsuite.com/" target="_blank"&gt;HootSuite&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Rank over time - There are actually two separate ranking features in RJMetrics, and we are removing the one that is very rarely used. You will be still be able to show the top 10 categories or the bottom 5% of users as described in &lt;a href="http://support.rjmetrics.com/entries/270474-top-or-bottom-x-categories" target="_blank"&gt;this help center article&lt;/a&gt;. However we are removing the ability to choose a specific element and plot changes to its rank over time.&lt;/p&gt;
&lt;p&gt;We hope you are as excited as we are about the upcoming improvements to RJMetrics.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/LVHuWsdxvdw" height="1" width="1"/&gt;</description><dc:creator>Jake  Stein</dc:creator><pubDate>Fri, 12 Aug 2011 14:51:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:44864</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/44864/Changes-coming-to-your-RJMetrics-dashboards</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/44865/New-and-improved-settings-page#Comments</comments><slash:comments>0</slash:comments><title>New and improved settings page</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/HUrftYKyr_0/New-and-improved-settings-page</link><description>&lt;p&gt;We released a complete rework of our settings page today. We&amp;rsquo;re very proud of our team&amp;rsquo;s work, and we wanted to highlight a few of the benefits our customers will see.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Faster navigation&lt;/li&gt;
&lt;li&gt;Cleaner user interface improved design&lt;/li&gt;
&lt;li&gt;Better chart management with find as you type, filter by trend, and batch deletion&lt;/li&gt;
&lt;li&gt;More control over data configuration with the ability to create, edit, and delete restriction sets&lt;/li&gt;
&lt;li&gt;Faster addition of data sources with the ability to create, edit, and test connections to your database&lt;/li&gt;
&lt;li&gt;Easier diagnosis of common connection problems with automatic detection of error types and recommendations for fixes&lt;/li&gt;
&lt;li&gt;More information in the system configuration summary with detail on references (also known as foreign keys)&lt;/li&gt;
&lt;li&gt;Easier account management with the ability to download receipts for all historical payments&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We are updating the relevant articles on &lt;a href="http://support.rjmetrics.com" target="_blank"&gt;support.rjmetrics.com&lt;/a&gt; with new instructions and information. If you have any questions, don&amp;rsquo;t hesitate to let us know.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/HUrftYKyr_0" height="1" width="1"/&gt;</description><dc:creator>Jake  Stein</dc:creator><pubDate>Thu, 04 Aug 2011 14:56:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:44865</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/44865/New-and-improved-settings-page</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/44866/How-to-A-B-Test-Using-Javascript-in-Your-Posterous-Blog#Comments</comments><slash:comments>1</slash:comments><title>How to A/B Test Using Javascript in Your Posterous Blog</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/7Lr1tRR3Tvk/How-to-A-B-Test-Using-Javascript-in-Your-Posterous-Blog</link><description>&lt;p&gt;At RJMetrics, we use Hubspot for marketing automation and decided to do some A/B testing to determine which links are more effective on our blog. We set up two buttons, or as Hubspot calls them, "Calls to Action". Hubspot randomly chooses which button to display&amp;nbsp; and lets us track the results of each. This requires embedding a snippet of Javascript on our blog, which Posterous (our blogging platform) does not allow.&amp;nbsp;&amp;nbsp; We can get around this limitation using iframes.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1.&amp;nbsp; Create a new page&lt;/strong&gt; where your Javascript snippet is housed.&amp;nbsp; You will need to upload this child page to an online host.&amp;nbsp; In this example, &lt;strong&gt;iframe_link_child.html&lt;/strong&gt; is populated with a simple link and the following Javascript:&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1067306.js?file=iframe_link_child.html"&gt;&lt;/script&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.&amp;nbsp; Add an iframe&lt;/strong&gt; to your new page from your Posterous blog post by editing the HTML and adding:&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1067303.js?file=blog"&gt;&lt;/script&gt;
&lt;br /&gt;
&lt;p&gt;&lt;strong&gt;3.&amp;nbsp; Update Link Attributes.&amp;nbsp; &lt;/strong&gt;If you have links, by default, they will open inside the existing iframe.&amp;nbsp; To improve the end user experience, it may be necessary to have links open on a new page.&amp;nbsp; Simply edit the target tag of your link by adding target='_blank' to all existing links in your child page:&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1067309.js?file=iframe_link_child.html"&gt;&lt;/script&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4.&amp;nbsp; Hubspot Specific: Edit Javascript to allow for new target.&amp;nbsp; &lt;/strong&gt;If you are using Hubspot's call to actions, you will need to use Javascript to edit the element's target property because Hubspot generates the link on the fly. To do this, execute the following Javascript code:&lt;/p&gt;
&lt;script type="text/javascript" src="https://gist.github.com/1067462.js?file=Hubspot%20Code"&gt;&lt;/script&gt;
&lt;p&gt;&lt;b&gt;Voila!&lt;/b&gt; Check out our finished Javascript-enabled button on the Posterous platform:&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;iframe frameborder="0" height="70" marginheight="0" marginwidth="0" src="http://www.rjmetrics.com/embedded_call_to_action_button.html" width="400"&gt;&lt;/iframe&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/7Lr1tRR3Tvk" height="1" width="1"/&gt;</description><dc:creator>Peter Zhang</dc:creator><pubDate>Thu, 07 Jul 2011 14:08:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:44866</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/44866/How-to-A-B-Test-Using-Javascript-in-Your-Posterous-Blog</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/44867/Our-Start-Up-s-First-Trade-Show-A-Data-Driven-Recap#Comments</comments><slash:comments>16</slash:comments><title>Our Start-Up's First Trade Show: A Data-Driven Recap</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/xtmM2L9ZTWs/Our-Start-Up-s-First-Trade-Show-A-Data-Driven-Recap</link><description>&lt;p&gt;Last week, &lt;a href="http://www.rjmetrics.com/about-us" target="_blank"&gt;Jake and I&lt;/a&gt; attended the 2011 &lt;a href="http://irce.internetretailer.com/2011/" target="_blank"&gt;Internet Retailer Conference and Exhibition&lt;/a&gt; (IRCE 2011) in San Diego.&lt;span&gt;&amp;nbsp; &lt;/span&gt;This four-day event is the world&amp;rsquo;s largest e-commerce convention, with over 7,200 attendees and 500 exhibiting vendors.&lt;/p&gt;
&lt;p&gt;This was our first &amp;ldquo;real&amp;rdquo; trade show with &lt;a href="http://www.rjmetrics.com/" target="_blank"&gt;RJMetrics&lt;/a&gt; and it was a new experience for both of us. Our main objectives were to generate sales leads and raise awareness of RJMetrics in the internet retail community. To help achieve these goals, we purchased a 10&amp;rsquo;x10&amp;rsquo; booth in the exhibit hall to peddle our wares.&lt;/p&gt;
&lt;p&gt;This post is a summary of our experience as newbies to the trade show circuit. It is the result of data collection and note-taking on both our and other exhibitors&amp;rsquo; behavior and performance. The data taught us three main lessons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It pays to be aggressive&lt;/li&gt;
&lt;li&gt;We have the most success with conference attendees who don&amp;rsquo;t look like us&lt;/li&gt;
&lt;li&gt;One of us has a very bright future as a carnival barker&lt;/li&gt;
&lt;/ul&gt;
&lt;p style="text-align: center;"&gt;&lt;a href="http://info.rjmetrics.com/Portals/17916/images/IRCETeam.jpg" target="_blank"&gt;&lt;img src="http://info.rjmetrics.com/Portals/17916/images/IRCETeam.jpg" alt="" width="500" height="491" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Who wouldn't buy software from these handsome, slightly blurry gentlemen?&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Exhibitor Social Dynamics&lt;/h3&gt;
&lt;p&gt;Within the first hour of the show, we observed quite a bit. Most notable was that trade show exhibitors appear to all fall somewhere on the &amp;ldquo;aggression spectrum,&amp;rdquo; with the most prominent approaches including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Disengaged&lt;/b&gt;: Exhibitors sitting behind their booths, not making eye contact with anyone, and waiting for attendees to approach them.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Passive&lt;/b&gt;: Exhibitors standing, saying hello, or otherwise giving physical signs that they are available to speak if passers-by are interested.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Passive-Question&lt;/b&gt;: Exhibitors attempting to engage passers-by with easy-to-reject questions such as &amp;ldquo;Can I give you some information on our company?&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Aggressive&lt;/b&gt;: Exhibitors approaching passers-by with out-of-the-blue questions related to their pitch, such as &amp;ldquo;do you ship product?&amp;rdquo; or &amp;ldquo;who is your domain name registrar?&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additionally, many exhibitors made use of &amp;ldquo;enhancers&amp;rdquo; to help attract attendee interest. (We had none of these to offer.) The most popular ones included:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Swag&lt;/b&gt;: Pens! Stress balls! T-Shirts! Nothing softens a sales pitch like free junk with your company&amp;rsquo;s logo on it. While some attendees were lugging bags of this stuff around, we didn&amp;rsquo;t perceive any disadvantage by not offering it. (This is based on casual observations of our performance relative to nearby booths that were aggressively distributing swag.)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Sweepstakes&lt;/b&gt;: There was a huge promotion at the conference in which attendees who collected &amp;ldquo;stickers&amp;rdquo; from about 40 specific booths would be entered to win a new car. (We could have been one of the 40 booths by shelling out $7,600 to the conference organizers.) We were definitely losing leads to this promotion, as many passers-by used &amp;ldquo;I have to get my stickers&amp;rdquo; as a reason for not staying to learn more about us.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Hot Girls&lt;/b&gt;: The vast majority of attendees were male, and some exhibitors hired models to engage passers-by and lure them in for a conversation. This appeared to be effective. However, I can see how certain attendees might find this patronizing or otherwise offensive.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Data Collection&lt;/h3&gt;
&lt;p&gt;For that first hour, Jake and I waited for people to come to us. We quickly decided that it would be worth A/B testing other approaches to see how we would do. For the next three days, we recorded the following data points about every interaction we had:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Date and Time&lt;/li&gt;
&lt;li&gt;Badge Type (attendee or exhibitor)&lt;/li&gt;
&lt;li&gt;Gender&lt;/li&gt;
&lt;li&gt;Approximate Age (by decade)&lt;/li&gt;
&lt;li&gt;Ethnicity&lt;/li&gt;
&lt;li&gt;Number of People in Group (when applicable)&lt;/li&gt;
&lt;li&gt;Discussion Starter (Jake or Bob)&lt;/li&gt;
&lt;li&gt;Success or Failure (success was defined as being able to give a 30-second pitch on what we do and learn where the attendee worked and what their role was at the company)&lt;/li&gt;
&lt;li&gt;Approach Used (see below)&lt;/li&gt;
&lt;li&gt;We collected data on four different conversation-starting approaches:&lt;/li&gt;
&lt;li&gt;&amp;ldquo;What is your average customer lifetime value?&amp;rdquo; This heavy question was designed to stop people in their tracks and be a lead-in to a conversation about the benefits we provide.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;How much of your revenue is from &lt;a href="http://www.rjmetrics.com/repeat-purchase" target="_blank"&gt;repeat customers&lt;/a&gt;?&amp;rdquo; This was a less intimidating question with the same intention as above.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Does Your Company Generate Data?&amp;rdquo; This was a question that we knew people should always say &amp;ldquo;yes&amp;rdquo; to.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Can I give you some information on RJMetrics?&amp;rdquo; This was passive-question approach.&lt;/li&gt;
&lt;li&gt;The Walk-Up (when people came up to us unsolicited).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At the end of the three days, we collected 330 data points, 230 of which were successful conversations and exactly 100 of which were rejections.&lt;/p&gt;
&lt;h3&gt;Inbound vs. Outbound&lt;/h3&gt;
&lt;p&gt;One thing was clear: it pays to have an outbound strategy. Only 28% of our conversations were Walk-Ups. This means that employing an outbound strategy allowed us to extract between 3 and 4 times as much value from the show as we would have otherwise.&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;a href="http://info.rjmetrics.com/Portals/17916/images/1.jpg" target="_blank"&gt;&lt;img src="http://info.rjmetrics.com/Portals/17916/images/1.jpg" alt="" width="500" height="366" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We initially speculated that the quality of walk-up traffic would be higher than that of random passers-by. However, we observed (unscientifically) that this was not the case. While some very high-value prospects did approach us as walk-ups, we ultimately derived more qualified leads from our outbound conversations.&lt;/p&gt;
&lt;h3&gt;Effectiveness by Outbound Approach&lt;/h3&gt;
&lt;p&gt;Naturally, 100% of walk-ups converted into conversations. Below, we show the conversion rates on the other outbound approaches.&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;a href="http://info.rjmetrics.com/Portals/17916/images/2.jpg" target="_blank"&gt;&lt;img src="http://info.rjmetrics.com/Portals/17916/images/2.jpg" alt="" width="500" height="366" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Clearly, the more aggressive methods (i.e. asking a pointed question that is difficult to brush off) were the most effective. Asking questions about repeat purchase rates such as &amp;ldquo;What Percent of Your Customers Come Back to Purchase a Second Time?&amp;rdquo; was the most effective method, with a whopping 79% conversion rate.&lt;/p&gt;
&lt;p&gt;The least effective method of the outbound approaches was the passive-question technique (i.e. &amp;ldquo;Can I give you some information on RJMetrics?&amp;rdquo;)&lt;/p&gt;
&lt;h3&gt;Age&lt;/h3&gt;
&lt;p&gt;The most common passer-by was in their 30s, and the populations steadily dropped off with each additional decade of age. The percentage of attendees in their 20s (like us) was surprisingly small.&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;a href="http://info.rjmetrics.com/Portals/17916/images/8.jpg" target="_blank"&gt;&lt;img src="http://info.rjmetrics.com/Portals/17916/images/8.jpg" alt="" width="500" height="366" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Our success rates were lowest with attendees in their 40s, but increased substantially at each extreme end of the age spectrum. We weren't surpised by our success with 20-somethings, but would not have predicted that we'd have such strong performance with much older attendees.&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;a href="http://info.rjmetrics.com/Portals/17916/images/9.jpg" target="_blank"&gt;&lt;img src="http://info.rjmetrics.com/Portals/17916/images/9.jpg" alt="" width="500" height="366" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Race and Gender&lt;/h3&gt;
&lt;p&gt;We were interested in the breakdown of attendees at the conference and our relative success levels with different groups of people. While there is a potential for selection bias here, we feel that we spoke with a random sample of the conference population. As such, the breakdown of our interactions is likely representative of the conference population as a whole.&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;a href="http://info.rjmetrics.com/Portals/17916/images/6.jpg" target="_blank"&gt;&lt;img src="http://info.rjmetrics.com/Portals/17916/images/6.jpg" alt="" width="500" height="366" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;72% of our interactions were with white males. Interestingly, it was about as likely that we interacted with someone who was non-white (15%) as with someone who was non-male (13%).&lt;/p&gt;
&lt;p&gt;The conversion rates of different race and gender combinations are also quite interesting. We were least likely to convert white males (58%) and most likely to convert non-white females (87%). Overall, our conversion rates on females and non-white attendees were higher than their counterparts.&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;a href="http://info.rjmetrics.com/Portals/17916/images/7.jpg" target="_blank"&gt;&lt;img src="http://info.rjmetrics.com/Portals/17916/images/7.jpg" alt="" width="500" height="366" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Jake vs. Bob&lt;/h3&gt;
&lt;p&gt;So, who was the better pitchman? Despite heroic trash talking, &lt;b&gt;Jake put me to shame&lt;/b&gt;. 66% of his attempts converted into conversations (compared to my paltry 55%).&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;a href="http://info.rjmetrics.com/Portals/17916/images/3.jpg" target="_blank"&gt;&lt;img src="http://info.rjmetrics.com/Portals/17916/images/3.jpg" alt="" width="500" height="366" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We also looked at conversion attempts for females only. This data revealed that, while Jake still converted attempts into conversations at a higher rate than I did, the gap was significantly smaller. Unfortunately, these rates did not carry over to the after parties.&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;a href="http://info.rjmetrics.com/Portals/17916/images/5.jpg" target="_blank"&gt;&lt;img src="http://info.rjmetrics.com/Portals/17916/images/5.jpg" alt="" width="500" height="366" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;The ROI of An Aggressive Pitch&lt;/h3&gt;
&lt;p&gt;All-in, our booth space, display materials, meals, travel, and accommodations added up to about $8,000 of total expense. (This does not include the opportunity cost of our time.)&lt;/p&gt;
&lt;p&gt;The exhibit hall was open for a total of 20.5 hours across 3 days, which works out to about &lt;b&gt;$6.50 per minute&lt;/b&gt; to participate in the exhibition. As the co-founders of a bootstrapped company, that figure weighed heavily in our minds every time we considered getting some lunch or taking a bathroom break.&lt;/p&gt;
&lt;p&gt;If you look at our total interactions, the numbers get even larger. Based on our count of 220 conversations, we paid around $36 per pitch. This is where our aggressive sales strategy really makes a significant impact. If we had only interacted with the 65 walk-ups from the conference, that effective rate would have been $123 per pitch.&lt;/p&gt;
&lt;p&gt;In other words, we extracted nearly 3 times as much value from our conference experience by simply getting out in front of the booth and selling more aggressively.&lt;/p&gt;
&lt;p&gt;Given these data points, it becomes clear why some companies are willing to invest money in novelties and gimmicks to increase traffic to their booths. Spending a few thousand dollars could double or triple the effectiveness of your experience while increasing your costs by a significantly smaller percentage.&lt;/p&gt;
&lt;h3&gt;Was it Worth It?&lt;/h3&gt;
&lt;p&gt;Given the price point of our product, we will break even on this conference if we convert a single lead into a long-term customer. Based on the leads generated and our typical sales cycle, it seems very likely that we will do much better than that.&lt;/p&gt;
&lt;p&gt;There were also less tangible benefits to participating in the show. We increased brand awareness, strengthening our relationships with existing customers, scoping out the competition, and keeping up-to-date with emerging trends and technologies.&lt;/p&gt;
&lt;p&gt;Perhaps most importantly, however, this experience has given us a new perspective on how to think about the costs of customer acquisition and spending money to acquire new business. If this show turns out to be a profitable endeavor, we will have have a great baseline for the cost of putting people into the top of our sales funnel. With this data, we can feel much more confident about making investments in advertising and other forms of lead generation.&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;iframe frameborder="0" height="70" marginheight="0" marginwidth="0" src="http://www.rjmetrics.com/embedded_call_to_action_button.html" width="400"&gt;&lt;/iframe&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/xtmM2L9ZTWs" height="1" width="1"/&gt;</description><dc:creator>Robert Moore</dc:creator><pubDate>Tue, 21 Jun 2011 14:30:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:44867</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/44867/Our-Start-Up-s-First-Trade-Show-A-Data-Driven-Recap</feedburner:origLink></item><item><comments>http://info.rjmetrics.com/blog/bid/44869/RJMetrics-at-Internet-Retailer-Conference-2011#Comments</comments><slash:comments>0</slash:comments><title>RJMetrics at Internet Retailer Conference 2011</title><link>http://feedproxy.google.com/~r/rjmetrics/metricsystem/~3/Ff5F-5_j4U0/RJMetrics-at-Internet-Retailer-Conference-2011</link><description>&lt;a href="https://www.webregnow.com/vwm/00012104/IRCE2011/login/login-att.aspx?EC120341=2011" target="_blank"&gt;&lt;img src="http://info.rjmetrics.com/Portals/17916/images/IRCE2011_Logo.jpg" alt="IRCE2011_Logo.jpg (250&amp;amp;times;125)" /&gt;&lt;/a&gt;
&lt;p&gt;We are exhibiting at Internet Retailer Conference &amp;amp; Exhibition 2011. &amp;nbsp;The conference is in San Diego, and it&amp;rsquo;s taking place June 14 - 17.&lt;/p&gt;
&lt;p&gt;If you have not yet signed up, you can &lt;a href="https://www.webregnow.com/vwm/00012104/IRCE2011/login/login-att.aspx?EC120341=2011" target="_blank"&gt;use our discount code EC120341 to get $100 off admission&lt;/a&gt;. In any case, make sure that you come see us at &lt;b&gt;booth 1940&lt;/b&gt;. If you would like to meet up with a member of our team at the show, send an email to sales at rjmetrics dot com. We will be giving demos, answering questions, shaking hands, and kissing babies.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/rjmetrics/metricsystem/~4/Ff5F-5_j4U0" height="1" width="1"/&gt;</description><dc:creator>Jake  Stein</dc:creator><pubDate>Thu, 09 Jun 2011 14:38:00 GMT</pubDate><guid isPermaLink="false">f1397696-738c-4295-afcd-943feb885714:44869</guid><feedburner:origLink>http://info.rjmetrics.com/blog/bid/44869/RJMetrics-at-Internet-Retailer-Conference-2011</feedburner:origLink></item></channel></rss>

