Dave Rapin

Mobile and Web Development

Meteor and React - Part 1

This is part one of a series of posts that go through creating a new web app with Meteor and React.

Prerequisites

  1. Meteor
  2. Nodejs
  3. OSX, Linux, or Cygwin.

Why Metor?

We’re always on the lookout for new methodologies in the web stack, and Meteor is one we’ve been keeping an eye on for a while. Here’s what we like about it:

  • Nodejs on the server performs significantly better than some other dynamic stacks like Ruby on Rails.
  • Websockets consume significantly less bandwidth than REST since there is no need to send HTTP headers every time.
  • No need to constantly customize APIs (also something GraphQL would solve).
  • Responding to data changes is straightforward via pub / sub. With React this is even easier.
  • Updating data is straightforward via Meteor methods.

Why React

We love React for it’s simplicity and always use it for our web UIs. Declaritive UI programming is where it’s at.

Code next to Markup was a bad idea right? Not really. As it turns out, having your UI code in your views when they are small (components) makes a ton of sense.

Don’t take our word for it though. Give it a whirl for yourself There’s a decent chance you’ll agree.

The Project Requirements

We’re going to step through building a Hot or Not style of application tailored to sports plays.

The three main components are:

Submit a Play

User should be able to submit a new play. The play will have a title, description, and Youtube URL.

Vote on Plays

User should be able to see two plays and vote for one of them.

Once user has voted for a play, they will be replaced with two new plays that they can then vote on.

There is no limit to the number of plays the user can vote on, however the user may not vote on the same play more than once.

Leaderboard

User should see a list of top ten plays with the most votes, ordered by number of votes descending. This list will update in real time as votes are added.

Getting Started

Create our project:

meteor create tehgosu

This creates a basic Meteor application that we can run right away:

cd tehgosu
meteor

Then visit http://localhost:3000

React and CoffeeScript

Before we can start working on any views, we need to install React since that’s what we’ll be using instead of Blaze.

Adding libraries to Meteor is super simple:

meteor add react

We personally prefer CoffeeScript over JavaScript due to the readability of significant whitespace. There’s a popular opinion at the moment that CoffeeScript is obsolete now that we have ES6 and Babel. I disagree because I think browsers will eventually support WebAssembly. Once they do we’ll see even more JavaScript alternatives.

meteor add coffeescript

Now we’ll need to do some standard tweaks in order to have React and CoffeeScript play nice without excessive amounts of syntax. First we’ll create a lib folder and add a component.coffee library to it.

mkdir lib
touch lib/component.coffee

In component.coffee we’re going to add a function that we’ll be calling instead of React.createClass

1
2
3
@Component =
  create: (spec) ->
    React.createFactory React.createClass(spec)

Notice the @ symbol used to declare our Component object? CoffeeScript places our code in a closure so as not to pollute the global namespace. In Meteor we need to attach our object to the global namespace using this (@ = this.). This is a little counter intuitive compared to CommonJS style requires, and maybe some day we’ll have a better alternative.

For now @Component makes our object accessible throughout the application.

Now we can create a React component in CoffeeScript like so:

1
2
3
4
TestComponent = Component.create
  render: ->
    div className: 'test-component',
      'Test Component'

The equivalent in JSX without our library would look like this:

1
2
3
4
5
6
7
8
9
TestComponent = React.createClass({
  render: function() {
    return (
      <div class="test-component">
        Test Component
      </div>
    );
  }
});

Project Structure

Now is as good a time as any to setup our basic structure for the application. Meteor has a convention where any code that’s placed within a directory named client will only run on the client. And naturally code in a directory named server will only run on the server.

We want the following directories under the root of the project:

  • lib: Common library functions. These are loaded before the other directories.
  • client: Code that should only be run on the client (browser).
  • server: Code that should only be run on the server.
  • public: Only served to the public. We’ll put our robots.txt and images in here.

    mkdir lib client server public

Let’s remove the initial files that meteor created. We don’t need them.

rm tehgosu.*

Time to Write Some Code

Create a new HTML file in the client directory. Since we’re using React for our views, this will be the only HTML file we need.

vi client/index.html

In this HTML file we just need a div element which react will replace once it’s loaded.

1
2
3
4
5
6
7
<head>
  <title>Teh Gosu</title>
</head>

<body>
  <div id="app">Loading...</div>
</body>

Now we need to attach our React views. Create a new CoffeeScript file in the client directory.

vi client/index.coffee

In this CoffeeScript file we load up our React views and attache them to the DOM.

1
2
3
4
5
Meteor.startup ->
  React.render(
    App({}),
    document.getElementById 'app'
  )

We’re referencing an object called App within the Render method, so we need to build that. Create a new CoffeeScript file in the client directory for it.

vi client/app.coffee

Our new app.coffee is going to hold our top level React component code.

1
2
3
4
5
6
{ h1 } = React.DOM

@App = Component.create
  render: ->
    h1 {},
      'Teh Gosu!'

We’re keeping it simple. All we’re doing is rendering an h1 tag with the text Teh Gosu!. Notice the @ symbol prefix to the App declaration. Again this is because of CoffeeScript’s automatic closure and the fact that Meteor needs the object to be on this to be accessible outside the file.

At this point we should have a working React + Meteor application. Run the server with:

meteor

Then visit http://localhost:3000

You should see Teh Gosu!.

Your directory structure should be:

client
  app.coffee
  index.coffee
  index.html
lib
  component.coffee
server
public

This concludes part one of our Meteor + React series. In part two we’ll add some data and the match view.

Using CoffeeScript With ReactJS

Lately I’ve been using ReactJS a lot to build rich user experiences on the web, and it’s been absolutely great. A huge improvement over AngularJS in my humble opinion.

The only ugly spot with ReactJS is JSX. I can see the appeal of using declarative HTML in templates for readability, but having switched to HAML (and Slim and Jade) long ago, writing HTML feels like a step backwards.

Luckily, using CoffeScript for my ReactJS components and eschewing JSX entirely, we can accomplish a syntax that’s very similar to HAML / Slim / Jade. If you’re not a fan of CofeeScript, HAML variants, or significant whitespace, there’s little chance I’ll be able to convince you otherwise. However if you are a fan of any of those, then it’s worth checking out.

This is the HTML we’ll be converting.

1
2
3
4
5
6
7
8
<div class="jumbotron">
  <div class="container">
    <h1>Hello, world!</h1>
    <p>
      <a class="btn btn-primary btn-lg" href="#" role="button">Learn more »</a>
    </p>
  </div>
</div>

Converting it to Javascript using ReactJS looks like this. It’s pretty verbose.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var Jumbotron = React.createClass({
  render: function() {
    return (
      React.createElement('div', {className: "jumbotron"},
        React.createElement('div', {className: "container"},
          React.createElement('h1', {},
            React.createElement('p', {},
              React.createElement('a', { className: "btn btn-primary btn-lg", href: "#", role: "button" }, "Learn more »")
            )
          )
        )
      )
    );
  }
});

Here’s the JSX version. Quite an improvement I think, but it mixes HTML and Javascript together and that seems a bit messy and most likely throws off your editor’s syntax highlighting.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var Jumbotron = React.createClass({
  render: function() {
    return (
      <div className="jumbotron">
        <div className="container">
          <h1>Hello, world!</h1>
          <p>
            <a className="btn btn-primary btn-lg" href="#" role="button">Learn more »</a>
          </p>
        </div>
      </div>
    );
  }
});

Finally, here’s the CoffeeScript version of the component. At least as succinct as the JSX version, and no mixed syntax or editor issues.

1
2
3
4
5
6
7
8
9
10
11
12
13
{ div, h1, p, a } = React.DOM

Jumbotron = React.createClass
  render: ->
    div className: "jumbotron",
      div className: "container",
        h1 {}, "Hello World"
          p {},
            a
              className: "btn btn-primary btn-lg"
              href: "#"
              role: "button"
              "Learn more »"

For the sake of completeness, here’s a CJSX version (CoffeeScript + JSX). Even more succinct, however again we’re mixing HTML with our CoffeeScript, making it a bit messy and giving you editor issues.

1
2
3
4
5
6
7
8
9
10
Jumbotron = React.createClass
  render: ->
    <div className="jumbotron">
      <div className="container">
        <h1>Hello, world!</h1>
        <p>
          <a className="btn btn-primary btn-lg" href="#" role="button">Learn more »</a>
        </p>
      </div>
    </div>

If you do opt for the straight CoffeeScript route, then there are a few gotchas to keep in mind. If you’ve been using CoffeeScript for a while, then they’re pretty obvious, but can cause grief for newcomers.

Gotcha 1: Optional Curly Braces

CoffeeScript allows you to omit Curly braces on hashes. This can cause readability issues for the next person who comes along to read your code.

1
2
3
4
5
6
7
8
9
10
11
12
13
{ div, h1, p, a } = React.DOM

Jumbotron = React.createClass
  render: ->
    div { className: "jumbotron" },
      div { className: "container" },
        h1 {}, "Hello World"
          p {},
            a {
              className: "btn btn-primary btn-lg"
              href: "#"
              role: "button"
              "Learn more »" }

Gotcha 2: Commas and New lines

CoffeeScript allows you to omit commas between hash assignments and opt instead for indented new lines. Again this can cause readability issues, especially when combined with Gotcha #1 above.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{ div, h1, p, a } = React.DOM

Jumbotron = React.createClass
  render: ->
    div
      className: "jumbotron",
      div
        className: "container",
        h1
          {}
          "Hello World"
          p
            {}
            a
              className: "btn btn-primary btn-lg"
              href: "#"
              role: "button"
              "Learn more »"

Ultimately if you are going to use CoffeeScript for your ReactJS components instead of JSX then it’s probably a good idea to agree upon some conventions with your team on when braces and commas are used. My preference has been to use braces for single line hash assignments, and I’m considering enforcing braces for multiple line attribute assignments w/ React to better separate them from the next element.

Pair Programming Remotely on a VPS

At Pair Shaped we firmly believe that pair working is the future (and the present). However a good part of our team works remotely and this can be a real challenge.

While remote pairing solutions are becoming increasingly popular, as a coder it’s hard to beat the Vim + Tmux combination. It’s simple, fast, and there’s no client OS or application dependencies.

In this post we take you through all of the steps to setup an amazing remote pairing environment using an affordable cloud server (VPS). What this will allow you and your team to do:

  1. Securely share persistent tmux (shell) sessions on a linux box on the cloud.
  2. Watch each other code.
  3. Take turns coding.
  4. Rotate between different persistent pairing sessions with multiple team members all within the same server.

I highly recommend adding voice to the mix whether it’s Skype, Google Voice, or a SIP provider.

For starters, we’ll need a linux box in the cloud. For the server we’re going to go Digital Ocean since it is one of the most affordable options at the time of this post. However, the steps are essentially the same with other hosts like Linode and EC2, so definitely check them out too.

Sign up for an account at Digital Ocean and then create a 512MB droplet running Ubuntu 12.04 x32. If you’re not sure about the hostname option, a good choice would be something like pair.yourcompanydomain.com. Make sure you chose a region that’s close to you and your team to minimize latency.

At this end of this tutorial you can shut you droplet down if you aren’t going to use it, and it’ll only end up costing you a few cents.

Once you’ve created the droplet, you should receive an email from Digital Ocean with your new boxe’s IP address and credentials. For the rest of this post I’ll use a fictional IP. Just substitute the IP you were given as needed.

Open up a terminal if you don’t already have one up and follow along with these commands to setup and install the basics.

Basic Server Setup

# Log into your droplet and enter the provided password when prompted.
ssh root@198.199.xx.x

# Update the system. This will take a little while to complete.
aptitude update
aptitude safe-upgrade

# Install essential build tools, git, tmux, vim, and fail2ban.
aptitude install build-essential git tmux vim fail2ban

# For more details on configuration options for fail2ban start here:
# https://www.digitalocean.com/community/articles/how-to-protect-ssh-with-fail2ban-on-ubuntu-12-04

Next we’ll need to setup user accounts for our pair. You can of course setup as many users as you want and run multiple tmux sessions, but that’s the topic of a future post.

Follow along with these commands, substituting your preferred usernames for “dave” and “dayton”.

Create Your Pairs

# Create the wheel group
groupadd wheel
visudo
# Add the following line to the bottom of the file
%wheel ALL=(ALL) ALL
# Save and quit. (:wq)

# Create our pair users
# You'll want to substitude your own usernames for dave and dayton
adduser dave
adduser dayton

# Add them to the wheel group
usermod -a -G wheel dave
usermod -a -G wheel dayton

Now that we have your users setup with full rights (this is something you may want to change down the road), we can disable the root account and instead use a pair account.

Secure the Server

# Copy your shh key to the server
scp ~/.ssh/id_rsa.pub dave@198.199.xx.x:

# Login to your account
ssh dave@198.199.xx.x

# Enable ssh access using your rsa key
mkdir .ssh
mv id_rsa.pub .ssh/authorized_keys

# Now you should be able to ssh to the server using your key. Go ahead and try it. 
exit
ssh dave@198.199.xx.x
# If you have to enter a password, something went wrong. Try these steps again.

# Edit the sshd config
sudo vi /etc/ssh/sshd_config
# Disable root login
PermitRootLogin no
# Save and quit. (:wq)

# Reload ssh
sudo reload ssh

Now we have a fairly secure server with our pair accounts using password-less access and it’s time to setup the pairing environment. We’re going to use wemux which is backed by tmux to manage the sessions.

Wemux Installation

# Install wemux
sudo git clone git://github.com/zolrath/wemux.git /usr/local/share/wemux
sudo ln -s /usr/local/share/wemux/wemux /usr/local/bin/wemux
sudo cp /usr/local/share/wemux/wemux.conf.example /usr/local/etc/wemux.conf

# Change the host_list value to your pair usernames
sudo vim /usr/local/etc/wemux.conf
host_list=(dave dayton)
# Save and quit (:wq)

You are now the proud owner of a remote pairing environment.

Start pairing

It’s time to take it for a spin and make sure everything’s copasetic.

# Launch a shared tmux session.
wemux

You should now be running in a shared tmux session. One of your other accounts (pair2, etc.) can login and use the same command to join your session.

You will definitely want to checkout the wemux documentation for all of the configuration options.

RubyMotion Provisioning Profiles

I recently ran into an issue with RubyMotion where I couldn’t build to a development device without explicitly setting the provisioning profile in the Rakefile. Not only is this annoying, but it’s a big problem for team development because you’ll always want to check your Rakefile into source control and each team member would have a different Rakefile.

So I started hunting for a solution.

Official Documentation is Misleading

The RubyMotion official project configuration documentation states that it look for and use the first provisioning profile it finds on your computer. This is false though, at least when you have multiple profiles, because even if each of your profiles contains the device UID you’re building to, this still won’t work.

Existing Solutions Insufficient

The existing solutions are simply to explicitly refer to your provisioning profile in your Rakefile. That’s OK for solo development (but still annoying), however it’s not a good solution for team development.

See this stackoverflow Discussion

My Solution

After a little light reading I discovered that the RubyMotion build will check for a default profile named “iOS Team Provisioning Profile”.

So we simply need to create a new provisioning profile via the iOS provisioning portal named “iOS Team Provisioning Profile” and containing the device(s) we want to be able to run development builds on.

iOS Development With Ruby Motion

I’ve been building an iOS app with RubyMotion for a while now, and the verdict is…

I’m in love with RubyMotion.

Here’s why:

  • Ruby syntax runs circles around Objective-C syntax. If you’ve used Ruby and Objective-C for anything significant, and you’re not a masochist, then you know what I’m talking about.
  • It already has some amazing libraries like Teacup, BubbleWrap, and Formotion.
  • Building and deploying is a cinch with Rake. There’s even a testflight gem.
  • Bundler and CocoaPods for dependency management.
  • The REPL. I actually haven’t found this that big of a deal, but it can come in handy now and then.
  • I can continue using a text editor (vim or Sublime Text) instead of that hog called Xcode.
  • Really small archives.
  • The only (minor) downside so far has been occasionally translating example Objective-C code to RubyMotion code from Apple’s docs and Stack Overflow.