In part ten of our twelve-part series on DevOps, we explore the concept and importance of shifting left, or testing as much as possible, as early as possible, in your development timelines.
Factor 10: Shift Left
The basic tenet of shifting left is to move as much testing as early in the pipeline as possible. By doing so, you detect problems before the application is deployed instead of after it, shortening the overall development cycle and reducing unpleasant surprises. Key practices supporting this effort include test-driven development (TDD), continuous integration (CI), and continuous testing (CT).
Under 12-factor DevOps, several checkpoints occur before the application can be deployed. Many of them can be used to prevent the branch from being merged if problems are detected. The CI pipeline should be triggered by the acts of committing code to the repository or opening a pull request. The success or failure of each of the steps then acts as a gate to permit or deny the merge. Fast failure means rapid feedback.
- Unit tests are automated and executed as the first step in a CI pipeline.
- Next, static code analysis assesses the quality of the code and looks for any potential vulnerabilities in it.
- Security scans against project dependencies ensure that no external vulnerabilities are present in the product.
- For containers, image scans can bring an additional layer of validation to the project.
- Integration tests ensure that the application functions as expected.
Unit tests can be written before or after the business logic is. If you’re practicing TDD they’ll be written in advance. Tests should target a minimum of 80% code coverage while ensuring that the tests are valid. It’s easy to game the coverage by writing one giant test which covers the whole application, but that only hurts you in the long term.
Static code analysis tests your code for duplicated lines or blocks, unsafe methods, and what are collectively known as code smells. It’s an invaluable tool for writing code that is easier to maintain, and many of the more popular utilities will not only estimate how much tech debt a given codebase has but will integrate directly with the developers’ IDEs, providing near-real-time feedback as code is being written. Of course, it should still be run as part of the regular pipeline as well.
Detailed security scans can detect vulnerabilities in both your application code and its dependent libraries as well as the final artifacts. For example, when you’re building container images, a security scan ensures that the images themselves don’t contain vulnerable packages. These scans often can’t be run until the final artifact is built, but they can be used to prevent its release to the registry/artifact repository.
Finally, on deployment to the development (or, at latest, testing) environment, automated functional, integration, and performance tests should be enacted as the final gates prior to a production deployment.
Any of these steps alone will help mitigate production problems. By using all of them together, the team will reduce their overall outage and error rates, and continue to increase customer satisfaction.