Spring cleaning your code base

Code rots over time. While you're busy adding new features to your app, you might be forgetting to throw out the old. This is a friendly reminder to sweep out the garage and get rid of the things you don't need.

You don't have to scour through every line of code to get results. Here are some areas you may be able to score a quick win.

Move any third-party assets in `app/assets` to `vendor/assets`. Putting third-party assets in your `app/assets` directory is generally a mistake, and that's ok. Clean up and put them where they belong and you'll be fine.

Remove any CSS files and/or rules no longer being used. The level of detail you achieve here depends on how much time you want to spend. Removing unused CSS may be as simple as removing some files you're no longer using. If you want to dive into removing rules, there's a great tool for that called deadweight.

Remove old JavaScript files. This is usually easy and difficult. You'll probably find at least one library or plugin no longer in use. Just remove it - that's the easy part. If you have a bunch of your own custom JavaScript i.e. a Backbone application, you may need to comb through it a bit more to find out which parts are not in use.

Get rid of legacy models/database tables. A few legacy models may have leaked into your code base early on in the life of your app (when you're under rapid development). That's ok. Figure out what they are and get rid of them. Write a migration to remove the table, too.

Find any unused partials. If you're refactoring quite a bit, you might forget to remove some unused partials. Check out this gem to remove unused partials.

Three ways you can bend the ransack gem to your liking

In the world's best yoga studio software for independent yoga studios, we have a page which lists all people in your studio. It's super basic: it only shows their name and role at the studio along with some actions you can take i.e. edit, delete. We haven't improved it much along the way.

I wanted to change that. TULA, in its essence, is a yoga centric CRM + billing system. Armed with inspiration from Intercom and their brilliant list of people, I set out to improve our people page.

We've had requests from our customers like "show me all the students who haven't been to class since X date" and "show me all the students who have joined the studio since Y date". These are great questions to ask and TULA should give you the answers. It's as simple as that.

To give them this, I did some investigation and found a great gem called ransack (if you haven't already, check out the ransack GitHub page). I quickly became satisfied with ransack as the basis of this new page. However, there were a few things I was constantly fighting with.

Ransackers derived from column aliases

This frustrated me for some time. I had a query like this:

I wanted to use their role, last attendance date, last purchase date, and join date as sortable columns in the table. However, it wasn't working out of the box until I realized I could simply pass an Arel node (thanks to this GitHub issue) of the column alias to a ransacker.

Default sort order

You can also use ransack to set a default sort order for when your users first visit the page.

Nulls last with ransackers

When you start sorting by column, you'll quickly notice null values getting in your way of the important data. For example, if you're sorting by the last time a user has made a purchase, you'll most likely want to see an order like this: about an hour ago, three hours ago, one week ago, etc. You wouldn't want to see an order like this: never, never, never, never, ... , about an hour ago, etc. The important data is getting buried by the nulls.

Ransack doesn't support this by default. However, there's a workaround (read more about how to add nulls last to ransack).

The workaround is great; however, it doesn't immediately work when you're using ransackers which return an instance of `Arel::Nodes::InfixOperation` or similar. You'll see a generated query similar to the following:

Obviously, this isn't valid SQL. This is actually due to the `full_name` ransacker defined above and in this case, the default sort order set to `full_name`. However, `Arel::Nodes::InfixOperation` responds to `to_sql`, so you can test for this case and transform it into valid SQL for the query. The code below will show you how:

Ransack is powerful, and we're just scratching the surface of its power. If you think I missed anything important, just mention me on Twitter or add a comment below.

The tools I use every day as a web developer

As web developers, we use so many different tools everyday. We can easily forget about everything we depend on. In the spirit of the new year, I want to take a moment to recognize all of the great products and projects which help me be the best developer I can be.

There's a saying out there, "You're only as good as your tools." (1) (2) This rings true in many different professions and in life. Tools that make you better at what you do are generally a great investment - typically risk free.

Here are my favorites. I use these every day, if not, every week.

Engineering is the easy part except when it's not

I've been hearing it a lot lately. Maybe you've been hearing it, too. "Engineering is the easy part," they say.

Try telling that to Twitter in early 2007 when they faced massive growth and intense scaling issues. I don't think you'd find many engineers at Twitter telling you how easy it is to manage 600 requests per second and 180 Rails instances backed by 1 database server.

The point is: engineering is hard. Everything is hard.

Ok, maybe I'm exaggerating a bit here. There is one case where "engineering is the easy part."

Let's say you have an idea. You want to build that idea into a weekend project. You've probably heard of this happening quite a bit. How many "I built this in a weekend while watching every episode of House of Cards" blog posts have you read over the years? Building a project in a weekend is easy. You shouldn't be focused on perfection. Most everything works the way it should, but it definitely isn't refined. If you overcome your lizard brain, you can ship it and see what people think.

Let's say a few people like what you've built. You have users! They start using the app as any good user should do. Guess what? They find bugs. Now, you've got to fix them (if you want your users to continue liking what you've built). Better yet, it's not just one bug. This bug, that bug. You have to prioritize bugs. You can't fix them all at once - even if each user cares passionately about the bug they reported.

Still easy?

BUT! Remember, you took some shortcuts so you can finish your project in a weekend? You have a choice to make. You can put a band-aid on it and simply patch it up, or you can do some refactoring for the future to make sure it doesn't happen again. You might even want to write a test for it - you know, because TDD 4 lyfe.

Now you've fixed those bugs and your users are happy again. Slowly, they're telling their friends and you start to get some SEO juice with Google. But, guess what? You're not done yet. These new users want new features. Surprise, surprise - your weekend project can't do everything a user might want. Better yet, you're in the same situation as the bugs. Just like all the bugs, every user has a feature they need.

You have another engineering decision to make. How does this new feature integrate into the code you've already written? You'll need to plan for the future. There will always be new features. You don't want to screw yourself over in six months. Granted, some features are pretty easy and you've done them before, but there's always a slight variation. There might even be a library out there to help you, but once again, you'll likely have to alter its behavior - even if it's just a little bit.

Still easy?

Your weekend project is starting to turn into an actual product. You have a faithful group of early adopters. They're always looking out for you and sharing what they're thinking. You've been able to keep them happy through bug fixes and new features. You still have bugs and you have a giant backlog of new features; however, you've been able to navigate successfully until this point. Your app is still fast, but not quite as fast as when you first started. Your app works - there are some bugs, but for the most part people can use your app with success. For the most part, people are happy.

You're starting to grow faster now. People are paying attention. Remember Twitter? You might start feeling their pain. Not many apps have massive scaling pains like Twitter, but most apps go through periods where you have to adjust. Your weekend project was built and tested with one user, you. Now, you might have hundreds, maybe thousands, of people using your app on a daily basis. This is entirely different than one user. New problems will popup because your app is serving more than just one user.

These are great problems to have, but they definitely aren't easy.

Engineering is the easy part only applies to companies that stop at Version 1.0. How many companies do you know that stop there? None. The engineering team gets you to Version 20.0. Through bug fixes, new features, scaling, migrations, architecture, data centers, etc., your engineering team is there every step of the way.

It took Twitter months of hard work to straighten out their scaling issues. It most certainly wasn't easy. They failed - quite a bit, but they didn't give up. Through months of pain, they eventually came up with solution after to solution to fix the fail whale. Their solutions were most definitely not easy. Keep in mind - they did all of this while people were still using Twitter. Downtime is just unacceptable in this day and age.

On the flip side, I had the opportunity to observe what happens when you have an engineering team that runs into major problems when upgrading a product. Now, I'm positive this team had the best of intentions and I'm positive they were trying as hard as they could to avoid these issues. I'm also positive they'll learn from these mistakes. However, they failed massively, and they know it.

Engineers are responsible for many different things. If you don't do one of those things right, it can snowball into other problems.

Communication is key. As an engineer, writing code is a small part of the job. In practice, most engineers write code for a fraction of their day. Instead of writing code, they're communicating with project managers to estimate time to production. They're talking with the designer about ways to work a new design into the existing product. They're thinking about what's next and how they'll manage the next database update required for that upcoming feature in three months. They're worrying about how their code base isn't as stable and well-tested as they had hoped for.

Most importantly, all of this isn't easy - not by a long shot. This is hard stuff. Don't buy into the link-bait. Engineering is not easy. Just like customer support, project management, and product ownership - engineering is a key part of your organization. If you think you can just throw bodies at an engineering problem, you're wrong.

Those bodies might be able to solve the problem at hand. They might get you somewhere and help you raise funding. However, those bodies certainly aren't worried too much about the future. They aren't setting you up for long-term success. You'll pay dearly for it later on.

Engineering isn't easy if you're doing it right. Engineering should be invested for the long-term. When you finally get there, you'll have an engineering team fully invested in your organization. Your engineering team will be a valuable asset full of talented people that know every tool, piece of software, and server your company has in its possession.

Don't say engineering is the easy part. It's not.

Thanks to @andrewwicklandr and @alexlaprade for reviewing this and providing some ideas for making it better.

Using GitHub as a notebook

Using GitHub as a notebook isn't a new idea. We've noticed a few companies and different people doing this and it's a great idea.

Sure, you can use Evernote. It's a great product. As a developer, GitHub seems to fit perfectly into your workflow anyway - so why not use it as a notebook?

People can submit pull requests to add to it or create issues to review things. It accurately reflects your knowledge base and keeps track what you've been working on. It forces you to write your ideas out on "paper", regurgitating what you may have learned in the past few weeks.

I'm trying a few different things at the moment to see if they work out.

  • idealprojectgroup/rails-configuration-files: Anytime I have to configure something, I try to add it to this repository. You'll find things like my custom dnsmasq settings and Apache configurations.
  • idealprojectgroup/guidelines: Currently, this is serving as a place to brain dump. We're only three engineers strong and we've kept a set of unspoken standards for awhile. I'd like to get these down on paper and work toward a more "official" standard. My favorite part of this repo is THINGS-TO-READ.md. I hope to keep a high standard for it. It should serve as a place that summarizes our philosophy as an engineering team.

More great GitHub "notebook" repositories