Approved stacks¶
The goal of this document is to list which stacks have been tested and validated internally so that you know what tools you can use without running into too much trouble.
Of course it is possible to put any other tool on the table, but this would have to be discussed and properly PoC’d. More on that later.
Approved tools¶
The tools listed below are safe to use in most projects. Of course some client requirements might change this but you will be notified if that is the case.
Django¶
Django is the backbone of most things we do. There is lighter and in some way better frameworks out there but to date none would justify giving up Django and re-training the whole team on something else.
A few features that are paramount in Django:
ORM — This comes with no surprise that the ORM system is very important. Because you can introspect it easily, it enables automatic admin interface generation, automatic migrations, automatic serializers for the API, etc. Moreover it handles very complex queries and allows to leverage most of PostgreSQL’s advanced features.
Migrations — Not only there is a migration system that allows to change the DB structure as you change the descriptive models but this migrations system handles cleanly the Git branching model and presents a great flexibility when it comes to doing “less-orthodox” changes.
Auto admin interface — The automatic admin interface generation is a huge time saver for many of our projects for which we didn’t specifically sell a back-office but we still need to somehow inspect the data without going too deep into the SQL.
Django Rest Framework¶
DRF is an API generation tool. It is very flexible, very orthogonally designed. In fact, it is practically considered as the standard way to create APIs in Django. Of course it has a few quirks but overall we were never limited by it to create the APIs we wanted.
Don’t hesitate to use only parts of it for specific purposes. Typically:
Even if you’re not doing a ViewSet you can still use a Serializer to validate JSON input from an untrusted source
The rate limiting system is fairly easy to use on its own, in case you want to rate limit authentication by example
Wagtail¶
A Django-based CMS. We use it as a traditional CMS or as a headless-ish CMS depending on the project.
What we love:
StreamFields
More StreamFields
Fantastic management if images and thumbnails
Celery¶
Many projects require either period or background tasks. Celery is a perfect way to run them in a scalable and observable way.
It’s a bit frightening to start using it but it’s actually very simple. All you need is a RabbitMQ instance but the same applies: frightening but actually easy.
Vue¶
There is a whole section on why we need a functional paradigm in front-end web and why Vue helps with this so there is not too many needs to explain this in depth here.
Another excellent thing about Vue is its vue-loader. It allows to store in the same file the HTML template, some (scoped) CSS and the JS that goes with it. This makes it very easy to organize the code and to have automatic JS/CSS bundles done by tools like Nuxt.
Why Vue and not another framework?
React — It’s not actually reactive, there is many abstraction leaks and overall and different performance issues. This statement has been more or less true over the years and comparatively to Vue, but overall Vue served us well and there is no reason to switch to another monster.
Svelte — Svelte is very interesting because it allows to write many less lines of code and promises to be even lighter. The build tools are blazing fast. However there is many goodies found in Nuxt that you won’t find in Svelte.
Angular — Angular had the genius of creating this concept of declarative templates. However it suffered from poor design and was complex to manage. It received complete overhauls and new versions but it was too late I was already on Vue (which is much, much simpler).
Nuxt¶
The best friend of Vue is Nuxt. As explained below, that’s what you should use to scaffold any Vue project. It solves under the hood a lot of things that you’re probably not thinking about.
Server-Side Rendering — Essential for SEO, meta-tags reading and overall performance
Auto-split of bundles — Each page gets its own independent JS file which can be loaded individually. This allows to reduce the amount of code required to display the page and thus the amount of code that the browser has to parse to display the page, which is a huge selling point if you want to optimize Google’s core web vitals.
Automatic routing — Routing is automatically generated from the file structure so you don’t have to configure the router manually
Good integration with Vue ecosystem — Works with the store, many plugins exist to communicate with libraries from the ecosystem, etc.
PostgreSQL¶
PostgreSQL is a libre database engine that is readily available on many cloud providers and for good reasons: it has an incredible set of features.
Indexable JSON fields — Make NoSQL whenever you want
PostGIS — Very comprehensive extension to use geographical objects
Full-text search — Has a full text search ability on its own, no need to use an external engine like ElasticSearch for most operations
Light-weight &mbash; Uses just a few megabytes of RAM (if you don’t count the data itself of course)
Redis¶
It’s a key/value store that keeps all its data in RAM. It is commonly used as a cache, as a queue or as a store for not-so-important data.
RabbitMQ¶
Queuing system, to use in conjunction with with Celery when appropriate. It’s actually quite simple to install and configure and will use very few resources.
BERNARD¶
BERNARD is a home-grown framework to manage bot conversations. It allows to work with Git and provides the abstraction layers that are required for our projects.
NPM¶
In order to manage JS/CSS packages, this is definitely the package manager to use.
Pip¶
And in order to manage Python dependencies, Pip is the tool of choice.
Note
Pip will be replaced by Poetry when we replace Felix, but now is not the time.
pip-tools¶
Some operations are a bit complicated with Pip alone, we use pip-tools
to help
managing pinning versions and upgrading what we need.
SASS (most importantly SCSS)¶
The go-to CSS pre-processor that we use is SASS. Because everyone uses it and it makes very little difference with its competitors (LESS, Stylus, etc.) at the level that we’re using it.
Please however use SCSS and not SASS syntax, as Prettier can handle the former but not the latter.
Webpack¶
To build JS, CSS, minify and other front-end shenanigans, please use Webpack. It’s a bit complicated to configure but:
For Wagtail projects you can find examples in previous projects
For Nuxt projects, Nuxt handles the Webpack configuration on its own
Recommended stacks¶
Let’s talk about the recommended combinations of stacks for different kinds of projects.
Content website¶
For a purely content-oriented website, let’s use a regular Wagtail stack:
Django for the base
Wagtail for the CMS
Webpack to compile static assets
SCSS for the style pre-processor
Vue to handle small dynamic behaviors
Advanced content website¶
If your website needs to have content but also advanced interactive parts that will require a lot of JavaScript, it is best to give up the vanilla Wagtail implementation and to make it headless. This way you can implement most of the front-end with Vue directly.
Django for the base
Wagtail for the CMS
DRF for the API layer
Nuxt and Vue to handle front-end code
SCSS for the style pre-processor
Making Wagtail headless is not a standardized procedure yet. You can have a look at what was done in TFS and ActiveSeed. The base idea is:
Generate HTML code using Django templates (because it’s simpler to generate the content with a direct access to the DB or the ability to generate thumbnails on the fly)
Let the Nuxt app get this code through an API
Compile the HTML code into a Vue template
Stitch up a Vue component on the fly
Render that component inside the Nuxt app
It comes with many small issues but most of them are resolved by proxying 100% of the Wagtail app through the Nuxt proxy. This way cookies and sessions can be consistent from page to page (as opposed to having the admin on a separate domain).
Light-weight front-end app¶
If your front-end app doesn’t need an API, it makes sense to generate it as a static Nuxt app. In that case you would use:
Nuxt as a base
Nuxt Content to manage potential content (blog posts, etc). Let’s note that to change the content you need to create Markdown files in the code. But still, you get some API to filter, sort, render the content so that’s fairly convenient.
SCSS as a style pre-processor
Let’s note here that this kind of app is best deployed on a static host like Netlify or straight out into a S3 bucket. This procedure is not standardized yet though.
Web app¶
If you’re doing a full web app, then it’s pretty straightforward:
Django for the base
DRF for the API layer
Nuxt and Vue to handle front-end code
SCSS for the style pre-processor
Approbation procedure¶
Any tool you want to use can be considered. Even if it’s not in the pre-approved list above or if it’s in the deprecated list below. You just need to talk about it with your manager, with reasonable arguments in order to establish if it can be used for the project that you’re working on.
Of course this only applies to major and structural tools. If you want to use a tiny Django app that helps you minify HTML, this is not really a point of debate. Just make sure to choose something that is not full of bugs, security issues and poor design decisions. In doubt, ask for help.
In order to work with new tools, it needs to clear the following requirements:
It has to be deployable. If it’s not deployable with our current infrastructure then the question of upgrading deployment scripts can be raised. However that’s a significant cost, so it must be done for good reasons.
The overall cost must either be paid by the client either pay for itself. For example we pay a ViewFlow licence yearly for some projects because it costs 700€ (on average two days of work) and saved many days by providing a strong structure.
The same project must not require too much re-training of the team on its own. One major new tool in a new project is fine. Doing everything with completely different components would be quite dangerous.
It must be judged worthy by the Tech Lead both with a cold analysis and after a few days working on the project. If the tool is not performing as expected, it can be removed from the project, which takes time. So that’s a risk that must be accepted when the project starts.
Those rules are a bit cold but they are by no means here to discourage proactivity. If you got a tool that you think is worth it, let’s talk about it and roll it out. That’s how Vue took over Angular in the early days, this can happen again if something worthy appears on the scene (like, idk, Svelte).
Deprecated libs¶
Those tools were heroes at a time, but heroes must die before they become the villain.
Moment¶
Moment brought features that are essential to date manipulation that the standard JS library doesn’t offer. However, it’s just too fucking heavy. The simple weight of it makes it an impossibility.
On top of that, it also features a very awkward API with mutable objects, that’s definitely the cause of a few bugs we had in the past. For more reasons, you can check the You don’t need Moment.js page.
As a good alternative (but definitely not a drop-in replacement at all) you can
have a look at date-fns. Indeed, its functional
approach while still leaning on the native Date
object makes it pretty
convenient to use. Specifically, it can be tree-shaked, so you don’t need to
import code that you’re not going to use.
jQuery¶
To understand jQuery, you must understand that it was created at a time where supporting Internet Explorer 5 was a thing. That’s the kind of browser where changing CSS could disable certain parts of the standard JS library. It was a hell to work with it. But now, for most operations that jQuery allows you to do, there is a very simple way to do it with the native API of browsers. So if you want to manipulate DOM directly, you might not need jQuery.
However that’s not the reason to ban jQuery for our projects. It’s simply that we don’t use the same paradigm anymore. For that reason it’s not jQuery that is forbidden, but it’s direct DOM manipulation that is. Unless extreme cases (communicating with a legacy library, manipulating things outside of Vue’s scope, etc.), please use Vue’s native pathways instead of manipulating DOM.
Vuetify¶
Vuetify looks like an amazing idea but in fact it’s heavy, it’s complex and it’s not fitting all that well with our designs. All projects that used it ended up regretting it. So let’s not use it anymore.
Vue CLI¶
Vue CLI is a boilerplate generator for Vue.js which is basically a wrapper around Webpack to let you access advanced Vue/Webpack features without having to understand how to configure it.
While it’s a great tool, it does not cover one specific aspect which is a requirement on most projects: server-side rendering. As explained in the Build Lifecycle part, we need a server-side implementation as well as the compiled JS code. In essence, you will not be able to deploy your Vue CLI project because it’s simply incompatible with our infrastructure.
The good news is that there is a simpler, better alternative: Nuxt. You can use Nuxt for any Vue project and it will be much simpler and more efficient than Vue CLI.
Yarn¶
Since Yarn was released, NPM learned a lot and definitely caught up. There is no need for an additional piece of software in the stack.
Tailwind CSS¶
Tailwind has several issues:
It comes with its own build complexity
It’s impossible to apply the documentation process
If the CSS file is far away from the HTML it might make sense, however in the context of Vue/Nuxt the CSS is definitely close to the HTML so this reduces the need for it
Previous attempts at using it proved to be too divisive and didn’t meet a broad adoption
For those reasons, let’s stay away from Tailwind.
Bower¶
Well, Bower was nice before all was in NPM and compiled with Webpack but now it’s just some kind of crazyness.