2021-05-31

Salaire en suisse : how to write a static website using Google Cloud and fancy technologies

https://sylvainleroy.com/wp-admin/options-general.php?page=ad-inserter.php#tab-2

I launched a new website to help workers in Switzerland to have a better understanding of their payslips. I discovered in four years working in Switzerland that a good understanding of your payslip is a tremendous help in the negotiations with your employer.

The website is called “Salaire en Suisse”  and is available at https://salaire-en-suisse.ch.

To build the website, from a simple idea, I met several issues or challenges and tried new technologies.

This article describes what has been tried and the result.

Frontend development

Alpine.js :

From the beginning, I wanted to use Alpine.js as my primary web framework. Since the website was purely static, I did not need anything particularly fancy or complex.

Alpine.js allow the coder to add quickly some behavior to an HTML page without breaking your SEO or the hassle to launch a server.

However, to be honest, as the first HTML page template was built, and more HTML was written, I was growing upset to not be able to have a Component-based design.

I read several articles on how to do such components with Alpine, and even using a custom template generator or Web components ( link1 ). Ultimately I felt bored and annoyed with this approach of programming where I am building Components using a JS Function and parsing the HTML to generate my DOM elements. It feels so awkward and prehistoric.

I quickly came back to my most efficient way to build a frontend: Vue.js

Tailwindcss

Several LinkedIn posts were talking about Tailwindcss and since I am positively tired of Bootstrap and MaterialUI, I decided to give it a try and that’s a big yes. I am really addicted to this way to compose your UI using non-semantic CSS helpers. Unconsciously I have been writing my CSS stylesheets this way for a long time.

Nuxt.js

Some time ago, I heard about Nuxt.js and did not have time to launch a project with it. Basically, it is the same as Next.JS and ReactJS but with Vue.js. I particularly wanted to test the static rendering functions.

I used several modules of Nuxt.JS to help me:

SEO and Analytics

I recommend nuxt-robots, nuxt-gtm and nuxt-sitemap to provide a basic SEO to your website.

Internationalization and multi-lingual website

Nuxt-i18n is an unbelievably useful extension, it handles your translations and your routes to build a multi-lingual website. The documentation of the module is also great. It was a really nice find.

Finally, I had the need of the REST API

Yes, I decided for Salaire en Suisse to create a REST API. For two reasons, I needed a proxy between the Database and the Frontend. I did not want to expose the Database to the web therefore I built a simple REST API between the Front and the Backend.

First, I used a Nuxt.JS endpoint directly in the backend using express. It was good enough for the development version. Easy to restart and to use. However, at a moment, I created two new routes, and even if I could keep the server, Nuxt.JS consumes too much RAM and CPU at the startup time. I had to increase my VM resources just to run the server ( once the compilation is done, the memory is meaningless).

I tried two solutions to replace my REST API prototype.

Using Google Cloud Functions

My first REST API implementation used Google’s CloudFunctions system. Implementing a Node.JS function is super simple. So is deployment.

An interesting new feature is the ability to plug Cloud Functions into Compute Instances to communicate with a database, for example.

I had no real issues with the Cloud Functions. My limitation was related to mapping the Cloud Functions to rest paths in my load balancer to form a complete Rest API. In other words, I wanted to map the Cloud Function “tax” to the “/rest/tax” path and the Cloud Function “simulate” to the “/rest/simulate” path of my LB

But the proposed solution had several flaws:
– a query on the LB comes out of the Google network to return to the Cloud Function
– otherwise, I have to deploy a “Cloud Endpoint” instance on CloudRunner and define a manual swagger. Except that for having tested it several times, this operation is really “try and retry” and one wastes a monstrous time to try to obtain an effective configuration. In short, this is a lot of time needed for such a small feature

TS.Ed framework

I like Express.js,  I really like it. However, I would like to use it with Typescript. Previously my found with TS.Ed, I was building something hybrid between Express.JS and the TS Compiler ( and a big usage of any).

The framework TS.Ed suggests a more mature solution to use Express.JS using Typescript. It feels like Spring Framework and it certainly looks like with the same qualities and defects.

The framework offers nice documentation, IOC, Swagger integration.

However in comparison with the Express.JS minimal approach, the TS.ED wrapper brings a somewhat different way to create a Route, a Controller using Decorators. I was a bit annoyed by this change but with some time, I get accustomed.

But why do I need a DB?

Yes, I said I wanted a  static website but ultimately I could not do it. Mainly because the tax data from the Swiss governments represent more than 3 million records ( for all the cantons ) and I could not store it into a plain JSON ( more than 50 mo ).

RethinkDB

I tried several databases since it was basically a read-only store. RethinkDB: the open-source database for the real-time web is a not-so-famous database but really practical.

RethinkDB

You can create a reactive binding, it’s JSON friendly and you can store documents without much thinking of the data structure ( don’t forget your indices though). I went for this first solution but I have been annoyed by two important characteristics: the database was eating my RAM like a newborn baby and the writes on the disk were painfully slow ( I had several millions of records to insert). I tried batch insertion and no clue. I tried several things but could not get what I was expecting.

SQLite

SQLite database is a powerful, low memory database that I used in the past. Using Batch writes and transaction, I have been able to disable the WRITE ON COMMIT behavior and achieving nice performances. Connection with Node.JS was also possible. But one of my future use cases implies concurrent writings and I could not keep the database any longer.

MongoDB

MongoDB is a platform document-oriented database program. MongoDB uses JSON-like documents with optional schemas. Basically, in my use case, the server does not consume much memory and the bulk insertion was crazy fast. I kept it 🙂

Conclusion with Google Cloud

It has been really fun to write this small website and I had to review several technologies to find something appropriate and cheap to host. Here is the architecture diagram of the solution I built. It is a temporary diagram.

Salaire en suisse : architecture-diagram

I hope that my comments have been useful for those who would be interested to write a Website. And if you want more articles about the Cloud, click here

Sylvain

 


Sylvain Leroy

Senior Software Quality Manager and Solution Architect in Switzerland, I have previously created my own company, Tocea, in Software Quality Assurance. Now I am offering my knowledge and services in a small IT Consulting company : Byoskill and a website www.byoskill.com Currently living in Lausanne (CH)

View all posts by Sylvain Leroy →
Exit mobile version