Monthly Archives: July 2019

What’s a PWA?

What’s a progressive web app (PWA)?

A progressive web app is a special type of web application (a software application that you use in a web browser). It maintains some functionality even when you’re offline. It can also be installed, like an app, on your cell phone.

Why take the trouble to develop a technology that makes it possible to use a web app offline, and make it act like an installed app on your cell phone? This may not seem useful, at first glance. Many web applications, like gmail, started out at home in a web browser, being used on a desktop computer. On desktops, you’re usually working online, so why take the extra effort to deal with the rare Internet outage at home?

Well, more and more people are using web apps on mobile devices. Even if you live in a heavily populated area, you may find that once in a while you get no Internet service on your cell phone. For most applications, that puts a hard stop to many of the uses for your phone. It’s frustrating for users. In some cases, a web app doesn’t really need a constant Internet connection to be useful. For example, you may want to visit your email client in a web browser to write an email even if you’re offline. You can queue up the draft to be emailed later, when you enter an area where data service is available.

This is where Progressive Web Apps (PWAs) enter the picture. If you run a web application that could be useful to people even when it’s offline, it can make sense to turn your app into a PWA.

Why Not Build a Native App?

If you’ve already built a web application, you could also build a native app for your users (an Android app, for example). From the provider’s viewpoint, this can be a big project – building a native app requires an entirely different set of development skills from web development, and it’s an additional cost. Aside from that, there’s a hurdle for users to install a native app, even if you’ve taken the trouble to build one. They have to go to the Google Play store, search for the app, wait for it to download, and then they might find that it’s not used very often or it’s just taking up space on their phone, so they wind up uninstalling it.

What if it were possible to download a “light” version of an app directly from the web app’s website? That’s what you can do if you build a PWA.

Properties of a PWA

According to Google’s Developers site, my PWA must fulfill some requirements:

  1. It must run in a web browser and as an app in mobile devices.
  2. It must be “fast and reliable” (even native apps aren’t always fast and reliable, so this requirement is a bit funny!). This just means it loads really fast, and does something useful even if you aren’t connected to the Internet. No “ERR_INTERNET_DISCONNECTED” errors like you’d get when your browser is offline, please.
  3. It must be installable. When installed, it appears in Android’s “Apps drawer” (where all apps are listed), and you can add a shortcut to it on your home screen (or desktop on a PC). When running on a mobile device, it’s a top-level app in the task switcher.

What you want, more than anything, is just to make sure that the web app does something useful when the user is offline. Instead of seeing a blank page with an error message, you get some functionality. You also want it to be easily accessible (hence installable) for people who will want to use it frequently.

How to Build a PWA

I’ve written a page which explains how to build a PWA, step by step. Take a look there if you’d like to follow the tutorial.

how to port your LAMP PHP 5.x web app to AWS in an afternoon

In the past, I’ve thought about moving a web app that I run to Amazon AWS, so that it runs in the “cloud”. I haven’t been very tempted, though. I think it will cost more than what I’m paying to my current, managed web hosting service. I also think it will be more of a pain to deal with AWS. My hosting services manages pretty much everything: email, SSL certificates, domain name registration, etc. The cost is only about $100/year.

Despite these misgivings, I decided to try migrating my application, just to see how much work it would be. I also thought it would be a fun experiment, and that I’d get a feel for running a service in the cloud.

The post is rather lengthy, so I set up an entirely separate web page about how I did it. If you are interested in AWS, and maybe were thinking of doing something similar, read about how I migrated my web app here.

Although I did get my web app to run successfully on AWS, I don’t think I’ll move it there. I’m very happy with my current web hosting service.

About those JavaScript performance tests

In my last couple of articles, I wrote about some simple performance tests to compare Array.some with a for loop. I noticed that the for loop ran substantially faster the second time it was called in my process, while Array.some did not.

This got me curious. I wanted to know what was happening, so I dug around a little bit. It’s the kind of behavior that can be pretty tough to track down. I started with freenode for #Node.js. I described what I’d seen and got some feedback. I didn’t find a definitive answer, although I did get a clue. I was told essentially that “microbenchmarking” is pointless, and one should just write maintainable code, and let the JIT compiler worry about performance. I was directed to Mr Aleph‘s website. Mr Aleph is a compiler engineer and enthusiast, and I found a lot of interesting articles at his site.

In 2012 already, he had written a microbenchmarks fairy tale. It turns out that the V8 JavaScript engine compiler performs various optimizations that can produce misleading benchmarks. As an example, he talks about LICM (“loop-invariant code motion”). Oh god, the jargon! But he gives an example, which I’ll explain now.

Prior to working with JavaScript, I was a Java coder. In Java, one commonly writes for loops like this: for (int i = 0; i < arr.length; i++) {...}.

When I was getting started using JavaScript, I was told to assign Array.length to a variable outside the loop, and then reference the variable in the iteration, like this:

var len = arr.length;
for (var i = 0; i < len; i++) {
    ...
}

The reason given was that JavaScript is an interpreted language, and it will evaluate Array.length on every iteration over the loop! Sounds wasteful to me. So I’ve been dutifully, manually setting a variable to Array.length outside my loop ever since then.

Java developers don’t need to do this, because Java is a compiled language. The compiler performs optimizations behind the scenes which basically do what I was doing manually in JavaScript.

Flash forward to 2008-ish, about 10 years ago, when Google Chrome was launched, integrated with the V8 engine. If you thought I’d gotten off-track, I’m now back on it. According to Mr. Aleph, the V8 engine uses LICM, and LICM performs the optimization I’ve been doing manually in assigning Array.length to a variable outside the loop. And that’s just the tip of the optimization iceberg.

If you want to read more about the V8 engine, there’s an excellent series about it written by Alexander Zlatkov in 2017. Start with How JavaScript works: inside the V8 engine + 5 tips on how to write optimized code. You should also take a good look at Mr. Aleph‘s articles.

Once JavaScript is not strictly being interpreted, trying to benchmark and optimize your code manually is probably just a mistake. Mr. Aleph’s conclusion, in 2012, was

The time when you could have easily guessed the cost of a single operation by simple observation is over. If you want to know something then sometimes the only way is to go and actually learn it from the inside out.

Mr. Aleph, “microbenchmarks fairy tale“, 2012

My own conclusion is that you should not think you are going to outsmart an optimizing compiler. Just write code which is readable. If, at some point, you notice bottlenecks, that’s when it makes sense to dig for performance improvements.

But I’ll still move Array.length outside of my iterators 😉

Sort order for files in VS Code Explorer

I just noticed another small plus for VS Code versus Sublime Text. You can sort the files displayed in your “sidebar” (aka “Explorer”) in several different ways when using VS Code. Sublime gives you no choice.

I just noticed this today because I was working with a folder that had a lot of files whose names were almost meaningless to me. I just wanted to focus on which file(s) were most recent, so I’d know where to pick up editing the most recent ones. So I wanted to sort the files by “last modified date” or “date modified”. I didn’t care whether it was ascending or descending, as long as it was sorted by modification date. Most modern “file browsers” will let you do this. If you see a list of files, you may have gotten so used to this behavior that you expect to be able to sort this way, as well as alphabetically.

I just searched around and I find that at least one person was hoping for this in Sublime in 2014. So far as I can tell, there’s still currently no way to change the sorting of files in Sublime Text’s sidebar.

VS Code hasn’t been around for very long, but it does have several sorting options for the file explorer on the left hand side of the IDE. If you want to change it, click the upper left menu File > Preferences > Settings and search for “explorer.sortOrder”. A dropdown lets you select from five possible options:

  • default – Files and folders are sorted by last modified date, in descending order. Folders are displayed before files.
  • mixed – Files and folders are sorted by their names, in alphabetical order. Files are interwoven with folders.
  • filesFirst – Files and folders are sorted by their names, in alphabetical order. Files are displayed before folders.
  • type – Files and folders are sorted by their extensions, in alphabetical order. Folders are displayed before files.
  • modified – Files and folders are sorted by last modified date, in descending order. Folders are displayed before files.

I understand why Sublime doesn’t have this sorting option. When you’re a small dev shop, you have to make tough decisions all the time about what features you’ll support. With the backing of Microsoft, I can see why VS Code has a richer feature set.

VS Code Explorer using default sort order
VS Code default sort order on my Gimp 2.8 directory
VS Code Explorer using modified sort order
VS Code “modified” sort order on my Gimp 2.8 directory

A performance test of the JavaScript Array.some function in Chrome browser

Previously, I performance-tested the Array.some function in Node.js version 8.16. Node.js is usually used for running microservices as a backend on a server. It’s not identical to JavaScript running client-side, in the browser. So it’s also interesting to run the same kind of performance test in a browser to see if the results apply there, too.

The source code for this test is similar to what it was in my previous test using Node.js. There are some necessary differences. I wanted to use the same word list, but I didn’t want to fiddle with trying to get the browser to read from a file, which is complex at best and impossible at worst (for security reasons).

Instead, I decided to use XMLHttpRequest to grab the word list I’d used previously, which was handily available on a web page.

However, you can’t just open Chrome browser and run the code below. If you try it (and you might want to), you’ll see this error message:

Access to XMLHttpRequest at 'https://norvig.com/ngrams/count_1w100k.txt' from origin 'chrome-search://local-ntp' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Oops! The solution is to first surf to Norvig’s page, then open the JavaScript console with Ctrl-Shift-J, paste in the code below, and call runTest().

/* Displays results */
var finishAndPrint = function(words) {
    console.log("words length: " + words.length);
    console.log("First word: " + words[0]);
    console.log("Last word: " + words[words.length-1]);
};

/* This test function is guaranteed to never match a word in the Norvig list of words */
var testFunction = function(item) {
    return item === "gsdjkoeu";
};

/* A performance test using the Array.some method: */
var performanceTestSome = function(words) {
    let t0 = performance.now();
    let result = words.some(function(el, i) {
        return testFunction(el);
    });
    let t1 = performance.now();
    console.log("The some method took " + (t1 - t0) + " milliseconds and the result was " + result + ".");
};

/* A performance test using a simple for loop: */
var performanceTestForLoop = function(words) {
    let len = words.length;
    var result = false;
    let t0 = performance.now();
    for (var i = 0; i < len; i++) {
        if (testFunction(words[i])) {
            // This code is necessary so the function does the same thing as the "some" method
            result = true;
            break;
        }
    }
    let t1 = performance.now();
    console.log("The for loop method took " + (t1 - t0) + " milliseconds and the result was " + result + ".");
};

/* Read words from a URL and return the list of words */
var readTheWordsFromURL = function() {
    let myURL = "https://norvig.com/ngrams/count_1w100k.txt";
    var xmlHttp = null;
    xmlHttp = new XMLHttpRequest();
    xmlHttp.open( "GET", myURL, false );
    xmlHttp.send( null );
    return xmlHttp.responseText;
};

var runTest = function() {
    var data = readTheWordsFromURL();
    var words = [];
    var lines = data.split('\n');
    lines.forEach(function(row, i) {
        var items = row.split('\t');
        if (items[0].length > 0) {
            words.push(items[0]);
        }
    });
    finishAndPrint(words);
    performanceTestForLoop(words);
    performanceTestForLoop(words);
    performanceTestSome(words);
    performanceTestSome(words);
};

runTest();

I did this in Chrome browser Version 75.0.3770.90 (Official Build) (64-bit), on my Ubuntu 16.04 desktop. I used private mode to make sure no other tabs, plugins, etc. would interfere with the test.

These were the results the first time I ran the code:

words length: 100000
VM18:4 First word: THE
VM18:5 Last word: PGY
VM18:36 The for loop method took 2.8300000121816993 milliseconds and the result was false.
VM18:36 The for loop method took 0.5550000059884042 milliseconds and the result was false.
VM18:20 The some method took 3.064999997150153 milliseconds and the result was false.
VM18:20 The some method took 2.6000000070780516 milliseconds and the result was false.

I repeated the test (closed the browser, reopened it, and ran the test), but this time changed the order of the tests. I ran the some test first:

...
VM18:20 The some method took 3.5149999894201756 milliseconds and the result was false.
VM18:20 The some method took 2.5599999935366213 milliseconds and the result was false.
VM18:36 The for loop method took 2.599999977974221 milliseconds and the result was false.
VM18:36 The for loop method took 0.670000008540228 milliseconds and the result was false.

Huh! I tried it again:

...
VM18:20 The some method took 3.5499999939929694 milliseconds and the result was false.
VM18:20 The some method took 2.634999982547015 milliseconds and the result was false.
VM18:36 The for loop method took 2.449999999953434 milliseconds and the result was false.
VM18:36 The for loop method took 0.5299999902490526 milliseconds and the result was false.

And again:

...
VM18:36 The for loop method took 2.9750000103376806 milliseconds and the result was false.
VM18:36 The for loop method took 0.5549999768845737 milliseconds and the result was false.
VM18:20 The some method took 3.939999995054677 milliseconds and the result was false.
VM18:20 The some method took 2.789999998640269 milliseconds and the result was false.

I ran another test case, just running the some method only. The result took 3.429999982472509 milliseconds. A test with just the for loop running once took 2.905000001192093 milliseconds.

The only conclusion I can draw is that Chrome doesn’t quite perform as well when running some instead of a simple for loop. The difference is not huge, and there’s some variation. This test runs over 100K words, and it still only takes a few milliseconds either way.

The results are similar to those in my previous post, which described a similar performance test using Node.js. This comes as no surprise, because Node.js runs on V8.

On the first run, it looks like a for loop performs a bit better than the some method. There’s some optimization on the second run. This is all déjà vu, if you read my last post.

Is it worth using a for loop everywhere to take advantage of that optimization? I think you’d really want to go deeper in your performance tests to understand the optimization, and make sure that it will be used before deciding to go with for loops everywhere. You will also want to be sure that it’s worth sacrificing code maintainability and readability in pursuit of some possibly minuscule performance boost.

It’s important to be aware of the potential for any performance impacts of special Array methods when architecting a new project or looking for bottlenecks in an existing one. But deciding never to use Array iterators just because you heard a vague rumor that they were not performant is unwise.