After a few years at a start-up turned scale-up, learning a few hard lessons along the way, I decided to share some principles I think are universal. I’m sure there'll be exceptions, like start-ups with near-unlimited runways funded by a generous benefactor, but for the rest of us, we have only so much time before we have to call it quits.
Two goals will influence all the principles I share.
- Achieving speed.
- Propelling growth.
I’ll start with general principles, and then more technical ones as I go on.
Focus
Even if we're a one-person startup, our singular goal can get lost and forgotten as we put our heads down to work. Imagine how much more difficult it is to keep focused with a multi-person team.
If our goal is the first 100 customers, as developers, we might get shiny-eye syndrome. We might start worrying about scaling once we've reached 100 customers when we should continue to iterate on features.
Whether we're a one-person or a multi-person team, we have to pull in one direction. We can't make progress if we're going around in circles. So there needs to be regular reminders of what the focus is for the month, week, day and even hour. It's too easy to forget our goal and get side-tracked.
And what things do we need to focus on? It depends on where we are:
- Getting the first customer. E.g. Do we need to get that first feature out the door? How quickly can we iterate?
- Growing to N customers. E.g. Do we need more features? How quickly can we release more?
- Preventing churn. E.g. Do we need to fix bugs and improve stability?
Essentialism
"Essentialism isn't about getting more done in less time. It's about getting only the right things done" - says a review for the book, Essentialism by Greg McKeown. How is this different from focus? I believe we need to set what the focus is first, then we can make sure all our actions work towards our goal.
Greg McKeown's diagram explains his concept perfectly. It's what happens when we put all our energy into moving in one direction. We'll get further than trying to spread our attention across too many things.
What does that mean for us?
If we're trying to reach product-market fit, we're probably trying different features that resonate with customers, building things fast.
- Should we worry about infrastructure?
- Should we even be worrying about scaling?
- Should we be worrying about the cleanest and most maintainable code?
If doing those things slow us down, and we can't even get one customer because our time is spent worrying about things that are not our core focus, then we're wasting time and resources. We're solving a problem we don't have and may never have.
Release small, release often
From a developer's perspective, large releases are downright terrifying.
So much code going into production can go all-kinds-of wrong, not necessarily at first, but in the hours and days to come. Having lots of small releases reduces the risk of introducing bugs. But there's another perspective.
When we're trying to get early adopters, even having a little tiny piece of a product in hours or days is better than having the finished super mammoth product in months or years! If we can get the product into someone's hands and get feedback, we'll learn fast from a technical point of view and from a product one. With this fast feedback, we can decide whether we should keep walking down that road to this big goal, or whether we should pivot or quit while we're ahead.
Don't waste time on developer problems
I believe in hiring tools like hiring people.
If we have a software engineer on our team, they're there to build products unique to us. So don't be afraid to allow our software engineers to leverage tools, whether paid or free. Using these tools is almost like hiring the person who built them or paying them but for much lower costs.
But you might think, why have a developer use tools when they should be able to build them?
For example, very few people would consider building their own payment gateway directly with banks, unless our focus is on becoming the next Stripe or Paddle!
So for instance, instead of letting our developer build a payment gateway integration from scratch to collect payments, which apparently took Stripe 6 months, we can set up a beautiful payment UI in a day or less using payment services that do it for us. The difference?
Cost using payment SaaS company = transaction costs + 1 developer dayCost using our own developer = 120 developer days + tonnes of maintenance time!
Once we reach a scale where we're now cost optimising, then we can worry about all these other things. We may indeed have a cheaper way of handling infrastructure, like DHH did when he left AWS. But in the meantime, we as developers have to frequently question, am I working on a developer problem and is there a tool I can use now so I have time to work on business problems?
Basically, don't reinvent the wheel, at least, not prematurely. Build things that are unique to the business.
Hire tools to avoid wasting time on maintenance
Some people say real developers roll out their own authentication. But let's take authentication as an example. It's not just a user table. It's managing emails. It's handling email bouncebacks. It's SMS and 2FA if we really want to protect customer data. It's handling customer passwords and secrets correctly.
Alternatively, we can use open-source tools or hire third-party tools from companies. Really, these companies could have dozens if not hundreds of developers that work on the solution they provide. When we use these tools, we're hiring these people! We're hiring their expertise.
For example, with Okta or Auth0, they keep up with security best practices and make improvements to their product all the time. If there's a security patch they need to apply, chances are, without us even knowing about it, those changes will be rolled out and working for us. Unless we're trying to be the next authentication provider, why not leverage these companies and tools?
It's the same with infrastructure, which is a hard one for me as I really like my servers. It's no problem to set up Let's Encrypt, write a GitHub Action and have full CI/CD. It takes me at most, an hour or two if that from scratch. But I also have to admit, what about DDoS attacks, and handling that? What about server patches, which will be needed at some point? What about scaling the infra to meet customer needs? These are all things I'd have to worry about by making the decision to have to maintain the thing.
Alternatively, I could just leverage infrastructure-as-a-service that does it all for me, and some of those have free tiers which is just enough to carry us through until we start getting enough users to worry about how to deal with costs at scale.
So we have a choice. We can have a developer spending weeks if not months per year worrying about these things that our customers didn't hire us for. We might make an allowance here or there, but we really have to decide if we can afford to or not.
Monitoring as QA
I've worked with some of the best QA Engineers, and they've literally prevented hundreds of bugs going into production, if not thousands. However, if we're starting out and don't have enough customers yet, hiring a great QA Engineer is not going to be our focus. So what can we do instead?
Using something like Bugsnag, an observability platform that checks for bugs and issues users experience in production means we use our monitoring as QA. As soon as there's an unhandled error, Bugsnag alerts us and gives us a digest of issues. This doesn't mean not testing as a developer, because even for a relatively simple project, I used TDD to write the core logic. However, it means not spending huge amounts of time trying to QA our product and slowing down release. Besides, a QA Engineer would probably do a better job of testing our code anyway, especially with fresh eyes anyway.
Write down your principles
If we're the founding engineer or CTO, we should write down our principles so that when we onboard new developers, they don't have to ask us millions of questions to make decisions. They'll have the autonomy to just move ahead with things.
This saves us time, because we share our core principles with our team, and it saves them time too. If there's no one else working with us, then it might not be a priority to care about, but there's nothing stopping us from having a quick list of 3 or 4 things in a sentence or less.
For example:
- Use a third-party tool with a free tier > open-source > roll out own.
- Use existing tools unless one doesn't exist.
- Use modular monolith over separate service.
- Scale vertically before worrying about scaling horizontally.
Have transparent roadmaps
Roadmaps shouldn't just be for the tech team but for the whole company. Everyone should be able to take a look at it and know what we are working on right now, what's been done, and what's to come.
Why? Two things:
- It gives our team focus. If a piece of work is in progress on the roadmap, but we're working on other things, we have to ask ourselves, why?
- If we're talking to current and potential customers, it'll make the conversations a lot easier, as we'll know what's in the pipeline.
Now whether we share this roadmap with the outside world is up to us, but some companies have done it with great effect! Take Supermetrics. Their customers know their roadmap, what integrations are being built and they can even offer suggestions for tools to integrate with.
Choose what we can be productive in
I love using new tools. I can't wait to learn Zig and Rust. I want to work with Go on a product with customers, not just personal projects. I know everyone is clearly using Next.js.
After years of working with Vue.js, knowing React is still the rage, I feel like I should pick it up again, but do we really need to build a single-page application?
Can we use a Go or Node.js server with some HTMX and Alpine.js sprinkled on top?
If we go down the React route, then we need to create an API.
Do we need an API? Then we need validation on the client and the backend. Can we just have validation on the backend?
Do we need two separate Git[Hub|Lab]/Bitbucket repositories?
Do we need Docker? I mean, do we really?
We might even ask, do we even need a server?
Could we just have something like Firebase and just a static app hosted on Netlify or Vercel or something?
Could we just use functions with functions as a service?
Depending on our skills and core competencies, starting with what we know means we can get productive fast. But sometimes, picking up a framework that does most of the work for us, especially if we know we'll need it will make our life a lot simpler, if we're willing to give ourselves a small amount of time to learn it upfront. I did this with HTMX like David Guillot did. But if we have one day to get that feature or part of that feature released, and we need to use what we know, that's probably the simplest and most productive thing that we can do, even if it's not the most efficient.
Now if we have all the time in the world, we can make the thing as complicated as we like: https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition.
Make it work, make it right, maybe make it fast
There's a saying, hindsight is 20/20. We know more about the project at the end rather than at the beginning. And maybe many of us have many things we'd do differently if we could work on a project again. So building the thing quickly gives us exactly that, hindsight.
Instead of trying to code a feature properly the first time, unless we know exactly what we're doing, get the thing built, then make it right. If we try to build something properly up front, not only do we risk building something that the customer might not use, but we risk wasting time on building it because we make mistakes anyway the first time round and spend longer doing so.
Forget ceremonies and the processes
"Agile processes" are the rage, but one of the fundamental principles from the Founding Fathers of the Agile Manifesto themselves is optimise for "individuals and interactions over processes and tools".
I've found that it's better to just take regular intervals to identify what's the focus, then double down and get back to building and doing whatever activity is needed to grow the business. So I wouldn't worry about sprints, stand-ups, ceremonies and story points. If they help us build software faster, by all means, but chances are, we don't need to do any of that, but instead, can do things that work for us.
Push to prod
Unless it's critical for us not to do so, push directly to prod. If we have to do manual deployments, we will find ourselves trying to avoid deployments all the time, and so our releases will get bigger, slower and more risky.
"And sacrilege. Pushing directly to production is irresponsible!" Or is it? If we're doing something that is sensitive, like working with payments or data, yes, have our test environments. We need to use our judgement of course, but if we can take away barriers to deploy to production, then we make it easier, not just to release features, but to fix bugs which will certainly happen at some point anyway.
If Michael Bryzek can do it with a company processing thousands of transactions per day on a mature website and platform, we can do it for our start-ups if there's very little risk.
https://www.youtube.com/watch?v=z-ATZTUgaAo&embedable=true
Of course, we need to test our features before the push.
Measure your product usage
We can interview our customers, which is a great idea. But what customers say and do are not always the same. When they have the product in their hand, using something like Hotjar or another tool to measure how the product is used will give us real-time insights. If we thought a set of features would help our users, and then after release, realised no one uses them, we can stop wasting time building on that feature even more or approach the feature from a different angle or move on to something else.
Make IntelliSense your friend
While I love TypeScript, for a new tool and hopefully product, I used JavaScript with JSDoc. It allows me to build quickly, but with JSDoc I get IntelliSense helping me to build the tool. In fact, after spending 2 hours writing the core logic of feature v0 for a product, I took the JSDoc comments, gave it to Claude.ai, then I asked it to write me the glue code. And it did!
When we optimise for IntelliSense, it's like documentation to help us write our code in real time without ever having to come out of the IDE. And writing code becomes faster at that too!
Document your tools
We all are leveraging a suite of different tools. If we're fortunate to get new hires and developers, they'll start introducing tools of their own. Before we know it, we've got overlap, and people don't know where to find stuff. Even if we're a one-person band, we might even forget all the tools we're using.
For me, it's things like analytics, email hosting, domain hosting, uptime monitoring. I even used a README to document it. We can use whatever we like. That saves time asking, what are we using.
Finally, don't stress
Stress prevents creativity. While we just need to get things done, sometimes creativity and realising there's a simpler, faster and better way to do something versus the way we've always done it can be beneficial. So avoid deadlines, especially if they create stress. Instead, we should try to choose the feature or work that we think will have the biggest impact on our goal that can be achieved in the fastest possible time, and then go do that.