<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link rel="hub" href="http://tumblr.superfeedr.com/" xmlns:atom="http://www.w3.org/2005/Atom"/><description></description><title>OpenSky Tech</title><generator>Tumblr (3.0; @oskytech)</generator><link>http://engineering.opensky.com/</link><item><title>Jonathan H. Wage: Ruler: A simple stateless production rules engine for PHP 5.3+</title><description>&lt;a href="http://jwage.com/post/31292541379/ruler-a-simple-stateless-production-rules-engine-for"&gt;Jonathan H. Wage: Ruler: A simple stateless production rules engine for PHP 5.3+&lt;/a&gt;: &lt;p&gt;&lt;a href="http://jwage.com/post/31292541379/ruler-a-simple-stateless-production-rules-engine-for" class="tumblr_blog"&gt;jwage&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What is ruler?&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="https://github.com/bobthecow/ruler"&gt;Ruler&lt;/a&gt; is a simple stateless production rules engine for PHP 5.3+ written by &lt;a href="http://twitter.com/bobthecow"&gt;Justin Hileman (@bobthecow)&lt;/a&gt;. Justin was previously employed at &lt;a href="https://opensky.com"&gt;OpenSky&lt;/a&gt; but these days you will find him hacking on a new startup named &lt;a href="https://twitter.com/presentate"&gt;@presentate&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;What is a rules engine?&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;From &lt;a href="http://martinfowler.com/bliki/RulesEngine.html"&gt;…&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;</description><link>http://engineering.opensky.com/post/31292836079</link><guid>http://engineering.opensky.com/post/31292836079</guid><pubDate>Mon, 10 Sep 2012 18:05:43 -0400</pubDate></item><item><title>Jonathan H. Wage: Doctrine DBAL: PHP Database Abstraction Layer</title><description>&lt;a href="http://jwage.com/post/31080076112/doctrine-dbal-php-database-abstraction-layer"&gt;Jonathan H. Wage: Doctrine DBAL: PHP Database Abstraction Layer&lt;/a&gt;: &lt;p&gt;&lt;a href="http://jwage.com/post/31080076112/doctrine-dbal-php-database-abstraction-layer" class="tumblr_blog"&gt;jwage&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Most people think ORM when they hear the name &lt;a href="http://doctrine-project.org"&gt;Doctrine&lt;/a&gt;, but what most people don’t know, or forget, is that Doctrine is built on top of a very powerful Database Abstraction Layer that has been under development for over a decade. It’s history can be traced back to 1999 in a library named…&lt;/p&gt;&lt;/blockquote&gt;</description><link>http://engineering.opensky.com/post/31204459521</link><guid>http://engineering.opensky.com/post/31204459521</guid><pubDate>Sun, 09 Sep 2012 12:25:50 -0400</pubDate></item><item><title>Jonathan H. Wage: Deploying OpenSky with Fabric</title><description>&lt;a href="http://jwage.com/post/31049115791/deploying-opensky-with-fabric"&gt;Jonathan H. Wage: Deploying OpenSky with Fabric&lt;/a&gt;: &lt;p&gt;&lt;a href="http://jwage.com/post/31049115791/deploying-opensky-with-fabric" class="tumblr_blog"&gt;jwage&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;At &lt;a href="http://opensky.com"&gt;OpenSky&lt;/a&gt; we use &lt;a href="http://docs.fabfile.org/en/1.4.3/index.html"&gt;Fabric&lt;/a&gt; to deploy new versions of software to our servers. We deploy dozens of times a day to our testing environments, and do daily deploys to production.&lt;/p&gt; &lt;p&gt;Our production web nodes are split in to two groups, &lt;strong&gt;group1&lt;/strong&gt; and &lt;strong&gt;group2&lt;/strong&gt;. It is setup that way so we can easily pull out…&lt;/p&gt;&lt;/blockquote&gt;</description><link>http://engineering.opensky.com/post/31204368811</link><guid>http://engineering.opensky.com/post/31204368811</guid><pubDate>Sun, 09 Sep 2012 12:24:24 -0400</pubDate></item><item><title>Kris Wallsmith: Symfony2 ESI error: File name too long</title><description>&lt;a href="http://kriswallsmith.net/post/22720626123/symfony2-esi-error-file-name-too-long"&gt;Kris Wallsmith: Symfony2 ESI error: File name too long&lt;/a&gt;: &lt;p&gt;&lt;a href="http://kriswallsmith.net/post/22720626123/symfony2-esi-error-file-name-too-long" class="tumblr_blog"&gt;kriswallsmith&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We recently came across a strange, intermittent error at OpenSky:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;(36)File name too long: Cannot map GET /_internal… HTTP/1.1 to file&lt;/p&gt;
&lt;/blockquote&gt; &lt;p&gt;We use Varnish to cache large sections of our pages that include
follow/unfollow buttons. If the user is following a certain curator we show
the unfollow…&lt;/p&gt;&lt;/blockquote&gt;</description><link>http://engineering.opensky.com/post/22720722252</link><guid>http://engineering.opensky.com/post/22720722252</guid><pubDate>Wed, 09 May 2012 12:44:55 -0400</pubDate></item><item><title>Kris Wallsmith: Hello Spork! (aka "Forking PHP...")</title><description>&lt;a href="http://kriswallsmith.net/post/20844920640/hello-spork"&gt;Kris Wallsmith: Hello Spork! (aka "Forking PHP...")&lt;/a&gt;: &lt;p&gt;&lt;a href="http://kriswallsmith.net/post/20844920640/hello-spork" class="tumblr_blog"&gt;kriswallsmith&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A few months ago I was tasked with speeding up the upload of assets to the OpenSky CDN, which was taking a few minutes each deploy. I ended up dividing the upload into multiple processes using &lt;code&gt;pcntl_fork()&lt;/code&gt; and bringing the total time of the upload down to a matter of seconds.&lt;/p&gt; &lt;p&gt;Since then I’ve…&lt;/p&gt;&lt;/blockquote&gt;</description><link>http://engineering.opensky.com/post/20849376641</link><guid>http://engineering.opensky.com/post/20849376641</guid><pubDate>Tue, 10 Apr 2012 13:31:39 -0400</pubDate></item><item><title>Kris Wallsmith: I ♥ Event Delegation</title><description>&lt;a href="http://kriswallsmith.net/post/19404235746/jquery-event-delegation"&gt;Kris Wallsmith: I ♥ Event Delegation&lt;/a&gt;: &lt;p&gt;&lt;a href="http://kriswallsmith.net/post/19404235746/jquery-event-delegation" class="tumblr_blog"&gt;kriswallsmith&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;jQuery event delegation is &lt;s&gt;one of the coolest things since&lt;/s&gt; way cooler than sliced bread.&lt;/p&gt; &lt;p&gt;This new hotness allows you to listen for an event farther up the DOM than where that event is triggered. If you understand event bubbling, you should be able to grok this fairly quickly.&lt;/p&gt; &lt;p&gt;It starts getting…&lt;/p&gt;&lt;/blockquote&gt;</description><link>http://engineering.opensky.com/post/19836032391</link><guid>http://engineering.opensky.com/post/19836032391</guid><pubDate>Sat, 24 Mar 2012 11:21:11 -0400</pubDate><category>jquery</category></item><item><title>"People tend to say things like ‘Git makes more sense when you understand […]’."</title><description>“People tend to say things like ‘Git makes more sense when you understand […]’.”&lt;br/&gt;&lt;br/&gt; - &lt;em&gt;Required reading of the day: &lt;a href="http://think-like-a-git.net/"&gt;Think like (a) Git&lt;/a&gt;.&lt;/em&gt;</description><link>http://engineering.opensky.com/post/12471817046</link><guid>http://engineering.opensky.com/post/12471817046</guid><pubDate>Mon, 07 Nov 2011 11:58:10 -0500</pubDate></item><item><title>Changing history, or How to Git pretty</title><description>&lt;a href="http://justinhileman.info/article/changing-history/"&gt;Changing history, or How to Git pretty&lt;/a&gt;: &lt;p&gt;OpenSky’s engineering and product teams have an ongoing lunchtime presentation series called Lunch and Learn. A couple of weeks ago, I gave a talk entitled “Lunch and learn2git”. I just posted an article on my blog based on that presentation. Check it out!&lt;/p&gt;</description><link>http://engineering.opensky.com/post/12351739295</link><guid>http://engineering.opensky.com/post/12351739295</guid><pubDate>Fri, 04 Nov 2011 22:07:08 -0400</pubDate></item><item><title>OpenSky moving day!</title><description>&lt;img src="http://24.media.tumblr.com/tumblr_ltfbidwDeY1r59yl4o1_500.jpg"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;OpenSky moving day!&lt;/p&gt;</description><link>http://engineering.opensky.com/post/11735039523</link><guid>http://engineering.opensky.com/post/11735039523</guid><pubDate>Thu, 20 Oct 2011 12:08:00 -0400</pubDate></item><item><title>How we chose Symfony2 as our web framework</title><description>&lt;p&gt;As we set out to build the next great social ecommerce platform we were struck with a rare and great opportunity to start with a clean slate. We were able to select each piece of our architecture without any predefined requirements.  This let us review the state of the Frameworks in PHP and select the best one for our needs.&lt;/p&gt;

&lt;h4&gt;First we developed a set of requirements&lt;/h4&gt;

&lt;p&gt;Brace yourself, it’s a long list.&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;ORM&lt;/li&gt;
    &lt;li&gt;DB Obj relationships ie: :has_many&lt;/li&gt;
    &lt;li&gt;Good db migration mgmt&lt;/li&gt;
    &lt;li&gt;Good master slave config for db&lt;/li&gt;
    &lt;li&gt;Intelligent db trans support&lt;/li&gt;
    &lt;li&gt;Scaffolding&lt;/li&gt;
    &lt;li&gt;CRUD friendly&lt;/li&gt;
    &lt;li&gt;Business logic kept in model not controller&lt;/li&gt;
    &lt;li&gt;Controllers have ability to get heavy&lt;/li&gt;
    &lt;li&gt;No heavy loading of controllers&lt;/li&gt;
    &lt;li&gt;No race conditions for controllers (ie routing)&lt;/li&gt;
    &lt;li&gt;Template engine&lt;/li&gt;
    &lt;li&gt;Objects accessible in view&lt;/li&gt;
    &lt;li&gt;Widget/component support in view layer&lt;/li&gt;
    &lt;li&gt;Good header mgmt&lt;/li&gt;
    &lt;li&gt;Good mgmt of js and css files&lt;/li&gt;
    &lt;li&gt;All js and css be compressed&lt;/li&gt;
    &lt;li&gt;Ability to define explict routes or priorities not based on file system&lt;/li&gt;
    &lt;li&gt;Smart SEO urls by default&lt;/li&gt;
    &lt;li&gt;XSS &amp;amp; CSRF Protection&lt;/li&gt;
    &lt;li&gt;Good Form builders&lt;/li&gt;
    &lt;li&gt;Form Validations&lt;/li&gt;
    &lt;li&gt;No XML =&amp;gt; YML or JSON&lt;/li&gt;
    &lt;li&gt;enforcement of coding stds&lt;/li&gt;
    &lt;li&gt;Convention and configuration&lt;/li&gt;
    &lt;li&gt;Ability to design by contract&lt;/li&gt;
    &lt;li&gt;Caching: Support for memcache and sessions&lt;/li&gt;
    &lt;li&gt;Configs cached not parsed&lt;/li&gt;
    &lt;li&gt;Cloud sensitive&lt;/li&gt;
    &lt;li&gt;Good role base ACL support (no global, system base)&lt;/li&gt;
    &lt;li&gt;Support for webservices&lt;/li&gt;
    &lt;li&gt;Easily loadable support for external libs&lt;/li&gt;
    &lt;li&gt;Profiler built in or easy to integrate (timers, number of queries, memory used, etc)&lt;/li&gt;
    &lt;li&gt;Localization (currency, dates etc)&lt;/li&gt;
    &lt;li&gt;CLI model access&lt;/li&gt;
    &lt;li&gt;CLI for testing&lt;/li&gt;
    &lt;li&gt;Unit testing&lt;/li&gt;
    &lt;li&gt;Actions are unit testable&lt;/li&gt;
    &lt;li&gt;Good file handling&lt;/li&gt;
    &lt;li&gt;Good exception handling – ie log4j&lt;/li&gt;
    &lt;li&gt;Support for multiple environments (dev, test, staging, prod)&lt;/li&gt;
&lt;/ul&gt;&lt;h4&gt;Comparing Frameworks&lt;/h4&gt;

&lt;p&gt;Then we looked at any framework that someone on the team would be willing to evaluate. We ended up with 7 Frameworks to compare.&lt;/p&gt;

&lt;p&gt;We only evaluated PHP specific frameworks as our team is primarily a PHP team and that is where our expertise is.&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;&lt;a href="http://symfony-reloaded.org/"&gt;Symfony2&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://www.symfony-project.org/"&gt;Symfony 1.4&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://www.yiiframework.com/"&gt;Yii&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://kohanaframework.org/"&gt;Kohana&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://zoopframework.com/"&gt;Zoop2&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://lithify.me/"&gt;Lithium&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://solarphp.com/"&gt;Solar&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Notice that Zend Framework, Cake, Code Ignitor or X Framework aren’t on the list. There were a good 10 or so popular frameworks that enough of our developers had used before and knew they didn’t meet our requirements, so we decided not to spend time evaluating them further.&lt;/p&gt;

&lt;h4&gt;Our Analysis&lt;/h4&gt;

&lt;p&gt;We performed this analysis May 2010. In the past 6 months both Symfony2 and Lithium which are under rapid development would score even better. It’s not my intention to keep this chart up to date as it’s a representation of historical analysis.&lt;/p&gt;

&lt;img src="http://media.tumblr.com/tumblr_lvr1wgpPab1r1m70c.png"/&gt;&lt;h4&gt;Further Analysis&lt;/h4&gt;

&lt;p&gt;At the end of our week of analysis we had a good overview of each Framework though there wasn’t a clear winner. What was apparent was that a “check” wasn’t equal to another check and some frameworks excelled in certain areas where other’s simply did enough to check the box. This made our analysis quite a bit harder.&lt;/p&gt;

&lt;p&gt;Additionally there were some other factors that weighted heavily into our decision. Strength of community, Quality of development and Momentum are the three factors that played the biggest role in our decision making, but are not represented in this feature set analysis.&lt;/p&gt;

&lt;p&gt;Ultimately we narrowed it down to 3 frameworks. &lt;a href="http://lithify.me/"&gt;Lithium&lt;/a&gt;, &lt;a href="http://symfony-reloaded.org/"&gt;Symfony2&lt;/a&gt; and &lt;a href="http://zoopframework.com/"&gt;Zoop2&lt;/a&gt;. All 3 were PHP 5.2+ and &lt;a href="http://spf13.com/post/next-gen-php-frameworks"&gt;Next Generation Frameworks&lt;/a&gt;. Given the substantial changes accompanying PHP 5.3, we determined that either we went with that now, or had a painful migration in our future. We decided to bite the bullet now which left us to choose between Lithium and Symfony2.&lt;/p&gt;

&lt;h4&gt;Lithium vs Symfony2&lt;/h4&gt;

&lt;p&gt;This wasn’t an easy decision. Both are excellent frameworks developed by really smart people. &lt;a href="http://twitter.com/nateabele"&gt;Nate Abele&lt;/a&gt;, who started the Lithium project and was the lead developer of CakePHP, is’s a personal friend and an NYC local. He was the person who turned me, and consequently OpenSky, on to MongoDB. Nate is doing innovative things with Lithium and has a true passion for what his work.&lt;/p&gt;

&lt;p&gt;Symfony2 is developed by &lt;a href="http://www.sensiolabs.com/en"&gt;Sensio Labs&lt;/a&gt; located primarily in France, on the other side of the world. At the time there were only 3 stateside Symfony team members. Symfony2 uses a bit more conservative approach to framework development, basing it largely on learnings from symfony 1 and established practices and patterns largely from the Java world.&lt;/p&gt;

&lt;p&gt;Ultimately we went with Symfony2. It wasn’t a cut and dry decision and in spite of all our diligence still ended up as a bit of a gut call. Symfony boasted a larger developer base and community. This was probably the factor that ultimately pushed us in Symfony2′s direction.&lt;/p&gt;

&lt;h4&gt;Why Symfony2&lt;/h4&gt;

&lt;p&gt;Fast forward 9 months. OpenSky has embraced Symfony2 with open arms. We have become the 2nd largest contributors to Symfony2 behind Sensio Labs. We employ &lt;a href="http://twitter.com/kriswallsmith"&gt;Kris Wallsmith&lt;/a&gt; and &lt;a href="http://twitter.com/jwage"&gt;Jon Wage&lt;/a&gt;, two core Symfony2 team members. We’ve developed one of the first production applications using Symfony2 and the first ecommerce platform on MongoDB.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://spf13.com/post/symfony2"&gt;More on why you should use Symfony2.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;by &lt;strong&gt;Steve Francia&lt;/strong&gt;&lt;/p&gt;</description><link>http://engineering.opensky.com/post/13793086171</link><guid>http://engineering.opensky.com/post/13793086171</guid><pubDate>Thu, 03 Feb 2011 11:00:00 -0500</pubDate><category>open-source</category><category>PHP</category><category>symfony</category></item><item><title>Inheritance in PHP, or why you want to use an Interface or an Abstract class…</title><description>&lt;p&gt;Every class has an interface, every class can be typehinted as a method argument, typehint lets you specify the collaborator requirements. Not every typehint is the same… Example:&lt;/p&gt;

&lt;!-- HTML generated using hilite.me --&gt;&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;&lt;pre style="margin: 0; line-height: 125%"&gt;&lt;span style="color: #8f5902; font-style: italic"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span style="color: #204a87; font-weight: bold"&gt;class&lt;/span&gt; &lt;span style="color: #000000"&gt;PaymentGateway&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold"&gt;{&lt;/span&gt;
    &lt;span style="color: #204a87; font-weight: bold"&gt;public&lt;/span&gt; &lt;span style="color: #204a87; font-weight: bold"&gt;function&lt;/span&gt; &lt;span style="color: #000000"&gt;charge&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000000"&gt;$amount&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #000000"&gt;BankAccount&lt;/span&gt; &lt;span style="color: #000000"&gt;$account&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;)&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold"&gt;{&lt;/span&gt;
        &lt;span style="color: #8f5902; font-style: italic"&gt;// make a call to http web service here...&lt;/span&gt;
        &lt;span style="color: #000000"&gt;$account&lt;/span&gt;&lt;span style="color: #ce5c00; font-weight: bold"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color: #c4a000"&gt;credit&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000000"&gt;$amount&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;)&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold"&gt;}&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;!-- HTML generated using hilite.me --&gt;&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;&lt;pre style="margin: 0; line-height: 125%"&gt;&lt;span style="color: #8f5902; font-style: italic"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span style="color: #204a87; font-weight: bold"&gt;class&lt;/span&gt; &lt;span style="color: #000000"&gt;BankAccount&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold"&gt;{&lt;/span&gt;
    &lt;span style="color: #204a87; font-weight: bold"&gt;public&lt;/span&gt; &lt;span style="color: #204a87; font-weight: bold"&gt;function&lt;/span&gt; &lt;span style="color: #000000"&gt;debit&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000000"&gt;$amount&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;)&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold"&gt;{&lt;/span&gt;
        &lt;span style="color: #8f5902; font-style: italic"&gt;//...&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold"&gt;}&lt;/span&gt;
    &lt;span style="color: #204a87; font-weight: bold"&gt;public&lt;/span&gt; &lt;span style="color: #204a87; font-weight: bold"&gt;function&lt;/span&gt; &lt;span style="color: #000000"&gt;credit&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000000"&gt;$amount&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;)&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold"&gt;{&lt;/span&gt;
        &lt;span style="color: #8f5902; font-style: italic"&gt;//...&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold"&gt;}&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;




&lt;p&gt;The example above is fairly straightforward – we have a PaymentGateway class that requires a BankAccount collaborator for crediting amount to be charged in its charge function. Since we call credit() on the second argument – we typehint it to be of type BankAccount, which would prevent us from passing anything other than instances of that class. Let’s add some more requirements to our little example. Say we have checking and savings accounts, and we need to be able to charge both of them:&lt;/p&gt;

&lt;!-- HTML generated using hilite.me --&gt;&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;&lt;pre style="margin: 0; line-height: 125%"&gt;&lt;span style="color: #8f5902; font-style: italic"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span style="color: #204a87; font-weight: bold"&gt;class&lt;/span&gt; &lt;span style="color: #000000"&gt;CheckingAccount&lt;/span&gt; &lt;span style="color: #204a87; font-weight: bold"&gt;extends&lt;/span&gt; &lt;span style="color: #000000"&gt;BankAccount&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold"&gt;{&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold"&gt;}&lt;/span&gt;

&lt;span style="color: #204a87; font-weight: bold"&gt;class&lt;/span&gt; &lt;span style="color: #000000"&gt;SavingAccount&lt;/span&gt; &lt;span style="color: #204a87; font-weight: bold"&gt;extends&lt;/span&gt; &lt;span style="color: #000000"&gt;BankAccount&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold"&gt;{&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Since both accounts are subclasses of BankAccount – the typehint still works fine. However, we have now opened the possibility for abusing the typehint… In case you didn’t know – classes in PHP don’t define a strict interface, and are open to change by subclasses:&lt;/p&gt;

&lt;!-- HTML generated using hilite.me --&gt;&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;&lt;pre style="margin: 0; line-height: 125%"&gt;&lt;span style="color: #8f5902; font-style: italic"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span style="color: #204a87; font-weight: bold"&gt;class&lt;/span&gt; &lt;span style="color: #000000"&gt;SomeAccount&lt;/span&gt; &lt;span style="color: #204a87; font-weight: bold"&gt;extends&lt;/span&gt; &lt;span style="color: #000000"&gt;BankAccount&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold"&gt;{&lt;/span&gt;
    &lt;span style="color: #204a87; font-weight: bold"&gt;public&lt;/span&gt; &lt;span style="color: #204a87; font-weight: bold"&gt;function&lt;/span&gt; &lt;span style="color: #000000"&gt;credit&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000000"&gt;$amount&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #000000"&gt;$someOtherParameter&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;)&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold"&gt;{&lt;/span&gt;
        &lt;span style="color: #8f5902; font-style: italic"&gt;//...&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold"&gt;}&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;NOTE: if you have strict errors enabled, you would get one…&lt;/p&gt;

&lt;p&gt;In the above example we changed the credit method signature by adding a second required parameter. We can now pass instances of SomeAccount class everywhere the BankAccount is expected and get nice fatal errors. Only interfaces and abstract classes/methods lock method signatures.&lt;/p&gt;

&lt;!-- HTML generated using hilite.me --&gt;&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;&lt;pre style="margin: 0; line-height: 125%"&gt;&lt;span style="color: #8f5902; font-style: italic"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span style="color: #204a87; font-weight: bold"&gt;interface&lt;/span&gt; &lt;span style="color: #000000"&gt;BankAccountInterface&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold"&gt;{&lt;/span&gt;
    &lt;span style="color: #204a87; font-weight: bold"&gt;function&lt;/span&gt; &lt;span style="color: #000000"&gt;credit&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000000"&gt;$amount&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;);&lt;/span&gt;
    &lt;span style="color: #204a87; font-weight: bold"&gt;function&lt;/span&gt; &lt;span style="color: #000000"&gt;debit&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000000"&gt;$amount&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;);&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold"&gt;}&lt;/span&gt;

&lt;span style="color: #204a87; font-weight: bold"&gt;class&lt;/span&gt; &lt;span style="color: #000000"&gt;BankAccount&lt;/span&gt; &lt;span style="color: #204a87; font-weight: bold"&gt;implements&lt;/span&gt; &lt;span style="color: #000000"&gt;BankAccountInterface&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold"&gt;{&lt;/span&gt;
    &lt;span style="color: #8f5902; font-style: italic"&gt;//...&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;For our particular example, we could use an abstract class:&lt;/p&gt;

&lt;!-- HTML generated using hilite.me --&gt;&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;&lt;pre style="margin: 0; line-height: 125%"&gt;&lt;span style="color: #8f5902; font-style: italic"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span style="color: #204a87; font-weight: bold"&gt;abstract&lt;/span&gt; &lt;span style="color: #204a87; font-weight: bold"&gt;class&lt;/span&gt; &lt;span style="color: #000000"&gt;BankAccount&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold"&gt;{&lt;/span&gt;
    &lt;span style="color: #204a87; font-weight: bold"&gt;abstract&lt;/span&gt; &lt;span style="color: #204a87; font-weight: bold"&gt;public&lt;/span&gt; &lt;span style="color: #204a87; font-weight: bold"&gt;function&lt;/span&gt; &lt;span style="color: #000000"&gt;debit&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000000"&gt;$amount&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;);&lt;/span&gt;
    &lt;span style="color: #204a87; font-weight: bold"&gt;abstract&lt;/span&gt; &lt;span style="color: #204a87; font-weight: bold"&gt;public&lt;/span&gt; &lt;span style="color: #204a87; font-weight: bold"&gt;function&lt;/span&gt; &lt;span style="color: #000000"&gt;credit&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000000"&gt;$amount&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;);&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Please note that in the example interface, I don’t specify method visibility. The reason is every method of the interface MUST be public and no explicit visibility means public in PHP.&lt;/p&gt;

&lt;!-- HTML generated using hilite.me --&gt;&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;&lt;pre style="margin: 0; line-height: 125%"&gt;&lt;span style="color: #8f5902; font-style: italic"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span style="color: #204a87; font-weight: bold"&gt;class&lt;/span&gt; &lt;span style="color: #000000"&gt;SomeAccount&lt;/span&gt; &lt;span style="color: #204a87; font-weight: bold"&gt;extends&lt;/span&gt; &lt;span style="color: #000000"&gt;BankAccount&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold"&gt;{&lt;/span&gt;
    &lt;span style="color: #204a87; font-weight: bold"&gt;public&lt;/span&gt; &lt;span style="color: #204a87; font-weight: bold"&gt;function&lt;/span&gt; &lt;span style="color: #000000"&gt;credit&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;(&lt;/span&gt;&lt;span style="color: #000000"&gt;$amount&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;,&lt;/span&gt; &lt;span style="color: #000000"&gt;$someOtherParameter&lt;/span&gt;&lt;span style="color: #000000; font-weight: bold"&gt;)&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold"&gt;{&lt;/span&gt;
        &lt;span style="color: #8f5902; font-style: italic"&gt;//...&lt;/span&gt;
    &lt;span style="color: #000000; font-weight: bold"&gt;}&lt;/span&gt;
&lt;span style="color: #000000; font-weight: bold"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A class like the one above would cause a fatal error to be thrown: “Declaration of SomeAccount::credit() must be compatible with that of BankAccountInterface::credit()” or “Declaration of SomeAccount::credit() must be compatible with that of BankAccount::credit()”, depending on which approach you chose to use. If someone wanted to implement a BankAccount to be used with our PaymentGateway, they would have to keep the method signatures exactly the same as we defined them.&lt;/p&gt;

&lt;p&gt;Happy Coding!&lt;/p&gt;</description><link>http://engineering.opensky.com/post/11732773605</link><guid>http://engineering.opensky.com/post/11732773605</guid><pubDate>Tue, 30 Nov 2010 10:38:00 -0500</pubDate></item><item><title>ZendCon 2010 in Santa Clara, California</title><description>&lt;p&gt;Hi everyone, in case you didn’t know – there was a ZendCon last Monday November 1st through Friday November 5th, 2010 in Santa Clara, California and most importantly – I got to attend and OpenSky sponsored my trip.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://zendcon.com/"&gt;ZendCon&lt;/a&gt; is an annual conference organized by &lt;a href="http://www.zend.com/"&gt;Zend the PHP company&lt;/a&gt; and held in California. Its known to be one of the biggest conferences in PHP world with attendees from all over the world varying from developers to top management, all using and interested in PHP. Zend makes PHP announcements – this year among other things, they announced that memory footprint of PHP had been reduced by 35% in the upcoming version – which are then followed up by different session from speakers from all over the world. These sessions vary in scope and context from detailed practical “how to”s of a framework or tool, to high level management advices and experiences.&lt;/p&gt;

&lt;p&gt;As I already mentioned, this year I was thrilled to be among ZendCon attendees!&lt;/p&gt;

&lt;p&gt;I arrived in Santa Clara on the evening of November 1st. This was my very first visit to west coast and I loved it. The first thing I saw when arrived at Santa Clara (after a 6 hour flight and a 2 hour ride on three trains – one of which had two levels) was a big Yahoo sign on one of the buildings which immediately felt like technology heaven.&lt;/p&gt;

&lt;p&gt;During the next three days, I met interesting people from all over the world, including people I knew from twitter, but never met in person. I would like to especially thank Ryan Weaver and Pablo Godel, who are seasoned conference attendees, for making a great company and helping me get accustomed to the environment and people at the conference. I also met and spent a decent amount of time with people as: Jonathan Wage, Fabien Potencier, Nils Aderman, Dustin Whitle, Michelangelo van Dam, Jeremy Kendall and many many others.&lt;/p&gt;

&lt;p&gt;I learned about Zend Uncon from Michelangelo during continental breakfast of the very first day of the main conference. Turns out that anyone could give a talk, even if it wasn’t included into the main session program. This is called the Uncon and there you can give a talk, do an interactive tutorial or round table on any topic you choose, all you need is to put your name in an empty slot in the Uncon schedule. Uncon sounded like a great idea and a good public speaking practice, so I registered… The session was amazing! Twitter was blown by quotations from my talk - tweeted, retweeted and re-retweeted. Attendees took pictures of me speaking and posted it on twitter too. Overall I was blown away by the success of my little experiment. As a result, my session was called the best Uncon session and I won a free lifetime license for Zend Studio 8 (they even wanted to call me up on stage during the final keynote, but I had a plane to catch that day).&lt;/p&gt;

&lt;p&gt;Jonathan Wage, who joined OpenSky on the November 1st, 2010, suffered from poor organization on the conference part. He was unfortunate to get scheduled to arrive after his first session and leave before the second one. As a result, he gave only one talk of the two planned as part of the Uncon. His talk was, however, really amazing and well received by attendees and they wouldn’t let him go for a good 30 minutes after the talk was over, asking questions and expressing admiration.&lt;/p&gt;

&lt;p&gt;Thank you ZendCon and see you again next year! Below are some pictures I took at the conference:&lt;/p&gt;

&lt;div class="flexslider"&gt;
  &lt;ul class="slides" style="list-style:none;padding:0;"&gt;&lt;li&gt;
&lt;img src="http://media.tumblr.com/tumblr_lvr1ekPRvt1r1m70c.jpg"/&gt;&lt;/li&gt;
&lt;li&gt;
&lt;img src="http://media.tumblr.com/tumblr_lvr1ewIx7c1r1m70c.jpg"/&gt;&lt;/li&gt;
&lt;li&gt;
&lt;img src="http://media.tumblr.com/tumblr_lvr1f71guY1r1m70c.jpg"/&gt;&lt;/li&gt;
&lt;li&gt;
&lt;img src="http://media.tumblr.com/tumblr_lvr1fjRXve1r1m70c.jpg"/&gt;&lt;/li&gt;
&lt;li&gt;
&lt;img src="http://media.tumblr.com/tumblr_lvr1fx8lZn1r1m70c.jpg"/&gt;&lt;/li&gt;
&lt;li&gt;
&lt;img src="http://media.tumblr.com/tumblr_lvr1gaFUFv1r1m70c.jpg"/&gt;&lt;/li&gt;
&lt;li&gt;
&lt;img src="http://media.tumblr.com/tumblr_lvr1gsnexS1r1m70c.jpg"/&gt;&lt;/li&gt;
&lt;li&gt;
&lt;img src="http://media.tumblr.com/tumblr_lvr1h5dGCH1r1m70c.jpg"/&gt;&lt;/li&gt;
&lt;li&gt;
&lt;img src="http://media.tumblr.com/tumblr_lvr1hkUlye1r1m70c.jpg"/&gt;&lt;/li&gt;
&lt;li&gt;
&lt;img src="http://media.tumblr.com/tumblr_lvr1hzVsRd1r1m70c.jpg"/&gt;&lt;/li&gt;
&lt;li&gt;
&lt;img src="http://media.tumblr.com/tumblr_lvr1ic9JRe1r1m70c.jpg"/&gt;&lt;/li&gt;
&lt;li&gt;
&lt;img src="http://media.tumblr.com/tumblr_lvr1iuq7xp1r1m70c.jpg"/&gt;&lt;/li&gt;
&lt;li&gt;
&lt;img src="http://media.tumblr.com/tumblr_lvr1j7jXfa1r1m70c.jpg"/&gt;&lt;/li&gt;
&lt;li&gt;
&lt;img src="http://media.tumblr.com/tumblr_lvr1jmzGR01r1m70c.jpg"/&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;by &lt;strong&gt;avalanche123&lt;/strong&gt;&lt;/p&gt; &lt;/div&gt;</description><link>http://engineering.opensky.com/post/13791667426</link><guid>http://engineering.opensky.com/post/13791667426</guid><pubDate>Mon, 08 Nov 2010 16:12:00 -0500</pubDate><category>conference</category><category>open-source</category></item><item><title>Unit Tests, Mocking, and PHPUnit 3.5′s new Mock Builder</title><description>&lt;p&gt;Unit testing is all about testing one piece of functionality in isolation. This is very easy when the subject of your test doesn’t involve any dependencies. Take the following method:&lt;/p&gt;

&lt;p&gt;&lt;script src="http://gist.github.com/%20&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&gt;&lt;/script&gt;&lt;/p&gt;</description><link>http://engineering.opensky.com/post/13791016515</link><guid>http://engineering.opensky.com/post/13791016515</guid><pubDate>Fri, 29 Oct 2010 16:00:00 -0400</pubDate><category>testing</category></item><item><title>Unit Tests, Mocking, and PHPUnit 3.5′s new Mock Builder</title><description>&lt;p&gt;Unit testing is all about testing one piece of functionality in isolation. This is very easy when the subject of your test doesn&amp;#8217;t involve any dependencies. Take the following method:&lt;/p&gt;

&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;
&lt;pre style="margin: 0; line-height: 125%"&gt;
	&amp;lt;?php

	class Tag
	{
	    public function normalizeName($name)
	    {
	        $normal = trim($name);
	        $normal = strtolower($normal);

	        return $normal;
	    }
	}
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Testing this method requires just an input and an expected output. This is a good case for using a PHPUnit dataProvider:&lt;/p&gt;

&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;
&lt;pre style="margin: 0; line-height: 125%"&gt;
	&amp;lt;?php

	class TagTest extends PHPUnit_Framework_TestCase
	{
	    /**
	* @covers Tag::normalizeName
	* @dataProvider provideNormalizeName
	*/
	    public function testNormalizeName($input, $expected)
	    {
	        $tag = new Tag();
	        $this-&amp;gt;assertEquals($expected, $tag-&amp;gt;normalizeName($input));
	    }

	    public function provideNormalizeName()
	    {
	        return array(
	            array('foo', 'foo'),
	            array('FOO', 'foo'),
	            array(' foo ', 'foo'),
	            array(' FOO ', 'foo'),
	        );
	    }
	}
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Unfortunately, it’s not always this easy. Let’s say we want to centralize this normalization logic in some sort of reusable Normalizer class, which we inject into the Tag class:&lt;/p&gt;

&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;
&lt;pre style="margin: 0; line-height: 125%"&gt;
	&amp;lt;?php

	class Tag
	{
	    protected $normalizer;

	    public function __construct(Normalizer $normalizer)
	    {
	        $this-&amp;gt;normalizer = $normalizer;
	    }

	    public function normalizeName($name)
	    {
	        return $this-&amp;gt;normalizer-&amp;gt;normalize($name);
	    }
	}
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The test above still passes, but we are now testing two things: the normalizeTag method and the Normalizer class; we are no longer testing our method in isolation.&lt;/p&gt;

&lt;h4&gt;Mock objects to the rescue!&lt;/h4&gt;

&lt;p&gt;To restore this isolation we create a “mock” version of the Normalizer class and tell that mock exactly what we expect will be done to it and how we want it to respond.&lt;/p&gt;

&lt;p&gt;In PHPUnit 3.4, creating this mock object would look something like this:&lt;/p&gt;

&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;
&lt;pre style="margin: 0; line-height: 125%"&gt;
	&amp;lt;?php

	class TagTest extends PHPUnit_Framework_TestCase
	{
	    /**
	* @covers Tag::normalizeName
	*/
	    public function testNormalizeName()
	    {
	        $input = 'foo';
	        $expected = 'foo';

	        // the final "false" tells PHPUnit not to call the Normalizer
	        // constructor because it requires another dependency, which we don't
	        // care about right now
	        $normalizer = $this-&amp;gt;getMock('Normalizer', array(), array(), '', false);
	        $normalizer
	            -&amp;gt;expects($this-&amp;gt;once())
	            -&amp;gt;method('normalize')
	            -&amp;gt;with($input)
	            -&amp;gt;will($this-&amp;gt;returnValue($expected));

	        $tag = new Tag($normalizer);
	        $this-&amp;gt;assertEquals($expected, $tag-&amp;gt;normalizeName($input));
	    }
	}

	
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Most of this is quite readable, thanks to Sebastian&amp;#8217;s nice mocking API. However, the initial getMock method is a bit gnarly. I&amp;#8217;ve added a comment so you understand what&amp;#8217;s going on, which I&amp;#8217;d rather not have to do.&lt;/p&gt;

&lt;p&gt;In PHPUnit 3.5 we can use the new mock builder object, a contribution of &lt;a onclick="javascript:pageTracker._trackPageview('/outgoing/giorgiosironi.blogspot.com/');" href="http://giorgiosironi.blogspot.com/" target="_blank"&gt;Giorgio Sironi&lt;/a&gt;, which makes our test code that much more readable:&lt;/p&gt;

&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;
&lt;pre style="margin: 0; line-height: 125%"&gt;
	&amp;lt;?php

	class TagTest extends PHPUnit_Framework_TestCase
	{
	    /**
	* @covers Tag::normalizeName
	*/
	    public function testNormalizeName()
	    {
	        $input = 'foo';
	        $expected = 'foo';

	        $normalizer = $this-&amp;gt;getMockBuilder('Normalizer')
	            -&amp;gt;disableOriginalConstructor()
	            -&amp;gt;getMock();
	        $normalizer
	            -&amp;gt;expects($this-&amp;gt;once())
	            -&amp;gt;method('normalize')
	            -&amp;gt;with($input)
	            -&amp;gt;will($this-&amp;gt;returnValue($expected));

	        $tag = new Tag($normalizer);
	        $this-&amp;gt;assertEquals($expected, $tag-&amp;gt;normalizeName($input));
	    }
	}

	
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;So there you go: unit tests, mocking, and the new mock builder.&lt;/p&gt;

&lt;p&gt;by &lt;strong&gt;Kris Wallsmith&lt;/strong&gt;&lt;/p&gt;</description><link>http://engineering.opensky.com/post/13791190097</link><guid>http://engineering.opensky.com/post/13791190097</guid><pubDate>Fri, 29 Oct 2010 16:00:00 -0400</pubDate><category>testing</category></item><item><title>Symfony NYC Meetup: Unit Testing</title><description>&lt;p&gt;People that RSVPed for the last Symfony NYC Meetup know, that it got canceled. We are very sorry, but the meetup speaker got sick and couldn’t make it. He did promise to give his talk on ESI caching as soon as he feels better.&lt;/p&gt;

&lt;p&gt;Meanwhile, the meetup was moved to this coming Thursday, October 28th, 2010. The new topic is “Unit Testing. A guide to writing clean, testable code, that will be easy to maintain and extend”. This will be the &lt;a href="http://engineering.shopopensky.com/post/clean-code-talk"&gt;repeat of the talk I gave to the OpenSky tech team&lt;/a&gt; a month ago. I will cover topics like unit-testing, dependency injection, mock objects and ways to refactor your code.&lt;/p&gt;

&lt;p&gt;If you haven’t yet, please RSVP for &lt;a href="http://www.meetup.com/Symfony-NYC/calendar/14509323/"&gt;the meetup&lt;/a&gt; and more importantly, come to hear me speak on the topic.&lt;/p&gt;

&lt;p&gt;Edit: I uploaded the slides from that talk to SlideShare and embedded them below&lt;/p&gt;

&lt;div style="width:425px" id="__ss_5609451"&gt; &lt;strong style="display:block;margin:12px 0 4px"&gt;&lt;a href="http://www.slideshare.net/avalanche123/clean-code-5609451" title="Clean code" target="_blank"&gt;Clean code&lt;/a&gt;&lt;/strong&gt; &lt;iframe src="http://www.slideshare.net/slideshow/embed_code/5609451" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"&gt;&lt;/iframe&gt; &lt;div style="padding:5px 0 12px"&gt; View more &lt;a href="http://www.slideshare.net/" target="_blank"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/avalanche123" target="_blank"&gt;Bulat Shakirzyanov&lt;/a&gt; &lt;/div&gt; &lt;/div&gt;

&lt;p&gt;Edit 2: We video-taped the full talk, which you can watch by clicking on the link below&lt;/p&gt;

&lt;a href="http://picasaweb.google.com/lh/photo/X1kAU37p8orM4orLdXamJhwa0gWwVAxekJEdyMCDZek?feat=embedwebsite"&gt;&lt;img src="http://media.tumblr.com/tumblr_lvr0kixwQq1r1m70c.jpg"/&gt;&lt;/a&gt;

&lt;p&gt;by &lt;strong&gt;avalanche123&lt;/strong&gt;&lt;/p&gt;</description><link>http://engineering.opensky.com/post/13790799521</link><guid>http://engineering.opensky.com/post/13790799521</guid><pubDate>Tue, 26 Oct 2010 09:00:00 -0400</pubDate><category>best-practices</category><category>dependency-injection</category><category>meetup</category><category>symfony</category><category>TDD</category><category>testing</category></item><item><title>Clean code talk on Friday</title><description>&lt;p&gt;At OpenSky, we concentrate on programmers’ skills and ways to improve them a lot. As part of that, we have Fridays dedicated to skill improvement – we, programmers, are allowed to write blog posts, prepare presentations¸ educate others on what we learned, refactor/improve our code or simply go through and add tests where they are missing.&lt;/p&gt;

&lt;p&gt;Last Friday was very special. I finally took the time (the whole weekend before that)  and put together some slides to give a long requested talk on unit-testing and the art of programming.&lt;/p&gt;

&lt;p&gt;I wanted to cover as many aspects of testing and OOP in general as I possibly could, while preserving the structure of test-oriented talk, without concentrating too much on any single area.&lt;/p&gt;

&lt;p&gt;I had no idea how to accomplish that when I started. However, the introduction section had given me a good understanding of how to relate all the different aspects, so it didn’t feel like I was jumping from topic to topic, not covering each in enough detail. I structured the talk around the properties of unit test – the properties we want to achieve in order to practice unit-testing. As a result of that, I was able to cover Dependency Injection (with the Law Of Demeter as a natural consequence), Mock Objects (leading me to Iterative Interface Discovery and Test Driven Development) and some general OOP techniques, that let programmers achieve much desired code clarity (Inheritance instead of Conditionals and Composition over Inheritance).&lt;/p&gt;

&lt;p&gt;Ideas promoted in the talk were inspired by a number of different sources, and I feel I should list the references, since they were not included in the slides:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;All definitions were taken from &lt;a href="http://wikipedia.org"&gt;Wikipedia.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.youtube.com/watch?v=wEhu57pih5w"&gt;The Clean Code Talks — Unit Testing&lt;/a&gt; by Misko Hevery (Google Inc.)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://static.mockobjects.com/files/mockrolesnotobjects.pdf"&gt;Mock Roles, Not Objects&lt;/a&gt; by Steve Freeman, Tim Mackinnon, Nat Pryce, Joe Walnes (ThoughtWorks UK)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.youtube.com/watch?v=4F72VULWFvc"&gt;The Clean Code Talks — Inheritance, Polymorphism, &amp;amp; Testing&lt;/a&gt; by Misko Hevery (Google Inc.)&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;The talk turned out to be pretty good and I received a lot of positive feedback on it from outside after posting it on &lt;a href="http://www.slideshare.net/avalanche123/clean-code-5281847"&gt;slideshare&lt;/a&gt;. Even though I reserved 90 minutes to cover everything and answer all the questions, I was not able to do so, since we started later than planned. Therefore, I’m sharing the talk here and if anyone has questions or comments after watching the slides, feel free to post them here.&lt;/p&gt;

&lt;p&gt;by &lt;strong&gt;avalanche123&lt;/strong&gt;&lt;/p&gt;</description><link>http://engineering.opensky.com/post/13790287327</link><guid>http://engineering.opensky.com/post/13790287327</guid><pubDate>Wed, 29 Sep 2010 10:00:00 -0400</pubDate><category>general</category><category>symfony</category><category>TDD</category><category>UNIX</category><category>testing</category></item><item><title>Symfony NYC Meetup</title><description>&lt;p&gt;Some of you might, others might not know that our company, OpenSky, became the official sponsor of Symfony NYC Meetups, which means, that we’ll be seeing you the last Thursday of every month, here, at OpenSky HQ in NYC for the foreseeable future.&lt;/p&gt;

&lt;p&gt;That was enough of the introduction, now to the point. Last Thursday, September 23rd, 2010, OpenSky held its first Symfony NYC Meetup. And, as anything OpenSky does, the Meetup turned out amazing. Our very own Kris Wallsmith gave an awesome talk, highlighting the differences between symfony 1.x and Symfony2. This was particularly useful, since my co-workers are the only people I know in NYC using Symfony2, and the majority of Meetup attendees are still in symfony 1.x world and hesitate to switch.&lt;/p&gt;

&lt;p&gt;During the second, less structured part of the Meetup, we were enjoying pizza, that OpenSky kindly provided, discussing Symfony2 feature roadmap, current limitations of certain components and proceeded to other interesting, but hardly Symfony2 related topics like NodeJS, Android OS, Document-Oriented Databases (CouchDB and MongoDB) and PHP 5.3 Object Document Mappers (Doctrine MongoDB ODM and Doctrine CouchDB ODM).&lt;/p&gt;

&lt;p&gt;In general it was a very interesting event and I feel sorry for those who couldn’t attend.&lt;/p&gt;

&lt;p&gt;Since this is definitely not the last Meetup OpenSky is hosting, make sure to come in next time, to meet fellow symfony developers, share ideas and get to know OpenSky.&lt;/p&gt;

&lt;img src="http://media.tumblr.com/tumblr_lvqzhha7dI1r1m70c.jpg"/&gt;&lt;img src="http://media.tumblr.com/tumblr_lvqzht8SpU1r1m70c.jpg"/&gt;&lt;img src="http://media.tumblr.com/tumblr_lvqzi0KDD81r1m70c.jpg"/&gt;&lt;img src="http://media.tumblr.com/tumblr_lvqzi7U8EU1r1m70c.jpg"/&gt;&lt;img src="http://media.tumblr.com/tumblr_lvqzidlP601r1m70c.jpg"/&gt;&lt;img src="http://media.tumblr.com/tumblr_lvqzillTkv1r1m70c.jpg"/&gt;&lt;img src="http://media.tumblr.com/tumblr_lvqzirxiTJ1r1m70c.jpg"/&gt;&lt;img src="http://media.tumblr.com/tumblr_lvqziw9KPY1r1m70c.jpg"/&gt;&lt;img src="http://media.tumblr.com/tumblr_lvqzj2WlIm1r1m70c.jpg"/&gt;&lt;p&gt;As a bonus, here is Kris’s video, where he talks about Symfony2.&lt;/p&gt;

&lt;iframe width="500" height="284" src="http://www.youtube.com/embed/6lzv6FPtFj0" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;by &lt;strong&gt;avalanche123&lt;/strong&gt;&lt;/p&gt;</description><link>http://engineering.opensky.com/post/13789926062</link><guid>http://engineering.opensky.com/post/13789926062</guid><pubDate>Tue, 28 Sep 2010 15:33:00 -0400</pubDate><category>general</category><category>symfony</category><category>TDD</category><category>testing</category><category>UNIX</category></item><item><title>Symfony2 PR 3 released</title><description>&lt;p&gt;The core symfony 2 team has just released Symfony 2 Preview Release 3. Of the 50+ different contributors, OpenSky provided 5 of them. Our developers contributed meaningful code commits which the core team approved and integrated with the release. We are excited to be a part of this thriving community and to be able to both use and contribute to such an excellent framework.&lt;/p&gt;

&lt;p&gt;Here is a list of our team members and their commit counts towards this release:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;39 Kris Wallsmith&lt;/li&gt;
    &lt;li&gt;16 Jeremy Mikola&lt;/li&gt;
    &lt;li&gt;6 Bulat Shakirzyanov (avalanche123)&lt;/li&gt;
    &lt;li&gt;2 Justin Hileman&lt;/li&gt;
    &lt;li&gt;1 Matt Fitzgerald (tiranog06)&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;a href="http://www.symfony-project.org/blog/2010/09/13/symfony2-pr3-released-the-need-for-help"&gt;&lt;a href="http://www.symfony-project.org/blog/2010/09/13/symfony2-pr3-released-the-need-for-help"&gt;http://www.symfony-project.org/blog/2010/09/13/symfony2-pr3-released-the-need-for-help&lt;/a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;by &lt;strong&gt;Steve Francia&lt;/strong&gt;&lt;/p&gt;</description><link>http://engineering.opensky.com/post/13789475785</link><guid>http://engineering.opensky.com/post/13789475785</guid><pubDate>Mon, 27 Sep 2010 10:00:00 -0400</pubDate><category>open-source</category><category>symfony</category></item><item><title>I Sell Tons of Products with the Term “beauty” in them. Why don’t I show up in the Search tab for Sellers?&#13;
</title><description>&lt;p&gt;This article was written by &lt;strong&gt;Matthew Fitzgerald&lt;/strong&gt;, Software Engineer, and &lt;strong&gt;Mike Zupan&lt;/strong&gt;, Systems Engineer at OpenSky&lt;/p&gt;

&lt;h4&gt;The fix will go live next week (Sept 29)&lt;/h4&gt;

&lt;p&gt;One of the most important ways Shoppers find Sellers is through Search. Recently, we’ve found a hole in our search index. The problem we had was, Sellers would select Products with keywords like “beauty” in the Product Name but that Seller would not show up in the Search results for “beauty”.&lt;/p&gt;

&lt;p&gt;The reason for this was our Seller search index only had direct information on the Seller, ie: Seller Username, Business Name, Bio, etc… The Seller index had no knowledge of Products the Seller was promoting. So any keywords the Product might have, wouldn’t return the seller in a search.&lt;/p&gt;

&lt;h4&gt;The Solution&lt;/h4&gt;

&lt;p&gt;We needed to modify our Seller index to have knowledge of both Products and Sellers and return the results of distinct sellers. The problem, our current Search technology (SOLR) didn’t support that behavior of Grouping Product Records by Seller and collapsing them into distinct Seller results.&lt;/p&gt;

&lt;h4&gt;The Tech Part&lt;/h4&gt;

&lt;p&gt;After some hefty Googling, I found that the feature to Group Search results does exist in a future version of the technology yet to be released. This feature became so popular that the developers of our Search technology released a “patch” to include this feature in the current version of the software. This is how I applied the patch.&lt;/p&gt;

&lt;h5&gt;Step 1&lt;/h5&gt;
&lt;p&gt;If you are like me, you hate Subversion and you love GIT. I run Ubuntu and using apt-get I installed a git subversion bridge.&lt;/p&gt;

&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;
&lt;pre style="margin: 0; line-height: 125%"&gt;
sudo apt-get install git-svn
&lt;/pre&gt;
&lt;/div&gt;

&lt;h5&gt;Step 2&lt;/h5&gt;
&lt;p&gt;Get some reading material, then start the checkout the latest stable tag of Solr&lt;/p&gt;

&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;
&lt;pre style="margin: 0; line-height: 125%"&gt;
git-svn clone &lt;a href="http://svn.apache.org/repos/asf/lucene/solr/tags/release-1.4.1"&gt;http://svn.apache.org/repos/asf/lucene/solr/tags/release-1.4.1&lt;/a&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;h5&gt;Step 3&lt;/h5&gt;
&lt;p&gt;Download and apply the patch&lt;/p&gt;

&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;
&lt;pre style="margin: 0; line-height: 125%"&gt;
cd release-1.4.1
wget &lt;a href="https://issues.apache.org/jira/secure/attachment/12448216/SOLR-236-1_4_1.patch"&gt;https://issues.apache.org/jira/secure/attachment/12448216/SOLR-236-1_4_1.patch&lt;/a&gt;
patch -p 0 -i SOLR-236-1_4_1.patch
&lt;/pre&gt;
&lt;/div&gt;

&lt;h5&gt;Step 4&lt;/h5&gt;
&lt;p&gt;Recompile it, Baby!&lt;/p&gt;

&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;
&lt;pre style="margin: 0; line-height: 125%"&gt;
ant compile
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Now you want to build the example project so we can test it&lt;/p&gt;

&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;
&lt;pre style="margin: 0; line-height: 125%"&gt;
ant example
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Now it is time to test. So go into the example project and the example data directory&lt;/p&gt;

&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;
&lt;pre style="margin: 0; line-height: 125%"&gt;
cd example/exampledocs
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Now you can import all the xml data&lt;/p&gt;

&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;
&lt;pre style="margin: 0; line-height: 125%"&gt;
java -jar post.jar *.xml
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Now start the server&lt;/p&gt;

&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;
&lt;pre style="margin: 0; line-height: 125%"&gt;
cd ..
java -jar start.jar
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Now you should be able to hit the following url and get back grouped data&lt;/p&gt;

&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;
&lt;pre style="margin: 0; line-height: 125%"&gt;
http://localhost:8983/solr/select?

  wt=json&amp;amp;indent=true&amp;amp;fl=id,name
  &amp;amp;q=solr+memory
  &amp;amp;group=true&amp;amp;group.field=manu_exact
  &amp;amp;collapse.field=manu_exact
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Are you into PHP? This is how to implement it with the native PECL Driver.&lt;/p&gt;

&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;
&lt;pre style="margin: 0; line-height: 125%"&gt;
$query = new SolrQuery('beauty');
$query-&amp;gt;addParam('group','true');
$query-&amp;gt;addParam('group.field','sellerId');
$query-&amp;gt;addParam('collapse.field','sellerId');
$query-&amp;gt;addParam('rows', 1000);
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;by &lt;strong&gt;Matthew Fitzgerald&lt;/strong&gt;&lt;/p&gt;</description><link>http://engineering.opensky.com/post/13789149181</link><guid>http://engineering.opensky.com/post/13789149181</guid><pubDate>Tue, 21 Sep 2010 10:00:00 -0400</pubDate><category>ANT</category><category>JAVA</category><category>SQLR</category><category>Search</category><category>UNIX</category></item><item><title>Creating a unified search experience</title><description>&lt;p&gt;If you’ve ever used the Internet (how else are you reading this?), then you have used a search engine. Search powers everything from shopping to dating to research, and is so common that people use it without thinking about it… it is just natural.&lt;/p&gt;

&lt;p&gt;Of course, when something is natural, you expect a comfortable experience and a good fit. You probably don’t wake up in the morning and put on someone else’s clothes; instead, you probably have a wardrobe of comfortable apparel that you piece together a look that feels good and feels right.&lt;/p&gt;

&lt;p&gt;We don’t feel this is how our search experience at OpenSky has been. If you wanted to find products, you could get to them pretty well. But if you were a seller trying to find a great supplier to connect with, the experience was… lacking? discombobulated? Not cohesive, at any rate.&lt;/p&gt;

&lt;p&gt;So we decided it was time to roll our own search experience rather than let our community search continue to be powered by [insert ginormous search engine]. Here is how we did it.&lt;/p&gt;

&lt;h4&gt;Search Technology&lt;h4&gt;

&lt;/h4&gt;&lt;/h4&gt;&lt;p&gt;We use &lt;a href="http://lucene.apache.org/solr/"&gt;Apache Solr&lt;/a&gt; to power our custom searches. Solr is a search platform that utilizes the popular Lucene search library as its core, is blazing fast, and is open-source… hey, we like open source projects around here.&lt;/p&gt;

&lt;p&gt;We decided to create a new Solr index for indexing and searching community data, rather than create a unified index for searching all data, the primary reasons being variance in relevant data fields and the ability to apply the unique schema to do more complex, targeted, and nifty search applications that we haven’t thought up yet.&lt;/p&gt;

&lt;p&gt;There are certainly some benefits that can be gained from having a unified index, and we are currently cooking up some things which will make use of both unified and specific indexes, so we can make our search experience as useful and intuitive as possible. Expect more great things coming up as search continues to evolve.&lt;/p&gt;

&lt;h5&gt;Schema Considerations&lt;/h5&gt;

&lt;p&gt;Careful thought and consideration went into how we designed the schema. We are using the &lt;a href="http://wiki.apache.org/solr/DisMaxQParserPlugin"&gt;DisMax Query Parser&lt;/a&gt; for our general search, and one of the things we learned that hard way is that inconsistent field configuration options, such as stopwords or other tokenizer index / query filters, can seriously affect query results. Also, it pays off to tweak some default configuration options to your needs.&lt;/p&gt;

&lt;p&gt;As a concrete example, the DisMax Query Parser defaults to requiring all search terms to be present in a field to generate a positive hit. Assume you have a document with title = “Essence of murtlap”, description = “Essence of murtlap is phenomenal!”
Assume title is a “string” field with no tokenizer filters defined, while description is a “text” field with a stopwords configuration that prevents “of” from being tokenized, as it has high frequency and low importance.&lt;/p&gt;

&lt;p&gt;In this case, a search for “Essence of murtlap” will not return any results. Why? Since “of” was not tokenized in the description field, 100% of the terms do not match, and so the entire document is a negative hit. However, searching for “Essence murtlap” would match. This may seem odd — after all, 100% of the terms DID match in the title field. For a mor thorough explanation, see one of &lt;a href="http://bibwild.wordpress.com/2010/04/14/solr-stop-wordsdismax-gotcha/"&gt;several&lt;/a&gt; &lt;a href="http://www.lucidimagination.com/blog/2010/05/23/whats-a-dismax/"&gt;available&lt;/a&gt; &lt;a href="http://lucene.472066.n3.nabble.com/Dismax-Minimum-Match-Stopwords-Bug-td493483.html"&gt;resources&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I also decided to throw a tokenizer filter to remove leading and trailing punctuation. The inspiration for this was trying to match a word at the end of a sentence. Using the same example above, one would expect to be able to have a positive hit by searching for “phenomenal” — but one would be mistaken. Without some TLC the actual token stored is “phenomenal!” so, unless you include that punctuation in your search, you are going to be disappointed.&lt;/p&gt;

&lt;p&gt;Fortunately, I found a &lt;a href="http://osdir.com/ml/solr-user.lucene.apache.org/2010-09/msg00455.html"&gt;very useful thread&lt;/a&gt; which presented a simple way to solve the problem using regular expression string filtering while indexing the document:&lt;/p&gt;

&lt;div style="background: #f8f8f8; overflow:auto;width:auto;color:black;background:#eee;margin: 2em 0; border: 1px dashed #aaa; border-width: 1px 0; padding: .5em;"&gt;
&lt;pre style="margin: 0; line-height: 125%"&gt;
&amp;lt;filter
  pattern="^(\p{Punct}*)(.*?)(\p{Punct}*)$"
  replacement="$2"
/&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;h5&gt;Conclusion&lt;/h5&gt;

&lt;p&gt;If you decide to use Solr to facilitate your next searching project, don’t be afraid to get your hands dirty and play with the schema configuration. Solr has a lot of good documentation, is extremely powerful, and isn’t nearly as scary as it seems.&lt;/p&gt;

&lt;p&gt;In the meantime, enjoy the new unified search experience and keep looking for more great things to come.&lt;/p&gt;

&lt;p&gt;by &lt;strong&gt;Ben Loveridge&lt;/strong&gt;&lt;/p&gt;</description><link>http://engineering.opensky.com/post/13788247225</link><guid>http://engineering.opensky.com/post/13788247225</guid><pubDate>Sat, 18 Sep 2010 10:00:00 -0400</pubDate></item></channel></rss>
