Rack and Session Store

A fellow asked me how he could store information per-user in Rack. This was my (brief) response:


Generally with the cookies object. Specifically, Rack has a "session", which encodes a session identity into the cookies object, usually with some or all of your data.

You can also map from the session ID to data on the server side, with what Rails calls a "session store". Rack comes with a few session stores (cookies, MemCache, pool) and Rails comes with more. Here are some useful links:

Your welcome message will contain a download link.
Posted: about 1 month ago (2013-04-01 12:53:39 UTC) / Updated: about 1 month ago (2013-04-01 12:55:04 UTC)

Order Muppet Programmers, Chaos Muppet Programmers

Have you read the Slate magazine article about whether you're an Order Muppet or a Chaos Muppet?

Did you know that programmers and programming languages have their own Muppet Chaos Theory?

Like in all of life, you can incline to order or chaos. Specifically, consider the Java tenets that other people shouldn't ever be able to screw you up, all development must be done in an IDE and you need a four-or-more-level directory hierarchy before you're allowed to write "Hello, World." Can you think of anything more Sam the Eagle?

Whereas in Ruby you can change the definition of any operation on any object anywhere, as late in the process as you want. Feel like changing the definition of "plus" fifteen minutes after your server starts? Knock yourself out. It is, let us say, a somewhat more Swedish Chef approach.

In many cases, that explains a lot of culture clash. If you read the Ruby spec and a fair bit of Python docs, you could be forgiven for not seeing a nickel's worth of difference in the semantics (not syntax) between them. But Python says "there should be one—and preferably only one—obvious way to do it". Can you say "Order Muppet"? It's a clash not based on language semantics, but on Muppet Type.

Does that mean if you write in Ruby you're a Chaos Muppet? Not necessarily, but it's a good indicator.

Or that if you write in Java that you're an Order Muppet? I'm afraid so. You'll need to get used to your place next to Sam the Eagle, Bunsen Honeydew and Bert.

It's not so bad. Just make sure to find the right Chaos Muppet as a partner and maybe there will be cookies for everyone anyway!

Your welcome message will contain a download link.
Posted: about 1 month ago (2013-03-31 04:17:56 UTC) / Updated: about 1 month ago (2013-03-31 04:19:58 UTC)

Free and Cheap Rails Training

On a local meetup list, somebody asked about cheap ways to learn Ruby on Rails stuff at a university's level of quality.

My response:

You'll see a lot of private (i.e. non-university, often offered by individuals) training. "University-level" is always arguable -- what university do you mean? And do you mean equal per-hour or equal to a full elite four-year program?

Marc-Andre Cournoyer's "Owning Rails" course costs around $500 when it's offered, and I'd consider it hour-for-hour the equivalent of a university course.

My own Rebuilding Rails book, while it's not a class, can be had for $40 (eventually $50), and I've literally taught Ruby on Rails at Carnegie Mellon's Silicon Valley campus, so presumably my work is also "university-level". You can also get the early bits of that for free in a couple of ways -- you can download the first few chapters of my book in return for your email address, or you can watch my Ruby Hangout presentation, also very similar to the early content there, for free.

Michael Hartl's amazing Rails tutorials are free if consumed in HTML. They're beginner-level and very, very good. CMU uses them, too, so I'm going to refer to them as "university-level" as well.

ConFreaks records every talk at every major Ruby conference and makes them all available for free. The best of those are easily university-level content. The worst aren't terrible and cost you only an hour of your time.

RailsCasts and PeepCode aren't free, but they're cheap.

Again, you can get a lot of excellent content for free or cheap these days in return for the time spent to go find it.

You can pay to eliminate the need for time and initiative on your part to bootstrap you into a very lucrative career. That is, without reasonable question, worth money. Or you can do the same thing for yourself, which will take longer -- but I promise you, the content is out there.

Your welcome message will contain a download link.
Posted: 2 months ago (2013-03-24 23:33:09 UTC)

How to Create XKCD-Style Charts Using Rickshaw

I recently wrote a post on the Ooyala engineering blog about how to create an XKCD-style Rickshaw renderer with the wobbly lines.

I think it's a pretty cool trick.

Your welcome message will contain a download link.
Posted: 2 months ago (2013-03-24 12:45:30 UTC)

Building Ruby Castles in the Clouds

Sebastian Marshall interviewed me recently. I think it came out great!

Building Ruby Castles in the Clouds is the name of the interview.

We're also running a GiveGetWin deal with copies of my book for $15, with proceeds going to charity. Been looking for a deal on Rebuilding Rails? Now is the time.

Your welcome message will contain a download link.
Posted: 2 months ago (2013-03-14 19:56:23 UTC)

Could Not Fetch Specs From https://rubygems.org/

Are you getting this error from Bundler?

(Short version: if using rvm, do "rvm pkg install openssl; rvm reinstall all --force --with-openssl-dir=$rvm_path/usr")

You could edit the live copy of lib/bundler/fetcher.rb to print out the exception -- and when you do, you might see it's a "bad ecpoint" problem in OpenSSL.

You won't have much luck Googling it, because it only happens when internal OpenSSL code fails in an obscure way, in assembly, only on certain versions of GCC on the Mac.

If that happens, switch to a less-bad version of OpenSSL. You may (or may not) have luck installing the Homebrew version and configuring Ruby to use it.

But I use RVM, so I'll suggest "rvm pkg install openssl", then "rvm reinstall all --force --with-openssl-dir=$rvm_path/usr".

That will pull down 1.0.1c, an RVM-approved version of OpenSSL. The second command rebuilds all your rubies so you'll actually use it.

Your welcome message will contain a download link.
Posted: 3 months ago (2013-03-07 18:32:31 UTC)

No More Requires

I hate all the “requires” at the front of Ruby files. I know what methods I'm using, but I have to write it in both places. Not exactly DRY. Rails skips them — you just use the classes you want. How can I automatically load my files like Rails does? Read on.

Ruby has method_missing. When you call a method that doesn’t exist on an object, Ruby tries calling “method_missing” instead. That lets you make “invisible” methods with unusual names.

Ruby also has const_missing, which does the same thing for constants that don’t exist. Class names in Ruby are just constants. Hmm...

const_missing and You

First, let’s see how const_missing works. Put this into a file called test_const_missing.rb and run it:

1
2
3
4
5
6
7
8
# test_const_missing.rb
class Object
  def self.const_missing(c)
    STDERR.puts "Missing constant: #{c.inspect}!"
  end
end

Bobo

When you run it, you should see “Missing constant: :Bobo”. So we get to the constant, but it’s not loaded. That seems promising. But we still get an error.

Create a file in the same directory called bobo.rb that looks like this:

1
2
3
4
5
6
# bobo.rb
class Bobo
  def print_bobo
    puts "Bobo!"
  end
end

Pretty simple. Let’s change the first file:

1
2
3
4
5
6
7
8
9
# test_const_missing.rb
class Object
  def self.const_missing(c)
    require "./bobo"
    Bobo
  end
end

Bobo.new.print_bobo

Now try running it again. It prints Bobo! as you’d hope. So we just need to return something from const_missing, and that’s what the unloaded constant acts like.

Hey, that’s exactly what Rails does!

CamelCase and snake_case

There’s one hitch, though. When you use a constant like BadAppleController, it’s not loading a file named BadAppleController.rb. It’s loading bad_apple_controller.rb. So we’ll need to convert from one to the other.

CamelCase is the name for alternating capital and lowercase letters to show where words begin and end. The other way is called snake_case when you use lowercase_and_underscores.

Since we know we need to do that conversion, let’s add a method to do it.

1
2
3
4
5
6
7
8
# to_underscore.rb
def to_underscore(string)
  string.gsub(/::/, '/').
  gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
  gsub(/([a-z\d])([A-Z])/,'\1_\2').
  tr("-", "_").
  downcase
end

I stole and lightly modified this from ActiveSupport in Rails. I’m not going to explain it here (I do in my book).

Putting It Together

You have all the pieces. You can catch a class not existing. You can convert a class name to a filename. You already know the rest -- it's basic. So let’s add automagic constant loading.

Open up test_const_missing.rb:

1
2
3
4
5
6
7
8
9
10
11
12
# Okay, one more require...
require "to_underscore"

# test_const_missing.rb
class Object
  def self.const_missing(c)
    require to_underscore(c.to_s)
    Object.const_get(c)
  end
end

Bobo.new.print_bobo

You've just written code to see that the class is used and load it up automatically. Now you just need to figure out where from...

But I'll leave that as an exercise for the reader.

And That's That...?

Did you enjoy this? It's pretty much straight from the book I'm writing. If you give me your email address below, you'll get the chapters leading up to it about building a Ruby web framework... And now you know how to make that framework load constants automatically!

Your welcome message will contain a download link.
Posted: 8 months ago (2012-09-15 22:31:19 UTC) / Updated: 8 months ago (2012-09-20 11:11:11 UTC)

Clean Ruby Code

A reader asked me for quick recommendations on writing clean code. Here's what I wrote back:


Clean code can be a number of things. For instance, a classmate of mine named Jim Gay likes a pattern called DCI for separation of concerns, and wrote a book about it (http://clean-ruby.com/).

But you may just mean "easy to maintain". For that, there are a number of Rails best practices that can help in Rails, if that's what you're using at the time. You can even install a gem to check some of them automatically (https://github.com/railsbp/rails_best_practices).

Finding a style guide can help, though it will only get you so far. It's easy to see how to improve a little, and the rules are well explained. Here's the one GitHub uses internally: https://github.com/styleguide/ruby

To a large extent, just make sure you maintain your own code. Nothing else keeps you honest quite as well as using and maintaining your own stuff!

Your welcome message will contain a download link.
Posted: 9 months ago (2012-09-10 15:48:18 UTC)

Five Kinds of Marketing for Tiny Web Businesses

This is a repost of email I sent to my 30x500 classmates.

In July I put a lot of time and effort into marketing, and it paid off pretty well.

There are clearly several divisions within marketing (and separate from writing my book). I'm trying to figure out how to balance them.

Here's how I'm currently thinking about that:

  1. "Feed the funnel" marketing. This is education and posts of all descriptions, as well as getting mentions of me into sites, newsletters, etc. Basically, anything that drives people to my blog or Rebuilding Rails. This is short-term in mindset, but gets me the most (direct) sales. The falloff in effectiveness over time is pretty vicious, though -- this is the most like having a job, and is the easiest to calculate an "hourly wage" for. Amy retweeted Thomas talking about "gold farming", and this really does feel like that.

  2. "Legibility" marketing. This is work that gets me no customers but lets me see things about them. Google Analytics, tracking codes, checking logfiles, split testing, propagating referrer tags in JavaScript... No money here at all, directly, but it makes every other category of marketing more effective. This is how I understand my audience and my watering holes.

  3. "Optimize the funnel" marketing. That's web site design, copy rewriting, adding social proof to my sales page and so on. The goal here is to improve the conversion at some step, or drive people to a later step instead of an earlier one (e.g. add mailing list signup right to the blog instead of making them click through). This can compound nicely but it's only a multiplier, it doesn't add revenue by itself.

  4. "Next bite at the apple" marketing. This can be emailing my list(s) with a sale or e-bomb. Eventually it could be emailing my buyer list with upgrades, new products or discount-for-your-friends offers. I don't have a good feel for the mechanics and payoff, but clearly it will work better as my lists grow. Early results look promising.

  5. "Engagement" marketing. I don't have a good feel for this yet. I'm building a lot of content that should stay valuable for a really long time -- for instance, by making documentation for Rack. But I'm currently only getting a short-term boost out of it, which feels like a waste. I think I should be working harder to drive people from one page in my blog to another, to build page rank, to get inbound links and otherwise to generate an honest-to-God passive trickle of constant traffic that I don't have to write for or pay for. This is the Patrick McKenzie holy grail. And I don't think I'm doing this effectively yet.

I'm focusing hard on type 1 marketing. It's the only additive (rather than multiplicative) bit here, so clearly I have to start with it. I feel like I'm doing both too much and too little type 2 marketing - I don't have a huge number of customers or a huge list so it feels wasteful, and yet I'm just guessing where my most valuable readers (the ones who actually buy!) come from.

I'm doing a little bit of type 3 marketing, but it feels like it's not very effective yet. Optimizing will get way easier when I can measure. But I am going to apply a real template to my sales site since the current design is getting flat-out embarrassing ;-)

And 4 and 5 are mostly future-tense. When I get major stuff done I'll send email to my list, of course, and I'm already planning on three more (loudly telegraphed) price hikes over the next few months. But 4 and 5 feel like it's too early for me to being working on, overall.

How do people divide work in marketing? Do you folks see anything major I'm missing, or have areas where you strongly disagree with my division or characterization?

Your welcome message will contain a download link.
Posted: 9 months ago (2012-09-05 05:18:04 UTC) / Updated: 9 months ago (2012-09-05 05:20:42 UTC)

Why Rails and not Sinatra or Node.js?

Rails is bloated and hard to learn. You'd love to use a really simple framework like Sinatra. But what if you need something from Rails that isn't there? You can't memorize all the hundreds of helper methods in Rails. But what are the important ones that will hurt you badly if you don't know them?

Why not build from something simpler and smaller? Node.js or Sinatra, say?

How much useful can Rails give you that's worth all the bloat?

Some good stuff, actually... But less than you think.

Security

The big answer is "security". I won't go over the entire list of security stuff you should care about for Rails. But here are some highlights that you'll need to fix if you build on a slimmer framework before you put it up online:

Rails has fixes for all of these linked in the list. Check the Rails security guide for more information about what this buys you.

The Rails security guide also covers a lot of problems you have to know in any web framework.

Do you care? You really, really should.

Assets

Rails will happily precompile your CoffeeScript, use Sprockets to compress your JavaScript, add jQuery to your app and generally get things ready for you.

But perhaps more importantly, it will rename your assets (images, CSS, javascript, etc) every time they change and fetch them at a slightly different address. This means that in development mode you get to skip a lot of cache bugs when you change files.

Rails will also do a few other things to your assets like auto-sprite-ify sets of images with CSS and serve your assets from several different asset subdomains for maximum speed.

Do you care? You probably care after you're scaling up significantly. Rails will give you these things for free, which is nice. Or your framework of choice will allow you to build it manually and then debug it.

Optimization

Rails makes it easy to do things like page, action and fragment caching backed by files, memory, MemCacheD or in several other ways.

It also has good support for things like ETags and If-Modified-Since via helpers like fresh-when and stale?.

That's probably the kind of thing you're happy to ignore when you pick a slimmer framework.

Libraries

Rails has a head start over everybody else in libraries. Sinatra can run Rack middleware and Node.js has an extensive library accessible through NPM, but Rails has an unparalleled selection of libraries that support it.

Basically everything Ruby supports Rails.

Some of the best stuff is Rack, and so it supports Rails and Sinatra. But often even if you're using Rack middleware, there's an additional wrapper with convenience functions for Rails, so Rails has the advantage again. For instance, Warden is a nice Rack-based authentication system, but Devise is the same thing nicely packaged for Rails.

Now Go Build in Whatever You Like

I'm not worried whether you use Rails, Sinatra, Node.js, Padrino, Rulers or something else completely.

But remember that a web app with bad security can compromise everybody else's security too. When you pick a smaller, simpler framework, know what you're missing and how to fix it.

Play safe!

Your welcome message will contain a download link.
Posted: 9 months ago (2012-09-05 02:48:41 UTC) / Updated: 9 months ago (2012-09-05 15:38:21 UTC)

The Pants Conspiracy, Cellular Edition

Society pressures you constantly to wear pants. You know it's true.

Your cellular carrier pressures you to wear pants.

Look at the awkward, ugly "belt holsters" for cellphones that they sell. Look how easy it is to drop and break your cellphone if you try to use them. Consider that even if you do use them, they need belt loops, and look terrible with dresses or too big and lopsided with shorts.

Your cellular carrier demands that you wear pants.

You must do the only thing you can do:

Call your cellular carrier and say: I am a Pants-Choosing American and you can't tell me whether to wear pants!

Your welcome message will contain a download link.
Posted: 9 months ago (2012-09-05 00:49:34 UTC)

The Anti-Pants Conspiracy, Cellular Edition

Ever notice how most cellular phones don't want to go in my pants?

Uh, I mean, your pants.

There may be an external button for the camera, to take many, many pictures of the inside of your pockets, as my old one did.

There may be an external volume button to make your phone silent next time you use it.

There will certainly be poorly controlled buttons that kill your battery by waking your phone up many times.

Without question the phones are designed to be horribly scratched up by your keys, pocket change and other pants paraphernalia.

This is because cellular carriers do not want you to wear pants.

Do the only thing you can do:

Call your cellular carrier and tell them: "I am a Pants-Wearing American and you can't tell me not to wear pants!"

Your welcome message will contain a download link.
Posted: 9 months ago (2012-09-05 00:43:55 UTC) / Updated: 9 months ago (2012-09-05 00:50:03 UTC)

Rejected by GoGaRuCo: Mocking Time and Threads, Part 2

This idea was rejected by GoGaRuCo (link to part one) as a talk. So you get to see it on this blog!

Quick summary: I've got a thing with a background thread. Clearly the code could have things go wrong. Oh Jeebus, how do I test it?

You can check out Hastur's Ruby client as an example here -- it has exactly this problem, but is simple enough to explain easily. So when you ask, "instead of the example code, what should this actually look like?", Hastur isn't a bad place to check. Hastur sets up a background thread automatically to send back a process heartbeat. It has some unit tests to check that, which use some of the techniques in this post.

Here's the much-simplified code we'll test with in this post:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# mylib.rb
class MyLib
  attr_reader :initialized

  def initialize
    @mutex = Mutex.new
    @counter = 0
    start_bg_thread
  end

  def start_bg_thread
    @thread = Thread.new do
      thread_method
    end
  end

  def counter
    @mutex.synchronize do
      @counter
    end
  end

  def counter_inc(increment = 1)
    @mutex.synchronize do
      @counter += increment
    end
  end

  def thread_method
    last_update = Time.now
    @initialized = true
    loop do
      sleep 1
      if Time.now - last_update >= 5
        counter_inc
        last_update = Time.now
      end
    end
  end
end

There are actually several techniques for mocking a background thread. It's a hard thing because it's inherently timing-dependent and stateful, and state and timing are two of the hardest things to test.

What are the options?

Mock the Thread Completely

One choice is to just never start a background thread. If you have a method that starts the thread, you can mock it. Or you can mock Thread.new just as you mocked Time.new in the last post. Or let the thread run, but don't use it.

You'll need to mock any methods the thread would call or values it would set that affect the main thread.

There's a lot that doesn't get tested that way. Since none of the thread's code ever executes, it could be completely broken and never do anything and you wouldn't know. You've mocked it away completely.

On the plus side, this methods gives the most reliable tests because you're not using a big ball of timing and state in your unit tests. The approach is very clean — so clean that it misses a lot of the problems you'd like to test.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# test_mylib.rb
require "./mylib"
require "test/unit"
require "mocha"

class TestThreadsCleanly < Test::Unit::TestCase
  def setup
    @obj ||= MyLib.new
  end

  def test_thread_stuff
    # Test later on when the counter is higher
    @obj.expects(:counter).returns(7)

    assert_equal 7, @obj.counter
  end

end

Mock the Thread Operations

You can also start the thread and mock all the things it calls. That tests the thread's code, but tests it in isolation from the larger system.

This is better since the thread code is guaranteed to not be 100% broken. It's not perfect because you're still not testing the interaction of the thread with the rest of the system. But it can be a very useful way to unit test.

You'll also notice a couple of (annoying) sleeps in the test code. To avoid those, you basically need some way for the library background thread and the test code to wait on each other -- that's so rarely a good idea that I'm not even going to go into it. Believe me, you can do it, and if you do then you're probably hardcoding the tests to the point where they don't really test the behavior of code that doesn't integrate that deeply.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# test_mylib2.rb
require "./mylib"
require "test/unit"
require "mocha"

class TestThreadOperations < Test::Unit::TestCase
  def setup
    @obj ||= MyLib.new
  end

  def test_thread_stuff
    # When we get here, we don't know if the
    # thread operations have actually started.
    # You can wait on an operation or even just
    # sleep(0.1) and be pretty sure.
    sleep 0.1 until @obj.initialized

    # First, the operation to check
    @obj.expects(:counter_inc)

    # Then ensure update will trigger
    t = Time.now + 15
    Time.stubs(:now).returns(t)

    # Now wait again for the sleep to end and
    # the thread to execute
    sleep(2)

    # We never call any explicit operations
    # because we only want to test the thread,
    # not the rest of the system.

    # When you exit, the "expects" on the
    # operation you were waiting for will trigger.
  end

end

The Full Monty

You can also let the system interact properly between thread and non-thread operations. That gives you the largest, most integrated testing while also giving the greatest chance that your test code is getting something subtly wrong. Writing multithreaded code integrating multiple components is hard, and your test is one more component that has to integrate with the thread.

Keep in mind that, at least with Mocha, any method you "expect" doesn't actually get called. So that can wreak havoc if you let it. Try to only "expect" things that are only side effects, or that you can mock away completely. It's hard, and you may have to cheat by calling original methods from test code in some cases.

Also, this should strike you as bigger, slower, more annoying and more brittle than the previous two cases, even in this simple, abstracted example. It is.

When Functional Programming people talk in smug tones about how you should avoid stateful programming because state is the Original Sin of programming and so on and so forth... This is what they're talking about. This is to be avoided where possible. Now all you have to do is use Haskell for everything, right?

Here's the example with the test code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# test_mylib3.rb
require "./mylib"
require "test/unit"
require "mocha"

class TestThreadOperations < Test::Unit::TestCase
  def setup
    @obj ||= MyLib.new
  end

  def test_thread_stuff
    # Same synchronization problems as last test
    sleep 0.1 until @obj.initialized

    # Get "pre" counter value
    c = @obj.counter

    # Also want to force update, like last test
    t = Time.now + 15
    Time.stubs(:now).returns(t)
    sleep 2

    c2 = @obj.counter

    # Assert that counter ticked up once
    assert_equal c + 1, c2

    # This is actually harder than it looks.
    # What if we had a counter update right
    # after getting c but before stubbing
    # Time.now?  We'd get a c2 that was
    # higher by 2, not 1.  This test will pass
    # by itself because the timing is pretty
    # reproducible.  Run it with something
    # that takes a multiple of 5 seconds, and
    # you'll occasionally hit that bug...
  end
end

What's the Right Answer?

I don't think there is a true right answer. When you ask me "unit tests or integration tests?", I think the answer has to be "both". When you ask me "mocking, or isolated testable units?", again I think it has to be "both." You have to test a lot of components whose design you don't control. And in a language with good mocking like Ruby, the overhead of dependency injection is often not worth it. Without it your code is often far more maintainable, and monkeypatching/mocking can effectively give you free dependency injection in most cases. Use it when it's worth the maintainability hit.

But getting back to "both"...

Integration tests are far more expensive per bug found than unit tests. But unit tests will never find interaction bugs between components. Mocking Time.now and Thread.new is clearly well into "integration test" territory. Don't replace unit tests with it, that's stupid. Use unit tests to check your individual components, including the thread itself. Then write integration tests that don't test each component all that much, but that are designed to test how each component talks to each other component.

It's expensive in time and effort, and often unpredictable. But it will catch bugs that no amount of unit testing will ever catch.

Your welcome message will contain a download link.
Posted: 9 months ago (2012-09-04 03:03:47 UTC) / Updated: 9 months ago (2012-09-04 03:54:25 UTC)

30x500 - why?

I took Amy Hoy's 30x500 class awhile back. A buyer of my book asked whether I thought it was worth it. Here's what I wrote back:

Yes, I'm a 30x500-er, and yes, I'd recommend it. "3x5er?" Not sure. We don't have a good collective noun :-)

I'd say the course is absolutely worth it if you're serious. As you've seen, it's not cheap. If you're only mostly serious, the price is a kick in the pants. You may actually do the work to avoid wasting multiple thousands of dollars. I don't think I individually needed that -- nobody seems to think it's for them! But empirically and numerically, that seems to help people. Isn't it nice to be able to hack the sunk cost fallacy to work in your favor? Relatedly, yes, I think the class will absolutely help other developers create products above a certain level of seriousness.

So here's the hard part, which is both the best and worst part of the course. As developers, you and I both want to write code and have people buy the results. Doing that is, like, maybe 30% of building an actual product, if you're lucky. 30x500 isn't about writing code. You already know how to write code and you don't need to pay to learn. You mention that you're already working on "the guts of a web app", which is a good sign, I was doing the same thing... But don't get too attached to it.

30x500 is a combination self-help and marketing course. That's what I actually needed. You will be ignoring that half-built web app and instead finding an audience (potential customers), figuring out what actual problems they have, and building something to help with that. Which is how I wound up shipping Rebuilding Rails instead of a freemium build-a-portfolio site for developers, which I had mostly built already. The class takes awhile. It has to, because it has to pry your darlings from that death grip you have on them. You'll see most of them strangled by the end of the class, which is exactly what needs to happen.

You need to refocus. Not just your eventual marketing efforts, but your from-the-start product design and development efforts. You have to solve a problem that somebody will pay to solve. If your half-a-web-app is like my various half-a-web-apps, that's not what you did. I certainly didn't survey the market first and build them because somebody was lining up with cash to solve a problem.

I built them because they seemed like a good compromise between "fun to build", "within my abilities" and "somebody might want it, maybe", which I judged by whether it was like some startup I'd heard of.

That compromise is death.

Somebody said that making money is so hard you can't do it by accident. You have to actually focus on it. But you can't not-focus on it for awhile and then start focusing on it. You have try to do something that people actually want (and will pay for), right from the beginning.

30x500 is a long series of calling you on your bullshit, one lesson at a time. There's some how-to as well, but those are the parts that you could find by Googling how-to articles. Don't take the class for the how-to articles. If you do you'll be disappointed. Take the class for the series of articles about being brave and focused, and here's what being brave and focused looks like during this one specific activity.

It emphasizes the process, and the process is simple, sometimes almost insultingly so. That's because you're going to, at some level, be terrified of what she's advising. It requires a lot of arrogance to make something from nothing and then tell people they should buy it because it's awesome. If you can follow a simple set of directions, consistently, week after week, 30x500 will be worth it to you.

Do that despite being terrified and disbelieving, failing repeatedly, getting little or no customer feedback early on, and generally having every reason to quit. You'll get there.

I'm not the most successful 3x5er. That might be Jarrod Drysdale or Brennan Dunn, I'm not sure. But I'm pretty sure I'm in the top handful. I'm also very good at following a simple procedure, consistently, while terrified and disbelieving.

I don't think that's a coincidence.

Your welcome message will contain a download link.
Posted: 9 months ago (2012-08-20 16:07:38 UTC) / Updated: 9 months ago (2012-08-21 04:03:57 UTC)

Redesign: Rebuilding-Rails.com

Have you guys seen BootSwatch? It's awesome.

Relatedly, I just redesigned Rebuilding-Rails.com so instead of a horrific eyesore, it now looks pretty generic.

You know that complaint that designers mention, the one that goes, "and then your site will look just like all these other sites put together by mediocre designers"?

I really hope some day that is my complaint. "Mediocre designer" is far more praise than my design skills deserve.

Good thing I'm a programmer, huh?

Screenshots, before:

Rebuilding Rails front page, before Rebuilding Rails front page, before Rebuilding Rails front page, before

Click through for 'after'

Your welcome message will contain a download link.
Posted: 10 months ago (2012-08-11 15:58:32 UTC) / Updated: 10 months ago (2012-08-11 16:08:53 UTC)

Rejected by GoGaRuCo: Mocking Time.now for Faster Tests!

I proposed a talk for the Golden Gate Ruby Conference, and got turned down. Usually that's it, but the excellent and classy Josh Susser offered to say why he'd turned people down (woot!). He said:

I think we had a good idea of what your talk would be about. But this year we are a bit tired of testing focused talks, and we were also skeptical that your talk would have a half hour of content.

Wow! Josh Susser, Leah Silber and Jim Meyer told me I couldn't be enough of a blowhard to talk about mocking Time.now for 30 minutes?

challenge accepted

It'll take me more than one blog post, though! Expect this to be a series. A 30-minute talk's worth of content would be quite a long post...

To start with:

Two-Week Tests in Thirty Seconds: Mocking Time.now and Threads

If you have sleeps or loops that check time in your library and you want to test that, it can take awhile. Let's see an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# mylib.rb
class MyLib
  def bar
    # No-op
  end

  def maybe_update
    t = Time.now
    if !@last_check || (t - @last_check > 10)
      @last_check = t
      do_something
    end
  end
end

This would normally take 10 seconds before it will call do_something again. That can make it hard to call it in consecutive tests, or to test that its update logic is working. Enter the magic of mocha and mocking:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# test_mylib.rb
require "./mylib"
require "test/unit"
require "mocha"

class TestMyLib < Test::Unit::TestCase
  def setup
    @obj ||= MyLib.new
  end

  def test_maybe_update
    @obj.expects(:do_something)
    @obj.maybe_update
  end

  def test_still_update_if_bar_happens
    @obj.expects(:do_something)
    @obj.bar
    @obj.maybe_update
  end
end

This test fails if you run both, even though it's fine if you run just one. It looks like calling bar, a no-op, makes maybe_update fail, even though it doesn't. Problems like these can be real head-scratchers, especially if the two tests are in different files. "Hey, this test worked fine on my machine but it's failing on the build machine!" No. You were running just that one file on your machine, and the build machine runs everything.

Let's see how mocking Time.now can fix this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
require "./mylib"
require "test/unit"
require "mocha"

# test_mylib.rb
class TestMyLib < Test::Unit::TestCase
  def setup
    @obj = MyLib.new
    @t ||= Time.now
    @t += 30
    Time.stubs(:now).returns(@t)
  end

  def test_maybe_update
    @obj.expects(:do_something)
    @obj.maybe_update
  end

  def test_still_update_if_bar_happens
    @obj.expects(:do_something)
    @obj.bar
    @obj.maybe_update
  end
end

This works! Test::Unit calls setup before each test and we mock Time.now to return 30 seconds later each time so that the 10-second check is fooled. This is way better than sleeping ten seconds before the second test. You'd be depressed to know how many people solve the problem that way and forever after their test suites run slowly.

Now think about a test that can run longer. The hacks around it are often horrible. Mocking Time.now isn't beautiful, but it's not awful.

Now you know the basics. In a few days I'll have another post for you with another use of this technique, and then we'll move on to how to use it in threaded situations -- a quite common reason to need to mock Time.now.

Your welcome message will contain a download link.
Posted: 10 months ago (2012-08-08 03:45:37 UTC) / Updated: 10 months ago (2012-08-09 16:53:41 UTC)

My First Thousand in Product Revenue: Story and Numbers

Want just the graphs and not a whole freaking biography? Scroll down to the bottom.

Hoping to sell a product? Rather start by using free services until you have some actual revenue? Curious how that will work out?

Here's how it did for me — along with the various good and bad luck along the way.

Selling to Developers

I started writing an ebook in February called "Rebuilding Rails". The idea is that the reader builds a Rails-like framework starting from Rack (Ruby's web compatibility layer). They understand Rails better because they've built something similar. The book is (I hope) useful for all Ruby web developers — lower-level Ruby web stuff is horribly documented and there's not a lot of good information about how to build on it.

As of this moment it has made me $1094.91 in revenue after processing fees, or about $1000 in profit.

Is an ebook really a product? Yes. Also, this isn't an ebook sold through Amazon or even O'Reilly - I'm selling it like I would sell software. I market it all by myself. I also fully wrote and entirely maintain the web site that backs it. I'm doing all the traffic and conversion tracking on my own and I'm generally using the ebook as a sort of tutorial. When I start selling software I'll already know the basics of marketing, billing and whatnot. You may have a head start too if you read this post.

It's also a product in that I started selling it in beta at a discount. This isn't a single "it's done!" book launch, but a long series of "buy before it's done!" blog posts and marketing emails. I'll tell you whether that works in a few months, shall I?

I'm actually writing it as part of Amy Hoy's 30x500 class in product design. Not only was it a great way to survey the audience in advance, but the alumni list is tremendously supportive. Great folks!

February

I already had an unused MailChimp account. I built a sales site (rebuilding-rails.com) and a lightly-edited email signup form. My design skills are crap but my audience is Rails programmers, who are more forgiving than random consumers.

I started writing my book in Google Docs (pro tip: don't). I finished the first chapter in about a night and just kept going.

I knew I wanted to put up the first few chapters for free download, so I was racing to get them done and get people on the email list. The plan was to sell a beta ebook at a discount and gradually raise the price as it neared completion -- that's still the plan.

By the end of February I had four people on my email list, all of them people I knew and had told in person. Well, okay, three that I knew plus me.

I also emailed Jesse Storimer, the author of Working with Unix Processes, out of the blue. I asked him what selling an ebook was like.

He wrote back! He loved the book! He has been, and continues to be, wonderful and supportive despite never having seen me in person. You may note a prominent quote from him on the sales page.

March

I worked occasionally on the book through March -- "occasionally" because I'm a dad, I have a day job with a great company and, hey, I'm a busy guy.

The sales site went from "utter crap" to "good enough to not repel somebody really interested" over this time, and Jesse gave me a great quote to headline with. Amy Hoy, my teacher in 30x500, tweeted about my site. I got around 30 email signups.

I sent out an introductory email, which MailChimp tells me nobody ever opened. So if it's still buried in your inbox then it's a collector's item!

I wasn't selling the book yet. I was terrified about asking people for money. I was trying to figure out how to set up Stripe in a way that wasn't likely to bankrupt me accidentally when some hideous bug happened. Stripe is very good at what they do, which didn't stop me from worrying.

I switched from Google Docs to Apple Pages during this time because Pages has tolerable PDF export (GD does not). I upped the font size and generally made the book prettier, and discovered that a horrible three-way merge of content doesn't make my life better. Apple Pages was not a seamless transition, though I'm glad I did it.

I switched on Stripe payments late in March, having emailed that I would do so. MailChimp says nobody opened that email, either. I was so bummed about email and how it was (not) working out that I didn't email anybody again until late July.

I was up to 39 list subscriptions, though.

April, May, June

These months were busy, but mostly not with the book. I churned through some chapters, worked hard on it and procrastinated like you wouldn't believe on doing any actual marketing.

I posted maybe two or three times in various places that I was writing the book. I got a tiny bit of organic Google traffic. But let's round my amount of promotion down to zero, shall we?

It didn't help that mid-May through mid-June were eaten entirely by Diablo 3.

Still, the email list grew to 47, then 48, then 49 people in consecutive months. Early July looked likely to be similar.

In Which I Get Frustrated

I had written a fair bit - I wanted a ten-or-so-chapter book and had written nearly seven of that, including two fairly difficult ones. Progress looked good. My reviewers didn't really review (I'm told that's normal). I had retooled my blog and semi-accidentally flushed the old one. Goodbye, blog.angelbob.com. Nobody misses you.

I was complaining to the 30x500 group that nobody seemed interested in my sales site (have you seen it? I don't blame them) and that I just needed to get the book done, validation or no. I was very sensibly argued out of this. But I still felt quite bitter about the whole thing. It's easy to feel bitter when you're procrastinating work you really don't want to do.

I won't say "things looked grim." I have a day job, so I can pretty much skip the cheap "will he starve?" drama. But things looked unlikely to change.

Still, by early July I actually wrote a couple of blog posts. The first one was likely to alienate my audience (it was even worse pre-editing!) and the other two weren't terribly interesting.

The idea was that these would magically attract my audience, despite me having no traffic. I posted one of them to Reddit and Hacker News and then basically ignored it. Reddit and HN ignored it, too.

But on July 12th I wrote a wonderfully persnickety and fiddly post on parsing URL params in Rack, which suddenly turned everything around. Thanks to Jim Gay, Reddit and RubyFlow for helping me put all the pieces into the right places…

A Purchase!

Specifically, on July 13th some guy I didn't know tried to purchase my book. And then, when it didn't work, Googled me and emailed me to complain. I don't know how long it would have taken me to notice otherwise. I'd probably have mistaken the log entry for me testing the page.

I thought it was a prank at first, honestly.

After debugging the site I emailed him an abject apology and a current PDF of the whole book. I let him know that I thought things worked now. I wasn't absolutely sure - it costs money to order an ebook from yourself and really really check!

They say that as a single random person selling a product you're supposed to make it clear that it's just you. Treat it as an advantage, they say. Let's just say that I do that a lot and so far it hasn't burned me badly. I recommend it!

The fellow in question was absolutely wonderful and, the next day, actually ordered my book. I was ecstatic and wrote an even fiddlier blog post to celebrate.

I also wrote a linkbait post on a genuine but minor Ruby language design problem and posted it to Reddit.

Reddit hated it, downvoted me mercilessly and sent me a bunch of traffic and email list subscribers. Yay?

I got another purchase on July 17th and another on the 20th. I was still checking my Stripe account manually and promised to email people their ebook "within about a day" on the payment page. Weirdly, it was purchase #12 before anybody else complained about delivery time. Why don't you people hate me more?

But developers kept looking at my posts. I kept posting some of them to Reddit and RubyFlow. Then I wrote probably my most useful post so far, in my own opinion.

I was still working on automating everything as quickly as I could… Sure, things were working, but I worried at every hour of the day and night. Was I disappointing my hypothetical customers? I'm a dad, worrying all night isn't out of my way.

First sales

The Flood

I had a few sales under my belt and a little traffic (see graph above). Clearly this was the beginning of "traction". So I resolved to raise my prices. I emailed my 96 subscribers late on July 27th to let people know they had a week left before the price rose from $30 to $35. I also completely left out any link to the sales site from the newsletter. D'oh!

On July 30th, RubySource found my book somehow. Thanks, RubySource! That was worth a few sales and a lot of subscriptions. By the end of July I was at 118 subscribers.

I also finally automated sending out people's ebook immediately when they paid me. That was kind of important ;-) I emailed 119 people about it, mostly because it was also two days before the price hike. This time I did include a link to buy the book.

Well, almost. After having written an impassioned post about how you should never put your credit card info into a page without a green lock, I forgot to type "https" in the email. Somebody emailed me back, mentioning my hypocrisy, immediately. Have I mentioned that I love writing for developers? I really do.

I thought fast and fixed it with a quick JavaScript patch before anybody else noticed. Abject apologies to my customers have served me well, but it's nice to make one fewer!

Things Slow Down… Wait, No They Don't

I had fun with all of this and sold hundreds of dollars of unfinished ebooks... But I was looking forward to things slowing down a bit. The book is fun but we're having crunch time at work, my kids are having a difficult week and there's (always) lots to do besides obsessing over Google Analytics.

Early sales

I sent my final pre-price-hike email to 152 people on Thursday night, got five sales, hiked the price on Friday morning, and breathed a sigh of relief.

Then a guy purchased for the higher price, $35. Huh. I angsted over whether to refund his $5 since he was clearly trying to get in on the sale. I assume? And then somebody else ordered. And another.

By the end I had 5 orders pre-price-hike and 5 more after. Huh?

I had emailed Peter Cooper earlier, and I discovered that he had mentioned me in Ruby Weekly. Ohhhhh…

Big sales day - price hike and Peter Cooper

I also finally started tracking more of my conversion rates rather than just eyeballing them. But I have my first early numbers — around 2% conversion from hitting Rebuilding-Rails.com to successfully buying the book, and between 15% and 50% (!) from Rebuilding Rails' front page to hitting the "Buy It" button (the pale blue line on the graph below).

Conversion rates from front page of Rebuilding Rails to a purchase

Done for a bit?

Yesterday my sales pushed just over the $1000 mark. I'm at 223 list subscribers. I'm taking all this as clear validation of my book idea, but it's not yet success in the same league as a few of my classmates ;-)

I'll keep publishing blog posts as I go — Rack is really poorly documented, and Rubyfolk need better tutorials for it. But I expect to have a month or so of head-down writing to finish the rough draft of all the chapters and start polishing the rest.

This blog post is taking a fair bit of writing time, but I'll tell you what. You guys buy lots of the book in the next six months and I promise I'll post again with more numbers, okay? grin

(Open these graphs in a new tab for a larger version.)

Traffic to this blog over that time:

Codefol.io traffic numbers

Traffic to Rebuilding-Rails.com over that time:

Rebuilding-rails.com traffic numbers

MailChimp subscribers:

Mailchimp subscriptions by month

Your welcome message will contain a download link.
Posted: 10 months ago (2012-08-06 00:32:20 UTC) / Updated: 10 months ago (2012-08-07 15:52:12 UTC)

Rebuilding Rails Exercises

[Update: Rebuilding Rails is finished, and yes, the exercises are in it.]

A reader asked me whether the book was entirely cut and paste or if there would be exercises that required actually writing new code in Rebuilding Rails, or only cut-and-paste. Here's my response:

There are a few small exercises in chapter one, and will be more and more extensive ones later. However, I'm not sure if it will be extensive enough for what you want.

For instance, in the new ORM chapter there will be an exercise on adding column accessors via method_missing, which requires a good basic grasp of what's going on.

There will be 3-5 exercises of about that difficulty (many a bit easier, a few significantly harder) in each chapter. The book is structured so that your framework gets better with each exercise, but no later chapter depends on the exercise being finished. So if you skip them, you get the pure cut-and-paste experience but it still works. If you do all of them, you'll have a much more usable framework.

The downloadable sample code just gives the base cut-and-paste framework, not the exercises.

Your welcome message will contain a download link.
Posted: 10 months ago (2012-08-01 16:15:55 UTC) / Updated: 5 months ago (2013-01-04 16:28:21 UTC)

Automatic HTTPS JavaScript Redirect

Awkwardly, I just emailed out links to pay for Rebuilding Rails with "http://" in front. Like, not "https://".

Not so good. I was immediately called on it by one of my list subscribers, using my own words! Can I just say how much I love you guys for actually paying attention? People on my mailing list rule.

I considered emailing out an abject apology and hoping I never did it again, until it hit me...

"Hey, wait! I should never allow insecure links to that from anybody. Can't I just force it https?"

Yup. Here's what I used:

1
2
3
    if(window.location.protocol != 'https:') {
      location.href = location.href.replace("http://", "https://");
    }

That's not as good as redirecting to https directly in NGinX, which I may also do. But it's a great quick fix, and it makes sure that the mistake will be fixed if it happens again.

Your welcome message will contain a download link.
Posted: 10 months ago (2012-08-01 03:40:22 UTC) / Updated: 10 months ago (2012-08-05 22:02:35 UTC)

Timing Attacks Are Really Tricky

Patrick McKenzie mentioned in a Hacker News comment that it's easy to leak database information with a timing attack, and that it's silly to secure that information very much in other ways if you aren't going to block the timing hole.

He says "Some folks think there are trivial ways to defeat timing attacks. You are either mistaken or you have a very different view of the word "trivial" than I do."

He is correct.

Much debate followed, often of the "just pad the total time up at the end and then they can't tell!" That is, many people think this is a trivial thing to defeat.

They are wrong.

Here's the problem: your web site is a system with large, complex pieces. Those pieces operate in a mostly-predictable way. Query an account? That hits the database with the same query every time. Reset a password? Also a known set of database queries. Queue a task to reset the password? There's a delay, but it's always the same set of database queries.

This isn't predictable in that if an attacker does it once, there's lots of sources of noise. The queueing system will be doing other things. The web site will have other load. They get a single measurement, and that measurement is probably garbage.

But they don't just get one measurement on that same machine right at the time.

They can pick any visible part of your system and see how it responds.

Other URLs? Sure. Different sites that share a queueing system? Yup. Do other things that enqueue a task and check the delay? Yup, they can do that. SSH in and see how long it takes to give a prompt? Often, yes.

You're not just fixing a single point where the attacker can check the behavior of your system. The attacker can pick any part of your system.

If you pad out the time it takes for the query with busy-waiting, other URLs will be slowed down. If you pad it out with sleeping, they won't. Both are different depending on how long the query actually took. If resetting a password requires more queries, or queries to different tables, than if the password doesn't exist then some URLs (that use those tables) will be slowed down.

Again, quoting Patrick:

The attacker wins with microsecond precision over the open Internet and nanosecond precision over the local network, which is plausibly achievable on all of the cloud providers than HNers like to host their apps at. Microsecond precision is enough to discriminate between "record in DB" and "record not in DB" on many plausible application architectures, even if your HTML/headers returned are exactly identical for the two cases (and they frequently won't be out of the box).

His measurements there assume the attacker can check repeatedly. But an attacker who knows statistics can check again and again and can, eventually, determine the difference at microsecond precision over the 'net.

Can't you just block that attacker? Not if they use a botnet or enough forged IPs. Can't you rate-limit them? Only if you can let them lock out all your real users.

The problem is that computers are hugely, delicately interconnected. What would solve these problems are highly-enforced resource quotas with no sharing between all your tasks.

Of course, then everything is unshareable and your costs go way up.

Defeating timing attacks is really, really hard.

By the way: what would work is if you could pad out the total work with exactly the same load between hits and misses on all of your infrastructure. Always queue a job, always return a user (but a false one), always make the database objects, all the way through the whole process. Do not allow a full nanosecond of difference between the two.

And that's the part that's really, really hard.

Do you like deep technical minutiae and understanding your whole application stack deeply? I'm writing a book that can help with that...

Your welcome message will contain a download link.
Posted: 10 months ago (2012-08-01 00:40:08 UTC) / Updated: 10 months ago (2012-08-01 00:41:40 UTC)

Bring Your Skills Up A Standard Deviation

Most people don't know anything about a given skill. But it's not as simple as "I know" or "I don't know". Skill is in categories -- beginner, novice, intermediate, master or whatever.

Lately I have to learn a lot all at once, what with the whole selling a book thing. So I have far more skills to learn than time to do it.

So I'm picking skills one at a time and bringing them up by one standard deviation.

The average knowledge of the skill is near zero. One standard deviation up is a beginner. The next deviation up is a bit higher. Each deviation takes longer, and I could put years of effort into most of these skills...

But I don't have to put in years. I can just bring my skill up by one standard deviation and see what happens. If it helps, I should put in more effort later. It goes on my "to do" list.

And if not, there's never a shortage of awesome-looking skills to learn.

Your welcome message will contain a download link.
Posted: 10 months ago (2012-07-31 01:08:35 UTC)

MiniTest 3.3.0 breaks some things...

MiniTest 3.3.0 seems broken in some (fairly simple-looking) cases that 3.2.0 didn't break. The presenting error is below.

It's claiming that an auto-generated Test Suite doesn't have a "run" method. I haven't looked through enough diffs to be sure what the problem is.

A simple workaround is to go back to MiniTest 3.2.0, possibly by adding a "~>3.2.0" to your Gemfile.

1
~/gems/minitest-3.3.0/lib/minitest/unit.rb:826:in `block in _run_suite': undefined method `run' for #<ArrayTest:0x007f859811fa10> (NoMethodError)
Your welcome message will contain a download link.
Posted: 10 months ago (2012-07-27 20:45:54 UTC) / Updated: 10 months ago (2012-07-27 20:46:52 UTC)

Developer, not Coder

There's a lot to developing software on a team that universities don't traditionally teach you. If you're already strong at theory and skills and you know you also need lots of practice, what else should you be doing to prepare?

Developing on a team requires a lot of people skills. Junior software developers are often "junior" specifically because they lack those skills - it's not uncommon to see junior developers with better "hard" skills than much higher-ranking and more senior developers. Indeed, it's easy to become bitter about that as a junior developer because you can't yet see what separates you from them.

Here are some examples of that separation:

  • More senior developers have been doing this longer and can often estimate the difficulty of a task with greater accuracy. This is requires so that managers of various kinds have a better idea of when you'll be delivering that software. That's utterly vital in business, but often treated as unimportant by developers ("it's done when it's done!").

  • More senior developers often better understand the business climate surrounding their software, and can prioritize features and effort independently because they know what parts of their software are most vital to actually selling that software. This is often unrelated to raw functionality.

  • More senior developers often understand other roles in the company better (sales, marketing, management, etc.) and can better optimize their communication and even their software to help those people. How do you make the software easy to demo impressively so that marketing can do better with it? How do you make it more obvious as you build which parts aren't done yet, and how done they are, so that management and non-technical people understand progress? How do you build software so that it's easy to see its current state for non-technical folks like customer support? How do you make it tool- and GUI-friendly so non-technical people can interact with it?

  • Great senior engineers have a deep love of documentation and automation. That's because other people adopt your stuff more readily if your code has it, and because it's far easier for you to pick something up later if you made it trivial to dig in and get started.

  • More senior engineers can often pick up new tools and codebases quickly because they spend a lot more time understanding and maintaining bad code. There are many sub-skills to this - it's complicated to learn well, and mostly you just need a lot of experience at it.

So, sure, that's a fun little sales pitch for experienced senior developers. But what do you do to become one?

  • Pick up bad code. There's a ton of bad open-source out there, it doesn't specifically have to be corporate bad code. Fork something abandoned on GitHub with a toolset you don't usually use and start playing with it. Build some of that documentation and automation into it so that it's easy to get started. And "bad" doesn't have to be pervasive. Just pick something that's not terribly popular without an easy on-ramp for new developers.

  • Read business books, especially those aimed at marketing, sales, management and product/project management. Blog posts help too, but nothing beats a full book. This isn't the best way to learn other people's roles, but it's (usually) easier than tracking them all down and beating it out of them :-P

  • Use a real development methodology when you're working, down to writing out task cards, estimating tasks and moving the cards between columns on a board. You'll feel stupid doing it, but nothing beats having actually worked that way. Scrum and Extreme Programming are good choices that aren't too hard to get started with and don't add too much overhead. The reason to do this, by the way, is to get good at estimation. The rest of the process may help a bit, but by far the most important part is that you actually break up projects into sub-tasks and estimate those sub-tasks. Then see how close you came when you're done.

  • Read case studies of companies, successes and failures. You can do this with business books, but read up on current (business) events, too. You're trying to get a feel for how products succeed or fail. That's a lifetime of work to do really well, but if you put fifteen spare minutes into it once a week, you're still ahead of most developers.

Then, do all the same things you know you need to. As you say, develop. If you come up with projects that may be useful and then promote them, that will teach you a huge amount of the rest.

Oh -- and make sure you're the one that has to maintain them! That's the other bit you should be learning, basic operations!

Your welcome message will contain a download link.
Posted: 10 months ago (2012-07-26 17:03:39 UTC)

Rack Authentication Middleware

Rack comes with a fair bit of built-in middleware that you can use to put together a simple app frame. Unfortunately, Rack authentication's documentation is pretty bad, so let's see some simple, self-explanatory examples, shall we?

Config

We'll need a config.ru file for this, and you'll need Rack installed. Here's how you want config.ru to look, at the beginning:

1
2
3
4
5
6
7
8
9
# config.ru
require "rack"

run lambda { |env|
  [200,
    {'Content-Type'=>'text/plain'},
    ["Hello, World!"]
  ]
}

This is as simple as Rack apps get. Return success (200), a content-type header that says it's text, and "Hello, World!" — which has to be in a list because Rack says so.

What's the easiest way to put a password in front of this?

Simple Middleware

Rack comes with nice simple built-in authentication modules. Here's how you use the Basic auth middleware:

1
2
3
4
5
6
7
8
9
10
11
12
require "rack"

use Rack::Auth::Basic, "Hello, World" do |username, password|
  'secret' == password
end

run lambda { |env|
  [200,
    {'Content-Type'=>'text/plain'},
    ["Hello, World!"]
  ]
}

The "use" statement says to include the password middleware. You can see that the password is "secret" with any user, so type "secret" as the password in your browser! Just return true if they pass the check or false otherwise.

You can also use Digest authentication with Rack::Auth::Digest::MD5. It wants to pass you the username and have you return the password, which it hashes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
require "rack"

# Long random string.  Use a better one than this.                              
opaque = "1234567890"

use Rack::Auth::Digest::MD5, "Hello, World", opaque do |username|
  'secret'
end

run lambda { |env|
  [200,
    {'Content-Type'=>'text/plain'},
    ["Hello, World!"]
  ]
}

That looks the same to you... But it doesn't send your password in the clear!

Notice that you have to set an "opaque" -- that's a long secret key which should always be the same for your app. I'd recommend you randomize it, not use "1234567890" :-)

Authentication

These are the only authentication methods Rack supports. That makes sense -- they're the only authentication methods that most browsers support properly.

Now that you have some decent examples, go forth and authenticate your Rack applications!

What Rack applications? That's anything with Rails, Sinatra or your framework of choice, of course!

If you like playing down in the Rack internals, have I mentioned that I'm writing a book called "Rebuilding Rails" about that?

Your welcome message will contain a download link.
Posted: 10 months ago (2012-07-23 00:00:25 UTC) / Updated: 10 months ago (2012-08-03 03:30:36 UTC)

"What is Rack?": A Primer

Maybe an engineer you respect just told you to go learn about Rack -- you won't get better at Ruby web stuff until you know what's underneath.

Maybe you have to write a config.ru to use Heroku and you're thinking, "what's config.ru?".

Maybe you have a deep, nasty Sinatra bug and you're having to dig into the Sinatra stack traces and stuff that might be failing is named "Rack". Why "Rack"?

Now what?

Now it's time to learn about Rack.

Quick Answers to "What's Rack?"

Here are a few things Rack is.

If these don't help, scroll down a bit. There's far more detail below.

Rack is a nice Ruby-fied replacement for CGI.

Rack sits between all the frameworks (Rails, Sinatra, Rulers) and all the app servers (thin, unicorn, Rainbows, mongrel) as an adapter.

Rack is a convenient way to build your Ruby app out of a bunch of thin layers, like a stack of pancakes. The layers are called middleware. Or pancakes, why not?

Less Hand-Wavey, Please!

Your app server (let's say unicorn) gets an HTTP request. Somebody wants to post to http://your_site.com/people/127/fire_with_cause (don't worry, it's Wally -- he'll weasel out of it).

Unicorn receives the request, parses it, hands it to Rack, and then Rack gives it to your Sinatra app (or Rails, or Padrino, or your framework of choice) as a request, usually a method call. This is where Rails routing takes over, for instance.

Rack keeps Sinatra from having to know anything specific about unicorn. Or mongrel. Or thin. Or lighttpd. Or any of the many other wacky app servers out there. That's why it's like CGI for Ruby.

But What Good Is It?

That's fine. But it helps the guys writing app servers, not you. How does Rack help you?

Rack lets you mess with those layers -- the ones above Rails or Sinatra, the ones underneath, and even the ones in the middle! That's the whole "coding your app in thin layers, like a stack of pancakes" thing from up above.

Rails is actually implemented as a whole bunch of Rack pancakes (same as middleware, but I'm calling them pancakes from here on out). Here's what that stack looks like, lightly edited:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ rake middleware
use ActionDispatch::Static
use Rack::Lock
use Rack::Runtime
use Rack::MethodOverride
use ActionDispatch::RequestId
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use ActionDispatch::DebugExceptions
use ActionDispatch::RemoteIp
use ActionDispatch::Reloader
use ActionDispatch::Callbacks
use ActiveRecord::ConnectionAdapters::ConnectionManagement
use ActiveRecord::QueryCache
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ParamsParser
use ActionDispatch::Head
use Rack::ConditionalGet
use Rack::ETag
use ActionDispatch::BestStandardsSupport
run RailsGame::Application.routes

Each of those things is a Rack middleware that's doing a little piece of the processing.

Like Rack::Lock, up near the top? That keeps more than one thread from running in your Rails server at once so that you don't have to make all your code thread-safe.

Or Rails::Rack::Logger? That makes sure your requests get logged to the Rails logfiles.

And what if you added one? Maybe you could fix a lot of nasty bugs with bad HTTP requests if you could just reject them immediately, before they got a chance to screw up your web framework...

Rack ships with a bunch of middlewares and Rails has a bunch of others that it adds. You can even insert your own into the stack if you mess with config.ru in your Rails app.

A rack pancake can be as simple as Rack::Config where you hand it a block of code and it runs it on each request. Or it can be as complex as RackAMole which logs every request to a MongoDB instance you have to set up. Or way, way more complex than that.

There are lots of fun pancakes out there.

How Do I Use It?

Mostly it's done for you. Rails and Sinatra already have Rack support. You can modify config.ru in a Rails/Sinatra/whatever app if you want to add Rack pancakes to your app.

But you don't have to do anything at all for basic Rack support if you're already using a Rack framework.

What if you want to write a Rack-based framework and learn all the best tricks? That's a longer answer. Luckily I'm writing a book with all those details.

For the first two chapters, sign up below:

Your welcome message will contain a download link.
Posted: 10 months ago (2012-07-22 23:37:26 UTC) / Updated: 10 months ago (2012-08-04 01:08:40 UTC)

Unsolvable Ruby Problems: Array#map on an Array subclass, but keep the subclass!

I love looking at problems with "no solution" in languages to stretch my mind. Here's a fun one from Ruby.

In Ruby, there's not a good way to map over a subclass of Array and get the same subclass back.

That is, if you start with this code:

1
2
3
4
5
class Array
  def but_doubled
    map { |x| x * 2 }
  end
end

This will work fine on an Array, but if you call my_array_sub_object.but_doubled, you'll get a plain, bare Array, not a subclass object.

Yes There Is, You Meanie!

You may think, "sure, no problem. Just re-define #map on the subclass to return the subclass." Ah, but then you don't get to choose whether to return the subclass or Array. Plus, if the author of the subclass didn't do that you can't do it... Or you have to monkeypatch. This is Ruby.

But if you don't know what subclass you might be passed, you have a problem. That happens sometimes, even in code like Rails, and then the solutions aren't always pretty.

Make a New One

You could create a new object of that subclass and then add the objects back into that. That works, right? Well, sometimes.

If you don't know the subclass, you don't know what initialize() takes as parameters. You can hope that it's the same as Array, but it often isn't...

Indeed, you don't have to ask long before people start telling you to avoid this entirely and rethink your whole approach.

Then... What?

I don't have a perfect answer -- nor does Rails, as you saw above.

But after thinking of several ways to solve the problem and coming up with a few of your own, do you now know more about Ruby?

Basically I mostly just like messing around in the guts of Ruby. Do you?

What things are impossible in your favorite language? What are your favorite half-solutions?

Your welcome message will contain a download link.
Posted: 10 months ago (2012-07-18 03:48:33 UTC) / Updated: 10 months ago (2012-07-18 03:56:54 UTC)

Rails Reading Club

Some day I would love to put together a Rails Reading Club. Like a book club, but for the Rails source.

I love fun weird Ruby trivia, and the Rails code is full of it!

As Joel Spolsky said, reading code is like reading the Talmud. You should get together and pore over the lines and debate properly over the intention and the expression of it.

Some day I'm going to find the right group of Ubergeeks and we're going to make that happen.

Your welcome message will contain a download link.
Posted: 10 months ago (2012-07-18 03:26:24 UTC)

Deep Rails: Understanding HashWithIndifferentAccess, Understanding the Params Hash

Rails parameter parsing can be hard to understand, but it goes beyond that.

Just understanding the "params" object in your controller actions is a little tricky. Ever notice how params[:bob] and params["bob"] both work? The magic type behind that is called HashWithIndifferentAccess. Yeah, it's a mouthful. I wish I were making that up, but no.

There's a lot of interesting code in Rails with interesting Ruby tricks - so let's de-magic the params object, find some bugs with it and get better at Ruby, all at once.

The Source

I like going straight to the source, so here is the current version of the file in ActiveSupport. You can just read, or follow along on GitHub.

It's a nice readable 176 lines.

What's It Do?

In Rails you can say params["people"] or params[:people], and either way you get the same thing back. Simple enough, right? Well, mostly.

You can see on line 7 that it inherits from Hash -- Ruby is convenient that way.

The biggest magic is on line 159, in fact, in convert_key(). It just converts any key it sees to a string.

listing from line 159

So HashWithIndifferentAccess is just a regular hash, but any symbol key is converted to a string. If you put in a key that was, say, nil, nothing would change.

Fun Ruby Tricks

This class shows one fun ruby trick - aliasing and replacing a method. The old hash update and assignment are renamed to regular_update and regular_writer.

listing from line 49

You can also see just how many methods you need to override to make your own hash... Default(), brackets, assignment, update(), key(), fetch(), dup(), merge() and many more. Making your own variant type is a bad idea unless you spend some quality time with the core language documentation and see what actually changes.

But if you do, it can be really useful, like the Rails params object!

What Can Go Wrong?

There are some oddities, like stringify_keys! and symbolize_keys! -- what do you do for a HashWithIndifferentAccess? They do nothing... Fair enough.

But right next to convert_key is convert_value()... And it's interesting - if you assign an array to the hash, you can see that they do a .map! and change the array before assigning it.

That means if you said:

1
2
my_array = [ :a, :b, { :c => :d } ]
params[:item] = my_array

Your array will actually change! That hash inside will suddenly have indifferent access and it will point to a whole different object!

(Why? I spent awhile with git log trying to answer that. Looks like it's because just mapping the Array won't give you the right subclass, so they rewrite the innards instead! Map into an unknown Array subclass is an unsolvable problem in Ruby, actually...)

Up To Date?

Nothing stays the same forever. In Rails, not much stays the same for long. So here is a link to the latest HashWithIndifferentAccess in GitHub, whenever you go look for it.

Enjoy Getting Your Hands Dirty?

Do you enjoy code spelunking to learn about Ruby and Rails? I'm writing a book about that. The first couple of chapters are free and awesome -- sign up below and download them.

Your welcome message will contain a download link.
Posted: 10 months ago (2012-07-18 03:22:04 UTC) / Updated: 10 months ago (2012-08-02 04:38:24 UTC)

Juggernaut with New Eyes - Nitpicks!

I'm picking up Juggernaut after a long hiatus and seeing it with new eyes, which is fun.

I'm realizing my old RailsGame architecture was horrifically overcomplicated. The rest of you probably knew this a long time ago.

I'm also realizing that Juggernaut has some problems in a High Availability setting, but that's a topic for a later post.

Juggernaut is interesting because I can now see a lot more of the seams where it's clearly a fun test project, not a "real" project, and I can see how to fix some of them.

For instance: a JavaScript client can send "events", separate from normal messages, and there's a custom event built in, but there are no accessors to send one. It's just kind of hanging on there, even though that would be ridiculously useful in some cases. Functionality's there, documentation and convenience aren't.

And you can subscribe to see messages on channels from non-JavaScript clients, but only by subscribing directly to Redis - you can't ask the server to send non-JavaScript clients things on a given channel. That's adequate for my needs, but sucks in a lot of other cases.

Basically, Juggernaut thinks of itself as server-push stuff, no full-on pub/sub.

Good to know.

Next post I'll be delving very deep into how to hook up Juggernaut in ways it doesn't expect to get around these problems :-)

Your welcome message will contain a download link.
Posted: 11 months ago (2012-07-08 16:06:57 UTC)

How Does Rack Parse Query Params? With parse_nested_query

What turns URL params like "http://site.com/people?name=bobo" into { :name => "bobo" } in Ruby?

And what turns extra-weird Rails or Sinatra params like "/path?people[][name]=bobo&people[][first_love]=cheese"?

What the Hell is that?

Googling "rails query param names with square brackets" doesn't help much. And Rails doesn't make it easy to find docs for this.

So what's going on with the weird params?

Rails uses Rack to parse them, so it's (mostly) the same in Sinatra, Padrino or your ruby web framework of choice as well.

What Does the Code Say?

Rack is really poorly documented. But the query param code is short, so instead of my usual "rebuild it" approach, let's go right to the source - Rack::Utils.parse_nested_query:

1
2
3
4
5
6
7
8
9
10
11
def parse_nested_query(qs, d = nil)
  params = KeySpaceConstrainedParams.new

  (qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p|
    k, v = p.split('=', 2).map { |s| unescape(s) }

    normalize_params(params, k, v)
  end

  return params.to_params_hash
end

That's just parsing the parameters by splitting on ampersand and semicolon. What about the square braces? They're handled in normalize_params (see below for abridged source, or GitHub for full). It gets called once for each parameter name.

What Does normalize_params Do?

First it checks the param name for anything that's not square-braces, and then read whatever is after that (called "after").

If the "after" is nothing there are no square braces -- great, assign the parameter, you're done.

If "after" is empty square-braces, that parameter is an array. Start with it being an empty array, and then append to it. So if you parsed p[]=a&p[]=b&p[]=c, you'd get {"p" => ["a", "b", "c"] }.

If "after" starts with empty square braces and then has more after it, it's nested. So the parameter is still an array, and could be something like an array of arrays. The code handles this by recursing.

So if you parsed p[][a]=a&p[][b]=b&p[][c]=c, you'd get { "p" => [{ "a" => "a", "b" => "b", "c" => "c"]}.

Feeling a little confused? Scroll down for another approach -- play with it in irb!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def normalize_params(params, name, v = nil)
  name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
  k = $1 || ''
  after = $' || ''

  return if k.empty?

  if after == ""
    params[k] = v
  elsif after == "[]"
    params[k] ||= []
    params[k] << v
  elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$)
    child_key = $1
    params[k] ||= []
    if params_hash_type?(params[k].last)
      && !params[k].last.key?(child_key)
      normalize_params(params[k].last, child_key, v)
    else
      params[k] << normalize_params(params.class.new, child_key, v)
    end
  else
    params[k] ||= params.class.new
    params[k] = normalize_params(params[k], after, v)
  end

  return params
end

Using irb

Since this is Ruby, pop open irb and require "rack".

We'll define a convenience function called p() because I hate typing.

Then we'll check to make sure we were right up above:

1
2
3
4
5
6
7
8
9
10
11
Athanor:rulers noah$ irb
1.9.3p125 :001 > require "rack"
 => true 
1.9.3p125 :002 > def p(params)
1.9.3p125 :003?>   Rack::Utils.parse_nested_query(params)
1.9.3p125 :004?>   end
 => nil 
1.9.3p125 :005 > p("p[]=a&p[]=b&p[]=c")
 => {"p"=>["a", "b", "c"]} 
1.9.3p125 :006 > p("p[][a]=a&p[][b]=b&p[][c]=c")
 => {"p"=>[{"a"=>"a", "b"=>"b", "c"=>"c"}]}

Looks pretty good. Let's try skipping the first open brackets:

1
2
3
4
1.9.3p125 :007 > p("p[x]=1&p[y]=2")
 => {"p"=>{"x"=>"1", "y"=>"2"}} 
1.9.3p125 :008 > p("p[123]=bobo")
 => {"p"=>{"123"=>"bobo"}} 

So that's what we usually see in Rails with a structure.

What else can we get by playing with this?

1
2
3
4
5
6
7
8
1.9.3p125 :017 > p("x[][y][w]=1&x[][z]=2&x[][y][w]=3&x[][z]=4")
 => {"x"=>[{"y"=>{"w"=>"3"}, "z"=>"2"}, {"z"=>"4"}]} 
1.9.3p125 :018 > p("x[][z][w]=1&x[][z]=2&x[][y][w]=3&x[][z]=4")
 => {"x"=>[{"z"=>{"w"=>"1"}}, {"z"=>"2", "y"=>{"w"=>"3"}}, {"z"=>"4"}]} 
1.9.3p125 :019 > p("x[][z][w]=1&x[][z][j]=2&x[][y][w]=3&x[][z]=4")
 => {"x"=>[{"z"=>{"w"=>"1", "j"=>"2"}, "y"=>{"w"=>"3"}}, {"z"=>"4"}]} 
1.9.3p125 :020 > p("x[][z][w]=1&x[][z][j]=2&x[][y][w]=3&x[][b]=4")
 => {"x"=>[{"z"=>{"w"=>"1", "j"=>"2"}, "y"=>{"w"=>"3"}, "b"=>"4"}]} 

Have fun! I hope you've learned some interesting things about Rack parameter parsing... And how to figure it out next time you see somebody doing something that looks complicated with Rails parameters!

Your welcome message will contain a download link.
Posted: 11 months ago (2012-06-29 12:38:22 UTC) / Updated: 10 months ago (2012-07-18 04:24:11 UTC)

VonChurch Recruiters are Really Obnoxious

[Update: while this reflects events as they occurred, vonChurch has reached out to me several times to try and rectify this. I'm off their list these days, and I haven't heard from their recruiters in awhile. So at the moment, they're doing fine by me. I presume they'd also take you off their lists at your request.]

I'm easy to find on the internet, so I get 5-10+ job inquiries per week. Email, LinkedIn, cell phone, the recruiters call to see if I'm looking for a new job.

Fair enough. As they sometimes point out, they're contacting me with public information.

That means they deserve at least as much courtesy as telemarketers, who also use public info, right? By having a resume they can find, I'm totally asking to be called night and day, work hours and dinnertime.

Eh, sure. Whatever.

But even among recruiters, VonChurch manages to be extra-obnoxious. Completely inappropriate jobs, repeated inquiries, having three or four VonChurch folks call or email in a row... I tell 'em I don't want to work in San Francisco, they keep offering San Francisco. Once I told one of them curtly that I wasn't looking for a job and he called me back to complain because I didn't stop to chat.

Seriously. No kidding.

I don't deal with VonChurch, which is no real loss to me.

But wow. It's amazing when one recruiting company can actually stand out from the pack of headhunters as especially obnoxious.

Your welcome message will contain a download link.
Posted: 11 months ago (2012-06-21 21:11:18 UTC) / Updated: 3 months ago (2013-03-11 15:49:04 UTC)

The Grace of the Snail

I want to feel like a stupid, incompetent, worthless person still gets to look at something nice because I have the physical ability to create it.

My wife wrote this about herself -- "I can have something nice, no matter how awful I am, if I can create something nice."

People are foolish and gawky and bad at things and contrary and, and, and...

Sure, okay.

And yet... It's not how bad your are most of the time. If at your very best you can make something, then forever after you know you made it.

No matter how slow or ugly the snail, it made that lovely spiraling shell.

You just have to be good enough to make something once.

If I can make one thing and then another, forever after I am a maker. The grace of the snail is grace indeed, and it's grace enough for me.

What more could I ask?

Your welcome message will contain a download link.
Posted: about 1 year ago (2012-05-21 15:29:41 UTC) / Updated: 11 months ago (2012-07-13 01:22:50 UTC)

Starting Rails programming

I tutored Rails at CMU West for a bit. They asked me for recommendations for what the students should be doing to prepare for Rails programming.

You know, that's advice I can share with anybody. Here's what I wrote:


Sure, I can help a bit with this.

Michael Hartl has an excellent free tutorial which is already given as a resource to the students. I'd definitely recommend sending them the link earlier so that can start looking at it sooner. It really is the best thing out there. Paper books exist but go out of date frequently, cost money and are otherwise less convenient. The Rails interface changes frequently and paper books haven't done a good job of keeping up with it.

I'd suggest a programming assignment rather than a reading assignment to get started -- don't tell them how much of Michael Hartl's tutorial to read, tell them what to accomplish and they can read what they need to get it done. That's better real-world practice anyway. Similarly, Google is a fantastically useful tool for Ruby and Rails programming and every sub-topic, so tell them they can and should use Google frequently, especially for error messages. It's miraculous how well it works for about 80% of programming and configuration errors. Again, an excellent habit for later real-world programming.

I'm pretty sure you also give them a link to the online "Pickaxe Book", Programming Ruby ("http://www.ruby-doc.org/docs/ProgrammingRuby/"), which should be thoroughly adequate to their early Ruby needs. There are at least some better paper books on Ruby than on Rails. It changes less frequently. The later edition of that same book, "Programming Ruby 1.9" is also good, and Ruby 1.9 has some changes from 1.8. But overall, the older free book online is fine.

I don't have a strong opinion about "Ruby then Rails" versus "Rails then more depth with Ruby". You can do Rails programming with very little Ruby sophistication in many cases, but eventually they'll need both. I haven't seen a compelling argument that one has to come before the other, in either direction. So make sure the students have access to online references for both and you're probably fine.

This probably all sounds very handwave-y. It should. Fundamentally, the most valuable skill you can teach them here is how to learn by constant online browsing supported only occasionally by partly-outdated "authoritative" materials. Programming languages are starting to move fast enough that traditional publishing can't support them properly, now that online publishing can at least attempt it. Online API references, language references, and eventually source code are the things that stay up-to-date, along with understanding of how to browse blogs, StackOverflow and so on for what they need. Google, in turn, will lead to those blogs, StackOverflow and so on.

Some fun possibilities for small, easy-with-Rails-type programming tasks:

  • Put together a blog. Example recommended feature list: format post with markdown-or-something, add keywords to each post, search by keyword. Extra credit: search titles by keyword.

  • Write a snippet-or-something rating program (examples: submit code and rate it, submit quotes and rate them). Example feature list: users can submit core-or-quotes-or-whatever, users can vote, program counts votes, show top 10 list of most popular quotes. Extra credit: allow a user to change their vote later, make sure votes only count one-per-user. Extra-extra credit: statistical confidence so that you can decide how a new quote with four up-votes and one down-vote should compare to an old one with 35 up-votes and 20 down-votes (an interesting question, with many fun possible answers!).

Feel free to cut those projects down if they sound too ambitious. They are specifically chosen to map well to what Rails offers, but especially with extra credit they're not necessarily easy. They are also chosen to be fairly free-form, which I think is good preparation but may be a little much for beginners...

Feel free to call me at XXX-YYY-ZZZZ if you'd like to discuss further. I just thought I'd put something in writing to start out.


(Already know Rails? Trying to get better? I have a book you can buy about that...)

Your welcome message will contain a download link.
Posted: about 1 year ago (2012-05-11 23:08:00 UTC)

The Five-Minute Framework

Here are slides from an upcoming talk at Hacker Dojo's lightning talks:

The Five Minute Framework (Slides)

Your welcome message will contain a download link.
Posted: about 1 year ago (2012-05-09 02:57:12 UTC) / Updated: 11 months ago (2012-07-13 01:20:37 UTC)

Your App Is Written From Your Point of View

Programming is writing for a computer. But more importantly, it is writing for a human.

That function you just wrote tells a little story. It has a point of view.

Some functions are written to tell how a web request flows through them. They are clear, easy to read, and tend to do badly if something goes wrong. That's not the story they are meant to tell.

The worst functions have no point of view. Perhaps they were written badly, or perhaps they were edited to death by a later programmer with a different point of view. But they are hard to follow because they change point of view.

Think about who you are writing for. Think about the story your function should tell.

Your welcome message will contain a download link.
Posted: about 1 year ago (2012-05-09 02:53:30 UTC) / Updated: 11 months ago (2012-07-13 01:20:24 UTC)

BigCo New Employee Training, Inside Voice

Hello, new software engineers! Welcome to the (slightly) dysfunctional BigCo family.

Some of you are coming from Ruby, some Java. A few of you still think we should rewrite everything in Node.js. The whole company, down to the last one-off script.

Good.

We've been doing things our way for a lot of years. We know why each thing is the way it is. Being so responsible beats you down over time, you know?

We know our coworkers, the battle-tested veterans we code next to each day. We know what they'll say to each of your naive, fun, uppity suggestions, alas. We got tired of arguing.

We remember the thrill -- "we should use this for everything!" Not just about Node.js. About every new technology. We love technology, just like you do.

We know all the reasons we shouldn't do the new exciting stuff at BigCo. We know them by heart. We throw buckets of cold water on the new exciting ideas just like our managers do. We don't hate new exciting ideas. We just feel like we should be responsible.

We really do care... I really do care about this code I'm writing. I can't spend all day on it without loving it a bit -- how could I?

You're looking toward a bright future. Unfortunately I'm going to dump cold water on your fun project ideas. So will the people around me.

I hope that you'll keep just a little of that precious perspective you have today.

Most of your ideas will go down in flames. I'll shoot some of them down myself.

But just like you're too naive to know all the reasons why not... We're too cynical to see the reasons why. Secretly, underneath where I don't tell anybody, I want you to convince me that it's the right thing to rewrite everything in Node.js. Everything. Not because I care about Node.js, but because hot damn would that be fun. I want to get up and do things, do the fun things.

Please. Convince me. Just a little.

I know I'm being a stick in the mud. I have to. Still, keep watch. Find, oh, I don't know, the three or four dumbest things we do here. Remind us that they're dumb. Show us how valuable your outside perspective is.

Perspective is precious. It really is. The old-timers here have long since lost it. Yours will trickle away, day by day, until you're like me.

Convince me that those three things are stupid. It won't be hard because they really are.

And in return, I'll let you rewrite one or two of them in Node.js.

Deal?


I love tech. A lot of what let me enjoy programming again was Ruby, Rails, and building frameworks. I'm writing a book to share the love. I hope it inspires you like I was inspired.

Your welcome message will contain a download link.
Posted: about 1 year ago (2012-04-17 03:19:39 UTC) / Updated: 8 months ago (2012-10-06 17:28:19 UTC)

Developers, Are You Sure That Payment Page is Secure?

Do you know a little JavaScript and HTML? Be sure the page is safe before you put in your credit card number -- especially if you want the product and don't know the vendor.

You can audit the page's security for yourself, especially if it uses Stripe. The early parts of the post are useful to check any payment processor.

I assume you know some HTML and JavaScript. We'll audit in order of importance. Start from the top.

Security

First, are they using HTTPS? Look for the green lock, green bar or equivalent for your browser.

Short version: no lock, no buy. You can skip to the next section if the lock is green.

No lock? They shouldn't be accepting your credit card number, full stop. Anything they send can be changed in transit without detection.

If they're using HTTPS but with a red or crossed-out lock, find out why. Mouseover or use WhyNoPadlock? (type the URL and hit "check").

A self-signed certificate is unusual but okay — especially if you're buying from another developer, who may not want to pay for an SSL cert. Insecure components on the page aren't great. It's hard for sites that scripts, ads and sharing buttons are often insecure. But the best sites have no insecure components, whether it's a developer running them or not.

Insecure components are a security liability.

JavaScript and Page Source

Now let's dig in.

We'll use https://rebuilding-rails.com/payment_page.html as an example.

See that green lock? So far, so good. Next, we check the code.

View the page source. Search for "stripe". Specifically, look for this:

1
<script type="text/javascript" src="https://js.stripe.com/v1/"></script>

If you can't find it, even in any sub-pages, the merchant probably isn't using Stripe. Then the rest of this post can't help you. You can check dev tools like "Scripts" or "Resources" and double-check, though that doesn't work if they're combining all the page JavaScript.

If you're really hard core, check the combined page JavaScript for "stripe" to be sure.

The Form

Now that you're sure they're using Stripe, we'll compare what the page does with Stripe's how to build a payment form tutorial to make sure they got the important parts right.

Find the form where you type payment information. You can "Inspect element" to find it in most browsers. Then in the page source, find it by the id or class.

On rebuilding-rails.com, for instance, you should look for "submit_payment" in the page source.

Example Payment Form
Payment Form

Names Have Power

The really important thing in this form is: name is not set for sensitive information. Your card number and expiration date should not have a 'name' in the page source.

Normally with Stripe your credit card number is in your browser and gets sent to Stripe.com, but rebuilding-rails.com won't ever see it. Name in an input says "send this to the server". So if you see <input name='credit-card-number' in the form, that means the server is getting all your information. Not good.

No name means "you can use it here on this page, but nowhere else." That's the right way.

A class is fine for your credit card number, expiration and CVC (security code). The class is how this page will find them (only in your browser). Only a name or explicit JavaScript will send to the server.

Code, Code, Code

Let's dig in deeper.

What else does the page do with your information? You found the class of the inputs for your information. In rebuilding-rails.com, it's class "card-number". So look through the page source and see where else that gets used.

On rebuilding-rails.com, the code looks like this:

JS code:  Secure Info Becomes a Token
Credit Card Info Turns Into a Token

You can see that rebuilding-rails.com does some kind of "local validity checks" -- that's exactly the kind of thing to check, and we will later.

Stripe.createToken() is the one thing that every Stripe site should do with your information and you want them to. That makes sure that Stripe can bill you without the site seeing your info.

And as you can see, that's it. Once you've checked the token, the page is safe and doing the right thing... As far as you can see.

Malevolence

None of this means the page is really secure. But it means the part you can see is done right, and that's a good sign. It also means they aren't getting around Stripe to steal your information... If you did a good job auditing them!

Safety

In the end, none of this replaces checking your credit card statements. But it's nice to be able to see when something is done wrong.

If it's wrong, don't risk it!

Are you the kind of Do-It-Yourself Programmer that wants to be able to audit page source yourself? Or write your own framework? My book, Rebuilding-Rails, can help you build your own web framework. Nobody audits the code as well as the guy who can build it from scratch!

Your welcome message will contain a download link.
Posted: about 1 year ago (2012-04-15 20:28:52 UTC) / Updated: about 1 year ago (2012-04-29 22:06:46 UTC)