Gradle 5.0 and Runtime Dependencies

I recently ran into a problem with CI, where an upgrade to Gradle 5 in their containers broke all of my builds. It seemed like some of the nested dependencies weren’t being downloaded and therefore not found at compile time, so I was getting a ton of Java compilation errors:

package xxxxx does not exist.

My leading theory is this was a consequence of Gradle 5 separating out compile and runtime dependencies.

So, I suspect that some of my dependencies list their dependencies as runtime dependencies, which had previously been included at compilation time by default. However, with Gradle 5 not doing that anymore, the nested dependencies were not being downloaded at compile time and therefore missing. Since I don’t have control of these third-party libraries, I had to explicitly list the missing dependencies as my own compile dependencies to work around the compilation errors.

Angular In-Memory-Web-Api For E2E Testing

Recently, I updated an Angular app with an HTTP interceptor to handle HTTP exceptions, from this tutorial — what an amazingly simple way to add that kind of feature! While adding an alert window to notify the user of a failed REST call was simple, I then found out that my e2e tests with Protractor failed because I didn’t have a live backend during the tests … which meant that my alert windows popped up automatically during each e2e test. I couldn’t figure out how to mock out my REST API, though. nock wasn’t working at all, and it seems like Angular took out their $httpMockBackend (plus Protractor doesn’t play well with it, even if it was still present).

Then, I stumbled upon the In-Memory-Web-Api for Angular, and it seemed like the perfect solution. However, turns out it doesn’t automagically work for nested REST URLs, i.e. api/namespace/resources and api/namespace2/entities — it has a very strict expectation for the REST API pattern by default, which I didn’t understand from the documentation. It assumes that the first path element after the apiBase (in the config) is the collection name, and the second is the element id — for example, namespace would be the collection and resources the id of a given namespace entity. i.e.

   GET /api/resources
   GET /api/resources/1

would work with the default methods, but

   GET /api/students/resources
   GET /api/students/resources/1
   GET /api/teachers/resources
   GET /api/teachers/resources/5

would require some customization.

So if your API pattern is a little different, you have to get creative. What I wound up doing was to parse all the get requests per my own pattern, similar to this example, which is duplicated below:

  // HTTP GET interceptor
  get(reqInfo: RequestInfo) {
    const collectionName = reqInfo.collectionName;
    if (collectionName === 'villains') {
      return this.getVillains(reqInfo);
    }
    return undefined; // let the default GET handle all others
  }

You can also create a custom URL parser, which is probably cleaner than my hack. Code duplicated below:

  // parseRequestUrl override
  // Do this to manipulate the request URL or the parsed result
  // into something your data store can handle.
  // This example turns a request for `/foo/heroes` into just `/heroes`.
  // It leaves other URLs untouched and forwards to the default parser.
  // It also logs the result of the default parser.
  parseRequestUrl(url: string, utils: RequestInfoUtilities): ParsedRequestUrl {
    const newUrl = url.replace(/\/foo\/heroes/, '/heroes');
    // console.log('newUrl', newUrl);
    const parsed = utils.parseRequestUrl(newUrl);
    console.log(`parseRequestUrl override of '${url}':`, parsed);
    return parsed;
  }

Installing Angular Custom Libraries Locally With NPM

For one of my projects, I’m using Angular with a custom library called services, which I share across several apps (all in a monorepo). I then link the built version of services locally via npm link, so it appears in package.json as a dependency (this looks like "services": "file:dist/services").

However, when I tried consolidating the code and running it through CI, I kept running into an error when running $ npm install:

#!/bin/bash -eo pipefail
npm install
npm WARN checkPermissions Missing write access to node_modules/services
npm ERR! path node_modules/services
npm ERR! code ENOENT
npm ERR! errno -2
npm ERR! syscall access
npm ERR! enoent ENOENT: no such file or directory, access 'node_modules/services'
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent

npm ERR! A complete log of this run can be found in:
npm ERR!     ~/.npm/_logs/xxxxx-debug.log
Exited with code 254

Even if I created node_modules/services before running $ npm install, I would get the same error. Turns out that because "services" is a locally installed module, npm tries to create a symlink from node_modules/services to dist/services — which doesn’t exist in a clean CI container. Chicken-and-egg problem (can’t run $ ng build services to populate dist/services without having the other NPM modules installed). So I actually had to create dist/services manually before running $ npm install. Oops!

Angular Component Libraries

I’ve recently been learning to use Angular for work, building simple UI tools with it. I like the framework — different than React, but similar goal of creating re-usable components.

One neat thing with Angular 6 is the ability to create your own libraries! This was useful to me, since I was creating three similar apps with many shared UI components (i.e. a table with selectable rows). This is apparently behavior that was previously supported by a separate library, ng-packagr, and then rolled into the Angular CLI with version 6.

As of right now, though, the documentation for the feature is a bit fragmented. Most of the CLI commands to create libraries are contained in this wiki page of user stories (and otherwise briefly mentioned in various GitHub issues), and some of the details can only be found on the original ng-packagr docs. For example, I wanted to create sub-packages (or secondary entry-points), so that I could do something like:

import { MyComponent } from '@mylibrary/subpackage1';

The ability to do this is briefly mentioned in the ng-packagr docs, though not mentioned in the Angular 6 CLI page explicitly. So don’t forget to check the original documentation if there is library functionality that you’re looking for!

CLIx Wins UNESCO Award

Wow! One of my projects — the Connected Learning Initiative (CLIx) — has just won a major UNESCO prize! You can read more about it in these press releases:

https://en.unesco.org/news/projects-india-and-morocco-receive-unesco-king-hamad-bin-isa-al-khalifa-prize-innovation
https://news.mit.edu/2018/mit-clix-project-receives-unesco-award-0313

It’s been amazing to watch this project grow from potential (the agreement will get signed soon) to reality (let’s start working!) to implementation (ship it to the schools) over the last five years. I’m proud to have been part of such a large ed-tech collaboration, since usually we talk about a handful of schools for a research project. Hundreds of schools and tens of thousands of students for an initial rollout boggles my mind.

Corny Quantum Jokes

So I don’t know why inspiration struck in this way, but some (very) corny quantum computing related jokes popped into my head recently. I’ve seen some pretty deep ones about Heisenberg, Einstein, etc., but mine are definitely on the cornier / shallower side. Here are a couple … maybe some day I’ll draw them up as one-panel cartoons. I think they might present better that way, if I could ever figure out how to draw a qubit:

  • A qubit is laying on its therapist’s couch. Therapist: “Tell me what’s been bothering you.” Qubit: “Nobody understands me…”.
  • A police officer pulls over a speeding car. By the time she walks up to the driver’s side window, the driver has disappeared. Instead, she sees a sign taped to the window. “Sorry officer, it seems like I’m in a different state right now. Better luck next time.”