sean hess

  • Twitter
  • LinkedIn
  • i.TV
    • 0
      1 Feb 2012

      You Only Wish MongoDB Wasn't Relational

      • Edit
      • Delete
      • Tags
      • Autopost

      http://seanhess.github.com/2012/02/01/mongodb_relational.html 

      Please subscribe to my new blog, and let me know if the atom feed isn't working. Thanks!

      • views
      • Tweet
      • Tweet
    • 0
      15 Dec 2011

      Bad Optimization is Like Firing Clay

      • Edit
      • Delete
      • Tags
      • Autopost

      Posted on github - http://seanhess.github.com/2011/12/15/optimization_is_like_firing_clay.html

      • views
      • Tweet
      • Tweet
    • 1
      13 Oct 2011

      How to debug cron

      • Edit
      • Delete
      • Tags
      • Autopost

      Cron is a simple system utility for linux to schedule things to happen at regular intervals. Most instructions tell you to edit the user's crontab with "crontab -e" which opens an editor. We needed a way to install cron tasks automatically when deploying. For that, you can replace /etc/crontab, or stick a file into /etc/cron.d/

      Cron seems simple, but there are several things that can go wrong. They can be hard to debug, because since your command is started by the system, you can't see the output easily. Here are a few of the mistakes I've made

      1. Use absolute paths to command - Cron doesn't keep track of your PATH. 

      * * * * * root /bin/echo "hello" # don't forget the /bin!

      2. Specify a user - when editing the system cron, you have to specify which user is running the command like this:

      * * * * * root /path/to/your/command

      3. Write to a log file - You're going to lose all your stdout and stderr, so send them to a log.  

      * * * * * root /path/to/your/command >> /var/log/mycommand.txt 2>&1

      4. Get the permissions right - Cron is picky about the permissions of the files in /etc/cron.d. Also, you have to use a simple name (no extension). 

      chmod 0644 /etc/cron.d/mycron

      If all else fails, look at /var/log/cron to find out what went wrong. 
      • views
      • Tweet
      • Tweet
    • 12
      28 Jun 2011

      Surviving a Production Launch with Node.js and MongoDB

      • Edit
      • Delete
      • Tags
      • Autopost

      We recently launched our overhauled i.TV app and aoltv.com. While we took a severe beating from our legacy users for removing some of their favorite features, our technology has held up better than we had hoped. 


      When we started re-architecting our systems about 10 months ago, we picked some of the newest technologies we could find. We did this mostly because they were fun, and we wanted to try something new, but also because they offer some distinct advantages and scale easily. After playing around with Ruby and CouchDB, we finally settled on Node.js and MongoDB. 

      Because the technologies are so new, there are a number of things we had to work through to get everything working. Here are a few things about our setup that might help you get to production. This is going to be a ramble, but I figure saying something is better than putting this post off longer. 

      Use What Makes You Happy

      While we had to work through a lot, we more than made up for our losses by using technologies that made us feel productive. They were fun, solved many difficult problems easily, and attracted the right people to our team. 

      One-step Deployment

      Our cluster is hosted entirely on Rackspace. It's basically EC2, just a little more expensive, but with great support and a better interface. They let you spin boxes up and down as you need them. 

      We wrote a simple bash script that installs all our software on a box and checks out our main repository. This is checked in to our code base, which keeps our environment and code in sync. We use node-control to automate our deployments. 

      One thing to note is that it didn't work to try to plan to automate everything from the beginning. We had to start out doing things by hand, and automate them as we started to repeat ourselves. 

      Testing

      We didn't start out with any tests, but quickly began using node-async-testing for our unit tests and expresso for code coverage. We use git hooks to run tests on every push to master. Testing has dramatically reduced our bugs and regressions. We reject the commit if a test fails or coverage goes down. 

      App Development is a Pain

      We decided early on to have our app hit a simple JSON API for its data. It should load data on every page, and take full advantage of HTTP conventions like cache headers to improve performance. This makes for an app that is extremely dependent on our API. While integrating with an API like Netflix is pretty stable, our internal API changed a lot. It was extremely difficult to figure out how to keep versions of our app in sync with our API. Users can take weeks or months to upgrade, and they can't downgrade an app if something goes wrong. 

      Since rollbacks are nearly impossible, we decided that we would make our API backwards compatible. We try to respect a rule that any URL should return the same format forever, so if you want to change the format, you have to introduce a new URL. If a route is going to be phased out, we simply mark it as deprecated, move it into a special deprecated section of our code base, and delete it a couple months later. 

      Node in Production

      We have our node apps running using express. We have an init.d script that runs our app using cluster, which writes the PID file, redirects logs, and daemonizes the process. The apps start on a non-privileged port (like 5000), and we proxy them with nginx. Nginx doesn't do much right now except gzip our JSON. 

      A Few Servers Go a Long Way (if you cache)

      Not including aoltv.com, we're currently getting about 30M hits a month on our API. Our setup is shown below. Server sizes are shown in RAM (see rackspace for more info). It's holding up just fine with low load averages.

      Load Balancer (Varnish - 1 x 4GB) -----> App Servers (Nginx, Node - 1 x 1GB) -------> Database(s) (Mongo - 1 x 4GB)

      We cache at every layer. Mongo stores stuff in memory (see below), our app sets a Cache-Control header on each request, which tells varnish how long to cache, and the app itself reads the cache control header to avoid hitting the servers at all. Sticking to http conventions has taken us a long way. 

      Get Your Mongo into Memory

      If you make your MongoDB servers big enough, it automatically stores every record and index in your working set in memory. We estimated our working set as all TV-Guide data for the current day. Later we realized that we could easily fit almost a week's data within 4GB of RAM. While we picked MongoDB partially because it can scale horizontally, they encourage you to scale vertically first. We're nowhere near the vertical limit yet and are doing just fine. 

      Be Ready to Write Your Own Libraries

      We had to roll many of our own libraries for node, including a MongoDB driver, an FTP client, and a host of 3rd-party API wrappers. While many are now redundant, they didn't exist when we needed them, and we couldn't just wait around for them to show up. We've published our MongoDB driver and hope to publish more soon via our github account. 

      Node.js is Easy to Pick Up

      While the concepts behind server-side development are quite different from client-side JavaScript, the client-focused JS devs we hired have picked up node very quickly. While it has it's warts (nested async calls anyone?), it's hard to argue against JS when it comes to familiarity. 

      With MongoDB, Relational is Almost Inevitable

      While we tried to make MongoDB non-relational, it almost never worked. TV-Guide data contains several many-to-many relationships, and you simply can't store them as nested objects. For example, a user chooses a Lineup, which lists their available Channels. Each Channel has a list of Events, which map an Episode to a Channel and start time. In theory, we could store the Events underneath the Channel, but that would mean we would have to pull out ALL the Events per Channel to get ANY of them. It ended up being easiest to store Events as separate documents. 
      What MongoDB really does well, though, is make every JOIN explicit. This encouraged us to denormalize data onto the most specific documents to avoid a second query. For example, by storing the name of the show on each Event, we can avoid having to hit the database a second time to get information about the show. It encourages you to make each document you DO have usable without a second trip to the db. 
      What Else?

      I'd be happy to write more about any of these topics, or any questions. 

      • views
      • Tweet
      • Tweet
    • 0
      2 May 2011

      i.TV is Hiring

      • Edit
      • Delete
      • Tags
      • Autopost
      http://i.tv/2011/05/now-hiring-exceptional-software-developer/

      If interested, please contact jobs@i.tv. We require that you work locally in Provo, Utah. 

      Exceptional Software Developer 

      I.TV creates software for television on mobile platforms and the web. Our recently updated TV-guide is the top TV app in the app store and has a large base
      of active users. This year, we will release our experience on multiple platforms,  and create fun content viewers can interact with while they watch TV. Our offices are in the clock tower in downtown Provo. 

      OUR TEAM is composed of startup and tech veterans, including our CEO Brad Pelo, who founded Ancestry.com, NextPage, and Folio; and our CTO Sean Hess, who was VP of Engineering at AmberAlert.com. Our engineers are smart, enjoyable people that push you to be your best. We are fully funded by investors who have been with us for three years.

      CULTURE is everything to us. For example, between sprints you can choose your own project for the week. There’s no vacation policy, you just decide how much you can take responsibly. Every Friday we all have lunch and choose company priorities together. We help you develop your career. We agree with Netflix's philosophy on this.

      BENEFITS - Fun, relatable product with huge momentum - Good salary - iPhone or iPad + data plan - 100% of premiums for Dental and Health Insurance - Any work equipment you need (MBP/monitor are standard issue) - Flexible Hours and Vacation Policy - Employee ownership through partner program

      RESPONSIBILITIES include developing our universal iOS app, html app, serverside, and later WM7 and Android. You’ll be responsible for keeping up in a fast-paced agile workplace and providing leadership as necessary. 

      REQUIRED SKILLS - Quick learner - Get things done faster than peers - Ability to write quality, organized code - Excellence on at least one software platform - Creative problem-solver.

      BONUS SKILLS (not required if you learn quickly) 
      - iOS (iPhone)
      - Android and Java
      - Any server-side experience (we use node.js and mongodb running on servers in the cloud but we value your Ruby and PHP skills) 
      - HTML, CSS, Javascript
      - Node.js
      - Mongodb 
      - Agile development
      - Linux (We use CentOS), Server administration, Automated deployment
      - Git 
      - Code organization/architecture 
      - Code testing (unit, integration, automated with a CI server, etc) 
      - Design (UI/UX or visual) 
      - Leadership skills 
      - Foosball skills
      • views
      • Tweet
      • Tweet
    • 0
      4 Jan 2011

      Git Autocompletion for OS X that actually works

      • Edit
      • Delete
      • Tags
      • Autopost
      I swear I've tried to set this up like 5 times. This is the only one that has actually worked. 

      http://www.codethatmatters.com/2010/01/git-autocomplete-in-mac-os-x/

      • views
      • Tweet
      • Tweet
    • 0
      31 Dec 2010

      A Git Workflow for Agile Teams

      • Edit
      • Delete
      • Tags
      • Autopost
      I just stumbled across this gem from reinh.com. Git is amazingly powerful, but it doesn't enforce a workflow. That means a team has to come up with some rules on their own to give meaning to the tool. 

      http://reinh.com/blog/2009/03/02/a-git-workflow-for-agile-teams.html

      He describes feature branches well, and takes it further than I have before. For example, he suggests always squashing little commits together before pushing. 

      Once work on the feature is complete, you will have a branch with a lot of small commits like “adding a model and a migration”, “adding a controller and some views”, “oh crap – adding tests” and so on. This is useful while developing but larger, incremental commits are more easier to maintain. We will use an interactive rebase3 to squash them together. Also, squashing these commits together will allow us to pretend that we wrote the tests first…
       
      Or the same thing about bugs. 

      With a bugfix, squash the commits down into one and exactly one commit that completely represents that bugfix. Half of a bugfix is useless. 

      He also covers QA branch management and production tagging. One thing that confirms my latest work is the goal to get close to deploying straight from the latest "green" build, or the latest commit that makes it through the CI server. 
      • views
      • Tweet
      • Tweet
    • 0
      28 May 2010

      NSBlockOperation for iPhone using Plausible Blocks

      • Edit
      • Delete
      • Tags
      • Autopost
      Plausible Blocks is fantastic. We use it all over our project to make coding asynchronous stuff way easier. Here's a simple implementation of NSBlockOperation to hold you over til blocks go mainstream on the iPhone.

       

      • views
      • Tweet
      • Tweet
    • 0
      22 May 2010

      iPhone Automatic layouts without using Interface Builder

      • Edit
      • Delete
      • Tags
      • Autopost
      This will place a square in the upper right hand corner, even if you change orientations. 

      • views
      • Tweet
      • Tweet
    • 5
      6 Nov 2009

      Use css to style a custom spark skin in Flex 4

      • Edit
      • Delete
      • Tags
      • Autopost

      I’ve finally had a chance to dive in to Flex 4. One trick I learned is incredibly powerful. CSS is a powerful way to specify settings to something from the outside, but it quickly becomes a pain if you need to push pixels around. I’m going to show you how you can create a skin that reads its properties from a stylesheet. This allows css to do what it does best: set simple properties, and lets you do the pixel pushing in the Skin.

      Let’s start with some Flex 3 code we’d like to duplicate. This will create a “modal” overlay that covers the app with a translucent screen. You might use this for a LightBox.

      <!-- MyOverlay.mxml -->
      <mx:Canvas 
          width="100%" height="100%"
          styleName="overlay"
          >
      
          <!-- Put a panel or something here -->
      
      </mx:Canvas>
      
      /** styles.css **/
      .overlay {
          background-color: #000000;
          background-alpha: 0.7;
      }

      Our First Skin

      We want to create this in Flex 4. The (rough) equivalent to canvas is a Group, but it isn’t skinnable, so we can use a SkinnableContainer instead.

      <!-- MyOverlay.mxml -->
      <s:SkinnableContainer
          width="100%" height="100%"
          skinName="overlay"
          >
      
          <!-- Stuff -->
      
      </s:SkinnableContainer>

      SkinnableContainer doesn’t have a way to set backgroundColor or backgroundAlpha! The css will not work.

      Let’s create the same functionality in a skin instead.

      <!-- skins/OverlaySkin.mxml -->
      <s:SparkSkin ... >
      
          <!-- The highest-level base class that can use this-->
          <fx:Metadata>
              [HostComponent("spark.components.SkinnableContainer")]
          </fx:Metadata>
          
          <!-- specify all the states the host component uses -->
          <s:states>
              <s:State name="normal"/>
              <s:State name="disabled"/>
          </s:states>
          
          <!-- Here's our overlay! -->
          <s:Rect left="0" right="0" top="0" bottom="0">
              <s:fill>
                  <s:SolidColor color="#000000" alpha="0.7"/>
              </s:fill>
          </s:Rect>
          
          <!-- Put the panel, or whatever is in the component here --> 
          <s:Group id="contentGroup" verticalCenter="0" horizontalCenter="0">
              <s:layout><s:BasicLayout/></s:layout>
          </s:Group>
          
      </s:SparkSkin>

      That’s not too bad. We have a skin, and now we can apply it to our component by setting theskinClass property. For example:

      <!-- MyOverlay.mxml -->
      <s:SkinnableContainer
          width="100%" height="100%"
          skinClass="skins.OverlaySkin"
          >
      
          <!-- content -->
      
      </s:SkinnableContainer>

      Or we can set the skinClass in the style.

      <!-- MyOverlay.mxml -->
      <s:SkinnableContainer
          width="100%" height="100%"
          styleName="overlay" 
          >
      
          <!-- content -->
      
      </s:SkinnableContainer>
      
      /** styles.css **/
      .overlay {
          skinClass: ClassReference("skins.OverlaySkin");
      }

      Using CSS on the Skin

      Now we have a styleName we can apply to any SkinnableContainer and it will make it look like our black, translucent overlay. This works great, so we start using it, but pretty soon we realize that we need to be able to add a background to another container, but we don’t want to create a new skin just to tweak the color and alpha. Here is where it gets fun. We change the Rect tag in our skin to look like this:

      <s:Rect left="0" right="0" top="0" bottom="0">
              <s:fill>
                      <s:SolidColor color="{getStyle('backgroundColor')}" alpha="{getStyle('backgroundAlpha')}"/>
              </s:fill>
      </s:Rect>

      Now it will get it’s color and alpha from the style. We can change our overlay style to look like this

      /** styles.css **/
      .overlay {
          background-color: #000000;
          background-alpha: 0.7;
          skinClass: ClassReference("skins.OverlaySkin");
      }

      That looks a lot more like the Flex 3 version! We can then add more styles for other kinds of containers that need backgrounds, and our skin is now much more useful than before.

      The Final Version

      <!-- skins/BackgroundSkin.mxml -->
      <?xml version="1.0" encoding="utf-8"?>
      <s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" 
                   xmlns:s="library://ns.adobe.com/flex/spark" 
                   xmlns:mx="library://ns.adobe.com/flex/halo">
          
          <fx:Metadata>
              [HostComponent("spark.components.SkinnableContainer")]
          </fx:Metadata>
          
          
          <s:states>
              <s:State name="normal"/>
              <s:State name="disabled"/>
          </s:states>
          
          <s:Rect left="0" right="0" top="0" bottom="0">
              <s:fill>
                  <s:SolidColor color="{getStyle('backgroundColor')}" alpha="{getStyle('backgroundAlpha')}"/>
              </s:fill>
          </s:Rect>
          
          <!-- Tells the skin where to put the children you have specified -->
          <s:Group id="contentGroup" verticalCenter="0" horizontalCenter="0">
              <s:layout><s:BasicLayout/></s:layout>
          </s:Group>
          
      </s:SparkSkin>
      
      /** styles.css **/
      .overlay {
          background-color: #000000;
          background-alpha: 0.7;
          skinClass: ClassReference("skins.OverlaySkin");
      }
      
      .error {
          background-color: #FF0000;
          background-alpha: 1.0;
      }
      
      .success {
          background-color: #00FF00;
          background-alpha: 1.0;
      }

      Using this technique will allow you to play to the strengths of both CSS and Spark Skins.


      Luan
      Great example but do when I do this in the Eclipse designer, my page is blank. Any idea? If I use the skinClass, all is well.

      Rick
      Thanks for the help, this stopped my frustrations

      Sean Hess
      Luan - you caught me. I never use the designer because, well, too many things make it break :)

      Try this instead: color="{getStyle('backgroundColor') || 0x000000}" which should use black if the style is null. 

      I haven't tried it, but it might work.


      AJ
      Hi Sean, Great example, helped me understanding the basic concepts. 

      One question though, can I define the layout type in host component instead of the skin file? I want to use the background rect in many containers but the layout type differs... any suggestions?


      AJ
      I think, I can define the layout in the host component as well, so that might just work.

      Can we define the style names in the component to class selector, ie:

      DataGrid 
      {
      backgroundAlpha: 0.2;
      headerStyleName: "GridHeader";
      }
      .GridHeader
      {
      color: #594733;
      }
      So for SkinnableContainer, something like:

      SkinnableContainer
      {
      styleName:rectStyle;
      }
      .rectStyle
      {
      background-color:Black;
      }


      Sean Hess
      Any layout you specify in the host component overrides the the one you specify for the contentGroup.

      Tim Oxley
      Hi Sean, Regarding your above default styling code:

      color="{getStyle('backgroundColor') || 0x000000}"


      I tried this with backgroundAlpha

      color="{getStyle('backgroundAlpha') || 0.5}"

      But I was wishing to set it to 0 in my style:

      <customContainer backgroundAlpha="0" />

      but 0 == false, so the OR fails and the backgroundAlpha is set to 0.5

      Workaround is to use a ternary operator in the skin, testing explicitly for undefined instead of anything that's equal to false (0, undefined, null, false, etc):

      <s:Group alpha="{getStyle('backgroundAlpha') != undefined ? getStyle('backgroundAlpha') : 0.2}" />

      :)


      Moxie Zhang
      the combination of color="{getStyle('backgroundColor') and CSS "skinClass: ClassReference..." works very well. 
      However, there is a bug (maybe). By doing so, if you have a transition for a state that to change a property of hostComponent, it won't work. Such as: Resize heightTo="5" target="{hostComponent}". Only way works is to assign skinClass directly in MXML while skinClass ref is still in CSS.

      Anybody knows a work around?

      • views
      • Tweet
      • Tweet
    « Previous 1 2 Next »
    • Search

    • Sites I Like

      • Lessons Learned
      • Both Sides of the Table 2x Entrepreneur turned VC
    • Tags

      • tutorial
      • flex
      • framework
      • php
      • ruby
      • component
      • sinatra
      • agile
      • code
      • git
      • iphone
      • sequel
      • spark
    • Archive

      • 2012 (1)
        • February (1)
      • 2011 (8)
        • December (1)
        • October (2)
        • June (2)
        • May (2)
        • January (1)
      • 2010 (4)
        • December (2)
        • May (2)
      • 2009 (7)
        • November (1)
        • August (2)
        • July (4)
    • Obox Design
  • sean hess

    Sean is cofounder and CTO of i.TV.

    62429 Views
  • Get Updates

    Follow this Space »
    You're following this Space (Edit)
    You're a contributor here (Edit)
    This is your Space (Edit)
    Follow by email »
    Get the latest updates in your email box automatically.
    Loading...
    Subscribe via RSS
    TwitterLinkedIn