(Bear with me, or just skim through to the next section.)
In 2015, I began learning to become a square dance caller. 🎤🕺🏻 Square dancing is a fun hobby and social outing, and I was ready for a new challenge. As I learned the mechanics of calling a dance though, I was constantly thinking “I can write an app to help with this.” 🤔
As a software engineer by day, I found that my career was moving from writing Java backend applications, to writing full-stack web applications. There were some gaps in my knowledge to make this leap.
Thus in 2016 a fusion of purposes was born. I would write that niche app for square dance callers, and I would use it to expand my programming experience into new areas. 🎉 It would be far more interesting than yet another to-do app 😴, as so many others have written when they want to play with new technology.
I started playing the Dart 1.0, which seemed really cool yet also really immature. I tried Ionic 2, but ran into usability troubles; a framework on top of another framework was complex and documentation was poor at the time. So I went a layer down to the underlying framework, Angular 2. Material Design existed, but the Angular library for it was still being built and missing critical components, and so I chose Bootstrap 3 which was still popular at the time.
The application needed a simple backend to authenticate users, save their data, and allow for optional sharing. My early prototype was written in Dart, but ultimately I decided to use Typescript for the backend to pair with the Angular front-end. A bit of exploring brought me to Feathers, a framework that combines the Express.js web server with Passport for user authentication. I threw it up on a DigitalOcean droplet server, which is basically a tiny virtual machine instance with a persistent file system.
I want to provide a pretty diagram showing the existing architecture… but this is all there is:
Also, since this is a server there’s also a README file explaining how to configure the server, including:
- Auto-run the custom Feathers server. (Remember, it’s Express.js.)
- Setting up Nginx with SSL to proxy to the Feathers server,
- Cron job to rotate the Let’s Encrypt SSL certificate.
- Cron job to backup the user data to an S3 bucket; the one piece of AWS.
This is not Infrastructure as Code (IaC)! Rather, this is the kind of setup where one dreads ever needing to rebuild. At least I had the foresight to document the manual process. 🤷♂️ At the time, that was something.
After two years, the app reached feature completion, and I learned a whole lot about front-end development and square dance choreography during the journey. Occasionally, other people even run it!
Around the same time as that completion, I became a certified AWS Solutions Architect. I’m still using Angular for web apps, but the backend… the cloud… oh my! I can do so much better now.
And so the stage is set. I have an existing application and want to move it to AWS. This is the classic cloud migration, albeit at a small scale. What are my options?
Lift & Shift
The most straight-forward approach is to setup an AWS Lightsail instance running Ubuntu, follow my README instructions to setup a new server. Copy the data, redirect DNS, and I’m done. ✅
Advantage: Quick and easy.
Disadvantage: I accomplished absolutely nothing!
If I take this approach, I spent a day of my time so that I can pay a few dollars a month to Amazon instead of a few dollars a month to DigitalOcean. There’s been no gain. ¯\_(ツ)_/¯
What else can I do to take advantage of AWS?
- Move the user data to S3 or DynamoDB? Yes, then you can use EC2 instead of Lightsail.
- Move the web app files to S3 and serve it with CloudFront? Yes indeed!
- Run the Express.js app in a Lambda? Now we’re getting interesting, and fitting into free tier!
- Switch authentication over to Cognito? Oh yes.
When we start thinking like this, we leave the realm of Lift & Shift and head into…
Cloud native development is when an application is architected to work natively in the cloud, taking advantage of managed services. Cloud native is not exactly the same as serverless, but the two often go hand in hand; an ideal cloud native architecture often is serverless, requiring none of that server setup work in my old README file.
Not Merely Serverless
The ideas thrown out above would achieve serverless. Using Cognito, Lambda, S3, DynamoDB (severless-ish), and CloudFront would make for a serverless solution. I could do this very easily, as I have done many times before. It’d be easy, and I would learn nothing in the process. Moving my app to AWS this way would take more time than a simple lift & shift and it would save me around $5/month (vs DigitalOcean) because my usage would fall under the free tier for all those AWS services. I thought about this for about a year, but the time spent isn’t worth saving so little money and I wouldn’t learn anything.
There’s something newer hitting mainstream development though. I’m even giving a presentation about it next month for the local AWS User Group, and yet I haven’t done anything of substance with this newer technology stack yet. And so once again, three years after the last time, a fusion of purpose has been born. I will migrate my app with…
Coming next time….
I will explore my app’s requirements, and architect a solution using AWS Amplify.