After you pick up the Rails basics, you still have a lot to learn. You have to understand gems, DSLs, refactoring, testing, and the deeper parts of Rails itself.
With the Ruby Book Bundle, launching on Monday, July 6, you can kickstart your Rails education with Practicing Rails and 5 other great Ruby books at a huge discount. Sign up to get a reminder when the bundle sale starts!
Imagine a question that can be either “pending”, “approved”, or “flagged”. Or a phone number that’s a “home”, “office”, “mobile”, or “fax” (if it’s 1982).
Some models call for this kind of data. An attribute that can have only one of a few different values. And that set of values almost never changes.
It’s a situation where, if it were plain Ruby, you’d just use a symbol.
You could create a PhoneNumberType or QuestionStatus model and a
belongs_to relationship to hold these values, but that doesn’t seem worth it. You could stuff them in a yaml file, but now you have to look in a totally different place to figure out what your object can do.
In 4.1, Rails took a stab at solving this problem with ActiveRecord enums.
A few values, in the model
ActiveRecord enums are pretty easy. You give your model an
List the values that attribute can take:
1 2 3
And now you can deal with strings instead of numbers.
Instead of this:
You’ll see this:
You can change that attribute using either strings or ints:
1 2 3 4
Or even using a bang method:
1 2 3 4
You get methods for asking if your attribute has some specific value:
And you can find all objects with the value you’re looking for:
If you want to see all the different values you can use, along with the numbers they’re associated with, use the
phone_number_types class method:
Which makes them easy to put into an HTML form:
1 2 3 4
A few things to watch for
Enums aren’t without their problems, though. You have to keep a few things in mind if you don’t want to run into trouble later on.
When you define an enum, order matters. So if you go back to your code and decide that those values should really be in alphabetical order:
1 2 3
Your phones won’t have the right types anymore. You can get around this by telling
enum which number goes with which value:
1 2 3
But really, your best option is to keep the order consistent.
A bigger problem is what to do outside the Rails world. Even though Rails sees these enum values as strings, they’re just numbers inside your database. So someone looking at your raw data will have no idea what those numbers mean. This also means that every app that reads that database will have to know that enum mapping.
You could dump your enum mapping to the database or a yaml file if you really needed other people to see them. But that’s not DRY, because now you’re defining your enum in two places. And if you’re going that far, it might be better to do what we were avoiding in the beginning: create a totally separate model and association, so that a Phone would
belong_to a PhoneNumberType.
But if you’re keeping it simple, enums are a great way to start.
P.S. In case you missed it, Practicing Rails is going to be included in the Ruby Book Bundle, launching on Monday, July 6. Get it and 5 other great Ruby books at a huge discount!
Rails’ scopes make it easy to find the records you want:
1 2 3 4 5
1 2 3 4
But if you’re not careful with them, you’ll seriously hurt your app’s performance.
Why? You can’t really preload a scope. So if you tried to show a few restaurants with their positive reviews:
1 2 3 4 5 6 7 8 9 10
Yep, that’s an N+1 query. The biggest cause of slow Rails apps.
You can fix this pretty easily, though, if you think about the relationship in a different way.
Convert scopes to associations
When you use the Rails association methods, like
has_many, your model usually looks like this:
1 2 3
But if you check out the documentation, you’ll see that they can do more. You can pass other parameters to those methods and change how they work.
scope is one of the most useful. It works just like the
scope from earlier:
1 2 3 4
1 2 3 4
Now, you can preload your new association with
1 2 3 4 5 6 7
Instead of 6 SQL calls, we only did two.
class_name, you can have multiple associations to the same object. This comes in handy pretty often.)
What about duplication?
There still might be a problem here. The
where("rating > 3.0") is now on your Restaurant class. If you later changed positive reviews to
rating > 3.5, you’d have to update it twice!
It gets worse: If you also wanted to grab all the positive reviews a person has ever left, you’d have to duplicate that scope over on the User class, too:
1 2 3 4
It’s not very DRY.
There’s an easy way around this, though. Inside of
where, you can use the
positive scope you added to the Review class:
1 2 3 4
That way, the idea of what makes a review a positive review is still only in one place.
Scopes are great. In the right place, they can make querying your data easy and fun. But if you want to avoid N+1 queries, you have to be careful with them.
So, if a scope starts to cause you trouble, wrap it in an association and preload it. It’s not much more work, and it’ll save you a bunch of SQL calls.
There are a ton of books, videos, podcasts, and courses for learning Rails. There’s no way you’d have time to go through them all! So what’s the best way for an absolute beginner to learn Ruby and Rails? Which resources should you start with, and when?
Books and websites
If you’re totally new to programming, the best place to start is Learn to Program, by Chris Pine. It’s an intro to the core programming ideas you’ll need to know. If you’re planning to learn Ruby and Rails, it’s especially great, because it uses Ruby for all of the examples.
After that, Daniel Kehoe’s Learn Ruby on Rails is a gentle introduction to Rails. It teaches you a small part of Rails that will prepare you to take on the harder resources.
If you already know a few other languages or frameworks, check out the free Getting Started with Rails guide. It’s a good, short intro to Rails, that will teach you Rails’ concepts and core ideas.
Once you know the basics, there are two bigger books that will fill out your Rails knowledge.
Agile Web Development with Rails is my favorite general Rails book. It does a good job of teaching first by example, and then by reference. We use it at work to teach devs without Rails experience, and like most of the rest of the Pragmatic Bookshelf books, it’s very good.
The Ruby on Rails Tutorial is the other big Rails resource. It walks you through most of what you need to know to build a fully functional example app. I know a lot of great Rails developers who got started with the Rails Tutorial. And the web version is free, so you can see if it’s your style before you commit to it. If you put in the effort, you’ll get a lot out of it.
Once you’ve gone through one or two of these books, it’s pretty normal to feel confused and frustrated. Especially when you try to put everything together and build your own apps. My book, Practicing Rails, will help you solve the most painful problems you’ll run into as you start your programming career. In Practicing Rails, you’ll learn how to debug your code when it breaks, pick up some processes you can follow to turn the ideas in your head into real features, and discover how to write tests without getting stuck.
While you build your own apps, there are two resources you’ll use more than any others:
The Rails Guides will teach you the most important parts of Rails with documentation and examples. I go back to these all the time. And they’re always up to date.
When you want to know how to call a Rails method, or even whether a method exists to do what you want to do, you’ll need the official Rails API documentation.
(There are much better ways of browsing the API documentation, though, and I talk through a few of them in one of the lessons in my free email course).
You can start building simple apps without knowing a whole lot of Ruby, but spending more time learning Ruby will become important, quickly. And Programming Ruby is the best book I’ve found to get comfortable with the language.
Videos and guided courses
Books and websites are my favorite way to learn new things about Ruby and Rails. But if you prefer watching to reading, there are lots of great screencasts and courses you can check out, too.
If you want a video course to teach you Ruby and Rails, I’ve heard lots of praise for the Pragmatic Studio courses. They sound like a great place to start.
The RailsCasts haven’t been updated in a few years, but they’ll still show you great answers to common web problems. The APIs might have changed, but the ideas have stayed pretty much the same. They’re definitely worth watching.
Avdi Grimm’s Ruby Tapas screencasts will show you fun Ruby code in 5-10 minute videos. They’re Ruby-focused (rather than Rails-focused), but I always learn a lot from them. You can find a few free sample videos on the site, but they’re all great. It’s really worth subscribing to.
The Destroy All Software screencasts aren’t specifically about Ruby and Rails, but watching them will make you a better developer, whatever your language.
Finally, bloc.io is an online bootcamp some readers have recommended. They pair you with a mentor who can help you with your specific problems when you get stuck.
One-on-one help is great – it can be exactly what you need while you’re learning. If you can’t find a friend or mentor to help you out, I wrote an email to my list about where you should look. (By the way, you can sign up here to get helpful emails like that every Friday).
What do I recommend?
I know, that’s still a whole lot of stuff! My recommendation, if you like reading and already know the programming basics, is to start with Programming Ruby and Agile Web Development with Rails. While you read, build some tiny sample apps to try out the things you learn. (You’ll learn more about how to do that in the free sample chapter of Practicing Rails).
Do you have any other recommendations for resources that helped you out? Anything you can’t believe I missed? Comment and tell us all about them!
You’re confident about the core ideas behind Rails. You can write working code, no problem. And you’re learning more about code quality, refactoring, writing great tests, and object-oriented design.
By this point, you’re starting to feel like you’re getting it, that you’re on the path to becoming an expert. When you look backwards, you see just how far you’ve come, and you’re pretty happy with your progress.
So why do you feel so slow? Now that you care about testing, maintainability, and design, it feels like it takes you way more time to ship anything!
Is it even possible to ship high quality code quickly?
It’s all part of the process
This feeling is incredibly common, no matter what you’re learning.
Now that you’re no longer a beginner, you’re starting to see all the different shapes that your code could have. You have more alternatives to think through whenever you put down a line of code. You have to test edge cases you never recognized before.
You’ve learned lots of helpful skills. But right now, they still take a lot of thought. You have to weigh every decision you make, so you feel comfortable that you’re making the right decision based on the things you’ve learned.
It will get faster, though. The skills you’ve learned will become more automatic. You’ll build intuition. And you’ll be able to make better decisions more quickly.
Which is nice to know, but it doesn’t help you right now. So what can you do now, to finish things faster?
Take it in stages
If you’re obsessed with writing perfect, high-quality, highly-maintainable code every time you put your fingers on the keyboard, you’ll never get anything done.
When I get stuck, I write code the same way I write articles. You’d start with a rough draft. Maybe sketch out some tests, code, or comments. Or even write some ideas out on paper. At this point, you wouldn’t worry about structure, you’re just using code to clear up the vague ideas you have in your head.
Then, I turn those ideas into a straightforward implementation. What you might call “The simplest thing that could possibly work.” It’s not perfect, and not even close. But don’t worry about it. Because once the code works, you’ll do a tidying pass. TDD edge cases, refactor obviously bad code, or make names clearer.
These “refined drafts” are usually good enough to ship. But I’ll usually do a few more passes. Not too many, though – you’ll soon start to see diminishing returns. You’ll spend more time cleaning up the code than it’s worth.
Then, if you really want to end up with the cleanest possible code, let it settle for a while. Come back to it in a few weeks or months, and do another pass at it. By that time, you’ll know more about your system, and you’ll have learned more about how to write great, highly-maintainable code. So you’ll do an even better job.
Just like writing, that process is:
- Sketch out a rough outline, draft, or prototype.
- Write a simple, unedited, straightforward implementation (often guided by TDD, or written along with tests).
- Refine, refactor, and clean up that implementation a little bit.
- Let it settle.
- Come back to it, and do one more pass.
It sounds like a lot more work. But when you go in stages like this, you’ll move faster, without always second-guessing yourself. And you won’t end up overthinking decisions between a few just-as-good options.
When you use Ruby to wrap an API, you have to have a way to configure it. Maybe the wrapper needs a username and secret key, or maybe just a host.
There are a few different ways to handle this. So which one should you choose?
The easy, global way
You might want your service to act like it’s always around. No matter where you are in your app, you’d have it ready to use. Otherwise, you’ll spend three lines of configuring it for every line of using it!
You could make the configuration global, using constants or class attributes:
1 2 3
1 2 3
Lots of gems use this pattern. It’s pretty easy to write, and really easy to use. But it has some big problems:
You can only have one
If you want to use the Product API as two different users, or hit different servers from a single app, you’re out of luck.
ProductApihas global data that’s easy to accidentally change.
If a thread or a part of your app changed
ProductApi.user, everything else using
ProductApiwould break. And those are painful bugs to track down.
So, class variables have some problems. What if you configured instances of your Product API class, instead?
What would it look like with
If you used instances, you’d create and configure your API wrapper when you need it:
1 2 3 4 5 6 7
Now, you can pass different details to your API whenever you use it. No other methods or threads are using your instance, so you don’t have to worry about it changing without you knowing it.
This seems better. But it’s still not as easy as it should be. Because you have to configure your API every time you use it.
Most of the time you don’t care how the API is set up, you just want to use it with sane options. But when you’re working with instances, every part of your app that uses the API has to know how to configure it.
But there’s a way to get the convenience of global access, using good defaults, while still being able to change it if you need to.
And this pattern shows up all the time in an interesting place: OS X and iOS development.
How do you get good defaults and flexibility?
What if you could configure each instance of your API wrapper, but you also had a global “default” instance when you just didn’t care?
You’ll see this “defaultSomething” or “sharedWhatever” pattern all over the iOS and Mac OS SDKs:
1 2 3
And you can still ask for instances of these classes if you need more than what the default gives you:
1 2 3
You could build something like that in Ruby, with a
default_api class method:
1 2 3 4 5 6 7 8 9 10 11 12 13
And the implementation might look something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
But this is a decent start.
Most gems I’ve seen, like the Twitter gem, will have you configure and create each API object when you need them. This is an OK solution (though I usually see people assigning these to globals anyway).
But if you go one step further, and also use a pre-configured default object, you’ll have a much more comfortable time.
Have you seen the Rails Competency Chart?
Brook Riggio of CodeFellows put it together to show all of the concepts a modern Rails developer should know. Take a look:
Frightening, isn’t it? It looks like a two-hundred-tentacled monster that’s preparing to attack you.
It’s no wonder learning Rails is intimidating. Some of the branches, like SQL and Deployment, could be entire career paths. You could spend years on Application Architecture and still not feel like an expert.
But it’s accurate. If you show this chart to a professional Rails dev, you’ll probably hear, “Yep, that sounds about right.” If anything, you’ll hear about what it’s missing.
So how can you deal with all this? How do you learn all this stuff without having started 5 years ago?
How do you handle all these topics?
Yeah, most professional Rails developers know a lot about a lot of those concepts. But you don’t have to know all these things to start building your Rails apps. You don’t need to study deployment until you’re ready to deploy, and you can look up how to group things in SQL the first time you have to do it.
One thing this chart doesn’t illustrate well (even though the blog post talks about it) is how the different areas reinforce each other. For instance, unit tests, integration tests, acceptance tests, and all the rest use similar skills and knowledge. Yes, there are some differences between the different types of tests. But once you start to understand the fundamentals of testing by writing a bunch of unit tests, you’ll pick up the other types much more quickly.
The more you learn, the faster you’ll learn. Functional programming is a lot easier to learn when you know Object-Oriented Programming. Service-Oriented Architectures can “feel” a little like Object-Oriented Programming. Learning CSS selectors will make using jQuery much easier. Many of the principles you learn will translate across different branches.
Where do you start?
If you try to pick up every one of these skills at the same time, you won’t take advantage of the extra speed you’ll get as you master them one-by-one. So focus on a few at a time, and learn them well.
Ask yourself this question:
“What do I need to know to make progress on the problem I’m facing?”
Use your answer to narrow in on which competencies to start with. As you pick those up, you can check out the skills right around it, and take advantage of what you just learned to learn similar things faster. For instance, if you’re feeling comfortable with the command line, you could pretty easily branch out into things like package management and permissions.
By building these skills as you need them, you’ll have a little extra kick of motivation. You’ll be spending time on the stuff that matters to you.
For instance, if I was learning multitenancy because I felt like it’s something I should just know, I’d be asleep halfway through the first blog post. If I was learning it because it was the only way I could get my app to work, I’d be glued to every tutorial and reference guide I could find.
It’s crushing to see a few hundred skills, and know you need to learn them all. Especially when those first few competencies take you weeks or months to pick up. You’ll feel like you’ll never become a professional Rails dev.
The chart’s not wrong. As a Rails dev, you’ll eventually know a lot about most of those things. But we didn’t all start there.
So, start somewhere. Prioritize, and move along the path that leads to your app being built. Branch out to fill in the gaps. And recognize that you’ll get faster as time goes on.
And if you want to learn those skills faster, and remember how to use them when it counts, grab this free sample chapter of Practicing Rails. You’ll learn the method I use to learn new Rails ideas quickly and thoroughly, without getting overwhelmed.
When you build Rails apps, you’ll use piles of gems. Some of them seem totally magical! But how does that magic happen?
In most gems, there’s nothing they’re doing that you couldn’t. It’s just Ruby code. Sometimes it’s complicated Ruby code. But if you explore that code, you’ll begin to understand where that magic comes from.
Finding the source code
To understand how a gem works, you have to find its code.
If there’s a method that you want to know more about, you have an easy way to find the source:
source_location. I wrote a little bit about these earlier. Here’s an example:
1 2 3
But what if you’re interested in more than one method?
If you have a console open inside your Rails app’s directory, you can go right to a gem’s code:
If it’s in your
bundle open rack will open up the entire
rack gem in your editor. You can comfortably browse all of the files inside it.
Where do you start?
Now that you know where the gem’s code is, how do you begin to understand it?
If you try to learn how
activerecord works by reading
lib/active_record.rb, you’re not going to get anywhere. You’re just going to find a lot of
It’s easiest to understand a gem after your app uses it a little bit. Once you know more about the kind of work that the gem is doing for you. That way, you’ll already have an idea about which interesting classes and methods you should start with.
After you have the names of some interesting methods, you can use
source_location, Find in Project in your editor, or ag on the command line to see where those methods are defined. And that’s when the fun starts.
The gem’s code is on your machine, right? That means you can change it however you want! You could even break it, and nobody else has to know.
When I’m trying to understand how a gem works, I don’t just read the code. I add
puts statements into the gem, I throw exceptions to figure out how my app got to certain lines, and I mess with the code to understand why the author wrote it that way.
Once you know how the trick’s done, it’s a lot less magical. And you won’t have to guess how that code will act in strange situations, because you’ll be able to see it for yourself.
Cleaning up after yourself
After you mess with gem code, your app could be in pretty bad shape. It might not even run anymore! And even if it does, it’s going to spam all those
puts statements you added into your console.
But RubyGems has a quick way to bring things back to normal:
1 2 3
Or, if you don’t remember which gems you messed with, and you’re really patient:
After that, all your gems will be back to the way they were when you installed them.
What are you going to explore?
When you find, read, and explore the code inside your gems, you’ll understand the code you depend on at a deeper level. And you won’t have to rely on assumptions and guesses anymore.
Is your Rails app slow?
When it takes seconds to load what should be a simple view, you have a problem worth digging into.
You could have too many database calls or some slow methods. Or maybe it’s that speedup loop someone put in your code and forgot about.
But my favorite tool for exploring performance problems does a lot more. Out of the box, it shows you what your code is doing. But when you add a plugin to it, it becomes even more powerful. It helps you see your app’s performance problems, visually. And that can help you find and fix slow apps, faster.
My favorite Rails profiler
My favorite Rails performance tool is called
rack-mini-profiler. When you add that gem into your app, you get a little indicator on each of your pages. It looks like this:
If you click on that box, it expands and you can see all kinds of great stuff. Which SQL statements were run, how long it took to render partials, and more:
MiniProfiler gives you a constant reminder of how long each page takes to load. That helps you learn more about how your app is performing. You’ll build an intuitive sense of which pages are slow, and which ones are fast. You’ll start to notice when a page takes surprisingly long to render. And you can start fixing it right away, while it’s still on your mind.
MiniProfiler can do more. But first, you’ll have to install the
When you do that, you’ll unlock a new way to see your app’s performance.
Flamegraphs: exactly as fun as they sound
A flamegraph looks like this:
Pretty clear where the name comes from, right?
After you install the
rack-mini-profiler gem and the
flamegraph gem, you can see a flamegraph for any of your requests. Just add
pp=flamegraph as an HTTP parameter, which would look like this:
The flamegraph will pop up, and you can zoom in and out, scroll around, and try to find interesting things to explore.
Each “layer” in the flamegraph is one line in a stack trace:
And the horizontal axis is time. So the far left side of the graph is when your request started, and the far right side is when the request finished.
So, it certainly looks cool. But what can you do with a flamegraph?
How to use a flamegraph
Because the X axis represents time, you can really get a clear picture of where your app’s getting bogged down. The widest layers take the longest to run. They’re the first areas you should look into, because speeding them up could have the biggest impact.
How much time is your app spending rendering your view? In the controller action? Hitting the database? Rendering partials?
All those are really easy to see, visually:
There’s another useful thing that a flamegraph can show you:
Do you see a bunch of spikes that are all about the same height, like this?
That often means you have some kind of N+1 query. You’re missing an
includes somewhere, or making a bunch of calls to an API. If you added an
includes, you’d get a flamegraph that looks more like this:
N+1 SQL queries are pretty easy to see with most performance tools: you just look for SQL calls that look similar. But non-SQL N+1 issues, like hitting an API too many times, are a lot harder to notice. Especially if your logging isn’t that great.
With flamegraphs, though, those problems are a lot more visible.
What not to pay attention to
Flamegraphs can be overwhelming. They show you a lot of information, and you’re pretty much forced to take it all in at once. So what can you ignore?
Usually, you can skip the bottom and top layers of the graph. Instead, I start exploring around the middle of the graph, or maybe ¾ of the way to the top. That’s where my code tends to hang out.
The top of the graph is usually ActiveRecord- or IO-related, and the bottom is Rails framework code, so it makes sense that your code would be somewhere toward the middle.
Have you ever used a flamegraph? They’re a great way to find the best places to optimize. So give it a try! Add the
flamegraph gems to your
Gemfile. You’ll be surprised how much more insight you’ll get into your code.
You know how painful it is to work with badly tested code. Every time you fix a bug, you create five more. And when things do work, you never really know if it was designed that way, or just worked coincidentally.
On the other hand, you just wrote what seems like 200 tests to ship one tiny feature. You constantly have to redesign already-working code to hit 100% test coverage. You can’t shake the feeling that your best-tested code is somehow getting less readable. And worst of all, you’re starting to get burned out on your app.
There must be a middle ground. So how much testing is the right amount?
It’d be great if there was a nice round number you could use as a rule: twice as many lines of test code as app code, maybe, or 95% test coverage. But even saying “95% test coverage” is ambiguous.
Coverage can be an indicator of well-tested code, but it’s not a guarantee of well-tested code. I’ve had 100%-covered apps that had more bugs than apps with 85% coverage.
So, the right amount of testing can’t be about a number. Instead, it’s about something fuzzier, and harder to define. It’s about testing efficiently.
Testing efficiently is all about getting the most benefit for the least amount of work. Sounds great, doesn’t it?
But there’s a lot that goes into testing more efficiently. So it helps to think about three things in particular: size, isolation, and focus.
Integration tests are awesome. They mirror a path an actual person takes through your app. They test all of your code, working together, the same way it’s used in the real world.
But integration tests are slow. They can be long and messy. And if you want to thoroughly test one small part of your system, they add a lot of overhead.
Unit tests are smaller. They run faster. They’re easy to think about, since you only need to keep one tiny part of your system in your head while you write them.
But they can also be fake. Just because something works inside a unit test doesn’t mean it’ll also work in the real world. (Especially if you’re doing a lot of mocking).
So how do you balance those?
Since unit tests are fast and easy to write, it doesn’t cost much to have a lot of them. So they’re a great place to test things like edge cases and complicated logic.
Once you have a bunch of well-tested pieces of your system, you still have to fill in the gaps. You have to test how those parts interact, and the full journeys someone could take through your app. But because most of your edge cases and logic are tested by your unit tests, you only need a few of these more complicated, slower integration tests.
You’ll hear this idea called the “Test Pyramid.” It’s a few integration tests, sitting on top of a base of many unit tests. And if you want to learn more about it, take a look at the third chapter of my book, Practicing Rails.
Still, if your system is complicated, it might take what feels like an infinite number of tests to cover every situation you might run into. This can be a sign that you need to rethink your app’s design. It means that parts of your system depend too closely on each other.
Say you have an object that could be in one of a few different states:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
If you wanted to test every possible path here, you’d have 12 different situations to test:
- User is an admin,
- User is an admin,
- User is an admin,
- User is a user,
- User is a user,
- User is a user,
- User is an author,
- User is an author,
- User is an author,
- User is anonymous,
- User is anonymous,
- User is anonymous,
There are so many cases to test because “sending a message based on a notification method” and “generating a message based on the type of a user” are tied together. You might be able to squeeze by with fewer, but it’s not obvious – and it’s just asking for bugs.
But what if you broke them apart?
1 2 3
Now you can test each part separately.
For the first part, you can test that the right message is returned for each type of user.
For the second part, you can test that a given message is sent correctly based on the value of
And finally, you can test that the parent method will pass the message returned from
do_stuff_based_on_user_type along to
send_email_or_text. So now, you have 8 states to test:
- User is an admin
- User is a user
- User is an author
- User is anonymous
- and one test for the parent method
Here, you save four tests by breaking code apart so you can test it separately. In the second example, it’s a lot more obvious that you can get by with fewer tests. And you can imagine how as you add more states, splitting your code up becomes an even better idea.
It takes time and practice before you’ll find the best balance between isolation and readability. But if you break your dependencies in the right place, you can get by with a lot fewer tests.
Your app should be well-tested. But that doesn’t mean every part of your app deserves the same amount of attention on its tests.
Even if you do aim for 100% test coverage, you still won’t test everything. You probably won’t test every line of text in your views, for instance, or that you’re polling for updates every five seconds instead of ten.
That’s where focus comes in. Writing fewer, more useful tests. And making a conscious decision where you can best spend the time you have.
Focus is another thing that’s hard to get right. These are a few questions I ask myself that help me concentrate on the most important tests:
How interconnected is this with the rest of my app? If it breaks, how many other pieces will go down with it?
How likely is it that this will change naturally? If my tests fail, will it be because of a bug, or because someone updated some text in the UI?
What’s the impact of this breaking? Am I going to charge someone’s credit card twice, or is it just going to end up with some missing text?
How often is this part used? Is it critical to the app’s behavior, or is it an about page buried somewhere in the footer?
You shouldn’t only test the important parts. But you’ll have an app that feels higher quality if you spend your testing time well.
If you try to test every single possible path someone could take through your app, you’ll never ship. TDD helps, but it won’t solve all of your testing problems.
Of course, that doesn’t mean you shouldn’t test at all.
You can use the test pyramid to keep your tests small. You can isolate and break dependencies to turn
m * n test cases into
m + n. And you can prioritize, so you can spend more time testing the most important parts of your app.
So, how much do you test? Do you consider any of these ideas as you build out your app? And how do you know which parts of your app to focus on? Leave a comment and tell me all about it!
I recently updated Ruby and upgraded a few projects. And while I did, I found some pretty cool RubyGems features that I didn’t know about before:
When your executables get out-of-date
I used to use
rvm to manage Ruby versions. But the last time I set up my machine, I decided to try going without it. You don’t need Gemsets when you have Bundler, and you can use Homebrew to keep Ruby up to date.
This works great, until you update Ruby. And
bundle install and all those other commands break. They’ll point to the old Ruby version, not the one you just installed.
You could fix this by uninstalling and reinstalling each gem one by one. But that’s just crazy. Instead, try
gem pristine takes a gem, and resets it to the version you originally downloaded. It’s like uninstalling and reinstalling the gem. (This is also helpful if you decided to edit a gem while debugging, and forgot to change it back.)
--all means “all gems”, and
--only-executables means “only reset files like
/usr/local/bin/bundle”. That is, only fix the scripts you use to run a gem from the command line.
So this command resets files like
/usr/local/bin/rails to what they would have been if you uninstalled and reinstalled the gem.
A minute later, you’ll be back to working on your app.
When you need an older version
When I wrote my post on
respond_to, I created some tiny apps to learn more about it. I used a few different Rails versions to see how each version dealt with
How do you generate each Rails app with the right Rails version? You don’t have to do this:
1 2 3 4 5 6 7
There’s an easier way. You can tell RubyGems which version you want to run, right on the command line, with underscores:
Fuzzy gem versions
But in that last section, there’s still a problem. You probably don’t actually want to install 4.0.0. You want the newest version of 4.0, with all the minor updates.
But do you remember what the newest minor version of Rails 4.0 is?
There are lots of ways to look it up. But why look it up, when RubyGems can just do what you want?
You can use all the version strings you know from Bundler:
Useful! Especially if, like me, you hate doing stuff that a computer is better at.
But you don’t have to know all this
When I ran into these problems, I didn’t know there was an easy answer. But you could guess there would probably be one.
These were all situations where you can solve the problem by yourself, but it’d be repetitive and annoying.
And when you find a repetitive, annoying task like this, especially in a well-used project, it means one of two things:
- Someone has already automated it, or
- Lots of people are hoping you’ll automate it.
So before you do the busywork, dig a little deeper. Investigate a little bit. It’ll be worth your time.