Ask HN: How bad should the code be in a startup?
Hey Hacker News! I was recently involved in a startup where the CEO had made a crazy complex app with prisma - it did loads of things but it was a mad balancing act of insecurity, bugs, badly mangled code and database design that left a lot to be desired. I think my problem is they were just copying something that already exists rather than making something new that needs extreme user testing for it to become a thing. Obviously on such a codebase the CEO could get things done pretty fast but I couldn’t help feel it was completely hopeless for anyone else trying to make the project work correctly. Of course even with all this brittle code there were no tests.
My question first is
a) has Hacker News/YC ever seen a startup fail because the codebase is so bad.
b) what is the best calculation to make when trading off code quality vs features?
c) do most YC startups write tests and try to write cleanish code in V1 or does none of this matter?
Should we just be chucking shit at the wall and seeing what sticks? Do most startups bin v1 and jump straight to v2 once they have traction?
182 comments
[ 2.9 ms ] story [ 162 ms ] threadb) Just take into account these: Will feature introduce major bugs like database corruption, or will it just cause minor bugs like UI bugs? Also consider if this feature is really necessary for MVP and will have a considerable financial return or not. In my startup I definitely don’t deliberately write bad code, but there is a limited time/financial funds, so it is ok for some of the code to be hacky(though never horrendous), I just put a TODO there to remind myself to fix after product release.
c) I favour an agile approach, try to implement the feature first without unit tests and see how it works with the overall architecture. I only unit test code: That can cause major bugs, or code that involves heavy math.
> do most YC startups write tests and try to write cleanish code in V1 or does none of this matter?
It only matters when bad code hurts your overall business velocity - what that means, only you can answer.
Nobody's writing tests for their purist aethestics, they're there to let you go faster - but there's an up-front cost you have to pay for them. Sometimes that's worth paying, sometimes the land grab is more important.
There's no single answer to this question.
There’s gonna be a big survivor bias here. You won’t hear about most of the startups that collapsed because the product just didn’t work.
b) Keep the bugs non fatal, make sure the features are worth it.
c) I’m not in YC, but yes. There’s a really good reason why tons of startups duct tape shit together with node and ruby, only to rewrite it later in something else.
I've worked in very small and very large companies, though never owned a startup myself.
A few things I have seen and experienced, personally or from close friends:
* It's ok to not be scalable from day 1 as long as you're not certain who your customer is. Because you are likely to have to shift a lot left right and center and it might slow you down. But do keep in mind that it will become an objective at some point.
* Your code should be reliable and high quality enough that you can refactor it fast and without headaches. I have lived situations where a change in one part of the application was creating bugs somewhere completely different. I've also been in places where tests were forbidden (bugs never come twice at the same spot , RIGHT?!). Not having tests with f* you hard because you wont be able to move without breaking stuff soon, but also because you won't be able to easily expand your team.
* Tangential to 1 and 2, do try to keep abstractions layers in place. That will make your life easier.
* You shouldn't be afraid to let new employees in the code, and to deploy. Otherwise you're a liability.
* Security is a tough one. It'll never be good enough, and it's usually a cost more than a revenue... Make sure that all the data of your customer is safe though, that should be the hard limit. Because if you're successful and get hacked you might never recover from it.
I have seen a brilliant company that had a nice business model go down not because the code was not high quality, but because lack of tests and lack of design abstractions made every step of the way 100 times harder a few years down the line.
You seem to have a pretty good idea where you're going already :).
All in all you wanna move as fast as possible, while making sure that you're not creating the shit of tomorrow. So if you write crap because reason, make sure it's contained :).
A cost of sloppy code and move-fast practices & attitudes that's not well-accounted for most places, I think, is that it makes it harder to add people to the project and get them contributing effectively. New hires, contractors, agencies. All will be less effective, longer. This factor gets much worse the longer you operate in that mode, and the more sloppy code goes to prod.
> I have seen a brilliant company that had a nice business model go down not because the code was not high quality, but because lack of tests and lack of design abstractions made every step of the way 100 times harder a few years down the line.
I suspect the "tech choices don't kill companies" wisdom is actually BS and it does happen often enough to worry about, it just doesn't often look like that's what killed them.
Yes definitely! I have seen VERY FEW startups that feel at ease with getting new people onboard the codebase. But as soon as your business model is validated, that's what will most likely happen so you better be ready for it.
> I suspect the "tech choices don't kill companies" wisdom is actually BS and it does happen often enough to worry about, it just doesn't often look like that's what killed them.
I don't know about that. Not that I don't agree, I really just don't know. In that specific case though it seems (though the exact opposite) related. They essentially had rebuilt everything. Their own SOAP layer, their own XML parser, UI framework.... And that was OK when the company was created, because there was no alternatives. But they never made the move to start using mainstream solutions when they appeared. Wait a few years, and what takes you a day of work takes 30 minutes with the current state of OSS in other startups.
> a) has Hacker News/YC ever seen a startup fail because the codebase is so bad.
No, but I have seen the mass velocity hits from short term decisions living on over the years. Tech Debt is real and can eat into 20 - 60% of a teams output because of bugs/issues/lack of documentation & context. These places are miserable to work at.
> b) what is the best calculation to make when trading off code quality vs features?
Unfortunately this may not be a popular opinion but here is what has worked best for me. You need a sound ARCHITECTURAL base from inception, to do this the person who makes the decisions or is in charge needs to use tools/languages/etc that they are experienced with to develop a clean base to work from. Its not hard to set up CI/CD, unit testing, proper devops, and code decisions like inversion of control, and proper service segregation from the outset IF you use technologies you are strong in. This lets you move quickly if need be but the "bad" code is limited to services/systems. Its easy to fix a single poorly coded rushed class/function/file. Its a nightmare if your entire basis you build off of is crap.
Startups tend to be limited on time... and sadly often startups hire inexperienced people who cant do the above or experienced people who focus more on shiny new technologies then using things that work and and be quickly executed.
c) do most YC startups write tests and try to write cleanish code in V1 or does none of this matter?
Never been part of a YC startup, but I would say my general experience is that when your still figuring out what your product/market fit is things like scale/code quality/architecture shouldn't matter... however two things need to be kept in mind. The first is having an "escape hatch"... this code is crap we all know it but its the code we need right now, is their a way we could pivot/transition to a new system/architecture in a few weeks when we finally get funded or "grow"/"scale". The second is identifying that pivot point and investing time to create the the first generation foundation (if you go full unicorn/scale again you may need to deal with this yet again).
In conclusion you need to do what gives you the most velocity for your effort, this means when you are super small and still figuring out the basics a costly foundation inst worth much. Then if you survive and shift into growth mode you need to expend some effort/rescourses into a good base to keep that velocity alive.
b) This really depends on having a combo of a product manager who appreciates technology and an engineering manager or CTO who appreciates business. You have to weigh the benefit of shipping feature X now vs. later, in favor of tech debt T. Both sides need to be honest about the consequences of delaying X or T.
c) Not a YC startup, but always try to write tests and good code. Never abandon it. But in the early days when you're trying to gain traction, don't feel bad about having to compromise on them during crunch times (which is most of the time).
My experience is that business promised novel products to investors and customers, but engineers could not deliver any miracles with the time and resources available.
Is that a failure of business or tech?
Well, I have seen others were there was just no market for the product. Like some paid service on the web when users expect it to be free of charge. I guess this qualifies as business failure.
See my point (b).
Delays in feature delivery and production issues are usually symptoms of poor code maintainability and high tech debt. It's a really difficult balance to strike, but it's worth tackling low-hanging fruit as you work on the code, and introduce good practices for new features as you keep going if it doesn't impair development too much.
1) Bugs/outages that affect your customers
2) Hard to grok code that slows down onboarding of new staff
3) Features taking longer time to develop
How you weigh these risks is different from business to business. For a fintech startup a bug in the code could end up bankrupting the company. For a VC backed social network, being able to quickly onboard new hires is really important. For an app that supports say BLM protestors, time-to-market is everything.
In the great scheme of things, having a crappy codebase that makes money is a good problem to have.
Be good enough to not fail an ethics test re customer data.
Everything else is sales.
b) The best metric is what is most boring and what is most comfortable. Boring tech is good. Boring code is good. Things are more or less defined by their failures than successes with languages. You want to be defined by what doesn't happen in your code because you made cogent decisions.
c) Do most YC write good code? Yeah but that's not what defines their success. Clean code is presentable. Clean code sets a tone. Tests are sometimes snake oil, sometimes valuable. It's hard to assess how valuable a metric is once you become invested in increasing it. No, writing tests won't save you. But decent DevOps will hopefully reduce cognitive load in managing features. Writing unit tests is in my opinion, a nice reprieve in between coding sessions. I look at it as paid downtime.
d) As someone pointed out, there is survivorship bias to consider. It's pretty common for v1 to a complete disaster where nobody knows what they are doing. Most fail and do not attempt v2. Eventually the to-do's and somedays just pile up and you lose to a competitor.
e) Another perspective, almost everyone's code will be some kind of dumpster fire. You'll realize perfect pipelines will always be desirable, as in nobody has one. The only code that is 'bad' is the code you fail to take accountability for.
If the answer is "no", then the tolerance for bad code goes way up.
Either way, in the early stages of a startup, a great deal of the code will end up being throwaway, and the trick is sometimes knowing which things are important to get right upfront, and which things can be punted on.
Well-defined service boundaries help a lot. This doesn't mean going to microservices, but it does mean keeping things well-isolated and independent even in the same codebase. In effect, you can have "well-architected bad code" which will help you stay flexible even as you move quickly.
I've worked at a few startups and I'll give you some examples where it matters and where it doesn't.
I was hired as employee #4 at a stealth startup that would turn into a zombie and I was the last non-founder to leave when our runway ran out. At no point in my time there did code quality or test coverage matter even a little bit - our biggest problem was convincing people to pay us, which was particularly difficult because our value to the people we wanted to pay us was intangible (at least to them). This was why the startup failed, we tried to sell to the wrong people for too long (ie, misaligned our values with what our target market actually valued).
Code quality didn't matter because we essentially strung up demo after demo in different contexts, the core technology was basically finished within a few months of founding, and the rest of us worked to put it into different contexts to show people what they could do with it. Those demos would never reach production, and most of them had a single developer. Who cares if there were no tests or it was all spaghetti? We were just trying to show off.
I'm currently an early employee at another startup and spent a lot of time over the last six months developing ci/cd infrastructure and we're going to make a major push for testing/benchmarking coverage in the next month or so. The reason is that we have a tangible and immediate impact to our business because it directly affects our value proposition.
So to answer your question, the answer is it depends. It all matters when it affects the bottom line, because code quality/testing doesn't make you money; it just costs you less money in the future. There is a very definite stage in the life of a startup where that matters, and as a developer in the org you have to budget your time to commit to it when it matters.
And this isn't just startups or side issues. I don't know anyone who has looked seriously at OpenSSL without being completely horrified.
They don't care if the code is good or bad, as long as the app does what they need it to do and does it well.
So to answer your question: The code should be bad enough that it allows you to ship as fast as possible, but not so bad that the app doesn't work properly.
This can be a shock if you've been raised on a steady diet of HN posts and comments, Medium articles from opinionated and often highly critical programmers, and open-source projects that only accept the best quality code. No one likes to brag about writing proof-of-concept grade code, so you won't be hearing about it online or in public.
a) Yes, startups have failed because their product doesn't work properly or the product is full of bugs. However, startups don't fail because the codebase is ugly, or convoluted, or not following best practices. You might be surprised at how hacky many early startup codebases are.
b) Regarding the calculation of code quality vs. feature velocity: When in doubt, consult with the senior devs and your manager. Knowing when, where, and how to strike this trade off is one of the defining features of being a senior developer, in my opinion. In most cases, it comes down to estimating the negative impacts on future development. A core component that touches every part of the app should be more carefully designed than a single-use feature only 1% of your customers might ever use.
c) Regarding tests and clean code for V1: In short, the only thing that matters is getting traction in the early stages. Every day you spend writing tests or refactoring code to feel cleaner reduces your chances at getting that next funding round. In the early days, it's all about a proof of concept and getting customers so you can grow the company. You can't grow the company if you don't have investors and/or customers, so that perfect code may be doing more harm than good in the early days.
Coupling is an obvious example. If you want to retain agility in your product, the various components inside should be pretty loosely coupled and have restricted domain of responsibility. When you find out the product needs to change - massively - you already have a lot of the bricks you need to make the new product.
On the other hand, it's clearly wrong (in my experience) to go full-bore microservices out of the gate, because you end up spending a lot of time on wiring and infrastructure.
So for me, the question isn't "what's the minimum level of quality?", because at every stage the quality should in practice be pretty good. I know people say "be embarrassed by the first version you put out" - but people also say to be obsessed with the product/problem. Product teams with high standards (in general, but including code) tend to be more successful. If quality work starts taking up substantial effort, that's a pointer to other decisions (choices of technology, for example) being wrong. Again, all IME, YMMV - I don't think there's a clear rule of thumb that applies to all startups.
In a perfect world, you'd make all of your decisions along the Pareto frontier of speed-vs-quality tradeoffs.
In the real world, you don't have perfect engineers, and the Pareto frontier isn't immediately obvious.
Generally speaking, the more experienced engineers are better at getting closer to that Pareto frontier of speed-quality tradeoffs from the first iteration. It's the less experienced engineers who end up somewhere less efficient on the 2D spectrum of speed/quality. This is where experience pays off the most.
When you're building out product and figuring out where it fits and what it should do, you want to retain a lot of optionality. If you don't have the ability to change the product quickly in an agile fashion, your development process way well end up being more pareto-efficient overall but your potential customer base would be much smaller. Better to be less efficient and grow a much bigger base.
Also you may be thinking in terms of a different optimality criterion for quality, which as the above poster noted may be unclear, e.g. a lot of effort in one direction that seems like the best decision in the short term but actually hinders needed flexibility in the long term. This just means the short term improvement wasn't really towards optimal after all.
That itch to improve things is more focused when revising whatever is the worst parts of the entire project rather than various pieces being decent when there are some horrific bits of the code base. Because those horrific bits end up eventually infecting everything else.
This changes a project grows to the point some code is old enough you don’t remember all the details. At that point you need to use best practices simply to make reasonable progress.
I'd argue that the difference in time of writing tests is balanced by less time debugging, and the moment you want to re-use the code you know it already works in all the contexts the tests use it in, in fact it was already designed for re-use because the tests and the application use it, so you avoid major refactoring and instead just assemble your Lego blocks in a different shape.
Jumping right into whatever is the most difficult problem also means your model of the best architecture is likely to evolve as your working on the problem.
Granted this should all be on a sliding scale depending on how novel the project is.
Startups do fail due to a failure to execute. Best practices aren't always about aesthetics. Ignore them too much and you end up with write-only code. You can compensate in various ways, such as designing the code so that it's possible to throw away the ugly parts later.
You are correct that good senior engineers are apt at striking this balance. I do not agree that the typical senior engineer is competent at this.
Obviously, the product must work, must not be buggy, and must be maintainable enough to move forward.
However, there’s nothing wrong with what you call write-only code in certain circumstances, especially at a startup. I’d much rather have some backed together, single-use code that lets us prove demand before investing resources in a proper rewrite. The project goals will likely change after first contact with the customer anyway.
One of the biggest time wasters I’ve seen at startups is engineers who lose track of the goal and instead start writing reusable frameworks, or over-generalized code, or separating architecture into modules so they can open-source part of it on GitHub.
Startups are trying to prove a business model as fast as possible. Once you prove demand, you scale it with the proper code backing it up.
It seemed like static typing, "find all references" and the limited use of reflection style coding made the difference between bad code being annoying and completely unworkable.
What really worked great for my teams in the past is to game the transition so that the team as a whole sees it as an internalized mission, usually much stronger than that of the company. Then killing X lines of code from the old mess and beautifying the codebase becomes a shared and extremely satisfying exercise
That being said, languages in that space seem generally less prone to write-only code, so I'd agree that language choice has a big impact. Especially when an entirely novel language or framework enters the picture.
Suddenly you will see you can’t just scale the team up because it takes new team members a long time to grok the codebase and work within it.
Similarly, a disconnect happens between business and engineering where building features that appear similar to already existing features still take longer to build since the existing implementations were never built to be extendable or reusable.
While all this is happening, the team is busy working around the codebase, not with it, to the point where they can’t apply solid refinement to the end product. Adequate time for bug fixing/testing is not allotted since the team is fighting the codebase to just get features out. Your product ends up lacking quality.
Developer quality of life goes down, which believe it or not, impacts velocity. Suddenly it’s not pleasant for the team to casually peruse the codebase. Suddenly those time estimates are all in the mid-high range, they can’t get a breather from the cognitive overload.
Finally, those little tweaks business wants to make become the stuff of nightmare. Stand-up becomes a call for mercy, ‘Making that change is not straightforward’, a constant compromise, ‘Can we just settle for this alternative instead?’.
A shitty codebase has an outsized cost for sure.
More importantly, my time at that startup was some some of the most stressful in my life, and for what, someone else's shitty code? I refuse to be a "code janitor" anymore. Of course all systems build tech debt over time, but it's not that hard to see which systems were built with a modicum of forethought, and which were just slapped together. Imagine if people building a house got a group together, gave everyone some tools and some lumber and said "go!" instead of actually creating a design, laying a foundation, etc. That's what a lot (not all!) of startup code is like, and I for one refuse to touch that from now on.
Could they fail because they fail to meet deadlines due to convoluted or buggy code or having to invest more money and time to fix those issues and bugs introduced by them?
They could also fail because code/architecure is overengineered, not invented here syndrome or because of premature optimization.
In the beginning, being able to adopt and/or pivot quickly might be much more important than to have 100% test coverage, keeping up with the latest JS framework or being able to scale to 100M users.
Yes, they do.
The obvious one is one senior developer who writes a bunch of trash code to get stuff done in a hurry. Later is asked to maintain it and add features. But it's no fun cause it's a pile of poo. New shiny attracts his attention and he moves on (cause, you know, he delivered at his current job!). New developers try to pick it up, including a new hire, try to work with it. Warnings about runway loom. Support is swamped and many of the tickets get kicked up to developers because support can't answer because they're obscure bugs. Most of developers time is spent trying to fix the worst bugs, but things just get worse because each bug fix introduces new bugs, cause the code-base is well neigh incomprehensible. Some developers see the writing on the wall and flee, leaving even more work for the remaining developers. No money for new hires. 3 months later, layoffs. 1 month later, closed. One poor guy is laid off 4 months after being hired.
Lather rinse repeat.
The upshot is crap code makes a crap product. Just like crap engineering makes a crap car. Customer do care about that. They'll get tired of the bugs and the infrequent updates and the poor support and eventually they'll move on.
There's some survivorship bias at play in this; it disregards all the startups that never reached the "later" point because they were too busy polishing the code.
They seemed content, but obviously a lot of resources went into tests.
2) Many late startups in SF spent a lot of time and effort on perfecting CI/CD software (multiple years), or struggling with k8s in the early days (1 year to finish one service.)
3) Often post-founder programmers these days have a lot of process to overcome before shipping. I know one startup that hired dozens of programmers, but the founder (alone) still writes most of the code.
And I worked on a project that literally saved the HTML on the page into a varchar, had 15,000 lines of JavaScript, and all the business logic was written in awful stored procedures.
Whatever speed quality trade-offs a good engineer is making will be worth it when a startup is still in the "I don't know if this company will exist in 6 months" phase.
I feel like people walk through hypotheticals like that, but I've not heard people say "Company X failed because of that scenario."
In my case this was a relatively mature company on a version 2 reimplementation of an existing product, so it wasn't a complete death sentence. It eventually led to a complete house cleaning of CTO and product management in the end though. But, the company sure didn't fail!
OP specifically referred to startups, though, not mature companies. Most startups only have 12-24 months' runway to begin with, and lacking clean code/testing/best practices/etc won't (usually) kill them in that timeframe.
Lack of product-market fit, on the other hand, is the one thing guaranteed to kill a startup in that first year or two (lack of financing is the other, but this is usually fixable if you've addressed product-market fit). It's why startups spend every single developer hour on rapid prototyping/iteration/features, rather than refactoring, testing and stability.
It's not black-and-white, though. Some code is so bad that it costs time in the very short-term, because noone can figure out how it works. Some functionality is so central to the product that tests are needed to confirm it's actually functioning as intended.
There's a vast spectrum between "fully tested, clean, reusable code" and "held together with sticky tape and segfaults every other minute".
I'd say that the one key skill for a startup CTO is deciding where the team should be on that spectrum on any given day.
"However, startups don't fail because the codebase is ugly, or convoluted, or not following best practices." Yes and no are both right I suppose, depending on the viewpoint.
Mark was a perfectionship in releasing a working product. That doesn't mean it was good from a programming standpoint, but it was tested and always worked well.
eBay is the poster child for shitty software. At one point their CTO was requesting one Sun E10k per month ($2 million each fully populated) because of how slow and leaky their Windows code was. The board said no and they had to fix it.
You took the sentence out of context. Obviously the product must work, must not have bugs, and must be straightforward enough to be maintainable.
If your code is so bad that the product doesn't work, then obviously no one is going to say you're doing the right thing.
I was speaking to walking the line between good-enough code and perfect-code, not advocating that people write code so bad that the product doesn't even work.
Are there more colors on the greyscale than 000 and fff?
Yes, I've been seen this happening on some projects that I joined. The most hilarious story I've is when a funded startup spent 12 months with a team of 5 and the app would crash with a single user with little usage. I managed to rewrite a functional prototype/v3 in 3 months that worked much better. Others were so costly to refactor and got shutdown.
More often that not, it is all about the specification and company culture that creates this chaotic outcome.
b) what is the best calculation to make when trading off code quality vs features?
This one, personally, I like to put the responsability on the dev team. Not having an exact spec is far from ideal but the dev team should work with the business team to create a good enough first version. If the code is garbage, you've to question the development team, period. If you take nano refactors (around 20 minutes) every day before you push your code and follow the community guidelines for the stack you're using, technical debt won't become a problem in the first stage.
When you're asking this question you need to ask: Why has the dev team wrote code that lead to this situation? Do we have PR reviews? Coding conventions?
c) do most YC startups write tests and try to write cleanish code in V1 or does none of this matter?
I don't know about YC startups but I can tell you that I'm yet to know a company that has, at least, 50% code coverage. Any time I mentioned writing tests, the other side looked at it as an unnecessary expense. Personally, I believe it is up to the dev team to identify key code components and write the tests. If you've a function that keeps breaking all the time, that is a great candidate for unit testing.
It is possible to write clean code on V1, this is what I do today. I've faced so many situation where I didn't and it ended up always costing me more time and working too many hours. I would rather to delay the release of v1 and having something stable than trying to please the business team at all costs.
Believe it or not, the business team don't give a f* about your codebase. Many times I reported security vulnerabilities and they thought I was creating problems lol. I've seen devs not reporting bugs because of the company culture.
As a developer, do your best and always keep learning and growing. If you do this, you'll produce better codebases naturally.
Negotiating with the business team is also key to have a sucessful release.
Business often doesn’t seem to treat developers (or any workers) as a first class value. This is true in the small just as much in the large. Hence the grotesque term “Human Resources”.
Writing “clean” aka pragmatic, well abstracted, robust, performant and readable code becomes naturally less “expensive” if practiced regularly (who would have thought).
So it is also an investment in developers: their skill, communication, happiness and engagement.
Disregard of that is short sighted and cynical. Just paying someone (well) instead of investing in them and growing with them leads to unhappy, stressed, uncreative workers, erodes trust and limits engagement.
b. It's all about extracting the max value out of your dev time. Will refactoring / improving code quality mean that future features get delivered quicker?
c. Most POC don't have tests from my experience. They are usually added later.
There not at odds.
And that's exactly what good startups do, they do business tests before they write any code. Don't write code at all unless it's providing value to the customers or helping you learn something you need to know to provide value to the customers.
Now that this is taken care of, we come to the problem of the code itself. Each bit of structure you add, whether it's a line of code or a database field on a table, is a bit of infrastructure you may have to maintain, possibly forever.
Some folks want to take their eye off the business tests and move directly to system tests, testing and then coding to make sure everybody can easily understand and maintain any code that's written.
Most startups fail because they never ever got the business tests working right. They either never got around to creating them and making them pass or they came up with something that worked but were unable to flywheel it or lost the plot somewhere. Some startups have almost-perfect code that nobody wants; that's actually one of the most common way of failing.
So the natural state of affairs is to always be experiencing some kind of stress between value discovery and code quality. Personally I believe you solve a lot of this by changing the way you code and the way you look at coding, but there's too much to go into here. The key thing for most programmers to remember is that if you're dying of thirst in a desert, you're not going to care very much if the guy selling glasses of water has glasses that leak or water that's muddy. The value proposition always comes before anything else.
But that's a tough thing to explain to a person that doesn't know any better. We're teaching coding as if it were a stand-alone thing instead of simply a tool to get us other things we want.
The variable names were random bollywood movie names, there was no class, functions all was hand coded in core PHP and it was too complex to add new codes.
As for some of these questions:
a) Yes I've seen a few companies go under because their code wasn't able to generate profits. A couple of times it's been so bad that customers didn't get what they needed immediately as a result. But usually the sorts of company failure modes from bad code are less dramatic. Sometimes this is like bad debt in that it looks good initially but comes at an existential cost later. Other times it's been more boring like lower velocity making the company uncompetative or too expensive to run.
b) If you are thinking of trading features vs code quality you've already lost because this isn't something that can be traded.
c) Writing some tests tends to be a pareto-optimal choice, in the sense that lower defect counts tend to allow you to create more economic value from the limited software development staff you have in a given time frame. Frequently you'll find that having some tests allows you to deliver things like features more efficiently than you would without them. High defect counts tend to result in not meeting requirements or unnecessary rework. There's a sweet spot here about tests and test coverage, there's definitely diminishing returns and getting to 100% coverage is very expensive because of the last few percent being disproportionately hard to get while not being worth the cost of getting it in many cases.
My enterprise would like to have a word with you. This is a trade they make daily.
Most likely you are startup building a software application service that is augmenting or automating or orchestrating some real-world interaction (like an e-commerce shopping or supply chain systems), then you care most about getting your product market fit figured out.
What this means is testing your understanding of the potential customer's needs, selling your product value to those customers (switching them from their existing way of life to your way of life), figuring out the business model (what costs are you optimizing, how much it costs you to run it your way, who will pay for it, can you cross-subsidize something, how does your business scale, at what scale your business becomes viable, at what point do you make profits etc).
This usually requires a lot of experimentation and product iteration. For this, you need to have very high feature developer productivity with very low costs for getting experiments wrong. For the past half decade, this is achieved by not building any IaaS/PaaS stuff in house and using stuff from some public cloud platforms.
Today, a new movement is happening – it is #lesscode or #nocode movement – you use frameworks and rapid application development tools that allow you to write very little or no code to create your applications and iterate quickly with very low software engineering skills. This allows a startup to go very far with very little burn while hunting for product-market fit.
Once you know you have a good product that is on the cusp of scaling, you can revisit your choices and figure out how to optimise costs through in-house software development. The bar is raising every year for what makes sense to build in-house.
Quality+Speed+Efficiency cowboy coding |0-----1------2-------3------4----5| perfect iphone
I would never expect a startup to be operating above 4 or 4.5, it might mean you are spending too much time future proofing.
The best teams operate around 3 or above, but they can do so because they are experienced, disciplined, trust eachother, have a set of tools they know very well, and can move at a quick pace because they automated a lot, have code patterns they follow and are not "re-inventing the wheel" or trying new frameworks for fun.
A LOT of startups are being started by inexperienced developers, where they jump onto some new language or framework, and end up doing a lot of non-core work due to inexperience and due to choosing some nascent framework. This immediately puts them at less than 3, probably between 1-2.
If you are at a 2, i would say you are doing OKAY, any less than that, and I would say you probably are suffering from inexperience, bad choice of frameworks, no tests, etc.
The biggest issue is not knowing your problems. If you are aware of your technical debt it means that probably you have a plan, or at least an idea of where to look when shit hits the fan. Otherwise people would run like crazy, deny the problems, miss deadlines and customers expectations and ultimately fail.
1) Code doesn't really matter as long as it solves the issue you are trying to solve. Don't expect your code to be beautiful from day 1. Be responsible and train your devs to be responsible as well, because in a startup you code, fix and deploy your own stuff. What does matter, though, is code complexity. Manage your complexity, don't overcomplicate things if you don't need to. No need to design a Ferrari when all you need is a horse and carriage.
2) Process matters. From day 1, make code reviews/pull requests the default. If you are the most senior dev, or a technical founder/CTO in a small startup be prepared to spend about 50% of your time reviewing code and helping others. You won't get to code as much, but you'll sleep better at night knowing at least you've tried to catch some bugs before they reach production. In an early stage startup, you will not have the time nor the resources to test everything, but this will give you peace of mind.
3) Tests matter. That being said, in the beginning only test mission critical stuff. If you find a critical bug, fix it and then write a test for it. If a new feature breaks something that already works it is a big no-no and might lose you customers. Testing will change for you as you progress with your startup. Start by making the process easy for the devs to run the tests locally. Then, progress in having CI. Then, maybe have CD as well.
4) Worst case scenario: full rewrite. If a 6 to 12 months old startup decides on a full rewrite. I'll give them the benefit of the doubt, maybe their whole use-case has changed, maybe they DO need a rewrite. That's fine. But, if you are a SaaS that is older than that and your dev team is around 10 devs and they are all busy solving critical bugs and putting out fires, a rewrite might mean your death.
5) Architecture matters. This matters more than code, in my opinion. Say you have a horrible piece of mission critical code, it is SLOW and begins affecting your business. That piece of code will need a rewrite, for sure. But what would you rather do: spend 30 days to fix it and lose customers, or just spin up another machine/add CPU/add RAM? This is a good architecture, it allows you to have time to think things through, allows your code to run well and perhaps most importantly, allows your developers to actually code.
Bad architecture is the leading cause for rewrites. Is that beautiful microservice architecture giving your small team headaches? Did you overcomplicate things, perhaps? You see, bad architecture is very hard to fix. People seem to underestimate how much a simple API + DB can scale and try to mitigate the risks by copying whatever FAANG does. Start small, scale later once you have the resources to do so.
TL/DR: Code quality doesn't matter if you solve your issue. What matters more is mitigating the risks that come with writing code in general. See above for some ideas that came from my own personal experience.