<?xml version="1.0" encoding="utf-8" ?>

<rss version="2.0" 
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:admin="http://webns.net/mvcb/"
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
   xmlns:wfw="http://wellformedweb.org/CommentAPI/"
   xmlns:content="http://purl.org/rss/1.0/modules/content/"
   >
<channel>
    
    <title>&lt;?paul</title>
    <link>http://blog.preinheimer.com/</link>
    <description>Paul Reinheimer</description>
    <dc:language>en</dc:language>
    <generator>Serendipity 1.5.3 - http://www.s9y.org/</generator>
    <pubDate>Thu, 16 May 2013 11:47:36 GMT</pubDate>

    <image>
        <url>http://blog.preinheimer.com/templates/default/img/s9y_banner_small.png</url>
        <title>RSS: &lt;?paul - Paul Reinheimer</title>
        <link>http://blog.preinheimer.com/</link>
        <width>100</width>
        <height>21</height>
    </image>

<item>
    <title>How we organize our websites</title>
    <link>http://blog.preinheimer.com/index.php?/archives/414-How-we-organize-our-websites.html</link>
            <category>PHP</category>
    
    <comments>http://blog.preinheimer.com/index.php?/archives/414-How-we-organize-our-websites.html#comments</comments>
    <wfw:comment>http://blog.preinheimer.com/wfwcomment.php?cid=414</wfw:comment>

    <slash:comments>4</slash:comments>
    <wfw:commentRss>http://blog.preinheimer.com/rss.php?version=2.0&amp;type=comments&amp;cid=414</wfw:commentRss>
    

    <author>nospam@example.com (Paul Reinheimer)</author>
    <content:encoded>
    &lt;p&gt;We recently migrated &lt;a href=&quot;http://wheresitup.com/&quot;&gt;Where&amp;#8217;s it Up&lt;/a&gt; to our fancy &lt;a href=&quot;http://blog.preinheimer.com/index.php?/archives/413-Buying-a-Zoo-server.html&quot;&gt;new hardware&lt;/a&gt;, it took a bit more effort than planned (some pains surrounding our use of MongoDB) but I&amp;#8217;m incredibly happy with how things have ended up. As mentioned earlier we&amp;#8217;ve purchased our own hardware, and have racked it with &lt;a href=&quot;http://www.peer1.com/&quot;&gt;Peer 1&lt;/a&gt; here in Toronto. We&amp;#8217;ve installed a hypervisor, and are running different VMs for critical services: MySQL, Mongo, Web Production, Web Development, etc. &lt;/p&gt;

&lt;p&gt;Our websites sit under &lt;span class=&quot;code-inline&quot;&gt;/var/www&lt;/span&gt;, so Where&amp;#8217;s it Up resides at &lt;span class=&quot;code-inline&quot;&gt;/var/www/wheresitup.com/&lt;/span&gt;. Under that directory we have &lt;span class=&quot;code-inline&quot;&gt;/noweb/apache/&lt;/span&gt; which contains both &lt;span class=&quot;code-inline&quot;&gt;wheresitup.com&lt;/span&gt; and &lt;span class=&quot;code-inline&quot;&gt;dev.wheresitup.com&lt;/span&gt;, configuration files for apache. The entire &lt;span class=&quot;code-inline&quot;&gt;/var/www/wheresitup.com&lt;/span&gt; directory tree resides nicely in our version control system. We hand off key configuration options to our websites through the use of Apache&amp;#8217;s SetEnv, things like &lt;span class=&quot;code-inline&quot;&gt;SetEnv mysql_host dev.mysql&lt;/span&gt;, these apache configuration options represent the only difference between the two code bases. &lt;/p&gt;
     
&lt;p style=&quot;margin-left: 10px; color: #7C8699;&quot;&gt;I&amp;#8217;ve written or maintained code that implied the state (Dev/Production/Stage) based on the Host, directory, or other factors in the past. I much prefer grabbing an explicit constant. It feels cleaner, I don&amp;#8217;t have to read up on which variables could have been manipulated by an attacker, and I can ask the exact question I want answered: Is this dev, rather than &amp;#8220;is the url the one that means this is dev&amp;#8221;. &lt;/p&gt;

&lt;p&gt;This allows us to match our Development and Production virtual machines very closely, the only difference between the two is which apache configuration file is sym-linked under &lt;span class=&quot;code-inline&quot;&gt;/etc/apache2/conf/sites-enabled&lt;/span&gt;. Clearly WebDev links to the &lt;span class=&quot;code-inline&quot;&gt;dev.wheresitup.com&lt;/span&gt; file, and WebProd links to &lt;span class=&quot;code-inline&quot;&gt;wheresitup.com&lt;/span&gt;. We actually cloned one machine to produce the other. &lt;/p&gt;

&lt;p&gt;Keeping the configuration files so close also makes a lot of sense to me. If I&amp;#8217;m adding a new constant on Dev, the immediate presence of Prod reminds me that I&amp;#8217;ll need to add it there as well. Storing the entire site: PHP code, supporting apache configuration, etc, all in once place makes it easy to avoid forgetting anything (which is easy when it&#039;s a different file on a different server). The only exception is SSL certificates. We currently host a number of our projects with GitHub, and trust them as we might, we&amp;#8217;re not willing to hand those to anyone else. &lt;/p&gt;
  
    </content:encoded>

    <pubDate>Wed, 15 May 2013 13:19:57 +0000</pubDate>
    <guid isPermaLink="false">http://blog.preinheimer.com/index.php?/archives/414-guid.html</guid>
    
</item>
<item>
    <title>Buying a Zoo (server)</title>
    <link>http://blog.preinheimer.com/index.php?/archives/413-Buying-a-Zoo-server.html</link>
    
    <comments>http://blog.preinheimer.com/index.php?/archives/413-Buying-a-Zoo-server.html#comments</comments>
    <wfw:comment>http://blog.preinheimer.com/wfwcomment.php?cid=413</wfw:comment>

    <slash:comments>1</slash:comments>
    <wfw:commentRss>http://blog.preinheimer.com/rss.php?version=2.0&amp;type=comments&amp;cid=413</wfw:commentRss>
    

    <author>nospam@example.com (Paul Reinheimer)</author>
    <content:encoded>
    &lt;p&gt;Buying physical hardware was a new step for WonderProxy, it&amp;#8217;s hard to say that we rushed into it, this being our third year, but it sort of feels that way. We&amp;#8217;re operating around 100 servers around the world right now, but all of them are either virtual servers, or dedicated machines we&amp;#8217;re renting from providers. Having a UPS guy drop off a rather large box one day was a big change.&lt;/p&gt;

&lt;p&gt;Everything has worked out well, but there was a few steps that could have gone more smoothly, this post is half note to myself on what to do better next time, and half for you.&lt;/p&gt;

&lt;h3&gt;Buying Hardware&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;As far as I can tell the Dell &amp;#38; HP websites have been largely designed to be horrible, in hopes of routing you to a sales person. I tried to fight this, but it was pointless. Phone someone at one of those companies and save yourself several hours.&lt;/li&gt;
&lt;li&gt;Watch for extras on the quote, your sales person will likely work your specifications, then insert the most expensive options around it, things like 24/7 hardware replacement with a 4hr SLA, fancy cable management systems, etc.&lt;/li&gt;
&lt;li&gt;Your data centre will have power requirements. Your phone rep may be able to help you there, Dell&amp;#8217;s &lt;a href=&quot;http://www.dellups.com/default.asp&quot;&gt;UPS website&lt;/a&gt; is also capable of turning your server specifications into amperage.&lt;/li&gt;
&lt;li&gt;Remote management cards are helpful, but you&amp;#8217;ll either need to set up pass-through on the NIC (if your card supports it) or have multiple drops to reach it.&lt;/li&gt;
&lt;li&gt;Check each component for compatibility with your operating system if it doesn&amp;#8217;t ship installed. We&amp;#8217;re using Debian, and had a mild panic attack before we found drivers for our Raid controller in Debian testing. &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Hosting&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Your hosting provider will sell you bandwidth as a &lt;a href=&quot;http://en.wikipedia.org/wiki/Burstable_billing&quot;&gt;95th percentile&lt;/a&gt;. That means they&amp;#8217;ll sample how much bandwidth you&amp;#8217;re using on regular increments (say every 15 minutes), sort those results biggest to smallest, delete the top 5% then charge you the next one. Unless you&amp;#8217;re buying a lot of bandwidth you&amp;#8217;ll probably end up paying more here than you would on a dedicated box by the GB.&lt;/li&gt;
&lt;li&gt;Hosting space comes in either U increments (1U, 2U, 4U, etc) or rack portions (full rack, half rack, quarter rack, eighth rack (octal). If you&amp;#8217;re buying directly from a provider you&amp;#8217;re likely going to need to over-buy if you&amp;#8217;re only racking one server.&lt;/li&gt;
&lt;li&gt;Providers also care about power usage they will likely tell you something like 8 AMPS. You&amp;#8217;ll need to spec your server out appropriately.&lt;/li&gt;
&lt;li&gt;The number of network cables and power ports inside your unit will also matter, there&amp;#8217;s no point in having a redundant power supply if you&amp;#8217;re only going to be able to plug one in.&lt;/li&gt;
&lt;li&gt;You will need to plan your move in date, your provider may need a lot of paper work signed and then a few more days before this happens. Talk to your sales rep about dates, and SLA for setting up new space. It may be as long as a week between getting your paper work in order and being able to move in.&lt;/li&gt;
&lt;li&gt;Find out how your server will be mounted, there appears to be both round and square holes. As we learned when we were four, you need to match the right peg to the right hole. If you&amp;#8217;re renting a very small fraction of space (like an octal) you may not have any mounting brackets at all, instead just letting things rest on the sheet metal between clients.&lt;/li&gt;
&lt;li&gt;Your sales guy may not manage things once you&amp;#8217;ve signed up, you may be handed off to the network team. Try to keep track of who knows what, if you&amp;#8217;re racking your server and have a problem sales guy can&amp;#8217;t help (and probably doesn&amp;#8217;t answer the phone after hours).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Visiting the Data Centre&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;You&amp;#8217;ll need ID, your network guy should be able to describe the requirements&lt;/li&gt;
&lt;li&gt;Depending on how many servers you&amp;#8217;re bringing in, you may be able to use the front door, or the loading dock.&lt;/li&gt;
&lt;li&gt;Ours had a nice man-trap on the way in, first door needed to close before the second would open&lt;/li&gt;
&lt;li&gt;It will be loud in the server room, ear plugs would be prudent&lt;/li&gt;
&lt;li&gt;A flash light might help see things, there&amp;#8217;s decent lighting but you&amp;#8217;ll likely have stuff on top and below you&lt;/li&gt;
&lt;li&gt;There should be a monitor, keyboard, and mouse on a trolley somewhere for configuring things&lt;/li&gt;
&lt;li&gt;There may not be wifi, or even 3g inside&lt;/li&gt;
&lt;li&gt;Pre-configuring your IP details stuff would be prudent, there will not be DHCP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That in hand, hopefully your server buying and racking experience will go smoothly.&lt;/p&gt; 
    </content:encoded>

    <pubDate>Mon, 15 Apr 2013 12:25:33 +0000</pubDate>
    <guid isPermaLink="false">http://blog.preinheimer.com/index.php?/archives/413-guid.html</guid>
    
</item>
<item>
    <title>Where's it Up - Visualized</title>
    <link>http://blog.preinheimer.com/index.php?/archives/412-Wheres-it-Up-Visualized.html</link>
    
    <comments>http://blog.preinheimer.com/index.php?/archives/412-Wheres-it-Up-Visualized.html#comments</comments>
    <wfw:comment>http://blog.preinheimer.com/wfwcomment.php?cid=412</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://blog.preinheimer.com/rss.php?version=2.0&amp;type=comments&amp;cid=412</wfw:commentRss>
    

    <author>nospam@example.com (Paul Reinheimer)</author>
    <content:encoded>
    &lt;p&gt;Andrew Quarton developed a nifty little visualization built using the &lt;a href=&quot;https://api.wheresitup.com/&quot;&gt;Where&amp;#8217;s it UP API&lt;/a&gt; called &lt;a href=&quot;http://geoping.com/&quot;&gt;GeoPing&lt;/a&gt;. Go take a look then come back.&lt;/p&gt;

&lt;p&gt;Our technology stack for the API includes supervisor to run workers, and &lt;a href=&quot;http://gearman.org/&quot;&gt;gearman&lt;/a&gt; to manage our job queue. We&amp;#8217;re normally running 25 workers to manage the queue. Work tends to come in chunks, and that number of workers has been able to keep the queue minimal or at zero.&lt;/p&gt;

&lt;p&gt;Since it&amp;#8217;s such an nifty tool, it made the front page of Hacker News today, which led to a few problems on our end. The number of jobs launched for each person hitting the GeoPing tool was rather high, enough to fill all the current workers. When many people started hitting the GeoPing tool in rapid succession the queue built and built. At one point Gearman reported 13,000 jobs in the queue.&lt;/p&gt;

&lt;p&gt;Noticing this I quickly changed the number of desired workers in &lt;a href=&quot;http://supervisord.org/&quot;&gt;supervisor&lt;/a&gt; from 25 to 100, than used &lt;span class=&quot;code-inline&quot;&gt;/etc/init.d/supervisord restart&lt;/span&gt; to apply the changes. That didn&amp;#8217;t seem to affect the queue, so I tried 250 workers, used restart to apply the changes once more, and watched. Then I noticed something the restart option wasn&amp;#8217;t launching the extra workers I wanted. Running &lt;span class=&quot;code-inline&quot;&gt;/etc/init.d/supervisord stop&lt;/span&gt;, then &lt;span class=&quot;code-inline&quot;&gt;start&lt;/span&gt; did. Then the queue finally started to recover. I kept an eye on the queue with a quick and dirty shell command from &lt;a href=&quot;http://stackoverflow.com/questions/3378760/how-can-i-get-the-number-of-queued-jobs-of-a-particular-type-in-gearman&quot; rel=&quot;nofollow&quot;&gt;stack overflow&lt;/a&gt;.&lt;/p&gt;

&lt;span class=&quot;code&quot;&gt;(echo status ; sleep 0.1) | netcat 127.0.0.1 4730 -w 1&lt;/span&gt;


&lt;p&gt;From our side, I think a few things went wrong:
&lt;ul&gt;
&lt;li&gt;We didn&amp;#8217;t have tooling in place to warn us when the queue broached reasonable limits&lt;/li&gt;
&lt;li&gt;We hadn&amp;#8217;t documented the proper way to increase workers (stop/start not restart)&lt;/li&gt;
&lt;li&gt;Our graphing system seems to have a hard coded max value, hiding valuable data&lt;a class=&quot;serendipity_image_link&quot;  href=&#039;http://blog.preinheimer.com/uploads/wiuapigraph.png&#039;&gt;&lt;!-- s9ymdb:51 --&gt;&lt;img class=&quot;serendipity_image_right&quot; width=&quot;110&quot; height=&quot;37&quot; style=&quot;float: right; padding: 4px;&quot; src=&quot;http://blog.preinheimer.com/uploads/wiuapigraph.serendipityThumb.png&quot;  alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;
&lt;p&gt;Having either of those first two items in place would have allowed us to respond to the issue much more quickly. &lt;/p&gt;
&lt;p&gt;We&#039;re working on them :)&lt;/p&gt; 
    </content:encoded>

    <pubDate>Fri, 12 Apr 2013 23:04:20 +0000</pubDate>
    <guid isPermaLink="false">http://blog.preinheimer.com/index.php?/archives/412-guid.html</guid>
    
</item>
<item>
    <title>Yanking Hard Drives</title>
    <link>http://blog.preinheimer.com/index.php?/archives/411-Yanking-Hard-Drives.html</link>
    
    <comments>http://blog.preinheimer.com/index.php?/archives/411-Yanking-Hard-Drives.html#comments</comments>
    <wfw:comment>http://blog.preinheimer.com/wfwcomment.php?cid=411</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://blog.preinheimer.com/rss.php?version=2.0&amp;type=comments&amp;cid=411</wfw:commentRss>
    

    <author>nospam@example.com (Paul Reinheimer)</author>
    <content:encoded>
    &lt;p&gt;I invested a portion of my day heading down to our data centre, and yanking a drive out of our newly racked server, and watching to see what would happen. The answer was: not much. The system kept merrily computing along, but it also failed to warn us that it had lost a drive. Some configuration tweaks later, I repeated the process, and my mailbox was quickly filled. Success.&lt;/p&gt;

&lt;p&gt;I did this for two reasons: I wanted assurance that our raid controller had been properly configured, and that things would continue operating normally if we lost a drive. I also wanted to ensure that should we lose a drive we&#039;d be notified, redundancy is worth little if actions aren&#039;t taken to correct problems that cause it to be lost. Today confirmed the first, and revealed problems in the second. Huge Success.&lt;/p&gt;

&lt;p&gt;If you&#039;re going to perform the same task, a few pieces of advice:
&lt;ul&gt;
&lt;li&gt;Do it before there&#039;s critical production software running on it, at least the first time&lt;/li&gt;
&lt;li&gt;Your raid controller will need to rebuild the drive after it&#039;s been pulled. This will take a while, and kills your redundancy (or a portion thereof) while it&#039;s happening. If you need to repeat the test pull the same drive each time to avoid real problems.&lt;/li&gt;
&lt;li&gt;Work to ensure that problem notifications leave the affected system as quickly as possible. If the only copy of an alert sits on the box that&#039;s having issues, you may lose it as well.&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;

 
    </content:encoded>

    <pubDate>Sun, 07 Apr 2013 21:35:39 +0000</pubDate>
    <guid isPermaLink="false">http://blog.preinheimer.com/index.php?/archives/411-guid.html</guid>
    
</item>
<item>
    <title>Working hard to stop treading water</title>
    <link>http://blog.preinheimer.com/index.php?/archives/410-Working-hard-to-stop-treading-water.html</link>
            <category>Op-Ed</category>
    
    <comments>http://blog.preinheimer.com/index.php?/archives/410-Working-hard-to-stop-treading-water.html#comments</comments>
    <wfw:comment>http://blog.preinheimer.com/wfwcomment.php?cid=410</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://blog.preinheimer.com/rss.php?version=2.0&amp;type=comments&amp;cid=410</wfw:commentRss>
    

    <author>nospam@example.com (Paul Reinheimer)</author>
    <content:encoded>
    &lt;p&gt;I&#039;m amazed at how much &lt;a href=&quot;https://wonderproxy.com/&quot;&gt;WonderProxy&lt;/a&gt; has grown. I think we signed up our first client with only 6 servers; we&#039;re on 6 continents now, with 89 proxies, and 5 private machines dedicated to things like command &amp;amp; control or monitoring. Despite that, the company hasn&#039;t really grown; we&#039;ve hired Allison to help out with copywriting &amp;amp; billing (which was a fantastic move on our part), but that&#039;s about it.&lt;/p&gt;
 
&lt;p&gt;&lt;a class=&quot;serendipity_image_link&quot;  href=&#039;http://blog.preinheimer.com/uploads/physical.jpg&#039;&gt;&lt;img width=&quot;300&quot;  src=&quot;http://blog.preinheimer.com/uploads/physical.jpg&quot; style=&quot;float: right&quot; /&gt;&lt;/a&gt;Over the past few weeks Will and I have mostly turned our attention inward, improving the way we monitor and configure our network. This was kicked off when we racked our first co-located box here in Toronto (with its additional layer of physical security):&lt;/p&gt;
 
&lt;p&gt;With the additional redundancy it&#039;s currently providing, we&#039;re better configuring and monitoring &lt;a href=&quot;https://puppetlabs.com/&quot;&gt;puppet&lt;/a&gt;, which watches the rest of our servers. We&#039;re testing out a new setup for our web and database systems that provides better isolation and makes them easier to update. Despite feeling anxious about doing work that isn&#039;t specifically customer focused, I&#039;m glad we&#039;re doing this as I&#039;m expecting it to pay dividends in time by freeing us from some routine tasks.&lt;/p&gt;
 
&lt;p&gt;While growing the network, Will and I have been relentless about reducing the things that require our time and effort but which don&#039;t improve things from our customers&#039; point of view. Every minute we spend treading water is a minute we&#039;re not striving forward. Will led the charge customizing and automating our server configuration process, which had added complexity because each VPS we buy is a bit different, ranging from a bare bones Debian install, to an &quot;everything including the kitchen sink&quot; install that has little more than a run-level stopping it from launching gnome. From there, we&#039;ve worked to recognize routine tasks that steal our time but do little to move us forward, and then automated them. Lots of little things have come together to help free us to focus on improving our products or writing new ones.&lt;/p&gt;
 
&lt;p&gt;Things like:
&lt;ul&gt;
&lt;li&gt;Disabling customer accounts automatically on a charge back&lt;/li&gt;
&lt;li&gt;Making it easier to send a user a free trial &lt;/li&gt;
&lt;li&gt;Ensuring our messages get delivered into the inbox, not the spam folder, the first time. &lt;/li&gt;
&lt;li&gt;Tweaking our billing code to recognize most of the common ways renewals come in to correctly attach them to the right account.&lt;/li&gt;
&lt;li&gt;Handing billing (both accounts receivable and payable) to Allison, to free technical time for technical tasks (she&#039;s also much better at it than I was).&lt;/li&gt;
&lt;li&gt;Documenting irregular, but not-yet-automated tasks so they can be completed quickly, with a minimum of research&lt;/li&gt;
&lt;li&gt;Distributing our authentication system to remove a single point of failure and ease diagnostics when there&#039;s a problem&lt;/li&gt;
&lt;li&gt;Automatically populating VPN accounts with all available servers&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;
 
&lt;p&gt;Negating a task (through automation, documentation, or otherwise) that takes just 5 minutes a day earns us back 2 hours of development time per month. It can be hard to justify spending an hour to &quot;fix&quot; something that only takes you 5 minutes, but with a return on investment of only two weeks, it would be foolish not to.&lt;/p&gt;
 
&lt;p&gt;I&#039;m also very picky when it comes to who mail goes to. I work relentlessly to reduce the number of recipients to any automated message. I no longer receive any messages from our hosting providers: they&#039;re directed to Will and Allison. Will deals with technical issues, and Allison pays the bills. Will doesn&#039;t get my MySQL &lt;a href=&quot;http://www.maatkit.org/doc/mk-query-digest.html&quot;&gt;slow query report&lt;/a&gt;, nor messages from our PayPal IPN script: they don&#039;t concern him. Every email you unsubscribe from is a gift of time to your future self.&lt;/p&gt;
 
&lt;p&gt;We have a few triggers to discover things we need to work on:
&lt;ul&gt;
&lt;li&gt;Noting common support questions, and either adding documentation or tweaking our applications to avoid them. Populating VPN accounts was a good example of this: our VPN service is built on the same codebase as our Proxy stuff, so when it launched, users needed to add the servers to their account. This generated many support requests that were easily resolved by a few lines of code.&lt;/li&gt;
&lt;li&gt;Regarding everything we&#039;ve done several times with suspicion. I&#039;ve added a user&#039;s IP to our white list a few times now: is it time to build an API so they can handle this themselves?&lt;/li&gt;
&lt;li&gt;Regarding anything we&#039;ve forgotten to do with suspicion: if it needs to be done that regularly, why does it still need a human?&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;
 
&lt;p&gt;I&#039;m convinced that if we hadn&#039;t been working so hard to automate or remove such day-to-day tasks, we&#039;d never have had time to write &lt;a href=&quot;https://wondernetwork.com/loadtesting&quot;&gt;Natural Load Testing&lt;/a&gt;, &lt;a href=&quot;http://wheresitup.com/&quot;&gt;Where&#039;s it Up&lt;/a&gt;, &lt;a href=&quot;http://wheresitfast.com/&quot;&gt;Where&#039;s it Fast&lt;/a&gt;, or our &lt;a href=&quot;https://wondernetwork.com/pings&quot;&gt;Global Ping Statistics&lt;/a&gt;.&lt;/p&gt; 
    </content:encoded>

    <pubDate>Sun, 24 Mar 2013 14:13:13 +0000</pubDate>
    <guid isPermaLink="false">http://blog.preinheimer.com/index.php?/archives/410-guid.html</guid>
    
</item>
<item>
    <title>Power vs Complexity</title>
    <link>http://blog.preinheimer.com/index.php?/archives/409-Power-vs-Complexity.html</link>
            <category>Op-Ed</category>
    
    <comments>http://blog.preinheimer.com/index.php?/archives/409-Power-vs-Complexity.html#comments</comments>
    <wfw:comment>http://blog.preinheimer.com/wfwcomment.php?cid=409</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://blog.preinheimer.com/rss.php?version=2.0&amp;type=comments&amp;cid=409</wfw:commentRss>
    

    <author>nospam@example.com (Paul Reinheimer)</author>
    <content:encoded>
    &lt;p&gt;I ended up taking several months off development of &lt;a href=&quot;https://wondernetwork.com/loadtesting&quot;&gt;Natural Load Testing&lt;/a&gt;. I needed to wait while my partner improved the software we actually use to apply the load (it&amp;#8217;s ready now), then I was caught up in other projects like the &lt;a href=&quot;http://api.wheresitup.com/&quot;&gt;Where&amp;#8217;s it Up API&lt;/a&gt;, and &lt;a href=&quot;http://wheresitfast.com&quot;&gt;Where&amp;#8217;s it Fast&lt;/a&gt;. Coming back to it was fantastically revealing: it was &lt;em&gt;very hard&lt;/em&gt; to use.&lt;/p&gt;

&lt;p&gt;Looking back, I can see why we made many of the decisions that I now identify as making it hard to use. Most of them were about offering power or flexibility to our end users: I think creation of &amp;#8216;tests&amp;#8217; and &amp;#8216;test suites&amp;#8217; is a great example. &lt;/p&gt;

&lt;p&gt;Users create tests, then put those tests into test suites: this allows for complex and powerful interactions where virtual users register for a site, then perform one of several different actions, before closing out. A sample load test might be Surf -&amp;#62; Register -&amp;#62; [Search to product OR Browse to product -&amp;#62; Add to shopping card -&amp;#62; Checkout. We can handle that, and I&amp;#8217;m proud that we can handle that.&lt;/p&gt;

&lt;p&gt;Unfortunately, it means that users getting started who may only want to load test &amp;#8220;Register&amp;#8221; have to jump through four additional complicated steps before getting the answers they want.&lt;/p&gt;

&lt;p&gt;In order to provide the Power that &amp;#8220;Power Users&amp;#8221; will want, I&amp;#8217;ve added tremendous complexity to the product that we present to every user. Since every user will start off as a &amp;#8220;New User&amp;#8221; I&amp;#8217;ve burdened everyone with a complicated interface all in the name of power.&lt;/p&gt;

&lt;h2&gt;The Challenge&lt;/h2&gt;

&lt;p&gt;I value the power we&amp;#8217;ve built into the product, and I know the few users who have managed the hurdles to get there value it as well. I don&amp;#8217;t want to remove it, but I need to do something to allow users who don&amp;#8217;t require that power to have an easier time load testing their sites. I&amp;#8217;m currently using a few different techniques:
&lt;ul&gt;
&lt;li&gt;More contextual internal links&lt;br /&gt;
Allow users who have missed a step to easily jump there to complete it. For example users on the Test Creation page who are missing requests are linked to the Domain Authorization page so they can add the domain they&amp;#8217;re missing. &lt;/li&gt;
&lt;li&gt; Options that allow parts of the process to be skipped&lt;br /&gt;
The general work flow is Create Tests -&amp;#62; Create Test Suite -&amp;#62; Group Tests into Test Suite. Allow users to create a Test, and a Test Suite containing only that Test in one step, rather than four. &lt;/li&gt;
&lt;li&gt;More Ajax&lt;br /&gt;
By allowing users to correct omitted steps on the page they&amp;#8217;re on, the system can avoid breaking their flow, or forcing them to restart. &lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s a work in progress (clearly) but I&amp;#8217;m already finding the site easier to use&amp;#8230; though, that may have been the problem in the first place. :)&lt;/p&gt;

&lt;h2&gt;My New Goal&lt;/h2&gt;
&lt;p&gt;Provide everyone with the &lt;b&gt;power&lt;/b&gt; to perform complex actions, while burdening them with as little &lt;b&gt;complexity&lt;/b&gt; as possible.&lt;/p&gt;
 
    </content:encoded>

    <pubDate>Thu, 14 Feb 2013 00:56:53 +0000</pubDate>
    <guid isPermaLink="false">http://blog.preinheimer.com/index.php?/archives/409-guid.html</guid>
    
</item>
<item>
    <title>Fixing (some) Phone Menus</title>
    <link>http://blog.preinheimer.com/index.php?/archives/408-Fixing-some-Phone-Menus.html</link>
            <category>Op-Ed</category>
    
    <comments>http://blog.preinheimer.com/index.php?/archives/408-Fixing-some-Phone-Menus.html#comments</comments>
    <wfw:comment>http://blog.preinheimer.com/wfwcomment.php?cid=408</wfw:comment>

    <slash:comments>2</slash:comments>
    <wfw:commentRss>http://blog.preinheimer.com/rss.php?version=2.0&amp;type=comments&amp;cid=408</wfw:commentRss>
    

    <author>nospam@example.com (Paul Reinheimer)</author>
    <content:encoded>
    &lt;p&gt;Calling a phone number on a website, and being asked to punch in numbers or say key words to navigate arcane menus to the person or department you need is silly. If you&#039;re already on a high bandwidth system that excels in information display, how is it sensible to be transferred to a low bandwidth system before making decisions?&lt;/p&gt;

&lt;p&gt;The average person speaks at 120-150 words per minute, and reads at 250-300 words per minute. So even before any other consideration the user will be able to move through information twice as fast on the website as over the phone. But it&amp;#8217;s much much larger than that. With the written word it&amp;#8217;s incredibly easy to skim, or skip entire sections you know to be irrelevant, on the phone you&amp;#8217;re forced to hear all options that precede the one you&amp;#8217;re interested in. It&amp;#8217;s also possible to jump between options as you evaluate them against your needs. &lt;/p&gt;



&lt;h2&gt;Consider:&lt;/h2&gt;
&lt;span style=&quot;text-align: center;&quot;&gt;
&lt;img class=&quot;serendipity_image_center&quot; width=&quot;216&quot; height=&quot;139&quot;  src=&quot;http://blog.preinheimer.com/uploads/phone-0.png&quot;  alt=&quot;&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot;/&gt;&lt;span style=&quot;font-weight: bold; display: block; font-size: 2em; padding: 8px;&quot;&gt;&amp;darr;&lt;/span&gt; 
&lt;img class=&quot;serendipity_image_center&quot; width=&quot;216&quot; height=&quot;139&quot;  src=&quot;http://blog.preinheimer.com/uploads/phone-1.png&quot;  alt=&quot;&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot;/&gt;&lt;span style=&quot;font-weight: bold; display: block; font-size: 2em; padding: 8px;&quot;&gt;&amp;darr;&lt;/span&gt; 
&lt;img class=&quot;serendipity_image_center&quot; width=&quot;216&quot; height=&quot;139&quot;  src=&quot;http://blog.preinheimer.com/uploads/phone-2.png&quot;  alt=&quot;&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot;/&gt;&lt;span style=&quot;font-weight: bold; display: block; font-size: 2em; padding: 8px;&quot;&gt;&amp;darr;&lt;/span&gt; 
&lt;img class=&quot;serendipity_image_center&quot; width=&quot;216&quot; height=&quot;139&quot;  src=&quot;http://blog.preinheimer.com/uploads/phone-3.png&quot;  alt=&quot;&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot;/&gt;
&lt;/span&gt;

&lt;p&gt;I could navigate that in seconds with great accuracy, and have the ability to jump around while I look for the best choice. I&#039;d actually buy a different phone number for every possible end point (rather than requiring a separate #[code], but even with this it&#039;s a vast improvement. I think I&amp;#8217;ve only ever seen PayPal do something similar with their web authentication codes for calling in. &lt;/p&gt; 
    </content:encoded>

    <pubDate>Tue, 12 Feb 2013 02:11:00 +0000</pubDate>
    <guid isPermaLink="false">http://blog.preinheimer.com/index.php?/archives/408-guid.html</guid>
    
</item>
<item>
    <title>The Mystery of the Double Stacked Graph</title>
    <link>http://blog.preinheimer.com/index.php?/archives/407-The-Mystery-of-the-Double-Stacked-Graph.html</link>
            <category>PHP</category>
    
    <comments>http://blog.preinheimer.com/index.php?/archives/407-The-Mystery-of-the-Double-Stacked-Graph.html#comments</comments>
    <wfw:comment>http://blog.preinheimer.com/wfwcomment.php?cid=407</wfw:comment>

    <slash:comments>3</slash:comments>
    <wfw:commentRss>http://blog.preinheimer.com/rss.php?version=2.0&amp;type=comments&amp;cid=407</wfw:commentRss>
    

    <author>nospam@example.com (Paul Reinheimer)</author>
    <content:encoded>
    &lt;p&gt;&lt;a class=&quot;serendipity_image_link&quot;  href=&quot;http://blog.preinheimer.com/uploads/normal1.png&quot;&gt;&lt;img class=&quot;serendipity_image_left&quot; width=&quot;110&quot; height=&quot;83&quot;  src=&quot;http://blog.preinheimer.com/uploads/normal1.serendipityThumb.png&quot;  alt=&quot;&quot; style=&quot;float: left; padding-right: 8px; padding-bottom: 8px;&quot;/&gt;&lt;/a&gt;There&amp;#8217;s been an issue on &lt;a href=&quot;https://wondernetwork.com/loadtesting&quot;&gt;Natural Load Testing&lt;/a&gt; (our fantastic web application load testing tool) for a while now, we&amp;#8217;ve been referring to it as the Double Stacked Graph. Normally the graphs should look like this, kindly sharing the load testing results with the end user, hopefully being both easy to start with and powerful as usage grows.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;serendipity_image_link&quot;  href=&#039;http://blog.preinheimer.com/uploads/double.png&#039;&gt;&lt;!-- s9ymdb:45 --&gt;&lt;img class=&quot;serendipity_image_right&quot; width=&quot;110&quot; height=&quot;83&quot;  src=&quot;http://blog.preinheimer.com/uploads/double.serendipityThumb.png&quot;  alt=&quot;&quot; style=&quot;float: right; padding-left: 8px; padding-bottom: 8px;&quot;/&gt;&lt;/a&gt;Unfortunately, what we&amp;#8217;ve been seeing occasionally is the dreaded Double Stack: Here you can see that there is two stacked red bars on top of each other. They represent the exact same space in time, but the data is being added to the graph twice for some reason.&lt;/p&gt;

&lt;p&gt;Initially I expected that this was an issue with me handling the updates to the graph with ajax poorly. We had an issue with Where&amp;#8217;s it Up for a while where results were duplicated. This was the result of asking the server for &amp;#8220;new&amp;#8221; results every second by passing the server the list of results already obtained. If a request took more than a second to complete, the following request (initiated while the first was outstanding) would be initiated with the same list of previously obtained results, so the server would obligingly return the same &amp;#8220;new&amp;#8221; results to both requests.&lt;/p&gt;

&lt;p&gt;It turned out however that this wasn&amp;#8217;t the problem at all, having learned from the &lt;a href=&quot;http://wheresitup.com/&quot;&gt;Where&amp;#8217;s it Up&lt;/a&gt; issue I&amp;#8217;d coded those ajax requests more carefully. It turns out that the issue had to do with how I was communicating with MySQL. Each time the graph updates it asks for results with a timestamp newer than the newest data it has. The exact query is something like this:&lt;/p&gt;

&lt;span class=&quot;code&quot;&gt;$query = &quot;SELECT `ts` as `timestamp`, `active_requests`, `requests_initiated`, `median_response`, `running_workers`, `bytes_transferred` FROM `test_results_stats` WHERE `job_id` = &#039;$job_id&#039; AND `ts` &gt; &#039;$minTime&#039; LIMIT 2&quot;;&lt;/span&gt;

&lt;p&gt;The issue here turns out to be the fact that I&#039;m quoting &lt;span class=&quot;inline-code&quot;&gt;$minTime&lt;/span&gt;. Take a look at these results:
&lt;span class=&quot;code&quot;&gt;
mysql&gt; CREATE TABLE `test_decimal` (
    -&gt; `job_id` varchar(32) NOT NULL,
    -&gt; `ts` decimal(13,3) NOT NULL
    -&gt; ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Query OK, 0 rows affected (0.01 sec)


mysql&gt; INSERT INTO `test_decimal` VALUES
    -&gt; (&#039;9_0209_511673437c4dd&#039;, 1360425827.491),
    -&gt; (&#039;9_0209_511673437c4dd&#039;, 1360425828.491),
    -&gt; (&#039;9_0209_511673437c4dd&#039;, 1360425829.491),
    -&gt; (&#039;9_0209_511673437c4dd&#039;, 1360425830.492);
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0


mysql&gt; SELECT * from `test_decimal` WHERE `ts` &amp;gt; &#039;&lt;span style=&quot;color: white;&quot;&gt;1360425827.491&lt;/span&gt;&#039; LIMIT 2;
+----------------------+----------------+
| job_id | ts |
+----------------------+----------------+
| 9_0209_511673437c4dd | &lt;span style=&quot;color: white;&quot;&gt;1360425827.491&lt;/span&gt; |
| 9_0209_511673437c4dd | 1360425828.491 |
+----------------------+----------------+
2 rows in set (0.00 sec)


mysql&gt; SELECT * from `test_decimal` WHERE `ts` &amp;gt; &lt;span style=&quot;color: white;&quot;&gt;1360425827.491&lt;/span&gt; LIMIT 2;
+----------------------+----------------+
| job_id | ts |
+----------------------+----------------+
| 9_0209_511673437c4dd | 1360425828.491 |
| 9_0209_511673437c4dd | 1360425829.491 |
+----------------------+----------------+
2 rows in set (0.00 sec)
&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;While using the greater than operator, I&amp;#8217;m obtaining results that are equal if the term I&amp;#8217;m comparing against is quoted. Without the quotes it performs as expected. This confused me greatly, I&amp;#8217;ve been told countless times that I can quote my variables in MySQL to no ill effect, in fact I probably should if I&amp;#8217;m not using paramaterized queries for increased security. &lt;/p&gt;

&lt;p&gt;The crux of the issue will come down to MySQL&amp;#8217;s &lt;a href=&quot;http://dev.mysql.com/doc/refman/5.1/en/type-conversion.html&quot;&gt;Type Conversion rules&lt;/a&gt;. It must be converting the two values to float to handle the quoted comparison, though I may be at a loss to describe why they&amp;#8217;re converted differently. By not quoting the decimal value I allow the comparison to occur between decimal values, and obtain the desired result. &lt;/p&gt;

&lt;h3&gt;Update&lt;/h3&gt;
&lt;p&gt;A few people have commented (either here or elsewhere) about MySQL versions. I just re-confirmed the test with the newest MySQL Debian would give me:
&lt;span class=&quot;code&quot;&gt;
mysql&gt; SELECT * from `test_decimal` WHERE `ts` &gt; &#039;1360425827.491&#039; LIMIT 2;
+----------------------+----------------+
| job_id               | ts             |
+----------------------+----------------+
| 9_0209_511673437c4dd | 1360425827.491 |
| 9_0209_511673437c4dd | 1360425828.491 |
+----------------------+----------------+
2 rows in set (0.00 sec)

mysql&gt;  SHOW VARIABLES LIKE &quot;%version%&quot;;
+-------------------------+-----------------------+
| Variable_name           | Value                 |
+-------------------------+-----------------------+
| protocol_version        | 10                    |
| version                 | 5.1.66-0+squeeze1-log |
| version_comment         | (Debian)              |
| version_compile_machine | i486                  |
| version_compile_os      | debian-linux-gnu      |
+-------------------------+-----------------------+
5 rows in set (0.00 sec)
&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Or our Percona server (issue resolved):
&lt;span class=&quot;code&quot;&gt;
mysql&gt; SELECT * from `test_decimal` WHERE `ts` &gt; &#039;1360425827.491&#039; LIMIT 2;
+----------------------+----------------+
| job_id               | ts             |
+----------------------+----------------+
| 9_0209_511673437c4dd | 1360425828.491 |
| 9_0209_511673437c4dd | 1360425829.491 |
+----------------------+----------------+
2 rows in set (0.00 sec)

mysql&gt; SHOW VARIABLES LIKE &quot;%version%&quot;;
+-------------------------+------------------------------------+
| Variable_name           | Value                              |
+-------------------------+------------------------------------+
| innodb_version          | 1.1.8-rel29.4                      |
| protocol_version        | 10                                 |
| slave_type_conversions  |                                    |
| version                 | 5.5.29-29.4-log                    |
| version_comment         | Percona Server (GPL), Release 29.4 |
| version_compile_machine | x86_64                             |
| version_compile_os      | Linux                              |
+-------------------------+------------------------------------+
7 rows in set (0.00 sec)
&lt;/span&gt;&lt;/p&gt;

 
    </content:encoded>

    <pubDate>Mon, 11 Feb 2013 14:55:00 +0000</pubDate>
    <guid isPermaLink="false">http://blog.preinheimer.com/index.php?/archives/407-guid.html</guid>
    
</item>
<item>
    <title>Assessing a site</title>
    <link>http://blog.preinheimer.com/index.php?/archives/406-Assessing-a-site.html</link>
            <category>Op-Ed</category>
    
    <comments>http://blog.preinheimer.com/index.php?/archives/406-Assessing-a-site.html#comments</comments>
    <wfw:comment>http://blog.preinheimer.com/wfwcomment.php?cid=406</wfw:comment>

    <slash:comments>1</slash:comments>
    <wfw:commentRss>http://blog.preinheimer.com/rss.php?version=2.0&amp;type=comments&amp;cid=406</wfw:commentRss>
    

    <author>nospam@example.com (Paul Reinheimer)</author>
    <content:encoded>
    &lt;p&gt;I used to use the design of a site as a quick measure for how mature the site was. For a variety of reasons: improving tutorials, better tools, resources like bootstrap, this is no longer the case. I&amp;#8217;m pretty happy with the design of this site, and Allison (not a designer) did it in just a few hours. &lt;br /&gt;
These are things I note while gauging site maturity:
&lt;ul&gt;
&lt;li&gt;Can I reset my password?&lt;/li&gt;
&lt;li&gt;Am I forwarded to the requested page after being bounced to a log in page?&lt;/li&gt;
&lt;li&gt;Are emails sent in multipart/mime format with an effective HTML and plain-text version?&lt;/li&gt;
&lt;li&gt;Is the URL system consistent and meaningful?&lt;/li&gt;
&lt;li&gt;Are there clear links to the privacy policy and terms of service?&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;
&lt;p&gt;None of these elements tend to be priorities while a site is being developed, but they pull at developers to be fixed over time. The more of these things a site has, the longer I tend to believe it&amp;#8217;s been around.&lt;br  /&gt;

What do you look at?&lt;/p&gt;
 
    </content:encoded>

    <pubDate>Mon, 28 Jan 2013 22:58:15 +0000</pubDate>
    <guid isPermaLink="false">http://blog.preinheimer.com/index.php?/archives/406-guid.html</guid>
    
</item>
<item>
    <title>Giving up on Movie Theatres</title>
    <link>http://blog.preinheimer.com/index.php?/archives/405-Giving-up-on-Movie-Theatres.html</link>
            <category>Op-Ed</category>
    
    <comments>http://blog.preinheimer.com/index.php?/archives/405-Giving-up-on-Movie-Theatres.html#comments</comments>
    <wfw:comment>http://blog.preinheimer.com/wfwcomment.php?cid=405</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://blog.preinheimer.com/rss.php?version=2.0&amp;type=comments&amp;cid=405</wfw:commentRss>
    

    <author>nospam@example.com (Paul Reinheimer)</author>
    <content:encoded>
    &lt;p&gt;I saw The Hobbit an unexpected Journey last night, it was pretty good. I liked some of the changes from the books a bit more than others, but I think that overall the additional will help cement Tolkien&amp;#8217;s universe in the minds of many.&lt;/p&gt;

&lt;p&gt;What I hated was the overall movie going experience. It was a relatively full theatre, full of people paying full price for a 3D movie, currently $14.25/person before concessions and taxes. So clearly the room had to contain a few people whose social lives couldn&amp;#8217;t sustain 3 hours without txting. There was also a man sitting in the third row who I think was completing his own screenplay on one of the largest &amp;#38; brightest screen cell phones I&amp;#8217;ve seen. I heard a few people ask him to put it away, including someone who got up walked down four rows, and tapped him on the shoulder. This seemed to constrain him to only keeping brief notes for the rest of the film, but he very much wasn&amp;#8217;t done.&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet tw-align-center&quot;&gt;&lt;p&gt;It confuses me that we’re a society so inconsiderate that people do that, but simultaneously so civil that no one started a fight.&lt;/p&gt;&amp;mdash; Paul Reinheimer (@preinheimer) &lt;a href=&quot;https://twitter.com/preinheimer/status/293165272754438144&quot; data-datetime=&quot;2013-01-21T01:17:02+00:00&quot;&gt;January 21, 2013&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&quot;http://blog.preinheimer.com//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;The pivotal moment for me was when a theatre employee walked in, past the guy on his phone (the brightest thing in the room by far, including the movie screen) sign the check in form on the far wall, then back past the phone user once more, without a word, and out of the room. &lt;/p&gt;

&lt;p&gt;Perhaps demographics have pushed so much that the dollar value of guests who want to user their cell phones out weighs the dollar value of guests who find that disruptive; theatres are best serving their stock holders by not stopping them. Fair enough, but I&amp;#8217;m not going to give them my money while they gladly accept and embrace people who disrupt what I&amp;#8217;ve paid to enjoy so much. For the price of two tickets I can get the Blu-Ray in a few months, turn the lights &amp;#38; my phone off, and enjoy the film uninterrupted.&lt;/p&gt;

&lt;p&gt;Also: fancy &amp;#8220;Digital Picture&amp;#8221; we paid to enjoy froze twice for several seconds during the film, but that was by far a smaller disruption. &lt;/p&gt; 
    </content:encoded>

    <pubDate>Mon, 21 Jan 2013 15:23:19 +0000</pubDate>
    <guid isPermaLink="false">http://blog.preinheimer.com/index.php?/archives/405-guid.html</guid>
    
</item>
<item>
    <title>My Broken Button</title>
    <link>http://blog.preinheimer.com/index.php?/archives/404-My-Broken-Button.html</link>
    
    <comments>http://blog.preinheimer.com/index.php?/archives/404-My-Broken-Button.html#comments</comments>
    <wfw:comment>http://blog.preinheimer.com/wfwcomment.php?cid=404</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://blog.preinheimer.com/rss.php?version=2.0&amp;type=comments&amp;cid=404</wfw:commentRss>
    

    <author>nospam@example.com (Paul Reinheimer)</author>
    <content:encoded>
    &lt;p&gt;I&amp;#8217;m one developer on a visualization project using &lt;a href=&quot;http://d3js.org/&quot;&gt;d3.js&lt;/a&gt;, which is pretty fantastic. I&amp;#8217;m working on the control panel at present, which displays a series of buttons to the end user to allow them to filter out certain metrics in the data set. The buttons do a bit more than that, they&amp;#8217;ve also got a nifty horizontal bar in them that indicates what percentage of that data is presently included. So if we were visualizing fast food data, and you filtered out Hamburgers the progress bar for McDonalds might drop down to 40%.&lt;/p&gt;

&lt;p&gt;We have a bit of hierarchical data that lends itself well to nested drop downs. When the user hovers over a button for a while, I&amp;#8217;ll display the drop down to let them explore the data in greater detail. Things were working well in Chrome, but my &lt;span class=&quot;code-inline&quot;&gt;:hover&lt;/span&gt; pseudo-event never fired to display the drop down in Firefox. I spent a great deal of time trying to figure out why. My buttons seemed quite simple. 
&lt;span class=&quot;code&quot;&gt;
&amp;#60;button&amp;#62;
  &amp;#60;div class=&amp;#8220;drophead&amp;#8221;&amp;#62;Food&amp;#60;/div&amp;#62;
  &amp;#60;ul&amp;#62;
    &amp;#60;li&amp;#62;Hamburger&amp;#60;/li&amp;#62;
    &amp;#60;li&amp;#62;Fries&amp;#60;/li&amp;#62;
  &amp;#60;/ul&amp;#62;
  &amp;#60;div class=&amp;#8220;barchart&amp;#8221;&amp;#62;&amp;#60;/div&amp;#62;
&amp;#60;/button&amp;#62;
&lt;/span&gt;
&lt;/p&gt;

&lt;p&gt;My usual fallback when I can&amp;#8217;t figure something out on the web, especially if there&amp;#8217;s inconsistencies involved, is to validate. Validation revealed that my divs and uls were &lt;a href=&quot;http://www.w3.org/TR/2011/WD-html5-20110525/the-button-element.html#the-button-element&quot;&gt;not valid children of the button element&lt;/a&gt;. Chrome managed to make this work, but Firefox had issues handling pseudo-events for these invalid children, so my drop downs didn&amp;#8217;t work. Even though it worked in Chrome now, there was no guarantee that my invalid syntax would continue to function long term. I swapped the buttons out for &lt;span class=&quot;code-inline&quot;&gt;div&lt;/span&gt;s, and asked a co-worker to help with some refactoring as &lt;span class=&quot;code-inline&quot;&gt;div&lt;/span&gt;s don&#039;t allow value attributes as &lt;span class=&quot;code-inline&quot;&gt;button&lt;/span&gt;s do.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://validator.w3.org/&quot;&gt;W3C Validator&lt;/a&gt; saves the day again. &lt;/p&gt;

 
    </content:encoded>

    <pubDate>Sat, 05 Jan 2013 04:23:22 +0000</pubDate>
    <guid isPermaLink="false">http://blog.preinheimer.com/index.php?/archives/404-guid.html</guid>
    
</item>
<item>
    <title>XHGui on MongoDB</title>
    <link>http://blog.preinheimer.com/index.php?/archives/403-XHGui-on-MongoDB.html</link>
            <category>PHP</category>
    
    <comments>http://blog.preinheimer.com/index.php?/archives/403-XHGui-on-MongoDB.html#comments</comments>
    <wfw:comment>http://blog.preinheimer.com/wfwcomment.php?cid=403</wfw:comment>

    <slash:comments>1</slash:comments>
    <wfw:commentRss>http://blog.preinheimer.com/rss.php?version=2.0&amp;type=comments&amp;cid=403</wfw:commentRss>
    

    <author>nospam@example.com (Paul Reinheimer)</author>
    <content:encoded>
    &lt;p&gt;This has been a long time coming. &lt;a href=&quot;seancoates.com/blogs/&quot;&gt;Sean Coates&lt;/a&gt;, &lt;a href=&quot;http://nerderati.com/&quot;&gt;Joel Perras&lt;/a&gt;, and I made an attempt a few years ago, pounding out a good start over a weekend holed up in Sean&amp;#8217;s house. Unfortunately, once we left the momentum was gone, and it&amp;#8217;s just gathered dust since. More recently, at &lt;a href=&quot;http://truenorthphp.ca/&quot;&gt;True North PHP&lt;/a&gt;, my love for the tool was rekindled, and an off-hand remark to &lt;a href=&quot;http://mark-story.com/posts/archive&quot;&gt;Mark Story&lt;/a&gt; led to some vague agreements about doing something eventually. Fast forward to December 2nd, and we decided to release something on Christmas.&lt;/p&gt;

&lt;p&gt;So we are.&lt;/p&gt;

&lt;p&gt;Mark &amp;#38; I are pleased as punch to introduce &lt;a href=&quot;https://github.com/preinheimer/xhgui&quot;&gt;XHGui on MongoDB&lt;/a&gt;. Our goal was to get as close to the original feature set of the tool I worked on a few years ago (which leveraged the starting point provided by Facebook) and then to release what we had. What we&amp;#8217;ve got now works; there&amp;#8217;s still a good distance to go, but we think it&amp;#8217;s far enough that we can ask for help form the community at large.&lt;/p&gt;

&lt;a class=&quot;serendipity_image_link&quot;  href=&#039;http://blog.preinheimer.com/uploads/runpage.png&#039;&gt;&lt;!-- s9ymdb:43 --&gt;&lt;img class=&quot;serendipity_image_left&quot; width=&quot;110&quot; height=&quot;67&quot;  src=&quot;http://blog.preinheimer.com/uploads/runpage.serendipityThumb.png&quot;  alt=&quot;&quot; /&gt;&lt;/a&gt;

&lt;a class=&quot;serendipity_image_link&quot;  href=&#039;http://blog.preinheimer.com/uploads/urlpage.png&#039;&gt;&lt;!-- s9ymdb:42 --&gt;&lt;img class=&quot;serendipity_image_left&quot; width=&quot;110&quot; height=&quot;61&quot;  src=&quot;http://blog.preinheimer.com/uploads/urlpage.serendipityThumb.png&quot;  alt=&quot;&quot; /&gt;&lt;/a&gt;


&lt;h3&gt;Why NoSQL?&lt;/h3&gt;
&lt;p&gt;I feel the data we&amp;#8217;re storing lends itself well to the loose document format provided by NoSQL solutions. While it&amp;#8217;s possible to normalize the information provided (in fact &lt;a href=&quot;http://xhprof.io/&quot;&gt;xhprof.io&lt;/a&gt; does just this), that&amp;#8217;s not an approach that appeals to me. I&amp;#8217;ve also had several colleagues comment that the only reason they had MySQL installed on a server was for this tool. My hope is that by allowing more nuanced querying and graphing, users will be able to better explore the data available.&lt;/p&gt;

&lt;h3&gt;Why MongoDB?&lt;/h3&gt;
&lt;p&gt;Tool familiarity. I&amp;#8217;d love to see some effort to make it work with Couch or other solutions.&lt;/p&gt;

&lt;h3&gt;Features:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Collects XHProf data and stores it in MongoDB&lt;/li&gt;
&lt;li&gt;Presents most recent calls on the home page&lt;/li&gt;
&lt;li&gt;Simplified URL aggregation pages&lt;/li&gt;
&lt;li&gt;Detailed run page&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Warning&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;XHProf (the php extension) only records a single layer of call depth when recording performance metrics. Consider two functions A &amp;#38; B each call getData(), and getData() invokes mysql_query() in turn. If mysql_query() takes one second to return one time, and 1ms to return the other, the tool isn&amp;#8217;t able to attach those values directly to the grandparent. XHProf only knows that mysql_query() was invoked by getData(). In practice this doesn&amp;#8217;t tend to matter. &lt;/li&gt;
&lt;li&gt;XHProf only provides inclusive times; exclusive times can be roughly calculated (with the caveat above in mind). I haven&amp;#8217;t tested that function thoroughly, it could be filling everyone with lies.&lt;/li&gt;
&lt;li&gt;We used Twig. It seemed like a good idea, then I saw the call graphs and memory usage. &lt;/li&gt;
&lt;li&gt;It does not have any sort of access control mechanism built in, we&amp;#8217;re trusting you to handle this on your own.&lt;/li&gt;
&lt;li&gt;The &amp;#8220;Custom View&amp;#8221; page currently doesn&amp;#8217;t graph&lt;/li&gt;
&lt;li&gt;We haven&amp;#8217;t included a tool to manage actually recording the views. This is coming soon.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;The Future&lt;/h3&gt;

&lt;p&gt;Mark and I both have interest in the tool. I&amp;#8217;ll be using it on &lt;a href=&quot;http://wheresitup.com/&quot;&gt;Where&amp;#8217;s it Up&lt;/a&gt;, and other &lt;a href=&quot;https://wondernetwork.com/&quot;&gt;WonderNetwork&lt;/a&gt; sites. Our goal is to be incredibly responsive when people have suggestions, pull requests, etc. To that end we&amp;#8217;re in the market for someone with ~two hours a week to help us out in terms of managing pull requests, cleaning up code and helping keep the ball rolling. &lt;a href=&quot;http://wondernetwork.com&quot;&gt;WonderNetwork&lt;/a&gt; will be providing a bit of cash, so this is a paid position. &lt;/p&gt; 
    </content:encoded>

    <pubDate>Tue, 25 Dec 2012 21:37:38 +0000</pubDate>
    <guid isPermaLink="false">http://blog.preinheimer.com/index.php?/archives/403-guid.html</guid>
    
</item>
<item>
    <title>Apple TV Stutters and Freezes</title>
    <link>http://blog.preinheimer.com/index.php?/archives/402-Apple-TV-Stutters-and-Freezes.html</link>
    
    <comments>http://blog.preinheimer.com/index.php?/archives/402-Apple-TV-Stutters-and-Freezes.html#comments</comments>
    <wfw:comment>http://blog.preinheimer.com/wfwcomment.php?cid=402</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://blog.preinheimer.com/rss.php?version=2.0&amp;type=comments&amp;cid=402</wfw:commentRss>
    

    <author>nospam@example.com (Paul Reinheimer)</author>
    <content:encoded>
    &lt;p&gt;I was having a problem with my first generation Apple TV: videos were stuttering while being played. The issue seemed more severe when I was watching HD content, but I was otherwise unable to correlate &amp;#8220;bad&amp;#8221; experiences with better ones.&lt;/p&gt;

&lt;p&gt;I managed to resolve the issue by downloading all of the content on my Apple TV to my computer, then formatting the device, and re-loading it with selected content. I theorize the issue was that the hard drive on the Apple TV was so full it was unable to buffer as much content as it wanted, so any network variation between it and the source of content caused it to stutter. Formatting the device, then re-loading it while leaving plenty of space free has given it the buffering space it wants.&lt;/p&gt;

 
    </content:encoded>

    <pubDate>Fri, 30 Nov 2012 23:53:10 +0000</pubDate>
    <guid isPermaLink="false">http://blog.preinheimer.com/index.php?/archives/402-guid.html</guid>
    
</item>
<item>
    <title>Fun Stuff at WonderProxy</title>
    <link>http://blog.preinheimer.com/index.php?/archives/401-Fun-Stuff-at-WonderProxy.html</link>
    
    <comments>http://blog.preinheimer.com/index.php?/archives/401-Fun-Stuff-at-WonderProxy.html#comments</comments>
    <wfw:comment>http://blog.preinheimer.com/wfwcomment.php?cid=401</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://blog.preinheimer.com/rss.php?version=2.0&amp;type=comments&amp;cid=401</wfw:commentRss>
    

    <author>nospam@example.com (Paul Reinheimer)</author>
    <content:encoded>
    &lt;p&gt;I gave an &lt;a href=&quot;https://joind.in/talk/view/7630&quot;&gt;unconference talk&lt;/a&gt; this weekend at the &lt;a href=&quot;http://truenorthphp.ca/&quot;&gt;True North PHP&lt;/a&gt; conference in Mississauga. Chris encouraged me to speak so I decided to do a quick talk on WonderProxy.&lt;/p&gt;

&lt;p style=&quot;margin-left: 10px; color: #7C8699;&quot;&gt;My friend Morgan gave me advice several years ago: The best talks are the ones that only you can give. By this he means that anyone can give a talk on &quot;Security&quot; or &quot;Performance&quot;, running through the numbers, but only you can give a talk on &quot;Security at $company&quot;, or &quot;Solving performance problems at $company&quot;, and those talks with the personal edge tend to be better. The more I reflect on the talks I&#039;ve given, the wiser his words seem.&lt;/p&gt;

&lt;p&gt;In the talk I ran through why I started WonderProxy, how the service grew, the problems we ran into along the way, and how we&#039;ve developed other products on top of our global network of servers. I tried to mix in a few lessons we&#039;ve learned that might apply to others, but by far the most appreciated parts were the funny anecdotes about the problems along the way. &lt;/p&gt;

&lt;p&gt;It was great to speak in Ontario once more (I haven&#039;t since php|works left), and I&#039;m looking forward to giving a better prepared and filled out version at &lt;a href=&quot;http://confoo.ca/en/2013/session/wonderproxy-a-story-and-a-look-under-the-hood&quot;&gt;ConFoo next year&lt;/a&gt;.&lt;/p&gt;
 
    </content:encoded>

    <pubDate>Thu, 08 Nov 2012 01:15:40 +0000</pubDate>
    <guid isPermaLink="false">http://blog.preinheimer.com/index.php?/archives/401-guid.html</guid>
    
</item>
<item>
    <title>How PayPal pushes us away</title>
    <link>http://blog.preinheimer.com/index.php?/archives/400-How-PayPal-pushes-us-away.html</link>
            <category>Op-Ed</category>
    
    <comments>http://blog.preinheimer.com/index.php?/archives/400-How-PayPal-pushes-us-away.html#comments</comments>
    <wfw:comment>http://blog.preinheimer.com/wfwcomment.php?cid=400</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://blog.preinheimer.com/rss.php?version=2.0&amp;type=comments&amp;cid=400</wfw:commentRss>
    

    <author>nospam@example.com (Paul Reinheimer)</author>
    <content:encoded>
    &lt;p&gt;There&amp;#8217;s a lot of things I don&amp;#8217;t like about PayPal: Their UI is horrible, search is weak and slow, and they seem to like &lt;a href=&quot;https://www.google.ca/search?q=paypal+froze+my+account&amp;ie=utf-8&amp;oe=utf-8&quot;&gt;randomly freezing accounts&lt;/a&gt;. Up until Stripe came to Canada, however it was one of the only choices for easy credit card acceptance online.&lt;/p&gt;
&lt;p style=&quot;margin-left: 10px; color: #7C8699;&quot;&gt;Will and I actually talked about selling WonderProxy to a US corporation we&amp;#8217;d start, just to get more payment processing options.&lt;/p&gt;

&lt;p&gt;One of the things that annoys me most is their handling of fraud. When someone accuses you of something, you&amp;#8217;re given an incredibly short list of options to resolve the dispute. The options are heavily weighted towards providing a FedEx or UPS tracking number, or refunding the money. These are in fact your options even when you describe your account and payment options as &amp;#8220;Services&amp;#8221; rather than &amp;#8220;Goods&amp;#8221; (something PayPal asks you). As providers of an online service, I find this lack of personalization bothersome.&lt;/p&gt;

&lt;p&gt;An average fraud case goes something like this: 
&lt;ol&gt;
&lt;li&gt;Get notified that someone bought something&lt;/li&gt;
&lt;li&gt;Get notified that there&amp;#8217;s a dispute&lt;/li&gt;
&lt;li&gt;Provide some details regarding the person who used our service&lt;/li&gt;
&lt;li&gt;Lose dispute&lt;/li&gt;
&lt;li&gt;Lose the amount of the sale&lt;/li&gt;
&lt;li&gt;Pay a bonus penalty&lt;/li&gt;
&lt;/ol&gt;
Occasionally both of the first two steps occur before I wake up in the morning.&lt;/p&gt;


&lt;p&gt;Resolving a dispute today, the options I was presented really bugged me:
&lt;div style=&quot;width: 600px; margin: 0px; overflow: scroll;&quot;&gt;
&lt;img src=&quot;http://blog.preinheimer.com/uploads/paypal-chargeback.png&quot; style=&quot;display: block;&quot;&gt;
&lt;/div&gt;
&lt;/p&gt;



&lt;p&gt;Examining my options:
&lt;ul&gt;
&lt;li&gt;I can provide proof that the item was shipped through an approved shipper to the address on the Transaction Details page.&lt;/li&gt;
Clearly not applicable, we don&amp;#8217;t ship things. I considered sending registered mail postcards once, but I think PayPal only covers your cost of the item, not the actual sale price.
&lt;li&gt;I can provide evidence other than proof of shipment.&lt;/li&gt;
Not applicable here, the person didn&amp;#8217;t actually use the service.
&lt;li&gt;I can provide proof that I refunded payment for this transaction.&lt;/li&gt;
No freaking clue how this could apply. Maybe if the person PayPal&amp;#8217;d me money, and I sent it back Western Union?
&lt;li&gt;I will accept liability for this transaction.&lt;/li&gt;
My only option. 
&lt;/ul&gt;
The choice &amp;#8220;I will accept liability for this transaction&amp;#8221; makes me feel like I&amp;#8217;m telling PayPal that this is my fault, that I&amp;#8217;m taking responsibility for the good people at PayPal processing a transaction that was clearly fraudulent. I&amp;#8217;ve tarnished their good name through my failure.&lt;/p&gt;

&lt;p&gt;This couldn&amp;#8217;t be further from the truth: They&amp;#8217;ve failed me. &lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://blog.preinheimer.com/uploads/paypal-features.png&quot; style=&quot;float: right; padding-left: 8px; padding-bottom: 8px;&quot;&gt;Fraud Reduction is in fact one of the features they&amp;#8217;re advertising (and we&#039;re paying for, over $3k in fees since January 2011). Apart from that, the entire fraud checking process is a black box to us. We&amp;#8217;re not passed a fraud-score with any transaction: either we get the money or we don&amp;#8217;t. We&amp;#8217;re not even passed granular details about how the transaction occurred: Did the CVV test pass? what about zip code matching? user&amp;#8217;s country (as determined by IP) vs credit card country? etc. We get none of that. Nor can we tweak our fraud protection options, I can stop people from paying us with eChecks, that&amp;#8217;s about it. &lt;/p&gt;

&lt;p&gt;We&amp;#8217;ve contacted PayPal in the past when we suspected a transaction was fraudulent, the only option we were given was to pre-emptively refund it. There was no way for us to recommend that they flag that transaction for review, or perhaps examine other transactions on the same account/card further. We reach out to customers making suspicious transactions now, and just refund them if we don&amp;#8217;t hear back. This is far from the optimal solution, and I feel it robs their fraud team of useful information, but it&amp;#8217;s all we&amp;#8217;ve got.&lt;/p&gt;


&lt;p&gt;As it stands, WonderNetwork will be using Stripe for all new products. As our payment processing system matures with our new products we&amp;#8217;ll be migrating it over to WonderProxy as well. I&amp;#8217;m just tired of being treated like a criminal by PayPal for using their system in the manner it was designed.&lt;/p&gt;
 
    </content:encoded>

    <pubDate>Fri, 02 Nov 2012 00:49:09 +0000</pubDate>
    <guid isPermaLink="false">http://blog.preinheimer.com/index.php?/archives/400-guid.html</guid>
    
</item>

</channel>
</rss>