Toxic mushroom has neither a compiler nor worries.

For most of us it is much easier to be a child than to be a teenager or an adult. One of the reasons why childhood could be the most joyful time of our lives is the lack of responsibilities, of which the most annoying is responsibility for your own wellbeing. As children we have parents, or legal guardians, or some other experienced, and responsible adults telling us what’s good and what’s not. And although we may still misbehave, and experience some part of this world through the misery of our own painful mistakes, this adult’s guidance we receive keeps us alive. Like very literaly.

Similar thing applies to compiled programming languages. Compiler acts as a caring adult, that prevents our applications from doing stupid mistakes. Compiler translates our high level code into some low level programming language (assembler, byte code, etc.), and in order to do this one should be valid-ish to be mapped to the other. We trust a compiler to let us know when we try to access a variable that we never declared, assign a value of type of MyHelloworldClass1 to a Boolean variable, or miss a semicolon 😖. We rest assured, that our code is never to be executed if we’ve screwed up. That is unless we use JavaScript. Or PHP, or Ruby, or any other language that is not lucky enough to have compile time, but let me focus on JS here (please).

So let us review some options, that I believe may help you to reduce number of run time errors, and therefore make your life much (or only a little bit) happier.

Disclaimer: Sometimes I am going to use a term ‘compiled language’ in its almost orthodox meaning, referring programming languages having compile time as opposed to languages having only just-in-time (JIT) compiling option.

The compiler is your friend. For real.

Option 1: static code analysis tool

Well, I guess that if you work with JavaScript for a while, you are already familiar with a concept. I am talking about a linter — a tool that analyses your code and tells you what’s wrong with it. No doubt about it, static code analysis software is the second most effective way to reduce amount of ridiculous runtime errors.

If some of you, my beloved readers, don’t know what linters (I’m gonna use this term instead of much lengthier “static code analysis”)are and what they do, here is a very brief overview. Linter is a program of a sort, that takes your code, and some instructions of what is considered to be bad code practices as input, and after analysing the former based on the later produces a list of problems you have. Like with your code, not in general (for that you need something better than a mere app). Normally, depending on your config, a linter may point out at syntax errors (e.g. undeclared variables), code smells (e.g. unused variables), violation of code style conventions (e.g. long lines), or deprecations. Although these tools can be used as standalone applications, they make more sense when integrated with your IDE, in which case they may analyse your code and provide you with a list of problems in real time. For example I use a linter called ESLint integrated with Visual Studio Code. When you initialise ESLint for your project you may choose whether you want to generate a new linter config based on your code style, or just take one of the popular ones used by big names like AirBnb or Google. I personally prefer AirBnb one with a bit of custom modifications, and I would suggest to try it first to get an idea of what it is actually capable of. Anyways, after some time most of development teams come up with their own linter configs, that best suit their needs. Because in our magical and heavily diversified world of IT no dev team is the same as the other.

So yes. Static code analysis tools AKA linters. Use them if you still don’t. There are really no excuses to not to.

An example of ESLint’s output.

Option 2: transpilers and language supersets

This is going to be a tricky one because I am going to talk about two connected but not exactly identical things. Bear with me, Okay?

The easiest way to survive JS’s lack of strong typing and compile time error checking is to add them. Which is possible with little trickery of using JavaScript language supersets like TypeScript, ResonML, Flow (which is called ‘a static type checker’) or CoffeeScript (which nobody cares about in 2018), that are then transcompiled back to vanilla JS. It’s almost fair to say that using one of these languages is the same as using a compiled laguage like Java. At least from the prospective of code analysis. Unlike a linter that may point at obvious mistakes but never actually prevents you from doing dangerous things, a compiler may raise a compilation error, which will prevent your code from running, at least until you fix all the problems found by a compiler. Which is a good thing because having no app is better, than having one that is broken.

Although you have to use a transpiler to generate JS from its superset, you may also use one to generate JS code from, say more advanced JS code. A good example of such tool would be Babel. For those of you unfamiliar with this tool, Babel is a JS transpiler, that converts code written using the latest and greatest of ES2015+ into older ES5 for better compatibility with slightly outdated browsers. So for the purists and unlikely fans of weak typed languages – you can still have a compiler-ish tool for your 100% pure JS code.

So as a résumé for this section I want to say this: If you are starting a new project or making your first steps with Node.js, please have a good look at TypeScript or maybe even ReasonML as these are great programming languages helping to avoid many pitfalls caused by JS’s not-so-logical take on types. Also if you are a front-end developer who has good reasons for not using anything but EcmaScript, then please at least use Babel. JS is getting better with each iteration of ES, and you really want to get access to all the new APIs ASAP, not to mention the fact that you’ll have a transpiler’s keen eye looking for nastiness in your code for you.

TypeScript, Flow and ReasonML are to the rescue when it comes to strong typing.

Option 3: Tests automation

*Sigh*, in the year 2018 I feel upset every time I need to argue about the significance of unit testing with seemingly sane developers working on fairly big projects with a whole lot of dependencies. Moreover the situation is getting a lot denser, should I suggest that developers could also write some automatic integration and/or functional tests. That is not only in the situation when you don’t have a dedicated test team. Say in a big, complex system there could be some tricky parts that integrate with each other on a level that may still qualify for white box testing which is not unit testing. For example you may want to test your Web API that has a few middleware functions called at different conditions (think Koa). In certain scenarios you can organise your code in such a way so you can mock underlying infrastructure and call your API’s endpoints without deploying it to a test environment.

Writing white box tests is boring, and this is getting the more boring, the more complicated your system becomes. However tests, even if they are very basic and incomplete, may, and will (sometimes) stop you from deploying broken code. Quite often this potential breakage won’t be caused by an incorrectly implemented algorithm, or something that has to do with logic of your application. No, not at all. Your culprit will likely be a missed semicolon, a typo, or an undeclared variable. All this things that are normally found and reported by a compiler.

Write your tests, run your tests before every commit, love your tests (or at least don’t ignore them).

Option 4 (controversial): level up your coding skills

Because you can always do better. Even if you are Elon.

Unlike other options I suggest, this one is passive and does not guarantee any results, but still I believe that well structured, and understandable code helps to reduce amount of ridiculous, easy-to-overlook errors. That said, I am not going to talk about all the possible, and impossible ways one can improve their code. Because you know, I have a feeling that someone, somewhere has already written a book or two about good practices in every programming language known to humanity. Instead, lets focus on something that, as I sincerely believe, is relevant to the main topic of this blogpost.

First, make your code as simple, as readable, and as obvious as possible. I already wrote about a fine approach I try to take whenever the busyness logic of a certain module becomes to complex. JavaScript allows us to use some concepts from the functional programming world, and I suggest you embrace them to improve the three qualities of your code I’ve mentioned in the first sentence of this paragraph. However, I do want to mention one programming concept, that I’ve learnt to use not so long ago, and I regret it took me so long to get there. That’s pure function – a function, which causes no side effects, and returns same result for same arguments. You can write them in any programming language, but the ability to compose, partially apply and curry functions makes them especially easy and effective in JS.

Second, and this is related to Option 3, write your code in a way that allows dependency injections. Without overdoing that though. This should help you to write more meaningful unit tests, that will help you to understand if there is something wrong with your code, rather than confuse you by breaking for no reason every time you make a small change.

Option 5: The only good one

Well, now let’s face the truth. Just as one person will never be as efficient as a seasoned team of professionals, none of the options mentioned above will ever be as good on their own as they will be when combined together.

Use TS/Flow/ReasonML to write clean, no-nonsense code, where an array will never be divided by a string. Add a linter to your IDE to keep track of unused variables and other nastiness in real time. Compile your code with Babel, to catch those stupid errors overlooked by the linter. Run automated white box tests before committing your code to make sure your system won’t blow up the moment it’s been deployed (to your test environment, hopefully). This won’t guarantee that you will never have a sleepless night spent recovering your whatever-you-build app from a critical failure, but this will surely help you to keep number of nights like this to a minimum.

Or use Java/C#/Go instead.

Thats’ all. Thanks a lot, and until next time.