Hey there! Before we dive into this week’s piece, we have a small announcement, which you may have already spotted in the email!
As Hybrid Hacker gets bigger, we want our brand to grow with it, so we are introducing a new, sleeker logo!
It keeps our beloved orange and makes the icon more stylized by focusing on the glasses! We also dropped the “The”, because… it’s cleaner (cit.)
We personally love it, but let us know what you think in the comments!
Back to this week’s piece! 👇
In the past, we used to write most of our software from scratch. These days, less so.
It feels to me that good engineering work is more and more about patching things together — and that’s because product platforms haven’t changed for a long time.
We are still building for the web and mobile, whose core tech has been the same for 15+ years.
Apps today look very similar to those from 10 years ago, which means we've got plenty of time to refine our tools. In fact, today there exist infinite options to do pretty much anything: languages, frameworks, libraries, no code, low code, and SaaS tools.
Choosing good technology is more important than ever, because it is a growing chunk of the overall engineering work.
But how do you choose technology? I wrote half a dozen articles about this in the past, because the problem has so many angles. Today I’ll try to put everything together in a coherent framework that you can use at work.
Here is what we will cover:
🎯 Goals — what do you want to achieve? What does a good tech choice look like?
🎰 Making bets — tech choices like bets, and finding asymmetric ones.
⚖️ Buy vs build — how you should think about this eternal struggle.
🔍 Evaluating tech — what to look for in libraries, frameworks, and tools.
📋 Decision process — how to decide as a team, by using reliable processes and docs.
📚 Related articles — plenty of further articles to learn more about specific angles.
Let’s dive in!
🎯 Goals
Choosing good tech has an impact on almost everything in your team: productivity, hiring, turnover, and overall wellbeing.
As I started writing this piece, I thought about the best tech choices I made in the past, in my teams. Here are a few:
Rails — for the initial monolith of my startup. We were extremely productive, and devs generally loved it — even those who picked it up for the first time.
React Native — for our mobile apps, when our web app was in React. The quality of the output was good enough, and the skill transfer was real: it made us more productive, simplified our hiring and made the team more resilient.
Airtable — for creating a whole portfolio of internal tools, as opposed to writing them from scratch. The output was infinitely better than what we would have built ourselves, with probably 1/100 of the effort.
Conversely, here are a couple of less than ideal ones:
Angular 1 — when we wanted to move the frontend off Rails. When Angular 2 came out and the migration chaos ensued, we ended up rewriting almost everything in React.
Auth0 — for authentication. Good tool but overly complex for our needs and not as turnkey as we thought.
So, what makes a tech choice good? Walking backwards from my experience, it is mostly three things:
🏆 Solves your problems — fits the product and the business.
💸 Ownership cost is low — both actual money (e.g. if you get a SaaS) and especially engineering time over its lifetime.
🎽 Makes your team stronger — engineers are happy, DX is good, hiring is easy.
Then, if you are an EM, a CTO, or someone in a leadership position, chances are you are not making these choices directly. So your problem shifts from “what tech we should choose” to “how do I make sure we choose good tech, as a team”.
Your concern becomes your tech portfolio, as a team, instead of the specific piece. For this, you can take the same questions from above and apply them to your whole stack:
Does my stack solve my problems? How well?
Does my stack cost a lot to maintain?
Does my stack make my team stronger?
Today we are covering both angles: the individual, and the team one.
So let’s start by talking about bets!
🎰 Making bets
Any tech choice brings potential upsides and downsides. In my experience, upsides are often well known and advertised, while downsides fall into various categories of unknowns.
Tech brings risk. The value of such a risk depends on the combination of two factors:
🎲 Probability — that something bad happens.
🔥 Impact — of the bad thing happening.
So you may want to look at tech choices like bets, and go for asymmetric ones: those that have limited downside (little probability and/or little impact), and high upside.
But how do you find those bets?
⚖️ Boring vs Exciting tech
I find it useful to look at tech through the lens of the boring vs the exciting:
🗿 Boring technology — is battle-tested, reliable, and well-understood.
✨ Exciting technology — is shiny, promising, and new.
A lot of this difference comes down to what we know about the tech itself. Boring tech has almost everything figured out:
Many known wins — it is widely adopted and supported
Many known fails — limitations are well known and documented
Few unknown fails — we know it inside out because so many things have already been tried
Exciting tech, instead, is good tech that is still discovering things about itself.
Many known wins — new paradigm!
Few known fails — it will solve all my problems!
Many unknown fails — because we just haven't discovered them yet.
So you can say that:
Boring tech is safer — because of fewer unknown unknowns.
Exciting tech looks better — and maybe it is, but you will also discover more downsides over time.
🃏 Making the right call
If you go back at how we defined tech risk, it's about probability * impact.
In turn, impact depends on two factors:
💼 How important the feature is for business — can we afford to get this wrong?
⛑️ How hard it is to recover — how reversible is this decision? How much lock-in do we develop if we go this route?
The easiest advice to minimize risk is: the higher the impact, the lower you want probability to be.
So, a solid strategy to make good asymmetric bets looks like:
Use proven, battle-tested tech for the most important parts of your stack — the ones that are critical to the business and hard to revert.
Make tactical, exciting tech choices on peripheral parts of your systems — these may also act as POCs for eventually using that tech with a larger scope.
⚖️ Buy vs build
A specific version of this dilemma is buy vs build decisions.
Even though this is often portrayed as a binary choice, things are more nuanced than that. At the very least, you can make the argument for it to be three-fold:
🛒 Buy — e.g. you use a SaaS.
🧩 Integrate — e.g. you use an open source library, or a no/low code tool.
🔨 Build — e.g. you create your own code from scratch.
But the truth is this is more a continuum than discrete options, as within each camp you have various degrees of freedom.
For example, say you want to integrate authentication in a Rails app:
You might code it from scratch, because how hard can it be (joking, don’t do it please) and it would be 100% build.
You can use Devise, the most popular gem for it. This counts as… integrate?
You can use a service like Auth0, which looks like a 100% buy (heck, you pay for it) but it still takes a decent amount of coding.
You can use something like Memberstack on the frontend, which is the closest you get to turnkey auth, but it would be pretty limited.
Some of these solutions are totally different and hard to compare. So, aside from verifying that they match your practical requirements, how should you decide?
👽 The Fermi’s paradox of building
In the intro I argued that, these days, most engineering work is (or should be) about patching things together, rather than building them from scratch.
I stand by this claim, and I believe you should only build with your own hands what makes for a core IP of your company and gives you a unique competitive advantage.
Custom tech is incredibly expensive to develop and maintain, so we should treat it as an exception, rather than the rule.
In the spirit of this, I argue that, if you can’t find anything pre-made that fits your needs, you should be suspicious of whether you need it at all. After all, if it is a legitimate need, chances are other companies need it as well, and someone would have built a product/library for it.
I call this the Fermi’s Paradox of Ideas — which is basically what Camille argued, too, a while ago 👇
🏗️ Bias for building
So, if you feel like I am pulling the rope for the “buy” team, the reason is that I believe most engineering conversations are biased in favor of building, and need to be rebalanced.
Most engineers I have known have kind of a build-first mindset — and I get it. They feel their work is to build things, so the more sophisticated the building, the more they are proving their value.
But this is, of course, dead wrong.
The goal of engineering is to serve the business, and to do it in the most efficient way possible. Engineers who find the simple, clever solution should be rewarded, as opposed to those who built the biggest castle.
🔍 Evaluating tech
So, once you have some candidates, how do you decide? I surveyed people in the community about their criteria for choosing tech, and here are the most popular factors, organized in a sort of checklist:
✅ Success stories — the #1 thing I look at is whether I can find examples of other products using that tech. Bonus points if such products are related to mine, in terms of scale or industry.
✅ Good Github repo — for open source tech, the repo contains an awful lot of information you should consider. Look at the number of stars, frequency of commits, number of contributors, and open vs resolved issues. Is this a healthy project? Is this actively maintained?
✅ Governance — on top of the above, is the project roadmap public? are issues visible? Is the decision making itself visible?
✅ Skin in the game — who maintains this? Is this a company’s pet project? Or is it core to their business? Does the company have a track record of good support to projects like this?
✅ Good docs — are docs comprehensive and clear? Do they refer to the latest version? Do they include my use case?
✅ Community — is there good enough community support? If I have any issues, is there anyone to ask?
Nicola also listed his very own factors 👇
When it comes to selecting programming languages, frameworks, and open-source software in general, we consider the following factors:
The maturity of the project
The level of support available
The project's openness to receiving contributions
The size and activity of the community.
The expertise we have in-house
The expertise available in the market
I believe the last two factors are often overlooked, and people sometimes choose what is trendy over what is practical for development and support.
Many of these items are subjective, and you may not agree with your co-workers about some of them. So let’s look at how you can turn this into team work.
📋 Decision Process
Finally, engineering is a team sport, and tech choices should get wide consensus whenever possible. This stands true at any level: whether you are the CTO or an intern, you should probably not decide by yourself.
Here is what you should consider when deciding as a team:
1) Principles 🌟
Like with general engineering principles you should write down principles and guidelines for choosing tech, for everyone to know and use.
You can take a lot of what we have covered so far as inspiration, like choosing boring over exciting, and making asymmetric bets. And for practical guidelines, you can also write down the items we covered in the evaluating tech section.
2) Footprint 👣
One of such principles should be keeping your tech footprint small.
The less your stack is spread out, of course, the simpler to handle by your team. Also, the larger the piece of your stack, the more such consistency is valuable: using the same language across your whole stack can be formidable for productivity, and the same goes for frameworks — e.g. if you already use React on the web, picking React Native for mobile is a big deal.
Conversely, consistency doesn’t do a lot for small items, when a dependency is local and the learning curve is low. For such choices (e.g. your HTTP request library), you can prioritize experimentation and fast turnaround.
3) Docs 📑
But how do you keep consistency? With docs.
For any meaningful tech choice, submit a written proposal. You can do it in the shape of an ADR, or a slightly tweaked Design Doc. Use such a doc with your team to converge on the choice, and, later, as a record of a decision.
In combination with this, you can use a tool like Backstage to keep track of existing services, tech, and their respective owners.
Good docs answer the question: “has anybody done this already?”.
4) Keep a Tech Radar 📡
A tech radar is a device, popularized by Thoughtworks, to create recommendations (positive or negative) around tech and methods.
Thoughtworks updates its own periodically, and has also released an open source tool to let you build your own.
If you keep track of your choices with ADRs, and have periodic retrospectives about projects, you can take learnings and put them on your own radar for posterity. That stands true also for when you discard options: don’t throw that work away! Write it down on the radar.
5) 👑 Clarify ownership
Clarify who needs to be involved in the decision. This depends on the scope and might be something along these lines:
Anything that is relevant company-wide → CTO
Anything that is relevant cross-team → CTO / Principal / Staff engineers
Anything that is relevant team-wide → Tech Lead
Anything else → Individual engineers
That said, the level of involvement may vary based on how much you are comfortable with delegation.
The more your thought process is written down — principles, docs, and such — and there is trust in the team, the more you should push decisions down, and either 1) only green-light at the end, or 2) make people make their calls, and only infrequently revert.
6) 🔀 Process
So, when you put all of this together, here is what your process might look like:
Check principles — how does this choice fit into your company culture?
Check docs & radar — do we have any history with some of this tech? Are we doing something similar using something else?
Submit ADR — create your pitch and discuss with relevant co-workers.
Final call — converge on a final decision. Not everybody should agree, but everybody should commit.
Update docs — update docs about what exists (e.g. on Backstage).
Retrospective — discuss this choice in a future retrospective. How is it going?
Update radar — write down learnings to simplify future decisions.
And that’s it for today! If you are finding this newsletter valuable, consider doing any of these:
1) 🔒 Subscribe to the full version — if you aren’t already, consider becoming a paid subscriber. You can learn more about the benefits of the paid plan here.
2) ❤️ Share it — The Hybrid Hacker lives thanks to word of mouth. Share the article with your team or with someone to whom it might be useful!
I wish you a great week! ☀️
Sincerely,
Luca