Jamie Gaskins

Ruby/Rails developer, coffee addict

Separate Unnecessarily Monolithic Apps

Published May 8, 2012

In my previous article, I mentioned that if your Rails app takes more than 5-10 seconds to load, you should consider separating it into smaller apps. Obviously, that duration is more of a rule of thumb (because "suggestion of thumb" doesn't have the same ring to it) than a rigid metric but if your main app contains features that can stand on their own, then by all means, they should.

Examples of features that shouldn't be in your main app

Blog

A collection of articles that potentially contain links have nothing to do with the rest of your data.

Forums

Sure, you want a place on your site for users to exchange information with other users. This is a great idea for some sites, but it's probably not the primary reason people type your domain name into their address bar.

Image Gallery

If you have a store app and want collections of images for your products, it's arguable that the gallery belongs in the app. For small galleries that are there simply to show off a few photos for each product, I'd agree with this. However, if you're providing a huge gallery (for real estate, for example), I'd argue that the gallery should stand on its own.

Why does it matter?

Having a large, monolithic app isn't the end of the world. We've all built them. However, there are several advantages to separating your apps.

Traffic in one app doesn't bog down the rest

This can be very important. Let's say an article on your blog hits Reddit's front page and suddenly the entire internet comes stampeding to your site. In a monolithic app, users of your main app are seeing massive spikes in response times. These users may or may not have any idea what's going on with the blog, but either way, this is likely to be unacceptable in their eyes and could cause them to stop doing whatever it is that they're doing that keeps money in your wallet.

If you're hosting each app on the same physical machine, this won't apply, but all cloud providers will offer this benefit.

Testing

To be honest, this is probably my biggest reason. First of all, we're all human. There is likely to be coupling somewhere in our code that we haven't gotten around to extracting or refactoring yet. Making a change in a single app of a collection of apps is less likely to break something in this still-crappy code. It's still possible to break another app if you modify an API somehow, but you just need to be mindful not to change public APIs unless absolutely necessary.

Second, running the tests in a smaller app takes a fraction of the time. If you modified something in the blog, you're still running the tests for everything else in a monolithic app. If you gain nothing else from splitting your apps, you'll still reduce your test runtime.

Free Heroku dynos!

Heroku is an awesome cloud-hosting platform for various reasons I won't go into. For every app, you get one free dyno (compute unit). If you split your app up across 3 Heroku apps, you get additional free CPU time.

Separate databases

This goes along with the first explanation here, but having each app using separate databases (especially if each DB is on a different physical machine) can lead to increased throughput for each DB when it's under load, especially if you are using something like MongoDB which uses a process-wide lock on write — when it's writing to the DB, nothing else that talks to that server can read from or write to it.

But what if these satellite apps need data from the main app?

Obviously, there will be times when you'll need, for example, your forum to share user information with the main app so it knows who is posting. For this particular example, there should be an API implemented on the forum so that the main app can trigger it whenever a user account is created or updated in the main app. The first idea that springs to my mind in this case would be to create a background job and trigger an HTTPS call to the forum to create the user. There are probably several other ways to implement such an API.

Doesn't it mean that I'll have to recreate things like User models?

This is a troubling thought I had, as well, when I first thought about this. And definitely, some of the data will need to be the same across your apps, but you don't need to copy and paste and you don't need to modify each of the user models across the various apps with every change.

Most of the data in each app will be specific to that app. For example, your forum-post data won't need to be tracked in your store app and your purchase data won't need to be available in your forum. Secondly, the behavior in each model won't need to be the same, so you can rip out any methods that aren't necessary for the specific app and just keep things like user IDs, names and e-mail addresses the same. I wouldn't recommend transferring passwords or other authentication credentials between them unless you really feel you need to allow users to login through one of these satellite apps. Transmitting passwords over the network comes with its own security concerns.

There's also the chance that you may not even need user data in the database. If you can provide the full experience without sharing data between your apps, you should.

Conclusion

Hopefully, you can understand the benefits of splitting monolithic apps. I'll warn you, it's not easy the first time you do it. But once you understand how things need to work for your specific case, you'll begin wondering why you ever wrote those epic apps to begin with.

TwitterGithubRss