Handling subdomains for Rails in your development environment

We built Tula with subdomains from the beginning, so we needed a nice way to handle subdomains in our development environments. We used pow for some time, but that wasn't the perfect solution for me. That's because I wanted a few things out of a solution: 

  • Configure it once and forget about it
  • Know exactly when my server was started and stopped
  • Use whatever I wanted as an app server i.e. unicorn

It took us awhile to settle on this solution, so here it is. It uses a combination of Apache (or nginx) and dnsmasq which I've become a huge fan of. 

The first part is simple. You'll want to install and use dnsmasq. It's a nice, lightweight and local DNS provider that will run on your machine. You can serve the names of local machines which are not part of the global DNS. 

It's easy to install on both Linux and Mac. 

# On Ubuntu Linux
sudo apt-get install dnsmasq

# On Mac with Homebrew
brew install dnsmasq

Once installed, you'll want to add the following to your dnsmasq.conf file. This will resolve any domain with a TLD of .dev to your local machine. This is handy if you have a lot of projects (Rails or otherwise) in the same directory. 

Next, you'll want to configure Apache (or nginx) as the following. The key for Apache is VirtualDocumentRoot. It allows you to set the document root based on various parts of the domain name. In this case, I've taken the main part of the domain name as the document root. The domain name will resolve to a project in my Projects directory. This will always work if I continue to use my Projects directory for Rails projects.

If you set this up once for your Rails projects, you'll never have to worry about adding anything to your hosts file, nor will you have to worry about port numbers. It's all taken care of for you.  You can access your subdomains as you would normally. It's important to note that unicorn is running on port 5000 in this example.

Make your Rails views easy with select

Recently, we were writing a new report for Tula. We needed to query for all users that had purchased a particular pass and when they purchased it. 

Here's what we came up with first: 

Well, that doesn't make it very easy to display in our view. We want a view as simple as this: 

Now that we had the simple view code with our favorite interface, we had to implement that interface. How would we do that? (By the way, you may notice we have date formatting in our view. You may want to try a decorator so your view is even simpler.)

By adding a select to our query, we can select all of the user attributes AND the pass attributes we need. We can add these attributes to the user (if you're familiar with SQL, we're essentially merging the join table attributes with the user being returned). You might want to read more about selecting specific fields.

 

Now, we've got a nice interface to work with that keeps our view super simple and not doing any extra work. We can access pass_name  and pass_purchase_date  directly from the user.

You should notice that we have a query in the controller. For simplicity, I kept it in the controller. You should really have this query in your model or better yet, in a single responsibility query object (see #4). 

If you have any questions or comments, please let us know in the comments section below.

Your code sucks, mine is better, and why code review doesn't have to be painful

We've been experimenting with different ways to make code review part of our culture. Although we'd like to, we don't pair program regularly for a variety of reasons. We're a remote team in 6 different time zones and we currently have 4 different projects for only 3 engineers. As a result, we try to keep context switching to a minimum, but code review naturally drives context switching for us.

Code review is a great way to improve code quality! 

Well, that's great, but how do you do it?  We set out to seek an answer to that question.

First of all, it's important to realize that all organizations are different. The people are different, the projects are different, the tools are different, etc. Sure, many of us share similarities, but for the most part, everything is slightly different. Although you can read and read about how other organizations do it, you have to find your own way through your own experimentation.

Experimentation is fun. If we find a new tool we'd like to use or a new idea we'd like to add to our workflow, we try it. We don't have a formal experimentation period. We just try it. If we like it, we find a way to keep it. If we don't like it, we throw it out. 

For example, we recently wanted to try Blossom. Up until that point, we were exclusive to Basecamp for project planning. We knew Basecamp was missing something, but transitioning clients to Basecamp has been pretty easy. Blossom has started to fill the hole in our hearts and we've decided to keep it. A word of warning though: some of your clients won't love your tools as much as you do. Not all of our clients liked Blossom. 

Like Blossom, code review is a specific piece of our workflow we're actively experimenting with.  We've tried a few different things so far, and we haven't been completely satisfied yet. That doesn't mean we've given up. We're just adapting and changing our experiments to make us happy.

Experiment #1  - Code reviews live on GitHub

This is obvious. All of our code is on GitHub. Their collaboration tools and commenting system is easy and if you've worked on open source, it's pretty easy to work with. We can review the code and comment inline on the lines of code in question. We can open up issues when we see them and suggest ways to refactor. 

Long ago when we first started doing this, we knew it was a success right at the start. To improve quality, this was definitely a win. 

One of the advantages of using GitHub for your code reviews is the rich history. If you're constantly talking about your code and using pull requests to signal when code gets merged, you'll have a rich history of discussions, bug fixes, and screenshots. If you practice continuous deployment, you'll have a history of deployments as well.

History is invaluable. You'll be able to answer questions like, "why did we do it this way?" You'll be able to see screenshots of the app as its being built. The history will serve as a seed to help you recall much more about the code written.

Although reviewing code on GitHub is great, code review comes with a price. We're a distributed team and sometimes only one engineer is online. How do you practice code review if you value the speed at which you execute? This was one of the problems. If we wanted to integrate code review into our organization, how do we do it in these cases? Do we sit and wait until another engineer comes online? This was a problem we didn't know how to address.

Experiment #2 - Assigning a code review todo on Basecamp 

Reviewing code on GitHub was definitely becoming part of our organization; however, we wanted to make sure we were doing it. Since we were using Basecamp at the time, we decided it was a good idea to create a todo on Basecamp and assign it to someone for code review. That person would be notified and they would review it, right? 

Much like Experiment #1, we still needed someone to be online. If one of our engineers completed a bug fix and no other engineers were online, what happens? The todo gets created and the code sits there until that person gets online. 

Another problem for us was context switching. If someone was online, should they immediately switch and do a code review? It doesn't seem like a good idea, does it? 

Experiment #3 - Added a code review step in Blossom 

As we started to use Blossom, we started to ditch our usage of Basecamp. We setup our kanban flow and decided to add a code review stage. It seemed like a code review stage was just what we needed.

We placed our code review stage after our QA stage (we're big fans of having a QA person to test the code as a user).  Over time, we started to see quite a bit of friction in our workflow. Code reviews weren't getting done "on time". We were ending up with code that had passed QA, but wasn't reviewed by another engineer.

We had been accustomed to merging code upstream as soon as something passed QA, and we were feeling pain now. The workflow wasn't working. 

Experiment #4 - Continuous code review 

After all of our experiments so far, we finally realized that code review shouldn't be a formal part of the process. Instead, we should train ourselves to do it all the time. We call this continuous code review.

We review code earlier in the process. Sometimes, we'll write some code, open the pull request, and pair up with another engineer to review. If code is in the QA stage before the first code review, we've failed.

If I had to come up with a rule, I'd say you should do your first code review halfway through implementation.  We don't really like rules though. Smart engineers can use their own discretion and figure out when a review would help them out. This has helped as immensely so far, but it's still too early to tell if this is the experiment we'll call a success.

Our goal is to ingrain code review in our culture. We know it improves quality. We know it makes us smarter. We know we want to do it. So do it.

 

HAML vs ERB: Keep your emotions out of it

There are tradeoffs in everything we do in life. Everything is relative to your situation. There are no absolutes.

Let's revisit a conversation our team recently had in HipChat. It was the ultimate debate of pros vs cons, and at one point it turned a little bit emotional.

HAML vs ERB

There are already a bunch of debates documented on the web. Just a simple Google search gives you enough to make your head spin: HAML vs ERB vs SLIM in terms of render speed, Haml vs erb, Fashion Runway: ERb vs. Haml, and so on. You get the point.

But, what about the arguments we were making?

We shouldn't be afraid of it.

I sensed a little fear from our team, so I had to say that. Our team isn't exclusively developers. Most of us know our way around HTML & CSS, and since we use ERB most of the time, everyone at least knows what it looks like. But, like anything else, we shouldn't avoid something because we're afraid of it. It's usually good to step out of your comfort zone.

We have an existing code base.

We have an application where we used ERB exclusively. Why should we try to make the switch to HAML? To me, it's a waste of time and a poor decision that wouldn't provide many benefits. While our code would suddenly be cleaner and a little more beautiful in HAML, we'd waste precious hours converting ERB to HAML. We have so many other important things to do, why waste that time on something so pointless in this case?

I can write ugly code in any language.

One of the common arguments for HAML is that it's clean and beautiful. While I agree that a language that depends on whitespace forces you to indent and keep things organized, I guarantee that I can write ugly code in HAML as well. Look what I found: Haml Sucks for Content

That doesn't look pretty and organized to me. If you use a tool like HAML in the wrong way, you'll end up something that looks terrible. Like Chris says in his post about why Haml Sucks for Content:

Haml’s use of CSS syntax for IDs and class names should make it very clear: The markup you write in Haml is intended to be styled by your stylesheets. Conversely, content does not usually have specific styling - it is styled by tags.

It's important to realize that your situation is completely different than everyone else out there. If you're starting a brand new application and you plan on experimenting with some new tools, you can afford to use HAML (and it's usually a good idea to learn something new). But what if you need to stand up an application in a week? Use what you know.

There are plenty of reasons to not use HAML. Maybe, you don't have time to learn it. Maybe, you have some junior developers on your team that only know ERB. Maybe, you have a personal preference against HAML.

It's all relative. You don't need to use HAML. ERB can do all the same things. They are just different tools for the same job.