Simon's Blog

Dev vs Ops - Case Sensitive Operating Systems

March 07, 2021

Series Introduction

I am starting a series of articles exploring issues at the line between Development and Operations.

In the past few years this middle ground has started being filled with DevOps Engineers. I believe that whilst DevOps is the logical next step in how we package, run and monitor our software, ever since it has no longer remained part of a software developer’s workflow it has caused Operational and Deployment issues to become “someone else’s problem”.

This encourages developers to care less about how or where their code is run, so as long that it runs on their machine.

Dev vs Ops aims at re-blurring this line, documenting issues I resolve as I work on my DevOps skills. I believe that all software engineers should have at least a cursory understanding of how and where their code will run, without needing to become Kubernetes experts.

Introduction

I was working on a NodeJS project written in TypeScript.

One of the files had an import written as follows:

import shortid from 'shortId';

Nothing out of the ordinary, and the code builds! Works on my machine! I submitted the code for review, it got approved and merged into our develop branch.

Our CI tool (in this case, Jenkins), dutifully detected a new merge on develop and started building the code for deployment onto our development environment.

The build failed and amidst the logs I found the following error (paraphrasing):

No module called shortId.

🤔

I double checked both package file and lock file to be sure I was not being bitten by something at runtime rather than at buildtime, however shortid was clearly present in both.

Blurred Line

It did not feel like a code problem and I did have a sneaking suspicion scratching at the back of my brain that this issue resided at the boundary between Dev and Ops, so I put on my metaphorical debugging hat.

What is the main difference between my machine and Jenkins?

The first that comes to mind is that my machine is a 2019 MacBook running MacOS whilst Jenkins is on a Linux machine. Is there potential for difference in behaviour between these two systems?

I felt close to a solution but also a bit hesitant. I did know that we package all our software as Docker containers and that Jenkins did basically that: build the Docker container and push it out to AWS.

To confirm whether it was the host system or the process of building the container, I decided to build the docker container locally. This was trivial to do as the Dockerfile is in the same repository.

Build failed! Does not work in my container!

From the Dockerfile I could see that we were using the node-alpine Docker image as a basis for our image. This convinced me that the issue was an incompatibility between running it on MacOS and running it in Linux, just not because of the machine the CI was running on as I originally thought was the issue.

Solution

The issue turned out to be case-sensitivity. Whilst MacOS tolerated shortid being written as shortId, Alpine only began accepting the import once I renamed the import to shortid.

Had I kept the mindset that anything that happens that is not on my machine is DevOp’s concern (or fault), I could have easily wasted everyone’s time and caused unnecessary friction between our teams.

Takeaway

Be aware of how your code is packaged and will be run - it is still your responsibility even if its not on your machine anymore!

Kudos to Daniel D’Agostino for the article review.


Written by Simon who lives in Malta. You can find out more about me on the about page, or get in contact.