When choosing a framework to work with, it’s important to pay attention to performance. Young developers often end up doing django vs ruby on rails performance comparison.
This article is aimed for beginners, who are trying to choose the path to follow.
Django is a web framework, first released in 2005. It was created to speed-up development of news websites, but evolved since then to a general purpose framework. You could’ve heard about some applications built on Django: Instagram, Bitbucket, Pinterest. As of January 2017, there are 1350 contributors to django on github.
Known for having «batteries included», Django provides built in ORM (and db migrations facilities), Admin UI, Authentication, Session management and other tools.
Core architectural principles on Django are heavily influenced by core principles of python - «explicit is better than implicit», «readability matters». The code is easy to write, easy to read and it’s always obvious how things will work when you run it.
Ruby on Rails
Ruby on Rails (RoR) was released in 2008. It was created in 37 signals to power their projects. RoR quickly gained traction and became even more popular than Django (even though was release later). RoR powers some popular websites, for example: AirBnB, Basecamp, Github, Fiverr. As of January 2017, there are 3224 contributors to Rails on github.
Just like Django, RoR provides all the base tools a developer might need to build a database driven application.
RoR follows "convention over configuration» principle, which means that you have to write less code than in Django, for example, but it’s not always immediately obvious why things work the way we work and how to modify it.
Rails vs Django comparison table
This table shows the state of rails vs django in 2017, at the time of writing this article.
|Average salary (Middle engineer)||$88 544||$86 801|
|Upwork jobs (at the time of writing article)||512||281|
|Configuration principle||Convention over configuration||Explicit is better than implicit|
|Pattern||Model View Controller||Model Template View|
|Models||Ruby on Rails has a generic ORM that allows managing database operations and migrations in Ruby. The same code works on all supported database backends. Model definition is spread across multiple files: 1. Model file, which defines business logic and validation rules 2. Migrations files, which contain definitions of incremental changes to database structure 3. Schema file, which contains a reference to current database structure||Django's ORM is similar in terms of features, but the code is organized differently: 1. Model file contains business logic, database structure and validation rules. 2. Migrations files are generated automatically as model file is updated and contain incremental db changes.|
|Routing||By default Rails routes URLs to controller methods. For example POST request to /geocoder will route to ||Django requires each endpoint to be explicitly defined in python code. Each endpoint is defined as |
Web framework performance
When I just started learning web development, it seemed obvious to me that raw language speed and framework optimization level are the most important parts to website performance, I even tried switching to Haskell just because it’s «fast». Now, 10 years later, it seems pretty obvious to me that framework and language speed just don’t matter in overall application performance and success.
Just by looking at the overview above we can see since Bitbucket is based on Django and Github is based on Rails and both of them are equally fast, then probably you can take any framework and build a high-loaded site that is fast enough. Still, let’s try to understand why framework speed doesn’t matter, what actually matters and what to use for your first application.
What impacts application performance
Let’s try to follow request’s lifecycle and specify what tools are involved in the process.
High loaded application will probably have multiple servers. Load balancer is the tool that will route the request to a needed backend. One of the most popular examples is HAProxy. SSL decryption can be also performed at this step.
Accelerators are used to compress and cache responses and then quickly serve responses from cache. Most of requests will be returned here from cache, blazingly fast. Popular web accelerator is Varnish.
Nginx most probably, will serve static files and route dynamic requests to underlying application server. Note that nginx is capable to doing load balancer’s and web accelerator’s job to some extent, so it might be enough for you to just configure nginx correctly.
Application server converts http request to an object that our web framework will understand. For example, Unicorn for Rails, Gunicorn for Django.
Now at last we are running our code. In order to generate a response, our framework will have to do following: authenticate user make requests to database to pull information for all part of the page process returned data and render html
In reality, multiple levels of our application level cache kick in. Only if cache is empty on all levels, we’ll go to the database.
Memcached or Redis. Our application will try to serve user’s page from cache first. If it’s not available - it will pull page fragments from cache. For fragments that are not in cache, it will get cached database responses and render that particular fragment of html.
Almost all of the websites and applications are database-driven. Waiting for database to fulfill query will take significant part of entire response time, so choosing database wisely and making queries correctly will speed-up response significantly.
It looks like if cache is not empty, ruby or python won’t even have to run. If it has to run, it only has to run for the fragment of the page, which is not in cache. When running, part of that time will be just waiting for the database response. Framework’s speed impact is not that important for the overall response time.
When there is nothing in cache and application has to make all the db queries and render everything, it takes up to 2 seconds (including all the db queries).
Fully cached response is 10-20ms. Partially cached response will take 200ms
Optimizing database structure and queries can reduce waiting time by 90%.
As you can see, architectural decisions can change response time drastically.
Ok, fine, ruby/python will run for just a fraction of total response time. Let’s measure speed difference between python and ruby during that running time - that’s exactly when raw language speed really shines.
As of January 2017, based on results from benchmarks game (http://benchmarksgame.alioth.debian.org/u64q/ruby.html), on average Python is slower than Ruby by 0.7%
|Task||Python 3 (sec)||Ruby (sec)|
At this point you can imagine how catastrophic for your application’s performance it would be to choose a «slower» framework.
It might have been a little bit too long joke, but hopefully I’ve made my point - when choosing between RoR and Django, forget about speed. It’s more important how fast you can learn, how easy it is to find a job, does language matches your way of thoughts.
These frameworks while similar, have different philosophy, which is easy to notice when you start using them. Just spend a month playing with each of them and go with the one that was easier. Really. Choosing the easier way is not cheating in this case.