Episode #454 - April 8th, 2014

Posted 4 months back at Ruby5

On today's episode: Rails 4 PostgreSQL integration, tips for hiring great software engineers, Ruby Love, what your conference proposal is missing, crafting a conference talk, an introduction to JSON schemas, Build a Ruby Gem, and Surviving APIs with Rails

Listen to this episode on Ruby5

Sponsored by Top Ruby Jobs

If you're looking for a top Ruby job or for top Ruby talent, then you should check out Top Ruby Jobs. Top Ruby Jobs is a website dedicated to the best jobs available in the Ruby community.
This episode is sponsored by Top Ruby Jobs

Rails 4 PostgreSQL Integration

One of the improvements in rails 4 was increased access to PostgreSQL features such as HSTORE, Arrays, and UUIDS as primary keys. If you haven’t had a chance to dive into these features, Yousef Ourabi wrote up a great post walking you through how to use each of these.
 Rails 4 PostgreSQL Integration

Tips For Hiring Great Software Engineers

The folks at Plataformatec just published a blog post this week about tips for hiring great software developers. Check out this fantastic blog post for more specifics and even a candidate profile template to help you structure your interview.
Tips For Hiring Great Software Engineers

Ruby Love

If you haven’t been reading the RubyLove.io blog, you may want to take a visit. There’s four great articles on writing better Ruby. From Applying Design Patterns to Ruby, to Refactoring code, to using an Ask, Don’t tell policy with Ruby.
Ruby Love

What Your Conference Proposal Is Missing

Sarah Mei just published a blog post called What Your Conference Proposal Is Missing, which covers how to write a proposal, moving past the basics into some techniques you can use to boost your proposal to the top of the pile.
What Your Conference Proposal Is Missing

Crafting a Conference Talk

Once you’ve written your conference proposal (and been accepted!), you might be looking for advice on how to actually write your conference talk. Justin Searls just published a post called Crafting a Conference Talk, which details the process he uses when developing a new talk.
Crafting a Conference Talk

An Introduction to JSON Schema

This week on the CodeMancers blog, Kashyap wrote up a great post on using the json-schema gem, which , as you might imagine allows you to easily validate incoming JSON to ensure it’s formatted correctly, and if not, provide good error feedback.
An Introduction to JSON Schema

Build a Ruby Gem eBook

Brandon Hilkert let us know about an eBook he released last week called Build a Ruby Gem. It is 19 chapters, totaling 136 pages, and its content ranges from how to get started with open source projects to the nitty gritty of configuration patterns in a Ruby gem.
Build a Ruby Gem eBook

Surviving APIs with Rails

Last week here at Code School we released our Surviving APIs with Rails course, taught by Carlos Souza. In the course he’ll teach you how to build and test REST APIs with Rails.
Surviving APIs with Rails

Back to Basics: Writing Unit Tests First

Posted 4 months back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home

The value of unit tests and TDD are well documented. Unfortunately, it's still daunting to start practicing it. Here's a primer.

Our desired code

We need to write a method that:

  • takes a string as an argument
  • reverses the string
  • saves the string to a file on the hard drive
  • returns the reversed string

Our tool and techniques

We'll use RSpec to test our method's output. We'll use red/green/refactor methodology. We'll write unit tests that are fast, isolated, repeatable, self-verifying, and timely.

Starting with desired end state

What's a good first test we can write? We know that given a particular input (a string "example string") should product a given output (the string "gnirts elpmaxe"):

describe StringChanger do
  it 'reverses strings' do
    string_changer = StringChanger.new

    reversed_string = string_changer.reverse_and_save('example string')

    expect(reversed_string).to eq 'gnirts elpmaxe'
  end
end

Now let's run our test. We'll use the documentation format, which is more verbose, but for the sake of this example will give us more information about the tests:

% rspec string\_mixer\_upper\_spec.rb --format documentation

We get the following output:

string\_mixer\_upper\_spec.rb:3:in `<top (required)>':
uninitialized constant StringChanger (NameError)

The test is telling us to create a StringChanger class. Let's write it:

class StringChanger
end

When we run our test, we get this output:

StringChanger
  reverses strings (FAILED - 1)

Failures:

  1) StringChanger reverses strings
     Failure/Error: reversed_string = string_changer.reverse_and_save('example string')
     NoMethodError:
       undefined method `reverse\_and\_capitalize'
       for #<StringChanger:0x007fafe5c66ff0>
     # ./string_mixer_upper_spec.rb:8:in `block (2 levels) in <top (required)>'

Finished in 0.00032 seconds
1 example, 1 failure

Failed examples:

rspec ./string\_mixer\_upper\_spec.rb:5 # StringReverAndSave reverses strings

Our test is telling us we need to write a method called reverse_and_save. Let's write it:

class StringChanger
  def reverse_and_save(string_to_reverse)
  end
end

We run our test again:

StringChanger
  reverses strings (FAILED - 1)

Failures:

  1) StringChanger reverses strings
     Failure/Error: expect(reversed_string).to eq 'gnirts elpmaxe'

       expected: "gnirts elpmaxe"
            got: nil

       (compared using ==)
     # ./string_mixer_upper_spec.rb:10:in `block (2 levels) in <top (required)>'

Finished in 0.00301 seconds
1 example, 1 failure

Failed examples:

rspec ./string\_mixer\_upper\_spec.rb:5 # StringChanger reverses strings

The simplest thing that could work

Our test is telling us our method's logic does match expectations. Let's make it pass:

class StringChanger
  def reverse_and_save(string_to_reverse)
    'gnirts elpmaxe'
  end
end

We run our test:

StringChanger
  reverses strings

Finished in 0.00079 seconds
1 example, 0 failures

Refactoring

We have a passing test, but there is a smell we can refactor out. Currently we are returning a hardcoded value. This obviously will not work. Let's do a little refactor and then depend on our tests to tell us if things are still good:

class StringChanger
  def reverse_and_save(string_to_reverse)
    string_to_reverse.reverse
  end
end

We run our test:

StringChanger
  reverses strings

Finished in 0.00079 seconds
1 example, 0 failures

Our test still passes but our method is not fully functional until we write our reversed string to a file.

Stubbing dependencies such as the file system

We're writing a unit test, which should be isolated. We don't want to create a new file every time we run our test, so we stub it out.

The RSpec Mocks library gives us the ability to send the stub message to an object and replace the method we're stubbing with a dummy method that doesn't do anything:

it 'saves string to the file system' do
  string_changer = StringChanger.new
  File.stub(:write)

  string_changer.reverse_and_save('example string')

  expect(File).
    to have_received(:write).
    with('example_file', 'gnirts elpmaxe').
    once
end

We expect the File object to receive the message write one time with the arguments 'example_file' and our reversed string by using the stub's ability to report on the messages it's received. This is called white-box testing.

We run our test:

StringChanger
  reverses strings
  saves string to the file system (FAILED - 1)

Failures:

  1) StringChanger saves string to the file system
     Failure/Error: expect(File).to have_received(:write).with('example_file', 'gnirts elpmaxe').once
       (<File (class)>).write("example_file", "gnirts elpmaxe")
           expected: 1 time with arguments: ("example_file", "gnirts elpmaxe")
           received: 0 times with arguments: ("example_file", "gnirts elpmaxe")
     # ./string_mixer_upper_spec.rb:19:in `block (2 levels) in <top (required)>'

Finished in 0.00106 seconds
2 examples, 1 failure

Failed examples:

rspec ./string\_mixer\_upper\_spec.rb:13 # StringChanger saves string to the file system

Our test is telling us to invoke the File object's write method. Let's write it:

class StringChanger
  def reverse_and_save(string_to_reverse)
    File.write('example_file', string_to_reverse.reverse)
  end
end

We run our test:

StringChanger
  reverses strings (FAILED - 1)
  saves string to the file system

Failures:

  1) StringChanger reverses strings
     Failure/Error: expect(reversed_string).to eq 'gnirts elpmaxe'

       expected: "gnirts elpmaxe"
            got: 14

       (compared using ==)
     # ./string_mixer_upper_spec.rb:10:in `block (2 levels) in <top (required)>'

Finished in 0.00136 seconds
2 examples, 1 failure

Failed examples:

rspec ./string\_mixer\_upper\_spec.rb:5 # StringChanger reverses strings

We made our new test pass but broke our old test because we are no longer returning the reversed string. This shows the benefit of old tests helping guard against regressions in our code.

Let's fix our original test:

class StringChanger
  def reverse_and_save(string_to_reverse)
    string_to_reverse.reverse.tap do |reversed_string|
      File.write('example_file', reversed_string)
    end
  end
end

We run our test:

StringChanger
  reverses strings
  saves string to the file system

Finished in 0.0011 seconds
2 examples, 0 failures

We now have two passing tests and a fully functional method. We did it writing the tests first. This is a simple example, but by following this process, we can conquer any sized programming task. Writing the tests first will also help us write testable code and help us keep our methods small.

What's next?

If you found this useful, you might also enjoy:

How to get an A+ on the Qualsys SSL Labs test

Posted 4 months back at mir.aculo.us - Home

Recently we upgraded our server infrastructure for Freckle Time Tracking and in the process wanted to improve how we serve SSL.

If you don’t know much about this, it’s fine—there’s a few simple steps you can take to make your website more secure and faster loading in the process. _Important: of course, there’s no absolute security, and I make no claim that what I describe here is secure and will work for you. Use it at your own risk._

Long story short, you’ll want to get an A+ rating on the Qualsys SSL Labs test.

For that you’ll need to do the following:

  • Don’t support older protocols. A lot of servers support really old and obsolete protocols. If you run a web app, your users will very likely not need support for these.
  • Don’t support flawed SSL ciphers. There’s a bunch of these and you can avoid using them. Browsers support multiple different ciphers, so this is not a problem.
  • Cache SSL sessions. This will improve performance.
  • Turn on HTTP Strict Transport Security (HSTS). This is a special header that will tell browsers to never connect to the server via normal HTTP.

And that’s it. In order so you don’t need to research the proper settings, here’s how this looks like in form of an nginx configuration:

server {
  # deferred allows for faster connections if there's
  # no other servers on port 443 defined
  listen 443 ssl spdy deferred;

  ssl on;
  ssl_certificate /etc/nginx/your-certificate.crt;
  ssl_certificate_key /etc/nginx/your-private-key.key;

  ssl_prefer_server_ciphers on;
  ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS:!AES256;
  ssl_session_cache shared:SSL:10m;
  ssl_session_timeout 10m;
  ssl_stapling on;

  # tell any upstream things like unicorns that we're on https
  proxy_set_header X-Forwarded-Proto 'https';
  underscores_in_headers on;

  location / {
    add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";
    # ...
  }

  # ...
}

And that’s it. Have fun with your new A+ rating on the SSL labs test.

Episode #453 – April 4th, 2014

Posted 4 months back at Ruby5

On today's episode, PDF generation options, some Ruby 2.1 garbage collection "discussion", CDN performance, an edge Rails treat, and a new book from Thoughtbot. Also, your intrepid hosts take their final bow.

Listen to this episode on Ruby5

Sponsored by New Relic

New Relic is _the_ all-in-one web performance analytics product. It lets you manage and monitor web application performance, from the browser down to the line of code. With Real User Monitoring, New Relic users can see browser response times by geographical location of the user, or by browser type.
This episode is sponsored by New Relic

PDF Generation in Rails

Joyce Echessa has a written a blog post that goes over how to use three PDF generation gems in Ruby: Prawn, PDFKit, and Wicked PDF.
PDF Generation in Rails

Ruby 2.1 Garbage Collection

Tim Robertson started a spirited conversation on the topic of garbage collection in Ruby 2.1 with this blog post on the Omniref blog.
Ruby 2.1 Garbage Collection

Mobile CDN Performance

Ilya Grigorik answers the question: Why is my CDN 'slow' for mobile clients? Spoiler: it is not.
Mobile CDN Performance

ActiveRecord::Enum

Edge Rails recently introduced Active Record enums for those columns that have a pre-defined set of values.
ActiveRecord::Enum

iOS on Rails

Thoughtbot are soon to pop with a new reference book titled, "iOS on Rails". You can get a discounted beta version now.
iOS on Rails

Removing Sass Duplication Using Sass Maps

Posted 4 months back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home

Recently Dan asked me to get new icons for Raleigh, New York City, and Austin added to some of our landing pages.

Original Icons

Once I created the icons, I checked out the site to put them in below the offices that have already been on the marketing pages. It looked like this:

&#boston:after {
  background: url('/img/icon_boston.png') no-repeat center top;
}

&#denver:after {
  background: url('/img/icon_denver.png') no-repeat center 42px;
}

&#sanfran:after {
  background: url('/img/icon_sf.png') no-repeat center 54px;
}

&#philly:after {
  background: url('/img/icon_philly.png') no-repeat center 42px;
}

&#stockholm:after {
  background: url('/img/icon_stockholm.png') no-repeat center 45px;
}

@media
(-webkit-min-device-pixel-ratio: 2),
(min-resolution: 192dpi) {

  &#boston:after {
    background: url('/img/icon_boston@2x.png') no-repeat center top;
    background-size: 97px 112px;
  }

  &#denver:after {
    background: url('/img/icon_denver@2x.png') no-repeat center 42px;
    background-size: 160px 71px;
  }

  &#sanfran:after {
    background: url('/img/icon_sf@2x.png') no-repeat center 54px;
    background-size: 210px 59px;
  }

  &#philly:after {
    background: url('/img/icon_philly@2x.png') no-repeat center 42px;
    background-size: 66px 85px;
  }

  &#stockholm:after {
    background: url('/img/icon_stockholm@2x.png') no-repeat center 45px;
    background-size: 93px 67px;
  }
}

Look at all that repetition! That's almost 50 lines of Sass. Adding new offices to that list would add even more to the repetition. I wanted to get rid of all the repetition and make it really easy to add new offices if we need to in the future. I started off by putting all our offices in a variable then looped through them and used some interpolation to assign the right icon to the right city.

$offices: boston, denver, sanfran, philly, stockholm, new-york, raleigh, austin;

@each $city in $offices  {
  &##{$city}:after {
    background-image: url('/img/icon_#{$city}.png');
    background-position: center 42px;
    background-repeat: no-repeat;

    @if $city == 'boston' {
      background-position: center top;
    }

    @if $city == 'new-york' {
      background-position: center top;
    }

    @if $city == 'sanfran' {
      background-position: center 54px;
    }

    @if $city == 'austin' {
      background-position: center 24px;
    }

    @if $city == 'raleigh' {
      background-position: center 28px;
    }
  }

  @include hirez-screen {
    &##{$city}:after {
      background-image: url('/img/icon_#{$city}@2x.png');
      background-size: 97px 112px;
    }
  }
}

There's still some repetition in that loop with different positioning for each of the icons. Each of the cities that I am overriding the position is getting two lines of positioning when one will do. I figured that there had to be a better way to handle to the differing positions in Sass too.

Luckily for me, Sass 3.3 was released with Sass maps while I was designing the new icons. Connie suggested I try putting the offices into a map with their respective y-position. I went back to my list of offices and converted it to a map.

$offices: (boston: top, denver: 42px, sanfran: 54px, philly: 42px, stockholm: 42px, new-york: top, raleigh: 28px, austin: 24px);

Then went back to my @each loop and changed it around to account for the map.

@each $city, $y-position in $offices  {
  &##{$city}:after {
    background-image: url('/img/icon_#{$city}.png');
    background-position: center $y-position;
    background-repeat: no-repeat;
  }

  @include hirez-screen {
    &##{$city}:after {
      background-image: url('/img/icon_#{$city}@2x.png');
      background-size: 97px 112px;
    }
  }
}

Now we're talking. It's really compact and there's no repetition.

New Icons

What's new in edge Rails: Active Record enums

Posted 4 months back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home

In an Active Record model, usually you will have a column that can only have a set of pre-defined values (such as a status column). Normally, you would define a constant for those values as well as several helper methods like the following example:

class Post < ActiveRecord::Base
  STATUS = %w(draft published)

  def draft?
    status == 'draft'
  end

  def published?
    status == 'published'
  end
end

In the upcoming Rails 4.1.0, the core team has added ActiveRecord::Enum support, which help clean up this type of attribute. With enum, you can rewrite the above code as:

class Post < ActiveRecord::Base
  enum status: %w(draft published)
end

With this single line of code, Rails will generate several helper methods for you:

# Query method
post.draft?
post.published?

# Action method
post.draft!
post.published!

# List of statuses and their corresponding values in the database.
Post.statuses

There is one gotcha which you might notice since this is called enum: you will need to update your database column to be an integer value. Rails will do implicit mapping between the integer value and the index of the value in the array automatically.

# Given that the `status` column has default value of '0'
post = Post.new
post.status # => "draft"

post.status = 'published'
post.published? # => true
post.save! # => UPDATE posts SET status = '1' WHERE id = '1'

If you are interested in trying out this feature, you can try it today on Rails 4.1.0.rc2. Be sure to read the documentation and release notes for more information. If you find any bugs, please do not forget to report them on Ruby on Rails GitHub issues.

Our Internet

Posted 4 months back at mir.aculo.us - Home

Our Internet isn’t big corporations doing whatever they want. Our Internet is not DRM, is not SOPA and not PIPA and not the spying on us (and everyone else). Our Internet isn’t bigots taking away human rights from people. Our Internet isn’t hiding being PR releases.

Our Internet isn’t greed, narcissism, fear and blind hate.

Our Internet is people helping each other be excellent. It’s sharing, caring and being proud of what we humans can do if we only put our will to it. It’s about helping the unprivileged when governments fail. Our Internet is about standing up to your mistakes.

Our Internet is about love and empathy.

The only thing we have is each other.

That is all.

Kestrel

Posted 4 months back at Mike Clark

Kestrel

This American Kestrel gave me a pose from atop one of his favorite hunting perches. The natural world has some amazing color palettes!

Giving Chase

Posted 4 months back at Mike Clark

Giving Chase

It's fairly late in the season to see bald eagles around here, but we'll enjoy it while it lasts. These juveniles were playing chase around the bay.

Episode #452 - March 28th, 2014

Posted 4 months back at Ruby5

Supersonic API stubbing with Mock5, visit tracking in your app with Ahoy, lexical analysis with lexeme, Rails 4.1.0 RC2, code ping pong with DHH, and 12 small ruby web frameworks all in this episode of the Ruby5!

Listen to this episode on Ruby5

Sponsored by New Relic

New Relic is _the_ all-in-one web performance analytics product. It lets you manage and monitor web application performance, from the browser down to the line of code. With Real User Monitoring, New Relic users can see browser response times by geographical location of the user, or by browser type.
This episode is sponsored by New Relic

Mock5

Tired of working around recorded API responses in your test suite? Need to stub out APIs in development with supersonic speed? Take a look at the mock5 gem from Rocketeer Pavel Pravosud!
Mock5

Ahoy

Simple, powerful visit tracking for Rails.
Ahoy

lexeme

Lexeme is a lexical analyzer written in Ruby. It lets you tokenize everything from mathmatical expressions to natural language with a simple API.
lexeme

Rails 4.1.0 Release Candidate 2

This is intended as the last stop before the final version of Rails 4.1.0 hits the virtual presses.
Rails 4.1.0 Release Candidate 2

Code Ping Pong with DHH

Submit your code. Get a response from DHH. Profit.
Code Ping Pong with DHH

12 Small Ruby Web Frameworks

You know about Rails and Sinatra, but had you heard of the menagerie of other Ruby web frameworks? This blog post takes you on a whirlwind tour of 12 of them!
12 Small Ruby Web Frameworks

Thread Safety With Ruby

Posted 4 months back at Luca Guidi - Home

Moore’s law is over. Modern computation is exploited by running processes on multiple cores. Ruby has always ignored this trend, and the community didn’t put enough attention on this topic.

Ruby’s model for concurrency is based on threads. It was typical approach for object oriented languages, designed in the 90s. A thread is sequence of instructions that can be scheduled and executed in the context of a process. Several threads can be running at the same time.

Ruby’s VM process allocates a memory heap, which is shared and writable by threads. If incorrectly coordinated, those threads can lead to unexpected behaviors.

Thread Safety

We define as thread safe a code that behaves correctly when accessed by many threads at the time. Most of the time, the correctness of execution is determined by the state of the memory that is visible by a routine in a given moment. For instance, a variable appears with a certain value, but in the meantime another thread may have changed it.

x = 0

10.times.map do |i|
  Thread.new do
    puts "before (#{ i }): #{ x }"
    x += 1
    puts "after (#{ i }): #{ x }"
  end
end.each(&:join)

puts "\ntotal: #{ x }"

What happens here? When the threads are starting they see the initial value of x. But when each of them, try to add +1, the value became different as result of the parallel computation. Without a proper synchronization, the partial state of x is unpredictable.

% ruby count.rb
before (2): 0
before (0): 0
before (1): 0
after (1): 3
before (5): 1
before (7): 1
after (2): 1
after (0): 2
before (4): 1
after (5): 4
after (7): 5
before (9): 1before (3): 1
before (8): 1
before (6): 1
after (4): 6

after (9): 10after (3): 7
after (6): 9

after (8): 8

total: 10

When the thread (3) started, x was equal to 1, but after adding +1 its value was 7.

Visibility

We met an important issue here: visibility. If the changes caused by a thread are observable by other threads, they can read the correct value, and then partial state is consistent.

Until now, we omitted an important aspect: which kind of variables are we referring to? We are talking about of all that represent a state of the system in a given moment. Global, class and instance variables require attention, when used in a concurrent context.

Local variables are exempt from these problems, because they don’t hold a state.

From this picture, we can infer that stateless programs are always thread safe.

Atomicity

Yet, stateful systems can be thread-safe. What’s important isn’t only what changes (_visibility_) but how it changes (_atomicity_). If we design write operations in a way that while they’re running, other threads can’t read nor alter the state we’re modifying, that change is thread safe.

We call these operations atomic, because their execution appear as indivisible to the rest of the system.

x, mutex = 0, Mutex.new

10.times.map do |i|
  Thread.new do
    mutex.synchronize do
      puts "before (#{ i }): #{ x }"
      x += 1
      puts "after (#{ i }): #{ x }"
    end
  end
end.each(&:join)

puts "\ntotal: #{ x }"
% ruby count.rb
before (2): 0
after (2): 1
before (1): 1
after (1): 2
before (0): 2
after (0): 3
before (5): 3
after (5): 4
before (6): 4
after (6): 5
before (8): 5
after (8): 6
before (9): 6
after (9): 7
before (3): 7
after (3): 8
before (4): 8
after (4): 9
before (7): 9
after (7): 10

total: 10

By using Mutex, we ensure the atomicity of the add operation.

The following example shows the weakness of a common pattern in Ruby applications: lazy loading via ||=.

##
# Counter is thread safe, we use a Mutex to guarantee the atomicity of #increment!
#
class Counter
  attr_reader :total

  def initialize
    puts 'initialized'
    @total = 0
    @mutex = Mutex.new
  end

  def increment!
    @mutex.synchronize { @total += 1 }
  end
end

##
# Application isn't thread safe, because the initialization of Counter
# happens with a non-atomic operation (`||=`).
#
class Application
  def increment!
    counter.increment!
  end

  def counter
    @counter ||= Counter.new
  end

  def total
    counter.total
  end
end

app = Application.new

10.times.map do |i|
  Thread.new do
    app.increment!
  end
end.each(&:join)

puts app.total
% ruby application.rb
initialized
initialized
1 # wrong

Please note that Counter is thread safe, but the final application isn’t. We have used ||=, which isn’t atomic. This caused a race condition: two threads have seen @counter as nil, and then they have initialized a new instance of it. The result of the computation is wrong.

The right way to write that class is:

class Application
  attr_reader :counter

  def initialize
    @counter = Counter.new
  end

  def increment!
    counter.increment!
  end

  def total
    counter.total
  end
end

As rule of thumb, avoid mutations after an object is being initialized.

Conclusion

In a nutshell, the limitations of Ruby concurrency model are: data mutability and difficult synchronization.

In an upcoming article, I’ll cover how Lotus achieves thread safety.

Welcome Aboard: You're Riding iOS on Rails!

Posted 4 months back at GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home

When I sat down to write my first API with Rails, I was overwhelmed with the abundance of options available to me. From ActiveModel::Serializers to JBuilder to Rabl to simply calling .as_json, just choosing which library to use for rendering JSON was a task in and of itself.

A couple weeks and a Sinatra app later, our team was on its way to building a solid, extensible, well-tested JSON API with Rails.

Half way through the project, Diana, an iOS developer, remarked to me: "Being able to create an API must be so cool! You want a new endpoint and then a few hours later - there it is!"

My response: "Being able to create an iOS app must be so cool! You want a new view and then a few hours later - there it is!"

And then a light went on: what if I, a Rails developer, could create both an API and an iOS app that used that API?

And so an eBook was born.

Introducing the Beta Release of iOS on Rails

iOS on Rails is a book for anyone with some Rails experience and little or no iOS experience.

After reading iOS on Rails, you will be able to create a JSON API with Rails and an iOS app that interacts with that API.

The book covers:

  • Which tools we chose for rendering JSON endpoints and why
  • How to test-drive development of your Rails JSON API
  • How to create JSON endpoints for GET, POST, and PATCH requests
  • How to create geocoded API endpoints
  • How to set up your first iOS app in Xcode
  • How to consume and use API endpoints in an iOS app

As with all our books, your initial purchase of the book gets you all future updates we make. We even give you access to the GitHub repository containing source code for a fully functioning Rails app and a fully functioning iOS app.

This blog post announces the beta release of the book. Once it comes out of Beta, this book will sell for $39. Get your copy of iOS on Rails beta for just $29 today!

Available for Free with Learn Prime

If iOS on Rails interests you, you may want to check out our subscription service, Learn Prime.

Companies

Posted 4 months back at entp hoth blog - Home

Howdy.

Today we are deploying some changes to Companies. Companies are groups of users that have access to each other’s private discussions. This is often used when your product/service is used by multiple people inside a company, and they all need/want to participate in discussions/issues. This is a helpful system, but it was missing one big feature: notifications. So today, we are introducing Notifications for Companies.

So what are the changes:

  • By default, all members of a company will receive notifications about any discussion started (or replied to) by someone else in the company. This will help reduce duplicate reports, and keep everyone in the loop about what’s going on.

  • While “notifications on” will be the default, it can be turned on/off for each company individually. Small companies may want to know about everything, while larger group might just need access. You can change the default on the company page.

  • Each user of a company can set their own preference regarding notifications. This means that if the default for a company is “off”, one particular user may still decide that they want to be notified about everything. On the other hand, if the default is “on”, one or multiple users might not need to be involved all the time and can decide not to receive notifications. We feel that this offers the most flexibility, both for the support site, and for the individual users.

  • Finally, if a user is subscribed to company notifications, they can still unsubscribe from a particular discussion by clicking the “unsubscribe” button or replying #ignore by email.

While notifications are the biggest change, there are also a number of smaller improvements across the board:

  • You can now add/remove a Company as a watcher. When a user who is part of a company creates a discussion or replies to a discussion, the company gets added as a watcher. So if you need to keep the discussion private with only this user, you can simply remove the company and the original user will be the only one with access/notifications.

  • Adding watchers now autocompletes on the “add watcher” widget, as well as on the “new discussion” page, both on the frontend and on the dashboard. And you can add companies directly (or you can add a member of the company, both will work).

    Adding a watcher

  • Users get notified when they are added to a company, and will get links to update their notifications and access all the company discussions. This should make onboarding of new members easier.

  • It is now easier to add an existing user to a company: just go on their profile and select the company in the dropdown.

    Selecting the company

  • You can now see if a user is part of a company in the discussion header: John Doe (Company).

That’s about it. Hope you enjoy the changes! You can find out more about companies in the knowledge base.

Cheers.

Why is my CDN 'slow' for mobile clients?

Posted 4 months back at igvita.com

We're using a CDN but when we look at the performance numbers it appears to be far less effective for mobile clients. We're considering disabling it entirely as we're not sure that it's worth it. Someone needs to build a special CDN for mobile, we'd definitely use that to improve latency!

The frequency with which I've been hearing this and similar arguments has been rapidly increasing as more teams are finally focusing on improving performance of their mobile sites. The problem is, while the statement is often based on real data (i.e. the relative performance improvements offered by a CDN are smaller for mobile clients), the conclusion is wrong: the absolute improvements are likely the same for all clients and hence worth every penny. Also, we don't need a "mobile CDN", we need carriers to fix their networks.

The many components of latency

To understand why the relative metrics between desktop and mobile CDN performance are misleading many otherwise well-informed teams, it helps to take a step back and consider the actual topology of the internet, plus what CDNs can and cannot do. In fact, for sake of a concrete example, let's assume the following:

  • Client is located on the west coast; server is located on the east coast.
  • The propagation latency between west and east US coasts is 50 ms.
  • The server response time is 50 ms.
  • Last-mile latency for "tethered" clients: ~18 ms for fiber, ~26 ms for cable, ~44 ms for DSL.
  • Last-mile latency for "wireless" clients: ~50 ms for 4G, ~200 ms for 3G.

The total time to service the request is a combination of all of the latencies in both directions: last-mile → coast to coast (50 ms) → server response (50 ms) → coast to coast (50 ms) → last-mile. For example, if the client happens to be on a fiber connection with a 18 ms last-mile path, then the total time is 18+50+50+50+18, or 186 milliseconds.

The last-mile latencies we're using above are specific to the US and are courtesy of the Measuring Broadband America report (FCC, 2013). Sadly, FCC has not yet published any similar reports for US mobile carriers. As a result, the ~50 and ~200ms numbers are based on specified and cited targets of existing US carriers.

Accelerating content delivery with a CDN

The whole premise of a CDN is to move the bytes as close to the user as possible and to do so CDNs deploy cache servers within various data centers and peering points around the globe. In other words, in the optimal case the CDN servers are located immediately outside the ISP / carrier network: the client makes a request, incurs the cost of last-mile latency to exit the ISP / carrier network and immediately hits a CDN server that returns a response. As a result, CDN minimizes the propagation latency and if a static resource is served, also reduces the server response time by returning a cached asset.

To continue with our earlier example, let's assume that our CDN server is optimally placed (~5 ms path instead of 50 ms coast-to-coast path) and that we are requesting a publicly cacheable asset that can be served by the CDN (~5ms) without hitting the origin. For our fiber client, the new total time is the sum of the last-mile roundtrip plus the CDN response times: 18+5+5+5+18, or 51 ms in total. As a result, adding a CDN took our request time from ~186ms down to ~51ms: a 365% improvement in total latency!

Last-mile Coast-to-Coast Server Response Total (ms) Improvement
Fiber 18 50 50 186
Cable 26 50 50 202
DSL 44 50 50 238
4G 50 50 50 250
3G 200 50 50 550
CDN + Fiber 18 5 5 51 -135 ms (365%)
CDN + Cable 26 5 5 67 -135 ms (301%)
CDN + DSL 44 5 5 103 -135 ms (231%)
CDN + 4G 50 5 5 115 -135 ms (217%)
CDN + 3G 200 5 5 415 -135 ms (133%)

Repeating the same calculation for each connection profile reveals an unfortunate trend: the relative effectiveness of the CDN "declines" as the last-mile latency increases. If you consider the topology of where the CDN servers are typically placed this makes perfect sense: CDN servers are outside the ISP network. That said, note that the absolute latency improvement is still the same regardless of the last-mile profile.

CDNs help minimize propagation and server response times. If your only metric is the relative before and after improvement, then it would appear that a CDN is not doing much for mobile clients - e.g. a mere 33% improvement for 3G clients. In reality, the savings are the same, and the real takeaway is that the last-mile latency of most mobile carriers dominates all other latencies of the resource transfer - yes, a rather sad state of affairs.

Operational and business costs of living at the edge

One obvious strategy to improve the end-to-end latency is to move the cache servers even closer to the client: instead of positioning them outside the ISPs network, could we move them inside? In principle, the answer is yes, and many ISPs already deploy their own cache servers. However, in practice, this is a tricky problem.

First, the number of peering points is relatively small, which allows CDNs to deploy in dozens of well known locations around the globe to provide their service. Also, to do so, they don't have to do any special deals with individual ISPs: typically, the servers are deployed in shared data centers (peering points). By contrast, moving servers into the ISP network would require individual deals with each ISP - not impossible, but obviously a much harder operational and business problem.

For the sake of argument, let's say a CDN does strike a deal with an ISP. Now the CDN needs to deploy many more servers, and ideally as close to their customers as possible (near the radio towers and other aggregation points). Doing so would require a lot of hardware, makes maintenance and upgrades an operations nightmare, and opens a lot of security questions - e.g. would you deploy a TLS termination node within a third-party operated network that you don't have direct access to? In short, it's a cost, security, and a logistics nightmare.

That's not to say this can't be done. Many ISPs have long been trying to move "upmarket" and provide CDN functionality. However, ISPs have a different problem: it's very hard for them to sign clients because most sites are not interested in signing individual deals with every ISP on the planet. In recent news, Verizon acquired EdgeCast... It remains to be seen what they do with it and if this will actually benefit Verizon clients.

Business and operational costs aside, there is nothing particularly special about optimizing CDNs for mobile clients. The root problem is that the last-mile latency of mobile carriers is atrocious - that's what we need to fix. Instead of pushing cache servers closer to the edge, we need transparency into performance of these networks, and we need more competition between carriers to address the underlying last-mile performance problems.

CDNs are not slow for mobile, use them

In short, there is no reason why CDNs are inherently 'slower' for mobile clients: don't confuse relative gains with absolute savings. That said, the actual performance will obviously vary for each CDN provider based on location of their servers and connectivity with various mobile carriers - measure, gather real data, optimize.

The Phusion founders’ PGP keys have been updated

Posted 4 months back at Phusion Corporate Blog

Phusion takes security very seriously. This is why we strongly believe in protecting the authenticity and integrity of our communications and our software, and why we employ the use of PGP digital signatures. Using our PGP keys, you can verify the authenticity and integrity of all emails and files that we publish to you or to the world. All software releases that we make are signed with one of our PGP keys.

The founders’ keys have changed

As Phusion’s founders, we – Hongli Lai and Ninh Bui – have our own personal PGP keys as well, which we use to encrypt or sign some of our emails and git commits. We’ve recently run a security audit and noticed that our PGP keys are no longer deemed as secure as they should be. The keys that we’ve been using until today were made back in 2009, but the recommended algorithms and key sizes in 2014 are quite different from what they were 5 years ago. For this reason, we’ve decided to revoke our old keys and to create new ones, with stronger security settings.

Nothing has been compromised. We are simply renewing our keys as a precaution.

Effective immediately, our new PGP keys are as follows:

  • Hongli Lai (hongli@phusion.nl)
    Short key ID: 8C59158F
    Long key ID: CD70085E8C59158F
    Fingerprint: 218A 7255 83D0 2ECE F3A9 C2A7 CD70 085E 8C59 158F
  • Ninh Bui (ninh@phusion.nl)
    Short key ID: 69481265
    Long key ID: AE405F7869481265
    Fingerprint: A77C 9CEF 766D 0E7D A95B 8778 AE40 5F78 6948 1265

If you had our old keys in your keyring, please update them so that you see the revocations:

gpg --refresh-keys --keyserver pool.sks-servers.net
# -OR-
gpg --refresh-keys --keyserver keyserver.ubuntu.com

No effect on the signatures of our file releases

Please note that Phusion’s software releases and Ruby gems are not signed with our personal keys. Instead, they’re signed with the Phusion Software Signing key, which is still considered strong enough.

Our git commits, though, are often signed with our personal keys.

If you’re using Phusion Passenger, we strongly recommend you to cryptographically verify every release. The Phusion Passenger documentation contains comprehensive instructions that explains how you can verify our tarballs, Ruby gems, Git commits and more.

Onward and upwards!

With kind regards,
Hongli Lai
Ninh Bui