Ashish's Wiki
This wiki is a curated collection of insights, best practices, and learnings from my journey in software engineering. It covers key concepts and code examples aimed at deepening technical understanding.
Links
[Website] [Notes] [Uses] [Todos] [Listens] [Movies] [Shows] [Books]
Topics
Main topics covered by this wiki:
Algorithms
- Recursion
- Sorting
- Round Robin
- Divide And Conquer
- Backtracking
- Greedy Algorithms
- Dynamic Programming
- Asymptotic Analysis
Asymptotic Analysis
A problem with complexity O(n) which takes 2^60 times will take 60 times in O(log n) complexity
<-- Fast | Slow --> | ||||
---|---|---|---|---|---|
Name | Constant | Logarithmic | linear | Quadratic | exponential |
Notation | O(1) | O(logn) | O(n) | O(n^2) | O(k^n) |
for(var i...){ // O(n)
1+1; // O(1)
}
/**
* Complexity = O(n^2) + O(2)
* We only care about worst case so we consider the worst time complexity only.
* i.e we take the highest order of the polynomial
* So the complexity is O(n^2)
*/
for(var i...){ // O(n)
for(var j...){ // O(n)
3+3; // O(1)
5+6; // O(1)
}
}
O(log n)
for(let i = 0; i < n; i*2){ //O(log n)
stmt;
}
Backtracking
- Technique used to solve problems with a large search space, by systematically trying and eliminating possibilities.
- Hence applied to problems not solvable in polynomial time and which are generally solvable using exhaustive search.
We use backtracking for NP Complete problem (Hard problem). As hard problem requires exponential time to solve it systematically.
- Each step tries to extend a partial solution by adding another element at the end.
- Tests if a solution is obtained. If yes, output, count and continue
- Otherwise checks, if it is extendible. If yes, continue.
- Otherwise backtracks.
Steps
- Construct the state space tree
- Explore the state space tree using depth first search.
- Prune non promising nodes.
State space tree
- A tree of choices being made.
- Root represents an initial state.
- Nodes of the first level represent the choices made for the first component of the solution.
- Nodes of the second level represent the choices for the second component.
- Thus each node represents a partial solution.
- An edge from node x to y exists if y was created by advancing from x.
Nodes
- Node is promising if it corresponds to a partially constructed solution that may still lead to a complete solution.
- Otherwise it is called non-promising.
- Leaves represent either non-promising dead ends or complete solution found.
Examples
- Finding a hamiltonian circuit
- Finding the most valuable subset of items in a knapsack
- Going through a maze
- Solving the 8-Queens problem
Divide and Conquer
In Divide and Conquer, the problem is divided into smaller sub-problems and then each problem is solved independently. The solution of all sub problems is merged to get the solution of the origin problem.
Examples
- Merge Sort
- Quick Sort
- Binary Search
- Strassen's Matrix Multiplication
- Closest pair (points)
Dynamic Programming
In Dynamic programming we break up a problem into a series of overlapping subproblems and build up solutions to larger and larger subproblems.
Examples
- Fibonacci number series
- Knapsack problem
- Tower of Hanoi
- All pair shortest path by Floyd Warshall
- Shortest path by Dijkstra
- Project scheduling
Greedy Algorithms
Introduction
In greedy algorithms, we find the optimum solution. The closest solution which may be optimum is chosen. It may lead to optimized solutions but mostly greedy algorithms do not provide globally optimized solutions.
Examples
-
Travelling salesman problem
-
Prim's Minimal Spanning Tree Algorithm
-
Kruskal's Minimal Spanning Tree Algorithm
-
Dijkstra's Minimal Spanning Tree Algorithm
-
Graph - Map Coloring
-
Graph - Vertex Cover
-
Knapsack Problem
-
Job Scheduling Problem
Recursion
The process in which a function calls itself directly or indirectly is called recursion.
Round Robin
The Round Robin scheduling algorithm is a simple and efficient method used in operating systems to manage processes. It allocates a fixed time slice or "quantum" to each process in the queue, cycling through them repeatedly.
How It Works:
- Processes Queue: All processes are placed in a queue.
- Time Quantum: Each process is given a fixed amount of time (quantum) to execute.
- Cycle Through: The scheduler cycles through the queue, giving each process its turn.
- Preemption: If a process doesn't finish within its time slice, it is moved to the back of the queue.
Example:
Suppose we have three processes, P1, P2, and P3, with a time quantum of 3 units.
-
Initial Queue: P1, P2, P3
-
Execution Order:
- P1 executes for 3 units, then moves to the back.
- P2 executes for 3 units, then moves to the back.
- P3 executes for 3 units, then moves to the back.
- Cycle Repeats: Each process gets another turn if they haven't finished.
Advantages:
- Fairness: Each process gets an equal share of CPU time.
- Simplicity: Easy to implement and understand.
Disadvantages:
- Inefficiency: Time quantum needs to be carefully chosen; too small can lead to high overhead, too large can cause delays.
This approach ensures that all processes are treated equally and prevents any single process from monopolizing the CPU.
Sorting
Bubble Sort
It works by swapping the adjacent elements if they are in wrong order. It is the most inefficient sorting algorithm because of simple it is. It has the time complexity of O(n^2). Insertion sort is better than bubble sort because it has the same asymptotic complexity but only requires O(n) swaps whereas bubble sort require O(n2) swaps.
Psuedocode
let n be the length of the array
for i from 0 to n-1
for j from 0 to n-1-i //The last element is already sorted after each pass
if arr[j] > arr[j+1]
swap(arr[j], arr[j+1])
let the array be [3,2,4,1]
i=0
j=0 //[3,2,4,1]
3>2
swap(3,2) //[2,3,4,1]
j=1 //[2,3,4,1]
3>4
j=2 //[2,3,4,1]
4>1
swap(4,1) //[2,3,1,4]
i=1
j=0 //[2,3,1,4]
2>3
j=1 //[2,3,1,4]
3>1
swap(3,1) //[2,1,3,4]
i=2
j=0 //[2,1,3,4]
2>1
swap(2,1) //[1,2,3,4]
Diagram
Optimization
we use a flag to track if there is swapping taking place, if there is no swapping it means the array is already sorted so no need for more pass.
for i from 0 to n-1
swapped = 0
for j from 0 to n-1-i //The last element is already sorted after each pass
if arr[j] > arr[j+1]
swap(arr[j], arr[j+1])
swapped = 1
if swapped == 0 // No elements are swapped so stop the loop
break
Insertion Sort
Insertion sort algorithm sorts an array by inserting an element from the unsorted part to correct position at sorted part.
Selection Sort
Selection sort algorithm sorts an array by repeatedly finding the minimum element from unsorted part and putting it at the beginning.
Psuedocode
let n be the length of the array
for i from 0 to n-1
min = i
for j from i+1 to n-1
if arr[j] < arr[min]
min = j
temp = arr[i]
arr[i] = arr[min]
arr[min] = temp
let the array be [3,2,4,1]
i=0
min = 0
j=1 //[3,2,4,1]
2 < 3
min = 1
j=2 //[3,2,4,1]
4 < 2
j=3 //[3,2,4,1]
1 < 2
min = 3
swap(a[i], a[min]) //[1,2,4,3]
i=1
min = 1
j=2 //[1,2,4,3]
4 < 2
j=3 //[1,2,4,3]
3 < 2
i=2
min = 2
j = 3 //[1,2,4,3]
3 < 4
swap(a[i], a[min]) //[1,2,3,4]
```<style>
.scroll-to-top {
font-size: 2.5rem;
width: 3.2rem;
height: 3.2rem;
display: none;
align-items: center;
justify-content: center;
position: fixed;
padding: 0.75rem;
bottom: 4rem;
right: calc(1.25rem + 90px + var(--page-padding));
z-index: 999;
cursor: pointer;
border: none;
color: var(--bg);
background: var(--fg);
border-radius: 50%;
}
.scroll-to-top.hidden {
display: none;
}
.scroll-to-top i {
transform: translateY(-2px);
}
@media (min-width: 1080px) {
.scroll-to-top {
display: flex;
}
}
</style>
<button type="button" aria-label="scroll-to-top" class="scroll-to-top hidden" onclick="scrollToTop()">
<i class="fa fa-angle-up"></i>
</button>
<script>
const scrollToTop = () => window.scroll({ top: 0, behavior: "smooth" });
window.addEventListener("scroll", () => {
const button = document.querySelector(".scroll-to-top");
button.classList.toggle("hidden", window.scrollY < 200);
});
</script>
<style>
footer {
text-align: center;
text-wrap: balance;
margin-top: 5rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
footer p {
margin: 0;
}
</style>
<footer><p>Copyright © 2024 • Created with ❤️ by <a href="https://ashish.me">Ashish Patel</a></p>
</footer>
C Sharp
Delegates
Delegates is an object that knows how to call a method or a group of methods.
Design Patterns
Design patterns may be said as a set of probable solutions for a particular problem which is tested to work best in certain situations.
Creational Patterns
These patterns deals mainly with creation of objects and classes.
Factory Method
Factory method design pattern abstract the process of object creation and allows the object to be created at run-time when it is required.
using System;
namespace FactoryPatternDemo
{
// 'IProduct' Interface
interface IFactory {
void details();
}
// 'ConcreteProduct' class
class PermanentEmployee : IFactory
{
public void details()
{
Console.WriteLine("This is permanent employee type object");
}
}
// 'ConcreteProduct' class
class TemporaryEmployee : IFactory
{
public void details()
{
Console.WriteLine("This is Temporary employee type object");
}
}
// 'Creator' abstract class
abstract class EmployeeFactory
{
public abstract IFactory Factory(string employeeType);
}
// 'ConcrteCreator' class
class ConcreteEmployeeFactory : EmployeeFactory
{
public override IFactory Factory(string employeeType)
{
switch (employeeType)
{
case "PermanentEmployee":
return new PermanentEmployee();
case "TemporaryEmployee":
return new TemporaryEmployee();
default:
throw new ApplicationException(string.Format("This type of employee can not be created"));
}
}
}
// factory method design pattern demo
// calling class/ client
class Program
{
static void Main(string[] args)
{
EmployeeFactory EmployeeFactory = new ConcreteEmployeeFactory();
IFactory permanentEmployee = EmployeeFactory.Factory("PermanentEmployee");
permanentEmployee.details();
IFactory TemporaryEmployee = EmployeeFactory.Factory("TemporaryEmployee");
TemporaryEmployee.details();
Console.ReadLine();
}
}
}
Singleton Method
Structural Patterns
These patterns deals with Class and Object Composition.
Behavioural Patterns
These mainly deals with Class - Object communication.
Entity
Entity Framework is an open-source ORM framework for .NET applications supported by Microsoft. It enables developers to work with data using objects of domain specific classes without focusing on the underlying database tables and columns where this data is stored.
Generics
Generics allow for designing a classes and methods whose types are specified only at the time of declaration and instantiation.
Without generics we will have to create class for every datatype. We can use object but it will involve boxing and unboxing. With generics, there is no need for that.
Advantages of Generics
- Casting is not necessary
- Generics makes code type safe
- Code is not duplicated for multiple types of data
using System;
using System.Collections;
using System.Collections.Generic;
public class Employee {
public string Name {get; set;}
public int EmployeeId {get;set;}
}
public class EmployeeList {
public List<Employee> employeeList = new List<Employee>();
public void addEmployee(Employee employee){
this.employeeList.Add(employee);
}
public void print(){
foreach (Employee item in employeeList) {
Console.WriteLine(item.Name);
}
}
}
public class Program {
public static void Main(string[] args){
Employee emp1 = new Employee();
emp1.Name = "Ashish Patel";
emp1.EmployeeId = 189;
Employee emp2 = new Employee();
emp2.Name = "Ansu Patel";
emp2.EmployeeId = 182;
EmployeeList empList = new EmployeeList();
empList.addEmployee(emp1);
empList.addEmployee(emp2);
empList.display();
}
}
With generics we can simply write the above code as below
using System;
using System.Collections;
using System.Collections.Generic;
public class Employee {
public string Name {get; set;}
public int EmployeeId {get;set;}
}
public class EmployeeList<T> {
public List<T> employeeList = new List<T>();
public void addEmployee(T employee){
this.employeeList.Add(employee);
}
public void display(){
foreach (T item in employeeList) {
Console.WriteLine(item.dump());
}
}
}
public class Program {
public static void Main(string[] args){
Employee emp1 = new Employee();
emp1.Name = "Ashish Patel";
emp1.EmployeeId = 189;
Employee emp2 = new Employee();
emp2.Name = "Ansu Patel";
emp2.EmployeeId = 182;
EmployeeList<Employee> empList = new EmployeeList<Employee>();
empList.addEmployee(emp1);
empList.addEmployee(emp2);
empList.display();
}
}
Linq
LINQ (Language Integrated Query) is uniform query syntax in C# and VB.NET used to save and retrieve data from different sources.
Types
It can be used in two ways i.e Query Syntax and Method Syntax.
Query Syntax
var result = from s in stringList
where s.Contains("Ashish")
select s;
Method Syntax
var result = stringList.Where(s => s.Contains("Ashish"));
Query Operators
Standard Query Operators in LINQ are actually extension methods for the IEnumerable
Query Syntax
var result = from s in stringList
where s.Contains("Ashish")
select s;
```<style>
.scroll-to-top {
font-size: 2.5rem;
width: 3.2rem;
height: 3.2rem;
display: none;
align-items: center;
justify-content: center;
position: fixed;
padding: 0.75rem;
bottom: 4rem;
right: calc(1.25rem + 90px + var(--page-padding));
z-index: 999;
cursor: pointer;
border: none;
color: var(--bg);
background: var(--fg);
border-radius: 50%;
}
.scroll-to-top.hidden {
display: none;
}
.scroll-to-top i {
transform: translateY(-2px);
}
@media (min-width: 1080px) {
.scroll-to-top {
display: flex;
}
}
</style>
<button type="button" aria-label="scroll-to-top" class="scroll-to-top hidden" onclick="scrollToTop()">
<i class="fa fa-angle-up"></i>
</button>
<script>
const scrollToTop = () => window.scroll({ top: 0, behavior: "smooth" });
window.addEventListener("scroll", () => {
const button = document.querySelector(".scroll-to-top");
button.classList.toggle("hidden", window.scrollY < 200);
});
</script>
<style>
footer {
text-align: center;
text-wrap: balance;
margin-top: 5rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
footer p {
margin: 0;
}
</style>
<footer><p>Copyright © 2024 • Created with ❤️ by <a href="https://ashish.me">Ashish Patel</a></p>
</footer>
OOPS
Class
Class is the blueprint of the object as it stores data and functions. It does not occupy space as it is just the logical representation of data.
Object
Object is instance of class. When an object is created using new operator, memory is allocated for the class in the heap.
Abstraction
Astraction is to represent the essential feature without representing the background details. It lets you focus on what object does instead of how it does it. It is nothing but putting all the variables and methods in a class that are necessary.
abstract class Human {
public void walking();
public void talking();
}
public class Male: Human{
public void Fighting();
}
public class Female: Human{
public void dancing();
}
Encapsulation
Encapsulation is a technique used to protect the information in an object from another object. For example we can hide the data for security by making variable private and we expose the variable by making it public.
Inheritance
Inheritance is when a class includes property of another class.
Polymorphism
Polymorphism means when a function behaves in different forms depending upon the parameters.
xUnit
xUnit Elements
- Fact - always true
- Theory - true with right data
- InlineData, MemberData, ClassData - passing data to a unit test
Clean Code
Conventional Commits
Format
<type>(<scope>): <description>
- feat: A new feature
- fix: A bug fix
- docs: Documentation changes
- style: Code style changes (formatting, etc.)
- refactor: Code refactoring
- test: Adding or modifying tests
- chore: Routine tasks, maintenance, etc
Examples
- fix(login): correct password hashing issue
- fix(cart): prevent items from duplicating on refresh
- fix(profile): resolve avatar upload error
- fix(navbar): align links correctly on mobile
- fix(modal): close button not responsive
- fix(button): make hover effect consistent
- fix(api): handle missing user ID in requests
- fix(api): correct error codes for unauthorized access
- fix(api): prevent null values in response
- fix(db): ensure indexes are used for faster queries
- fix(db): correct foreign key constraint in orders
- fix(db): handle data migration for older records
- fix(auth): resolve token expiry handling
- fix(payment): correct tax calculation logic
- fix(file-upload): prevent large files from causing timeout
- fix(css): adjust padding for form inputs
- fix(js): prevent null pointer error on page load
- fix(svg): correct icon alignment in header
- fix(store): ensure cart state persists on refresh
- fix(state): prevent duplicate entries in wishlist
- fix(redux): correct initial state for auth
Data Structures
Array
Inserting a new item is quite slow // O(N)
Searching is quite fast with binary search // O(logN)
removing an item is slow //O(N)
Graph
.scroll-to-top { font-size: 2.5rem; width: 3.2rem; height: 3.2rem; display: none; align-items: center; justify-content: center; position: fixed; padding: 0.75rem; bottom: 4rem; right: calc(1.25rem + 90px + var(--page-padding)); z-index: 999; cursor: pointer; border: none; color: var(--bg); background: var(--fg); border-radius: 50%; } .scroll-to-top.hidden { display: none; } .scroll-to-top i { transform: translateY(-2px); } @media (min-width: 1080px) { .scroll-to-top { display: flex; } }
Hash Table
.scroll-to-top { font-size: 2.5rem; width: 3.2rem; height: 3.2rem; display: none; align-items: center; justify-content: center; position: fixed; padding: 0.75rem; bottom: 4rem; right: calc(1.25rem + 90px + var(--page-padding)); z-index: 999; cursor: pointer; border: none; color: var(--bg); background: var(--fg); border-radius: 50%; } .scroll-to-top.hidden { display: none; } .scroll-to-top i { transform: translateY(-2px); } @media (min-width: 1080px) { .scroll-to-top { display: flex; } }
Linked List
Inserting a new item is very fast //O(1)
Searching is sequential //O(N)
Removing an item is fast because of the references
Queue
.scroll-to-top { font-size: 2.5rem; width: 3.2rem; height: 3.2rem; display: none; align-items: center; justify-content: center; position: fixed; padding: 0.75rem; bottom: 4rem; right: calc(1.25rem + 90px + var(--page-padding)); z-index: 999; cursor: pointer; border: none; color: var(--bg); background: var(--fg); border-radius: 50%; } .scroll-to-top.hidden { display: none; } .scroll-to-top i { transform: translateY(-2px); } @media (min-width: 1080px) { .scroll-to-top { display: flex; } }
Stack
.scroll-to-top { font-size: 2.5rem; width: 3.2rem; height: 3.2rem; display: none; align-items: center; justify-content: center; position: fixed; padding: 0.75rem; bottom: 4rem; right: calc(1.25rem + 90px + var(--page-padding)); z-index: 999; cursor: pointer; border: none; color: var(--bg); background: var(--fg); border-radius: 50%; } .scroll-to-top.hidden { display: none; } .scroll-to-top i { transform: translateY(-2px); } @media (min-width: 1080px) { .scroll-to-top { display: flex; } }
Time Complexity
List of common complexities
In computer science, the performance of program is determined by total time and space taken to execute the program with respect to input.
Commonly used asymptotic notations for time and space complexity are below
- Omega notation (Best Case)
- Theta notation (Average Case)
- Oh notation (Worst Case)
We mostly consider Oh notation because it will give the execution time in the worst case.
Common Big O's
Let say if the input is N = 10 then the time taken by common asymptotic notations can be viewed from below table.
Name | Notation | Time |
---|---|---|
Constant | O(1) | 1 |
Logarithmic | O(log N) | 3.3219 |
Linear | O(N) | 10 |
Linearithmic | O(N log N) | 33.219 |
Polynomial | O(N^2) | 100 |
Exponential | O(2^N) | 1024 |
Factorial | O(N!) | 3628800 |
O(n) Linear Time
An algorithm is said to run in linear time if its time execution is directly proportional to the input size, i.e. time grows linearly as input size increases.
Consider the following examples, below I am linearly searching for an element, this has a time complexity of O(n).
int find = 66;
var numbers = new int[] { 33, 435, 36, 37, 43, 45, 66, 656, 2232 };
for (int i = 0; i < numbers.Length - 1; i++)
{
if(find == numbers[i])
{
return;
}
}
O(log n) Logarithmic Time:
An algorithm is said to run in logarithmic time if its time execution is proportional to the logarithm of the input size. Binary search and all the operations of binary search tree have logarithmic time complexity has we discard half of the data on every iteration.
O(n2) Quadratic Time
An algorithm is said to run in quadratic time if its time execution is proportional to the square of the input size.
Tree
Binary Search Tree
Binary search tree is a node based binary tree data structure.
Introduction
- The left subtree of a node contains only nodes with keys less than the node's key.
- The right subtree of a node contains only nodes with keys greater than the node's key.
- If we goto the left as far as possible we will find the smalled node and if goto the right as far as possible than we will find the largest node.
Time Complexity : O(log N)
Important Points
- It keeps the keys in sorted order: so that lookup and other other operations can use the principle of binary search.
- Each comparison allows the operations to skip over half of the tree, so that each lookup/insertion/deletion takes time proportional to the logarithm of the number of items stored in the tree.
- This is much better than linear time O(N) required to find items by key in an unsorted array, but slower than the corresponding operations on hash tables.
Binary search tree have to be balanced to be efficient. Tree is balanced if the left subtree contains as many nodes as the right subtree. If the binary search tree is not balanced then the search will take more time as it will not ignore irrelevant values. That means that our search performance will be decreased compared with a balanced tree.
Popular algorithms to balance the tree are
- AVL Tree
- Red Black Trees
Deletion
- Node is a leaf node
Set the node to null - Node has a single child
Update the reference of parent of the node to child of the Node - Node has two child
We look for the largest item in the left subtree or the smallest item in the right subtree and swap with the Node.
Traverse
- In order Traverse
The left subtree is visited first, then the root and later the right sub-tree. - Pre order Traverse
The root node is visited first, then the left subtree and finally the right subtree. - Post order Traverse
The root node is visited last, hence the name. First we traverse the left subtree, then the right subtree and finally the root node.
Docker
Docker
Server ( Docker Daemon)
Docker Server manages creating and maintaining containers using containerd, networking, persistent storage, orchestration and distribution -
REST API
Client (Docker API)
.scroll-to-top { font-size: 2.5rem; width: 3.2rem; height: 3.2rem; display: none; align-items: center; justify-content: center; position: fixed; padding: 0.75rem; bottom: 4rem; right: calc(1.25rem + 90px + var(--page-padding)); z-index: 999; cursor: pointer; border: none; color: var(--bg); background: var(--fg); border-radius: 50%; } .scroll-to-top.hidden { display: none; } .scroll-to-top i { transform: translateY(-2px); } @media (min-width: 1080px) { .scroll-to-top { display: flex; } }
Cheatsheet
# Run a container based on a docker image
docker run -d nginx # -d for running in background
docker run -d --name ashishdotme-nginx -p 9090:80 nginx:latest # expose 80 port from the container and map it to 9090
docker run -d --name ashishdotme-nginx -p 80 nginx:latest # expose 80 port to randomly available port
docker port ashishdotme-nginx 80 # find the port of host machine to binded to 80
docker run -d --name ashishdotme-nginx -p 80 -v c:\nginx:/data nginx:latest # mount host storage for persistent container
# Get details about running container
docker inspect ashishdotme-nginx
# Get logs from a container
docker logs ashishdotme-nginx
# Stop services only
docker-compose stop
# Stop and remove containers, networks..
docker-compose down
# Down and remove volumes
docker-compose down --volumes
# Down and remove images
docker-compose down --rmi <all|local>
# Starts the container and leaves them running
docker-compose up -d
Container
.scroll-to-top { font-size: 2.5rem; width: 3.2rem; height: 3.2rem; display: none; align-items: center; justify-content: center; position: fixed; padding: 0.75rem; bottom: 4rem; right: calc(1.25rem + 90px + var(--page-padding)); z-index: 999; cursor: pointer; border: none; color: var(--bg); background: var(--fg); border-radius: 50%; } .scroll-to-top.hidden { display: none; } .scroll-to-top i { transform: translateY(-2px); } @media (min-width: 1080px) { .scroll-to-top { display: flex; } }
Html
Position
CSS treats each HTML element as its own box, which is usually referred to as the CSS Box Model. Block-level items automatically start on a new line like headings while inline items sit within surrounding content. We can use the position property to override the layout of elements.
Position
Relative
When the position of an element is set to relative, it allows you to specify how css should move the element relative to its current position in the normal flow of page using top, bottom, left, right.
Absolute
Absolute removes the element from the normal flow of the document, so surrounding items ignore it. It locks the element in place relative to its parent container.
Fixed
Fixed is type of absolute positioning that locks the element relative to the browser window. The difference between fixed and absolute positions is that an element with a fixed position won't move when the user scrolls.
Float
Float property removes the element from normal flow of a document and push it to either left or right
Javascript
Core Concepts
- Closure
- Async Await
- Callback Hell
- Generator
- Babel
- Prototypes And Classes
- Hoisting
- Es6
- Exports Imports
- Es5
- Webpack
Closure
Practical Example (Counter):
function createCounter() {
let count = 0; // Variable in the outer function
return function () {
count++; // Inner function has access to 'count'
return count;
};
}
const counter = createCounter(); // Create a closure
console.log(counter()); // Output: 1
console.log(counter()); // Output: 2
console.log(counter()); // Output: 3
Here:
createCounter
defines a privatecount
variable.- The returned function (a closure) remembers
count
and updates it each time it's called, even thoughcreateCounter
has finished running.
Async Await
- Async/await builds on top of promises
- Enables synchronous style execution of multiple asynchronous methods
- Functions are prefixed with the "async" keyword
- Enables the use of the "await" keyword for invoking promisified functions
Babel
Babel is a javascript compiler. It translates the modern javascript features so our code also works on older browser.
Callback Hell
- The callback pattern is the default pattern for managing the outcome of an asynchronous method
- Nested callbacks become unmanageable and unreadable
- Nested callbacks are often termed as "Callback hell"
Example
firstFunction(args, function () {
secondFunction(args, function () {
thirdFunction(args, function () {
// And so on…
})
})
})
ES 5
Classes
Classes are passed by value
ES 6
Let vs Const
In javascript, var
is used to create variable. With ES6, let
and const
were introduced. Var
still works but its recommended to use let
and const
. Use const
to create constant value whose value never changes and use let
to create variables whose value is going to change.
Arrow functions
Arrow function syntax is a bit shorter than the normal syntax since it omits the function
keyword. When we use this
inside an arrow function it will keep its context and not change it.
const multiply = (number) => number * 2;
Three dots as Rest/Collector
...names
in the below example is a collector which collects rest of parameters
var [city, ...names] = ["Pune", "Ashish", "Ansu", "Anju"]
console.log(city); // Pune
console.log(names); // ["Ashish", "Ansu", "Anju]
Three dots as Spread
Spread takes all elements, all properties and distributes them in new array. Spread is use to create new object to prevent reference copying as objects and arrays are reference types. So when we reassign arrays or objects, we are copying the pointer, not the value.
const names = ["Pune", "Ashish", "Ansu", "Anju"]
const updatedNames = [...names, "Patel"]
console.log(updatedNames); // [ 'Pune', 'Ashish', 'Ansu', 'Anju', 'Patel' ]
Destructuring
Destructing allows extracting array elements or object properties and store them in variable.
// Array destructuring
[firstName, lastName] = ["Ashish", "Patel"]
console.log(firstName); // Ashish
console.log(lastName); // Patel
// Object destructuring
const { firstName } = { firstName: "Ashish", lastName: "Patel"}
console.log(firstName) // Ashish
Exports Inports
Default Export
const school = {
name: "Bhavans"
}
export default school
Export by name
Generators
- Generators are functions that provide us with an iterator
- Generator objects can be paused and made to return a value using the yield keyword
- Calling next() resumes the function and we get successive values
- Async generators combine the power of async/await and generators
Hoisting
In JavaScript, hoisting refers to the behavior where variable and function declarations (but not initializations) are conceptually moved to the top of their scope (function or global) during the compilation phase.!
var
Has function-level or global scope. This means a variable declared with var is accessible throughout the entire function it's declared in, or even globally if declared outside of any function.
let and const keywords were introduced in ES2015 or ECMAS-6, before this variables were used to be declared only with var.
Prototypes and classes
Generating objects using functions
We can generate objects using function but each time new object is created, there are multiple copies of same functions.
function personCreator(name, age) {
const newPerson = {};
newPerson.name = name;
newPerson.age = age;
newPerson.increaseAge = function() {
newPerson.age++;
};
return newPerson;
};
const ashish = personCreator("Ashish Patel", 24);
ashish.increaseAge()
Generating objects using prototypes
So we use prototypes to create objects for storing functions with their associated data.
function PersonCreator(name, age){
this.name = name;
this.age = age;
}
PersonCreator.prototype.increaseAge = function(){
this.age++;
};
// Using new creates a new object and returns it
const ashish = new PersonCreator(“Ashish Patel”, 24)
ashish.increaseAge()
Subclassing can be achieved by below code
function PersonCreator(name, age) {
this.name = name;
this.age = age;
}
PersonCreator.prototype.increaseAge = function(){
this.age++;
}
function PersonCreatorWithCaste(name, age, caste){
PersonCreator.call(this, name, age);
this.caste = caste;
}
PersonCreatorWithCaste.prototype = Object.create(PersonCreator.prototype);
PersonCreatorWithCaste.prototype.displayCaste = function(){
console.log(this.caste);
}
const ashish = new PersonCreatorWithCaste("Ashish Patel", 25, "Agharia");
console.log(ashish.age);
ashish.increaseAge();
console.log(ashish.age);
ashish.displayCaste();
Generating objects using classes
Class was introduced with ES2015, it let us write the shared methods in one place instead of writing the constructor and shared methods separately.
class PersonCreator {
constructor (name, age){
this.name = name;
this.age = age;
}
increaseAge(){
this.age++;
}
}
const ashish = new PersonCreator("Ashish Patel", 24);
ashish.increaseAge();
Subclassing in ES2015 can be achieved by below code
class PersonCreator {
constructor (name, age){
this.name = name;
this.age = age;
}
increaseAge(){
this.age++;
}
}
class PersonCreatorWithCaste extends PersonCreator {
constructor(name, age, caste){
super(name, age);
this.caste = caste;
}
displayCaste(){
console.log(this.caste);
}
}
const ashish = new PersonCreatorWithCaste("Ashish Patel", 24, "Agharia");
console.log(ashish.age);
ashish.increaseAge();
console.log(ashish.age);
ashish.displayCaste();
Webpack
We need bundler because we want to write modular code and split our code in multiple files so that each file has clear task, We use webpack to bundle all our files into couple of files in end for deployment. Bundling helps in reducing the number of requests browser has to make to get all the files.
Webpack also allows us to apply a couple of other build steps before it does the bundling.
Design Patterns
Adapter Pattern
Adapter Pattern is an abstraction for nasty or 3rd party code, you need in your main clean codebase.
It is basically a wrapper around a particular class or object, which provides a different API and utilizes the object’s original one in the background.
Use Cases
- It is used to create a bridge between two different interfaces
- Removes incompabilities between the interfaces
- Prevents or minimizes refactoring client application code
- Lets you build packages with an opinionated API, with custom adapters for maxmium compability
// index.js
import { v4 as uuidv4 } from 'uuuid'
console.log(uuidv4()) // without adapter pattern
// uuid.js
import { v4 as uuidv4 } from 'uuuid'
class uuid {
generate() {
return uuidv4()
}
}
export default new uuid()
// App.js
import uuid from './uuid
console.log(uuid.generate())
Builder Pattern
- It enables the creation of an easy to use interface to a complex process.
- By Introducing a step by step workflow, npm packages can be made easy to understand and consume
// Course.js
class Course {
constructor(name, sales, isFree = false, price, isCampain = false) {
this.name = name
this.sales = sales || 0
this.isFree = isFree
this.price = price || 0
this.isCampain = isCampain // Advertising Campaign
}
toString() {
return console.log(JSON.stringify(this))
}
}
module.exports = Course
// CourseBuilder.js
const Course = require('./course')
class CourseBuilder {
constructor(name, sales = 0, price = 0) {
this.name = name
this.sales = sales
this.price = price
}
makePaid(price) {
this.isFree = false
this.price = price
return this
}
makeCampain() {
this.isCampain = true
return this
}
build() {
return new Course(this)
}
}
module.exports = CourseBuilder
//App.js
const CourseBuilder = require('./CourseBuilder')
//const course_1 = new CourseBuilder('Design Patterns 1', 0, true, 149 , true);
//const course_2 = new CourseBuilder('Design Patterns 1', 0,false, 0, false);
const course_1 = new CourseBuilder('Design Patterns 1').makePaid(100).makeCampain().build()
const course_2 = new CourseBuilder('Design Patterns 2').build()
course_1.toString()
course_2.toString()
Decorator Pattern
Decorator Pattern is designed to provide you with a clean way of extending abilities of your original Object or Component, without impacting its initial state or structure.
- It ingests a function and returns back a function
- Decorators can be used to add features and function to existing objects dynamically
- Implemented as high order functions
// User.js
class User {
constructor(firstName, lastName, title) {
this.firstName = firstName
this.lastName = lastName
this.title = title
}
getFullName() {
return `${this.firstName} ${this.lastName}`
}
}
// UserDecorator.js
class UserDecorator {
constructor(user) {
this.user = user
}
getFullName() {
return this.user.getFullName()
}
}
// UserFullNameWithTitleDecorator.js
class UserFullNameWithTitleDecorator extends UserDecorator {
getFullName() {
return `${this.user.title} ${this.user.getFullName()}`
}
}
// App.js
const user = new User('Arthur', 'Frank', 'Mr')
user.getFullName()
const decoratedUser = new UserFullNameWithTitleDecorator(user)
decoratedUser.getFullName()
Factory Pattern
In factory pattern, we create objects without exposing the creation logic to the code that requires the object to be created.
- It provides an interface for constructing pre configured objects
- Code is cleaner
- It allows you to offer an easy to understand interface to your packages function
// Factory.js
function deliveryFactory(address, item) {
if (distance > 10 && distance < 50) {
return new DeliveryByCar(address, item)
}
if (distance > 50) {
return new DeliveryByTruck(address, item)
}
return new DeliveryByBike(address, item)
}
class DeliveryByBike {
constructor(address, item) {
this.address = address
this.item = item
}
}
class DeliveryByTruck {
constructor(address, item) {
this.address = address
this.item = item
}
}
class DeliveryByCar {
constructor(address, item) {
this.address = address
this.item = item
}
}
const newDelivery = deliveryFactory('121 baily ave, Toronto, canada', 'nitendo 360')
Abstract Factory Pattern
In factory pattern, we take care of creating objects of same family whereas in abstract factory pattern we will provide a constructor for creating families of related objects, without specifying concrete classes or constructors.
function abstractFactory(address, item, options) {
if (options.isSameday) {
return sameDayDeliveryFactory(address, item)
}
if (options.isExpress) {
return expressDeliveryFactory(address, item)
}
return deliveryFactory(address, item)
}
Proxy Pattern
A proxy is an object that has the same interface as another object and is used in place of that other object. It provides a surrogate or placeholder for another object to control access to it. It intends to add a wrapper and delegation to protect the real component from undue complexity.
- It allows us to create placeholder wrappers for objects
- A proxy Object allows external access control to the object
- Implements the same interface as the original object
Use cases
- Caching remotely accessed data
- Optimize or pre process data on access
- Logging
- Encryption
- Simulating private and inaccessible properties
- Data validation
// External API Service
function CryptocurrencyAPI() {
this.getValue = function (coin) {
console.log('Calling External API...')
switch (coin) {
case 'Bitcoin':
return '$8,500'
case 'Litecoin':
return '$50'
case 'Ethereum':
return '$175'
default:
return 'NA'
}
}
}
function CryptocurrencyProxy() {
this.api = new CryptocurrencyAPI()
this.cache = {}
this.getValue = function (coin) {
if (this.cache[coin] == null) {
this.cache[coin] = this.api.getValue(coin)
}
return this.cache[coin]
}
}
const proxy = new CryptocurrencyProxy()
console.log(proxy.getValue('Bitcoin'))
console.log(proxy.getValue('Litecoin'))
Singleton Design Pattern
- Singletons are objects that can only have a single instance, with a single point of access
- The module system in nodejs offers a rudimentary implementation of a singleton
- In modules, single instance of class is created and cached
Example
// CashRegister.js
let cash = 0
const CashRegister = {
credit(amount) {
cash = cash + amount
return cash
},
debit(amount) {
if (amount <= cash) {
cash = cash - amount
return true
} else {
return false
}
},
total() {
return cash
},
}
module.exports = CashRegister
// App.js
const cashRegister = require('./CashRegister')
const cashRegister2 = require('./CashRegister')
cashRegister.credit(10)
cashRegister2.credit(20)
cashRegister.debit(5)
console.log(cashRegister.total()) // answer is 25 as both object are using same instance
Kafka
Topic
- Topics are like table, provides scalability
- Each topic has 1 or more than 1 partition
- Each partition is an ordered, immuatable sequence of records
- Each record is assigned a sequential number called offset
- Each partition is independent of each other
- Ordering is guaranteed only at the partition level
- Partition continously grows as new records are produced
- All the records are persisted in a distributed commit log in the file system where Kafka is installed
Misc
English
Prepositions
.scroll-to-top { font-size: 2.5rem; width: 3.2rem; height: 3.2rem; display: none; align-items: center; justify-content: center; position: fixed; padding: 0.75rem; bottom: 4rem; right: calc(1.25rem + 90px + var(--page-padding)); z-index: 999; cursor: pointer; border: none; color: var(--bg); background: var(--fg); border-radius: 50%; } .scroll-to-top.hidden { display: none; } .scroll-to-top i { transform: translateY(-2px); } @media (min-width: 1080px) { .scroll-to-top { display: flex; } }
Vocabulary
-
menace - be a threat
-
adamant - refusing to change ones mind
-
avert - turn away
-
dwindle - get smaller
Gym
Chest
Bench press
Incline bench press
Dumbell fly
Pushup
Pec deck
Shoulder
Reverse Fly
Overhead Press
Lateral Raise
Tricep
Tricep Extensions
Workout Plan
6 Day PPL Routine
Day Exercise Day 1 Chest, Shoulder and Triceps Day 2 Back, Biceps and Abs Day 3 Legs Day 4 Chest, Shoulder and Triceps Day 5 Back, Biceps and Abs Day 6 Legs Day 7 OFF 3-Day PPL Routine
Day Exercise Day 1 Chest, Shoulder and Triceps Day 2 Back, Biceps and Abs Day 3 Legs Full Workout Routine
Exercises
Day Exercise Day 1 Barbell bench press, Dumbbell overhead press, Dumbbell Fly, Triceps extensions, lateral raises Day 2 Bent over row, Cable Row, Biceps Curl, Hammer Curl, Reverse Fly Day 3 Front Squat, Leg Curl, Leg Extension, Calf Raise Muscle Group
Day Muscle Day 1 Chest, Shoulder, Chest, Triceps, Shoulder Day 2 Back, Back, Bicep, Bicep, Back Day 3 Back, Leg, Leg, Leg Links
Health
Skincare
Product Uses Salicylic Acid Treats Pimple Niacinamide Hydration Glycolic Acid Exfoliation of the top layer of the skin Retinol Skin looks firm Hyaluronic acid Hydration Maths
Logarithm
Logarithm, the exponent or power to which a base must be raised to yield a given number. The default base is 10.
Examples
Random Formulas
Inverse a Number
Mod(%) operation on a number by 10 returns the rightmost digit Divide(/) operation on a number by 10 removes the rightmost digit
Num = 126
Reversing 126 % 10 = 6
int(126/10) = 12
12 % 10 = 2
int(12/10) = 1
1 % 10 = 1Personal
CLI
List
CLI Description Hoarder Bookmarks manager Organize Organize files Common Info
Name: Ashish Patel
Ring size
Eu size - 62
Diameter - 19.8 cm
UK - T 1/2
US - 10Shortcuts
Custom
Shortcut Description Ctrl + Shift + p Proofread Glazewm
Shortcut Description Alt + Enter Wezterm Alt + Shift + Enter Microsoft Terminal Alt + Ctrl + G Visual Studio Code Alt + Ctrl + E Microsoft Edge Browser
Shortcut Description Ctrl + L Go to Address Bar Ctrl + Shift + C Close all tabs (Install extension) TickTick
Shortcut Description Ctrl + Shift + E Show window Alt + Shift + A Quick Add Windows
Shortcut Description Windows + V Paste window Windows + E Explorer window Windows + . Emoji Window Visual Studio
Shortcut Description F12 Go to Definition Ctrl + F12 Go to Implementation Subscriptions
Service Cost Billing Cycle Notes 48.ie €12,99 Monthly Domain renewals €25 Annual Expiry 4 October 2025 Wifi €35 Monthly VPS €8.3 Monthly Paid till November 2024 Google One €3 Monthly Apple iCloud €3 Monthly Youtube Premium €3 Monthly TickTick €4 Monthly Gym €31 Monthly Total Monthly - ≈€103.2
Setup
Macbook Setup
Show path bar
defaults write com.apple.finder ShowPathbar -bool true
XCode
xcode-select --install
Homebrew
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
Tools
brew tap caskroom/cask brew install git brew cask install google-chrome brew cask install spectacle brew cask install iterm2
Git
git config --global user.name "Ashish Patel" git config --global user.email "ashishsushilpatel@gmail.com"
Shell
zsh
# Install zsh brew install zsh zsh-completions # oh-my-zsh sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)" # Change shell chsh -s /bin/zsh # Restart iterm # Install auto suggestions plugin git clone git://github.com/zsh-users/zsh-autosuggestions $ZSH_CUSTOM/plugins/zsh-autosuggestion # Install poweling font # Change font to Meslo LG L for powerline https://github.com/powerline/fonts # Use following config in zshrc plugins=(git colored-man colorize github jira vagrant virtualenv pip python brew osx zsh-syntax-highlighting zsh-autosuggestions) ZSH_THEME="agnoster" DEFAULT_USER=$(whoami)
Nodejs
# Install nvm curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.0/install.sh | bash # Install latest lts nodeks nvm install -lts brew install yarn --without-node
Docker
brew cask install docker
VS Code
# Press command + shift + p and click on Shell Command : Install code in PATH ```<style> .scroll-to-top { font-size: 2.5rem; width: 3.2rem; height: 3.2rem; display: none; align-items: center; justify-content: center; position: fixed; padding: 0.75rem; bottom: 4rem; right: calc(1.25rem + 90px + var(--page-padding)); z-index: 999; cursor: pointer; border: none; color: var(--bg); background: var(--fg); border-radius: 50%; } .scroll-to-top.hidden { display: none; } .scroll-to-top i { transform: translateY(-2px); } @media (min-width: 1080px) { .scroll-to-top { display: flex; } } </style> <button type="button" aria-label="scroll-to-top" class="scroll-to-top hidden" onclick="scrollToTop()"> <i class="fa fa-angle-up"></i> </button> <script> const scrollToTop = () => window.scroll({ top: 0, behavior: "smooth" }); window.addEventListener("scroll", () => { const button = document.querySelector(".scroll-to-top"); button.classList.toggle("hidden", window.scrollY < 200); }); </script> <style> footer { text-align: center; text-wrap: balance; margin-top: 5rem; display: flex; flex-direction: column; justify-content: center; align-items: center; } footer p { margin: 0; } </style> <footer><p>Copyright © 2024 • Created with ❤️ by <a href="https://ashish.me">Ashish Patel</a></p> </footer>
React
Binding
Default binding
function display(){ console.log(this); // 'this' will point to the global object } display();
Implicit binding
var obj = { name: 'Saurabh', display: function(){ console.log(this.name); // 'this' points to obj } }; obj.display(); // Saurabh
var name = "uh oh! global"; var outerDisplay = obj.display; outerDisplay(); // uh oh! global
function setTimeout(callback, delay){ callback(); // callback = obj.display; } setTimeout( obj.display, 1000 ); var name = "uh oh! global"; setTimeout( obj.display, 1000 ); // uh oh! global
Explicit hard binding
var name = "uh oh! global"; obj.display = obj.display.bind(obj); var outerDisplay = obj.display; outerDisplay(); // Saurabh
Lifecycle
Create
Contructor(props)
- It's a default es6 class feature
- Used to call super(props)
- You can set up state
- You should not cause side effects
ComponentWillMount()
- You can update state
- You can do last minute optimization
- You should not cause side effects
Render()
- You can structure your code here
ComponentDidMount()
- You can cause side effects
- You can call APIS and do data modification
- You should not update state though as it triggers re render
Update
ComponentWillReceiveProps()
- You can sync state to props
- You should not cause side effects
ShouldComponentUpdate()
- You can decide wether to continue or not
- You should not cause side effects
ComponentWillUpdate()
- You can sync state to props
- You should not cause side effects
ComponentDidUpdate()
- You can cause side effects
- You should not update state as it triggers re render
ComponentWillUnmount()
Redux Sideeffects
Redux is a predictable state container for JavaScript apps which makes state management easier but the actions dispatched via Redux are synchronous. For network calls, we need the ability to dispatch actions asynchronously. Dispatching actions asynchronously can be done by popular middlewares like i.e Redux Thunk and Redux Saga. Redux middleware is code that intercepts actions coming into the store via the dispatch() method.
Sideeffects
When doing the fetch request in redux, we can't be sure what the call will return or that it will even succeed. This is known as a side effect.
Redux Thunk
Redux Thunk uses promises for async actions.
const getPosts = ({dispatch}) => { dispatch({type: 'POSTS_LOADING'}) fetch('api/posts') .then(res => dispatch({type: 'GET_POSTS', payload: res.data})) .catch(err => dispatch({type: 'GET_ERRORS', payload: {})) } store.dispatch(getPosts)
Redux Saga
Redux Saga uses generators for async actions.
export default function* onGetPosts() { yield takeLatest('RECORDS/FETCH', function getPosts() { try { const response = yield call(fetch, 'api/posts'); const responseBody = response.json(); } catch (e) { yield put(fetchFailed(e)); return; } yield put(setRecords(responseBody.records)); }); }
Redux
Redux is used to change the state of application.
Three principles of Redux
- Single source of truth - State of whole application is stored in a single tree
- State is read only - Only by emitting action, we can change the state of applcation
- Changes are made with pure functions - Reducers which are pure functions can only change the state
Connect
mapDispatchToProps
- It's a method you provide to connect
- Recieves dispatch as an argument
- Allows you to create functions which dispatch actions
- It can return an object which is passed to component as props.
Testing
Testing with Mocha, Chai, Enjyme and Sinon
Mocha
Mocha is a javascript test framework which supports asynchronous testing, test coverage reports and use of any assertion library.
Chai
Chai is a BDD/TDD assertion library
Enzyme
Enjyme is a javascript testing utility for React that makes it easier to traverse and manipulate react component's output
Sinon
Sinon is used for Spies/Stubs/Mocks. It can also fake ajax calls and timers. So basically it allows you solve problems which occur due to external dependencies.
- Spies - offers information about function cals
- Stubs - Which are like spies but completely replace the functions
- Mocks - It replaces the whole object by combining spies and stubs
Adding Mocha, Chai, Enjyme and Sinon to the project
yarn add --dev chai yarn add --dev enzyme yarn add --dev enzyme-adapter-react-16 yarn add --dev mocha yarn add --dev @types/chai yarn add --dev @types/enzyme yarn add --dev @types/enzyme-adapter-react-16 yarn add --dev @types/mocha yarn add --dev chai enzyme enzyme-adapter-react-16 mocha yarn add --dev @types/chai @types/enzyme @types/enzyme-adapter-react-16 @types/mocha ```<style> .scroll-to-top { font-size: 2.5rem; width: 3.2rem; height: 3.2rem; display: none; align-items: center; justify-content: center; position: fixed; padding: 0.75rem; bottom: 4rem; right: calc(1.25rem + 90px + var(--page-padding)); z-index: 999; cursor: pointer; border: none; color: var(--bg); background: var(--fg); border-radius: 50%; } .scroll-to-top.hidden { display: none; } .scroll-to-top i { transform: translateY(-2px); } @media (min-width: 1080px) { .scroll-to-top { display: flex; } } </style> <button type="button" aria-label="scroll-to-top" class="scroll-to-top hidden" onclick="scrollToTop()"> <i class="fa fa-angle-up"></i> </button> <script> const scrollToTop = () => window.scroll({ top: 0, behavior: "smooth" }); window.addEventListener("scroll", () => { const button = document.querySelector(".scroll-to-top"); button.classList.toggle("hidden", window.scrollY < 200); }); </script> <style> footer { text-align: center; text-wrap: balance; margin-top: 5rem; display: flex; flex-direction: column; justify-content: center; align-items: center; } footer p { margin: 0; } </style> <footer><p>Copyright © 2024 • Created with ❤️ by <a href="https://ashish.me">Ashish Patel</a></p> </footer>
Software Development
Computer Architecture
Memory
Heap and stack are generic terms for ways in which memory can be allocated. Stack is more faster than heap because
Stack
In Stack, the items sit on top of the other in they order they are are placed and you can only remove the top one. No table is needed to maintain stack, we just need pointer to the top of stack. Programs have call stack which stores information about which functions call other functions and return. It also stores local variables.
Heap
In Heap, there is no particular order to the way items are placed. You can remove item in any order. Heap allocation requires maintaining what memory is allocated and what isn't. Memory is allocated dynamically and randomly.
Oops
Abstraction
Abstraction is basically capturing the core data of an object and ignoring the details.
In the above example, When student class need to work with Course class, it can do so with directly referencing course class, without worrying about how the course details are internall managed, stored, etc.
Advantages
- Reduces complexity
- Increases Efficiency
Banl UML
UML Diagram
classDiagram class Bank { -balance: int +getBalance: int } class Atm { -amount: int +withdraw(amount): int } class Customer { -name: string -accountNumber: int +getCustomer(accountNumber): string } class Account { -accountNumber: int } class Transaction { -accountNumber: int -transactionId: int } class CheckingAccount { -accountNumber: int } class SavingsAccount { -accountNumber: int } CheckingAccount <|-- Account SavingsAccount <|-- Account Bank *-- Account Customer *-- Account Bank --> Atm Transaction ..> Atm ```<style> .scroll-to-top { font-size: 2.5rem; width: 3.2rem; height: 3.2rem; display: none; align-items: center; justify-content: center; position: fixed; padding: 0.75rem; bottom: 4rem; right: calc(1.25rem + 90px + var(--page-padding)); z-index: 999; cursor: pointer; border: none; color: var(--bg); background: var(--fg); border-radius: 50%; } .scroll-to-top.hidden { display: none; } .scroll-to-top i { transform: translateY(-2px); } @media (min-width: 1080px) { .scroll-to-top { display: flex; } } </style> <button type="button" aria-label="scroll-to-top" class="scroll-to-top hidden" onclick="scrollToTop()"> <i class="fa fa-angle-up"></i> </button> <script> const scrollToTop = () => window.scroll({ top: 0, behavior: "smooth" }); window.addEventListener("scroll", () => { const button = document.querySelector(".scroll-to-top"); button.classList.toggle("hidden", window.scrollY < 200); }); </script> <style> footer { text-align: center; text-wrap: balance; margin-top: 5rem; display: flex; flex-direction: column; justify-content: center; align-items: center; } footer p { margin: 0; } </style> <footer><p>Copyright © 2024 • Created with ❤️ by <a href="https://ashish.me">Ashish Patel</a></p> </footer>
Shopping cart UML
Shopping cart
classDiagram class Item { -itemId +isRestricted() } class Customer { -name +getAddress() } class Address { -country -state } Customer "1" *-- "1" Address : composition
Uml
Library UML
Restaurant UML
UML Concepts
Types of Relationships
1. Association
Association is: Class A uses Class B.
Example:
- Employee uses Bus/train Services for transportation.
- Computer uses keyboard as input device
And in In UML diagram Association is denoted by a normal arrow head.
2. Aggregation
Class A contains Class B, or Class A has an instance of Class B.
An aggregation is used when life of object is independent of container object. But still container object owns the aggregated object.
So if we delete class A that doesn't mean that class B will also be deleted. E.g. none, or many, teachers can belong to one or many departments.
The relationship between Teachers and Departments is aggregation.
3. Composition
Class A owns Class B.
E.g. Body consists of Arm, Head, Legs. BankAccount consists of Balance and TransactionHistory.
So if class A gets deleted then also class B will get deleted.
Relationships Cheatsheet
Mermaid class UML diagram syntax
Type Description <|--
Inheritance *--
Composition o--
Aggregation -->
Association --
Link (Solid) ..>
Dependency ..|>
Realization ..
Link (Dashed) Assets
Sql
Basics
Create table
--Create the main employee table CREATE TABLE employee ( id int PRIMARY KEY, name varchar(255), age int ); --Create the employee age table CREATE TABLE employee_age ( id int PRIMARY KEY, age int );
Insert
INSERT INTO employee VALUES (1, 'Ashish', 'Pune'); INSERT INTO employee VALUES (2, 'patel', 'Nagpur'); INSERT INTO employee VALUES (4, 'Ansu', 'Bikaner'); INSERT INTO employee_age VALUES (1, 23); INSERT INTO employee_age VALUES (2, 27); INSERT INTO employee_age VALUES (3, 21);
Select
SELECT * FROM employee;
id name city 1 Ashish Pune 2 patel Nagpur 4 Ansu Bikaner SELECT * FROM employee_age;
id age 1 23 2 27 3 21 .scroll-to-top { font-size: 2.5rem; width: 3.2rem; height: 3.2rem; display: none; align-items: center; justify-content: center; position: fixed; padding: 0.75rem; bottom: 4rem; right: calc(1.25rem + 90px + var(--page-padding)); z-index: 999; cursor: pointer; border: none; color: var(--bg); background: var(--fg); border-radius: 50%; } .scroll-to-top.hidden { display: none; } .scroll-to-top i { transform: translateY(-2px); } @media (min-width: 1080px) { .scroll-to-top { display: flex; } } Joins
SQL Joins is used to combine data or rows from two or more tables based on a common field between them. Different types of Joins are:
Employee Table
id name city 1 Ashish Pune 2 patel Nagpur 4 Ansu Bikaner Age Table
id age 1 23 2 27 3 21 Inner Join
It selects all rows from both the tables as long as the condition satisfies. Only using JOIN is same as INNER JOIN
SELECT employee_age.id, employee.name, employee.city FROM employee INNER JOIN employee_age ON employee.id = employee_age.id;
id name city age 1 Ashish Pune 23 2 patel Nagpur 27 Left Join
This join returns all the rows of the table on the left side of the join and matching rows for the table on the right side of join.
SELECT employee_age.id, employee.name, employee.city FROM employee LEFT JOIN employee_age ON employee.id = employee_age.id;
id name city age 1 Ashish Pune 23 2 patel Nagpur 27 NULL Ansu Bikaner NULL Right Join
RIGHT JOIN is similar to LEFT JOIN. This join returns all the rows of the table on the right side of the join and matching rows for the table on the left side of join.
SELECT employee_age.id, employee.name, employee.city FROM employee RIGHT JOIN employee_age ON employee.id = employee_age.id;
id name city age 1 Ashish Pune 23 2 patel Nagpur 27 3 NULL NULL 21 Full Join
FULL JOIN creates the result-set by combining result of both LEFT JOIN and RIGHT JOIN.
SELECT employee_age.id, employee.name, employee.city, employee_age.age FROM employee FULL JOIN employee_age ON employee.id = employee_age.id;
id name city age 1 Ashish Pune 23 2 patel Nagpur 27 3 NULL NULL 21 NULL Ansu Bikaner NULL .scroll-to-top { font-size: 2.5rem; width: 3.2rem; height: 3.2rem; display: none; align-items: center; justify-content: center; position: fixed; padding: 0.75rem; bottom: 4rem; right: calc(1.25rem + 90px + var(--page-padding)); z-index: 999; cursor: pointer; border: none; color: var(--bg); background: var(--fg); border-radius: 50%; } .scroll-to-top.hidden { display: none; } .scroll-to-top i { transform: translateY(-2px); } @media (min-width: 1080px) { .scroll-to-top { display: flex; } } System Design
Availability vs Consistency
Consistency Pattern
Methods to ensure data consistency across distributed systems. Three main types:
Strong Consistency
Immediate data updates, high integrity, but low availability and high latency2. Example - when a user initiates a transfer of funds from one account to another, the system immediately updates the balance of both accounts and all other system components are immediately aware of the change. This ensures that all users can see the updated balance of both accounts and prevents any discrepancies.
Weak Consistency:
Delayed data updates, high availability, low latency, but potential inconsistencies. Example - When a user plays a game, their actions are immediately visible to other players in the same data center, but if there was a lag or temporary connection loss, the actions may not be seen by some of the users and the game will continue. This can lead to inconsistencies between different versions of the game state, but it also allows for a high level of availability and low latency.
Eventual Consistency:
Data updates eventually propagate, balancing availability and integrity, but with possible temporary inconsistencies. Example - An example of eventual consistency is a social media platform where users can post updates, comments, and messages. The platform is designed for high availability and low latency, so the data is stored in multiple data centers around the world. When a user posts an update, the update is immediately visible to other users in the same data center, but it may take some time for the update to propagate to other data centers. This means that some users may see the update while others may not, depending on which data center they are connected to. This can lead to inconsistencies between different versions of the data, but it also allows for a high level of availability and low latency.
Availability Pattern
- Failover
- Description: Automatically switches to a backup system if the primary system fails.
- Example: A database cluster where, if the primary database fails, a standby replica takes over immediately.
- Load Balancing
- Description: Distributes incoming requests across multiple servers to ensure no single server is overwhelmed.
- Example: A web application uses a load balancer to route user requests to multiple web servers, ensuring the app remains responsive.
- Caching
- Description: Stores copies of frequently accessed data to reduce load and latency.
- Example: A content delivery network (CDN) caches website content closer to users to provide faster access and reduce server load.
- Replication
- Description: Duplicates data across multiple systems to ensure availability even if one system goes down.
- Example: A NoSQL database like Cassandra replicates data across several nodes, so it's still accessible if some nodes fail.
Basics
System Design
System design is the process of defining the elements of a distributed system, as well as their interactions and relationships, in order to satisfy a set of specified requirements. Example of distributed systems - different microservices (accounts, payments, orders, inventory) work together to handle transactions.
Performance vs Scalability
- If you have a performance problem, your system is slow for a single user.
- If you have a scalability problem, your system is fast for a single user but slow under heavy load.
Latency vs Throughput
Latency and throughput are two important measures of a system’s performance. Latency refers to the amount of time it takes for a system to respond to a request. Throughput refers to the number of requests that a system can handle at the same time.
Generally, you should aim for maximal throughput with acceptable latency.
Availability vs Consistency
Availability refers to the ability of a system to provide its services to clients even in the presence of failures. This is often measured in terms of the percentage of time that the system is up and running, also known as its uptime.
Consistency, on the other hand, refers to the property that all clients see the same data at the same time. This is important for maintaining the integrity of the data stored in the system.
In distributed systems, it is often a trade-off between availability and consistency. Systems that prioritize high availability may sacrifice consistency, while systems that prioritize consistency may sacrifice availability. Different distributed systems use different approaches to balance the trade-off between availability and consistency, such as using replication or consensus algorithms.
Cap Theorem
The CAP Theorem states that a distributed system can guarantee only two of the following three properties simultaneously:
- Consistency: Every read receives the most recent write or an error.
- Availability: Every request receives a response, without guarantee that it contains the most recent write.
- Partition Tolerance: The system continues to operate despite network partitions.
Example
Imagine a distributed database system spread across multiple servers.
Scenario: Network Partition
- Consistency and Partition Tolerance (CP):
- The system ensures all nodes agree on the latest data, but some requests may fail if parts of the network are inaccessible.
- Example: A banking system prioritizes consistent account balances over availability.
- Availability and Partition Tolerance (AP):
- The system remains operational and responsive even if data isn't consistent across all nodes.
- Example: A social media platform where users can still post messages, but might see outdated comments during a partition.
- Consistency and Availability (CA):
- This combination can only work if there are no network partitions, which is unrealistic for distributed systems.
In practice, systems choose trade-offs based on specific needs, like prioritizing availability in user-facing applications or consistency in financial transactions.
Database
SQL
ACID Properties
-
Atomicity
- Definition: Each transaction is all-or-nothing. If any part of the transaction fails, the entire transaction fails.
- Example: If you're transferring money between bank accounts, either both the debit and credit occur, or neither does.
-
Consistency
- Definition: Transactions must move the database from one valid state to another, maintaining all predefined rules.
- Example: If a transaction updates an account balance, the total amount of money should remain the same before and after the transaction.
-
Isolation
- Definition: Transactions should not affect each other. They should behave as if they're executed sequentially, even if they're run in parallel.
- Example: If two transactions are occurring simultaneously, one transferring funds and another checking balance, they should not interfere with each other.
-
Durability
- Definition: Once a transaction is committed, it remains so, even in the event of a system failure.
- Example: After a successful transfer, the system crashes. Once back up, the transaction should still be reflected in the database.
Example
Imagine a bank transaction where Alice transfers $100 to Bob:
- Atomicity: If the debit from Alice's account fails, the credit to Bob's account won't happen.
- Consistency: The total money in Alice's and Bob's accounts remains unchanged.
- Isolation: Another transaction checking Bob's balance won’t see the transfer until it’s complete.
- Durability: Once the transfer is confirmed, it remains so despite any crashes.
These properties ensure that databases operate correctly and predictably, even in complex scenarios.
Sharding is a database architecture pattern used to horizontally partition data across multiple servers, enabling systems to handle more data and transactions. It improves scalability and performance.
Sharding
- Definition: Divides a database into smaller, manageable pieces called "shards."
- Purpose: Allows distribution of data across multiple machines, balancing the load and reducing bottlenecks.
Sharding Key
- Definition: A specific key or column used to determine how data is distributed across shards.
- Purpose: Ensures that related data is stored together and efficiently queried.
Sharding Example
Imagine an e-commerce application with a database table
Orders
:OrderID UserID Product Amount 1 101 Laptop 1200 2 102 Phone 800 3 103 Headphones 150 4 101 Monitor 300 5 104 Keyboard 100 -
Choose a Sharding Key: Let's use
UserID
as the sharding key. -
Shard Distribution:
- Shard 1: Users with IDs from 100 to 199
- Orders for UserIDs 101 and 102
- Shard 2: Users with IDs from 200 to 299
- Orders for UserIDs 201 and 202
- Shard 1: Users with IDs from 100 to 199
Benefits
- Scalability: As data grows, add more shards.
- Performance: Queries are distributed, reducing load on a single server.
- Fault Tolerance: Failure of one shard doesn't affect others.
By choosing a proper sharding key, data is balanced across shards, minimizing data transfer and optimizing query performance.
NOSQL
Introduction
- Scalability
- Horizontal Scaling: Easily distribute data across multiple servers.
- Data Model Flexibility
- Dynamic Schemas: When your data structure is evolving or unstructured.
- Performance
- High Volume of Reads/Writes: Low-latency requirements for large datasets.
- Specific Use Cases
- Big Data Applications: Handling massive data and analytics.
- Real-Time Applications: Such as chat apps or IoT platforms.
- Content Management Systems: With varied and flexible content types.
Key Considerations
- Consistency vs. Availability: Decide based on your application needs (CAP theorem).
- Data Relationships: NoSQL is better for denormalized data but less ideal for complex joins.
-