Why and how I build and maintain multiple products simultaneously


Building a single successful software product is hard. Building multiple ones at the same time is extremely hard. Most people would suggest you should focus on only one at a time.

But is that the only way?

I run a small startup company, Launch Platform. As the name implies, it’s a platform for launching innovative software products. So far, I have launched and am maintaining two products:

  • Monoline - a messenger-like app but only for sending self a note
  • BeanHub - a beancount text-based accounting book based on git
Monoline
Monoline
Beanhub
BeanHub

Is there a good reason to build multiple ones instead of just one simultaneously?

You may ask.

Personally, I think while it’s not for everyone, the answer is a yes for me. Recently Monoline finally got its first paying customer. While it may not sound like a big deal, it is a big milestone for me. It validates the needs and proves that people are willing to pay for the product. Today I would like to share the reasons and my experience building, launching, and maintaining multiple products simultaneously.

Why multiple products?

Many people would say

Building and running multiple software products at the same time sounds like a crazy idea 😅

I know, I know, but hear me out. Here are the reasons I think building multiple products makes sense, well, at least for me.

Marekting, content SEO, user adoptions all take time

No matter how good your product, marketing, and SEO is, it always takes time for these efforts to work, so as acquiring new users. In history, most software products have taken a long time to grow their user base. There were only very few examples of a software product gaining a massive number of users in a short time. Slack could be a great exceptional example. Expecting your product to grow as fast as Slack is basically unrealistic.

Growth chart of Slack in its early days
Growth chart of Slack in its early days

Also, if you build a single product one after one, the time to grow is short for the products launched later after your previous success or failure.

Chart showing that the multiple product approach has a longer time to grow for each product
Chart showing that the multiple product approach has a longer time to grow for each product

When you are building only a single product at a time, the benefit is that you can concentrate all your resources on it. With only a single product, your concentration makes you eager to see the result. But like chemical reactions, you could only speed it up by using a catalyst or increasing the temperature or other approaches that much. Even if there’s a way to speed it up, the problem is that you don’t know what works and what doesn’t work. Therefore, you need to try them out. You will often try something, and if it doesn’t show any progress in a short time, you will drop it immediately and try the next one.

With multiple products, I have better peace of mind to let things grow organically for each of them. Such as for a marketing campaign for a product, once it’s up and running, I can let it runs for a while and context switch to other products. Overall, each product gets more time to grow on its own compared to building a single product at a time.

Slow down for more time to think about the product roadmap

People who have ever worked with me know that I build software at an extremely fast speed. For example, Embassy is a lightweight async HTTP server library written in Swift from the ground up without any third-party dependency for my ex-employer Envoy. It’s mostly for mocking API server responses of iOS app testing. From the first commit to the first alpha release, it took me 5 days, and I didn’t cut corners. It got fully automatic test cases when the first alpha was released.

Embassy commit history from May 19, 2016, to May 23, 2016
Embassy commit history from May 19, 2016, to May 23, 2016

Another example is Avataaars Generator, a very popular open-source avatar generator written in TypeScript with React by me. The background story of this web app was that one day I saw an incredible designer, Pablo Stanley, publish his Avataaars Sketch library at Product Hunt on November 15, 2017. It inspired me the idea of building a web-based generator based on his work. Then I made it and published it at Product Hunt on November 19, 2017, and got the #1 for that day, mostly thanks to Pablo’s great graphic design of his Sketch library. I spent after-work hours in only 4 days.

Avataaars Sketch library Product Hunt launch screenshot
Avataaars Sketch library Product Hunt launch screenshot
Avataaars generator Product Hunt launch screenshot
Avataaars generator Product Hunt launch screenshot

Coding machine

More than one of my co-workers called me that in the past. I am not sure if that’s a good thing or a bad thing 😅

Fast typing prosthetic hand from Ghost in the Shell: Innocence, 1995
Fast typing prosthetic hand from Ghost in the Shell: Innocence, 1995

Regardless of what people say, I am proud of myself for being able to build software products at an extremely fast speed with decent quality. It should always be a good thing, right?

Not so fast!

Why? The problem with moving extremely fast is that it’s very easy to get too excited about different feature ideas and implement too many at once without proper thinking. I believe that building a great product takes, if not equal, but way more time in thinking and evaluating the product roadmap and talking to users than the actual time of building it. In short, it’s a marathon instead of a sprint.

Building multiple products simultaneously means I have more time to think about product features and the roadmap and communicate with the users. When you context switch from one product to another, it forces you to stay a distance and cool off from the excitement from the previous one. That’s yet another reason why I choose to build multiple products at the same time.

Shared experience

Another benefit of building multiple products simultaneously is that the experience of building one product can be shared with another product easily. Such as, if I find a good library for solving common problems among my products, I can easily adapt it to other products. And because each product could be in a different stage. Like one could be in early beta and only has a few users, which makes it easier to try out new risky technology or approach. As if it works out, it can be bought to more mature products.

Shared infrastructure

The cost of running software products is always an important concern to think about. The highest cost for early-stage startups when you are the one doing most of the work, besides the time you spent on it, it’s very likely to be the server fee. I have plenty of experience reducing the software infrastructure cost in the past, from a few hundred dollars scales to millions of dollars a month. But I understand no matter how good you are, how hard you try, unless you adopt specific architectures like serverless, there is always a certain level of basic spending you need to pay regardless.

For example, when you create a standard Kubernetes cluster with a cloud provider, the cluster instance usually costs not much but at least something. To make your service highly available, we usually run at least three instances of the same service on different machines. In other words, you need at least three machines up and running. Costs like these add up quickly. And since your startup is very early, there aren’t too many users using it. As a result, your servers are more likely to have a very low utilization rate. Since the low utilization rate, running service for multiple products doesn’t cost too much. As a result, the unit cost per product is lower.

Sounds interesting, but how?

Building and running multiple products at the same time could sound like an interesting idea, but a more important question to ask is how. Here’s how I do it.

I build products for myself and use them on a daily basis

My theory of building products based on your own needs is straightforward. I am very tech-savvy. All the products I built or am going to make are all the products I want myself badly and will use daily. When I want software, and I cannot find it anywhere, it usually means there’s a market for it. So as long as I can build a product that meets my needs, there must be a group of people who happen to have the exact requirement. It’s only a matter of how big the market size is and how to find them. The market could be very niche. But since I am looking for steady growth, not hypergrowth, and given how big the internet is, a niche market might still be big enough for a small startup to prosper.

Take Monoline as an example because I love sending myself a message in a chat app to take notes, but I cannot find an app that meets my needs, so I built one myself and made it a product. The same for BeanHub. I want a GitHub-like service for hosting and automating my startup company’s Beancount accounting book. I cannot find anything I want in the market, so I build one myself and make it a product.

Another benefit of building a product for yourself is saving time for market research. You don’t need to talk to customers before releasing it since you are the first customer. Thus, the go-to-market time will be way shorter. However, you still need to talk to customers after you release it. Otherwise, the product could end up limited by your own bias.

Commitment

While making many products sounds like giving up quickly, that’s not the approach I am taking here. In the startup community, people like to say

You should try things out and fail fast

People say that mainly because they are taking funds from venture capital. Most VCs want to see hypergrowth and only have an appetite for home run investments. So if they think your market is too niche, growth is too slow, they would probably want you to give it up quickly and pivot to a new topic.

Another situation where a software product is given up quickly is because it’s too easy for big tech companies to make money. If the expensive product development time spent on the product cannot be justified with massive income, big tech companies usually would rather kill the product quickly instead of spending more effort on it. Google is an infamous example. Looking at the Killed by Google list, you will be amazed at how many products Google has tossed out, like used tissues.

Screenshot of killedbygoogle.com website
Screenshot of killedbygoogle.com website

The business logic is straightforward. Google’s core ads business is making billions and billions of dollars. If making a new product, say it can make ten million dollars a year, while it sounds like a lot, that’s nothing compares to the money they are making from other products. Similar to VC’s appetite, the appetite to make big money forces Google to toss out new products easily. When you have a money-printing machine in your backyard, do you bother to catch a gold egg-laying chicken passing by your front door? Probably not. Many products they killed can easily be a small or medium-sized startup like Google Reader was replaced by Feedly. So the ability of big tech to print money easily is a blessing and a curse.

Fed printing money video by Tim van Helsdingen

Since I don’t take any VC funds, and fortunately, I don’t have the luxury of making billions and billion dollars every year, the market is small or slow growth is hardly a big concern for me. Having more time for each product to grow is a critical advantage. Thus, commitment to your product is necessary to make the multiple product strategy work, and giving up quickly is not an option. Thanks to the building for your own problem approach I took, I can feel exactly the pain of using it if there’s any. Thus, I can envision myself keep improving the same products I use daily in many, many years to come.

Time-based context switching doesn’t work.

While building different products, I tried different context-switching approaches. The first approach I took was to switch between different products in a rigorous amount of time. For example, I give myself two weeks to work on one product. After two weeks, I will drop whatever I was working on and switch to another product. The problem with this approach is that the momentum built up in the period will reset to zero after switching to another project. When switching back, I will need to recall what was the feature or bug last time and warm up to get into the situation once again. It’s very frustrating. Turns out this approach is not very productive.

Chart showing time-based context switching
Chart showing time-based context switching

With that experience in mind, I took another approach. The second approach is milestone-based. I will set a small milestone for a product and then focus on it. Usually, a limited set of features or bug fixes. After the goal is achieved, a new version is released, and I will context switch to another project. It works great so far. I found myself more productive this way.

Chart showing milestone-based context switching
Chart showing milestone-based context switching

Automate everything

Firefighting for software development usually means there are always bugs in your software, your servers crash often, and you are always busy fixing problems instead of making meaningful progress. No matter how fast you move as a software engineer in firefighting mode, it will always be very slow. Because the development time is limited and shared by multiple products, there’s definitely no room for firefighting. To maintain multiple software systems at the same time, automation is key. A certain level of discipline and obsession with automation is needed. Ideally, you should automate everything whenever possible.

Zoom background video for telling your co-workers that the house is on fire without telling them the house is on fire. You can download it here from LIVELYBG.com. LIVELYBG is made by me, by the way.

For example, all software building and deployment processes are well defined and running on CI. I can always make a new release easily and quickly by pushing a new Git tag without manual steps. And, of course, the software is covered by automatic testing. Without CI / CD and automatic tests in place, you could easily forget how to make a release for a specific component, or fixing a simple bug could take forever.

Monoline App build pipeline CircleCI screenshot
Monoline App build pipeline CircleCI screenshot

Automation for deployment is also very important. All the services are running on Kubernetes with proper high availability configuration. Ideally, the service should just be running forever, and you should never find yourself in need to restart a server. In short, keep good disciplines for automating everything as much as possible so you will have enough bandwidth to focus on building a new product and features.

Use a finite set of boring technologies

One benefit of being a software engineer is that there’s always no lack of new toys to play with. You can always overhear people sharing on the internet about the most cutting-edge, cool, fantastic new technology they are using right now. While trying out new technology is exciting, most of the latest technologies die after the hype goes down. And remember, all the cool new technologies were once very young and cool when they came out. Heck, I still remember how fancy it was when React Native came out.

Chow Yun Fat entrance scene from God of Gamblers movie
Chow Yun Fat entrance scene from God of Gamblers movie

But if I talk to a developer saying that I am using React Native, I wonder if they are going to yield their seat to me on a bus 😂

Some new technologies are indeed game-changers. I recently finally ditched Flask as my go-to Python web framework after using it for many years. Now I use FastAPI even for traditional server rendering style web backend. I really love the approach of its dependency injection. It also has native support for Python’s new asynchronous operations. It makes my life easier when I need to deal with WebSocket or anything async.

Logo of FastAPI
Logo of FastAPI

But this decision didn’t come easy. I worked on multiple projects with FastAPI and tried it out for rendering HTML instead of just returning API responses. After I cleared my doubts about its ability to handle HTML response (given its name FastAPI 😅), I became sure that it works for my needs. But using a new technology also means tossing out some of the tools you used in the ecosystem. Like, for example, I will certainly miss Flask-DebugToolbar, and maybe a similar tool for FastAPI would be my next open source project to work on.

As you can see, new technologies come with risks and unknowns. It also consumes extra energy to learn and get used to it. Building multiple products simultaneously is already risky enough, given you don’t know if people will use them or even pay for them yet. Also, when the number of products grows, if you use different technologies for different products solving the same problem, it usually means you won’t be able to share the same piece of code easily. So ideally, you should have a finite set of boring technologies shared among many products. You can focus on building product features instead of solving similar problems for different tech stacks.

Otherwise, you will realize that switching between different tech stacks is way harder than jumping between different projects using the same tech stack. You may even find yourself writing C++ syntax in a Python project and suddenly realize

What the heck I was doing 🙈

If you want to learn more about reasons for choosing boring technology, I recommend reading this Choose Boring Technology presentation.

You have to market hard

One of the mistakes I made when building multiple products was I didn’t market hard enough. It’s always not easy to publish your work for others to use and judge, especially since you know it’s early stage and there is a big room for improvement. And because of that, I often found myself reluctant about marketing.

But the problem is, most of the time, the products will not sell themselves unless you have a viral growth engine or it’s already good enough to see word of mouth spreading. Otherwise, marketing is essential considering the time to grow leverage you got by adopting this approach. So I would recommend market as hard as you can, also as early as possible. If you don’t feel ashamed about sending out a cold email inviting people to try out your products, you probably are not trying hard enough.

The shame shame shame scense from Game of Throne TV show
The shame shame shame scene from the Game of Throne TV show

I recommend content marketing, Search Engine Optimization, and invite influencers to try them out instead of paid ads for the marketing strategies. While paid ads campaign could bring in new users shortly, that will stop as soon as you stop paying.

The tight tight tight scene from Breaking Bad TV show
The tight tight tight scene from the Breaking Bad TV show

Multiple products for paid ads campaign means the cost adds up quickly. And one of the biggest advantages of the multi-product approach is that you have more growth time for each product. Therefore, adopting a marketing strategy that pays dividends in the long run, sounds more reasonable.

You can read this article, How we built a $1M ARR open source SaaS by Plausible, to learn how they market without paid campaign. Plausible is a privacy-friendly Google Analytics alternative SaaS startup. I use them for all of my websites, paying by myself.

1M ARR growth chart from the "How we built a $1M ARR open source SaaS article" by Plausible
$1M ARR growth chart from the "How we built a $1M ARR open source SaaS" article by Plausible

This may not work for you

Now you know why I took this approach and how I do it, but then you may ask, is this going to work for me? Well, I would say it depends. I think there are some requirements you need for this approach to even run at all. You probably going to need a solid technical background yourself.

Suppose you are building all the things yourself. In that case, you also need to be able to context switch between different projects, like you might be coding in React Native this hour. Suddenly you are jumping into coding in the backend Python API server next hour. Then next, you might be writing a Helm chart for Kubernetes deployments. And that’s not just for a short amount of time. You need to be able to run this for years.

One Man Band short film by Pixar
One Man Band short film by Pixar

So, I talked many about the bright side of this approach. Surely, there are also many drawbacks. Such as

  • Frequent context switching among projects takes a toll on you, and it’s easier to feel fatigued
  • Feel overwhelmed by the sheer amount of work to be done
  • Feel burnout more frequently
  • There is always momentum lost between products
  • It consumes a bit of your soul
The Scream
The Scream by Edvard Munch

Final thoughts

That’s it. Is this approach going to fly? Honestly, I have no idea, and I think only time can tell. But regardless, while it’s a very consuming approach, it is also very rewarding at the same time. I enjoy building software products from end to end and have lots of fun. I also felt great that I could utilize what I have learned in the past as much as possible and keep learning new things every day. It’s definitely not a boring choice.

Hope you can find something useful in my article. What do you think about building products this way?

Do you think it’s a stupid idea and will fail 👎?

Or do you think it’s a great idea, and maybe you are doing similar things 👍?

Feel free to let me know what you think below in the comments section or post your feedback in the Hacker News post here.

Recent articles:

CADing and 3D printing like a software engineer, part 1 - baby step with an overengineered webcam raiser
How I discovered a 9.8 critical security vulnerability in ZeroMQ with mostly pure luck and my two cents about xz backdoor
High-speed 10Gbps full-mesh network based on USB4 for just $47.98