What have I learned in a month of JavaSript development as a Python developer
Tags: javascript, webdev, beginners
Published: 2021-10-04 20:58:18

### table of contents

- intro
- js
- html
- css
- special thx to

### intro

For the last few years I was a python-terraform-ansible-gcp engineer. Regardless, my latest quest was to build a PoC (proof of concept) — and that's including UIUX part.

Considering I was super rusty with JS / HTML / CSS (last time I've touched these Pluto was still a planet and that's sayin') this was a promising challenge from the start, but I've never anticipated how much pain I'll actually find..

So I want to share some outcome thoughts with you ladies and gentlemen just to feel sane again. Oh and also to be of some help to backend developers / JS apprentices.

**disclaimer:** These lessons-learned are not something that should be used per se for decisions in commercial projects! I'm not a professional frontend developer!

### js

- as a rule of thumb always aim for the native & modern solution. Basically yeah, this is true for most languages, however JS is the place where the profits of that are super noticeable, almost palpable. Most of the time popular JS-related questions at stackoverflow usually contain 3 types of solutions: jquery, es6/es7 and the old js. You need the es6/es7 one. You'll easily spot that one since it'd be the most laconic.

- `const` -> `let` -> `var` (for variables and functions declaration). Which means: `const` is the best choice, the second best thing is `let`, making `var` the worst.

- [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) are _literally_ awesome, use them everywhere to format your strings (instead of string concatenation):
```js
let name = 'Bruno';
console.log(`Hello ${name}, sum of 2 and 3 is ${2+3}`);

// Hello Bruno, sum of 2 and 3 is 5
```

- frameworks (react.js, vue.js) are actually hard. Even the ones that are in fact human-faced. You'd have to learn state, components, initialization, bundling, .. BEFORE anything will work for you. I have exceeded the time limit I was comfortable with to put on that and therefore had to drop vue.js.

- w/o framework you don't have a way to render your templates at the browser side. Which actually leads to ugly js code. I don't think I have a proper solution for that. I just left it as an ugly js code building html pieces. It works.

- beware of [red-blue functions](https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/) and async code. The thing is, other languages with red-blue functions (like Python) generally allow you live in a sync world by default and (whenever you ready) you are ok to start doing some async work.
This is not the case with JS. It's async by default, and (though there are decent reasons for that) it damages your learning curve badly. The code seems to be working properly but with the first user you'll start to get mandelbugs, lots of them — because your flow of execution is unpredictable, and that's because you have a terrible mess of a sync and an async code due to the inexplicit syntax.
I'm confused what advice to give here, but what helped me was to carefully check where are actually async code and what pieces / in which order call it. At the end I've started to use [chained promises](https://javascript.info/promise-chaining) for the async and it worked like a charm.

- please consider allocating some men-hours / women-hours in order to build & bundle your project. In my case in a temptation to cut corners during a small project I've decided to go w/o it and was punished multiple times. I couldn't use Sentry, Typescript, some of the linters, many libraries and widgets — because in modern world everyone simply assumes you're building & bundling your js, so they won't provide you with `<script>` way to plug-in.

- typescript is an awesome way to solve _a lot_, but not _most of the_ js pitfalls. Reach for it early, it's totally worth it

- while I've mentioned typescript, objects comparison / checking for null|undefined|empty string are indeed a huge pain. (Yeah turns out it wasn't just a silly pub joke Python programmers tell each other.) Don't even try to guess it. stackoverflow / mozilla docs are your only friends on this damned land

- definitely setup an auto-formatter (in js the go-to weapon is [prettier](https://prettier.io/), and the best thing is that you could use it even without CI/CD simply [via pre-commit hook](https://prettier.io/docs/en/precommit.html#option-3-pre-commithttpsgithubcompre-commitpre-commit)) and preferably also a linter (I've tried eslint, and it gave me nothing useful but a lot of false positives. Maybe the default configuration was off, no idea).

- the other main danger of the js: the language silently swallows any errors and issues that'd happen during execution flow. Yes, that's exactly as bad as it sounds, because due to that fundamental design flaw you never actually know what happened and when. (Again, I know it was intentional, still it's terrible in terms of developer experience.)
I've had some success fighting this by introducing extensive logging everywhere across my code, it looks kinda like this:
```js
function debug(msg) {
    const today = new Date();
    const time = `${today.getHours()}:${today.getMinutes()}:${today.getSeconds()}`;
    const js_module = import.meta.url.split('/').pop();
    console.log(`[${time}] [${js_module}] [DEBUG] ${msg}`);
}

function handleMyEvent(e) {
    debug(`${e.type} handler invoked`);
    // logic
}
```
again, ain't pretty but it works well. The `import.meta.url` is the chef's kiss I like: it shows you which js file actually throwed the log message.

- avoid `window.onload` / `document.onload` statements: they will silently override each other if you're using them in more than one file. Prefer constructions like this instead:
```js
function main() {
    // your logic
}
window.addEventListener('load', main, false);
```

- avoid working with `localStorage` directly. It seems friendly and handy, but that's deceptive: native js localstorage can only do strings, and (for example) it will gladly and silently accept empty array from you, but it will return empty string back on that key. Use 3rd party wrappers instead (I've chosen [lockr](https://github.com/tsironis/lockr) and I'm pretty happy with it) or methods of your framework (that one is preferable if you have a framework)

- beware of caching: opposed to the backend world where nothing is cached untill you configure it to do so, in the frontend world EVERYTHING is cached by default. And that's not only static server, it's also cdn, local server, browser and so on. You'd have to spent a bit of time till you'll learn each layer and how to work with them. I'd emphasize on one though: caching of static files on redeploys. 

- beware of [mutation](https://blog.sapegin.me/all/avoid-mutation/). Luckily I havn't cached one of those issues but it looks scary enough to be aware of.

- don't you ever fall into the temptation of implementing your filters like I did.
What I did was: at each user click query all checkboxes, put all the gathered states into `localStorage`, then just throw a `window.location.reload();` and on each page load use `localStorage` value to render controls. 
Turns out (surprise!) not only this logic is super bad for the page performance / user experience, but it's also unreliable as hell (data flow between localStorage and controls is unpredictable) and leads to the ocean of non-debuggable bugs.
Instead use [CustomEvents](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent), separate listeners and dispatchers by js modules properly ― this specifically is how I rewrote it and it worked like a charm ever since. 

### html

- definetely start by throwing in additional meta-tag in your base template:
```html
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
```
this'll allow users to somewhat decently access your site from mobile

- aim really hard to NOT use `<div>` tag for everything. There are `<section>`, `<a>`, `<main>` and many others. This is the important concept called ["semantic html"](https://dev.to/kenbellows/stop-using-so-many-divs-an-intro-to-semantic-html-3i9i), it's easy and it greatly helps both to read the code and to access the site ([a11y](https://www.a11yproject.com/)).

- whether possible try to link your js files as modules, not as scripts. That way you'd be able to reuse code from them:

```html
<script type="module" src="{% static "js/sidebar.js" %}"></script>
```

### css

- always use classes, never ids. That's much more reliable and maintainable (for instance, it covers the case with multiple elements that carry the same purpose). Then you could access it with a selector like this:
```js
document.querySelector('.toggle_button'); // for a class toggle_button
```

- if you're assigning more than one css class to an element via literal, don't forget you have to do it in a separate class statement:
```html
<button class="button_yellow button_toggle"></button> // correct

<button class="button_yellow" class="button_toggle"></button> // wrong
```
otherwise one of the two `class=""` instructions will silently override the other.

- assign different classes with meaningful names to elements with different purposes, don't cut corners on naming in css

- I've had moderate success by using either `display: flex;` or `display: inline-block;` on css rules in order to make page blocks behave, but besides that css is still some sort of weird witchcraft and deserves it's own article.
However [this small educational material](https://wizardzines.com/zines/css/) by [Julia Evans](https://twitter.com/b0rk) is the best thing I could only think of on the subject.

### special thx to

-  [@twanttobealighi](https://twitter.com/twanttobealighi) for css / js / html help 💛