What makes a good tool?

At some point during a long career of building software, you reach a level of experience that allows you to identify the right tools and patterns to use the moment you're presented with a new problem. The products you are building may be different, but you start to recognize patterns from features you've already built, and building becomes more of an exercise of figuring out how to best fit things together than how to execute lower level details.

A tool in the context of software engineering could be a package of code, architectural pattern, or a program that does some of your work for you.

Ideally, this toolkit you're assembling should be more than just a collection of items you had a great time with; they should help you do your job better. Therefore the value of a tool depends on what your definition of doing your job "better" is.

The Good Tool

To me, doing my job better means shipping quickly with a high-level of quality, while having done as little of my own work as possible. If this is something you're aligned with, the tools you pick should be ones that help you ship good products faster. Here are some of the attributes of tools that enable this:

1. Part of a vibrant ecosystem.

If you want to move quickly, the best way to do so is by standing on the shoulders of giants, ideally on top of those who are already in motion with their big, long, giant legs.

Choosing tools that are a part of a mature and open-source ecosystem means you'll have a vast library of code you can incorporate into your project, along with a ton of relevant StackOverflow and GitHub Issues, and the ability to get your hands dirty to contribute yourself when necessary.

This could mean picking a battle-tested framework such as Django or Ruby on Rails. Both of them have been around since the beginning of time and will have most of your needs taken care of already, implemented either directly into the framework itself or installable as a package or gem.

This could also mean avoiding less popular or mature frameworks. You won't have the same level of support and will be on your own if you have a question or run into any issues.

2. Makes low-level decisions for you.

When building a product or service, you have better things to think about than where to put a new file or how to wire up your API to your database. Ideally, these types of decisions are made at the beginning of your project and rarely revisited.

Even better, you can leverage a framework or architectural pattern that makes these decisions for you, so you can focus on the core issue at hand. This could look like using an opinionated framework such as Rails, or adhering to the gospel of Domain Driven Design.

3. Lets you own your data and product.

If you want to maintain the ability to control how your product works and looks, you should avoid handing over control of mission critical functionality to external providers. Otherwise you'll be at their whim and limited by the functionality they offer. And if they don't offer good customization options, you can end up writing a lot of code massaging it into a form that's almost close to what you need it to be.

One feature this happens frequently with is auth. There are plenty of services out there that will gladly sell you an exponentially expensive auth solution in exchange for added complexity and slowness in your app. You should instead prefer packages that let you integrate auth directly into your product and database while still handling the underlying complexity for you, such as OpenAuth or Django Allauth .

4. You know it inside and out.

The best tool is usually the one you already know. Otherwise, you'll find yourself trying to learn a new tool at the same time you are figuring out the thing you are building. This will slow you down and be incredibly frustrating.

If you're trying to replace a tool that you've used before and have determined sucks, I recommend trying it out in a new side-project, or in a limited portion of an already well-established product.

One example of where trying out a new tool went well for me was introducing type-checking into a very large Python codebase that was shared by multiple teams. Rather than trying to get complete code coverage and slow everyone down with an unfamiliar tool, I set it up to check just one directory at first, and then slowly expanded coverage from there as the team built confidence and became more comfortable with mypy.

Finding new tools

If staying relevant is important to you, you'll want to periodically step outside your comfort zone and see what else is out there.

I do this by subscribing to all the <X> Weekly newsletters, such as React Weekly or Django Weekly, and bookmarking or GitHub starring anything that piques my interest. I'll revisit this list whenever I have the urge to build something new, or if I have a need for them in something I'm already building.

If you're part of a lively ecosystem like Python or JavaScript, it's easy to become overwhelmed by the constant deluge of new tools and services being released, and maybe even feel like you're becoming a dinosaur by sticking to the ones already in your toolkit.

At the end of the day, customers could care less how you built your product—only that it works and solves their problem.