The early days of a startup are often a chaotic mix of excitement, rush and fear. Software-enabled startups are learning about their product as they iterate with their first customers. This leads to frequent and unplanned changes that will help rapidly evolve their product to fit the market they’re trying to disrupt. Nevertheless, the decisions taken, consciously or unconsciously, on how to evolve their product will inevitably affect their future.
The compromise culture
If you have the chance to live the exciting experience of the early days of a startup as a software engineer, you’ll most likely lead on the technical decisions and will be working hands-on on the code of the product around which the company will be built. And you’ll be the first cause for technical debt.
Technical debt is the compromise you make to get things done faster and grow rapidly. Compromising on quality is justified by the short term goals you want to achieve to establish yourself in the market as soon as possible. You have identified a problem, you’ve found a solution that helps your potential customers do the job and you work hard to sell your solution. But since most startups at such an early stage are just losing money, their focus is mainly around shipping features to sell. This means the tension is all towards rushing to the delivery. Anything stopping you from delivering earlier is an obstacle for the company.
One such obstacle is the “Engineering” bit in Software Engineering.
Engineering is the application of scientific knowledge and mathematical methods to practical purposes of the design, analysis, or operation of structures, machines, or systems. (Wikipedia)
The application of a methodological engineering approach to the crafting of your early stage software product is most likely overkill for any early stage startup because it requires time and thorough thinking. Often, you can’t afford to spend too much time on it because you can’t even be sure what you’re building will be useful to your potential customers.
Conscious vs Unconscious compromise
What’s critical in this early stage of the journey is to remain conscious about the compromises you’re going to make to sacrifice quality over speed. Consciousness implies that you’re trying hard to plan to address the technical debt you’re already accumulating. Hoping that the technical debt you’ve accumulated will go away by itself is not a strategy and will end up biting you in the ass as you grow. Worse, not realizing you’re accumulating technical debt will most surely lead to the most painful growth for your engineering organization.
As a good technical leader you should plan for technical debt as if one day your business will be extremely successful.
Planning for technical debt
Not all startups are technological, of course, but if technology is the enabler for your business then you have to make sure technical debt is understood across the company. Understanding the impact technical debt has on your future is hard enough, but it’s especially hard to understand for the less technical people in the company.
As a technical leader, one responsibility you have is ensuring that the state of technical debt is very clear across the board.
If the compromises you’ve made on the quality of the software you’re producing have helped you getting your second client then you’ve only been half-successful as an early-stage startup engineer. The other half of your success resides in making sure the company realizes how much slower you are now on acquiring your third client or on-boarding your next engineer, or fixing that new bug that has just been logged. Every compromise you make has to be clearly understood in order for your future engineering organization to be effective in the next iterations of your product.
Planning for technical debt is definitely not easy and there’s no single success recipe for it. But keeping technical debt in mind should be part of the job of a technical leader. I’ve tried to list a few questions here that it might help to ask yourself from time to time when growing together with the rest of the organization.
- Are the functionalities of your product documented?
- Will it work tomorrow when success brings trouble?
- How much do you know about your software in production?
- How long will it take for your next hire to get going on the code-base?
Are the functionalities of your product documented?
Implementing new features and iterating on them happens at a very fast pace in the early stages of a startup. Agreement on what to ship to production often happens verbally between founders and there’s no room for process overhead to formalize those decisions. This means there’s probably no documentation about how your product is behaving for your customers.
Lack of documentation is a form of technical debt. This particular form of technical debt will become hard to address as your company grows and you start hiring more people.
There’s an update your company wants to ship as part of a feature that’s considered very important across the board. This new bit of functionality relies on the existing feature you have implemented in the very early days. You join the conversation and help the new developers understand how the existing functionality behaves. There’s no documentation or automated tests that define how the software in production is behaving so your help is very important at this stage. Your team successfully delivers the change and ships it in production. Everything seems great until one of your customers receives the update and realizes they can’t use the feature they were relying on anymore in the way they intended the feature to be used. Turns out other stakeholders in the company had sold the feature as something else to some of the more recent clients, something not really close to how you expected that feature to be used. Your team now has to rush and “fix” what you have just shipped to restore the old functionality otherwise your most recent client will be very upset.
I’ve seen this happening multiple times. This causes immense frustration across the company and specifically among engineers. It affects the confidence they have in you as a technical lead because you’ve just led them to ship something that has caused more harm than anything. It dramatically impacts the confidence they have in what themselves are shipping to production subsequently. And, undeniably, it affects the perception the other stakeholders in the company have of the engineering organization. Therefore, it is your responsibility to make sure this doesn’t happen.
Documenting is vital for your engineering organization to stay healthy. BDD (Behavior-Driven Development) techniques can really help in this regard as they help you merge the documentation phase with the test phase. This helps you in creating a contract between the functionality and the rest of the organization. It also helps the engineering organization be more confident about changes to the product. Automated tests and documentation help the engineers know what to expect from their changes and it also represents the artifact that defines the product functionality, helping reduce the ambiguity across the company.
Scalability is one of those aspects you might have compromised on in the early days in order to be quicker at delivering. If you’ve done this consciously your company is aware that the current software is not fit for a larger scale yet and will invest resources in scaling it before things go bad. Your role as a technical leader is consult on the planning for resources.
Nowadays this problem seems almost non-existent since the majority of the software runs on managed infrastructures as a service that allow for instant horizontal scaling. And yet, I’ve seen poor technical decisions and insane quantities of technical debt strangling platforms and make them unscalable even if running on cloud platforms.
This can be because of:
- lack of documentation on specific details to be aware of when scaling
- insane number of dependencies on third-party providers
- code base so coupled with the underlying infrastructure that it had hard-coded assumptions on which server it was running on (seriously)
- asynchronous jobs to be run manually
and so on.
Scalability issues will definitely hit your company if your product is successful. You have to do something to prepare your business to handle the success that it deserves.
Communication is vital for addressing this aspect of the technical debt. Make sure it’s clear across the board every time compromises are being made on the scalability. Be honest to yourself and the rest of the organization about it and act promptly before it’s too late.
How much do you know about your software in production?
Collecting metrics about how your software is doing in production might not seem obvious at the beginning of your startup journey but is vital for your company to be successful. Relying only on your clients to know how it is going is not scalable (see above) and the later you address this the worse it is for your organization.
Measuring is the only way you have to build your organization’s confidence on how the product is being used and how reliable it is in production while at the same time removing any ambiguity around it. Making sure usage patterns and service reliability data points are clearly collected and radiated will help define an unambiguous picture of the software that runs in production, allowing your company to make informed decisions.
Lack of monitoring and instrumentation is not only technical debt: it’s organizational debt. A company that grows without measuring what it does will deliver a product that is the result of the decisions of who shouts the loudest in the organization. And this kind of organizational debt is one of the hardest to address because it shapes the culture of your company.
It’s your responsibility, as a technical leader, to campaign for ensuring that monitoring and instrumentation is adopted as early as possible.
How long will it take for your next hire to get going on the code-base?
As a technical leader you’ll most likely take part in hiring at least the first engineers working on the code that you have crafted for your product to hit the market. You’ll most likely look for someone that fits your company culture and maybe has experience with the technologies your product is currently taking advantage of. But what you should ask yourself, regardless of the type of engineer you’re going to hire, is whether your next hire is going to be able to become autonomous on making changes to the code-base and, ideally, be able to lead future hires as your company grows.
The compromises on the quality, documentation, architecture and sensibility in general of your technological asset will affect the ability of your future hires to impact positively your company. There will be no 10X developer able to overcome insane assumptions on which your software relies on. And this is especially true when your product has been built with technologies that require a high degree of discipline in order to keep everything manageable.
Ruby is one of those technologies that I consider requires a high degree of discipline. It gives you the freedom to do pretty much any thing you want. You can easily override any method you like and inject different behavior for already existing functionality pretty much everywhere. From great power comes great responsibility said someone. This is particularly true with this kind of technology.
I’ve seen so many surprising changes to core parts of used libraries that the original intended behavior had completely been altered, leaving newcomers completely knocked out learning how things were behaving completely unpredictably. Someone called this The principle of most surprise and is measurable by the number of WTFs per minute shouted by the developers at work.
This is one of those things I consider to dramatically affect the morale and health of the engineering organization. On top of that, such insensible things are so technical that they are even harder to explain to the rest of the organization when it’s time to address them.
Crafting a product from scratch and building a company around it is not an easy job. The fact that the company turns out to have a market for the product you’ve built is a big success on its own. You should feel proud of it as you’ve been one of the main factors for this success. But different phases in the growth of the company require an adaptive mindset as things evolve. The skillset required to build a company from scratch are different from the ones needed to scale it. And the most important thing is acknowledging this bit.
Technical debt is everywhere and is inevitable. Technical companies will always struggle trying to manage it but the successful ones are the ones that plan for it rather than hoping it goes away by itself.
As you go through the wonderful experience that an early stage startup is, try to think about the questions we’ve just gone through and imagine if things can be done at least slightly better before it’s too late. Try to always question the way you are achieving your results and understand how many shortcuts you’re taking to get there. Pick technologies carefully and be ready to dismiss them as you realize they don’t fit your purpose. Don’t force nasty workarounds to make them work the way they’re not intended to work. Do not blindly fall in love with your code but, rather, be always ready to get rid of it for the better.