Wednesday, September 14, 2022

Deciding on a web server

As a long-time software engineer, I've been party to more debates than I care to on the topic of which framework and/or language is the best one to use in a particular situation.

Real talk: Usually there's more than one perfectly fine option that will get the job done, which is the most important thing.  Ultimately the direction you go tends to wind up being matter of personal preference.  If you're starting a company or growing a team you might consider the type of engineer you want to hire on to help, and what kinds of technologies/languages would be best suited for that.  But, for this project, I expect it will just be me for now, so I wanted to pick technologies that would work best for me and get the job done.

One of my first technical decisions in building sportsmap.world was deciding what to use for a web server framework.  I knew I wanted one that could run a regular data collection job to query my sports schedule data source, store the query results in a local database instance, offer those results via an internal query endpoint, and serve it all up via web front-end endpoint.  I investigated a few possible choices, including Tomcat/Apache (which I was familiar with from working on Tableau Server), Jetty server, Node.js, Nginx, and Open Liberty.

Apache could definitely do everything I wanted, and familiarity with it was a plus.

Pros: 

  • Can code in Java, which is a more mature language with well-supported official frameworks and libraries.  
  • Works great with IntelliJ, my favorite IDE.  
  • Testing with JUnit feels like a snap and is also well-supported in IntelliJ.  
  • Attaching a debugger to root out problems is a lot easier.

Cons: 

  • Java is seen as antiquated in some circles, which isn't entirely fair.  I feel like it can get any job done pretty well, although it can feel like there's too much boilerplate code for simple things; some of the more modern Java features help alleviate this.  Still, it might not be the first choice for a startup-type environment, which is more what I'm going for.  
  • Spring tries to be one framework to rule them all, and I like it in some contexts, but I also find its paradigms around dependency injection to be pretty confusing and hard to configure correctly.  

Node.js, meanwhile, is a lighter weight option that I've mostly only used in testing and doing quick one-off projects.

Pros: 

  • Quick to spin up.  
  • It is a well-supported framework at this point.
  • The Express library makes it easy to add endpoints.  
  • There are a ton of open-source options to add functionality.

Cons: 

  • Server code written in JavaScript?  On my computer?  Extending the hastily conceived JavaScript beyond the world of browser front-ends feels like a mistake (although Typescript does address most of my concerns).  
  • Debugging is a chore and not well-supported.  IDE debugging is technically possible but difficult to set up -- I haven't even done it yet -- so I tend to rely on console logging, which feels like several steps backward.  
  • Visual Studio Code is not bad, but still doesn't feel as solid as IntelliJ.  
  • Although there are a lot of open source libraries, many of them tend to fall out of date or become unsupported over time, so managing dependencies could be challenging in the future.
Ultimately I chose Node.js for its light weight, and it's actually been a more solid environment than I expected.  So far I actually prefer the Node.js developer experience over React, which is surprising given the original purpose of JavaScript.

My early set-up steps were fairly simple:

Fairly quickly, I was able to build and run, and get a "Hello world" response from a listening port.  Ultimately, my backend runtime dependency list wound up looking like this:
  • Axios for making external API requests via HTTP
  • axios-rate-limit to avoid flooding external API endpoints
  • cors for allowing internal requests to server endpoints
  • dotenv for enabling .env configuration files, good for storing local development settings and API keys
  • Express
  • luxon for handling time-based calculations and time zones more gracefully than native JavaScript (a replacement for moment,js, no longer supported)
  • node-pg-migrate, for postgres schema migrations
  • pg, for postgres operations
Using those libraries, I have a server that makes external API calls on a set schedule, stores the query results in postgres, and provides endpoints the front end can call.  Additional libraries allow for testing and verifying operations against postgres.  It all manages to feel quick and lightweight but also robust and reliable enough for what I wanted to accomplish.  So overall, I've been satisfied and pleasantly surprised with Node.js.