Systems Design for Advanced Beginners
robertheaton.com
robertheaton.com
1. Prototype and benchmark each of your stack pieces before you pick a stack. It is far easier to fix architecture mistakes when you don’t have 10000 users expecting overnight customer service. If you are using new technology, find good open source products to see how they’ve structured their projects. Your architecture, designed for speed and experience, will be your key differentiator. Inherent speed at core task, design to user needs, and name choice are the 3 musketeers of a solid growth.
2. Prepare for abusers to attack your system from every direction, especially if you enable users to publish content under your domain. You will see bots looking for Wordpress installations, users trying to fill content with SEO links, users trying every hacking vector known to market. Collect known vectors and test for them and never refuse a legitimate bug bounty request.
3. There is an eternal debate about the trade off between building a quality product at start or opening early to get user feedback before you get too deep into features. There is merit to both choices as a solo founder. The moment you open the gates to users, your ability to make changes comes with very high friction. With time, trying new features becomes a tremendous luxury hidden under bug requests, roadmap, customer service replies, etc. Build your biggest riskiest assumptions first.
4. Testing is hard as a solo founder. Selenium is your friend. If you don’t spend time with them, your users will take that time in multiples after a mistake.
The best way to learn is to come up with a product you really want and build it in your own time. You can test launch in a weekend.
When I started launching consumer sites solo as an engineer, I went from a tight specialization to being unafraid to try any tech if it gives me an advantage in solving a problem. Once you’ve simulated enough problems and dealt with the consequences of your choices personally, you can play that 10 level chess game with the architecture of each new feature much faster.
The companies I've seen succeed were 100% focused on shipping their product to customers. Not 90% focused on customers and 10% focused on code quality, but 100% focused. They'd rather have to spend 30 engineer-days a few years from now fixing an issue if they get to that point than spend 3 hours getting it right upfront.
As an engineer that goes against every instinct I have, it really seems like spending a couple hours upfront must be a better use of time. It seems like it should be possible to spend 10% of your time setting yourself up well for the future, that's still just a rounding error of your time. And then if you do survive another few years, you'll have a huge leg up on other series B or C stage competitors if you're not hindered by a lot of tech debt at that point.
But from a capitalist perspective, it's probably not so crazy. If you are working with a $200,000 seed round in the beginning, and an engineer costs $80,000 a year, 3 hours of their time costs $115 which is 0.06% of your funds. And more importantly, that $200k is maybe enough for a year of runway, so 3 hours is 0.14% of the time you have to live given a 40-hour a week year (or 0.07% of an 80 hour a week year). Every bit of that starts to add up. Whereas by the time you're a later-stage company and you've raised, say, $40 million dollars and are paying engineers $150k, 30 engineer-days of work is $17,300 but that's only 0.04% of the money you've raised plus your runway is now approaching infinity if you're close to profitable.
I'm still kind of playing devil's advocate here, my instinct really wants to believe that a better balance than what I've seen is possible. One huge missing factor is that people have a strong tendency to ignore spread out costs like the time wasted fixing bugs that pop up later whereas the upfront cost of writing a bunch of tests is more visible. But it has been interesting for me to consider that maybe most founders really are acting pretty reasonably, even though it originally seems pretty careless and lazy to let your startup build up a ton of tech debt early on.
If you'd like a guided video code-tour of how all the pieces of a production web-app fit together, I publish detailed weekly screencasts showcasing the code, systems, and architecture behind Oxbridge Notes, the business that's supported me for the past decade.
So far I've covered:
— software dependency vetting
— data integrity systems (constraints, foreign keys, transactions etc.)
— integration testing systems
— trade-offs in software quality between customer-facing and admin areas
— softer stuff, like designing for SEO (marketing ease is a critical part of any system I design, as an indie-hacker)
Just a heads up - I tried to sign up for your mailing list but kept seeing "ERROR: Did you forget to type your email?" even after typing the email. I've tried a few different emails and also tried viewing the page in incognito mode. Hope you get this fixed soon, as I'd really love to get more of your content!
Also, it'd be great to be able to turn off the mailing list sign up on the videos. I'm already technically subscribed via RSS and it'd be great if the videos play through without intervention
+-----------+ +--------------+ +-----------------+
|Web Browser| |Smartphone App| |Client Libraries/|
+-----+-----+ +------+-------+ |Other API code |
| | +-------+---------+
| v |
| +-----+------+ |
+--------->+ Steveslist +<-----------+
| Servers |
+------------+
Why not this? +-----------+ +-----------------+ +--------------+
|Web Browser|-->|Client Libraries/|<--|Smartphone App|
+-----------+ |Other API code | +--------------+
+-------+---------+
|
v
+-----+------+
| Steveslist |
| Servers |
+------------+See openapi/swagger for good examples how client generation works
Of course, the generated client is not very convenient, being a 1-to-1 mapping with the API. You build a high-level client with the more common operations on top of the generated one.
It's possible to do this in a way that gets you the best of both approaches, with some up-front planning.
That stuff is only done at the end unless you're chargin for that at the beginning.
If you're not B2B positioned, you probably won't have a client library for a while.
> Calculating a hash value from an input is computationally very easy, but reversing the transformation and recovering the original input from its hash value takes so much time and computing power that it is, practically-speaking, impossible.
The above is true for encryption but not for hash codes. Recovering the original input from a hash code is not just practically impossible; it's provably impossible -- even with an infinite amount of computing power -- because in general a hash code contains less information than the original text.
The phrase you mentioned is notable (with a slight edit) - so I suppose you mean you could index phrases by notability, then it may be tractable find tweets of notable phrases, since the number of notable phrases is relatively low.
It's actually kind of a fun problem -- the fewer bits you have in your hash the easier it is to find _any_ collision that gives access to the current system, but the harder it is to uniquely reverse the hash into a plausible password for stuffing into other systems.
That is true, but has nothing to do with your ability to use a rainbow table or dictionary attack on my hashed statement.
The specific reason why you can reverse my hash is because it's unsalted. The time-complexity of my example hash is somewhat low.
'you are wrong' is 13 characters that spans the lowercase alphabet with spaces, in all english words that can be found in a dictionary. The actual key-space is 13^10 because of the limited characters I used, but when creating a rainbow-table it would probably take a key-space of 13^27 because you don't know the specific characters I'm using. (There are 13 characters in my statement, then there are 26 lower-case letters in the alphabet - plus space - which makes 27... 13^27)
Now, if I followed general op-sec suggestions I would have added a salt to my statement, so the process looks like SHA512('you are wrong' + '7aomAxgeVjAvyDXGrdmNJNKuuiumYbkG') which gives you the possible key-space of 45^63. Also, the salt should be something not found in a dictionary.
2812CDA67BF0EA2D5FE125C2637466FA9A81C12AE9D101771C581DB87EBEB05D7724C9DCFBC6F905B99F9737948543EC64CAC5D89C785125DDA2E3297214CC58
On the upper-side of the estimate there are 10^82 atoms in the universe. There are about 14^103 possible solutions to that salted hash above, with many possible collisions. Good luck with creating a database that needs more rows than available atoms, or waiting for a brute-force to complete on that hash, then sorting through the collisions. This is the "impossible" reversible hash you are talking about.
If you are interested in this topic and would like to do this in your code: use the HMAC function which is built for this, or specifically for passwords use bcrypt/blowfish because that algorithm is designed to run slowly (brute force protection).
SQL.
> How do their different applications talk to each other?
Proprietary APIs.
> How do they scale their systems to work for millions of users?
T H E C L O U D
> How do they keep them secure?
They just... don't.
> How do they make sure nothing goes wrong?
They just... don't.
> What are APIs, webhooks and client libraries, when you really get down to it?
Easily outsourced to India.
What kind of a job profile should I be looking at if I am in a position where I absolutely need to have one?
I don’t slot particularly well in any one thing I feel, neither a great developer nor a great systems person. And I did do a bunch of recruiting and tech consulting too:
Also, the sibling commenter mentions one of the big reasons I found so much joy in it. This kind of hardcore technical support is in many respects closely related to working on greenfield projects. In my experience, the fun stuff usually ends up with some unfun caveats like company bureaucracy, office politics, or having the tech stack chosen beforehand, this kind of thing. But there's an interesting inversion when a company's production environment is broken and you're the one that can fix it. Obstacles magically disappear and you have a tremendous amount of freedom to do your job, with effectively two different companies doing what they can to enable your work, because the only thing everyone cares about is getting it working again.
You do have to be able to walk the walk -- and I cannot stress enough that it takes a certain type, and just knowing your shit isn't going to cut it -- and you also have to get some personal enjoyment out of chaotic environments, and be able to talk people out of a tree sometimes. But you'll never run out of new and interesting problems to solve, you'll be testing your mettle far more frequently than your peers, and you'll be expanding your professional network every week about as much as everybody else does once or twice a year when they go to a convention. It's the closest thing the tech industry has to a firefighter or superhero or something.
Recently a client asked if I can help reverse their own android app because the developers were holding their source code hostage. It was lots of fun and lots of struggle but overall satisfying.
Maybe something like basic security freelance work especially basic webapp security(xss,sqli,csrf, the likes) and some process security with maintaining proper logins, maintaining and rotating credentials etc.
Thank you for your ideas.
Frontend/full stack agency developer (node/react).
Eventually you get to enjoy deprecating old services as much as building new ones, simply because you never have to teach others about them again.
Do people use Kubernetes for running scheduled jobs like this? It seems like it'd be overkill but in saying that I'm not sure if I know of anything that can be used for running scheduled tasks in a reliable and observable way that's scalable. Maybe Jenkins?
We do, mostly because we already have Kubernetes and automation to deploy to it, so why not? The reliablity and monitoring are better than something we'd cook up on our own.
azure devops, jenkins, concourse, drone, gitlab, ...
also a lot of etl tooling has this stuff (airflow comes to mind immediately)
there's also nomad which is easy to run and can schedule a lot of jobs pretty quickly, with decent observability.
there's... a surprising amount of tooling in this exact space!
Alternatively you could be the tech person in a 2 man startup that lucks onto success and grab onto your seat in a wild ride and just never let go.
The default/common path is evolving into the architect role which seems like a "bad" process of developing an architect.
The best way to develop a new architect, is to have him learn alongside a mentor/teacher who is an architect himself. Developing and architecture are very different jobs which require different mindsets and skills. Also, I've seen many places, teams, etc where people are mostly made to implement feature after feature with no time in between for learning, self-development, courses, etc.
Otherwise, after you've just "arrived" to that architect role you start learning on your own what architecture really is and means.
If you can find someone who needs something for their business or organization, you'll learn a lot of this by working backwards from what they need and building it. So I would suggest the opposite: the smaller the organization the more you can jump around and set up the basics of all these things.
Don’t sell yourself short: there are systems everywhere you look, not just where there’s convenient precedent to make a web service.
What kind of query would you have to write to bring down a production db? What makes a solution like hive much better - I guess its optimized for this?
Scans and Sorts, seen in a query plan, are relatively expensive to run in a production row store. OLAP queries (GROUP BY with aggregate functions like COUNT, SUM, and AVG) do large^/full table scans by definition. They take seconds to run while your goal in a Cloud OLTP system is thousands of requests per second. An automatic sort issued per query in an OLTP system is pathological and represents a vector for a DoS attack.
> What makes a solution like hive much better - I guess its optimized for this?
Column stores use compressed bitmap indexes that are optimized for scans over a small number of columns. Hive is SQL over Hadoop, and is inherently slow but it does offload the processing from your Production OLTP server. Hive supports the RCFile format which is partially column oriented. The ORC file format is fully column oriented, replaces RCFile format, but requires Presto (or equivalent). Hive is brownfield for existing Hadoop clusters but it has no place in a discussion about greenfield architecture other than discussing historical systems.
If you have a need for GROUP BY style analytics, a true column store like Presto, Impala, or RedShift is a necessity.
^EDIT: based on zbentley's comment
Isn't it only a full table scan if your query isn't otherwise filtered? Those functions have to read every row of "something", but that something might not always be a whole table.
:facepalm: beanstalkd can handle a pretty massive amount of jobs before you need to start worrying about scale. I love the huge jump from simple to complex.
Even with proper indexing? I haven't seen this issue with Postgres but maybe I wasn't working on large enough data sets.
Looking at the request/response headers in Firefox's web developer tools, it's gone through Cloudflare, but there's also a x-github header, so maybe some custom tooling that's pushed content to github?
Usually you have plenty of themes to choose from. I use Hugo and can tell you there are many themes similar to the one in this website.