Last week I heard back from a company hiring for a production engineer, and they told me that I passed a coding challenge I'd taken a month prior, and I'd be having an interview in a couple weeks. I was ecstatic!
They provided details on my interview, that would be split into three parts:
- Coding (Yes!)
- Systems Design (Wat?)
- Behavioral (Yes!)
I had never ever heard about System Design, but I had two weeks until I was going to interview for this awesome position. So I decided to hit the books.
The definition of a System is a set of things working together as parts of a mechanism or an interconnecting network.
In this way, System Design for Software is similar to a Library System.
If you wanted a convenient way to share books between people, you might build a small library, maybe with a single person handling all the tasks of library-ing like:
- Checking out books
- Taking late payments
- Cleaning and re-stocking the shelves
What if your library starts to gain popularity, and soon hundreds of people are coming in to use it? You may need to design the library infrastructure such that it reliably serves the increased library traffic. Maybe you'd add shelves to hold more books? Maybe you'd assign specific jobs to specific people (e.g librarian etc.). Perhaps each person might have a backup who's on call in case they are sick? This is one example of designing a reliable and efficient library system.
In this same way, if you write some code that does something useful, say... a library API. Maybe you built a single application that:
- Manages check-outs
- Handles transactions
- Signs In/ Creates User accounts
And let's say that people love using your API, and a lot of people want to use it, we mean MILLIONS of people. You may add more servers and databases? Maybe you'd separate your central system into modular systems for each API service? Maybe you'd install backup servers or databases to make sure the API is always available. This is one example of software system design.
Here's what I think the perks of knowing the basics of System Design are:
- If you want to build useful apps that help people on a larger scale, familiarity with the infrastructure that makes your frontend and backend go will really help you pick the right technology (i.e parts of the system) for the job.
- Most larger companies build and maintain large systems, and thus System Design knowledge seems to be valued by these companies!
- It is full of technical jargon, which means you'll look smart ;).
Client: For all intents and purposes, consider it as an entity that makes requests of servers. This could be a React application making a fetch request, or a browser requesting access to a URL.
Server: It's a computer/program that takes requests from the client directly or from another component and interacts with other components like a database. This is like a controller/model pair in Rails that persists, retrieves, or updates things from a database.
Service: Pretty ambiguous term. It's a feature-specific thing the system does for you. This is like an URL shortening Service, or Netflix Streaming Service.
Database: Structured data held in a computer that persists. These are like your SQL databases hooked up in a rails backend
Request/Response: Communication typically sent between client/servers following an application protocol like HTTP. I can't really explain it better than this.
Latency: How long it takes to get a response.
Bandwidth: How much data can be passed through (aka throughput).
At a very high level, the two main pieces of a web application are:
The Frontend Client: Anything that is making the request to the backend server(s). In a Rails-React app this would mean the React project would be the Client.
The Backend System: The part that handles requests from the Client through HTTP or similar requests and persists data if necessary. This could be a cloud service, or an API that I built in backend hooked up to a PostgreSQL database.
The System simply takes requests, handles it, and gives a response back to the Client. System Design focuses on the Backend System.
So far, in the past two days, I've learned of two structures/architectures for the System: the Monolith and Microservice Architecture.
Put simply, a Monolithic System Architecture means you have a backend system whose full functionality resides with a single unit (think of it as one giant program or machine). This architecture "style" applies to the servers as well as the database.
Server: Single program/machine that handles all fetches for all resources
Database: If you have a single database holding all the data.
If you ever built a Rails backend, that is a completely monolithic architecture. I'm pretty familiar with this so this was a bit of an 'Ah-Ha!' moment
Microservice Architecture means that you split responsibility among different units, thus being modular. This also applies to both the server and the database.
Server: If you have separate programs/machines that focus on taking fetches for different resource (or service).
Database: If you have multiple databases, perhaps one database for each resource.
I have never built anything based on this architecture, but I have heard of some technologies that use this architecture such as MongoDB for databases and Microsoft Azure for servers. I would like to get some hands on experience at some point, hopefully before the interview.
Just like there are principles when writing code (an example being the 4 Pillars of Object Oriented Programming), there are also System Design Principles. Here's what I found in my studies:
1) Scalability - What if your product/service gets popular? Are you going to buy more servers? Are you going to replace your current server with a bigger one? etc.
2) Reliability - What if part of your product/service unexpectedly turns off? Do you have backup servers? etc.
3) Availability - How often will your product/service be usable? 100% of the time (never needs maintenance)? 10% of the time?
4) Efficiency - How quick is the response to a fetch (aka latency) and how much data can pass through the system (aka bandwidth)
5) Serviceability - How easy is your product/service to operate and maintain?
As I'm learning more about the components in Monolithic and Microservice design, I'll keep these principles in mind, as they typically govern why one design decision is made over another.
So, if I were trying to build my own software product, which one should I use?
As someone who has been learning about this for less than 2 days, I don't know the definitive answer. But from my research, there are advantages and disadvantages of both systems and typically it's wise to incorporate both architectures into your system to reap the benefits of both.
- Quick internal processing time: Because everything lives in a single system/machine, things DO NOT need to communicate over the network/internet. This speeds up how quickly this system can perform.
- Consistent Data: Since everything is localized in one place, it's easier to make sure things are updated before returning data to the client.
- Less Complex: You don't have additional parts to manage separate & distinct services. Designing it is less complex.
- Hardware limitation: Imagine having to turn off a huge system that serves thousands or millions of people every time you had to update it. Also, following a monolith architecture, upgrading your system means replacing it with something bigger and better, which works only until a point (space limitations etc.)
- Single Point Of Failure: If one part of your monolith breaks, your entire monolith breaks. This is like having one giant script with a syntax error on line 43,287. Your entire script will come to a grinding halt.
- Scales Well: Because a Microservice isn't one giant thing, and is instead modular pieces that are connected via a network, when you want to add more capacity, you can add infrastructure anywhere in the world. Also, because your system is made up of independent parts, integrating a new service doesn't affect the availability of other services (nothing needs to be shut off... in a sense).
- Resilient: If one of your servers suffers a catastrophic failure, like a rat chewing on wires, or the intern accidentally flips the power switch, your entire system won't crash. One of my peers gave me a perfect example of how Netflix's recommendation system might go down, but you can still watch your movies (you probably wouldn't even notice).
- Higher Latency: You have separate systems, which may need to communicate via the network/internet. This will bog down the system.
- Inconsistent Data: Since your system is broken up or "distributed", getting the most up to date data is not a given. You'll need to account for this.
- More Complex: There will be additional components because there's more to manage in a microservice architecture. You'll also need to connect them, which is another design hurdle.
What has been covered in this blog post is very High Level Design. Actually implementing these architectures (Low Level Design) is incredibly complicated and I am currently learning how to further break down systems into functional components before I apply my coding skills to implement them. There is so much left for me to learn, and I'll be trying to cover them in some subsequent blog posts. My hope is that it might help another developer with little to no knowledge of System Design feel less intimated by the subject and find some direction so they might also get prepped to take an interview that involves System Design.
If at this point, you're still interested in learning more, I'll leave a couple resources at the bottom of this post.
The next steps in preparing for my system design interview will be:
1) Learning the specific components of a distributed system (Caches, SQL, noSQL, Load Balancers, Proxy Servers) and understand their uses and how they work.
2) Learning about strategies for optimization such as Data Partitioning, Indexing, Consistent Hashing and other words that at this point sound like jargon to me.
3) Understanding the process of answering system design questions in an interview environment
4) Breaking down a couple large well known system services such as Facebook Messenger, Instagram Posts, Netflix Streaming and trying to explain it in a way that even I can understand it.
I'll see y'all in another blog post!
Good luck with your own endeavors!