Blog


Mar

Streamio Marketing Site - the Design Process


I will explain my typical process when designing a marketing site by showing you examples from my work with Streamio.

Why Streamio? Because they are a fun company to work with, easy to cooperate with and they give clear and good feedback.

First I got a mockup from Streamio with some thoughts and wishes. It's actually rare that you get a mockup this good from the customer:

The mockup from Streamio

The mockup from Streamio, which I'm very impressed with. Sooner or later they won't need my help anymore :).

An important thing with a marketing site is to get the user's attention. This is done by giving enough information in a short amount of time, so that the user gets interested and keeps on reading further down. This means that we need to scale down the information, put it in a natural order and keep it simple and clear.

It's quite known how much, or little, we read on the internet. Studies show that we read very little, I myself is a typical example. We browse sites very fast, and it doesn’t take many seconds before we jump to the next one. This is something we have to think about when designing web sites, we only have a couple of seconds to catch the users attention, not much more exposure then a logo. Some interesting articles on the subject are UXMYTHS - People read on the web, How Users Read on the Web and E-Mail Newsletters: Increasing Usability.

The first thing I do in the design process is to look through the information on the customer's mockup. The second step is to make my own interpretations. My first thoughts on the Streamio mockup was that there was too much information and the headlines were unclear. On the following drawings I have scaled down the information and changed the layout in the at the top:

Draw with pencil on paper

I love to draw with pencil on paper - a great way to get your thoughts down at the beginning of the process.

Close-up on Streamio's mockup

Close-up on Streamio's mockup.

Final drawing of the design

My final drawing of the design, which I showed Streamio.

What's left is:

  • a short headline about Streamio: they help you upload and publish videos online.
  • then a picture of a computer and two devices with their video platform or video, to show that it works on all modern platforms.
  • followed by 3 short blurbs about their advantages.
  • the 3 blurbs are then put into one sentence to make it even more clear.
  • a prominent Call-to-Action button makes it easy for the user to try the service.
  • finally there is a price tag with the minimum price.

When I'm done I show the customer the new drawings. This time Streamio was happy with the result, so then I continue with the next step: the real designing.

I design directly in the web browser, which is most efficient today. This way you work closer to the end result and you don't have to work in two steps, like when you're using Photoshop. I do additional graphical elements in Photoshop, but I constantly look at the end result in the web browser. Another great advantage with working in the web browser is that you have access to A LOT of fonts from @font-face services, such as Typekit. Today you can do a lot with the design using html and css3, which I'm sure you already know, but if you want to read more about it you can take a look at Smashing Magazine or NetTuts.

Two fonts

Two fonts used on Streamio's site. The first one is the popular serif FF Tisa which I think is great! It is used for all the content on the site. The second one: FF DIN Pro Condensed, is used for the logo.

First layout

This is my first layout after the drawings. Here I have made the basic layout and placed the content, and made some screenshots and additional graphics. But it is a bit plain and boring.

Streamio likes a very sharp and glossy style, and I won't say no to that. A lot of sites can't pull this of, but I think it gives a great vibe and harmony to this site and it works with Streamio's kind of service.

Some screenshots from the final site:

Final site 1

Final site 2

Final site 3

I really like the last page because it's only built with three images. It's a fun challenge to try to use as few images as possible. This keeps the loading time for the site short, or rather compensate for custom fonts.

Streamio launched their site on March 7th. It looks a bit different from my final version because they combined some of the final design with some of the earlier to create what they want.

Take a look at Streamio.com.

In my next blogpost I will write about the design process behind the actual video tool which David at Streamio has developed and I've made the design for.

If you have any comments or questions you can text me on twitter: @leuchovius, thanks!

Jul

Continuous Integration Testing for Ruby on Rails with Integrity


Doing test-driven development usually means you have a lot of tests in a project. While this is almost entirely a good thing, running the thousands of Cucumber features and RSpec examples in a large project takes a couple of minutes. If you run your entire test suite every time you commit this will easily eat up a large chunk of your day. Offloading some of this to a continuous integration server will allow you to save time by running your tests asynchronously, in addition to its other benefits.

At eLabs we usually run our unit tests locally—as well as the Cucumber feature for the story we're currently working on—before checking in. Then we let our CI server run the rest of our Cucumber features and notify us if something goes wrong. Here's the setup we use:

Integrity

At eLabs we've looked at a number of different CI servers, such as CruiseControl.rb and Run Code Run, but our favorite by far is Integrity.

Screenshot of our Integrity site

Integrity suits us perfectly. It fetches our code from our private GitHub repositories, can run any testing command and notify us in a variety of ways such as email and Campfire. It also has a very nice and clean interface. Its one major shortcoming is its complete lack of error reporting. If there's something wrong with your setup it will silently fail, which makes troubleshooting a nightmare. Hopefully the instructions below will help you avoid some of the pitfalls.

Installation

We installed Integrity on a server running Mac OS X and Passenger under Apache. Here's a quick guide.

First we installed the gem:

$ sudo gem install integrity

Then set it up in your chosen directory using the --passenger option:

$ integrity install --passenger /Library/WebServer/Sites/integrity

Next, set up a virtual host in Apache, pointing its DocumentRoot to the public folder in your Integrity installation.

DocumentRoot "/Library/WebServer/Sites/integrity/public"

One absolutely crucial step that we missed at first is to make sure that the system user that runs the Integrity passenger processes has git in its PATH. The simplest way to do this is to set the PATH in the virtual host configuration:

SetEnv PATH /opt/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

After configuring Apache you have to configure Integrity by editing config.yml in the root directory of your Integrity installation. We used SQLite for the database (couldn't get it to work with MySQL). If you want to use a hash password for the admin user, here's a simple way to get the SHA1 of a password:

$ ruby -r 'digest/sha1' -e 'puts Digest::SHA1.hexdigest("password")'

The final step is to create the database:

$ integrity migrate_db

You should now be able to log in to your Integrity site and add your projects.

Setting Up a Project

The most important part of setting up a project for CI is the build command. This is the command that Integrity runs to test your app, and it can be anything that exits with a status of 0 when successful. We use a simple rake task that prepares our project by copying a database.yml file and runs RSpec and Cucumber tests.

namespace :ci do
  task :copy_yml do
    system("cp #{Rails.root}/config/database.yml.ci #{Rails.root}/config/database.yml")
  end

  desc "Prepare for CI and run entire test suite"
  task :build => ['ci:copy_yml', 'db:migrate', 'spec', 'features'] do
  end
end

With that committed to our repository (along with a database.yml.ci file) we add the project to Integrity. The important parts here are the Git repository and Build script settings.

Add a project to Integrity

You must also make sure that the Integrity user can access your repository on GitHub. There are a couple of different ways you can do this, but we created a separate free GitHub account that we add as a collaborator to our projects.

After you add the project you should be able to request a manual build from the Integrity web interface. Note that the build is done synchronously—so you'll have to wait a while—but if the build succeeds you're ready to set up the Post-Receive hook for GitHub to have Integrity run your tests whenever you push your code to GitHub.

GitHub Post-Receive URL settings

Go to your project's page on GitHub and click the Admin link in the top menu, and then Service Hooks in the sub menu. Enter the push URL for your Integrity project as Post-Receive URL. The URL has the following format:

http://username:password@hostname/project-name/push

After you've updated the settings, click the Test Hook link and Integrity should start a new build. If that works, you're all set for having automated builds on every push to GitHub.

Notifiers

While Integrity's interface is nice, you probably don't want to visit your Integrity site after every commit to check the status of your build. The point of asynchronous tests after all is to get notified when somethings goes wrong. Integrity has a bunch of different notifiers you can use. We use the ones for email and Campfire. Find more and installation instructions on the Integrity site.

In addition to Integrity's own notifiers we also use CCMenu, a Mac OS X Menu extra built for showing CruiseControl build status. It works with Integrity as well with the gem integritray.

We also use GitHub's Campfire service hook that posts a message to our Campfire room every time someone pushes new code. This makes it very easy to keep track of what other people in the company are working on.

Campfire screenshot

Not having to wait for our entire test suite to run before each commit saves us a lot of time. But we can still feel confident knowing that Integrity has our backs and will alert us if something goes wrong.

Jun

Relieving the Pain of Controller Tests


Lately we've been embracing Cucumber as the preferred way of testing our Ruby on Rails applications. Cucumber is awesome, both for communicating with the customer and for getting thorough, full-stack tests of the application. We like Cucumber so much, we basically thought that it could replace both view and controller tests. It turns out we were wrong.

While our policy of Cucumber over view tests has been working out great so far, controllers are a different story. There is simply too much logic in the controller that is very hard to test (in a sane way) with Cucumber. It makes sense to have a cucumber feature that specifies that, for a non-admin user, a certain link should not be there, however that doesn't test the security of the application, despite the link not being there, the action may still be freely accessible for the user. Cucumber is not well suited (nor is it intended) to test these kinds of things.

But writing controller tests is a serious pain, so we tried to find a stack that felt natural and pleasant to work with. After some experimentation, we've settled on a slightly odd and interesting stack, consisting of the following:

  • Remarkable's descriptions and steps
  • RSpec's normal mocking syntax
  • Macro-style methods for different user contexts

We first tried using Remarkable on its own, but quickly found that we did not like the mocking syntax:

mock_models :data_point

describe(:post => :create, :data => "params") do
  expects :bulk_create, :on => DataPoint, 
          :with => proc { [@current_account, "params"] }, 
          :returns => proc { [mock_data_point] }

  it { should set_the_flash(:notice) }
  it { should render_template('data_points/new')}
  it { should assign_to(:data_points, :with => [mock_data_point]) }
end

The fact that it uses a "class-method" level for the DSL presents a lot of problems, it is impossible to simply use instance variables, methods need to be wrapped in procs, etc... It also, for some reason, does not seem to support stubs, which is very inconvenient in some cases. In the end we realized that there is absolutely no advantage to Remarkable's DSL over simply doing:

mock_models :data_point

describe(:post => :create, :data => "params") do
  before do
    DataPoint.should_receive(:bulk_create).with(@current_account, "params").and_return([mock_data_point])
  end

  it { should set_the_flash(:notice) }
  it { should render_template('data_points/new')}
  it { should assign_to(:data_points, :with => [mock_data_point]) }
end

One sore point though was that there was a lot of setup required in each controller spec for getting the logged in user right. We thought that with some block trickery we might be able to take care of this tedious setup:

module LogInContext

  def as_user(params={}, &block)
    describe "(as a logged in user)" do
      before do
        @current_user = mock('current_user')
        controller.stub!(:current_user).and_return(@current_user)
      end

      describe(params, &block)
    end
  end

  ...

  def deny_access_to_visitors(params={})
    as_visitor(params) do
      it { should redirect_to(new_session_path) }
    end
  end

end

Spec::Rails::Example::ControllerExampleGroup.extend(LogInContext)

Now we can use these contexts in our controller tests:

mock_models :data_point

as_user(:post => :create, :data => "params") do
  before do
    DataPoint.should_receive(:bulk_create).with(@current_account, "params").and_return([mock_data_point])
  end

  it { should set_the_flash(:notice) }
  it { should render_template('data_points/new')}
  it { should assign_to(:data_points, :with => [mock_data_point]) }
end

deny_access_to_visitors(:post => :create, :data => "params")

But we can do one better:

module LogInContext
  ...

  def as_user_only(params={}, &block)
    as_user(params, &block)
    deny_access_to_visitors(params)
  end
end

Now it is as simple as:

mock_models :data_point

as_user_only(:post => :create, :data => "params") do
  before do
    DataPoint.should_receive(:bulk_create).with(@current_account, "params").and_return([mock_data_point])
  end

  it { should set_the_flash(:notice) }
  it { should render_template('data_points/new')}
  it { should assign_to(:data_points, :with => [mock_data_point]) }
end

And this single test checks both that the post action is accessible to users, and also that it is not accessible to visitors. Of course these contexts can get a lot more advanced once different roles come into the picture. Here's something we're doing in our upcoming app KiNumbers:

module LogInContext
  ...

  def as_admin_or_user(params={}, &block)
    as_logged_in_user(params.dup, &block)
    as_admin(params.dup, &block)
    deny_access_to_visitors(params.dup)
  end

  def as_anyone(params={}, &block)
    as_admin(params.dup, &block)
    as_logged_in_user(params.dup, &block)
    as_visitor(params.dup, &block)
  end
end

This way there is no overhead in testing that a particular action is accessible to several different groups of users. Note that we had to call #dup on params, before passing it along, since Remarkable seems to use destructive operations on the Hash (it turned out to be empty after having been used in a describe block).

We ended up with a controller test that looks like this:

require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')

describe DataPointsController do

  mock_models :data_point

  as_admin_or_user(:get => :new) do
    it { should respond_with(:success) }
  end

  as_admin_or_user(:post => :create, :data => "params") do
    before do
      DataPoint.should_receive(:bulk_create).with(@current_account, "params").and_return([mock_data_point])
    end

    it { should set_the_flash(:notice) }
    it { should render_template('data_points/new')}
    it { should assign_to(:data_points, :with => [mock_data_point]) }
  end

end

Short, easy to read, yet also very thorough. Controller tests are sexy again! Spread the word!