Do Things Right with npm install

Lately I’ve been wrestling with npm. Here are some rules I’ve learned:

Use `npm ci` rather than `npm install`

`npm ci` will bring down exactly the dependencies specified in package-lock.json. `npm install` does more than that; it also tries to update some libraries to a more recent version. Sometimes it updates URLs or nonsense in package.json so that it my `git status` is dirty. Sometimes it does deduping. Sometimes it sticks the version you have lying around. I haven’t figured it out. It seems to be pretty dependent on the current circumstances on my file system.

Now I only use `npm install` if I specifically want to change the dependencies in my filesystem.

Use `npm install –save-exact`

Especially for snapshots. Semver does not work for snapshots or branches or anything but releases. And npm only works with semver. If you are not using a release; if you publish with build tags or branch tags or anything like that; do not give npm any sort of flexibility. It will not work. Specify a precise version or else it will give you nasty surprises, like deciding some alphabetically-later branch is better than the master-branch version you specified.

Use `npm view` to check the status of a library

This is quite useful. Try `npm view ` and it brings to your command line the info you can get from the npm website. You can ask it for specific fields. To get the latest version of chalk:

$ npm view chalk dist-tags.latest
2.4.1

If you want to do anything programmatic with this info, the “do things right” flag for `npm view` is `–json`.

Try `npm ls` but then dig around on the filesystem

Exploring the dependency tree, `npm ls` is really cool; it shows it to you. You can see where you’re getting a specific library with `npm ls ` except that it doesn’t always work. In the end, I dig around in my node_modules directory, using `find -name .` to look for the real thing.

Other times I use my little node-dependency dungeon explorer game to see what version of stuff is where. 

These are just a few of the nasty surprises I’ve found moving from Java to TypeScript, from maven dependencies to npm. Dependency management is an unsolved problem, and the people working on npm have made huge improvements in the last few years. I look forward to more.

Reference: Typescript asynchronous sleep that returns a promise

I want some code to execute after a delay. I want to do this with promises, in TypeScript, asynchronously. Apparently this is hard. Here is the spell:

const sleepPlease: (number) => Promise<void> = 
    promisify( (a, b) => setTimeout(b, a));

const slow: Promise<string> = 
    sleepPlease(500).then(() => “yay finally”);

I imported promisify from “util”. setTimeout is built in, but its arguments are in the wrong order to naturally pass to promisify

Bring the data to the code, or the code to the data?

Object-oriented code was conceived as message-passing between objects. Service-oriented architecture emphasizes delegation to another system. The entire web is a whole bunch of requests flying around. There is one clear way to be efficient about this: stop waiting for results.

When we’re writing imperative code, we want to write the operations in the order they should happen. This is straightforward and makes sense to our brains. Pseudocode:

let filename = // calculate filename
let data = new File(file).readAllLines();
// filter the data
// summarize the data
// reformat the output
let status = new File("output").writeAllLines(newData);
println("done!");
sendEmail("done! status = " + status);
println("email sent");

This describes the order in which operations need to happen. The problem is, it is not efficient. We’re holding up a thread waiting for I/O. Take the part where we read lines from the file, for instance — we can’t proceed until we get that result back, right? the rest of our code needs that data.

There is an alternative.

Instead of bringing the data to our code, we can ship our code to the data.
With functions-as-values, we can send our code along with the request for the data. This frees up our thread to continue processing, and then our code can execute when the data is ready. When passed as a parameter, the code to execute after completion is known as a callback or a continuation.

Instead of waiting for the data to come back from the file read, we can pass the code that needs to operate on the data. That way whatever thread winds up with the data can execute the code: code and data are brought together.

The pseudocode example has three asynchronous operations. In each case we can change the rest of the code in the block into a callback.

let filename = // calculate filename
new File(file).readAllLines().andThen( { data ->
// filter the data
// summarize the data
// reformat the data
new File("output").writeAllLines(newData).andThen( { status ->
println("done!")
sendEmail("done! status = " + status).andThen( {
println("email sent")
})
})
})

When this executes, the filename is calculated, the read is triggered and then our program goes about its business doing whatever’s next. Everything needed to process the data is bottled up in that function we passed, that continuation. We’re passing the code to where the data is, instead of freezing the code in place until the data is available.

The idea of putting functions into values and passing them to the data, instead of bringing data back to the code, facilitates the message-passing that OO was based on. It facilitates a faster service-oriented architecture. It can make a faster web. JavaScript is all over this technique; AJAX and Node.js use this principle.

Continuation style is a lovely combination of imperative style — everything happens in the order specified — with the functional concept of code-as-data. It frees the browser or the runtime to optimize and keep open threads busy.

If your reaction is, “yeah, but it’s fugly!” then look for my next post.

starting to maybe get the point of node.js

Listening to Glenn Block talk about node.js at Technology and Friends, there’s something interesting about the philosophy behind node.js.

Threads are hard. Threads include overhead, but more significantly, using them requires the developer to hold more stuff in his head. Node.js has a philosophy that leads to asynchronous processing without multiple threads.

Glenn explains how the node.js server is single-threaded, but all the APIs are asynchronous, using callbacks. All the incoming requests go onto one queue, and then whenever processing a request requires calling a service or doing I/O or anything that may take some time, that call is executed asynchronously and the callback goes onto the queue. Because there’s only one thread, developers don’t have to think about multithreading. Because of the asynchronous APIs with callbacks, the single thread doesn’t block waiting for anything. Concurrent performance without threading.

Here’s a speculation. This idea is implemented in JavaScript because the restrictions of the browser and the mechanics of JavaScript have driven us toward this event-driven, callback model in that language. It is natural, then, to take this idea to the server in the same language. Is this model, with a single thread and a queue of incoming requests and callbacks to process, implemented in any other languages in different frameworks?