Failing Faster is a Good Thing—Learn to Fail Faster and Iterate with Modern Dev Practices
Tags: webdev, programming, node, javascript
Published: 2020-06-17 12:38:20

---
title: Failing Faster is a Good Thing—Learn to Fail Faster and Iterate with Modern Dev Practices
published: true
description: Using modern software development practices enable us to find and fix bugs faster and iterate. This post offers a primer into some of these modern practices.
tags: webdev, programming, node, javascript
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/55wh3dstbq0rzclsjjf0.png
canonical_url: https://typeofnan.dev/failing-fast-and-iterating-with-modern-practices/
---

*Please give this post a 💓, 🦄, or 🔖 if it helped you fail faster!*

<hr />

This post comes straight from my dev mailing list! If you enjoy it, please consider [signing up](https://buttondown.email/devtuts)!

<hr />

I have long believed that "failing fast" is one of the most important tenets of modern software development. The sooner you realize your code is wrong or that you have introduced a bug, the sooner you can course-correct. It keeps you and your team moving faster and significantly reduces the likelihood your users encounter bugs.

Today, I'm going to take a shallow dive into some of these modern practices.

# Version/Code Control

Use version control on your code (e.g., git). This allows for mobility, collaboration and backup.

Version control enables pretty much all other quality control measures. It allows you to implement "hooks" to force things like code testing and linting when you push your code remote repositories. You can hook your code repository up to Continuous Integration servers. The bottom line: modern software development starts at version control!

# Automated Testing

Automated testing allows you to develop with confidence. They serve as a form of documentation as they assert what your app should do. Automated testing also helps you refactor without fear since you are relatively confident in your new code if tests pass.

You can write your code and “smoke test” it, meaning you try playing with your app a bit to make sure it works right. But how do you know your users won’t hit a weird edge case that blows up the app? You don’t, but you can help mitigate this concern by writing automated tests. Once written, these tests live forever, meaning less concern about software regression since your exists tests will (hopefully) fail if your code introduces a bug to previously-developed functionality.

As a bonus, you can use version control hooks and/or Continuous Integration to require your tests to pass before you can move forward in deploying your code.

# Continuous Integration (CI)

CI allows you to merge your code into a single repository frequently. A CI server can run automated tests and other checks to make sure your code is ready to be merged and, in conjunction with your version control service, can be a quality gate.

When you push code to a remote repository, you can know *immediately* if your quality measures (e.g., tests, linting) have failed. This is a whole lot better than finding out because a user has emailed you that something is broken!

# Continuous Delivery/Deployment

Continuous delivery means you continuously deliver new code into a releasable state, ready to be sent to production at the click of a button. Continuous deployment goes one step further and deploys code, usually as soon as it’s merged into a branch.

Making it easy to integrate really small changes into your production environment is critical for iterating. The truth is that you *will* merge some breaking changes into production. Software development is error prone and we all ship bugs. 

However, if we ship *really* small chunks of code to production, our lives become much easier when we eventually do ship a bug. First, if you need to revert your production code, it’s much easier to do so with a very small change set. Second, when you need to figure out what went wrong, you have a pretty small amount of code to investigate. It’s much easier to find a bug in a couple days worth of code than a couple months worth of code!

# Intellisense and Linting

Use a code editor that has language services for your language. Ideally it provides autocomplete and lints your code. It highlights any compilation, syntax, and lint rule issues real-time as you’re writing code.

Features like autocomplete and code highlighting eliminates a lot of bugs *as you write them*. **This may be the fastest way to fail** and therefore it might be the most important item on the list! Linting keeps your code consistently-formatted, which makes it a lot easier to read for things like code review and facilitates identifying bugs.

# Feature Flagging

Feature flags are boolean (true/false) variables in your code that hide functionality that’s in development from your users. It allows you to keep releasing code as new features are mid-development, meaning those features don’t block continuous delivery.

Releasing continuously is a cornerstone of failing faster. Without feature flags, we might hold off on shipping code for a while because we don’t want to ship a half-baked feature. Feature flags let us ship constantly without worrying about these not-quite-done features!

# Instrumentation and Monitoring

Use a service like New Relic or Datadog that monitors your app for errors. Set up notification thresholds that notify you or your team when a particularly high number of errors are encountered.

Let’s say we ship a change that causes our web server to start spewing 500-level errors. We don’t necessarily want to wait until a bunch of users complain—monitoring tools let us know immediately when we’re getting a high level of abnormal responses. We can then investigate and mitigate the situation before too many users are affected.

Generally, these tools have simple integrations with team collaboration tools like Slack. That means you can set up a bot to ping your team's channel if any thresholds are met!

# Containerization

Reduce concerns about different environments and simplify deployments by using a containerization service (e.g., Docker). If an app can run locally in a Docker container, it can run deployed on a server as a Docker container.

Containerization allows us to be working locally in an environment (pretty much) identical to our deployment. This increases the chances that we detect any environment-related issues locally rather than in our production environment. We like figuring out issues locally rather than in production.

# Conclusion

The faster you fail, the faster you can course-correct. Hopefully this list of best practices gives you some ideas to help you start failing faster yourself!

<hr />

This post comes straight from my dev mailing list! If you enjoy it, please consider [signing up](https://buttondown.email/devtuts)!