We're planting a tree for every job application! Click here to learn more

Become a Better Programmer by Making It Hard to Write Bad Code

Adam Boro

28 Feb 2018

5 min read

Become a Better Programmer by Making It Hard to Write Bad Code
  • JavaScript

It is often said, and very true, that setting boundaries is beneficial for creativity. But these are not the kind of boundaries that this article is about — what I have in mind is more like railings that prevent you from falling from a staircase or fences that restrict access to areas which people are not supposed to visit. Like a swampy toxic waste area — it’s just not a good idea to go there. Or like deploying code that does not even compile.

Fortunately, such fences for programming can be set up, and a part of modern software development is just that — setting boundaries that will not let bad code make its way into the wild. This post is about some of these practices in the JavaScript environment, namely: linting, testing, CI, commit message formatting, and type checking.


What do you do when you’re writing on a digital medium and unsure about spelling? The answer is probably not a dictionary or even a google search — just write whatever and see if the spellchecker complains. Code linting works similarly. I got so used to it that without a linter I feel like driving for the first time on my own.

fun fact — the word “linting” does not pass spell check

My favorite tool for JS is called eslint. And while I’m recommending I’ll throw in standard, a “JavaScript style guide, with linter & automatic code fixer”. For me, this combo is even more indispensable than StackOverflow. Configure linting with your code editor for some visual feedback and you’ve just saved something like 867 hours per year in development time!

Also, if you’re unsure about why a particular piece of code caused eslint to freak out, take time to read about the rule that was broken — I’ve personally learned a lot by doing that. Here is the list of available rules — a nice learning resource on it’s own.


That’s pretty obvious for any experienced programmer, but it took me a long time to really appreciate writing tests. The problem here is complexity — when programming, it may seem obvious that some piece of code will simply work. It looks solid, the linter is not complaining, and you’re actually a bit proud of its terseness and how it does one job and does it well. But then there might be this one edge case that combined with another one and then something else makes up for a show-stopping error.

Another argument for testing is that when it’s time to refactor, and that’s always, a solid test suite will allow a programmer to focus solely on the code, without worrying if the program will break because of an inconspicuous change.

Finally, decent test coverage is like a quality mark on the code, a signal that some work was put into it. My favorite tool for testing JavaScript is jest. Setting it up for a project is simple and features like snapshot testing or code coverage reporting make it my first choice.

Continuous integration

But what good are a linter configuration and an amazing test suite if they are not enforced and run every time before the code is deployed? That’s where Continuous Integration comes in handy. It’s basically automating a set of tasks (first and foremost — running the tests) that ensure the code is stable and ready to ship to production.

This way, CI is a great way to enforce the aforementioned practices and be sure that all the necessary checks have been performed. Configuring TravisCI for a public GitHub repository is super simple and free — just add a .travis.yml file at the root of the repo, set up an account on travis-ci.org and there it is, CI configured. That shiny “build: passing” badge awaits.

Commit messages

This is one case where setting boundaries actually provokes creativity. Commitizen is a simple tool for providing properly formatted commit messages.

Initially, I was sold on the feature of automatically generating a changelog, but later realized that the main advantage comes from something else: reflection. By forcing the developer to define changes introduced by a commit in a structured manner, it makes them think for a moment about the changes. They may decide that it’s not a time for a commit yet or that the changes should be split into two commits. Or simply, if it’s hard to decide what the changes are actually about (is it a feature or just refactoring?), then maybe the new code is too ambiguous.

To use commitizen, just $ npm i -g commitizen and use git cz instead of git commit. Introducing commitizen in a repository is also very straightforward. And remember, you also get a changelog for free, which is pretty sweet.

Pro tip: set up commit message validation to ensure that the standard is upheld.

Also, semantic-release package is worth mentioning here. It streamlines the whole open-source release process using the tools mentioned above. If your project cannot be open sourced, then check out corp-semantic-release.

Type checking

When singularity comes, writing code will probably start to look more like interacting with HAL 9000, but until then we have to rely on other tools to tell us when we screw up. Linting can only get us so far, as can spellchecking when writing prose. But imagine writers had a way of automatically checking the logical coherence of their text. In software development, a close analogy would be type checking.

In programming, types are simply the types of data that a particular function handles. They can be things like strings, booleans, numbers, but also custom structures made up from the basic types, like this one (I’m using flow syntax here, more on that below):

type Person = {
  name: string,
  age: number

A static type checker reads type annotations and checks if all the calls to a particular function adhere to this ‘contract’:

// add takes `num`, which must be a number, and returns a string
const isItTheAnswer = (num: number): string => {
  if (num === 42) {
    return `${num} is a the answer to life, the universe and everything!`
  } else {
    return `${num} is not a the answer, try harder.`

isItTheAnswer(42) // => 🙂 compiles
isItTheAnswer('eating cat food') // => 💩 flow error - incompatible types
without looking at the function body, we can already see that the Answer® must be a number

In JavaScript, the two main choices for type checking are TypeScript and Flow. The above example was using flow, which is a type annotation system developed by Facebook that can be introduced very gently to a project, file by file.

With type checking, the development environment can actually teach you something about your own code. A couple of times after tracking down the source of a flow error it turned out that there was this one specific case I did not think about. But flow did.

In conclusion

If you were not using linting, testing, writing meaningful commit messages, or using a type checker, I hope to have convinced you a bit to doing all that. All of these tools and practices not only will help you to write better code — they also can teach you a thing or two about programming.

And because just like being less stupid is better than trying to be very intelligent, writing good code may mean simply making it harder for yourself to write bad code.

If you’re passionate about Front End development, check out the JavaScript Works job-board here!

Did you like this article?

Related jobs

See all


The company

  • Remote


The company

  • Remote


The company

  • Remote


The company

  • Remote

Related articles

JavaScript Functional Style Made Simple

JavaScript Functional Style Made Simple

Daniel Boros

12 Sep 2021

JavaScript Functional Style Made Simple

JavaScript Functional Style Made Simple

Daniel Boros

12 Sep 2021


CareersCompaniesSitemapFunctional WorksBlockchain WorksJavaScript WorksAI WorksGolang WorksJava WorksPython WorksRemote Works

Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ

108 E 16th Street, New York, NY 10003

Subscribe to our newsletter

Join over 111,000 others and get access to exclusive content, job opportunities and more!

© 2023 WorksHub

Privacy PolicyDeveloped by WorksHub