Death, Taxes, and Database Migrations
In this world, nothing can be said to be certain, except death, taxes, and migrations.
Earlier in my career, I would come to a new project and inevitably a hectic migration would be underway. It’s not always a “stop the world” change, it can be as simple as switching from NPM to Yarn, but something is always changing. I used to naively believe my managers when they said cute things like “just this once” or “we’ll finally have our dependencies up to date.”
Let’s be clear about something. Migrations are here to stay, and while we can’t be rid of them completely, we can learn how to use them less painfully. I’ve put together a small list of guidelines that have helped me cope with migrations, and maybe they’ll help you too.
#1 Get the names right the first time
Naming variables is hard, but naming database keys and API behaviors is much harder. When you name something that other code and systems rely on, you either won’t be able to change it in the future, or that migration is going to be excruciating. I have a few rules of thumb on variable naming, so I won’t rehash all the details here. That said, here’s a tl;dr.
- Following existing naming conventions of the language or framework that you’re using. In Python, use
snake_case. - Single-letter variables have a place, and that place is rare.
- Include units in your variable names.
sleepTimeMillisecondsvssleepTime. - Include types in your variable names if it isn’t obvious.
createdAtis better thancreatedfor a timestamp. - Make the name as long as necessary but no longer.
- Include the meaning of complex calculations in your variable names.
- Use the properly pluralized form of the item.
- Don’t use abbreviations or acronyms without sufficient context.
- No magic numbers or magic values, use a variable.
I’ll mention one more that I’ve been thinking about recently. Just because product or marketing decided that your users are going to be called “friendly huggy bears”, doesn’t mean you should riddle your code with that name. If there is a more “standard” way to name an entity in your system, that might just be a good idea. Marketing teams are always changing their minds about what to call stuff. If they give you a ridiculous display name for something, maybe use a more descriptive and generic name in the code instead.
#2 Frameworks vs tools
Migrating from a simple tool, like moment.js or date-fns, is fairly easy. Migrating a single-page app from React to Vue is nearly impossible. In fact, you might as well just start over.
I’m not saying to never use frameworks, that would be hypocritical of me since I use Vue.js all the time. I’m saying you need to be okay being tied to your framework for the rest of your project’s life. There is a significant “lock-in” cost when using a holistic framework, and if you can get the job done easily without one, why use one? I write Go on the backend, and frankly, I’ve never even been tempted to use a framework. There are some out there, but the standard library is so rich that writing the API from scratch isn’t a problem at all.
Use small tools and libraries over frameworks wherever possible. It’s the Unix philosophy.
#3 Database features are a slippery slope
Forget about changing a database schema for a second, the only thing worse than that is actually changing databases entirely. Moving from MySQL to Postgres may not be so bad, but try moving from Mongo to MySQL - it’s not always an easy task. I understand that when you need to push your database to its limits, you may need to take advantage of ElasticSearch’s percolate queries or Postgres’s partial indexes. If you can do without, however, using a smaller feature set will make future moves easier.
Think of your database choice as a tool. If you aren’t careful, that tool will morph into a more invasive framework.
#4 Careful about what you save to disk

I won’t go into too much detail on this one either, as I wrote a whole article on keeping your data simple at rest. That said, I’ll give you another tl;dr. If you can get away from storing calculated data in your database, you’ll never have to move it. In other words, the less you save, the easier your life is. Let me provide an example.
Let’s say you have a height variable for each user in your database. Now, on the front end of your application, you need to show everyone who is over 6ft tall that they should get a special shirt size. You could add a new boolean field in your database, is_tall that’s set to true for people over 6 feet. My point is that your life will be easier if you do that calculation in your application code each time you query someone’s height. If you never save it to disk, you’ll never have to migrate it.
#5 Keep your dependencies organized
While you can make a globally accessible database connection and write SQL queries in any old place, don’t do it. You’ll save yourself a lot of headaches by writing a package or module that abstracts knowledge of the database “implementation details” away from the business logic. This is classic “clean architecture” stuff by Uncle Bob Martin, but it won’t just keep your code clean, it will make future database changes much easier.

Related Articles
What are UUIDs, and are they better than regular IDs?
Jul 23, 2021 by Lane Wagner - Boot.dev co-founder and backend engineer
In the context of back-end web development, an ID is just a unique identifier for a record of data. For example, each user on a website will have its own ID. If the site is a social media platform, then each post will also have a unique ID.
Backend Developers are UX Designers Too
Apr 12, 2021 by Lane Wagner - Boot.dev co-founder and backend engineer
Too often I neglect the idea of UX design in backend work. The goal of user experience design is to give users a product that’s easy to use. In the world of front-end development, that typically means making it obvious how to navigate your site, using commonly-understood icons, or implementing well-contrasted colors for foreground and background, making your site easy to read.
HMAC and MACs - The Inner Workings of JWTs
Aug 05, 2020 by Lane Wagner - Boot.dev co-founder and backend engineer
HMACs and MACs are authentication codes and are often the backbone of JWT authentication systems. A Message Authentication Code (MAC) is a string of bits that depends on a secret key and is sent with a message to prove the message wasn’t tampered with. HMACs are a more strict version of MACs that offer additional security benefits.
Building Alerts with Percolate Queries in ElasticSearch
Nov 14, 2019 by Lane Wagner - Boot.dev co-founder and backend engineer
Once upon a time, a company I worked for had a problem, we had thousands of messages flowing through our data pipeline every second, and we wanted to be able to send real-time emails, SMS, and Slack alerts when messages matching specific criteria were found. A simple solution built using ElasticSearch’s percolate queries ended up being our saving grace.