Getting Started with System Design!
Tags: design, architecture, microservices, codenewbie
Published: 2020-05-18 09:56:46

## Let's get you started with a real world example:
# *Opening a Restaurant(A Pizza Parlour)*


### **Opening of the restaurant:**

You open up the restaurant with a single chef. There comes a point that A single chef can not handle all the orders.

__*How would you then manage all the incoming orders then?*__

If you think like a manager, You'll ask the chef to work harder 😁. And you'll pay them more: Put more money, get more output.


Here: 
__*We are Optimizing Processes and Increase Throughput Using the same resource.*__  It's called __Vertical Scaling__

The other thing you can do is: If the order is a pizza, you can have some ingredients/pieces prepared beforehand so when the order comes, less time is taken.

__*Preparing beforehand during non-peak hours*__. It's termed as __Pre-processing & Cron Job__




### **Let's make the business Resilient:**

Let's say that chef calls in sick one day and you won't have any business that day, So the chef becomes a single point of failure.

What you can do for this kind of emergency:

Hire a backup chef, so, in case if the primary chef doesn't comes, you can employ the backup chef that day.

__*Keep backups and avoid single point of failure*__.  __Backups__


Aside from backups, what you can do is hire more primary and backup chefs.
That's buy more resources. It's called __Horizontal Scaling__.


### **Let's Expand our Business:**

Let's say you got 3 chefs in the Pizza shop and they have their specialties:
chef 1 and chef 2 got specialty in Pizzas, while chef 3's specialty is in garlic bread.

So, to efficiently get the orders done, when an order comes you can direct/route those orders according to the specialty of a chef.
If the order is of a pizza, you can send it to either chef 1 or 2 according to their availability etc. If you want any change in the recipe of a garlic bread, chef 3 is your man.

Let's make a team around the chefs that we have, 
Team1: totals chefs: 3, leading: Chef 3 (Getting all the Garlic Bread order)
Team2: total chefs: 3, leading: Chef 2 
Team3: total chefs: 4, leading: Chef 1
(Team 2 and 3 get all the Pizza orders)

Now all the pizza orders are being divided/routed towards the Team 2 and 3, while all the garlic bread orders are going to Team 1.

What you're doing is that you are scaling these three teams at different rates and dividing the responsibilities among them.

What we have here now is a __Micro-Services Architecture__.

At this point your restaurant/Shop is doing pretty well, able to handle different orders and this business is scale-able to a large extent.

But, What if, there is an electricity outage in this shop? You won't have business that day.
What if you loose licence that day? You won't have business that day.

You don't want your eggs in a single basket, you want a separate shop, in a different place may not have the same number of chefs, but, at-least you have a backup.


Now, we create a new shop __SHOP 2__. This is very we take complexity to a new level. An advantage of shop 2 is that orders close to its range, can be served by it.

Now if you receive an order, you need to be able to route it that either you want this order to be sent to __SHOP 1__ or __SHOP 2__. This is called a __Distributed System__.(partitioning) 
It's more response tolerant and gives a quicker response time.

Now let's say you have a customer who sent its order to the Central Authority(the routing mechanism), but you need some specific requirements to route that order to either __SHOP 1__ or __SHOP 2__. The parameter can be the delivery time.

Let's say, if you send the order to the __SHOP 1__, it takes 1.5 hours for it to deliver to the customer, as it's a popular shop. But the __SHOP 2__ only takes 1 hour to deliver the order.

So, the central authority should route the order to the __SHOP 2__, and as long as the Central Mechanism is getting real time updates, It can make __smart business decisions__, which means, __more money__. 

This central Mechanism is called __Load Balancer__.

At this point, The System is:
Scalable and Fault Tolerant.

__How to make it Future Proof?__(Extensibility).

You have a delivery agent and a pizza shop, and they have nothing in common, The delivery agent's concern is to only deliver the order as quickly as possible to the customer, while the shop's concern is to prepare the order as quickly as possible, it does not cares who is going to pick the order up.

We can see the separation in responsibilities. It's called __Decoupling the System__. (Separating out the concerns).

Let's say, __SHOP 1's__ oven becomes faulty or the __Delivery agent's__ bike becomes faulty. You need all the events(logs) happening in present or that have already happened. It's called __Logging and Metrics__. 


The __Most Important Point__, as a back-end engineer, you need to make your system as extensible as possible, you do not need to rewrite your code again and again to serve a different purpose.

For example, __Delivery Agent__ doesn't need to know that it's delivery a Pizza, it could be a burger tomorrow. __Extensible__

Finally, Now we are able to scale our business.

Let's recap and see what are the High level problems that we faced and how we resolved them:

Following is know as __HIGH LEVEL DESIGN__
 
###Order Overload --> Recruitment
###Complexity --> Separation of Concern
###Mishaps --> Fault Tolerance

__LOW LEVEL DESIGN__ has a lot to do with how you code, making classes, objects, functions, signature.