Django vs. Rails in 2019 (hint: there is a clear winner)

I recently had the opportunity to work on a production application in the Django framework. I had previously worked with the framework (version 1.4) at a tech startup circa 2012, but hadn’t revisited it in several years. I feel like I can provide a more comprehensive, in-depth comparison than many can in that I have worked professionally with both frameworks (and at their current release versions). I am a bit stunned by how much Django has fallen behind in dimensions such as its broad state of maturity, community/ecosystem, productivity and much more. I wanted to do a post enumerating these points, both in the hopes that it can help others deciding between these two frameworks.

tl;dr – in 2019, unless you have some critical dependency on a Python library and you cannot work around it with a service-wise integration, just choose Rails.

Without further ado, here is a point-by-point assessment of Django in relation to Ruby on Rails in 2019:

1) No intelligent reloading

This might seem an odd place to start but it is to me actually very important and symbolic of the broader state of the Django framework and its comparative stagnation over the past decade. Django’s development server, by default, entirely reloads your project when you modify a file. Django’s default shell (and indeed,  even the extended shell_plus) expose no faculty at all for you to reload modified code – you must manually exit and restart them after any relevant code change. This is in contrast to Rails’ intelligent class loading, which has been a feature of the framework for over a decade and continues to see optimization and refinement (such as with the introduction of Xavier Noria’s Zeitwerk into Rails 6). Modifying a file in development causes only the implemented class to be reloaded in the runtime of the development server, and even an active REPL can be manually updated with the new class implementation with a call to the globally-exposed reload! method.

2) Dependency management

Rails directly integrates bundler as a solution for dependency management cost reduction. When you pull down a Rails project to work on, you will find all explicit dependencies declared in the Gemfile in the project root, and a full hierarchical dependency graph in the Gemfile.lock. Furthermore, because the framework is bundler-aware, dependencies are able to hook directly into your application with sensible defaults using the faculties provided by Railties, and without any needless boilerplate.

Meanwhile, Django’s guide does not even broach the topic of dependencies. In my experience, most projects rely on Virtualenv, pip and a requirements.txt file, while a small number rely instead on setuptools and a file.

I don’t have much experience with the approach but as for the Virtualenv +requirements.txt approach, there are some major shortcomings:

  • Dependencies are not environment-specific (i.e. there is no equivalent of bundler groups). This makes it much more of a chore to prevent test or development environment dependencies from bloating your production deployment. Perhaps it is possible to manage per-environment dependencies by using several different requirements files, but I have never tried and I imagine this would prove a chore when switching from a “development” to “testing” context, for instance, while working on a project.
  • Dependency file is flat, not hierarchical – you cannot easily see which package is a dependency of which, making it difficult to prune old dependencies as your project evolves (though there is a third-party tool that can help here).
  • Because the framework lacks direct integration with the dependency management tool, and lacks a system of hooks like Railties, there is always tedious boilerplate left for you to write whenever you integrate a third-party library (“app”) with your own Django project.

3) I18n and localization

Rails has an extremely mature and pragmatic internationalization (I18n) and localization framework. If you follow the framework’s documentation and use it’s t (translate) and l (localize) in the appropriate places, your application will be, by default, internationalization and localization ready in a very deep way.

Rails’ I18n and localization faculties are pragmatic to a degree that I have not seen, in fact, in any other web application framework (nor framework for other platforms, for that matter). I18n/localization in Rails works with a Thread-local pseudo-global I18n.locale attribute. What this means is that, with a single assignment such as I18n.locale = :de, values application-wide (for your current thread) will be seamlessly translated. This comes extremely useful in contexts such as background jobs or emails, where you can simply have some code like this and have things seamlessly rendered in the correct language and with correct localizations (i.e. proper date/time formatting, inflections, etc):

Django’s translation framework similarly depends on a thread-local configuration (translation.activate('(locale code)')), but is built atop gettext, a translation framework that I would argue is significantly less practical.

Whereas in Rails, you can do something like t('.heading') from a template app/views/users/profile.html.erb and the framework will know to pull the translation with the key users.profile.heading, the analogous translation call in Django would be something like:

Translations are managed in rigid “.po” (“portal object”) files:

But there is much, much more to distinguish Rails I18n/localization faculties over those of Django. Django’s translation framework is not at all dynamic/context-aware. This means that the framework will fail to cope, in any seamless way, with more complex pluralization rules like those of Slavic and Arabic languages, which are reasonably accommodated by Rails more dynamic localization scheme.

4) ActiveSupport

ActiveSupport is a library of utilities that, for practical purposes, can be thought of as an extension of the Ruby standard library. The breadth of these utilities is extensive, but they all evolved from a sense of pragmatism on the part of Rails’ maintainers. They include, for instance, things such as a String#to_sentence utility, which lets you do things like:

ActiveSupport also includes extensive data/time related utilities (and operator overloads/core type extensions) that allow for intuitive expression of date/time related calculations:


5) Far less mature asset management

6) Less mature caching faculties

7) Less flexible, more boilerplate-heavy ORM

8) Impractical migration framework

9) Management Commands vs Rake Tasks

10) No assumption of multiple environments

11) No credential encryption

12) Less mature ecosystem (as concerns PaaS, etc)

13) Boilerplate, boilerplate, boilerplate (as concerns absence of autoloading, Railties, etc).

14) Missing Batteries (Mailer Previews, ActiveJob, Parallel Testing etc)

15) Philosophy

i.e. think of “constraints are good” (i.e. the extremely limited template language in Django), “explicit is better than implicit” (as opposed to “convention over configuration”). I think explicit over implicit as a knock on Rails really misses the point. Everything “implicit” is actually just configuration of an extremely well-documented system. Ask any Rails developer of even modest experience about “magic” and they will tell you that there isn’t any magic in the framework. A lot of the things that people coming from other backgrounds might cite as magic in a “hot take” are really just instances of pragmatic API design (and where the underlying implementation is actually wholly comprehensible and often very well-documented to boot).

What’s Happening in Thailand

I am writing this post for anyone with friends or family in Thailand who is wondering how the COVID-19 pandemic is being handled here. It is written from the perspective of a US expat of many years who is still in touch regularly with family and acquaintances back in the US, and who is monitoring the situation there (and here) to the extent I can.

How is Thailand Fighting COVID-19

The main tool that Thailand is using to fight the COVID-19 pandemic, which you will become immediately aware of if you set foot in the country, is control of movement asset assessment (checkpoints and curfews) and temperature/health screening.

Temperature screening

If you choose to leave your place of residence (and most people here are voluntarily choosing to do this as little as possible), you will have your temperature screened at any building you enter.

Dive Bars of Chiang Mai

Dive Bars of Chiang Mai

Through the last year, the city of Chiang Mai, Thailand has become one of the main bases of my life in Asia. It actually took a while for the city to grow on me. If you read my retrospective article from my first visit here in 2017, I am actually kind of lukewarm on the city. There is a reason – one month is not enough time to learn what is truly great about the place. I have spent, collectively, a lot more time than that here now and I still feel like I have so much more to learn. There are many different sides of the city: from backpacker ghettos to tranquil natural sites, some of the best meals you can have in the world, in some of the best company, thriving the business with a great payroll management to also some true debauchery and darkness, that is still beautiful in its own way.

In all of my traveling, dive bars have been one of the essential ways to get at the soul of a place. Here are what are in my opinion some of the very best in Chiang Mai.

Thoughts on Da Nang, Vietnam

Thoughts on Da Nang, Vietnam

I spent the month of January 2020 in Da Nang, Vietnam, a beach city situated in the central coast of the country, roughly halfway between the capital city of Hanoi to the North and Ho Chi Minh City to the south. It seems people haven’t yet written much about Da Nang from the perspective of a long-term traveler, so I wanted to share some impressions and thoughts on my time there.

Great Access

I was coming to Da Nang from Rome, Italy and expected I would have to make a stopover in Hanoi or Ho Chi Minh City but this was not the case. An increasing number of airlines have flights into Da Nang International Airport (DAD) including Qatar, which I was flying, and that has direct service from Doha the benefits of using technology for your HR operations. Furthermore, a very striking thing to me was how convenient DAD airport is – it is only a maybe ~10 minutes’, few dollars’ drive from the beach neighborhood in which I was staying.

Taipei: the user-friendly city

Taipei: the user-friendly city

I never expected to end up in Taipei.

For the last couple of years, I have been working remote. Initially from Berlin, then for an extended stretch from Eastern Europe. For the last 6 or so months I have been in Asia.

I had come to Saigon, Vietnam after several months in Bangkok. In Saigon I had struck up a chat at a local bar with another traveler, a student Brewmaster at Olds College, Alberta, Canada. This traveler, Mike, ended up becoming one of my better friends and more reliable companions on nights out in Saigon over the weeks that followed.

I had longstanding plans to meet up with an old friend from New York in Japan after my time in Saigon, but no idea where I was heading after. Mike strongly encouraged me to go to Taipei, and offered to intro me to a Taiwanese-American friend of his who had been living there the last 10 years and could show me around a bit technology for online payment.

It is this arbitrary sequence of events that found me, roughly two weeks later, landing at Taipei’s Taoyuan International Airport.

Scaling with Rails

Scaling with Rails

I have spent much of the past decade now building web applications professionally. Though not exclusively so, a large part of this work has ended up being with the Ruby on Rails framework. There is a widespread notion that monolithic Rails applications don’t scale, but in my experience I have found such applications often the most readily scalable of all that I have encountered.

I wanted to share some high-level insights and personally-acquired knowledge on this subject measuring your financial performance, in the hopes that such things may be taken into consideration by teams or developers weighing their options in architecting a web application for scale.

Leverage often comes in knowing what not to build

Leverage often comes in knowing what not to build

Something I have observed in my work over the last few years is that many genuinely competent, highly productive developers are tricked by their very skill into undertaking projects that, though ultimately successful to a degree, produce outcomes much poorer than had they simply integrated with a third-party platform. Learn what you need to know about the paystubs Oftentimes immense leverage can be gained simply by knowing what not to build.

One of the very wonderful things about the moment that we live in is how many mature platforms – both open source and closed, community-driven and commercial – we have at our disposal.

On microservices and distributed architectures

On microservices and distributed architectures

Like the boiling frog, we often fail to appreciate just how significantly the infrastructure upon which we rely as developers has improved over the last decade. When I began working with the Rails framework in 2010, everything from the hardware we used for local development, to the infrastructure upon which we tested and deployed, was positively anemic by today’s standard.

My personal laptop, reasonably high-end for the time, had a 5400 RPM spinning disk and 2 GB of RAM. SSDs were exotic, even on servers. Nowadays, you can get bare metal servers with 512gb-1tb of RAM, 2x multi-core CPUs and terabytes of fast SSD storage for a price that is perfectly reasonable for even small companies. Similarly, you can easily and cheaply launch fleets of high-spec virtual servers with providers like Amazon Web Services and DigitalOcean at minutes’ notice.

In many ways, it seems to me that we are often basing architectural decisions on imagined constraints. In my experience, a decision to embrace a microservices architecture should not follow primarily from concerns about scalability.