When you build a great product it will eventually attract more and more users who will expect performance and availability.
As the app grows and over time it handles more requests per minute. If you’re not prepared for this, app performance will drop and you will potentially lose your audience.
This article will show you what to pay attention to when building a scalable app.
What is application scalability?
Application scalability is the potential for an application to grow over time – being able to efficiently handle more and more requests per minute (RPM). It’s not just a simple tweak you can turn on/off, it’s a long-time process that touches almost every single item in your stack, including both the hardware and software sides of the system.
In case of problems you can keep adding new CPUs or increase memory limits, but by doing so, you’re just increasing the throughput, not the app performance.
It’s not the way you should stick to when you see your app is starting to have efficiency problems. Scaling the app is not an easy thing and thus you should know your app very well before starting to think about how and when to scale it.
Here’s a quick overview of how the internet has grown over the last 20 years:
Let’s use Rails as an example – some say it introduces scalability issues when your project grows too large, but the applications ability to scale is more about the whole system architecture, not only the framework itself.
But it doesn’t mean that scaling a Rails app is always a pain – of course, Twitter moved from Rails to Scala, but on the other hand, Shopify is constantly growing with Rails at the backend for about 10 years, with over 50,000 requests per minute and 45ms response time.
Even if you don’t have performance or scalability problems like Twitter or Shopify, planning and developing the application in a proper way is priceless, regardless of the nature of potential problems.
You may face dozens of different issues when it comes to scaling – a few general sources of your problems may be related to:
Limited physical resources like memory and CPUs etc
Incorrect memory management
An inefficient database engine
Complicated database schema, bad indexing
Poorly performed database queries
Wrong server configuration
App server limitations
Overall spaghetti code
Lack of monitoring tools
Too many external dependencies
Improper background jobs design
And much more...
Rails is a great framework with an incredibly huge community and millions of already answered questions online – it has hundreds of great open-source tools that you can use to instantly build into your stack and a lot of profiling and analyzing tools that can help you identify bottlenecks in your system.
Click below to get access to 12 powerful tips for scaling your web app:
How can I get quick wins?
Let's use Ruby on Rails as an example – use these points to help your developer team scale efficiently:
Use common gems like bullet or rack-mini-profiler to identify the problems instead of paying for some extra memory in advance.
Use update_all for bulk updates with the same value (bear in mind that `update_all` does not perform any callbacks nor validations) or consider writing a custom SQL query on your own. Using AR methods (e.g. update) for thousands of objects in a loop is not the best practice.
Consider using UUIDs instead of IDs – when you use standard, incremental IDs as primary keys, all database writes in most cases have to go through a single database. When you use UUIDs, you can you can spread them out across many servers easier in the future
Make use of database-level functions like SQL SUM, COPY or DISTINCT. Example: Use `Model.sum(:value)` instead of `Model.sum(&:value)`. The first one performs an SQL sum function and returns the result; the second one fetches all the records, maps the collection, goes through every single item and takes the `value` attribute. Then it uses Array’s sum method to return the result we’re waiting for. Guess which one is faster?
Use `pluck` instead of `map` to fetch the same attributes from multiple objects.
Don’t use `length` to count records - `ActiveRecord::Relation#length` will always load up all the records and then call Ruby’s `#length` on the resulting array. Use `size`, which will touch the database only when needed. `count` is also often a better solution, as it performs a single count query.
There isn’t any magic formula for scaling an app – every single application is actually a unique system.
But if you pay careful attention while developing your app it can be surprisingly easy to handle its growth – thanks to a great set of available tools you don’t have to be an expert to scale your application.
In most of the cases, optimized code, efficient SQL queries, proper DB indexing and some caching should be enough to get started.