A walk in JavaScript

DAY 11

Quality and reliability

An introduction to the “reliability” and “quality” concepts

Even though both aspects a intimately related, they’re very different between them. We can think about them in the following terms:

In the software industry, there’s a big overlap between quality and reliability, and the better the quality assurances processes applied to the code production, the more reliable the software tends to be.

The bibliography is huge and there are many definitions, sometimes you’ll find yourself asking the client “what does quality mean to you” to be able to trace a plan and avoid investing efforts in the “wrong” place.

My general approach is that “the quality is owned by the team”, every engineer MUST take the necessary measures to warrant the written code and propose corrections if a brittle code has been detected. One of the most important measure is to recognize as a fact that you WILL introduce defects in the code you write, no matter how expert you are, eventually you’ll break something. So don’t excessively trust yourself, ask around for opinions, write tests, make it readable instead of “smart”-ish and try to be a better engineer every single day.

Here some reading to start.

Unit / Integration / Functional testing

Usually the metaphor of a Pyramid is used to describe the impact of the different testing techniques and how speed, ROI, cost and other aspects are related to them. There are several “Pyramids” with some variations, but usually it starts with “unit test” on the base of the pyramid, followed by Integration and ending with functional testing, where the base provides the biggest benefits and the rest is built on top of that. (here an interesting article with a variation of this. The practical test Pyramid by Ham Vocke)

Definitions

Comparison

I’ve found this incredibly clear table for the first two types to show you the characteristics of both techniques on the “Software testing class” website.

Unit TestingIntegration Testing
Unit testing is a type of testing to check if the small piece of code is doing what it is suppose to do.Integration testing is a type of testing to check if different pieces of the modules are working together.
Unit testing checks a single component of an application.The behavior of integration modules is considered in the Integration testing.
The scope of Unit testing is narrow, it covers the Unit or small piece of code under test. Therefore while writing a unit test shorter codes are used that target just a single class.The scope of Integration testing is wide, it covers the whole application under test and it requires much more effort to put together.
Unit tests should have no dependencies on code outside the unit tested.Integration testing is dependent on other outside systems like databases, hardware allocated for them etc.
This is first type of testing is to be carried out in Software testing life cycle and generally executed by developer.This type of testing is carried out after Unit testing and before System testing and executed by the testing team.
Unit testing is not further sub divided into different types.Integration testing is further divided into different types as follows:
Top-down Integration, Bottom-Up Integration and so on.
Unit testing is starts with the module specification.Integration testing is starts with the interface specification.
The detailed visibility of the code is comes under Unit testing.The visibility of the integration structure is comes under Integration testing.
Unit testing mainly focus on the testing the functionality of individual units only and does not uncover the issues arises when different modules are interacting with each other.Integration testing is to be carried out to discover the the issues arise when different modules are interacting with each other to build overall system.
The goal of Unit testing is to test the each unit separately and ensure that each unit is working as expected.The goal of Integration testing is to test the combined modules together and ensure that every combined modules are working as expected.
Unit testing comes under White box testing type.Integration testing is comes under both Black box and White box type of testing.

You can think of it in this terms, both features (door and lock) work perfectly as separated units, but the integration fails.

TDD

Testing is so important that a particular development process relies on writing the test first and then write the code to pass them called Test Drive Development! Of course it might sound crazy as many of the Extreme programming related techniques but indulge me and think about this:

If you have a detailed specifications about how your software/feature should work. What if you first think about how the feature should be tested to make it “testable” and “reliable”, then write the abstract tests it’s supposed to accomplish, as a contract, and then start thinking about the actual code for the feature and finally write it. … Those steps forced you to think before coding, and especially made you concentrate on how to make your code more testable first instead of writing it and having to iterate on refactoring sessions because is not testable and maintainable enough.

Testing Frameworks for JavaScript

The market provides innumerable resources for testing your JavaScript apps, they can be suitable for Unit testing, integration testing, automated testing, for UI/E2E, etc. Each one has its pros and cons and some are designed for specific libraries like QUnit was for jQuery and some are more robust and generic like Jest but most of them evolved to cover more techniques or died in the way.

Here a list of unit testing frameworks in Wikipedia

Debugging

So you think that testing your code will be enough huh? LOL not even close, even when you enter a green field (as opposite to legacy code) you’ll end up having to deal with “dammit, where the heck is the error?!!!” Some can be detected with the introduction of more accurate tests, and some will escape from every testing attempt leaving you with the happy task of hunting them with creativity, but don’t despair, there are several tools to assist you.

Debugging is the process of finding and resolving defects or problems within a computer program that prevent correct operation of computer software or a system.

Debugging tactics can involve interactive debugging, control flow analysis, unit testing, integration testing, log file analysis, monitoring at the application or system level, memory dumps, and profiling.

Source: Wikipedia

Get familiar with the tools available, use them, learn them as you learn how to use your IDE, they’ll save you a lot of time.

Debugging tools available for JavaScript

Global console object

MDN > Web APIs > console

One of the most used, misused, underused tools is the globally available console object in your browser. It has several methods (but the engineers insist on using just the console.log)

Node.js console

node.js > api > console

Similar to the consoleglobal object provided by Web Browsers but not quite the same.

debugger statement

MDN - debugger

The debugger statement invokes any available debugging functionality, such as setting a breakpoint. If no debugging functionality is available, this statement has no effect.

node.js debugger

node.js > debugger

An out-of-process debugging utility accessible via a V8 Inspector and built-in debugging client.

Browser’s developer tools

Chrome DevTools

Every modern browser will provide you with a battery of tools to inspect and debug your web applications. Network traffic, memory usage, performance, code debugging and many more tools will be available for you to understand how your app behaves on that specific browser.

IDE interaction with a browser to debug

Some modern IDEs provide you extensions to be able to use an external browser debugger for your code without leaving your IDE or the other way around, testing an app running in your browser using the IDE debugger.

e.g. Chrome Debugging for VS Code

Transpilers

We saw during this walk that the features defined by ECMAScript might not be implemented in all JavasScript engines. How do we write our code in e.g. ECMA2019 and make sure it’ll run on Edge? Transpiling it.

What’s a transpiler? essentially a program that takes a source code as input and returns a source code to match a target system, e.g ES2019 to ES5 or TypeScript to ES2015. This technique let’s you write your code in one consistent way and choose how to create an output for a specific target without taking care of many sources.

One of the most used transpilers for JavaScript is Babel

Here you can see how a simple generator example taken from MDN is transpiled by Babel

Original:

function* generator(i){
  yield i;
  yield* anotherGenerator(i);
  yield i + 10;
}

Transpiled:

"use strict";

var _marked =
/*#__PURE__*/
regeneratorRuntime.mark(generator);

function generator(i) {
  return regeneratorRuntime.wrap(function generator$(_context) {
    while (1) {
      switch (_context.prev = _context.next) {
        case 0:
          _context.next = 2;
          return i;

        case 2:
          return _context.delegateYield(anotherGenerator(i), "t0", 3);

        case 3:
          _context.next = 5;
          return i + 10;

        case 5:
        case "end":
          return _context.stop();
      }
    }
  }, _marked);
}

You can try it out here.

Task runners, bundlers, build systems

Well, we went through testing, to testing frameworks to transpilers but how in the world do I make them work together?

JavaScript became a huge ecosystem with many tools and techniques for delivering the code like testing, minification, bundling, linting. Here below I’ll list some; each of them provide different features which might be broader (like webpack) or more dedicated to a specific task (like grunt)