Who Cares if it Scales?
wickedsmaht.medium.com
wickedsmaht.medium.com
Building it to handle the load was actually really easy (the architecture naturally handled many simultaneous requests easily), but testing it was very expensive, because it also involved making external requests we had to pay for.
When the site finally launched, it did indeed get "a lot" of traffic. At its absolute peak, it hit around 20 requests per second.
Sigh.
Normalize your database in a practical way and you should be able to scale fairly well into typical growth. Bad database designs are the most common culprit I see.
Try one out of every 10 million.
FAANG. There's only 5. And all of them have been around for a long-ass time now. All the easy money is at the beginning, not when it is entrenched.
And that also makes me think of another example people always give..."I'm not going to dig for the gold, just sell the miners the tools." Right. Because you're the very first person who has thought of it. Unfortunately, that first tool seller is mostly likely going to get the monopoly. They set up shop on Main Street because they were the first people there. They have strong relationships with the suppliers of the mining tools, and buy in a huge quantity so get quantity discounts that allow them to sell for less than you can purchase them for. As the gold boom town is now, well, booming, real estate prices are skyrocketing, and all you can afford as the new tool seller is some side street at the edge of town. And, everyone knows the original tool seller, Bob, and everyone likes him and he has all kinds of customer appreciation actions - he will go into the saloon once a week and buy everyone in the place a round, have parties, etc.
Nobody is going to be the next Facebook, nobody. Unless they are. It's just not going to be you, any more than you are going to hit that $1 billion lottery. ("but you never know!!! I might! I might be the next Facebook AND win the $1 billion lottery all in the same week! You never know, it could happen! Plus a supermodel will want to marry me, but before I win the lottery and my company goes public so I know she'll love me for me!")
And, 100% agree on normalizing databases. Are there companies that don't?
Oh, and also, financials. Cash flows, financial controls. Make sure you never get in a partnership, ONLY a corporate structure. If you don't understand financial statements (balance sheet, income statement, cash flow statements), and you don't want to learn ("That's what CFOs are for") then you should not be a founder of a company.
Legal structure...yeah, you want to know that so you won't get diluted right out of existance.
"On May 15, 2012, Business Insider obtained and released an exclusive email from Zuckerberg detailing how he cut Saverin from Facebook and diluted his stake. Zuckerberg privately stated at the time, "Eduardo is refusing to co-operate at all ... We basically now need to sign over our intellectual property to a new company and just take the lawsuit ... I'm just going to cut him out and then settle with him."
- Carlson, Nicholas (May 15, 2012). "Exclusive: Here's The Email Zuckerberg Sent To Cut His Cofounder Out Of Facebook". Business Insider. Retrieved February 9, 2016.
Oh heck yeah there are.
Seriously, how does that even happen? They hire people without a computer science degree that doesn't know about normalization? I don't have any experience with that so I'm actually curious as to how it happens, if you know, and have had experience with that.
The biggest problem seems to be connections to the database. Front-end people use databases as a persistent store, and don't realize that databases have connection limits. Your front-end or middleware scales, but your backend won't.
Your data store should be able to handle your connection load. That might mean pulling the database information and putting it into a cache (redis, memcached).
You need to understand where the bottlenecks in your systems are/will be. Authentication is always a bottleneck; can your system handle 5 million attempts at authentication in a second? Probably not.
You also need to understand your failure modes and how to handle them. In the above case, exponential backoff won't really work. If you can only authenticate 1000 users a second the other 4,999,000 users will be hitting your service at exactly the same time, every time. Randomly distributing them across the backoff interval is pointless.
And even at your fastest throughput authenticating your users will take 5,000 seconds, or around 83 minutes. That probably won't work out. Assume you need to store tokens for all of the users, well, that means 1,000 writes to the DB a second. That probably will fail as well.
Most of the time you'll be lucky to get a few thousand users. But at some level you should understand what you'll need to do if you get lucky and your utilization pops.
The problem is that you do need to understand your end-to-end architecture to do this sort of analysis. And experience counts; if you're aware of what you need to do you can design things in such a way as to make scaling easier (ie: no major rewrite required).
The front end, however, was only capable of < 5 messages per second and since no one at BigCo anticipated their side would be the problem, they had absolutely zero anticipation of having to solve anything on their end.
Every solution will be fine for a while, but will break at a different scale.
The goal isn't to get something that scales from the get-go, the goal is to make it so when you do need to scale you can do it without a ton of work.
Building for millions of users is expensive, time-consuming, and difficult. If you're a startup with limited funding design for a small number of users first, because you won't get millions of users. Then as your user base ramps up start upgrading your pain points.
If you do hit that millions-of-users mark immediately, hit up your backers for more money and throw hardware at it until you have time/space to rebuild your stack.
The other problem with continually and habitually silencing (perfectly valid) scaling concerns is that the people who are being condescendingly told that they're "prematurely optimising" will eventually leave. When you turn this article's advice into a Harry Potter-esque spell that somebody can shout during a design session: "Premature Optimisation!" it will get abused by people who don't like detail, or want to make some stupid deadline that they agreed to before they thought deeply enough about the problem space. How long can you retain good engineers if they're constantly battling against this? When you finally saturate some choke point and your system begins to fail in unexpected ways, or your costs are too high and you suddenly realise that scalability also means scaling down too, those people who you silenced might not be there.
I was once told, while cobbling together a metrics solution spanning 8 data centers that some of the things I wanted to spend a day or two on were "premature optimisation". Until we switched it on. It was dropping 50% of metrics on the floor (useless for alerting) and we got a call from the networks team because it was saturating the links. I spend those two days on my optimisations it worked. We were extremely lucky that the breakage happened at the start, and not months later. We were lucky that it didn't just turn into a random alert for a random team in the middle of the night. We were lucky that we had a network team monitoring things adequately. We were lucky that we didn't build more things on top of the bad design that relied on it.
Sometimes one man's premature optimisation is another man's due-diligence. You need to be sure that your rewarding the right behaviours.
If something works for decades and then has to be replaced due to scale, that's a good problem to have. The unwillingness to replace things is where it all goes awry.
OTOH, wanting to _rewrite_ should almost always be told no.
There were so many red flags at that company, and inability to scale was just one, for sure. But these things sometimes come as a complete package.
I think my problem with the article is that it thinks it's selling some generically applicable advice. But the wrong type of company with inexperienced engineers can take the wrong message from that article and totally fuck up an otherwise promising product.
That said, personally I think that there are a few things that take very little effort and can help you avoid a "singleton" application, which cannot be reasonably run on more than one instance and thus presents not only horizontal scalability risks, but also serious risks in regards to downtime since startup might be so long that your single instance going down or needing a restart will result in a prolonged downtime.
For starters, I think that the 12 factor app principles are pretty good: https://12factor.net/
But for the most part, you just want to lean towards a "shared nothing" architecture, where you don't use local memory or local file system for persistent storage of any kind (e.g. files, session information, application caches). Sure, those are bad practices in general (e.g. all sessions being lost after an application restart if they're ever stored in memory, or even counting on a temp directory for persisting them) but I've seen them in plenty of applications in the past.
Those decisions might not be too hard to fix individually once you do care about resiliency, but if you're looking at a monolith that has been around for 5-10 years and now needs to be refactored, you're pretty much out of luck, since I've seen some with lots of tight coupling. I've actually talked about that in the past here on HN: https://news.ycombinator.com/item?id=32182047
In essence, what I'd advocate for would be doing the bare minimum towards being scalable, the things that are easy to do and also simple: like using a separate Redis instance for your caches/sessions, using S3 for storing files, always using some database for your data persistence, even if just a single instance in the beginning. Things like using feature flags in front of your scheduled processes, or enabling/disabling certain modules are underrated.
Then, if you hit a performance bottleneck 2 years down the line, you'll be able to address it relatively easily. And if you don't? You'll still have a nice architecture that should lend itself to changes well, as well as throwing out pieces and rewriting them in something else if you want (e.g. your PDF framework doesn't run on anything other than JDK8 so you need something else).
That said, if you're working on small projects that aren't meant for a business and don't exactly have customers (that expect some sort of an SLA) to worry about, then even something like SQLite being your entire persistence layer might be enough.