Learnings from patching a bug in a modern project

I’m continuing to dive deep on modern typescript/node development. I fixed a bug in a new tool I am using (projen) and learned a ton along the way. This post is to share some of that.

If you have followed me lately you know that I am developing code for telephony again (and loving it! Want to work in my group? We’re hiring!. A big part of this is developing the deployment automation that goes with the application - the “infrastructure as code” part of the solution. I am all-in with the Amazon Cloud Development Kit (CDK) and I’m very excited about a new book that just came out, appropriately titled “The CDK Book”. If you are serious about using the CDK stop reading this and go buy it. Seriously. You need it.

I especially like the section on levels of abstraction using “constructs.” That’s a post for another day. The book describes how to easily build and publish a CDK construct as an npm module. The authors of the tool don’t believe in templates (yikes!) and prefer a tool to build a templated repo for you. That’s where Projen comes in.

Projen aims to “define and maintain complex project configuration through code.” I believe the same thing about Infra and Operations, so I’m all in. I have to know more. I immediately did the “Getting Started” steps.

And it immediately blew up.

gherlein@ip-172-31-61-56:~/t$ npx projen new awscdk-construct
👾 Project definition file was created at /home/gherlein/t/.projenrc.js
yarn install v1.22.11
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
info fsevents@2.3.2: The platform "linux" is incompatible with this module.
info "fsevents@2.3.2" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 15.41s.

> t@0.0.0 eslint
> npx projen eslint

Error: Command failed: git init -b main
error: unknown switch `b'

I dug around a bit and verified that yes, it wants to do “init -b main” to set the default branch to main (not master). The right thing to do. More digging.

It turns out that git only added “init -b” as an option in version 2.28. I was working on an EC2 instance running Ubuntu 20.04 LTS. Behold:

gherlein@ip-172-31-61-56:~/t$ git --version
git version 2.25.1

This is quickly fixable, of course:

sudo apt remove -y git git-man
sudo add-apt-repository -y ppa:git-core/ppa
sudo apt -y update
sudo apt -y install git

But my new role is in my DNA now, and I don’t want other folks to have this friction. They at least need to know that it’s a known issue that they should upgrade. So I sent a Pull Request to edit the README. Very, very quickly I had a reply from @Chriscbr suggesting we revert to the older way of doing the git commands that accomplishes the same thing. Then @eladb quickly commented that maybe we should check the version and then do the right thing. Good call and Kudos to Elad and Christopher for being right on top of new issues.

Which now brings us to the point of my blog post. Find it, try to fix it, right? Plus, I really need to understand how larger, more complicated node projects are organized and what the workflow is to develop them.

Projen has an excellent page on contributing. I often don’t read those pages because they are T&Cs about licensing. In this case, it’s an excellent primer on how to go about setting up a development environment. Here’s the neat trick I learned extrapolated to any similar “tool” you will run with npx:

First, in your tool directory:

cd /path/to/local/tool/repo
yarn link

Then, in the folder you plan to work from:

cd /path/to/working folder
yarn link <tool name>
node_modules/projen/bin/<tool name>

The command “yarn link” creates a symlink at the global node_modules level. You can then directly run your tool from the command line.

Practicality of Approach

The projen example is a perfect way to build system-level tools using typescript. It seems pretty easy to make shell aliases to npx commands, and you can even run them directly from github without an install.. I can totally see building some tools to help me automate some of the silly things I seem to need to do on new machines. And I get new machines all the time. You should too. You are creating and destroying new EC2 when you need to do a quick test right? Having really easy automation makes it pointless to keep a dev server laying around.

Thoughts on Projen

I think I’m a believer now. I had looked around for some templates that could be a good starting point for development. I love how “cdk init” just works and projen give me that for many more project types. At least until something shows me otherwise I now fully support the #TemplatesAreEvil movement!.

Next Steps for Me

I think a logical extension of this will be to create projects at a higher abstraction level. The [CDK book] talks about Level 3 constructs:

For example, maybe you’ve adopted AWS Serverless and want to build all your APIs using API Gateway, Lambda, and DynamoDB. You could create a construct called MySimpleApi that creates a new API Gateway, Lambda Function, and DynamoDB Table L2 constructs according to your own specific architectural needs."

In this example, a L3 construct “MySimpleApi” is the atomic unit of operation and below it are hidden all the implementations.

“What if we could take something like projen, add some stock code and a configuration file and “synthesize” a fully working application? In the example above, if you add in all the HTML and code for the website you can get MySimpleWebSite and it’s a “one click install” (only no clicks, since I’m a command line kind of guy). I think there’s a lot of progress to be made around this area and I can’t wait to learn more!

Shout Outs

Key contributors to projen and cdk - super helpful guys who were immediately responsive:

and to Court, who turned me onto the CDK Book and constructs:


This blog does not represent the thoughts, intentions, plans or strategies of my employer. All opinions here are purely my own.