<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Bryan Lee</title>
    <description>The latest articles on DEV Community by Bryan Lee (@kickingthetv).</description>
    <link>https://dev.to/kickingthetv</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F275279%2Fcf8d9d54-7ab4-4d32-94f4-62867d8d3a78.JPG</url>
      <title>DEV Community: Bryan Lee</title>
      <link>https://dev.to/kickingthetv</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kickingthetv"/>
    <language>en</language>
    <item>
      <title>Master is the new Prod, Devs are the new Ops</title>
      <dc:creator>Bryan Lee</dc:creator>
      <pubDate>Thu, 02 Apr 2020 19:23:32 +0000</pubDate>
      <link>https://dev.to/kickingthetv/master-is-the-new-prod-devs-are-the-new-ops-176b</link>
      <guid>https://dev.to/kickingthetv/master-is-the-new-prod-devs-are-the-new-ops-176b</guid>
      <description>&lt;p&gt;&lt;strong&gt;Written by &lt;a href="https://twitter.com/borja_burgos"&gt;Borja Burgos&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lz9NIP1h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3660/1%2ARGbVXn8Ugr7OlnpQ7rnKGw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lz9NIP1h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3660/1%2ARGbVXn8Ugr7OlnpQ7rnKGw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Operational concerns of shipping software and keeping production up and running have been largely automated. Ultimately, even when things go wrong, modern-day monitoring and observability tools allow engineers to triage and fix nasty bugs faster than ever before. In part due to this, engineering teams and their budgets are shifting left. With the fear of downtime in the rearview mirror and operational challenges largely at bay, businesses are investing heavily in development to increase the quality and speed at which business value is delivered. The biggest bottleneck? Your failing master branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Ops Wayback Machine
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;The year is 2004. It’s time for deployment. You’re confident about the software you’ve written. You clear your mind, get one last sip of coffee, and get ready to deploy. Before you proceed, you open up terminals, many terminals, and tail every log file on every server that could possibly be affected. You have business metrics up and running on your second monitor. Next to it, there are infrastructure and application-level metrics. You hit the return key and proceed to deploy the latest release to a single server. Now you watch.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You scan rapidly across every terminal in your 19'’ CRT monitors to identify patterns and look for discrepancies: are there any errors in the logs? Has the conversion rate changed? What’s the load on the server? Was there a change in disk or network i/o? You wait a few minutes, if everything looks good, you proceed with a second server, else you roll back to the previous release as fast as humanly possible, hoping that’ll fix whatever it is that broke.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;While the excerpt above may sound ridiculous in this day and age, that’s how many deployments were done in the good old days of the internet after the &lt;a href="https://en.wikipedia.org/wiki/Dot-com_bubble"&gt;Dot-com bubble&lt;/a&gt;. Then came automation, hand-in-hand with the proliferation of “DevOps” and “microservices”. These practices were born from the ever-increasing speed and complexity of the applications being developed, a consequence of businesses’ competitive desires to deliver more value to customers, faster. Businesses could no longer afford to ship new features every 6 months; a slow release cycle represented an existential threat.&lt;/p&gt;

&lt;p&gt;But businesses weren’t always concerned with shipping new features at all costs. If anything, that wasn’t even a priority back in the early 2000s. The biggest fear of any company running software on the internet has always been downtime (ok, maybe the second biggest fear, with a security breach being at the top). And for this reason, among others, ops teams have always had sizable budgets for tech companies to sell into. After all, anything that minimizes downtime is likely cheaper than downtime itself.&lt;/p&gt;

&lt;p&gt;Fast-forward to today and you’ll see a &lt;a href="https://www.youtube.com/watch?v=hZ1Rb9hC4JY"&gt;whole new world&lt;/a&gt;. A world in which high-performing engineering organizations run as close to a fully-automated operation as possible. While every team does things a little bit differently, the sequence mimics the following: the moment a developer’s code is merged into master, a continuous integration (CI) job is triggered to build and test the application; upon success, a continuous delivery process is triggered to deploy the application in production; oftentimes this automated deployment is done in a minimal fashion, just a few nodes at a time or what’s known as a &lt;a href="https://martinfowler.com/bliki/CanaryRelease.html"&gt;canary deployment or release&lt;/a&gt;; in the meantime, the system, equipped with the knowledge of thousands of previous deployments, automatically performs multi-dimensional pattern matching to ensure no regressions have been introduced; at a certain degree of confidence, the system proceeds to automatically update the remaining nodes; and if there are any issues during deployment, rollbacks are automated, of course.&lt;/p&gt;

&lt;p&gt;Automation doesn’t necessarily stop with the deployment and release of an application. More and more operational tasks are being automated. It’s now possible, and not uncommon, to automate redundant tasks, like rotating security keys or fixing vulnerabilities the moment a patch is made available. And it’s been many years since the introduction of automatic scaling to handle spikes in CPU or memory utilization, to improve response time and user-experience, or even to take advantage of discounted preemptible/spot instances from IaaS providers.&lt;/p&gt;

&lt;p&gt;But, as anyone who has ever had to manage systems will be quick to tell you: &lt;a href="https://medium.com/scopedev/testing-in-the-cloud-native-era-41f63a0e101b"&gt;no amount of testing&lt;/a&gt; or automation will ever guarantee the desired availability, reliability, and durability of web applications. Fortunately enough, for those times when shit ultimately hits the fan (and it undoubtedly will), there is monitoring to help us find the root cause and quickly fix it. Modern-day monitoring tooling — nowadays being marketed as “observability” — offers fast multi-dimensional (metrics, logs, traces) analysis with which to quickly debug those pesky unknown-unknowns that affect production systems. Thanks to &lt;em&gt;observability&lt;/em&gt;, in just a handful of minutes, high-performing engineering organizations can turn “degraded performance”, and other problematic production regressions, to business as usual.&lt;/p&gt;

&lt;p&gt;The amount and complexity of the data that an engineer can rapidly process using a modern observability tool is truly astounding. In just a few keystrokes you can identify the specific combination of device id and version number that results in that troublesome backend exception, or which API endpoint is slowest for requests originating from Kentucky and why, or identify the root cause behind that seemingly random spike in memory consumption that occurs on the third Sunday of every month.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8J2HESlM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/7680/1%2ATvnYwCNVWqiXd1WkVWkNOQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8J2HESlM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/7680/1%2ATvnYwCNVWqiXd1WkVWkNOQ.gif" alt="Using an observability service (Datadog shown) to narrow down on problematic transactions."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While this level of automation and visibility isn’t achieved overnight, we’re unequivocally headed this way. And it is the right path forward, as demonstrated by the adoption of these tools and processes by the world’s most innovative tech companies. And so, with operational concerns at ease, what’s next? Business value! And what’s the biggest bottleneck we’re currently facing? Failing to keep master branch green (i.e. healthy/passing CI). Let me explain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping master green
&lt;/h2&gt;

&lt;p&gt;In terms of development, testing, and continuous integrations, the closest software engineering concept to “keeping production up” is to “keep master green”, which essentially means it’s deployable.&lt;/p&gt;

&lt;p&gt;This is something that’s likely to strike a chord with most software developers out there. It makes sense after all; if teams are going to cut releases from master, then master must be ready to run in production. Unlike years ago, when releases were cut far and few between, the adoption of automation (CI) and DevOps practices has resulted in development teams shipping new software at a much faster rate. So fast, that high performing engineering organizations are able to take this practice to its extreme, by automatically releasing any and every commit that gets merged to master — resulting in hundreds, sometimes even thousands, of production deployments on a daily basis. It’s quite impressive.&lt;/p&gt;

&lt;p&gt;But you might be left wondering, if you’re not continuously deploying master, and instead, you’re doing so once a week, or maybe once a month, why bother keeping master green? The short answer is: to increase developer productivity, to drive business value, and to decrease infrastructure costs. Even if you’re not shipping every commit to master, tracking down and rolling back a faulty change is a tedious and error-prone task, and more often than not requires human intervention. But it doesn’t stop there, a red (broken) master branch introduces the following problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A red master leads to delayed feature rollouts, which themselves lead to a delay or decrease in business value and potential monetary loss. Under the assumption that CI is functioning as expected, breaking master means that a faulty or buggy code commit needs to be detected, rolled back, and debugged. And for many companies, the cost of delaying the release of a new feature, or [security] patch, has a direct correlation to a decrease in revenue.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A broken (red) master branch has a cascading negative effect that also hurts developer productivity. In most engineering organizations, new features or bug fixes are likely to start as a branch of master. With developers branching off a broken master branch, they might experience local build and test failures or end up working on code that is later removed or modified when a commit is rolled back.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A broken/failing build is also money wasted. Yes, automated builds and tests are performed precisely to catch errors, many of which are impractical to catch any other way. But keep in mind that for every failed build, there’s at least another build (often more) that needs to run to ensure the rollback works. With engineering teams merging thousands of commits every day, build infrastructure costs can no longer be disregarded — at some organizations, CI infrastructure costs already exceed those of production infrastructure.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Convinced of the perils of a red master branch, you may ask yourself, what can I do to keep things green? There are many different strategies to reduce the number of times that master is broken, and when it breaks, how often it stays broken. From &lt;a href="https://cacm.acm.org/magazines/2016/7/204032-why-google-stores-billions-of-lines-of-code-in-a-single-repository/fulltext"&gt;Google’s presubmit infrastructure&lt;/a&gt; and &lt;a href="http://dev.chromium.org/developers/tree-sheriffs/sheriff-details-chromium-os"&gt;Chromium’s Sheriff&lt;/a&gt;, to &lt;a href="https://www.dropbox.com/s/w88eccvm2gthyfk/eurosys19uber.pdf?dl=0"&gt;Uber’s “evergreen” SubmitQueue&lt;/a&gt;, there’s no doubt that the world’s highest performing software organizations understand the benefits of keeping master green.&lt;/p&gt;

&lt;p&gt;For those that aren’t dealing with the scale of Google, Facebook, and others their size, the most widely established, and easily automated approach is to simply build and test branches before merging to master; easy, huh? Not really. While this often works for relatively simple, and monolithic codebases, this approach falls short when it comes to testing the microservice applications of today. Given the inherent distributed complexity of microservice applications, and the rate at which developers are changing the codebase, it is often impractical (i.e. too many builds that would take too long) to run every build, not to mention running the full integration and end-to-end test suites on every commit for every branch for every service in the system. Due to this limitation, branch builds are often limited in the scope of their testing. Unfortunately, after the changes are merged and the complete test suite is executed, it is common for this approach to result in test failures. And back to square one, master is red. So what can you do?&lt;/p&gt;

&lt;h2&gt;
  
  
  There’s been an outage in master
&lt;/h2&gt;

&lt;p&gt;At Undefined Labs, we spend a lot of our time meeting and interviewing software engineering teams of all sizes and maturity levels. These teams are developing systems and applications with varying degrees of complexity, from the simplest mobile applications to some of the largest distributed systems servicing millions of customers worldwide. We’ve seen an interesting new pattern emerge across several software engineering organizations. This pattern can be summarized as:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Treat a failure (i.e. automated CI build failure) in your master branch as you would treat a production outage.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is not only exciting but indicative of how engineering organizations continue shifting left, further and earlier into the development lifecycle.&lt;/p&gt;

&lt;p&gt;Most software teams already aim to “keep master green”, so what’s the difference? Traditionally, keeping master green has been on a best-effort basis, with master often failing over multiple builds across different commits, and days going by before returning to green.&lt;/p&gt;

&lt;p&gt;As engineering teams mature, it becomes even more urgent to fix master in a timely manner. Now, if master is red, it’s a development outage, and it needs to be addressed with the utmost urgency. It is this sense of urgency and responsibility that development teams have set upon themselves to get things back to normal as quickly as possible that is truly transformative. Given the business repercussions, associated costs, and productivity losses of a failing master branch, we expect broad adoption of this pattern across engineering teams of all sizes in the near future.&lt;/p&gt;

&lt;p&gt;Let’s take a look at some practical things you can do to keep master green:&lt;/p&gt;

&lt;h3&gt;
  
  
  If you can’t measure it, you can’t improve it
&lt;/h3&gt;

&lt;p&gt;This is true for many things, and it’s particularly true here. Before setting out on a journey to improve anything, one needs to be able to answer these questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;How long does it take us to fix master when it breaks?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How often do we break master?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These questions may sound familiar. Change master to “production” and these questions have well-known acronyms in the operational world. For anyone that has hung around an SRE (site reliability engineer) long enough, the terms MTTR and MTBF come to mind.&lt;/p&gt;

&lt;p&gt;MTTR or mean time to repair/resolution is a measure of maintainability. In the context of this article, MTTR answers the question, how long does it take to fix master? MTTR starts a running clock the moment a build fails and only stops when it’s fixed. As failures continue to occur, the MTTR is averaged over a period of time.&lt;/p&gt;

&lt;p&gt;MTBF, or mean time between failure, is a measure of reliability. In the context of this article, MTBF answers the question, how often do we break master? MTBF starts a running clock the moment a build goes from failing to passing and stops the next time a build fails. For example, for a team that breaks master once every week, the project’s MTBF will be approximately 7 days. As the project continues to experience failures, the MTBF is averaged over a period of time.&lt;/p&gt;

&lt;p&gt;Unfortunately, until now, there’s no easy nor automated way to monitor these metrics. Few CI providers/tools provide insights into related information, and even fewer provide an API with which to more accurately calculate these metrics over time.&lt;/p&gt;

&lt;p&gt;In Scope, we’re adding both MTTR and MTBF to our user’s service dashboards. That is, for every service for which Scope is configured, teams automatically see these values and trends tracked over time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5Dqbld26--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4600/1%2As1G3qmpuPdPnBW039sKNhA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5Dqbld26--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4600/1%2As1G3qmpuPdPnBW039sKNhA.png" alt="Scope Service Dashboard showing MTTR &amp;amp; MTBF for Development."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that you know what “normal” is, it’s time to figure out ways to improve MTTR and MTBF, in the never-ending quest to keep master evergreen.&lt;/p&gt;

&lt;h3&gt;
  
  
  MTTR — if you can’t debug it, you can’t fix it
&lt;/h3&gt;

&lt;p&gt;MTTR is a measure of maintainability: how quickly a failure can be fixed. To fix a software problem, software engineers need to understand what the system was doing at the time of the error. To do this in production, SREs and developers rely on monitoring and observability tools to provide them with the information they need in the form of metrics, logs, traces, and more to understand the problem at hand. Once the problem is well understood, implementing a fix is usually the easy part.&lt;/p&gt;

&lt;p&gt;However, the contrast between production and development is quite stark. In CI, developers lack the detailed and information-rich dashboards of production. In CI, developers get a “build failed” notification, followed by a dump of the logs of the build. Here is an example output from a top CI provider:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OMjiX0T6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/3976/1%2AaIMcqzY3Mqx8Fhi3Uz_FmA.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OMjiX0T6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/3976/1%2AaIMcqzY3Mqx8Fhi3Uz_FmA.gif" alt="Example failure output from a CI provider."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The problem is evident. Whereas operationally we have an endless amount of data, visibility, and infinite cardinality to probe the system and quickly understand complex production issues, when it comes to CI, developers are left in the dark, with nothing more than a log dump.&lt;/p&gt;

&lt;p&gt;To deal with this problem, before moving to Scope, the organizations we’ve encountered had either built a custom solution, frustrated by the lack of options in the market, or were trying to jerry-rig their production monitoring tools to work for CI without much success. There are key differences between production, a long-lived system handling transactions, and CI, short-lived and fast-changing environments running unit and integration tests, that make using production tooling impractical in CI.&lt;/p&gt;

&lt;p&gt;Teams interested in reducing the mean time to resolution in development to increase productivity, reduce CI costs, and increase business value, ought to look no further. Scope provides low-level insights into builds, with visibility into each and every test, across commits and PRs. With distributed traces, logs, exceptions, performance tracking and much, much more, teams using Scope are able to cut down their MTTR by more than 90%.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x9Q0JOsq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/4988/1%2ACO-6xjKJeHGtPxuEN3qKhg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x9Q0JOsq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/4988/1%2ACO-6xjKJeHGtPxuEN3qKhg.gif" alt="Debugging a flaky integration test using Scope."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  MTBF — a reliably flaky build
&lt;/h3&gt;

&lt;p&gt;MTBF is a measure of reliability: how often master breaks. After meeting with countless teams, and reviewing their CI builds, the verdict was clear: the leading cause for build failures in today’s software development teams is flakiness. If something is flaky, by definition, it cannot be reliable. As such, to increase a project’s MTBF the best thing any engineering organization can do today is to improve how flakiness is managed in a test suite and its codebase.&lt;/p&gt;

&lt;p&gt;Lots have been written about flakiness. Most recently, Bryan Lee, from Undefined Labs, has written a &lt;a href="https://medium.com/scopedev/how-can-we-peacefully-co-exist-with-flaky-tests-3c8f94fba166"&gt;great primer on flakiness&lt;/a&gt;; you should read it. In this post, Bryan lists a clear set of patterns to successfully handle flakiness:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Identification of flaky tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Critical workflow ignores flaky tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Timely flaky test alerts routed to the right team or individual&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Flaky tests are fixed fast&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A public report of the flaky tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dashboard to track progress&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Advanced: stability/reliability engine&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Advanced: quarantine workflow&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Due in part to the limited visibility into CI that most development teams have today, the way developers deal with flakiness is quite rudimentary. When a build fails, and if the developer suspects a flaky test is the reason behind it, they simply hit that retry button. Again and again, until the build passes, at which point they can proceed with their job. Not only is this wasteful, and costly, from an infrastructure perspective, it’s also highly inefficient and unproductive, as developers may be blocked while a build is taking place.&lt;/p&gt;

&lt;p&gt;Other solutions, less rudimentary, but still largely ineffective, require manual intervention from developers to investigate builds in order to identify flakes; however, these flakes are not properly tracked, and rarely dealt with, given the overhead experienced by teams without testing visibility. Without the means to quarantine or exclude known flaky tests from builds in master, teams with flaky tests are quick to give up on any ambition to keep master green. This, of course, carries grave business consequences as the team’s ability to innovate and ship new features is hindered by their broken builds.&lt;/p&gt;

&lt;p&gt;While this may be the case for most, there are those high-performing engineering organizations that have built internal tooling to address these challenges. Google, Microsoft, Netflix, Dropbox, among others, have built custom solutions to deal with flakiness and minimize the frequency at which master is red. The problem? These solutions are custom-built and not readily available for the rest of us.&lt;/p&gt;

&lt;p&gt;To address this glaring problem, we’re adding flaky test management features right into Scope. Starting with flaky test detection, automatic test retries, and a dashboard to track all flaky tests. In this dashboard, teams can track every flaky test, their flaky rate, the date and commit in which the test first exhibited flakiness, as well as the most recent flaky execution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wN4e_-Qr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2880/1%2Ax9NO29gqCp3Ztjv2l7wBcA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wN4e_-Qr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2880/1%2Ax9NO29gqCp3Ztjv2l7wBcA.png" alt="Flaky Test Management in Scope."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another one of the biggest struggles developers face when attempting to improve very flaky codebases and test suites are: where do I even begin? While all flaky tests may seem as good candidates for fixing, prioritization is key when dealing with flaky test suites. If you’re actively experiencing flakiness across hundreds of tests, it’ll be a futile attempt to try and fix them all. Instead, development teams should prioritize those tests that experience the highest rate of flakiness and are also the slowest to execute. Everything else being equal, these are the tests that have the most negative impact on your application and development processes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MHlBTALY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2624/1%2AfermnUHfe1e-x9j4SlTKcA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MHlBTALY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2624/1%2AfermnUHfe1e-x9j4SlTKcA.png" alt="Scatterplot of flaky tests — top-right quadrant contains the most negatively impactful flaky tests."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Our journey to the left
&lt;/h2&gt;

&lt;p&gt;At Undefined Labs we’re big believers in shifting left, and are always looking for innovative and transformative ways to improve application development. Treating master as production may still raise a few eye-brows in this day and age, but as shown in this article, there is clear business value in doing so: faster feature rollouts, increased developer productivity, and reduced costs. Similarly, once-reserved-for-production indicators like MTTR and MTBF, feel right at home as part of the development process, and provide development teams with the responsibility and accountability they need to more efficiently run their operations.&lt;/p&gt;

&lt;p&gt;When building Scope, we often ask ourselves: what happens when you apply the modern and sophisticated tooling that we have in production to problems in development? what happens when you close the feedback loop, and use everything we know about our applications running in production to make more informed decisions during the development process? The possibilities are endless, and quite exciting! If this sounds interesting, make sure to follow and stay tuned for more coming from us very soon!&lt;/p&gt;

&lt;p&gt;In the meantime, happy testing!&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CVIX17lN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2ADC09ClmlhKC-Q5aHUNyaiQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CVIX17lN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2ADC09ClmlhKC-Q5aHUNyaiQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The way we build applications has drastically changed with the rise of DevOps, Microservices, and Cloud Native — but the pinnacle of developer testing has remained static: run every test for every commit in CI and get no visibility whatsoever when things go wrong.&lt;/p&gt;

&lt;p&gt;We’re building &lt;a href="https://scope.dev/?utm_source=dev.to"&gt;Scope&lt;/a&gt; to give teams a modern testing platform that provides a solution to the biggest pains in testing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Debugging unit and integration tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Identifying and managing flaky tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reducing time spent testing by 50–90% (leading to a dramatic decrease in CI costs)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Detecting regressions before they reach production&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Keeping master green&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Working at Undefined Labs</title>
      <dc:creator>Bryan Lee</dc:creator>
      <pubDate>Wed, 26 Feb 2020 20:53:19 +0000</pubDate>
      <link>https://dev.to/kickingthetv/working-at-undefined-labs-51b5</link>
      <guid>https://dev.to/kickingthetv/working-at-undefined-labs-51b5</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;Originally written by &lt;a href="https://twitter.com/JaVidalPe" rel="noopener noreferrer"&gt;Javier Vidal&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ACrDjd5Twu73fozSvN5Yocw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ACrDjd5Twu73fozSvN5Yocw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are planning to invest or work with Undefined Labs, this blog post is for you. After almost a year working as a Frontend Engineer at Undefined Labs, I’m excited to summarize how it’s been one of my best experiences working for startups.&lt;/p&gt;

&lt;p&gt;This is my personal view of a promising startup inside the rich Spanish culture.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Team
&lt;/h2&gt;

&lt;p&gt;The team is led by &lt;a href="https://twitter.com/borja_burgos" rel="noopener noreferrer"&gt;@borjaburgos&lt;/a&gt; and &lt;a href="https://twitter.com/fernandomayo" rel="noopener noreferrer"&gt;@fernandomayo&lt;/a&gt;, very smart technologists with a clear vision about the future. &lt;a href="https://www.docker.com/blog/docker-acquires-tutum/" rel="noopener noreferrer"&gt;They already sold their previous startup to Docker&lt;/a&gt;, Tutum, and since then, they have been working on the same market, so few people in the world know the Docker environment better than these two. They are always looking at the industry, obsessed about converting ideas into business. And now they are trying to repeat the success of Tutum. Believe me, they know what they are doing.&lt;/p&gt;

&lt;p&gt;We are only eight engineers, all talented senior developers. Not having any junior or mid-level developers is a questionable decision, but what I can say is that this is working for us. We try to build as fast as possible. Fewer people means less time communicating and organizing, so we can move and pivot quickly.&lt;/p&gt;

&lt;p&gt;Our strength is our differences. Except for the frontend team, who are three javascript developers, the rest of our engineers code in different languages: .NET, Python, Java, Go, and Swift. This diversity in programming languages is required by the products we are building, but also a decision we made to support the multilingual systems of most engineering organizations. Since the majority of our developers work alone on their stack, it requires a high degree of responsibility and ownership. And we don’t fall into the trap of having what-is-the-best language or IDE arguments. Brie Wolfson described it as Tupertine.&lt;/p&gt;



&lt;p&gt;Sometimes, having only one person resolving technical problems in each language can be painful, but it gives us a considerable perspective when dealing with a strategic decision about products.&lt;/p&gt;

&lt;p&gt;And all of this was possible because of the hiring process. Fernando, the CTO, has tried very hard to find the best talent in Spain. He has a clear vision of the kinds of players that would aspire to form a perfect team. It should fit perfectly for the way we do technology.&lt;/p&gt;

&lt;h2&gt;
  
  
  Software development
&lt;/h2&gt;

&lt;p&gt;Choosing technology is a vital decision, so we do it strategically. As we are building things from scratch, we have the freedom to choose whatever we want, with no dependencies or debt. But we also know that there are &lt;a href="https://en.wikipedia.org/wiki/There_are_known_knowns" rel="noopener noreferrer"&gt;unknown unknowns&lt;/a&gt; that could slow us down, so we always try to use already proven technology. Or frontend is written in React, while our backend is in Python. We use Apollo for communications, so GraphQL is our daily language.&lt;/p&gt;

&lt;p&gt;While it’s easy to get overeager in our choices around technology, the team always grounds these decisions by holding the end-user experience as the leading priority. We always make decisions with the user in mind, careful not to add complexity that isn’t justified by the value delivered to the user. Keep it simple is our mantra. Unjustified complexity is forbidden.&lt;/p&gt;

&lt;p&gt;The benefit of building developer tools is that we are always our first users. Dogfooding is a widespread practice in the industry, and we embrace it. It increases the sense of ownership, as you feel the wins and pains of the product directly. It’s a common occurrence to see a colleague sharing a new dogfooding case in Slack, followed by questions and suggestions on how we could improve the experience.&lt;/p&gt;

&lt;p&gt;Another exciting prospect of building developer tools is the opportunity to impact how you and others in your profession will work. Few professions are responsible for building many of the tools they will use on a day to day basis. It can be invigorating having such a tight feedback loop, where every iteration of the product immediately enhances the way my coworkers and I work.&lt;/p&gt;

&lt;p&gt;Dream big, everything is possible. Fernando has taught — by doing — that no matter how far you are from the Bay Area, you can still out-compete technology incumbents. An inspirational ideal that gives us the confidence to compete in a demanding market.&lt;/p&gt;

&lt;h2&gt;
  
  
  The market
&lt;/h2&gt;

&lt;p&gt;We are developing tools for developers. The space for tooling is vast, so we are focusing on the CI/CD phases. Some of the hot topics at the office are observability, testing, and building.&lt;/p&gt;

&lt;p&gt;If you want to know more about the products we have already released, check out &lt;a href="https://undefinedlabs.com" rel="noopener noreferrer"&gt;https://undefinedlabs.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the beginning, when I entered Undefined Labs, I was skeptical about the market. I thought it was all about IDEs and Plugins, which I find very boring. But the founders’ motivation surprised me. And after a couple of months, I could understand why this market has so much potential.&lt;/p&gt;

&lt;p&gt;We are in a new promising market. As digital products evolve, so does the software behind it. The systems that power these products are getting more complex every day, so companies are spending more and more money developing, shipping, and maintaining these complex systems. On the other hand, the DevOps culture is growing fast and more and more developers are getting into the operations space. By addressing the needs of developers, your technology can reach millions of end-users.&lt;/p&gt;

&lt;p&gt;Many of the existing solutions at our disposal are brilliant, built by the best minds in the industry. You can learn a lot by just looking inside these new products and features. To have the opportunity to compete with these minds — and do it successfully — is a very humbling and fulfilling experience.&lt;/p&gt;

&lt;p&gt;Because the market is getting bigger, a lot of companies from small startups to big fortune 500s are entering, and it can be exciting being a part of this chaotic, fast-paced ecosystem. We usually watch the more significant industry conferences together like &lt;a href="https://www.youtube.com/watch?v=9EoNqyxtSRM" rel="noopener noreferrer"&gt;GitHub Universe&lt;/a&gt; and &lt;a href="https://www.youtube.com/watch?v=7-31KgImGgU" rel="noopener noreferrer"&gt;AWS re:Invent&lt;/a&gt;, and pay close attention to how the announcements may affect us, either immediately or down the road. It seems commonplace during these conferences that a big company announces an acquisition or the release of a new feature that makes the latest trendy tool in the market useless. The frenetic pace can seem crazy, but it gives you a sense of urgency. This adrenaline keeps us focused.&lt;/p&gt;

&lt;p&gt;Finally, our customers are smart people. Often, they are the innovators within their larger company. They know exactly what they need, so the feedback they give is invaluable. Also, we speak the same language as our customers, so &lt;a href="https://www.youtube.com/watch?v=mAiNdU1go1A&amp;amp;t=2791s" rel="noopener noreferrer"&gt;the GAP between what we are building and why we are doing it&lt;/a&gt; is drastically reduced.&lt;/p&gt;

&lt;h2&gt;
  
  
  The environment
&lt;/h2&gt;

&lt;p&gt;At the time I’m writing this, there are ten of us in the company. Two of us are in the USA, handling meetings and looking for customers and partners. The developer team is in Madrid, the capital of Spain.&lt;/p&gt;

&lt;p&gt;VC investors from Silicon Valley back the company. The difference in the average salary between Silicon Valley and Madrid is significant, which allows us to be very money-efficient while still offering the best compensation in Spain. This allows us to enjoy and live in one of the best countries in the world.&lt;/p&gt;

&lt;p&gt;We also enjoy one of the best locations in Madrid. The office is located in the city center, near good restaurants and public transportation.&lt;/p&gt;

&lt;p&gt;Madrid is a vibrant city. Like other capitals, it is full of young people from all around Spain striving to leave their mark. Also, it receives influences from people coming from Latin America. This makes Madrid a beautiful place to sample Spanish culture.&lt;/p&gt;

&lt;p&gt;We have the best weather in Europe, with clear skies and a temperate climate. The summer is hot, and the winter is cold, but it never snows. If you want to go to the beach, you can take a 3h train to Valencia or Barcelona. If you prefer the mountains, you have ski resorts less than 2h by car.&lt;/p&gt;

&lt;p&gt;We enjoy the city together. Some of the team members have lunch in the office, and others go out to have lunch daily. But altogether we go out on Friday for our team lunch.&lt;/p&gt;

&lt;p&gt;I’m looking forward to seeing what new products or ideas we bring to life. If you are also interested, follow us on &lt;a href="https://twitter.com/undefinedlabs" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, and keep an eye out for an opportunity of joining us at &lt;a href="https://undefinedlabs.com/about-us/" rel="noopener noreferrer"&gt;https://undefinedlabs.com/about-us/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2AKCWB-TJGKvqLu_Od.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2AKCWB-TJGKvqLu_Od.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Testing is a core competency to build great software. But testing has failed to keep up with the fundamental shift in how we build applications. Scope gives engineering teams production-level visibility on &lt;strong&gt;every test&lt;/strong&gt; for &lt;strong&gt;every app&lt;/strong&gt; — spanning mobile, monoliths, and microservices.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Your journey to better applications through better testing &lt;a href="https://scope.dev/?utm_source=dev.to"&gt;starts with Scope&lt;/a&gt;.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Testing Strategies for Modern Web Applications
</title>
      <dc:creator>Bryan Lee</dc:creator>
      <pubDate>Fri, 21 Feb 2020 20:28:39 +0000</pubDate>
      <link>https://dev.to/kickingthetv/testing-strategies-for-modern-web-applications-16a5</link>
      <guid>https://dev.to/kickingthetv/testing-strategies-for-modern-web-applications-16a5</guid>
      <description>&lt;p&gt;&lt;strong&gt;Written by &lt;a href="https://twitter.com/soyguijarro"&gt;Ramón Guijarro&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--U3qSY_lZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AEFwDH-ld8g1iwNkAKcQKtw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--U3qSY_lZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AEFwDH-ld8g1iwNkAKcQKtw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why frontend testing matters
&lt;/h2&gt;

&lt;p&gt;It’s no secret that websites are nowadays more complex than ever. The last decade has seen a big shift on the web: as user expectations have changed with the rise of the smartphone, we’ve effectively transitioned from web pages mostly based on HTML and CSS to web applications driven by tons of JavaScript code. Unlike traditional document-based websites, current webapps have rich interfaces that support heavy user interaction, &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data"&gt;async data fetching for partial content updates&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage"&gt;data caching&lt;/a&gt; and even &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Offline_Service_workers"&gt;offline usage&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If only because of this complexity, we should be testing our web applications to make sure that they behave as expected. As developers, we want to &lt;a href="https://medium.com/scopedev/testing-in-the-cloud-native-era-41f63a0e101b"&gt;increase our confidence in the software we write&lt;/a&gt;, and that’s what tests provide. But making sure our webapps work is even more important if we think about the fact that they’re the entry point to our products. It can even be argued that your webapp &lt;strong&gt;is&lt;/strong&gt; your product since it’s the thing your users are actually using. When users think about your product, they think about your UI, and all they care about is accomplishing tasks through it. So how do we go about testing it?&lt;/p&gt;

&lt;h2&gt;
  
  
  Interpreting the test pyramid
&lt;/h2&gt;

&lt;p&gt;From a conceptual standpoint, besides picking specific testing tools and technologies, one of the first questions that arise is at which level we need to be testing and how many tests of each kind we should be writing. The classic &lt;a href="https://martinfowler.com/bliki/TestPyramid.html"&gt;test pyramid&lt;/a&gt; quickly comes to mind as an answer, but let’s see how it applies to modern component-based web applications — the kind built with libraries like &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt; or &lt;a href="https://vuejs.org/"&gt;Vue&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--k-AC6c9H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/0%2A43POxwpBWejylBAb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k-AC6c9H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/0%2A43POxwpBWejylBAb.png" alt="Traditional testing pyramid, not practical for today’s applications (source: [https://martinfowler.com/articles/practical-test-pyramid.html](https://martinfowler.com/articles/practical-test-pyramid.html))"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The thin line between unit and integration
&lt;/h3&gt;

&lt;p&gt;Following the test pyramid will get us writing lots of unit tests, as those constitute its base. In our webapp context, they’re usually interpreted as testing a single component completely isolated from the rest of the tree, mocking out all of its dependencies and subcomponents. However, this kind of test doesn’t very accurately reflect how people will actually use our app.&lt;/p&gt;

&lt;p&gt;That last statement is especially true for those who believe that a test that writes to the DOM or receives user input cannot be considered a unit test but an integration test, because there is &lt;a href="https://en.wikipedia.org/wiki/Input/output"&gt;I/O&lt;/a&gt; involved or &lt;a href="https://en.wikipedia.org/wiki/Side_effect_%28computer_science%29"&gt;side effects&lt;/a&gt; in general. But while you can call it an integration test all you want, it’s probably not the kind of integration test the pyramid is referring to, as it is not noticeably more expensive to run. And hence the advice of not writing as many of them arguably doesn’t apply.&lt;/p&gt;

&lt;p&gt;The technologies used for unit and integration tests of components are in fact usually the same — typically, a test runner like &lt;a href="https://jestjs.io/"&gt;Jest&lt;/a&gt; that uses an emulated &lt;a href="https://github.com/jsdom/jsdom"&gt;browser-like environment&lt;/a&gt; under the hood — so sometimes the distinction between them only comes down to who you’re asking.&lt;/p&gt;

&lt;h3&gt;
  
  
  End to end tests are fundamentally different
&lt;/h3&gt;

&lt;p&gt;On the other hand, end to end tests at the top of the pyramid much better reflect how users interact with the app. For web applications, these rely on tools that run your tests in an actual web browser, instead of an emulated DOM like the ones we just mentioned. This fact makes them conceptually different and forces you to test from the end user’s point of view. You can think of them as manual tests that are automated.&lt;/p&gt;

&lt;p&gt;Historically, end to end tests have been slow, prone to flakiness, and hard to debug. However recent testing tools and frameworks, like &lt;a href="https://www.cypress.io/"&gt;Cypress&lt;/a&gt; or &lt;a href="https://pptr.dev/"&gt;Puppeteer&lt;/a&gt;, are improving all of these aspects to the point where some people are even advocating to invert the test pyramid altogether — something generally considered an antipattern — on the basis that we ought to be testing &lt;strong&gt;exactly&lt;/strong&gt; what the user is experiencing.&lt;/p&gt;

&lt;p&gt;I personally wouldn’t go as far as inverting the test pyramid, but what is definitely becoming clearer nowadays is that our webapps could benefit from raising the level at which you’d typically write tests; moving it above single isolated components. Let’s see why.&lt;/p&gt;

&lt;h2&gt;
  
  
  The case for higher-level tests
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why classic unit testing doesn’t cut it
&lt;/h3&gt;

&lt;p&gt;Testing our components in isolation and mocking everything around them is not only a poor reflection of their real-world usage — hence not providing that much value in terms of confidence — but it almost inevitably leads to coupling our tests with their implementation details. This can get particularly bad with libraries such as &lt;a href="https://airbnb.io/enzyme/"&gt;Enzyme&lt;/a&gt;, which lets developers select nodes based on component names, arbitrarily modify their internal state, and skip rendering of all children altogether with &lt;a href="https://airbnb.io/enzyme/docs/api/shallow.html"&gt;shallow rendering&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Under this approach, it’s common that making almost any change to a component will break its tests, even if its API stays the same. If end users or consumers of the component would not notice changes, why should tests fail? Also, fixing the tests will sometimes force you to basically rewrite them from scratch. This means that those tests will actually hinder your ability to refactor and will never be able to catch regressions. So what’s their value then?&lt;/p&gt;

&lt;h3&gt;
  
  
  Integration tests to the rescue
&lt;/h3&gt;

&lt;p&gt;A lot of components in our applications are meant to be working in conjunction with others to form a larger component, a certain screen, or a feature. Features are what users care about and how we should measure confidence in our app. So instead of testing the individual components at the leaves of the tree — what would be usually referred to as unit testing them — look for the higher-level components that constitute true units in terms of features and test these without mocking its children. You will cover the real use case, the tests will take less effort to write and maintain, and you will be able to refactor all the subcomponents without breaking multiple tests.&lt;/p&gt;

&lt;p&gt;To ensure that you’re testing the same way your users would use the app, it’s a good idea to rely on tools like &lt;a href="https://testing-library.com/"&gt;Testing Library&lt;/a&gt;, since it gives you utilities to query for nodes similarly to how users would find them. And because its queries are based on&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques"&gt; ARIA roles&lt;/a&gt;, testing with it will force you to improve the accessibility of your app as a bonus.&lt;/p&gt;

&lt;p&gt;This approach allows us to write tests that closely imitate real user interactions and are resilient to changes, just as end to end tests would do, which is exactly what we want. But they have the benefit of running much faster, since they’re not using a real browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  The role of end to end tests
&lt;/h3&gt;

&lt;p&gt;So if we can get a similar level of confidence with integration tests, what are end to end tests good for then? An excellent use for them in our context is &lt;a href="https://en.wikipedia.org/wiki/Smoke_testing_%28software%29"&gt;smoke testing&lt;/a&gt;. Build processes of modern webapps have many moving pieces and involve sophisticated tools like &lt;a href="https://babeljs.io/"&gt;transpilers&lt;/a&gt;, &lt;a href="https://webpack.js.org/"&gt;bundlers&lt;/a&gt; or &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Polyfill"&gt;polyfills&lt;/a&gt;, with non-trivial configurations that are often different for development and production. That means that your production build could fail whilst the development one is working fine. So a simple test that opens your webapp in a browser and checks that it loads actually gives you quite some value for little investment.&lt;/p&gt;

&lt;p&gt;Another use case for end to end tests is to cover the happy path of your most important user flows, exercising real APIs instead of having network requests mocked — either production ones, or in testing or staging environments. These tests might seem redundant, as well as more prone to exhibit flakiness since they hit real backend services, all on top of being slower. That’s why it’s advisable not to have a ton of them and maybe only run them before a deployment or as a nightly process. But they’re still relevant since they emulate the usage of your app in the most realistic way of all automated types of testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making responsible use of mocking
&lt;/h2&gt;

&lt;p&gt;We’ve discussed an approach to tests based on emulated DOM technology that tries to get as close as possible to the benefits of end to end browser-based tests, and we’ve seen how too much mocking goes against our goals in this area. But you will still need and want to mock some things in your non-browser tests. So let’s briefly discuss what to mock and how.&lt;/p&gt;

&lt;h3&gt;
  
  
  Global mechanisms
&lt;/h3&gt;

&lt;p&gt;You usually won’t want to render your whole app, but at the same time, you’ll want whatever global mechanisms you have in place to be available in your tests. This way, you can confidently rely on those in your code knowing that your tests won’t fail. For example, if you’re using React you will probably have some top-level &lt;a href="https://reactjs.org/docs/context.html#contextprovider"&gt;context providers&lt;/a&gt;; it can be a good idea to write mocked versions of them and mount them in all your tests.&lt;/p&gt;

&lt;p&gt;In a similar vein, you will want some functions used across your app to always be mocked. A typical example is date formatters: if you ever change the way you format dates in your app, you don’t want to have to modify assertions in every test under the sun. You can write unit tests for those functions to check that the formatting works as expected, and then have global mocks return a constant to ignore these in the rest of your tests. Testing frameworks like Jest allow you to &lt;a href="https://jestjs.io/docs/en/manual-mocks"&gt;define global mocks once&lt;/a&gt; for your own modules or third party dependencies. And you can always restore the original implementation for a particular test if you need to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Network requests
&lt;/h3&gt;

&lt;p&gt;You will also want to mock network requests in your integration tests to ensure that they run fast and are not flaky. You can do that in exactly the same way, as long as all your requests eventually go through the same module. The key is to always encapsulate core functionality like this in reusable modules and consistently rely on them. This will not only make testing easier but improve the architecture of your application, avoiding duplication and reducing the risk of diverging implementations and duplicated errors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Specific components
&lt;/h3&gt;

&lt;p&gt;Finally, there are legitimate reasons to mock components in a particular test, besides top-level or global ones. For example, you might want to have actual unit tests for some core components. That’s fine, but instead of using techniques like &lt;a href="https://airbnb.io/enzyme/docs/api/shallow.html"&gt;shallow rendering&lt;/a&gt; to completely prevent rendering all child components — which might unknowingly hide errors from you — explicitly mock only what you need. Again, Jest makes it easy with &lt;a href="https://jestjs.io/docs/en/mock-functions#using-a-mock-function"&gt;mock functions&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Going beyond tests with static analysis
&lt;/h2&gt;

&lt;p&gt;The easiest tests to maintain are the ones that you don’t need to write. Static analysis tools can automatically catch a lot of bugs for us, effectively saving us from writing certain kinds of tests. These tests tend to be repetitive and cumbersome, so help is even more welcomed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prevent common bugs
&lt;/h3&gt;

&lt;p&gt;A common source of bugs in modern web applications is the incorrect use of components by other consumers, like forgetting to set some mandatory property, or using a mismatching value for it — e.g., a string when a number is expected. This can be addressed with mechanisms like &lt;a href="https://reactjs.org/docs/typechecking-with-proptypes.html"&gt;PropTypes in React&lt;/a&gt;, but these only warn you in runtime during development, if the particular component happens to be mounted, and via the browser console — so you can miss the warning anyway. A better alternative is to declare types for properties and state of components with tools like &lt;a href="http://typescriptlang.org/"&gt;TypeScript&lt;/a&gt; or &lt;a href="https://flow.org/"&gt;Flow&lt;/a&gt;, that perform static checking of the types to ensure that these issues are all caught at build time. They will also support you while making changes in your components and allow you to refactor with greater confidence.&lt;/p&gt;

&lt;p&gt;Another relevant source of bugs in JavaScript applications is null pointer errors, such as &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cant_access_property"&gt;cannot read property &lt;em&gt;x&lt;/em&gt; of undefined&lt;/a&gt; or &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Not_a_function"&gt;&lt;em&gt;x&lt;/em&gt; is not a function&lt;/a&gt;. Type checkers can also help prevent these errors, as they will for example statically check if a particular key that your code is trying to access actually exists in an object. They do this based on the &lt;a href="https://www.typescriptlang.org/docs/handbook/interfaces.html"&gt;object shapes you declare&lt;/a&gt;, and their value is multiplied thanks to &lt;a href="https://www.typescriptlang.org/docs/handbook/type-inference.html"&gt;type inference&lt;/a&gt; — so you don’t need to explicitly declare types all the time. Support for &lt;a href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#nullable-types"&gt;nullable types&lt;/a&gt; completes the deal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Define safe data models
&lt;/h3&gt;

&lt;p&gt;We can leverage this ability to declare our own types to make our applications safer in some other ways. For example, we can write factory functions that receive data fetched from our backend APIs and process and sanitize it, returning objects safe to use in our components — what we’d call &lt;a href="https://en.wikipedia.org/wiki/Data_model"&gt;models&lt;/a&gt;. And we can define custom types for the shape of these models and export them to use as prop types of our components. This can help us gracefully handle mistakes in backend responses so that our UI doesn’t break, while still being able to log custom errors to a monitoring service like &lt;a href="http://sentry.io/"&gt;Sentry&lt;/a&gt; to be aware of the issues.&lt;/p&gt;

&lt;p&gt;We can go even further down this road by using tools that automatically generate type definitions for our API responses. This allows us to use the generated types directly in our components without any extra work, providing a solid safety layer. Since &lt;a href="https://graphql.org/"&gt;GraphQL&lt;/a&gt; has a type system at its core, APIs based on it are particularly well-suited for this. Tools like &lt;a href="https://graphql-code-generator.com/"&gt;GraphQL Code Generator&lt;/a&gt; can generate TypeScript and Flow types from a GraphQL schema, and next-generation systems like &lt;a href="https://www.prisma.io/with-graphql"&gt;Prisma&lt;/a&gt; go one step further and generate them from the database itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  In conclusion
&lt;/h2&gt;

&lt;p&gt;Writing tests for our web frontend code is important because it’s the part of our product that our users will be directly interacting with. We want to simulate that interaction as faithfully as possible, so browser-based tests would be the way to go, but they’re too slow to use at scale. However, we can get pretty close with non-browser based tests if we write them at a high enough level, use selectors based on accessibility roles, and make sensible use of mocking. Adding a static type checker to the mix will further increase our confidence and prevent some common bugs.&lt;/p&gt;

&lt;p&gt;So go ahead and write some tests for your webapp. Your users will unknowingly thank you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1GgsbC9t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/0%2AsuyXMYjgxQ315pyQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1GgsbC9t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/0%2AsuyXMYjgxQ315pyQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Testing is a core competency to build great software. But testing has failed to keep up with the fundamental shift in how we build applications. Scope gives engineering teams production-level visibility on &lt;strong&gt;every test&lt;/strong&gt; for &lt;strong&gt;every app&lt;/strong&gt; — spanning mobile, monoliths, and microservices.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Your journey to better applications through better testing &lt;a href="https://scope.dev/?utm_source=dev.to"&gt;starts with Scope&lt;/a&gt;.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Introduction to Profiling and Optimizing SQL Queries for Software Engineers</title>
      <dc:creator>Bryan Lee</dc:creator>
      <pubDate>Mon, 03 Feb 2020 20:58:37 +0000</pubDate>
      <link>https://dev.to/kickingthetv/introduction-to-profiling-and-optimizing-sql-queries-for-software-engineers-4dpo</link>
      <guid>https://dev.to/kickingthetv/introduction-to-profiling-and-optimizing-sql-queries-for-software-engineers-4dpo</guid>
      <description>&lt;p&gt;&lt;strong&gt;Written by &lt;a href="https://github.com/AdrianLC"&gt;Adrián López Calvo&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XiPQvlGT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/5180/1%2A8jwkhnvlkvOIVoDZU21VNg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XiPQvlGT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/5180/1%2A8jwkhnvlkvOIVoDZU21VNg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nowadays it is quite uncommon to have dedicated &lt;a href="https://en.wikipedia.org/wiki/Database_administrator"&gt;&lt;em&gt;Database Admins&lt;/em&gt; (DBAs)&lt;/a&gt; on application development teams. Whether it’s the adoption of microservices architectures, cloud, or DevOps processes that is to blame, more and more development teams are now responsible for their databases. Now more than ever, solid database skills are indispensable on your path to becoming a proficient programmer.&lt;/p&gt;

&lt;p&gt;Response-time is a key indicator of the performance of any application,. Database optimization can be one of the fastest ways to give a speed boost to your application, website or API. Learning the basics of profiling and optimizing SQL queries is actually not as hard as it might seem, and you should not feel intimidated by it. In this post, I will explain the general steps I followed with a real-world scenario I ran into recently while working on &lt;a href="http://scope.dev"&gt;Scope&lt;/a&gt;. Armed with the skills described in this post, you’ll be optimizing your own database queries in no time!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: our main database is PostgreSQL and most of our backend stack is written in Python. While the concepts I cover should also be applicable to MySQL or other SQL databases, please bear in mind that all practical examples in this article will be for PostgreSQL. There will also be some recommendations or examples specific to Python.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding slow queries to profile
&lt;/h2&gt;

&lt;p&gt;First things first, before jumping to profile any random query, we need to find a good candidate database query to profile. Slow queries are usually the best ones to start with, but profiling can be used for much more than speeding up slow queries. If there are queries that appear to be behaving erratically, or otherwise returning unexpected data, profiling will help you determine the reason for these abnormal behaviors.&lt;/p&gt;

&lt;p&gt;There are many ways to find slow queries. From client-side instrumentation to server-side configuration, through automatic application-level monitoring or through server logs. Each has its pros and cons. Let’s take a look at some of our options:&lt;/p&gt;

&lt;h2&gt;
  
  
  Database Slow Query Log
&lt;/h2&gt;

&lt;p&gt;Most SQL databases provide a &lt;a href="https://wiki.postgresql.org/wiki/Logging_Difficult_Queries"&gt;Slow Query Log&lt;/a&gt;, a log where the database server registers all queries that exceed a given threshold of execution time. With it enabled and configured, the database will automatically output warning messages and query information for all slow queries.&lt;/p&gt;

&lt;p&gt;There is no prescriptive way to access these logs, and most of the usual suspects will work here. You could use &lt;em&gt;grep&lt;/em&gt;, for example. But you can also get more sophisticated, and have a simple script that parses the contents of the file and notifies you via Slack.&lt;/p&gt;

&lt;p&gt;The Slow Query Log method, while somewhat rudimentary, does have an advantage. With this method you’re getting the information directly from the source of truth, thus eliminating the need for any third-party system or component. The downside? You may experience a &lt;a href="http://blog.symedia.pl/2016/10/performance-impact-general-slow-query-log.html"&gt;small performance hit&lt;/a&gt;, originating from the database server having to time every query. Furthermore, keep in mind that enabling this feature does require admin privileges in the database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Middleware and Application Logs
&lt;/h2&gt;

&lt;p&gt;Other alternatives are application-side middlewares and application-level logging. There are many ready-made solutions for this approach. For example, a popular choice for Python and Django is the &lt;a href="https://github.com/jazzband/django-debug-toolbar"&gt;&lt;em&gt;django-debug-toolbar&lt;/em&gt;&lt;/a&gt;. Alternatively, there also exists the option to enable &lt;a href="https://docs.djangoproject.com/en/3.0/topics/logging/#django-db-backends"&gt;logging directly from the ORM&lt;/a&gt;. But even simpler than this is to just add logging to the code interacting directly with the database to print or log the latency of each query. You can even mimic the behavior of the Slow Query Log, and only log the queries exceeding a given threshold of execution time.&lt;/p&gt;

&lt;p&gt;Since these are client-side solutions, latencies include networking times. This can be advantageous. Oftentimes a slow query isn’t due to the database taking too long to resolve the given query, but instead, the slowness is due to the size of the payload. With large payloads, the bottleneck may actually be on the data transfer between the database and the application server. This is more likely to occur while using an ORM, as it may default to fetching all the columns from the database table, even when they’re all not required.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uG_9GQWP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/0%2A2x79sH2fxOAh72YV" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uG_9GQWP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/0%2A2x79sH2fxOAh72YV" alt="Screenshot from *django-debug-toolbar, *which adds a debugging panel to your website displaying all the SQL queries with latency information. Really useful when you need to profile queries on a specific page from your website!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  APM and Distributed Tracing
&lt;/h2&gt;

&lt;p&gt;Last on this list is APM (Application Performance Management) and Distributed Tracing. While they aren’t one and the same, for the purpose of this article, and the value they provide in profiling database queries, I’ve decided to put them in the same category.&lt;/p&gt;

&lt;p&gt;The way most APMs work is through a library or agent that is installed alongside your application and automatically instruments its client libraries, like http, grpc, sql, etc. to monitor and log transactions and queries.&lt;/p&gt;

&lt;p&gt;If you are up to speed with the latest advancements in &lt;a href="https://opentelemetry.io/"&gt;observability and distributed tracing&lt;/a&gt;, and already have instrumentation for your application’s database queries, there are open-source distributed trace visualization tools, like &lt;a href="https://www.jaegertracing.io/"&gt;Jaeger&lt;/a&gt;, that can help you easily identify slow queries.&lt;/p&gt;

&lt;p&gt;Let’s see an example of a request containing one such slow database query:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SiF9_Q61--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2940/0%2AIg60ywTcW8bs1oU1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SiF9_Q61--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2940/0%2AIg60ywTcW8bs1oU1" alt="Searching recent traces by duration and noticing the latency breakdown by service. In this screenshot from Datadog, the green area is time running our backend code whilst purple is time spent on resolving PostgreSQL queries."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WvHQyx1r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3200/0%2A8fJf2Ao8u9B6PU6-" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WvHQyx1r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3200/0%2A8fJf2Ao8u9B6PU6-" alt="Detail screen of a trace for a slow request with an SQL query spanning over 10 seconds. The flame graph shows that &amp;gt;90% of the request time was spent on a single query."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, with APM or tracing data, and a good service or tool for visualization, finding slow database queries to profile is actually quite easy.&lt;/p&gt;

&lt;p&gt;In any case, no matter which method you choose, as long as you have a way to time your queries, you’re likely to find a slow query that is worth optimizing!&lt;/p&gt;

&lt;h2&gt;
  
  
  Profiling a SQL Query
&lt;/h2&gt;

&lt;p&gt;Now that we’ve identified our slow query, the next step is profiling. Profiling, in the context of a SQL database generally means, &lt;a href="https://www.postgresql.org/docs/current/sql-explain.html"&gt;&lt;em&gt;explaining&lt;/em&gt;&lt;/a&gt; our query. The &lt;em&gt;EXPLAIN&lt;/em&gt; command outputs details from the &lt;a href="https://www.postgresql.org/docs/current/planner-optimizer.html"&gt;&lt;em&gt;query planner&lt;/em&gt;&lt;/a&gt;, and gives us additional information and visibility to better understand what the database is actually doing to resolve the query.&lt;/p&gt;

&lt;p&gt;You can execute this command directly from a command line shell in your database, but if you would rather avoid terminals, most database clients with a GUI also include &lt;em&gt;EXPLAIN&lt;/em&gt; capabilities. Following along with the earlier example of our slow query, let’s now profile it. To do this, we simply need to pre-append the original slow query with &lt;em&gt;EXPLAIN ANALYZE&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Attention! It’s important to understand the difference between &lt;em&gt;EXPLAIN&lt;/em&gt; and &lt;em&gt;EXPLAIN&lt;/em&gt; &lt;em&gt;ANALYZE&lt;/em&gt;. While &lt;em&gt;EXPLAIN&lt;/em&gt; will only give details about the plan, without executing the query, &lt;em&gt;EXPLAIN&lt;/em&gt; &lt;em&gt;ANALYZE&lt;/em&gt; actually executes the query, providing you with exact timing information under the current server load. But you need to be very careful with this, particularly on production databases. Not only could it impact performance, you could potentially modify or delete data if you are profiling an &lt;em&gt;UPDATE&lt;/em&gt; or &lt;em&gt;DELETE&lt;/em&gt; operation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xDE7qvhC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2688/1%2AghHXc44RHPN2_ticWCZmFg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xDE7qvhC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2688/1%2AghHXc44RHPN2_ticWCZmFg.png" alt="Public gist [here](https://gist.github.com/AdrianLC/eaac58f4429d41deaa16a5529539bd34#file-sql-explain-sql)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After running the EXPLAIN ANALYZE query on a PostgreSQL shell, you’ll get an output similar to this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z-YudX3Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3398/1%2AnhpoTo7lBBhoAFDPAFGkjQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z-YudX3Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3398/1%2AnhpoTo7lBBhoAFDPAFGkjQ.png" alt="Public gist [here](https://gist.github.com/AdrianLC/eaac58f4429d41deaa16a5529539bd34#file-sql-explain-txt)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the output for this is quite cryptic! What does all of this mean? PostgreSQL’s &lt;em&gt;EXPLAIN&lt;/em&gt; is very thorough, it really shows us everything the database knows and plans to do with our queries. As such, it is to be expected that we will not understand most things. While explaining all of the output is beyond the scope of this article, we can still learn quite a few things from it.&lt;/p&gt;

&lt;p&gt;The first tip is that, if we want to think about the steps the database would follow with our query &lt;em&gt;sequentially,&lt;/em&gt; it helps to read from the bottom upwards. This is because the output is like a break-down of operations, so the last ones are actually the first step for each parallelized block of the execution.&lt;/p&gt;

&lt;p&gt;Also, if you are obtaining your &lt;em&gt;EXPLAIN&lt;/em&gt; output from the shell, I highly recommend using an &lt;em&gt;EXPLAIN&lt;/em&gt; visualization tool, I personally like &lt;a href="https://explain.depesz.com/"&gt;this one&lt;/a&gt;. It provides syntax highlighting and table formatting to help with legibility. You can also easily share the report with other teammates! &lt;a href="https://explain.depesz.com/s/uaan"&gt;Here’s a link to an example query&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3NAe-85N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3200/0%2AI_VqbN9x3_nAiyiA" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3NAe-85N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3200/0%2AI_VqbN9x3_nAiyiA" alt="PostgreSQL EXPLAIN visualization [website](https://explain.depesz.com/s/uaan)."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://use-the-index-luke.com/sql/explain-plan/postgresql/operations"&gt;This site&lt;/a&gt; is also a great source to learn about what most of the operations on SQL plans are. But for this practical example, we’ll just be taking a look at two operations, &lt;em&gt;Seq Scan&lt;/em&gt; and &lt;em&gt;Index Scan&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Seq Scan&lt;/em&gt; is a full search on the table with the given conditions. These are usually bad because they will become slower as the data in your tables grow.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Index Scan&lt;/em&gt; is using one of the indexes that exist on your table. These are usually better since the database has a shortcut to the rows that match the conditions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most often optimizing your queries will be a matter of replacing a &lt;em&gt;Seq Scan&lt;/em&gt; that is too big with an &lt;em&gt;Index Scan&lt;/em&gt; by creating an index on the columns that are involved in the conditions. Thought you should know that adding indexes to your tables is not always appropriate. When adding a new index we are trading off writing performance for query speed, due to the database having to update the index when writing to the table. So you should try to have the lowest number of indexes that you can afford and only create the ones that you find unavoidable.&lt;/p&gt;

&lt;p&gt;As we continue to debug our slow query, we can see in the visualization above that a single step in the plan is the culprit for most of the time spent resolving the query. So we should focus on these lines:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KJYVtWqg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2876/1%2A__brbXGG2K9yjUx5krZU2Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KJYVtWqg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2876/1%2A__brbXGG2K9yjUx5krZU2Q.png" alt="Public gist [here](https://gist.github.com/AdrianLC/eaac58f4429d41deaa16a5529539bd34#file-sql-explain-snippet-txt)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This step in the plan is finding rows in the table &lt;em&gt;scope_testexecution&lt;/em&gt; with a column &lt;em&gt;agent_id&lt;/em&gt; that matches the primary key on the table scope_agent &lt;strong&gt;through&lt;/strong&gt; the index called &lt;em&gt;scope_teste_agent_i_f352da_idx&lt;/em&gt;. It is resolving a foreign key from one table to another. Unfortunately, it is already using an index, so that is not the issue for this specific query.&lt;/p&gt;

&lt;p&gt;You can check what kind of index is being used on PostgreSQL. To do that we use the command &lt;em&gt;\d+ scope_testexecution&lt;/em&gt;, resulting in:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Indexes:

…

“scope_teste_agent_i_f352da_idx” btree (agent_id, fqn)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is not how we usually index foreign keys. The database is using a compound index on 2 columns, &lt;em&gt;agent_id&lt;/em&gt; and &lt;em&gt;fqn&lt;/em&gt; and we do not have a single column index on &lt;em&gt;agent_id&lt;/em&gt;!&lt;/p&gt;

&lt;p&gt;Furthermore, the &lt;em&gt;fqn&lt;/em&gt; column is a varchar(1000) with very high cardinality (a lot of different values per agent) and the &lt;em&gt;EXPLAIN&lt;/em&gt; is actually telling us that this step involves 83967 &lt;em&gt;heap fetches.&lt;/em&gt; On the &lt;a href="https://www.postgresql.org/docs/current/indexes-index-only-scans.html"&gt;&lt;em&gt;Index Only Scan&lt;/em&gt;&lt;/a&gt; operation, PostgreSQL scans through the index but it stills needs access to the table storage. This area in storage where the table is stored is called the &lt;em&gt;heap&lt;/em&gt;, so the number of &lt;em&gt;heap fetches&lt;/em&gt; is the number of read operations from the table. In summary, the query is requiring a lot of I/O access to fetch these values from the table, and that is probably the cause for low performance.&lt;/p&gt;

&lt;p&gt;We could decrease the size of the data that PostgreSQL needs to resolve this condition if we had a single column index on agent_id. Having a dedicated index for each foreign key is the standard set up, usually autogenerated by ORMs or framework tooling, but in this case, it’s missing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing an optimization
&lt;/h2&gt;

&lt;p&gt;Now that we have an idea of what to change, we can experiment and see if the query performs better. It is better to do this on a testing or staging database when possible since it will involve altering our indexes and there’s always the chance we’re wrong, potentially affecting our production database.&lt;/p&gt;

&lt;p&gt;It’s likely that you have a mechanism in place to change your database schema; these are usually called &lt;a href="https://en.wikipedia.org/wiki/Schema_migration"&gt;database or schema migrations&lt;/a&gt;. Schema changes should involve code reviews, as well as be part of a continuous integration process to be tested and validated.&lt;/p&gt;

&lt;p&gt;While this isn’t the best way to debug, unfortunately, we cannot test this kind of change on a development machine, since we need data resembling the actual size of the production database. With this in mind, a trick I’ve used to get past this limitation is to make our changes within a transaction itself. PostgreSQL allows transactional changes to indexes and table structures, which comes in handy for our use case:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XuQkJcuz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2660/1%2AfsUR7FQKwbp4koO6J8GDdw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XuQkJcuz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2660/1%2AfsUR7FQKwbp4koO6J8GDdw.png" alt="Public gist [here](https://gist.github.com/AdrianLC/eaac58f4429d41deaa16a5529539bd34#file-optimization-create-index-sql)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this change, we can actually test a different plan for our query without affecting how it currently works for other transactions, and if we were to be wrong, nothing is affected; we can simply undo the index through a quick &lt;em&gt;ROLLBACK&lt;/em&gt;!&lt;/p&gt;

&lt;p&gt;Let’s try this out. The next step is to profile the query again, and to use our visualizer to see the report and compare to the previous results we obtained:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oaahwcD1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3200/0%2AdkJLzAD6wbzEu05y" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oaahwcD1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3200/0%2AdkJLzAD6wbzEu05y" alt="Visualization of the *explain* after our new index optimization. Public link [here](https://explain.depesz.com/s/Qxq6)."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the screenshot above, the same query now takes just over a second. Remember it initially took over 10 seconds! Our optimization, creating a separate index for &lt;em&gt;agent_id&lt;/em&gt;, has been successful!&lt;/p&gt;

&lt;p&gt;You may be curious as to why we did not have the standard index for the foreign key on the &lt;em&gt;agent_id&lt;/em&gt; column. It turns out that in previous iterations of our product, the table &lt;em&gt;scope_testexecution&lt;/em&gt; was being used on several queries that aggregated results. Because of this, we had more queries with &lt;em&gt;GROUP BY&lt;/em&gt; on &lt;em&gt;agent_id, fqn&lt;/em&gt; than we did directly accessing it. That index was necessary at the time. Fortunately, things have changed since then and we can now revert back to using the standard index.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Optimization of SQL queries may be daunting at first, but it is fascinating and within every developer’s reach. Hopefully, this post has helped demonstrate that there are easy optimizations you can do today, such as proposing the addition of a missing index.&lt;/p&gt;

&lt;p&gt;But even if you’re just getting started with databases, you can already help your team by identifying slow queries and providing the output of &lt;em&gt;EXPLAIN&lt;/em&gt; to help debug issues — they will surely appreciate it!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Scope can help you identify slow SQL queries in testing before they ever make it to production!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---vVwxzQr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/0%2AU0pSX6D8v1FM2pgq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---vVwxzQr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/0%2AU0pSX6D8v1FM2pgq.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Testing is a core competency to build great software. But testing has failed to keep up with the fundamental shift in how we build applications. Scope gives engineering teams production-level visibility on &lt;strong&gt;every test&lt;/strong&gt; for &lt;strong&gt;every app&lt;/strong&gt; — spanning mobile, monoliths, and microservices.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Your journey to better applications through better testing &lt;a href="https://scope.dev/?utm_source=dev.to"&gt;starts with Scope&lt;/a&gt;.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>sql</category>
      <category>database</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Limitations of xUnit in Cloud Native Testing</title>
      <dc:creator>Bryan Lee</dc:creator>
      <pubDate>Mon, 13 Jan 2020 17:05:27 +0000</pubDate>
      <link>https://dev.to/kickingthetv/limitations-of-xunit-in-cloud-native-testing-4jmc</link>
      <guid>https://dev.to/kickingthetv/limitations-of-xunit-in-cloud-native-testing-4jmc</guid>
      <description>&lt;p&gt;&lt;strong&gt;Written by &lt;a href="https://twitter.com/drodriguezhdez"&gt;Daniel Rodriguez&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kJPwdknh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/5180/1%2AM_6VvAuVl1c8l_4jc8cFIQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kJPwdknh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/5180/1%2AM_6VvAuVl1c8l_4jc8cFIQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;xUnit is the name used for the collection of test frameworks loosely based on the original Smalltalk Test Framework, proposed by Kent Beck in 1998, and later popularized by &lt;a href="https://junit.org/junit5/"&gt;JUnit&lt;/a&gt;. While it has become common nowadays, the idea of systematically checking an application’s correctness in code (e.g. a test) was quite novel at the time.&lt;/p&gt;

&lt;p&gt;Another revolutionary idea in those days was the concept of Continuous Integration: every developer merging code on a recurring basis to ensure everything was working as expected. And to help them check for correctness and identify potential regressions, teams leveraged these testing frameworks to test their applications during the continuous integration flow.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But if you stop to think about it, we are talking about practices that were introduced somewhere between 20 and 25 years ago!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;With regard to CI, there is no shortage of options nowadays, from free and open-source solutions to commercial SaaS and on-premise products. And with the adoption and proliferation of Docker and containers, it is really easy for developers to run their custom tech stacks on any CI provider. But at the end of the day, CI services are still predominantly dumb runtimes, where a developer can define what to run, but the CI doesn’t actually understand what is being executed. And it is only due to “&lt;em&gt;standardization”&lt;/em&gt; around the xUnit XML format that some CI tools are able to parse and report on test data.&lt;/p&gt;

&lt;h3&gt;
  
  
  xUnit has failed to evolve for the cloud native world
&lt;/h3&gt;

&lt;p&gt;But in the era of cloud native applications, innovation in testing has been stuck in a seemingly alternate universe where XML is the pinnacle of testing innovation. There are sophisticated engineering organizations running thousands of tests at planet scale, and they’re still generating XML reports and uploading them to their CI or reviewing them with a text editor.&lt;/p&gt;

&lt;p&gt;Furthermore, there is no XML schema standard to represent this report – every vendor has freedom in how they define their schema, which may have varying levels of compatibility with the most popular CI’s. All of this only to see a summary of your passing and failed tests. It makes no sense.&lt;/p&gt;

&lt;p&gt;While this way of testing was sufficient when we only had unit tests, it falls predictably short with current software engineering needs that emphasize integration with other services. Suites of integration tests are now a must-have to reduce the risk of deploying bugs into production. As a matter of fact, &lt;a href="https://blog.usejournal.com/lean-testing-or-why-unit-tests-are-worse-than-you-think-b6500139a009"&gt;Lean Testing&lt;/a&gt;, a modern testing philosophy, questions the validity of the traditional &lt;a href="https://martinfowler.com/bliki/TestPyramid.html"&gt;testing pyramid&lt;/a&gt; and instead advocates for more integration tests, and fewer unit tests — resulting in the “Testing Trophy”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D8HX166c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2APW0wMKOY4DamEsK6mRYxew.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D8HX166c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2APW0wMKOY4DamEsK6mRYxew.png" alt="Testing trophy by Kent C. Dodds"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Testing trophy by Kent C. Dodds.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  xUnit only provides superficial insights
&lt;/h3&gt;

&lt;p&gt;XML test reports are insufficient to understand what is happening under the hood. Yes, the reports show when a test has failed, but developers won’t know the type of test (unit? integration? benchmark? end-to-end? other?) and if it is an integration test, to which services it is integrating to, or which versions are running, or in which environment. Is a test failing due to a code change or a config change? Or is it failing because of a dependency? With today’s XML reports, we simply cannot figure out the answer to these and many other questions. And consequently, developers end up spending more time trying to understand the problem than fixing it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Observability in testing: a must-have in a cloud native world
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://medium.com/scopedev/what-happened-to-tests-9af43b1bc2be"&gt;Leveraging observability patterns in our integration tests&lt;/a&gt;, we cannot only start providing reliable information about what services are touched by our tests, but we could also &lt;a href="https://medium.com/scopedev/testing-in-the-cloud-native-era-41f63a0e101b"&gt;start executing controlled tests in production&lt;/a&gt;. Modern production observability tools give developers the visibility they need to understand complex systems, but why wait until production to actually understand how our applications are behaving? Given a choice, every developer would much rather catch a bug before it ships to production, &lt;a href="https://medium.com/scopedev/testing-in-the-cloud-native-era-41f63a0e101b"&gt;where the cost is always much greater.&lt;/a&gt; Yet, developers lack the tools to efficiently do this with today’s modern applications.&lt;/p&gt;

&lt;p&gt;It’s now clear that with the proliferation of containers, serverless, Kubernetes, and cloud native, both the way we develop and the applications we develop have changed. But developers are struggling to properly test and debug these new applications with the current tools at their disposal. Testing and testing frameworks need to evolve to understand better what is happening in our tests. As is, current methods for debugging integration tests are unreliable, time-consuming, requires a high level of expertise, and don’t always lead to resolution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--y4Vwd8pe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AxYv0oMQNQikyluNvN4EBig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y4Vwd8pe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AxYv0oMQNQikyluNvN4EBig.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Testing is a core competency to build great software. But testing has failed to keep up with the fundamental shift in how we build applications. Scope gives engineering teams production-level visibility on &lt;strong&gt;every test&lt;/strong&gt; for &lt;strong&gt;every app&lt;/strong&gt; — spanning mobile, monoliths, and microservices.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Your journey to better engineering through better testing &lt;a href="https://scope.dev?utm_source=dev.to"&gt;starts with Scope&lt;/a&gt;.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>observability</category>
      <category>cloudnative</category>
    </item>
    <item>
      <title>A Modern Approach to Manual Testing</title>
      <dc:creator>Bryan Lee</dc:creator>
      <pubDate>Tue, 17 Dec 2019 22:05:40 +0000</pubDate>
      <link>https://dev.to/kickingthetv/a-modern-approach-to-manual-testing-273h</link>
      <guid>https://dev.to/kickingthetv/a-modern-approach-to-manual-testing-273h</guid>
      <description>&lt;p&gt;&lt;strong&gt;Written by &lt;a href="https://twitter.com/JotaEscribe"&gt;Juan Fernandez&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TdWK3vVE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4442/1%2A1fYbPC5ENyGl8ata91fBqg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TdWK3vVE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4442/1%2A1fYbPC5ENyGl8ata91fBqg.png" alt="Bridging the gap between Dev and QA."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting the stage
&lt;/h2&gt;

&lt;p&gt;We’ve all seen it, the bigger an organization gets, the more difficult it becomes to have meaningful and efficient communication between teams. This is particularly apparent when incentives are misaligned. Often, development teams are incentivized to build as much as possible in the shortest time possible. On the other hand, QA teams are incentivized to reduce the inherent risk in a codebase/application to an acceptable degree. The problem is obvious: whereas development teams optimize for speed, QA teams optimize for correctness. This misalignment of incentives results in frustration and burnout between and within these teams.&lt;/p&gt;

&lt;p&gt;This inherent friction between development and QA teams is most acute when finding a bug. At that time, QA professionals prioritize having said bug fixed. In contrast, developers get conflicted between shipping a new feature in a timely manner, or delaying it in exchange for a bugfix, which could take five minutes or five weeks to implement, and has no clear ROI.&lt;/p&gt;

&lt;p&gt;While an argument could be made that the right culture could [potentially] prevent this, our experience having talked to hundreds of organizations is that, more often than not, teams with competing incentives behave this way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The state of affairs
&lt;/h2&gt;

&lt;p&gt;Let’s take a look at what happens today, at any given organization, when QA finds a bug in an application. For the sake of this post, let’s pretend this is an e-commerce application.&lt;/p&gt;

&lt;p&gt;Step 1: QA contacts the developer or development team &lt;em&gt;supposedly&lt;/em&gt; responsible for the fix. They do this on a communications tool like Slack, or by creating an issue on a tracker like Jira.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5vwS3F2I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2560/0%2AF1_UBK6DnbDyKXgX" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5vwS3F2I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2560/0%2AF1_UBK6DnbDyKXgX" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 2: The QA professional then proceeds to talk with the “Checkout Dev Team.”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NVo5yohK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2576/0%2A_dAtWesgd9GRasEs" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NVo5yohK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2576/0%2A_dAtWesgd9GRasEs" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 3: QA is left confounded and unsure of how to proceed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lJsQ4M-m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/0%2AA5442di6_E4SY6Sv" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lJsQ4M-m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/0%2AA5442di6_E4SY6Sv" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What would follow is a back and forth between the QA and development teams struggling to reproduce the issue across different development environments, while sharing screenshots and recordings, and trying to fish for the appropriate logs of the apparent issue at hand. All of this while banging their heads against the wall, because the problems only show up under seemingly random circumstances that cannot be determined. On top of it all, it’s likely that after days with this issue lingering and bouncing around JIRA, not one development team confidently claimed ownership of the fault, let alone is working on a fix.&lt;/p&gt;

&lt;p&gt;This sequence of events happens even in the most dedicated and collaborative organizations with robust processes in place. The problem is the depth and complexity of the software applications that we’re developing these days. Correctly identifying what team, microservice, configuration, or transaction is at fault for any given issue, and quickly debugging it to find a proper solution is one of the most difficult challenges in modern-day software engineering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can we do better?
&lt;/h2&gt;

&lt;p&gt;Of course, we can! But before I show you how, let me introduce myself: I’m Juan, and I work as a Software Engineer at Undefined Labs. We work on developer tools, and we believe it’s time to fundamentally change the way testing and development teams collaborate, and significantly improve how organizations test their applications. In this post, I’d like to show you the power of &lt;a href="http://scope.dev?utm_source=dev.to"&gt;Scope&lt;/a&gt; for manual web-based testing.&lt;/p&gt;

&lt;p&gt;To explain our approach better, let’s revisit our previous scenario, this time with Scope:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oqTb9f4x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2548/0%2A6PhD_-dpP1-uMl4e" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oqTb9f4x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2548/0%2A6PhD_-dpP1-uMl4e" alt="QA can provide a deep link to the test report for Developers to analyze."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;QA can provide a deep link to the test report for Developers to analyze.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YIntMUa2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3200/0%2A1ll9QywOvi1CR8BF" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YIntMUa2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3200/0%2A1ll9QywOvi1CR8BF" alt="*All reports in Scope include a trace showing the transaction recorded during the execution of the test.*"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;All reports in Scope include a trace showing the transaction recorded during the execution of the test.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The verdict:&lt;/em&gt; screenshots and logs, while handy, are hardly sufficient to deal with most of the issues a development team will face any given day in today’s modern applications. With Scope, we’re making it trivially easy for QA teams to provide their development teams with the rich and in-depth visibility they need to fix any manual test and any bug. Let’s see how.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Scope for Chrome
&lt;/h2&gt;

&lt;p&gt;When we set out to build Scope, we mainly set out to solve problems for developers. And while developers are ultimately responsible for fixing a bug, we saw in Scope the potential to build a bridge between QA and development teams. Scope for Chrome is our first step towards building this bridge.&lt;/p&gt;

&lt;p&gt;Whereas many of the frameworks, SDKs, and agents for testing we’ve built to date cater to developers, it was clear early on that the needs and tools of a QA are quite different. With Scope for Chrome, we wanted to build the easiest way for anyone to create meaningful manual browser tests. As such, the only requirement to use Scope for Chrome is to (1) install our browser extension, and (2) know how to use a web browser.&lt;/p&gt;

&lt;p&gt;It really is that easy:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SU3wRgmz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://g.recordit.co/428vzoGSrA.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SU3wRgmz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://g.recordit.co/428vzoGSrA.gif" alt="Performing a manual test using Scope for Chrome"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After anyone records a manual test using Scope for Chrome, a report is generated automatically. This test report includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;User actions like clicks or keyboard strokes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;HTTP requests with their headers and payloads.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Responses by the backend and even database queries being fired as a result of the request.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Console logs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Exceptions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, every manual test comes with a detailed report, including everything a developer would want to see when trying to debug any given regression. And best of all, it eliminates the need to try to reproduce the issue at hand. There is also no “what browser were you using?” or “what user were you logged in as?” Everything you need to understand the problem is in a single pane of glass. And it is easier than ever to know what team is best suited for the fix, or what service is at fault.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;Simply put: when a user clicks on the “Start Recording” button, &lt;a href="https://home.undefinedlabs.com/goto/scope-for-chrome"&gt;Scope For Chrome&lt;/a&gt; starts listening and recording everything happening within your current tab.&lt;/p&gt;

&lt;p&gt;In more detail, to accomplish this, our effort is threefold:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Listen to and record user events such as mouse clicks, keyboard strokes, and exceptions happening within the tab.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Monkey patch &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest"&gt;XHR&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch"&gt;fetch&lt;/a&gt; by injecting code to the tab under test. Each request creates a new span (“individual unit of work” as per &lt;a href="https://opentracing.io/docs/overview/spans/"&gt;OpenTracing terminology&lt;/a&gt;) that then propagates to the backend.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Listen to &lt;em&gt;main_frame&lt;/em&gt; requests (a document that is loaded for a top-level frame). This is the first request that your browser does when going to a new page. For this, we use the &lt;a href="https://developer.chrome.com/extensions/webRequest"&gt;webRequest extension API&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, this is just a glimpse at what Scope for Chrome does. None of it would have been possible without the work behind our &lt;a href="https://docs.scope.dev/docs/javascript-installation"&gt;javascript agent&lt;/a&gt;, our other agents (&lt;a href="https://docs.scope.dev/docs/python-installation"&gt;Python&lt;/a&gt;, &lt;a href="https://docs.scope.dev/docs/ios-installation"&gt;iOS&lt;/a&gt;, &lt;a href="https://docs.scope.dev/docs/dotnet-installation"&gt;.NET&lt;/a&gt;, &lt;a href="https://docs.scope.dev/docs/java-installation"&gt;Java&lt;/a&gt;, &lt;a href="https://docs.scope.dev/docs/go-installation"&gt;Golang&lt;/a&gt;), our backend capable of ingesting and processing test data and distributed traces, and our purpose-built web UI to display tests in an interactive and structured way.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P.S. Check out the Technical Addendum below for more information.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;p&gt;With the ever-increasing complexity of modern software comes bigger, more sophisticated software teams. In the same way teams work to improve the interfaces between distributed services, we should improve how we collaborate and communicate between teams. We believe &lt;a href="https://home.undefinedlabs.com/goto/scope-for-chrome"&gt;Scope for Chrome&lt;/a&gt; can help alleviate the most frustrating problems associated with the lack of visibility in manual testing, and help bridge the gap between QA and Dev.&lt;/p&gt;

&lt;p&gt;You can learn more about &lt;a href="https://home.undefinedlabs.com/goto/scope-for-chrome"&gt;Scope for Chrome here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Addendum: technical challenges faced while building Scope for Chrome.
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Monkey patching is hard
&lt;/h3&gt;

&lt;p&gt;For those that haven’t dwell into the world of monkey patching, it is &lt;a href="https://www.audero.it/blog/2016/12/05/monkey-patching-javascript/"&gt;a technique to add, modify, or suppress the default behavior of a piece of code at runtime without changing its original source code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example, consider a class with a method &lt;strong&gt;get_value&lt;/strong&gt;. Suppose this method does a database query when being called. Imagine you are now unit testing your class: you may not want to do an actual database query, so you dynamically replace &lt;strong&gt;get_value&lt;/strong&gt; by a stub that returns some mock data.&lt;/p&gt;

&lt;p&gt;This can be extended to other uses. For example, in a web application, you might want to substitute &lt;strong&gt;console.log&lt;/strong&gt; by a function that not only logs a message but also adds the date at which the function was called.&lt;/p&gt;

&lt;p&gt;Here’s an example:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const log = console.log

console.log = function() {

  log.apply(console, [new Date().toISOString(), ...arguments])

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Basic monkey patching of &lt;strong&gt;window.fetch&lt;/strong&gt; is simple (note that this is just an example and is not prepared to be production code):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const oldFetch = window.fetch

window.fetch = (...args) =&amp;gt; {

   // do something here
   return oldFetch(...args)

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Things get more interesting when you want to do async stuff in there, like communicating with a &lt;a href="https://developer.chrome.com/extensions/background_pages"&gt;background script&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const oldFetch = window.fetch

 window.fetch = (...args) =&amp;gt;

  new Promise(resolve =&amp;gt; {

   asyncCommWithBackground().then(newRequestInfo =&amp;gt; {

    const newFetchArgs = [...args, ...newRequestInfo]

    resolve(oldFetch(...newFetchArgs))

   })

  })
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This pattern is quite powerful. But with great power comes great responsibility. By monkey patching, we are slowing every request in the active tab down by however long &lt;em&gt;asyncCommunicationWithBackground&lt;/em&gt; takes to resolve.&lt;/p&gt;

&lt;p&gt;And here’s an example of doing &lt;em&gt;something&lt;/em&gt; with the result of the fetch:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;window.fetch = (...args) =&amp;gt;

 new Promise(resolve =&amp;gt; {

  asyncCommWithBackground().then(newRequestInfo =&amp;gt; {

   const newFetchArgs = [...args, ...newRequestInfo]

   resolve(oldFetch(...newFetchArgs)).then(fetchResult =&amp;gt; {

    // do something with fetchResult

    return fetchResult 

   })

  })

 })

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can simplify the code a bit with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function"&gt;async/await&lt;/a&gt;, but you have to be careful. You probably want to know if your fetch has failed, for which you would use try/catch. But if you do that, you would stop exceptions from propagating to the consumer, which is a scenario you’d want to avoid. The most important thing to remember here is: monkey patching done right should be transparent.&lt;/p&gt;

&lt;p&gt;To do something with the response data, like adding it to the span as tag or metadata, you need to be careful with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Response/clone"&gt;cloning&lt;/a&gt; your response before, as it is a stream and can only be consumed once.&lt;/p&gt;

&lt;p&gt;If you want to dig a bit deeper into this pattern, we have set up a repository with a &lt;a href="https://github.com/juan-fernandez/monkeypatch-example-scope"&gt;small project of a functioning chrome extension&lt;/a&gt; that delays all your &lt;em&gt;fetch&lt;/em&gt; requests. The pattern is highlighted &lt;a href="https://github.com/juan-fernandez/monkeypatch-example-scope/blob/master/background.js#L16-L26"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;An alternative to this solution is to use the &lt;a href="https://developer.chrome.com/extensions/webRequest"&gt;webRequest API&lt;/a&gt; with hooks like &lt;em&gt;onBeforeSendHeaders&lt;/em&gt;, but as of now, this API does not allow the capture of response payloads, which was a requirement for Scope.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Monkey patching in a browser is even harder
&lt;/h3&gt;

&lt;p&gt;As it turns out, if you want to affect the &lt;em&gt;window&lt;/em&gt; variable of the tab, which we need for monkey patching, a &lt;a href="https://developer.chrome.com/extensions/content_scripts"&gt;content script&lt;/a&gt; is not enough. You need to execute code like the one shown in &lt;a href="https://github.com/juan-fernandez/monkeypatch-example-scope/blob/master/background.js#L3-L9"&gt;here&lt;/a&gt;. This means handling your code as string. There are some alternatives like using &lt;em&gt;function.toString()&lt;/em&gt; and &lt;a href="https://github.com/kentcdodds/babel-plugin-macros"&gt;babel macros&lt;/a&gt; to evaluate variables in build time, but the extra complexity defeats the purpose, as your monkey patched functions should not be big anyway.&lt;/p&gt;

&lt;p&gt;Utility functions that your monkey patched functions need, like random number generation or parsing of data need to be available in the tab, which means again handling your code as strings to inject it. The tab shares no execution environment with your background, and while it would be possible to asynchronously request and wait for results, this would mean slowing down all your requests.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Sending responses asynchronously
&lt;/h3&gt;

&lt;p&gt;Your content scripts and injected code will communicate with your background through &lt;a href="https://developer.chrome.com/extensions/messaging"&gt;message passing&lt;/a&gt;. At some point, the responses might require some async operation. To leave the communication channel open you need to return &lt;em&gt;true&lt;/em&gt; before calling &lt;em&gt;sendResponse&lt;/em&gt;. More of this pattern &lt;a href="https://riptutorial.com/google-chrome-extension/example/7152/send-a-response-asynchronously"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Bundling your extension
&lt;/h3&gt;

&lt;p&gt;The window that appears when you click on your browser’s extension icon, also known as a popup, will grow sooner than you expect and a state management library will come in really handy.&lt;/p&gt;

&lt;p&gt;To avoid the hassle of managing a webpack configuration with all the perks (like hot reloading), there are some excellent starter projects and tools for this specific purpose.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/samuelsimoes"&gt;
        samuelsimoes
      &lt;/a&gt; / &lt;a href="https://github.com/samuelsimoes/chrome-extension-webpack-boilerplate"&gt;
        chrome-extension-webpack-boilerplate
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A basic foundation boilerplate for rich Chrome Extensions using Webpack to help you write modular and modern Javascript code, load CSS easily and automatic reload the browser on code changes.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
Chrome Extension Webpack Boilerplate&lt;/h1&gt;
&lt;p&gt;A basic foundation boilerplate for rich Chrome Extensions using &lt;a href="https://webpack.github.io/" rel="nofollow"&gt;Webpack&lt;/a&gt; to help you write modular and modern Javascript code, load CSS easily and &lt;a href="https://webpack.github.io/docs/webpack-dev-server.html#automatic-refresh" rel="nofollow"&gt;automatic reload the browser on code changes&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
Developing a new extension&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;I'll assume that you already read the &lt;a href="https://webpack.js.org" rel="nofollow"&gt;Webpack docs&lt;/a&gt; and the &lt;a href="https://developer.chrome.com/extensions/getstarted" rel="nofollow"&gt;Chrome Extension&lt;/a&gt; docs.&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check if your Node.js version is &amp;gt;= 6.&lt;/li&gt;
&lt;li&gt;Clone the repository.&lt;/li&gt;
&lt;li&gt;Install &lt;a href="https://yarnpkg.com/lang/en/docs/install/" rel="nofollow"&gt;yarn&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;yarn&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Change the package's name and description on &lt;code&gt;package.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Change the name of your extension on &lt;code&gt;src/manifest.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;yarn run start&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Load your extension on Chrome following
&lt;ol&gt;
&lt;li&gt;Access &lt;code&gt;chrome://extensions/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Check &lt;code&gt;Developer mode&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click on &lt;code&gt;Load unpacked extension&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Select the &lt;code&gt;build&lt;/code&gt; folder.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Have fun.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
Structure&lt;/h2&gt;
&lt;p&gt;All your extension's development code must be placed in &lt;code&gt;src&lt;/code&gt; folder, including the extension manifest.&lt;/p&gt;
&lt;p&gt;The boilerplate is already prepared to have a popup, a options page and a background page. You can easily customize…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/samuelsimoes/chrome-extension-webpack-boilerplate"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;




&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/xpl"&gt;
        xpl
      &lt;/a&gt; / &lt;a href="https://github.com/xpl/crx-hotreload"&gt;
        crx-hotreload
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Chrome Extension Hot Reloader
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
Chrome Extension Hot Reloader&lt;/h1&gt;
&lt;p&gt;Watches for file changes in your extension's directory. When a change is detected, it reloads the extension and refreshes the active tab (to re-trigger the updated scripts).&lt;/p&gt;
&lt;p&gt;Here's &lt;a href="https://60devs.com/hot-reloading-for-chrome-extensions.html" rel="nofollow"&gt;a blog post explaining it&lt;/a&gt; (thanks to &lt;a href="https://habrahabr.ru/users/KingOfNothing/" rel="nofollow"&gt;KingOfNothing&lt;/a&gt; for the translation).&lt;/p&gt;
&lt;h2&gt;
Features&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Works by checking timestamps of files&lt;/li&gt;
&lt;li&gt;Supports nested directories&lt;/li&gt;
&lt;li&gt;Automatically disables itself in production&lt;/li&gt;
&lt;li&gt;And it's just a &lt;a href="https://github.com/xpl/crx-hotreload/blob/master/hot-reload.js"&gt;50 lines of code&lt;/a&gt;!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
How To Use&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drop &lt;a href="https://github.com/xpl/crx-hotreload/blob/master/hot-reload.js"&gt;&lt;code&gt;hot-reload.js&lt;/code&gt;&lt;/a&gt; to your extension's directory.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Put the following into your &lt;code&gt;manifest.json&lt;/code&gt; file:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight highlight-source-json"&gt;&lt;pre&gt;    &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;background&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;: { &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;scripts&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;: [&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;hot-reload.js&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;] }&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Also, you can simply clone this repository and use it as a boilerplate for your extension.&lt;/p&gt;
&lt;h2&gt;
Installing From NPM&lt;/h2&gt;
&lt;p&gt;It is also available as NPM module:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install crx-hotreload
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then use a &lt;code&gt;require&lt;/code&gt; (or &lt;code&gt;import&lt;/code&gt;) to execute the script.&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/xpl/crx-hotreload"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;We’ve used React but these should work for any other state management library.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Browser compatibility
&lt;/h3&gt;

&lt;p&gt;The problem with browser compatibility is not well solved with extensions. Though we have not dug into it yet, there seems to be a lot of potential in &lt;a href="https://hacks.mozilla.org/2019/10/developing-cross-browser-extensions-with-web-ext-3-2-0/"&gt;web-ext&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Host commands
&lt;/h3&gt;

&lt;p&gt;Our javascript agent gets some of its metadata with &lt;strong&gt;host&lt;/strong&gt; commands. But you’re running in a browser extension, so that is not an option.&lt;/p&gt;

&lt;p&gt;Some questions then arise:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Where to get credentials from? Traces sent to the backend need an API endpoint and an API key.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How would I calculate the &lt;a href="http://www.ntp.org/"&gt;NTP&lt;/a&gt; offset in my machine needed for precise timestamp measurements in the trace view? When talking about distributed traces, resolution and precision in the order of microseconds and even nanoseconds is important, as the traces are often generated in different machines. Any small offset can ruin your data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the future: how do I get the code of this specific file and line number that threw an exception?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are different ways to answer these questions. For example, we can solve number 1 by logging our extension in using the browser’s cookies. This would allow the extension to send authenticated requests to our backend. This is risky though, as it requires a &lt;a href="https://www.chromestatus.com/feature/5088147346030592"&gt;SameSite=None cookie&lt;/a&gt;. Number 2 is tricky as there are no “external world” solutions — we need host rights. Number 3 could be solved the same way as number 1, but again, that is risky.&lt;/p&gt;

&lt;p&gt;An option that answers all 3 questions is using our Scope Native App via the &lt;a href="https://developer.chrome.com/extensions/nativeMessaging"&gt;native messaging API&lt;/a&gt;. The native app is already configured with the API endpoint of your choice and it has access to the API key, which solves question number 1. It can also run host commands, so that solves number 2 and number 3. The disadvantage is that we couple our extension with a different product, but with our current and future requirements in mind, this seems like the best possible alternative.&lt;/p&gt;

&lt;p&gt;Building browser extensions is very rewarding. The technical challenges we faced on this one were really thought provoking and and we’re sure we will continue to face many more. You can also rest assured we’ll continue to invest and innovate in this space, as we’re confident of our ability to help bridge the gap between Dev &amp;amp; QA with tools like Scope for Chrome.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6nsUVNaq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/0%2APyDT_bdqYdcNP7p1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6nsUVNaq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/0%2APyDT_bdqYdcNP7p1.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Testing is a core competency to build great software. But testing has failed to keep up with the fundamental shift in how we build applications. Scope gives engineering teams production-level visibility on &lt;strong&gt;every test&lt;/strong&gt; for &lt;strong&gt;every app&lt;/strong&gt; — spanning mobile, monoliths, and microservices.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Your journey to better engineering through better testing &lt;a href="https://scope.dev?utm_source=dev.to"&gt;starts with Scope&lt;/a&gt;.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>microservices</category>
      <category>devops</category>
    </item>
    <item>
      <title>Introduction To Observability For An iOS Developer</title>
      <dc:creator>Bryan Lee</dc:creator>
      <pubDate>Thu, 12 Dec 2019 18:53:34 +0000</pubDate>
      <link>https://dev.to/kickingthetv/introduction-to-observability-for-an-ios-developer-1icb</link>
      <guid>https://dev.to/kickingthetv/introduction-to-observability-for-an-ios-developer-1icb</guid>
      <description>&lt;p&gt;&lt;strong&gt;Written by &lt;a href="https://medium.com/@nacho_24898"&gt;Ignacio Bonafonte&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DWKpN5kp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AX1PqnQlUSHEF3dH88bndQg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DWKpN5kp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AX1PqnQlUSHEF3dH88bndQg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Issues and failures in production
&lt;/h2&gt;

&lt;p&gt;Tracking down crashes and issues in asynchronous code is usually very hard. If your code crashes, the crash report and the stack trace are related to the thread that crashed, but the context where the crash happened is usually lost. If the app didn’t crash but had a wrong behavior, it can be even worse, because the best information you can probably get is a log line in a hidden log file.&lt;/p&gt;

&lt;p&gt;To locally track these problems, Apple provides ActivityTracing.framework, which lets you group your application code in Activities and assign logs to those activities. ActivityTracing also allows you to leave a trail of events to help you identify the path your code walked before the problem happened. This functionality is very helpful to identify problems locally. If you are still not using this technology in your app, take a look at Apple’s &lt;a href="https://developer.apple.com/documentation/os/activity_tracing"&gt;documentation&lt;/a&gt;, it can help make life easier as a developer.&lt;/p&gt;

&lt;p&gt;However, the usefulness of ActivityTracing is limited if your application interacts with multiple services and performs requests and receives responses asynchronously. As a developer, identifying the root cause for failure turns into a guessing game: if the failure happens in a repeatable manner, you can run the problematic code many times while monitoring the service to find it; but if the error arises in the hands of your users and is not reproducible then you lack the visibility to find a solution. Here comes Observability to the rescue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observability and distributed tracing
&lt;/h2&gt;

&lt;p&gt;Observability means understanding how and why an application reached its current state just by its outputs without modifying its current status. So, when something wrong occurs in the wild you should have all the data needed to know why it happened just by checking the output of the existing application and related services.&lt;/p&gt;

&lt;p&gt;It consists of several practices that must be followed in all the systems involved: monitoring, alerts, logs, and a common way to compose all the information from your different systems working together.&lt;/p&gt;

&lt;p&gt;Distributed tracing is a method used to profile and monitor applications, especially useful for those built using a microservices architecture. It monitors the transactions that happen between systems and reports the monitoring and log results of every system that participate in that communication to a central server that unifies the different reports around the transaction. You could say that it works like ActivityTracing but in a multi-system environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why bother with microservices?
&lt;/h2&gt;

&lt;p&gt;IT and DevOps use distributed tracing for debugging and monitoring distributed software architectures, but you can also use it for your development and debugging purposes. When developing application functionality around an external service, the communications with that service are not always as nice as desired: maybe you misimplemented the specification of a REST API and sometimes your application doesn’t work, maybe the server just didn’t handle a corner case properly and your application is receiving an error 500, or maybe the service changed under the hood and your code is not compatible anymore.&lt;/p&gt;

&lt;p&gt;When your application is released and your code is running in the client’s hands, if some feature doesn’t work as expected the error reports will find their way back to you. You have to start the process of debugging to figure out why it is happening: probably trying to reproduce the issue yourself, checking the latest code added to that functionality, or checking the crash if you have them. Wouldn’t it be better if you could just look for the issue in the logs and see that the server returned an error because it had an internal error? Wouldn’t it be even better if you could provide the exact request that made the service fail to your fellow colleague who’s writing the backend stuff?&lt;/p&gt;

&lt;p&gt;This is what observability and distributed tracing can bring to your workflow, the complete context for every interaction with an external system that your application or framework has. You can also add your existing ActivityTracing activities to have a complete frame of the code and narrow down issues even faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Meet OpenTelemetry
&lt;/h2&gt;

&lt;p&gt;Observability is mainly used in microservices environments and each solution supports a subset of system and languages. Finding one that supports both your backend systems and your iOS platform may not be an easy task.&lt;/p&gt;

&lt;p&gt;OpenTelemetry is an open-source observability framework still in the works, formed through a merger of the two most popular distributed tracing standards (OpenTracing and OpenCensus). The goal of OpenTelemetry is to provide both the API and a vendor-neutral implementation so you won’t be tied to what the vendor of your solution provides for all your platforms.&lt;/p&gt;

&lt;p&gt;Right now, iOS is not in the group of officially supported platforms, but we are working at Undefined Labs to provide the source of a Swift client that will allow any iOS or macOS developer to use this technology in their products. We will be providing the first alpha version of the code in the following weeks.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://undefinedlabs.com/?utm_source=dev.to"&gt;Undefined Labs&lt;/a&gt;, we are interested in the standardization of distributed tracing in all platforms. One of our products in the works, &lt;a href="https://scope.dev?utm_source=dev.to"&gt;Scope&lt;/a&gt;, is a management and monitoring platform for all your testing needs. Scope provides these observability superpowers to all your tests, so when a test unexpectedly fails, the root cause of the failure can be easily found and fixed. Scope makes it easy for you to keep your test suites healthy and robust.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Y6IxUvDh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AcC11qx3AQwm65RAmcpV-Lg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y6IxUvDh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AcC11qx3AQwm65RAmcpV-Lg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Testing is a core competency to build great software. But testing has failed to keep up with the fundamental shift in how we build applications. Scope gives engineering teams production-level visibility on &lt;strong&gt;every test&lt;/strong&gt; for &lt;strong&gt;every app&lt;/strong&gt; — spanning mobile, monoliths, and microservices.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Your journey to better applications through better testing &lt;a href="https://scope.dev?utm_source=dev.to"&gt;starts with Scope&lt;/a&gt;.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ios</category>
      <category>observability</category>
      <category>testing</category>
      <category>devops</category>
    </item>
    <item>
      <title>Testing in the Cloud Native Era</title>
      <dc:creator>Bryan Lee</dc:creator>
      <pubDate>Wed, 11 Dec 2019 17:28:16 +0000</pubDate>
      <link>https://dev.to/kickingthetv/testing-in-the-cloud-native-era-5973</link>
      <guid>https://dev.to/kickingthetv/testing-in-the-cloud-native-era-5973</guid>
      <description>&lt;p&gt;&lt;strong&gt;Written by &lt;a href="https://twitter.com/fernandomayo"&gt;Fernando Mayo&lt;/a&gt;&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w1D_ULZj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3094/1%2APpskAi_4ui7_4DMhBPKVaQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w1D_ULZj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3094/1%2APpskAi_4ui7_4DMhBPKVaQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As applications are being broken down into smaller interdependent pieces and shipped at ever faster rates, we need to update our definition of software testing. We need to make sure our testing methods keep pace with how we develop, to ensure we continue shipping reliable and performant software, in a cheap and fast way.&lt;/p&gt;

&lt;h2&gt;
  
  
  You are always testing
&lt;/h2&gt;

&lt;p&gt;When you think about the “software development lifecycle”, you will probably picture something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1hWxOXvb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3094/1%2AZNsXWtuFtpnal6E1uqje6A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1hWxOXvb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3094/1%2AZNsXWtuFtpnal6E1uqje6A.png" alt="The traditional software development lifecycle"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;According to traditional wisdom, “testing” is something we do after we finish developing and before we start deploying. But in a world where monolithic applications are being broken down into smaller “services”, this traditional definition of testing no longer holds true. This is due to several factors: increasing complexity (number of deployable artifacts and APIs, independent release schedules, number of network calls, persistent stores, asynchronous communication, multiple programming languages…), higher consumption rates of third-party APIs of staggering variety, frequent deployments thanks to CI/CD pipelines, and a step-change in power when it comes to observability and monitoring tools.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X_ovVAXW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3696/1%2AerGtTb2ss18e1w6xBwSKBw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X_ovVAXW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3696/1%2AerGtTb2ss18e1w6xBwSKBw.png" alt="The new software development lifecycle"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You test when you run a few unit tests before pushing your code, or when CI automatically runs a suite of integration tests every night. But you also test when a product manager uses your staging environment to try out a new feature, or when you gradually send traffic to a new version of your application that was just deployed and you’re continuously monitoring for errors. You also test when you run periodic checks that drive your UI automatically to perform a synthetic transaction on your production instance. And yes, when your customers are using your application, they are helping you test it as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  What do we test for?
&lt;/h2&gt;

&lt;p&gt;At a bare minimum, any service owner would want to ensure a certain level of quality of their service regarding these aspects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Correctness&lt;/strong&gt;: does it do what I want it to do without defects?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt;: does it respond to its consumers with an acceptable delay?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Robustness&lt;/strong&gt;: does it degrade gracefully when dependencies are unavailable?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are many other non-functional aspects of your application you might want to test for depending on your application’s specific requirements (e.g. security, usability, accessibility). Any breach of expectations in any of these dimensions becomes something you want to be able to detect, troubleshoot, and fix as soon as possible, with the lowest possible effort, and have a way to prevent it from happening again in the future.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Correctness&lt;/strong&gt; is the aspect we typically associate &lt;em&gt;testing&lt;/em&gt; with. We immediately think of unit and integration test suites that ensure the application returns an expected response to a set of predefined inputs. There are also other very useful approaches to testing correctness, like &lt;a href="https://increment.com/testing/in-praise-of-property-based-testing/"&gt;property-based testing&lt;/a&gt;, fuzz testing, and &lt;a href="https://medium.com/appsflyer/tests-coverage-is-dead-long-live-mutation-testing-7fd61020330e"&gt;mutation testing&lt;/a&gt;, that can help us detect a wider range of defects in an automated way. But we should not stop there.&lt;/p&gt;

&lt;p&gt;Even with the most comprehensive test suite in the world, a user is still going to find a defect when it goes live. That’s why we should extend correctness testing to production as well, with techniques like canary deployments and feature flags. As we will discuss later, an efficient testing strategy will make use of multiple techniques across all environments in order to proactively prevent issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt; is a very important quality aspect of any software application, yet we don’t actively test for it as much as we should, as it becomes a complex endeavor to figure out which combination of data, access patterns, and environment configuration will be the one most representative of “production”, which is what will eventually dictate the performance of our application as seen by the end user.&lt;/p&gt;

&lt;p&gt;Benchmark testing is a good and cheap way to get early feedback about any performance regressions on part of our code, and we should definitely use it as part of our strategy. But again, there’s more we can do to test the performance of our application.&lt;/p&gt;

&lt;p&gt;This is the perfect example of how expanding our definition of testing to the entire software lifecycle can help us increase software quality with less effort. Even if we invested in having pre-production load and stress tests to give us an idea of the throughput of our application and making sure we don’t introduce regressions, there’s nothing closer to production than production itself. That’s why a good performance testing strategy should also include adding the required instrumentation and tools to be able to detect and debug performance issues directly in production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Robustness&lt;/strong&gt; is very often overlooked, as we are biased towards testing for the “happy path”. This wasn’t much of an issue in the world of monoliths — failure modes were few and mostly well known. But in the brave new world of microservices, the number of ways our application can fail has exploded. This is also the aspect of our application that, if not properly and thoroughly tested, has the most direct impact on the end user experience.&lt;/p&gt;

&lt;p&gt;Making sure our services tolerate issues and degrade gracefully when dependencies fail is very important, and we should make sure we test for that. In this case, testing emphasis should be put on pre-production testing: failure handling code, by its nature, will not be exercised very frequently in production (if things go well), so having automated tests that programmatically simulate failure is essential.&lt;/p&gt;

&lt;p&gt;Investing in failure injection and &lt;a href="https://launchdarkly.com/blog/testing-in-production-the-netflix-way/"&gt;chaos engineering&lt;/a&gt; in production is another option if we consider that there are possible failures that we cannot reproduce in a controlled environment and we need to resort to testing them directly in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  The modern testing toolbox
&lt;/h2&gt;

&lt;p&gt;Software engineers are gradually becoming service owners, where they are responsible for a specific part of an application all the way from development to production. This includes testing, but not just in the traditional sense — it starts with unit testing their code, and extends to adding telemetry to effectively test in production.&lt;/p&gt;

&lt;p&gt;Just as the DevOps movement highlighted the importance of developers to understand and be involved in the deployment and ongoing monitoring of the service they own, it is also important for them to understand the different testing techniques available to them, and use them appropriately to increase the reliability of their application at the lowest possible cost.&lt;/p&gt;

&lt;p&gt;As we have seen earlier, some of these new techniques enable safely testing in production, if &lt;a href="https://medium.com/@copyconstruct/testing-in-production-the-safe-way-18ca102d0ef1"&gt;done right&lt;/a&gt;. For example, canary deployments allow for testing an application in production for a small percentage of real user data. For it to work, the application must be developed in a way to support this kind of testing, for example, by adding appropriate metrics to detect when there is an issue, logs and/or traces to troubleshoot what went wrong in the case the test fails, and by making sure there are no side effects on any datastore should the deployment need to be rolled back. While there may be cases where these testing techniques can help us efficiently test, they are complex to setup and execute, and one must understand all the prerequisites and implications of performing such tests.&lt;/p&gt;

&lt;p&gt;Including tools for testing in production in your toolbox will allow you to use it when it’s the most efficient (cheapest) for the feature or bug fix you want to test, since the cost of synthetically testing it earlier in the cycle might actually be more expensive (e.g. data requirements, or dependencies that cannot be mocked or replicated).&lt;/p&gt;

&lt;h2&gt;
  
  
  The value of testing
&lt;/h2&gt;

&lt;p&gt;In order to make sure our application is correct, performant, and robust, we have to make sure we take a holistic approach to testing and explore all the different testing options at our disposal. But how do we decide which type of test to use? It comes down to reducing &lt;em&gt;costs&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We also know that, at some point, our application will not perform as expected, no matter how much we test. There are simply way too many factors involved that we cannot anticipate: too many possible user inputs, too many states in which your application can find itself, too many dependencies that are outside of your control. So why testing if we cannot avoid failure completely? When should we stop? It comes down to managing &lt;em&gt;risk&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testing is about &lt;em&gt;reducing the risk&lt;/em&gt; of your application performing unexpectedly, at the &lt;em&gt;lowest possible cost&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The costs associated with catching issues in production
&lt;/h2&gt;

&lt;p&gt;Let’s consider the cost of addressing issues in production. It comes in different forms:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Detection cost&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;How and when do I get notified if it is not working as intended?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Does the user need to notify us of the problem?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is the time delay between the issue being introduced in the application, and someone in the organization being alerted?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do we have automated alerting, or do we have to actively monitor a dashboard?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Does the alerting work properly?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do we have the right metrics?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How do we detect non-obvious issues that aren’t accompanied by a spike in latency or an increased error rate?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Troubleshooting cost&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Once I know there is an issue, how do I know what caused it?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Did I add the appropriate instrumentation (metrics, logs, traces, exceptions) to debug the issue?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do the metrics have the right tags and resolution to aid with debugging?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do we have the logs, or have they been deleted because of retention policies?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Have the relevant traces for troubleshooting been sampled?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What are the costs associated with processing and storing this information?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do I have to reproduce the issue in another environment to find out more about it? How much time will that take?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do I know who has the knowledge to debug it?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When was it introduced?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Fixing cost&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Who is the team responsible for fixing this?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do they have the bandwidth to address the issue?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can I rollback safely to temporarily fix the issue, or am I forced to come up with a hotfix ASAP and roll forward?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Did the issue affect any datastores or other services that now need cleaning up?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How long will the fix take to propagate through all affected environments?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Verification cost&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Can I automate verifying the fix, or does it need manual verification?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How much time and resources does verifying the fix take?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do I have to rely on an affected user for verification?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can I verify all possible permutations of the issue?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can I verify the fix without side effects on the production instance?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;User impact cost&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Are users impacted by the issue?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If they are, how many, and for how long?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Is the business losing money?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Is the company’s brand or reputation being negatively impacted?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How many support tickets have resulted from this issue?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is the cost of processing and replying to these support tickets?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5qmKl8w8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/5238/1%2ApYJBKnlUYWvlZ3u9HG5GBA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5qmKl8w8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/5238/1%2ApYJBKnlUYWvlZ3u9HG5GBA.png" alt="The code journey from the developer’s laptop to the end user"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As issues approach the end user of the application, the more expensive it becomes to address them. A bug detected with a unit test that a developer ran locally while working on a feature branch, for example, is the cheapest to address: the bug has been detected immediately after the developer introduced it (detection cost); easy to debug as it pinpoints exactly where the problem is, along with rich debugging information (troubleshooting cost); the developer just introduced the issue, so they already have the proper context to quickly fix the problem (fixing cost), can immediately verify the fix by re-running the test (verification cost), and the issue has resulted in zero user impact.&lt;/p&gt;

&lt;p&gt;On the other hand, an issue that comes up weeks after a new version has been released to users is arguably the most expensive one. Costs for detection, troubleshooting, fixing, verification, and user impact will all be at their highest.&lt;/p&gt;

&lt;p&gt;Note that I have &lt;a href="https://blog.turbinelabs.io/deploy-not-equal-release-part-one-4724bc1e726b"&gt;separated&lt;/a&gt; &lt;em&gt;production&lt;/em&gt; from &lt;em&gt;end user&lt;/em&gt;. By using canary deployments or feature flags, the issue can reach production, while we control which end users are exposed if any at all. In this case, an issue detected after &lt;em&gt;deployment to production&lt;/em&gt; (the new code is running in production infrastructure) but before &lt;em&gt;releasing it to all users&lt;/em&gt; (no users or only a small fraction of users are being served by the new code), helps to mitigate the user impact cost, but all of the other costs still apply.&lt;/p&gt;

&lt;p&gt;Also, we should note that engineering teams that are constantly interrupted to address issues, especially ones that have been detected late in the cycle, incur variable costs of stress, which can ultimately lead to burnout. Regardless of whether engineers are on-call or not for the services they own, adding unplanned work to debug and fix production issues, which requires context switching from their already planned and full sprints, has a negative effect that becomes readily apparent over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing can be cheap, but it’s never free
&lt;/h2&gt;

&lt;p&gt;Addressing issues in production is expensive. Ideally, we want to utilize tests to catch them as cheaply and as early in the cycle as possible. But while tests can be cheap, they’re never free. Some of the associated costs include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Creation cost&lt;/strong&gt;: how much time and effort is needed to write the test, and make the system testable?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Execution cost&lt;/strong&gt;: how long does it take to actually run the test to get feedback? How many computing resources does it consume?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Maintenance cost&lt;/strong&gt;: if I change my application (refactoring, new feature, etc.), how much time and effort does it take to update the test accordingly?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Any software development team must be on top of their testing costs and actively manage them, like any other aspect of the code they write. Reducing execution cost can be done in many ways: removing overlapping tests, making sure tests run quickly (by doing I/O only if absolutely necessary, and using mocks where possible), running only tests that cover the code that has &lt;a href="https://martinfowler.com/articles/rise-test-impact-analysis.html"&gt;changed&lt;/a&gt; (like &lt;code&gt;go test&lt;/code&gt;, &lt;code&gt;jest&lt;/code&gt; or &lt;code&gt;bazel&lt;/code&gt; do), or by “failing fast” and getting feedback before all tests finish running.&lt;/p&gt;

&lt;p&gt;Flaky tests (defined as tests that both pass and fail with the same codebase) are especially costly, as they don’t just introduce noise and distraction, and the need for retries — they decrease developer confidence in the system, and will either slow down the workflow (the build needs to be green to continue), or increase risk (we know the tests failing are flaky — so let’s continue anyway). Flakiness should be &lt;a href="https://blogs.dropbox.com/tech/2019/05/athena-our-automated-build-health-management-system/"&gt;measured&lt;/a&gt; and reduced to a minimum. Some tests will need to perform I/O operations and will inherently have some degree of flakiness — in these cases, adding retries to the test or making the I/O operations more resilient to transient failures, can be the most efficient way to tackle them, as rewriting them to completely remove flakiness might be much more expensive, or even impossible. Techniques like mocking dependencies by &lt;a href="https://github.com/vcr/vcr"&gt;recording and replaying HTTP traffic&lt;/a&gt; (a kind of &lt;em&gt;snapshot testing&lt;/em&gt; but for integration tests), can also help reduce flakiness and speed up testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Strategies to reduce testing cost
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MpXiRe5I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4112/1%2ALcjq7Lex2NGwtwFQz3pHAg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MpXiRe5I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4112/1%2ALcjq7Lex2NGwtwFQz3pHAg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The execution cost of tests can be reduced by having an effective strategy when running them. For example, by running only fast unit and integration tests locally when working on a bug fix or new feature, we reduce the time to feedback from the developer. Then, after pushing the code to the central repository, CI can kick off a round of more in-depth integration tests. The master branch can have a nightly run of longer and more expensive system or end-to-end tests, etc.&lt;/p&gt;

&lt;p&gt;The idea is to balance execution cost with the time to receive feedback; for example, by reducing the execution cost, we increase the troubleshooting/verification cost: by running tests less often, we will create “gaps” in the history of test executions that, in the case of a broken test, will introduce a larger search space for the actual culprit of the failure; the less frequent the test executions, the wider the gaps in history, as depicted in the above graph.&lt;/p&gt;

&lt;p&gt;Because testing is all about reducing risk, one must balance risk appetite with the cost of testing. Even within the same application, not all parts of the application will need the same amount of testing. For every scenario you want to test (e.g. a new feature, a bug fix, or a new dependency failure handler), try to think about how you can test it at the lowest cost possible. Would a simple unit test be sufficient? Do I need to test it against a real instance of a dependency? Or is the most efficient way to test it to add proper instrumentation and alerting, and do a canary deployment in production?&lt;/p&gt;

&lt;p&gt;This is something that must be evaluated by the developer and potentially the greater team, on a case by case basis. It highlights the importance of the developer being familiar with the entire range of testing methodologies available to them in order to choose the most cost-effective one.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do we test what we don’t know can fail?
&lt;/h2&gt;

&lt;p&gt;As we have seen, testing allows us to detect, debug and fix issues in a cheaper manner than waiting for them to be surfaced by a user. But, how do we test for things that we are not aware of that can fail? How do we test for the &lt;em&gt;unknown unknowns&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--71kP4LfW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3718/1%2ApmrwcrlESwlNihh0TOX2rg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--71kP4LfW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3718/1%2ApmrwcrlESwlNihh0TOX2rg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our objective should be to bring as much information as possible to the known knowns quadrant, which are the facts about our service. When we change something on our application, previous known knowns are invalidated. Testing helps us move from &lt;em&gt;known unknowns&lt;/em&gt; to &lt;em&gt;known knowns&lt;/em&gt;, i.e. we know the questions to ask, and by executing the test, we’ll get the answer. We can do this in an automatic, quick, and very efficient way. For example, “does this function return what I expect when I provide these specific arguments?”, “does my service return a 400 when the user sends an invalid payload?” or “does the UI show an error message when a user tries to log in with an invalid password?”.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Unknown unknowns&lt;/em&gt; are issues that appear that we didn’t anticipate because we didn’t even know they could happen. We can’t test for them, as by definition, we don’t know what can actually fail until it does. For this case, good instrumentation and tooling in production will allow us to debug (and sometimes detect) new issues we couldn’t anticipate, but it comes at a high cost. If the root cause finally ends up being one that could come up in the future (and not just a transitory operational issue), it’s always a good idea to write the &lt;em&gt;cheapest&lt;/em&gt; test possible for it, to avoid regressions, and bring it to the &lt;em&gt;known unknowns&lt;/em&gt; quadrant for future versions of the software, which will save us precious engineering time.&lt;/p&gt;

&lt;h2&gt;
  
  
  How much testing is enough?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FQ9oVGln--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3200/0%2ASfv1ianxBI4537SD" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FQ9oVGln--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3200/0%2ASfv1ianxBI4537SD" alt="The perfect application does not exist"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We know testing will never be able to tell us that our application is 100% reliable, as testing is about managing risk. That’s why traditional testing coverage is not a good measure of quality or a target an engineering team should focus on. As we have seen, unit testing is just one of the many techniques we should be using to test our services — and code coverage is based on that. It can only tell us how extensive our unit tests are, but not if we are building a high-quality service.&lt;/p&gt;

&lt;p&gt;What can we use instead? We instinctively know that if we don’t test our application, its quality won’t meet our user’s standards. We also know that we could just keep investing in testing forever and we will never reach perfection. There is a compromise somewhere in the middle, but how to measure it?&lt;/p&gt;

&lt;p&gt;The performance (latency) and robustness (availability) aspects of your application should be already being measured and monitored, with a corresponding &lt;a href="https://landing.google.com/sre/sre-book/chapters/service-level-objectives/"&gt;SLO&lt;/a&gt;. SLOs provide a target you should strive for in these dimensions. Testing should support hitting those goals, which will depend on the application requirements. Critical services will have very aggressive SLOs, thus requiring a high level of investment in testing, and non-critical services will have more relaxed requirements. Only by directly linking the testing budget to objective targets like SLOs will provide the right incentives for teams to decide how much risk they want to remove.&lt;/p&gt;

&lt;p&gt;The correctness aspect is harder to measure directly, but equally important. You application might be extremely reliable and performant, yet your users might be unhappy because your application is just not doing what it’s supposed to do. A pragmatic approach to continuously measure correctness could be to have a target on the rate of new high priority defects in production. Just like an availability SLO, that number can be a good proxy on whether defects are slipping through to end users too often, and guide the team to adjust their testing efforts accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Testing has always helped us build applications that are more maintainable, debuggable, reliable and performant, and allowed us to ship faster and with more confidence. But as applications have become more and more complex and dynamic, new types of failure modes have been introduced which are increasingly more difficult to anticipate and troubleshoot. In order to be able to proactively and efficiently detect, debug and fix them, we should review and adapt how we use traditional testing techniques and embrace new ones that apply to all stages of the development lifecycle.&lt;/p&gt;

&lt;p&gt;Only then can testing return to be the invaluable ally it once was in delivering high quality software.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Y6IxUvDh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AcC11qx3AQwm65RAmcpV-Lg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y6IxUvDh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AcC11qx3AQwm65RAmcpV-Lg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Testing is a core competency to build great software. But testing has failed to keep up with the fundamental shift in how we build applications. Scope gives engineering teams production-level visibility on &lt;strong&gt;every test&lt;/strong&gt; for &lt;strong&gt;every app&lt;/strong&gt; — spanning mobile, monoliths, and microservices.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Your journey to better engineering through better testing &lt;a href="https://scope.dev?utm_source=dev.to"&gt;starts with Scope&lt;/a&gt;.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>microservices</category>
      <category>cloudnative</category>
      <category>devops</category>
    </item>
    <item>
      <title>We Have A Flaky Test Problem</title>
      <dc:creator>Bryan Lee</dc:creator>
      <pubDate>Mon, 09 Dec 2019 16:43:50 +0000</pubDate>
      <link>https://dev.to/kickingthetv/we-have-a-flaky-test-problem-11ol</link>
      <guid>https://dev.to/kickingthetv/we-have-a-flaky-test-problem-11ol</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zP7SyMWw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A1a6GmPIParXcVAejiwo3Gg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zP7SyMWw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A1a6GmPIParXcVAejiwo3Gg.png" alt="A developer hitting retry on their CI build"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Flaky tests are insidious. Fighting flakiness can sometimes feel like trying to fight entropy; you know it’s a losing battle, and it’s a battle you must engage in again and again and again.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://testing.googleblog.com/2016/05/flaky-tests-at-google-and-how-we.html"&gt;Google’s definition&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We define a “flaky” test result as a test that exhibits both a passing and a failing result with the same code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At Undefined Labs, we’ve had a chance to talk to dozens of engineering organizations of all different sizes, ranging from 3 person startups to Fortune 500 companies. We listen and gather feedback around all things “test.”&lt;/p&gt;

&lt;p&gt;When we talk about the frustrations and major issues organizations encounter with testing, inevitably, flaky tests will always come up. And when we get to this part of the discussion, the people we’re talking to will have a visible shift in demeanor, wearing the expression of someone trying to put out more fires than they have water.&lt;/p&gt;

&lt;p&gt;We, too, once wore this same expression. While we were at Docker, the co-founders of Undefined Labs and I were spread across and working on different products, from enterprise on-premise solutions, CLI developer tools, to various SaaS (Software as a Service) solutions. We also got to see the work of our co-workers on various open-source projects like Docker Engine, Docker Swarm, and Docker Compose.&lt;/p&gt;

&lt;p&gt;It was this experience and the frustrations with testing in general that led to the creation of Undefined Labs and our first product, &lt;a href="https://scope.dev/"&gt;Scope&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Throughout our talks with these various engineering organizations, we’ve heard about all kinds of different solutions to tackle flakiness, with varying success. We noticed that the organizations that were best able to cope with flakiness had dedicated teams ready to create best practices, custom tools, and workflows to deal with flakiness.&lt;/p&gt;

&lt;p&gt;But not all teams had such lavish resources to throw at the problem, without having to worry about efficiency. We saw some of these teams hack together workflows through existing tooling and scripts. And some teams did nothing at all. They threw their hands up and succumbed to the torrent of flaky tests.&lt;/p&gt;

&lt;p&gt;I think it’s paramount to have a plan in place to address flaky tests. Flaky tests are bad, but they’re even worse than you think.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why flaky tests are even worse than you think (is that even possible?)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h1wWZ5tJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4512/0%2Ao9MuWmXo7Xj-8kjK" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h1wWZ5tJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4512/0%2Ao9MuWmXo7Xj-8kjK" alt="A visual depiction of how developers feel while debugging a flaky test. Photo by [Elizaveta Korabelnikova](https://unsplash.com/@korabelnikova?utm_source=medium&amp;amp;utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&amp;amp;utm_medium=referral)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing plays a significant role in the productivity of engineers.
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://testing.googleblog.com/2016/05/flaky-tests-at-google-and-how-we.html"&gt;Google on developer productivity&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Productivity for developers at Google relies on the ability of the tests to find real problems with the code being changed or developed in a timely and reliable fashion.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The keywords here are “real problems,” “timely,” and “reliable fashion,” all of which seem to point a big fat finger directly at the consequences of flaky tests.&lt;/p&gt;

&lt;p&gt;When tests behave as expected, they’re a boon to productivity. But as soon as tests can’t find real problems, their results arrive too slowly or can’t be trusted, it turns into one of the most miserable time-sucks known to modern humanity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flaky tests love collateral damage
&lt;/h3&gt;

&lt;p&gt;Not only do flaky tests hurt your own productivity, but there is cascading loss of productivity experienced by everyone upstream.&lt;/p&gt;

&lt;p&gt;When master is broken, everything comes to a screeching halt.&lt;/p&gt;

&lt;p&gt;We’ve seen some of the highest performing engineering organizations implement various strategies to mitigate this collateral damage. They gate and prevent flaky tests from ever making it to master and/or have a zero-tolerance policy for flaky tests; once they’ve been identified, they’re quarantined until fixed.&lt;/p&gt;

&lt;p&gt;Other tests, and even the entire test suite, can also be collateral damage. Test flakiness left unabated can completely ruin the value of an entire test suite.&lt;/p&gt;

&lt;p&gt;There are even greater implications of flaky tests; the second and third-order consequences of having flaky tests is that it spreads apathy if unchecked. We’ve talked to some organizations that reached 50%+ flaky tests in their codebase, and now developers hardly ever write any tests and don’t bother looking at the results. Testing is no longer a useful tool to improve code quality within that organization.&lt;/p&gt;

&lt;p&gt;Ultimately, it will be the end-users of your product that bear the brunt of this cost. You’ve essentially outsourced all testing to your users and have accepted the consequences of adopting the most expensive testing strategy as your only strategy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Increases Costs
&lt;/h3&gt;

&lt;p&gt;As mentioned by Fernando, our CTO, in his blog post &lt;a href="https://medium.com/scopedev/testing-in-the-cloud-native-era-41f63a0e101b"&gt;Testing in the Cloud Native Era&lt;/a&gt;, tests have an associated cost attached to them. And when it comes to flaky tests, there are hidden costs, and the cost is generally increased across the board: creation cost, execution cost, fixing cost, business cost, and psychological cost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creation cost:&lt;/strong&gt; this includes both the time and effort needed to write the test, as well as making the system testable. A flaky test requires you to re-visit this step more often than you would like, to either fix the test or make the system more testable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Execution cost:&lt;/strong&gt; if you’re interested in trying to generate signal from your flaky tests without necessarily fixing it, you can execute the test more than once.&lt;/p&gt;

&lt;p&gt;Additional executions can be manual — we’ve all hit the “retry build” button, with the hope that this time, things will be different. We’ve also seen some teams leverage testing frameworks that allow for automatic retries for failing tests.&lt;/p&gt;

&lt;p&gt;Execution cost can also potentially manifest itself as requiring a platform team to help keep the pipeline unblocked and moving at a fast enough pace to service the entire organization. Your team needs both infrastructure and scaling expertise if you want to reach high levels of execution.&lt;/p&gt;

&lt;p&gt;There’s also the cost of the infrastructure required to run your tests, and perhaps the most valuable resource of all, your time. Increased executions mean more time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fixing cost:&lt;/strong&gt; debugging and fixing flaky tests can potentially take hours of your workweek. Some of the most frustrating parts about flaky tests are reproducing them and determining the cause for flakiness.&lt;/p&gt;

&lt;p&gt;Fixing a flaky test also demands expertise and familiarity with the code and/or test. Junior developers brought in to work on a legacy code base with many flaky tests, will certainly require the oversight of a more senior developer that has spent enough time to build up sufficient context to fix these tests.&lt;/p&gt;

&lt;p&gt;This is all made worse if you have dependencies (it’s another team’s fault), run tests in parallel (good luck finding only your specific test’s logs), or have long feedback cycles (builds that take hours with results only available after the entire build is finished).&lt;/p&gt;

&lt;p&gt;And in the worst cases, you lack the information and visibility into your systems necessary to fix the test, or the fixing cost can be too high to be worth paying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Business cost:&lt;/strong&gt; Flakiness consumes the time of developers investigating them, and developers represent one of the most expensive and scarce resources for any business. Fixing flaky tests adds accidental complexity, which ultimately leads to more of the developer’s time being taken away from working on new features.&lt;/p&gt;

&lt;p&gt;Other parts of the business will also be impacted due to potential delays in project releases. If the same number of development cycles are required to release a new product, but now every development cycle takes longer, products will be released late, impacting marketing, sales, customer success, and business development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Psychological cost:&lt;/strong&gt; responsibility without the knowledge, tooling, and systems in place to actually carry out that responsibility is a great way to set someone up for failure and cause psychological stress to your developers.&lt;/p&gt;

&lt;p&gt;And what’s more, flaky tests will force you to undergo this cost cycle of a test more than just once while trying to remove or mitigate the flakiness. A great test can have just one up-front creation cost, minimal execution cost (because you trust the first signal it gives you), and very little maintenance cost. Every time a test flakes, it will require you to re-absorb the costs of the test.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reduces Trust, Leads to an Unhealthy Culture, and Hurts Job Satisfaction
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5sh7Zs_---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AacBnfY68spLEZDd1FR4iMg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5sh7Zs_---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AacBnfY68spLEZDd1FR4iMg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When it comes to job satisfaction for engineers, I think it’s safe to say we all prefer working in an organization with a healthy culture. While we may each have our own definition of what a healthy culture looks like, having trust is a major factor. If you don’t trust your organization, your team, or your co-workers, you’ll most likely be looking for the exit sometime soon.&lt;/p&gt;

&lt;p&gt;If your tests seemingly pass and fail on a whim, it’s only a matter of time before trust is eroded. And once trust is eroded, it’s very difficult to build back up. I also think that trust works from the bottom up. You need a solid foundation in which trust can begin to gain traction.&lt;/p&gt;

&lt;p&gt;Organizations that try to increase trust among co-workers from the top-down, usually sow even more distrust. If management is telling me I need to trust my co-workers, then they must be untrustworthy, otherwise, why would they even bring this up?&lt;/p&gt;

&lt;p&gt;When it comes to engineering organizations, a major factor in that foundational level of trust often starts with testing. The testing strategy and general attitude towards testing speak volumes about an engineering organization’s culture.&lt;/p&gt;

&lt;p&gt;If you can’t trust your tests and testing processes, then everything else built on top of tests will slowly crumble. It may not happen quickly, but cracks will begin to form, and morale will suffer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2yofRIT0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2470/1%2APOpkBM_2PgnOR7LbkxOgew.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2yofRIT0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2470/1%2APOpkBM_2PgnOR7LbkxOgew.png" alt="Trust must be built from the bottom up"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is why the prevalence of flaky tests and what you do when they occur matters so much. Flakiness left unguarded, will destroy the trust people have in their tests.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If there is rampant, inadequately addressed flakiness in your tests, then you can’t trust the tests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you can’t trust the tests, then you can’t trust the code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you can’t trust the code, then you can’t trust developers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you can’t trust developers, then you can’t trust your team.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you can’t trust your team, then you can’t trust the organization.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you can’t trust your organization, then there’s obviously a lack of trust in the culture, which means you work at a company with an unhealthy culture.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If your company has an unhealthy culture, your job satisfaction will steadily decline.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There will be a tipping point where you transition from thinking about your organization as an organization &lt;em&gt;that has flaky tests,&lt;/em&gt; to &lt;em&gt;the kind of organization&lt;/em&gt; that has flaky tests. Once you make the mental shift and believe it’s &lt;em&gt;because of the organization&lt;/em&gt; that there are so many flaky tests, trust in the organization has been eroded.&lt;/p&gt;

&lt;p&gt;With job satisfaction continuing to plummet, it’s at this time that your top engineering talent will begin looking elsewhere, actively searching, or maybe just a little more willing to open the emails and messages from recruiters that they had been previously ignoring.&lt;/p&gt;

&lt;p&gt;The saving grace of this situation is that this degradation happens over time. With the right strategies and tools, you can mitigate and even reverse the damage. But it’s not easy, and you can’t do it alone.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flaky tests aren’t going away
&lt;/h3&gt;

&lt;p&gt;Flakiness is only getting worse, not better. As your codebase and test suites grow, so too will the number of flaky tests and results. As you transition, or if you’re already using a microservice architecture, you can have many dependencies. As dependencies increase, flakiness is magnified.&lt;/p&gt;

&lt;p&gt;For example, even if all of your microservices have 99.9% stability, if you have 20+ dependencies each with the same stability, you actually end up having a non-trivial amount of flakiness:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;98.01% stability for 20 dependencies&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;97.04% stability for 30 dependencies&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;95.12% stability for 50 dependencies&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As your engineering organization scales, how it addresses flakiness will be one of the most important factors impacting overall productivity.&lt;/p&gt;

&lt;p&gt;A presentation was released by Google, &lt;a href="https://ai.google/research/pubs/pub45880"&gt;The State of Continuous Integration Testing @Google&lt;/a&gt;, where they collected a large sample of internal test results over a one month time period and uncovered some interesting insights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;84% of test transitions from Pass -&amp;gt; Fail were from flaky tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Only 1.23% of tests ever found a breakage&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Almost 16% of their 4.2 million tests have some level of flakiness&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Flaky failures frequently block and delay releases&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;They spend between 2–16% of their compute resources re-running flaky tests&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Google concluded:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Testing systems must be able to deal with a certain level of flakiness&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  In order to address flaky tests, you need systems thinking
&lt;/h2&gt;

&lt;p&gt;In google’s conclusion, they mentioned testing &lt;strong&gt;systems&lt;/strong&gt; must be able to deal with a certain level of flakiness, not teams or engineers. Looking from the bottom up, from the perspective of an individual, will blind you to the larger universal patterns at work and how they must change.&lt;/p&gt;

&lt;p&gt;To understand why no one person can do it alone, I like to turn towards systems thinking. The power of systems thinking comes when you shift your perspective of the world away from a linear one, and towards a circular one. This reveals a world in which there is a much richer and complex interconnectedness between seemingly everything.&lt;/p&gt;

&lt;p&gt;While seeing things as they truly are can be eye-opening, it can also be a little daunting. Most of the common ways we know to affect change have little leverage.&lt;/p&gt;

&lt;p&gt;Donella Meadows in her book &lt;em&gt;&lt;a href="https://www.amazon.com/dp/B005VSRFEA/ref=dp-kindle-redirect?_encoding=UTF8&amp;amp;btkr=1"&gt;Thinking in Systems: A Primer&lt;/a&gt;&lt;/em&gt;, described the different ways one could influence a system. Here’s a great graphic that shows them all stack-ranked:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kGC-BgtJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2226/1%2AKmsIKH1O2ExG4FvSpWbAXg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kGC-BgtJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2226/1%2AKmsIKH1O2ExG4FvSpWbAXg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What’s important to take away from this graphic is that the capacity of an individual is limited to the least powerful system interventions. This is why teams or organizations with notoriously high turnover rates continue to have high turnover rates, even as new individuals are placed within the system. By and large, teams don’t hire bad employees who turnover quickly; there are only bad teams with high turnover rates.&lt;/p&gt;

&lt;p&gt;If you want to have a high performing culture and have an organization that attracts the best engineers, you’re going to need to have a system in place that reinforces best practices, rewards behavior you want to be repeated, has all of the right feedback loops, to the right people, in the right context, in the right time frame, and has redundancy built in to ensure the system is resilient.&lt;/p&gt;

&lt;p&gt;A CI/CD pipeline, the team that manages it, the various development teams that are dependent on it - they’re all part of a greater system. Whether the system was designed or grew organically, they are a system.&lt;/p&gt;

&lt;p&gt;So when it comes to handling flakiness effectively and with resilience, what are the common system patterns implemented by the best engineering organizations?&lt;/p&gt;

&lt;h2&gt;
  
  
  Common patterns found in systems successfully addressing flaky tests
&lt;/h2&gt;

&lt;p&gt;There were a handful of clear patterns that seemed to crop up in every instance of teams that successfully handled flaky tests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Identification of flaky tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Critical workflow ignores flaky tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Timely flaky test alerts routed to the right team or individual&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Flaky tests are fixed fast&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A public report of the flaky tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dashboard to track progress&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Advanced: stability/reliability engine&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Advanced: quarantine workflow&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s go over each of these a little bit more in-depth…&lt;/p&gt;

&lt;h3&gt;
  
  
  Identification of flaky tests
&lt;/h3&gt;

&lt;p&gt;The first step in dealing with flaky tests is knowing which tests are flaky and how flaky they are.&lt;/p&gt;

&lt;p&gt;It also helps to have your tests exist as a first-class citizen, which will allow you to keep track and identify flaky tests over time/commits. This will enable tagging tests as flaky, which will kick off all of the other patterns listed below.&lt;/p&gt;

&lt;p&gt;When working with flaky tests, it can also be very useful to have test flakiness propagate throughout your system, so you can filter your test list or results by “flaky”, manually mark tests as “flaky” or remove the “flaky” tag if no longer appropriate.&lt;/p&gt;

&lt;p&gt;We’ve also seen different organizations have particular dimensions of flakiness that were important to them: test flakiness per commit, flakiness across commits, test flakiness agnostic to the commit and only tied to the test, and flakiness across devices &amp;amp; configurations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test flakiness per commit:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Re-run failing tests multiple times using a test framework or by initiating multiple builds&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the test shows both a passing and failing status, then this “test &amp;amp; commit” pairing is deemed flaky&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Test flakiness agnostic to the commit and only tied to the test&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A test is tagged as flaky as soon as it exhibits flaky behavior&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Exhibiting flaky behavior may occur in a single commit, or aggregated across multiple commits (e.g. you never rebuild or rerun tests but still want to identify flaky tests)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The test will stay tagged as flaky until it has been deemed fixed&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The prior history and instances of flakiness will stay as metadata of the test&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This can help with the verification of a test failure, to determine if it’s broken or likely a flake, i.e. if this test was previously flaky but hasn’t exhibited flakiness in the past two builds, this recent failure means it’s still likely flaky and was never fixed&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Test flakiness across devices &amp;amp; configurations&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Re-run a single test multiple times across many device types and/or whatever configurations are most important to you i.e. iPhone 11 Pro vs iPhone XS, iOS 12 vs iOS 13, or Python 2.7 vs Python 3.0&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A test can be flaky for a specific device or configuration, i.e. the test both passes and fails on the same device&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A test can be flaky across devices and configurations, i.e. a test passes on one device, but fails on another device&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most common pattern we saw, were teams rerunning failed tests anywhere from 3 to 200 times. A test was then labeled as flaky in either a binary fashion (e.g. at least one fail and at least one pass) or there was a threshold and flakiness score given (e.g. test must fail more than 5 out of 100 retries).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Identifying flaky tests based on a single execution&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are techniques and tools available (including the product I work on, &lt;a href="https://scope.dev/"&gt;Scope&lt;/a&gt;) that can help identify flaky tests, only requiring a single execution. Here’s a brief summary of how it works if you’ve just recently pushed a new commit and a test fails:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You need access to the source code and the commit diff&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You need access to the test path, which is the code covered by the test that failed&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can then cross-reference the two, to identify if the commit introduced a change to the code covered in this particular tests’ test path&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If there was a change to the code in the test path, it’s likely that this is a test failure. And the reason for the test failure is likely at the intersection of the commit diff and the test path&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If there was no change to the code in the test path, it’s a likely sign the test is flaky&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Critical workflow ignores flaky tests
&lt;/h3&gt;

&lt;p&gt;Once the test is identified as flaky, the results from this test are ignored when it comes to your critical workflow. We oftentimes see organizations set up multiple workflows, one dedicated to the initial testing of PRs and one dedicated to master.&lt;/p&gt;

&lt;p&gt;By catching flaky tests before they make it to master, you can then choose to ignore the test results of flaky tests or quarantine these flaky tests and only allowing them to run in specific pipelines if any.&lt;/p&gt;

&lt;h3&gt;
  
  
  Timely flaky test alerts routed to the right team or individual
&lt;/h3&gt;

&lt;p&gt;In order for a system to properly function and remain resilient, it needs feedback loops. Not just any feedback loop; these loops need to be timely, convey the right information and context, be delivered to the right actor, and this actor must be able to take the right action using the information and context delivered.&lt;/p&gt;

&lt;p&gt;The pieces when assembled:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Notification once the flaky behavior is identified (through email, Slack, JIRA ticket, GitHub issue, etc.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Notification must be sent to the party who will be responsible for fixing this flaky test (test author, commit author, service owner, service team, etc.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The notification must contain or point to the relevant information required to begin fixing the test&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Flaky tests are fixed fast
&lt;/h3&gt;

&lt;p&gt;Most of these organizations place a high priority on fixing flaky tests. Most of the teams we saw, usually fixed flaky tests within the week. The longest we came across that still proved to be fairly effective was a month.&lt;/p&gt;

&lt;p&gt;The most important takeaway though, is that whenever the time elapsed to fix a flaky test surpassed the explicit or implicit organizational threshold, the test was almost always forgotten and never fixed.&lt;/p&gt;

&lt;p&gt;In order to fix these tests, varying levels of tools and workflows were set up for developers to begin debugging. These systems always had some smattering of the following: traces, logs, exceptions, historical data points, diff analysis between the current failing and last passing execution, build info, commit info, commit diff, test path, prior trends &amp;amp; analysis).&lt;/p&gt;

&lt;p&gt;Essentially, the more visibility and the more context you can provide to your developers for the specific test in question, while at the same time removing any noise from irrelevant tests, the better.&lt;/p&gt;

&lt;h3&gt;
  
  
  A public report of the flaky tests
&lt;/h3&gt;

&lt;p&gt;This can take many different forms, but the gist of this pattern is to make public the status of the flaky tests identified and the flaky tests fixed, with an emphasis on the flaky tests identified but that have not yet been fixed.&lt;/p&gt;

&lt;p&gt;Some teams had this information available via a slackbot along with the “time since identified”, or would post this list weekly every Monday in the team channel. A couple of organizations even surface these flaky tests within the dashboards used to display metrics for team performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dashboard to track progress
&lt;/h3&gt;

&lt;p&gt;In addition to seeing the current state of flaky tests in your system, most organizations have a way to track progress over time. If your goal is to reduce flakiness, how will you know if you’ve actually hit your goal? How do you know if things are getting better and not worse?&lt;/p&gt;

&lt;p&gt;This high-level system feedback is necessary to make adjustments to the overall system and help identify patterns that aren’t working, or are broken and need fixing.&lt;/p&gt;

&lt;p&gt;At its most basic, this is just a timeline of your builds and the build statuses.&lt;/p&gt;

&lt;p&gt;In more advanced versions, you might get every test execution from every test, the ability to filter by flaky tests, multiple builds &amp;amp; commits worth of information, and the date each of these results were captured.&lt;/p&gt;

&lt;p&gt;Here’s a screenshot of &lt;a href="https://scope.dev/"&gt;Scope&lt;/a&gt;, viewing the Insights for a particular service:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--42qGQ7Cj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2276/1%2AfAsNA86s_kjztLX85XwUfA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--42qGQ7Cj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2276/1%2AfAsNA86s_kjztLX85XwUfA.png" alt="Filtering for tests that have had a flaky result in the past 30 commits, and viewing the aggregated test results for a given test &amp;amp; commit pair"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Advanced: stability/reliability engine
&lt;/h3&gt;

&lt;p&gt;This is an advanced use case, which we’ve only seen versions being used at some of the biggest tech companies (Netflix, Dropbox, Microsoft, &amp;amp; Google), but we think could be useful for any organization trying to deal with flaky tests.&lt;/p&gt;

&lt;p&gt;The general idea is to have two different testing workflows, one for the critical path, and one for the non-critical path. The primary objective of the stability engine is to keep the critical path green. This is done by creating a gating mechanism with specific rules around the definition of “stable tests” and “unstable tests”.&lt;/p&gt;

&lt;p&gt;A test is deemed “unstable” until proven “stable.” So every new test or “fixed” test is submitted to the stability engine, exercises the test in different ways depending on your definition of flaky, and ultimately determines if the test is stable or not, and if unstable, how unstable.&lt;/p&gt;

&lt;p&gt;Unstable tests are either quarantined and never run in your critical path, or the test results of these unstable tests are just ignored.&lt;/p&gt;

&lt;p&gt;All stable tests are now included in your “stable” tests list and will run in your critical path.&lt;/p&gt;

&lt;p&gt;Any test deemed “unstable” must be remediated, and once fixed, re-submitted to the stability engine.&lt;/p&gt;

&lt;p&gt;For example, this may be as simple as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;For any new PR, for all &lt;strong&gt;new&lt;/strong&gt; and &lt;strong&gt;fixed&lt;/strong&gt; tests (tests that were previously unstable), execute each test 20 times&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the test passes more than once, but less than 20 times, the test is marked as &lt;strong&gt;unstable&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fixed&lt;/strong&gt; tests that are still &lt;strong&gt;unstable&lt;/strong&gt; remain quarantined and their test results are ignored&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If there are any &lt;strong&gt;new&lt;/strong&gt; &lt;strong&gt;unstable&lt;/strong&gt; tests in the PR, the PR is prevented from being merged&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Advanced: quarantine workflow
&lt;/h3&gt;

&lt;p&gt;The most basic version of the quarantine workflow is to simply mark the test results of flaky tests as “ignored” in your critical path.&lt;/p&gt;

&lt;p&gt;However, we’ve seen some interesting workflows implemented by savvy companies. A quarantine workflow makes it easy for developers to follow all of the patterns listed above and helps keep your critical path green.&lt;/p&gt;

&lt;p&gt;For example, this is the workflow we’re currently working on for &lt;a href="https://scope.dev/"&gt;Scope&lt;/a&gt; (each of these steps are optional):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Flaky test identified&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The flaky test is added to the Quarantine List and skipped during testing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;JIRA/GitHub issue is created&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automatically remove the test from Quarantine List when the issue is closed&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ping commit author on Slack&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remind author of their Quarantined test(s), every week&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ability to view Quarantine List&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ability to manually remove tests from the Quarantine List&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With a proper quarantine workflow implemented, it really helps ensure the collateral damage of a flaky test is minimized, and the responsible party for fixing the test is properly notified.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;One of the best techniques to ensure high code quality is to use tests. Unfortunately, as applications become more complex and codebases grow larger, test flakiness will begin to rear its ugly head more often. How your organization handles flakiness will be a major factor in defining your engineering culture.&lt;/p&gt;

&lt;p&gt;Ultimately, no single person can fix flakiness as just a single actor within a larger system. Systems thinking should be used and there are useful patterns that are already being implemented by many of the highest performing organizations.&lt;/p&gt;

&lt;p&gt;A peaceful co-existence with flaky tests is available to anyone willing to invest in the tools and processes necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=FrBN94gUn_I&amp;amp;t=1s"&gt;Netflix Automation Talks: Test Automation at Scale&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://testing.googleblog.com/2016/05/flaky-tests-at-google-and-how-we.html"&gt;Flaky Tests at Google and How We Mitigate Them&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://ai.google/research/pubs/pub45794"&gt;Who Broke the Build? Automatically Identifying Changes That Induce Test Failures In Continuous Integration at Google Scale&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://storage.googleapis.com/pub-tools-public-publication-data/pdf/45880.pdf"&gt;The State of Continuous Integration Testing @Google&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.deflaker.org/get-rid-of-your-flakes/"&gt;DeFlaker Tool&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/devops/learn/devops-at-microsoft/eliminating-flaky-tests"&gt;Microsoft — Eliminating Flaky Tests&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://blogs.dropbox.com/tech/2019/05/athena-our-automated-build-health-management-system/"&gt;Dropbox — Athena: Our Automated Build Health Management System&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://arxiv.org/pdf/1907.01466.pdf"&gt;Understanding Flaky Tests: The Developer’s Perspective&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Y6IxUvDh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AcC11qx3AQwm65RAmcpV-Lg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y6IxUvDh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AcC11qx3AQwm65RAmcpV-Lg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Testing is a core competency to build great software. But testing has failed to keep up with the fundamental shift in how we build applications. Scope gives engineering teams production-level visibility on &lt;strong&gt;every test&lt;/strong&gt; for &lt;strong&gt;every app&lt;/strong&gt; — spanning mobile, monoliths, and microservices.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Your journey to better engineering through better testing &lt;a href="https://scope.dev?utm_source=dev.to"&gt;starts with Scope&lt;/a&gt;.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>flakytests</category>
      <category>microservices</category>
      <category>distributedsystems</category>
    </item>
  </channel>
</rss>
