If you’d like to start a new Express app, there are thousands of articles on how to do so. Most of them, targeting beginners, include all the code in one or two files. Although, technically correct, these articles are quite lax on good practices. In no particular order, I’d like to address the address a couple of them.
App Start Up Issues
The API/web endpoint accepts requests before a database connection was established. Usually, the offending code would be structured like this:
Because, in node.js, almost all the calls are asynchronously, your app will start listening for connections before the database connection was established. Although this might not be a problem when developing the app, it’s a different story when deployed in production. A fast start up time might be 300-500 ms, connecting to redis and mongodb, might take 600 ms or more. Are you sure there are no incoming connections in those 300-600 ms your app takes to start?
A minimal fix, would delay the listening for connections part until the database connection was established.
No Setup For Connecting to Multiple Databases/Services
Most examples connect to zero
or one database/service.
These are fine, simple examples, however I’d like to make them a bit more complex. First, your router should not require your model. If really what to do that query in your router, at minimum, you should pass in the router and model as a dependency.
If you’re inclined to, you’d have a chance to mock router and/or the model, to test them independently.
If one would like to go further, model and/or the redis client can be further refactored into a
store.js file that will handle the databases interaction. For example, return a cached version of the articles, and only if none is found, query the database. Maybe also store the last result for 10 seconds.
To write a unit test for the above code, one would start with
store.js. The npm packages
redis-js could be used to setup an in-memory database for mongo and redis.
Using the same technique, one can inject any type of service that requires configuration and setup (eg. RabbitMQ, Push Notifications Services, websockets). If at a later point, one would like to replace redis with memcache, it shouldn’t be a
require('redis') in every file.
Tight Code Coupling
Or as seen in almost every online example
require the same local or external module in every file.
can be replaced with
The same can be applied to app.js.
And even to config.js. Beside all the connection strings (mongo, redis, etc), one can use this file to assign a release version to the current app. This maybe be useful if one needs to pass in that info to other services, like sentry.io.
Using the presented building blocks, when setting up an app, a start module can be build, so all the services start only after the required connections were established.
It is a good practise that when writing a new service, one should answer the question, how should this new code be tested? Today, all the cool kids use mongo, but tomorrow, they go hipster and switch to FoxPro.
We, as developers, craft bespoke apps that connect to remote servers, over encrypted connections. Those connections are authenticated using API keys, username and passwords or public certificate and private keys. Sometimes, those connections work out of the box, sometimes we’ll spend 6 hours figuring out what’s wrong.
The easiest way to establish a plain text connection from the terminal to a server, is to use telnet
then issue a HTTP command like
GET / and you’ll get Google’s homepage, which will be a redirect to a HTTPS version of the same page.
To establish a SSL connection, you can use the
openssl Swiss knife.
and then issue the same HTTP command
GET / and you’ll get the HTTPS version of the Google homepage.
OpenSSL can be used to open a connection that requires certificate authentication too, just supply those as CLI options. This way you can test that the Apple Push Notification connectivity, by using your developer certificate and private key. Just make sure that they are converted to the PEM file format first.
After you’ve figured out which developer certificate and which private key are still active and match your remote server, you can establish the same connection from PHP.
In most of the cases, after running this script, the output will be
However, if you’re unlucky, you’ll get the following output
After you double check several times, you reach the conclusion that you’re using the same certificate, key and CA certificate as above. You’ll start wondering if there is a difference when the connection is made using
openssl s_client and PHP’s
One of the ways to get a glimpse into what each program is doing, is to use DTrace if you’re lucky enough to use one of the OSes where’s available (like MacOS X, FreeBSD or SmartOS) or to use its poor friend strace.
After a careful check of those file’s output, you’ll notice that OpenSSL and PHP are using two different CA stores. Open SSL’s
/usr/lib/ssl/certs/, versus PHP’s
/usr/share/ca-certificates/mozilla/. You can spot this by checking what happens before getting the
stream_socket_client(): SSL operation failed with code 1. error message:
After figuring this little difference, it’s pretty easy to fix the PHP code. Change the
stream_context_create to include the new CA path:
Tip o’ the hat to Ben Hearsum’s Python and SSL Certificate Verification article for suggesting to use strace to figure out why do we get different results, while using the same certificates.
A couple of years ago, I bought a nice Danish watch, Skagen 597LSLB. It wasn’t a very expensive watch, but it was a pretty one. At that time, I paid about €120 for it.
Fast forward a couple of years later, some parts of the watch do not seem to be that solid. The leather band started to peel off, like an onion. It’s quite unfortunate that this happened, having in mind that I did not wear this watch every day, since I got it, but only about half of those days. We all know that things are not built as they used to be and that we’re living in a consumerist world, so nothing new so far. One would assume that getting a leather band replaced, shouldn’t be a big deal though. However, it seems that the folks running Skagen could not be bothered to sell any watch accessories anymore. Since they do not offer a replacement on their site, your only option is eBay or a third party company.
A couple of days later, the battery ran out (for the third time since I got the watch). That’s fine, they are not designed to last forever. Let’s check Skagen’s site again, to find out what battery should I buy. Again, I was out of luck, as I could not find that info online.
To save others the trouble of researching this bit, I’ve written this blog post. The Skagen 597LSLB watch model is using a SR616SW/Renata 321/Energizer 321 cell.
Here is a photo of the watch’s internals, in case you’re curious about the built quality.