Skip to content

Month: September 2021

Six Patterns to Optimize Your Monolithic Codebase

Migrating to microservices isn’t always needed: first, you must fix your monolith.

The tech industry, and software engineers, are wired for the new and the flashy. That’s also why we see dozens of new javascript frameworks getting created every year, the majority of which end up burning into oblivion as they re-enter the Earth’s atmosphere—well, except for jQuery, which somehow keeps surviving.

The same can be said of architecture: almost every time I hear or read someone mention monolithic architecture, there’s almost always a negative connotation associated with it, because it has this feeling of old and outdated.

But simply because monolithic architectures are older doesn’t mean they’re bad, or that they’re less, compared to service-oriented architecture or to serverless.

This reputation comes from the fact that most monolithic architectures end up turning into giant spaghetti monsters of code, difficult to build, deploy, and evolve. I agree with that, that has also been my experience.

What I disagree with is the speed with which many engineers are ready to discard monolithic architectures entirely and switch to something else, say microservices, which they understand even less, instead of trying to fix what’s already there. There’s a lot of hype involved with such pushes, because it entails using new cool frameworks, new programming languages, and so on.

In addition to that, there’s often a lack of understanding from engineers that the decision of choosing an architecture must never depend only on technical considerations. In fact, it should be the other way around: picking an architecture should always be done by putting most weight on what will best serve the business needs and growth of the company over time, and take technical considerations only as a second-order concern.

And before discarding an entire architecture or codebase, one should always strive to fix it with what’s already there.

In this article, I want to share techniques I’ve seen deployed in production and which have helped make monolithic codebases easier to work with. I’ve seen first-hand that they were successful in improving build times and consequently deployment times.

The six patterns for optimizing your monolithic architecture are:

  1. Remove build bottlenecks
  2. Extract frequently updated code areas into their own modules
  3. Clean up unneeded dependencies
  4. Clean up unused code
  5. Enable server-side caching in your CI/CD
  6. Use subviews to mock dependencies

In the rest of this article, I will share more details about those techniques, and how to go about using them

I’ll be using the term “microservices,” as if I’m taking the perspective of a backend system. But this article also applies to frontend applications and to microfrontend architectures. Also, I’m going to stay very generic in my statements, and that’s intentional: I want to focus on the big picture ideas without being specific to a particular language or toolchain.

How to Get Your Silent 1-on-1s Back on Track

During 1-on-1 meetings, I’ve often had a direct report who says “I have nothing to share” or “nothing from my side this week.”

When I was still an inexperienced manager, I would reply “okay great, let’s end the meeting and go back to work then!” However, after more years of running 1-on-1’s with dozens of different personalities, I’ve learned that ending the meeting is always the wrong thing to do.

Over time, I’ve developed a list of questions that I keep readily available in a corner of my mind in case those situations arise, as a way to unblock them and generate more insightful discussions. In this article, I’m sharing my approach.

The Most Important Step Of Every Great Conversation

If you’re like me, chances are you walked into many high-stakes conversations without even realizing what was at stake, and without having either a goal or a game plan on how to achieve that goal.

And then, you walked out without understanding what the heck just happened and why everything turned out so wrong.

Having good conversations is a skill. You need to keep track of all of your interlocutors’ signals including values, beliefs, arguments, body language, logical fallacies, and so on, while keeping track of your own presence and communication.

So if on top of that you realize mid-flight that you didn’t plan exactly what preferred outcome you wanted from the interaction, then it’s game over.

Entering a conversation with a goal can be the deal-breaker that will make the conversation a success for both parties, or a drag and the beginning of a conflict.

Most shortcomings can be avoided by preparing and practicing the art of conversation, and by taking care of the most important step of all.