The first beta of Rails 4.2 was announced last week, and it already looks amazing. I’m really excited to use ActiveJob, Web Console, Adequate Record, and Foreign Key support in my own apps.

But the beauty of Rails is in the details. And if you do a little digging, you’ll find some less advertised features that will totally improve your daily work with Rails.

Easily load config files

OK, I might be biased. But having a built-in way to load config files is going to be awesome.

config_for, new in Rails 4.2, works exactly like you’d expect:

config/redis.yml
1
2
3
4
5
6
7
8
9
development:
  host: localhost
  port: 6379
test:
  host: localhost
  port: 6379
production:
  host: redis-production
  port: 6379
1
2
irb(main):001:0> Rails.application.config_for(:redis)
=> {"host"=>"localhost", "port"=>6379}

That is, if you call config_for(:redis), it’ll look for config/redis.yml in your Rails app, parse it, and returns the right configuration for your RAILS_ENV.

It even lets you put ERB in your yaml:

config/redis.yml
1
2
3
4
5
6
7
8
9
development:
  host: localhost
  port: <%= ENV['REDIS_PORT'] %>
test:
  host: localhost
  port: <%= ENV['REDIS_PORT'] %>
production:
  host: redis-production
  port: <%= ENV['REDIS_PORT'] %>
1
2
3
4
$ REDIS_PORT=6380 bin/rails c
Loading development environment (Rails 4.2.0.beta1)
irb(main):001:0>  Rails.application.config_for(:redis)
=> {"host"=>"localhost", "port"=>6380}

If you configure lots of services in your app, this’ll make your initializers much easier to read.

Bootstrapping your apps

Most Rails apps need you to run some commands before you can try them out. Even mostly-empty Rails apps still need the database to be set up before they’ll boot.

So, Rails, once again going with convention over configuration, created a place specifically for your setup code: bin/setup.

The default is good. But bin/setup is also the place to put any other code you need to get your app started up.

So now that this is the convention, if you’ve already written a bootstrap script for your app, rename it to bin/setup, so people using your apps can get started easily.

bin/setup gives you one less decision to make when you generate new Rails apps. And once you get in the habit of running bin/setup after you git pull, you’ll never have to remember to run rake db:setup when you generate a new app again.

Transform your hash values

This is another thing I need often enough that I wish it was built-in to Ruby. When you call transform_values on a hash, it acts like calling map on the hash values, and returns a new hash with the original keys associated with the replaced values:

1
2
3
h = {a: 1, b: 2, c: 3}

h.transform_values { |v| v * 2 } # => {a: 2, b: 4, c: 6}

Simple enough. But you’d be surprised how often it comes in handy.

Bonus: More configuration!

Rails 4.2 offers a simple way to set your own global configuration:

1
2
3
4
Rails.application.config.x.some_configuration_key = "Some Value"

Rails.application.config.x.some_configuration_key # => "Some Value"
Rails.configuration.x.some_configuration_key # => "Some Value"

This works especially well when you combine it with config_for:

1
2
app_config = Rails.application.config_for(:app)
Rails.application.config.x.block_phone_calls = app_config["block_phone_calls"]

And there’s more!

It looks like Rails 4.2 is set up to be an amazing release. But it’s the little refinements that make it so great to work in Rails every day. So, if you haven’t yet, take a quick look through the 4.2 Release Notes and see which other helpful improvements you can find.

(And if you do find some cool stuff, don’t keep it to yourself. Share it here, so we can all learn something new!)

Rails’ i18n library is more powerful than it looks. You don’t need to only use it for translation. The i18n library is useful anywhere you want to decouple the text you display from the place you display it.

While I’ve been at Avvo, we’ve used i18n to do some really cool stuff. I’m going to share a few of the things that we learned that have come in handy, along with a crazy abuse of the library that ended up working out incredibly well for us.

Automatic HTML escaping

Do you have lines that look like:

1
<%= raw(t('form.required_field_header')) %>

in your views? You don’t need that raw, because if your translation key ends with _html, you get escaping for free:

1
<%= t('form.required_field_header_html') %>

Simple, and more consistent with your other t() calls.

Accessing locales more conveniently

When you build your locale files, you’ll probably have some of your keys grouped under the same parent:

1
2
3
4
5
6
en:
  bugs:
    index:
      new_label: "File a new bug"
      edit_label: "edit"
      delete_label: "delete"

To reference a bunch of these all together, you could reference them by their full key:

1
<%= t('bugs.index.edit_label') %> | <%= t('bugs.index.delete_label') %>

That’s pretty annoying and repetitive. But t() helpfully takes a scope, so you can reference keys more conveniently:

1
2
<% bugs_scope = 'bugs.index' -%>
<%= t('edit_label', scope: bugs_scope) %> | <%= t('delete_label', scope: bugs_scope) %>

If you name your partials well, you don’t even need to specify the scope:

app/views/bugs/index.html.erb
1
<%= t('.edit_label') %> | <%= t('.delete_label') %>

That is, .edit_label references bugs.index.edit_label, because you’re in bugs/index.html.erb.

ActiveRecord backends

Sometimes, static translations in a yaml file just won’t work for your project. If you use the ActiveRecord i18n backend instead:

config/initializers/locale.rb
1
2
require 'i18n/backend/active_record'
I18n.backend = I18n::Backend::ActiveRecord.new

you can look up translations in a translations table in your database. This way, you don’t have to define all your translations up-front. Instead, you can add new translations on the fly.

Setting up the translations table requires a specific migration. The README on the i18n-active_record repo has all the information you need to get it working.

Sharing partials between object types

At Avvo, we have a lawyer directory, attorney reviews, and legal advice. But a few years ago, we didn’t just have lawyers on our site. We had doctors and dentists, too!

A lot of our UI was the same between these professions. But enough was different (for example, what lawyers call “practice areas”, doctors call “specialties”), that it would be hard to share the same views or partials without some pretty ugly code.

Eventually, we thought about trying to lean on the i18n system for this. After all, English lawyerese is kind of a dialect of English, and doctorese is the same way. We didn’t want to block ourselves from eventually using other languages, so we decided to create two new locales: en_jd and en_md.

This turned out to be easy to set up as a custom i18n backend:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class AvvoI18nStore < I18n::Backend::Simple
  def translate(locale, key, options = {})
    begin
      default = options.delete(:default)
      super(locale, key, options)
    rescue I18n::MissingTranslationData => e
      # fall back to "en" if we can't find anything under "en_jd", etc.
      fallback_locale = locale.to_s.split("_").first
      super(fallback_locale, key, options.merge(:default => default))
    end
  end
end

I18n.backend = AvvoI18nStore.new

And defining translations was just as easy:

1
2
3
4
5
en_jd:
  practice_area: "practice area"

en_md:
  practice_area: "specialty"

It worked great for translating entire partials, too (note the filename):

app/views/questions/_answer_badge.en_jd.html.erb
1
<!-- Lawyer badge HTML -->
app/views/questions/_answer_badge.en_md.html.erb
1
<!-- Doctor badge HTML -->

And it even fell back to the en locale, for shared translations:

1
2
3
en:
  leaderboard:
    title: "Leaderboard"

When you were in the “Doctors” section of the site, we changed the default locale to :en_md, and vice versa:

1
I18n.locale = :en_md

And everything just worked!

I’m not sure I’d recommend this. It’s a little nuts, thinking of different professions having different languages. But it worked amazingly well while we did it. And it reveals just how much power simple tools like i18n can have.

Where do you pick up this stuff?

Last week, I talked about taking deep dives into specific technologies as a way to move from a beginner to an expert. This is another example of that: most of what we learned about i18n we learned from reading the Rails guides and API docs.

So, take that extra step. Learn the tools you rely on well. You’ll find that you’ll run into conveniences and tricks that will not only make you more productive, but might unlock brand new categories of solutions you’d never even have thought of otherwise.

So, you’ve finished a few Rails tutorials. You might have taken a class or two or watched some screencasts. You’ve followed along and built a copy of some tutorial apps. It’s pretty clear that it’s time to move to the next level in your Rails development.

Somehow, though, you’re stuck. There are tons of books, classes, and videos for people just starting out. But where are all the tutorials for intermediate Rails devs?

It’s not like it was before

Once you pass the beginner, “building baseline knowledge” stage of being a Rails developer, the resources dry up. Why is that?

Becoming an intermediate Rails developer is nothing like being a beginner. It might seem like it’s just a little different, with some more complicated stuff to learn. But passing through the intermediate stage of learning is a totally separate process.

Don’t think of it as, “A beginner knows this stuff. An intermediate developer knows all that stuff a little better, plus some extra things off to the sides.” For an intermediate developer, learning is more focused. Instead of knowing a little about a lot, you’ll learn a lot about a little.

Find a few areas to focus on. Learn more details about testing and TDD. Learn a few of the design patterns that Rails encourages, in depth. Learn about how you should design a great data model. But don’t learn it all at once. Learn one thing at a time, and learn it really well.

Once you understand the Rails basics, you’ll know enough to read API documentation, even if you don’t understand all of it yet. You could read the best books on TDD, even if they’re not written specifically for Rails. After you’ve seen enough examples of Ruby code, you can go source-diving and understand parts of Rails at a level that few others do.

When you concentrate on learning one thing well, there are many more resources to learn from. And each thing you learn will make every other thing easier to learn.

(If it seems easy for people to pick up their third or fourth language, this is one reason for it. A lot of the core concepts stay the same, which means there’s a lot less you have to learn to travel through the intermediate stage in a new language).

How do you choose what to play with next?

If you’re going to learn one thing at a time, you have to choose what to focus on first. But how do you pick, when there’s so much to learn?

Doesn’t it always seem easier to learn something when you’re interested in it? It definitely does for me. So, what’s the best way to force yourself to be interested in learning something new?

Write your own apps! Lots and lots of apps. Write apps, modify apps, add features to existing apps.

When you write an app, you will get stuck. You’ll get stuck a lot. But that’s a great thing! You should learn to love the stuckness, because it means you’re about to learn something new. Being stuck is awesome, and the more you can enjoy it, and even seek it out, the faster you’ll become an expert.

Once you research, learn, and write a solution, try to do it again in another app. Try to write it without looking at the documentation. Really learn it. Then, continue building your app, and watch for the next place you get stuck.

I love learning this way, because you get to focus on the stuff you’re going to run into most often. You’ll learn faster, because you’re not just studying to study. You’re trying to figure out how to solve a problem. And isn’t that why you fell in love with software development to begin with?

But you can’t get them all this way

After you understand the basics of Rails, you can learn serendipitously. If you understand what intermediate and expert Rails devs are talking about, you can accidentally run into conversations that will take your studying down really interesting paths.

So, when I get past the beginning, tutorial stage of learning something new, I subscribe to a bunch of blogs. I follow some of the leaders of the community on twitter. I subscribe to the WhateverWeekly newsletter for the language (RubyWeekly, iOS Dev Weekly, JavascriptWeekly, etc.).

You don’t have to read it all. You shouldn’t read it all. But let good stuff hit your radar, and try to read and follow the things that seem interesting. I’ve learned some really great tips this way, and they’ve led me into some useful topics I might not have encountered until much later.

So, what are you going to learn next?

If you’re feeling stuck because you can’t find great intermediate resources, take control of your learning. Start building an app, and pay attention to how you build it. Try something you’re only halfway sure will actually work, and seek out places you can get stuck. Use that stuckness, and find API docs, guides, or tutorials on just that small part. Go source-diving if you need to. (It might feel weird at first, but the more you look at Rails code, the more comfortable you’ll feel with it).

Really understand a small part, become an expert in it. And then, move on to the next thing.

You want to test-drive some code, but you’re stuck. Maybe you’re not totally sure what your object’s interface should look like. Maybe you’re distracted by another sunny summer day. You might not be sure you can test what you’re thinking of building. Or you could be procrastinating, because you just don’t feel like writing tests right now. How do you get the benefits of TDD when you don’t feel like TDDing?

Prototyping, or building one to throw away

“Where a new system concept or new technology is used, one has to build a system to throw away, for even the best planning is not so omniscient as to get it right the first time. Hence plan to throw one away; you will, anyhow.” — Fred Brooks

Sometimes, when I start a new feature, I’ll feel paralyzed when I think about writing my first tests. There are so many decisions to make about how the API should look, which patterns and practices will be most appropriate, and how it should all fit together.

I have a few ways I get started when I’m stuck like that. Building a prototype is another.

When you write a prototype, you should think of it like a sketch. Brainstorm and try things out. Don’t bother with tests or TDD yet. Instead, explore the decisions you’re having a hard time making, with code. Try out a few patterns, and see which of them fit the feature you’re trying to design. Figure out where the shaky parts of your app are, what needs more thought, and what you were worrying about for no real reason.

Then, throw it away and rebuild it. This time, using TDD and your newfound knowledge about how you can best build the feature.

You know when you accidentally run git checkout -f after you wrote something, and you get that feeling like you just got kicked in the stomach? But then you figure, this has to be built, so I guess I’ll do it again, and it turns out much better than it did the first time? This is also true with rebuilding prototypes. Now that you have some solid ideas of how the feature could look, TDDing that feature will go a lot more easily.

Reverse TDD

Have you ever run into a situation where you know how to build something, but you don’t know how to write the tests for it first? Or maybe it’s a one-line change to a method, but it might need some tweaking, so you don’t want to lock it down with a test before you know what the change will actually look like?

There’s a simple process that helps a lot with these situations:

  1. Write the code, without tests.
  2. Write a test for the code. Make sure it passes.
  3. Comment out the code you wrote, or revert the file you made the code change in.
  4. Run the test again. Make sure it fails.
  5. Write the code again. Run your tests. Make sure they pass.
  6. Refactor the code, taking advantage of your new tests.

I think of this as Reverse TDD or Green-Red-Green-Refactor. You won’t get the “test-driven design” part of TDD, but you’ll still get to see your tests fail when your code is broken. That’s important, because you can’t trust tests that don’t fail at least once.

Reverse TDD usually works best with tiny changes that don’t need much design. Think bugfixes, or changes that are localized to a single line, method, or class. But I use this technique a lot, especially for small changes that I’m still playing with.

The Pairing Game

The Pairing Game is a great way to break out of your Red-Green-Refactor routine when you have another developer around. It works like this:

  1. Find a partner.
  2. You write a test that will break.
  3. Your partner tries to fix that test with the simplest code possible.
  4. You write another test that will fail on that code.
  5. Your partner writes code that will pass that test.
  6. Repeat…
  7. At some point when the tests are green, you can choose to refactor some code instead of writing a test.
  8. After refactoring, swap tester and coder positions.

I’ll let you in on a secret: playing the Pairing Game on a bowling score calculator is how I originally learned TDD. It’ll help you practice writing simple code based on failing tests, and writing those tests to begin with. Both developers will learn a lot about each other’s coding style and favorite techniques. And you’ll hit flow almost immediately, which means you’ll feel great when you finish.

You might not produce code as quickly, but it’s a lot of fun, and a great learning experience.

Stay playful and experiment

TDD shouldn’t be dogma. There are ways you can play with the core TDD concepts that can lead you to some really interesting places. And you might end up with even better code.

So experiment. Try new approaches to writing code and TDD. See how they make you feel, and what kind of code you end up with. And keep rediscovering the fun and the flow in the work you do each day.

Memoization is a technique you can use to speed up your accessor methods. It caches the results of methods that do time-consuming work, work that only needs to be done once. In Rails, you see memoization used so often that it even included a module that would memoize methods for you.

Later, this was controversially removed in favor of just using the really common memoization pattern I’ll talk about first. But as you’ll see, there are some places where this basic pattern just doesn’t work right. So we’ll also look at more advanced memoization patterns, and learn some neat things about Ruby in the process!

Super basic memoization

You’ll see this memoization pattern all the time in Ruby:

app/models/order.rb
1
2
3
4
5
6
class User < ActiveRecord::Base
  def twitter_followers
    # assuming twitter_user.followers makes a network call
    @twitter_followers ||= twitter_user.followers
  end
end

The ||= more or less translates to @twitter_followers = @twitter_followers || twitter_user.followers. That means that you’ll only make the network call the first time you call twitter_followers, and future calls will just return the value of the instance variable @twitter_followers.

Multi-line memoization

Sometimes, slow code won’t fit on one line without doing terrible things to it. There are a few ways to extend the basic pattern to work with multiple lines of code, but this is my favorite:

app/models/order.rb
1
2
3
4
5
6
7
8
9
class User < ActiveRecord::Base
  def main_address
    @main_address ||= begin
      maybe_main_address = home_address if prefers_home_address?
      maybe_main_address = work_address unless maybe_main_address
      maybe_main_address = addresses.first unless maybe_main_address
    end
  end
end

The begin...end creates a block of code in Ruby that can be treated as a single thing, kind of like {...} in C-style languages. That’s why ||= works just as well here as it did before.

What about nil?

But these memoization patterns have a nasty, hidden problem. In the first example, what if the user didn’t have a twitter account, and the twitter followers API returned nil? In the second, what if the user didn’t have any addresses, and the block returned nil?

Every single time we’d call the method, the instance variable would be nil, and we’d perform the expensive fetches again.

So, ||= is probably not the right way to go. Instead, we have to differentiate between nil and undefined:

app/models/order.rb
1
2
3
4
5
6
class User < ActiveRecord::Base
  def twitter_followers
    return @twitter_followers if defined? @twitter_followers
    @twitter_followers = twitter_user.followers
  end
end
app/models/order.rb
1
2
3
4
5
6
7
8
9
10
class User < ActiveRecord::Base
  def main_address
    return @main_address if defined? @main_address
    @main_address = begin
      main_address = home_address if prefers_home_address?
      main_address ||= work_address
      main_address ||= addresses.first # some semi-sensible default
    end
  end
end

Unfortunately, this is a little uglier, but it works with nil, false, and everything else. (To handle the nil case, you could also use Null Objects and empty arrays to avoid this problem. One more reason to avoid nil!)

And what about parameters?

We have some memoization patterns that work well for simple accessors. But what if you want to memoize a method that takes parameters, like this one?

app/models/city.rb
1
2
3
4
5
class City < ActiveRecord::Base
  def self.top_cities(order_by)
    where(top_city: true).order(order_by).to_a
  end
end

It turns out that Ruby’s Hash has an initalizer that works perfectly for this situation. You can call Hash.new with a block:

1
Hash.new {|h, key| h[key] = some_calculated_value }

Then, every time you try to access a key in the hash that hasn’t been set, it’ll execute the block. And it’ll pass the hash itself along with with the key you tried to access into the block.

So, if you wanted to memoize this method, you could do something like:

app/models/city.rb
1
2
3
4
5
6
7
8
class City < ActiveRecord::Base
  def self.top_cities(order_by)
    @top_cities ||= Hash.new do |h, key|
      h[key] = where(top_city: true).order(key).to_a
    end
    @top_cities[order_by]
  end
end

And no matter what you pass into order_by, the correct result will get memoized. Since the block is only called when the key doesn’t exist, you don’t have to worry about the result of the block being nil or false.

Amazingly, Hash works just fine with keys that are actually arrays:

1
2
3
h = {}
h[["a", "b"]] = "c"
h[["a", "b"]] # => "c"

So you can use this pattern in methods with any number of parameters!

Why go through all this trouble?

Of course, if you start adding these memoization patterns to a lot of methods, your code will get pretty unreadable pretty quickly. Your methods will be all ceremony and no substance.

So if you’re working on an app that needs a lot of memoization, you might want to use a gem that handles memoization for you with a nice, friendly API. Memoist seems to be a good one, and pretty similar to what Rails used to have. (Or, with your newfound memoization knowledge, you could even try building one yourself).

But it’s always interesting to investigate patterns like this, see how they’re put together, where they work, and where the sharp edges are. And you can learn some neat things about some lesser-known Ruby features while you explore.

(I sent this post to my list a while back. If you enjoy it, and want to read more like it, you should sign up!)

The Rails ecosystem moves fast, way too fast for print. If you’re like me, you want to learn the most recent version of your frameworks and gems. But the best resources are often a few versions behind.

These resources are still useful, though. There’s nothing like a well-edited book, screencast, or tutorial to learn a library’s API, philosophy, and structure.

For example, if the best Rails books only describe Rails 4.0, you should still start from there. When you’re learning a new gem or framework, it’s important to learn why it’s designed a certain way and how all the pieces fit together. That’s hard to get from reference documentation and blog posts, but easy to get from books.

But once you build experience with an older version of a gem, how do you get caught up?

Catching up with changes

Most popular gems have CHANGELOG files in their git repository, like bundler: https://github.com/bundler/bundler/blob/master/CHANGELOG.md. These are a great way to catch up on the big changes from version-to-version. Usually, they’re just a short summary of each major change. But they give you a starting point, so you can do more research on interesting changes.

Many changelogs reference bug numbers on GitHub. If you see an entry in a changelog that has a bug number attached, you can find the bug in the project’s Issues to understand what changed, how it changed, and why it changed.

So, how do you find changelogs? Usually, I just search google for bundler github (if I’m looking for the bundler changelog), and they’re usually on the first GitHub page you see.

If there isn’t a changelog, you can also look at the project’s README or the project’s wiki on GitHub. But since those aren’t designed to help you catch up from version-to-version, they usually take longer to go through.

Using up-to-date reference documentation

When you’re working with gems, you’ll also need to keep up-to-date reference documentation around. That way, you can look up API usage and see examples while you’re writing your own apps.

You can find API documentation for any version of any gem at rdoc.info. But for even faster doc lookup, you should check out Dash or Zeal.

I use Dash, so when I need to look up API docs, I hit option-Space, start typing, and all my gem documentation shows up instantly. It’s a change in my workflow that’s paid for itself many times over.

A few tips on Rails, specifically

Rails is a large project, and the Rails contributors do a great job of maintaining changelogs and documentation.

The Rails guides are good, and they’re also built from the same git repository as Rails, so they’re always up to date.

If you’re trying to catch up to the newest version of Rails, the release notes are the best place to start. For example, here are the release notes for Rails 4.1: http://guides.rubyonrails.org/4_1_release_notes.html

The process I usually take

Putting it all together, this is what I do when I want to get completely up to date on a new library:

  1. Read a book, tutorial, or documentation about the gem. I usually try to find the newest resource I can. While I’m reading, I build an app, practice, etc. on whichever version I’m learning.
  2. Find the project on GitHub.
  3. Read the project’s changelog, readme, or wiki to take me from the version I know to the most recent version.
  4. If I’m interested in a specific change, google around for it or go through the project’s issues to learn more.
  5. Upgrade to the newest version of the gem.
  6. Install the new gem’s documentation in Dash.
  7. Write code with it!

I don’t do all those steps all the time. But that’s generally the order I go in, and this kind of process is helpful to keep around in case I get stuck on a step or don’t know where to go next.

What if you can’t find a changelog or can’t make sense of the docs?

Sometimes you just won’t be able to get the information you need out of the gem’s GitHub repo or API documentation. When that happens, you’ll have to dive into the code and start reading it.

Surprisingly, reading code is not like reading a book. Instead of reading files from beginning to end, you have to explore the code. This is more of an art than a science, but it’s an important skill to learn. So, I’ll probably have more to say about it later!

What tricks have you learned for getting caught up on gem changes? How do you stay up to date?

API docs will tell you how to use an API. But when things go wrong, you can be left on your own. Error messages are often incomplete, misleading, or unhelpful. And what are you supposed to do with NoMethodError: undefined method '[]' for nil:NilClass, anyway?

When you learn an API, framework, or library, you can’t just learn how to use it when things go well. You also need to figure out what to do when it hands an error back.

How do you break code?

There’s an easy way to learn what to do when an API you’re using breaks. Break it yourself!

For example, I’ll:

  • Pass data of the wrong type. You could pass a symbol instead of a String, a String instead of an Array, a Hash instead of an Array, things like that.

  • Pass incomplete data. You can pass nil, hashes without some fields filled out, and objects that have just been initialized.

  • If the API requires network access, disconnect from WiFi or pull the network cable. Does it just time out, or does it tell you which service it couldn’t reach?

  • If the API allows you to pass in a block, throw exceptions inside the block, or return data of the wrong type.

A great API will tell you what you did wrong. An excellent API will tell you how to fix it. But most often, you’ll run into a Ruby NoMethodError, unexpected nils, or, worse, getting totally bizarre return values back.

Why break code?

This isn’t all bad. If you’re playing with an open-source gem, you can take time to understand where that unexpected behavior came from and why it happened. You can debug and read a little bit of code to learn a lot about how the library or API works.

Once you discover where the NoMethodError is coming from, you can go a step further. You can fix the error message for the next person to run into this problem for real! Little error message fixes make great open-source contributions and easy pull requests. And they make the entire Ruby ecosystem a little better for everyone else.

Even if it’s a closed-source REST API, you can still get something out of this exercise. After you see the different errors you’ll get from the API, you’ll have an easier time fixing the problem when you run into an error for real.

Once you become more comfortable seeing and fixing errors in the code around you, you’ll see broken code as a puzzle to be solved. You won’t automatically recoil when you see an exception and backtrace dumped to the screen. Instead, you’ll see them as an opportunity to learn more about the system you’re working with.

Finally, you’ll know that when code breaks, you’ll be able to put it back together again. You’ll improve your confidence in trying new libraries and APIs. And that boldness will increase your rate of learning new things.

There’s a lot of good, free Rails information around. But as you improve your development skills, it can be hard to find knowledge that’s useful to you.

If it’s too basic, you’ll just read about things you already know. Too advanced, and your eyes glaze over and your brain shuts off. Three paragraphs in, and you don’t even remember what your name is anymore!

You can’t just type “intermediate-level Rails blogs” into Google and hope some good sites pop out. To get the information you’re looking for, you’re going to have to do some digging.

Finding & filtering

First, look wide and shallow. When you use social sites like reddit, twitter, and Stack Overflow, click on every link that looks interesting to you. Skim an article or two on each site, and if the site seems interesting, keep it around.

Next, you can filter and curate. You should build a place where posts find you. If you use an RSS reader (I use Feedbin), subscribe to the site. If you prefer email, sign up to receive email updates. You just want to be sure you see new articles as they come in.

If you skip more than a few articles from a site, unsubscribe. Eventually, you’ll find a small group of people that you enjoy hearing from, who post things you’re interested in, and that you can learn something from.

They’ll grow along with you, and the articles will get more advanced at a rate you can handle. Plus, they’ll often link to the people who they find insightful, which is a much faster way of finding people to learn from.

It’ll take a while to build this group. But you’ll get a little bit more of a benefit from every site you find.

Learn serendipitously

This doesn’t completely solve the “at your level” problem. But I have a little secret: Finding people at just the right level for you isn’t actually all that important. Many of my favorite writers write things that are way more basic or way more advanced than my current skill level.

How does this work?

When something is too basic, you can think of it as a way to review your fundamentals. The first time you learned something, you might have formed bad habits or internalized some ideas incorrectly. When you review basic information you get a second chance to think about and improve those things.

I had this happen when I read Eloquent Ruby as part of the RubyRogues’ book club.

The first few chapters were really basic—I almost stopped reading it, because I didn’t think I’d learn anything interesting. But I went through it, I focused on it as if I was learning Ruby for the first time. And I came out of it with some Ruby tricks and conventions that I had totally forgotten about.

What about articles that are too advanced? You can get a lot out of those, too:

  • You get introduced to more jargon and patterns. Even if you can’t understand what the terms mean, you can search for the ones that sound interesting. You might find some better descriptions, or other good sites to subscribe to!

  • The more often you see an advanced idea, the less you’ll be intimidated by it when you have to learn it for real. It’ll also be easier to learn, because you will have already learned a little about it from seeing it in context.

Just for fun, I subscribe to some CS and math blogs that assume my math skills are way beyond where they actually are. Sometimes I only get a paragraph or two into the article before I give up. But the paragraphs I do read are some of the most interesting and insightful things that come through my feed reader.

You do have to come into advanced blogs and resources with the right mindset. You can’t let them intimidate or overwhelm you. You have to remember that it’s not a reflection on you if you don’t get it. And getting anything out of an article that’s beyond your skill level is a big accomplishment.

So, find some interesting articles. Follow some blogs. If they stay interesting, keep them around. Even if they’re not quite at your current skill level.

Last week, I wrote about methods with consistent return values, and how they’ll make your code simpler. But how does that happen? How can the right refactoring make your code easier to work with? What makes good abstraction good, and bad abstraction bad? I mean, you can’t just blindly rearrange your code and end up with quality software.

If you can learn why these techniques work, you’ll be better able to understand where your code needs help. And you’ll be able to use the right tools where they matter most.

What’s the hardest problem in software development?

“There are only two hard problems in Computer Science: cache invalidation and naming things.”

— Phil Karlton

Sure, that quote is everywhere. But there’s actually a harder problem in real-world software development: managing complexity. Complexity in software development has a few different definitions. At its core, though, the complexity of a program is the amount of stuff you have to keep in the front of your mind while you’re working on it.


As you write more software, you’ll be able to keep more stuff in your head at once. But even the best devs have limits. If your project is too complex, you’ll overload what your mind can handle, and you’ll start forgetting about different areas of your program. And the worst bugs show up when you make a change in one part of your project without realizing how the change will affect a totally different part of the same project.

Simplifying through assumptions

If you had photographic memory, and could remember how all the different parts of your program fit together, you’d have a lot fewer bugs, right? Memory can be hard to build. But you can get a lot of the same benefits from being able to focus on one thing at a time.

Many best practices in software development are about reducing the number of things you have to keep in your mind at once. A few examples:

  • Consistency in your return values means you only have to think about how to deal with one kind of data, instead of different kinds of data in different situations.

  • Abstraction is a way to hide code behind a simpler interface. With good abstractions, you can just think about how the abstraction should act, and you don’t have to worry about how it works on the inside.

  • Testing can keep you from accidentally breaking code in one area while you’re working in another. You can assume that anything you accidentally break will be caught. This means you can focus just on the code you’re working on, and fix anything you break later.

  • Test-Driven Development will help you write code that will work the way you expected it to work. You can concentrate on writing the simplest possible implementation of your method that passes the tests. If it’s too simple and doesn’t actually work as you’d expect, your tests will catch it.

When you use these techniques in the right way, you can make some good assumptions. With these assumptions, you don’t have to keep anywhere near as much in the front of your mind. You can write better, more reliable code, because you don’t have to worry about the nearly infinite consequences your code could have on the system.

On the other hand, using these techniques in the wrong place will hide code that you actually need to see. By hiding the code, the assumptions you make will sometimes be wrong. This makes it even more likely that you’ll end up breaking it!

That’s why bad abstractions are worse than no abstraction at all, and why you can’t just throw “extract method” at code until it magically becomes good.

Right refactoring, right place

Clear code is code that’s up-front about what it’s doing. Showing what you’ll need to know is as important as hiding what you don’t need to know. When you perform a refactoring, or use a software best practice, you should think about the code you end up with, and how well it’s helped you reduce complexity. Are you helping the rest of the code make good, simplifying assumptions? Or are you burying essential knowledge behind a too-simple interface?