Home About Projects Learn Tracker πŸ“„ Resume

Learn Software Engineering

My interview-prep and engineering notes, cleaned up and organised by topic. Pick a page on the left, read, and ask a question at the bottom if something is unclear.

πŸ—ΊοΈ Roadmap

The map I used to prepare for backend / SDE-2 interviews. Everything on this site hangs off these buckets.

1. Coding (DSA)

  • Complexity: Time & Space Β· Asymptotic analysis (Big-O, Θ, Ξ©) Β· Amortised cost Β· Recurrences
  • Foundations: Arrays Β· Strings Β· Hashing Β· Two Pointers Β· Sliding Window Β· Prefix Sums
  • Search & sort: Binary Search Β· Merge / Quick Sort Β· Sorting-based patterns
  • Linear DS: Linked Lists Β· Stacks Β· Queues Β· Monotonic Stack / Deque
  • Trees: Binary Trees Β· BST Β· Tries Β· Segment / Fenwick Trees
  • Heaps & intervals: Priority Queue Β· Top-K Β· Merge Intervals
  • Graphs: BFS / DFS Β· Topological Sort Β· Dijkstra Β· Union-Find Β· MST
  • Recursion: Backtracking Β· Divide & Conquer Β· Dynamic Programming (1D, 2D, knapsack, LIS, strings)
  • Greedy Β· Bit Manipulation Β· Math

2. Machine Coding

  • Setup speed: know your editor's shortcuts β€” generate constructors / getters / equals & hashCode (Alt+Insert / Cmd+N), extract & rename. Keep a starter project ready.
  • Read & scope (5–10 min): clarify requirements, list the must-have flows, park the nice-to-haves.
  • Model: list entities β†’ relationships (association / aggregation / composition) β†’ enums for fixed states.
  • Structure: packages by layer (model, service, repository, strategy), main() to demo.
  • Patterns & SOLID: talk about them (Factory, Builder, Strategy, interfaces at variation points) β€” if time is short, don't implement them; implement the main functionality correctly first.
  • Correctness: input validation, custom exceptions, thread-safety where state is shared (ConcurrentHashMap, synchronized, atomics).
  • Finish strong: working demo > extra features; a few unit tests on the core flow; walk through the design and the trade-offs you took.

3. Low Level Design

  • OOPS Β· SOLID Β· Relationships
  • UML (on paper / draw.io)
  • Patterns: Factory, Abstract Factory, Singleton, Observer, Strategy, Builder, Decorator, Adapter, Facade
  • Practice: Hotel Mgmt, Car Parking, Elevator, Chess, Ticket Booking, ATM, Tic-Tac-Toe

4. High Level Design

  • 19 fundamentals β†’ see HLD Fundamentals
  • Estimation β†’ QPS, storage, bandwidth
  • Trade-offs: consistency vs availability

5. Fundamentals

  • OS: Deadlocks, Mutex, Semaphores
  • DBMS: Constraints, UNIQUE, LOCK, SKIP LOCKED, NOT NULL, Triggers
  • CN: TLS, SSH, VPN, Subnet, Static vs Dynamic IP
  • Cloud: AWS/GCP, VM, Kubernetes, Docker, instance types

6. Language depth

  • C++ STL β†’ complexity, iterator invalidation, comparators
  • Java β†’ Collections, Streams, Generics, JVM, concurrency
  • Spring Boot β†’ thread pool model, stateless beans, WebFlux

Mandatory for SDE-2 backend interviews

ConceptImportance
ACID Β· Isolation levelsMandatory
Distributed transactions Β· 2PCMandatory
Saga patternVery important
IdempotencyVery important
Outbox patternVery important
Eventual consistencyVery important
Kafka / event-driven systemsVery important
Requirement gathering β†’ YAGNI. Plan execution β†’ KISS. Keep a record of progress β†’ SOLID.

HLD Fundamentals

The 19 building blocks every high-level design conversation is made of. Know the what, the when, and one trade-off for each.

  1. Capacity estimation — tables, powers of 2 and 10, million/billion/trillion, KB→MB→GB relations.
  2. HTTP & HTTPS β€” REST, methods (GET/PUT/POST/PATCH/DELETE), status codes, TLS.
  3. Server β†’ client push β€” WebSockets (chat, stock ticks), Polling, Server-Sent Events.
  4. Horizontal vs vertical scaling β€” difference, when to use what.
  5. Latency & throughput β€” p50/p99, QPS.
  6. CAP theorem β€” under partition pick C or A; fintech β‡’ consistency > availability.
  7. Load balancers β€” see Load Balancers & Proxies.
  8. Proxies β€” forward vs reverse, and why.
  9. Consistent hashing β€” distribute traffic/data across servers so adding/removing a node moves minimal keys.
  10. SQL vs NoSQL β€” ACID; key-value, document, graph; when to use what; how each scales.
  11. Storage β€” BLOB/object storage (images), Quad Trees (maps/location), graph stores.
  12. Indexing β€” speeds reads, slows writes. Decide per access pattern.
  13. Replication & sharding β€” data can't live in one place (failure + latency). Replicate to survive; shard to partition.
  14. Caching β€” hit/miss, eviction (LRU, LFU, FIFO), and why one policy suits your system.
  15. Message queues & Pub/Sub β€” async processing, decoupling sender & receiver, absorbing spikes.
  16. Resiliency β€” retries, timeouts, circuit breakers, fallbacks, graceful degradation.
  17. Paging & filtering β€” offset/limit or cursor; bring it up yourself for any large dataset.
  18. Rate limiting β€” per user/IP/time window; protects cost, prevents bot abuse.
  19. Logging & monitoring β€” what happened, where, and alerts on it.

How to drive the conversation

  • Clarify functional + non-functional requirements first (scale, latency, consistency).
  • Estimate: DAU β†’ requests/day β†’ QPS β†’ storage/bandwidth.
  • Draw the high-level boxes, then go deep on two components (usually DB schema + caching).
  • Always say why you chose a trade-off, not just what you picked.

Back-of-envelope Estimation

Memorise a handful of numbers and follow a fixed template β€” that gets you 80% of the way.

Numbers to memorise

Time

  • 1 day β‰ˆ 86,400 s β†’ round to 100K s/day
  • 1 month β‰ˆ 2.5M s
  • 1 year β‰ˆ 30M s

Sizes

  • UUID 16 B Β· int 4 B Β· timestamp 8 B
  • Tweet/post β‰ˆ 200 B Β· user profile β‰ˆ 1 KB
  • Image 200–500 KB Β· 1 min video β‰ˆ 50 MB

Powers

  • 210 β‰ˆ 1 K Β· 220 β‰ˆ 1 M Β· 230 β‰ˆ 1 G
  • 1 million = 106, billion = 109, trillion = 1012

The template

  1. DAU β€” given or estimated.
  2. Requests per user per day β†’ multiply β†’ total requests/day.
  3. Γ· 100K β†’ average QPS. Peak β‰ˆ 2–3Γ— average.
  4. Storage = writes/day Γ— object size Γ— retention (years).
  5. Bandwidth = QPS Γ— response size.
  6. Cache β€” 80/20 rule: cache 20% of daily read volume.
Example β€” URL shortener
100M DAU Γ— 1 write/day            = 100M writes/day  β†’ ~1K write QPS
reads 10Γ— writes                  = 1B reads/day     β†’ ~10K read QPS
each record β‰ˆ 500 B Γ— 100M Γ— 365 Γ— 5y β‰ˆ 90 TB over 5 years

Distributed Systems Concepts

Vocabulary that comes up in every HLD discussion β€” with the precise meaning, not the hand-wavy one.

Idempotency

An operation is idempotent if executing it multiple times with the same input produces the same result as executing it once. PUT is idempotent; PATCH and POST generally are not. Pair idempotent APIs with retry + exponential backoff. Store idempotency keys durably β€” Redis can go down, so keep a DB fallback.

Consistency

  • Eventual consistency β€” "quick response now, consistent eventually". Fine when real-time accuracy isn't critical (DynamoDB, WhatsApp profile picture propagating across devices).
  • Dirty read β€” reading data another transaction modified but hasn't committed.
  • Skewed / stale read β€” write to node A, read from node B before replication catches up. A side effect of eventual consistency.
  • Materialized view β€” a DB object storing precomputed query results.

Race conditions

A timing bug between concurrent operations: multiple threads/processes touch shared data, at least one writes, and there's no synchronisation. Classic: two users buy the last item at once β†’ overselling.

  • Locks / mutexes around shared resources
  • Atomic operations (AtomicInteger, DB atomic updates)
  • Thread-safe data structures Β· DB transactions (ACID) Β· synchronized

Failover Β· Fallback Β· Failback

TermMeaning
Fallback"If something goes wrong, do this instead." Core of fault tolerance along with circuit breakers, timeouts, retries.
FailoverAutomatic switch from primary to backup during a failure.
FailbackReturning from backup to the original primary once it recovers. Hard parts: data consistency, disruption during switch, primary failing again.

Safe failback needs: health checks, data sync, LB switching, automation, quorum checks, graceful shutdown, shadow testing, and (for critical systems) manual approval.

Coupling

AspectTightLooseNone
Know each otherYesNoNo
Share contractsYesYes (topics/schema)No
Direct callsYesNoNo
Change impactHighMediumNone
Realistic?YesYes❌ No
Pub/Sub has loose coupling, not no coupling β€” publishers and subscribers still agree on topic name, message schema, semantics, and broker.

Other terms worth owning

  • Transition state β€” a short-lived intermediate state ("Authenticating", "Processing Payment") between stable states.
  • Dedupe β€” keep one unique copy, link the rest. Saves storage, cleans lists, stops fraud.
  • Sidecar β€” helper process/container attached to the main app for auxiliary tasks (proxying, logging, auth).
  • Upstream / downstream β€” services you call vs services that call you.
  • Fan-out / fan-in β€” one event to many consumers / many results merged into one.
  • Complacency trap β€” assuming you know everything so you stop asking questions. Dangerous in design reviews.

Kafka

Distributed messaging / event-streaming platform. Logs, sensor data, events β€” stock market feeds, social feeds, IoT. High throughput and horizontally scalable.

Core vocabulary

  • Producer / Consumer
  • Topic β€” logical category/feed, like a DB table.
  • Broker β€” a server; a cluster is multiple brokers.
  • Partition β€” unit of parallelism. Ordering is guaranteed only within a partition.
  • Offset β€” sequential id of a message inside a partition.
  • Replication factor β€” avoid single point of failure.
  • Consumer group β€” each partition consumed by exactly one consumer in the group (load balancing + fault tolerance). Each group keeps its own offsets, so multiple apps can consume the same stream independently (broadcast).

Why is Kafka fast if it writes to disk?

  • Sequential, append-only writes β€” linear disk writes can beat random memory access.
  • Zero-copy transfer β€” bypasses the user-space copy between disk and socket.
  • OS page cache instead of an in-process cache β€” no JVM GC penalty, cache stays warm across restarts.
  • Producer parallelism β€” keyed messages hash to a partition; unkeyed are round-robined.

Producer acks

SettingBehaviourRisk
acks=0Fire-and-forgetData loss, fastest
acks=1Leader acknowledgesLost if leader dies before followers replicate
acks=all / -1All in-sync replicas acknowledgeSafe only with min.insync.replicas β‰₯ 2

Operational things interviewers probe

  • Rebalance is "stop-the-world" β€” consumption pauses while partitions are reassigned. Use static membership in volatile environments (K8s spot instances) to avoid full rebalances.
  • Consumer lag β€” delay between produce and successful consume; the key health metric.
  • Restart semantics β€” a consumer resumes from its group's last committed offset; a dead pod's partitions are reassigned to surviving members of the group.
  • Pair Kafka with the Outbox pattern for exactly-once-ish DB + event publishing.

Redis & Caching

Redis is more than a cache: cache, Pub/Sub, persistence (snapshot or append-only file), locks (Redisson), rate limiting.

Caching basics

  • Hit / miss, TTLs, cache-aside vs write-through vs write-behind.
  • Eviction: LRU, LFU, FIFO β€” be ready to argue why one suits your system.
  • Cache ~20% of hot data (80/20 rule) for most read-heavy systems.
  • Caching a balance or anything money-related? Treat the DB as source of truth; cache only derived/read views.

Redis vs Memcached

Memcached is a pure in-memory key-value cache. Redis adds data structures (lists, sets, sorted sets, hashes), persistence, Pub/Sub, Lua scripting and clustering.

Redis Cluster β€” slot-to-node metadata cache

Keys hash (CRC16) into 16,384 slots spread over nodes. The client caches the slot→node topology so each command is one network trip instead of "ask where key lives, then send command".

Without metadata cache:  App β†’ ask cluster where key lives β†’ answer β†’ send command   (2 trips)
With metadata cache:     App β†’ local topology β†’ send command directly             (1 trip)

Why not implement that map in your own service? You'd also need slot calculation, cluster discovery (CLUSTER SLOTS), MOVED handling, rebalancing, retries, failover, connection management and health checks. That's why Jedis / Lettuce / Redisson exist.

Idempotency store

Redis can go down. If you store idempotency records only in Redis you can double-process. Keep a durable record in the database and use Redis as the fast path.

CDN

Geographically distributed cache for static (and increasingly dynamic) content β€” video chunks (~4 s MP4 segments with a manifest listing bitrates for ABR/HLS/DASH), images, JS/CSS.

Load Balancers & Proxies

A proxy is an intermediary acting on behalf of another entity. A load balancer is a reverse proxy that distributes load across instances of the same service.

Forward vs reverse proxy

TypeSits in front ofUsed for
Forward (client-side)ClientsAccess control, content filtering, privacy/anonymity, caching, VPN / firewall / NAT
Reverse (server-side)ServersLoad balancing, caching, SSL offload, security, service routing / discovery / registration

Load-balancing algorithms

  1. Round Robin
  2. Weighted Round Robin
  3. Least Connections
  4. Geographical
  5. IP Hashing β€” sticky sessions; stateful requests become easy
  6. Network bandwidth–aware (e.g. video streaming)

Good LBs also watch %CPU, RAM and in-flight requests via health checks / heartbeats to make better decisions. Keep health-check polling short.

Consistent hashing

Place servers and keys on a hash ring; a key goes to the next server clockwise. Adding/removing a server moves only the keys in one arc, not everything. Use virtual nodes to spread load evenly. Questions to be able to answer: how data migrates when a shard is added/removed, who manages it (app layer vs DB layer), and how the app connects to shards + replicas (e.g. MongoDB mongos router, PostgreSQL read replicas).

Databases & Storage

What to know, grouped the way interviewers ask about it.

Storage internals

  • WAL (write-ahead log) Β· B+ trees Β· indexing
  • Leader-follower replication Β· data partitioning
  • Bloom filters Β· hot/cold storage Β· object storage (S3)

Transactions

  • ACID vs BASE Β· isolation levels
  • Shared locks for reads, exclusive for writes
  • Deadlock detection via wait-for graphs β†’ victim rolled back
  • 2PC Β· Saga Β· Outbox

Modelling

  • SQL vs NoSQL (key-value, document, graph)
  • OLTP vs OLAP Β· read/write patterns
  • Data retention Β· backup & restore

Indexing β€” the rule

Indexes make reads faster and writes slower. Decide based on the system's access pattern, and say so out loud in an interview.

Replication & sharding

  • Data can't live in one place: a single location fails, and you want data near the client.
  • Replicate to survive failures and serve reads. Shard (partition) to scale writes and storage.
  • Pick the shard key by the dominant query pattern; avoid hot shards.

Communication & APIs checklist

JWT Β· OAuth Β· CORS Β· throttling Β· serialization (Protocol Buffers) Β· REST vs gRPC Β· API versioning Β· API gateway Β· service mesh Β· long polling Β· WebSockets Β· idempotency Β· retry patterns Β· circuit breaker Β· message queues Β· dead-letter queue.

Reliability & observability checklist

Metrics Β· logging Β· distributed tracing Β· alerting Β· SLO/SLI/SLA Β· error budgets Β· health checks Β· heartbeats Β· autoscaling Β· load testing Β· canary / blue-green deployments Β· rollbacks Β· graceful degradation Β· chaos engineering Β· incident response.

Must-solve Design Problems

Grouped by the dominant pressure in the system. For each, the bullets are what the interviewer actually wants you to focus on.

Read-heavy

  • URL shortener β€” key generation, collisions, DB/caching, sharding
  • Image hosting β€” object storage, CDN, deduplication, resizing
  • Social platform β€” posts, timelines, denormalised storage, sharding
  • News feed β€” push vs pull, fan-out, ranking, pagination

Write-heavy

  • Rate limiter β€” token/leaky bucket, Redis, TTL
  • Log collection & analysis β€” Kafka, ELK, partitioning, real-time query
  • Voting system β€” idempotency, fraud prevention, real-time aggregation
  • Trending topics β€” count-min sketch, sliding window, ranking

Search, messaging & delivery

  • Word dictionary β€” trie, prefix lookups
  • Text search engine β€” tokenisation, inverted index, ranking
  • SQL-backed message broker β€” durability, ordering, delivery semantics
  • Distributed task scheduler β€” idempotency, retries, time-based triggering
  • Recent searches β€” LRU cache, user isolation

Fintech flavour (SDE-2 product companies)

Order placement, portfolio feed, notification system, payment processing, real-time price feed. Remember: consistency > availability, and go deep on two components β€” usually schema + caching.

How to approach an LLD problem

Use this as your script. Timings are for a 45–60 min round. Always narrate why you choose an approach.

  1. Clarify requirements & scope (1–2 min) β€” core operations, scale, performance goals, persistence, correctness vs eventual, concurrency needs. Decide constraints: single node vs distributed, QPS, memory.
  2. State APIs / use-cases (1–3 min) β€” list main APIs with example calls and input/output shapes.
  3. High-level components (2–5 min) β€” draw boxes for main classes/components and their interactions. Simple first.
  4. Detailed class design (5–12 min) β€” classes, methods, key fields, relationships (aggregation/inheritance). Highlight interfaces/abstractions (SOLID). Show the sequence for main flows.
  5. Data structures & algorithms (3–8 min) β€” pick DS for critical ops (priority queue, hashmap, LRU list) and state complexity.
  6. Concurrency & correctness (2–6 min) β€” race conditions, locks vs lock-free, thread-safety (synchronized, atomics, concurrent collections), transactional boundaries.
  7. Persistence (2–5 min) β€” RDBMS vs NoSQL, schema sketch, indices, caching layers.
  8. Scaling & availability (2–6 min) β€” bottlenecks β†’ partitioning, replication, caching, queueing, graceful degradation.
  9. Edge cases & failure modes (2–5 min) β€” input errors, retries, duplicates, partial failures, network partitions.
  10. Testing & metrics (1–3 min) β€” unit/integration tests, key metrics and alerts.
  11. Extensions & trade-offs (1–3 min) β€” what you'd add next and what you consciously gave up.

Practice set

Hotel Management Β· Car Parking Β· Elevator Β· Chess Β· Ticket Booking Β· ATM Β· Tic-Tac-Toe. Resources: codezym.com, "System Design and Gossip" on YouTube.

Moving from definitions to instinct

Practise scenario-based quizzes, "class vs interface vs abstract class?" questions, pattern identification, and refactoring exercises. Group similar patterns (Factory/Abstract Factory, Decorator/Proxy, Strategy/State) and for each ask: what's the problem, which pattern solves it, how does it look in real code?

SOLID Principles

Core intention: control change. SOLID is not about splitting everything β€” it's about finding volatility points (where change happens) and applying principles there.

S β€” Single Responsibility

"A class should have only one reason to change." Think Swiss Army knife: sharpen the blade and you carry the whole tool. Granularity: class level (sometimes method).

// ❌ three reasons to change: business rule, email provider, DB
class UserService {
  void registerUser(User u) {}
  void sendEmail(User u) {}
  void saveToDB(User u) {}
}

// βœ… SRP applied
class UserService   { void registerUser(User u) {} }
class EmailService  { void sendEmail(User u) {} }
class UserRepository{ void save(User u) {} }
If a class has multiple reasons to change, split it.

O β€” Open/Closed

"Open for extension, closed for modification." A game doesn't change when a new controller ships β€” the controller implements the standard interface. Apply where behaviour varies (payments, notifications, storage types).

// ❌ every new payment type modifies this
if (type.equals("CARD")) ... else if (type.equals("UPI")) ...

// βœ…
interface Payment { void pay(); }
class CardPayment implements Payment {}
class UpiPayment  implements Payment {}

L β€” Liskov Substitution

"Subtypes must be substitutable for their base types." A Smart TV remote must still have a working power button. Square/Rectangle with setWidth/setHeight is the classic violation. Applies only where inheritance exists.

// ❌
class Bird { void fly() {} }
class Ostrich extends Bird { void fly() { throw new UnsupportedOperationException(); } }

// βœ… fix the abstraction
interface Bird {}
interface FlyingBird extends Bird { void fly(); }
class Sparrow implements FlyingBird {}
class Ostrich implements Bird {}
If a child cannot honour parent behaviour β†’ wrong abstraction.

I β€” Interface Segregation

"Clients shouldn't depend on interfaces they don't use." Separate breakfast / lunch / drinks menus instead of one giant page.

// ❌ Tester forced to implement code()
interface Worker { void code(); void test(); void deploy(); }

// βœ…
interface Coder  { void code(); }
interface Tester { void test(); }
interface DevOps { void deploy(); }

D β€” Dependency Inversion

"High-level modules should not depend on low-level modules; both depend on abstractions." The lamp has a plug, the wall has a socket β€” neither cares about the other's wiring. Bonus: interfaces are mockable, concrete classes aren't. Apply at system boundaries: DB, APIs, messaging, storage.

// ❌
class OrderService { MySQLDB db = new MySQLDB(); }

// βœ… inject the abstraction
class OrderService {
  private final DBInterface db;
  OrderService(DBInterface db) { this.db = db; }
}

Where each applies

PrincipleGranularityApply at
SRPClass / methodAny class with >1 reason to change
OCPBehaviour variation pointPlaces new types/behaviours are expected
LSPInheritance hierarchyWherever inheritance exists
ISPInterface designImplementers that use only parts
DIPModule interactionHigh-level logic ↔ low-level details

Design Patterns Cheat Sheet

When to use Β· what to use Β· how it works. Revise by grouping similar patterns and coding two a day.

Creational

PatternWhenWhatHow
SingletonOnly one instance should exist (Logger, Config)Private constructor + static instanceRestrict instantiation, give global access. Watch out for double-checked locking, reflection, serialization.
FactoryCreation logic varies by inputCentral factory methodswitch/map returns the right subclass
Abstract FactoryFamilies of related objects (Mac vs Windows UI)Factory of factoriesEach factory creates a related family
BuilderMany optional fieldsChained step-by-step constructionSeparate construction from representation; supports immutability
PrototypeCloning is cheaper than creatingClone an existing objectclone() or copy constructors

Structural

PatternWhenWhatHow
AdapterInterfaces are incompatibleWrapperConverts one interface into what the client expects
BridgeDecouple abstraction from implementationTwo independent hierarchiesAbstraction holds a reference to the implementation
CompositeTreat individual & group uniformlyTree with common interfaceRecursive composition
DecoratorAdd behaviour dynamicallyWrap in layersComposition decorates the original
FacadeSimplify a complex subsystemOne high-level interfaceEncapsulates multiple subsystems
ProxyControl access (caching, lazy loading, security)Stand-in objectSame interface, controls access
FlyweightMany similar objects, memory mattersShare intrinsic stateFactory + cache of shared instances

Behavioural

PatternWhenWhatHow
StrategyMultiple algorithms selectable at runtimeEncapsulated algorithmsInterface + interchangeable implementations
ObserverOne-to-many updates (UI, events)Publisher–SubscriberSubject keeps a list of observers
CommandRequest as an object (undo/redo)execute() interfaceClient creates, invoker runs, receiver executes
Chain of ResponsibilityPass request along handlersLinked handlersEach handles or forwards
StateBehaviour changes with internal stateState subclassesContext delegates to the current state
Template MethodSkeleton in base, steps in subclassesAbstract class with hooksSome methods fixed, others overridden
IteratorTraverse without exposing structureIterator interfaceSeparate traversal object

How to revise

  • Group similar patterns: Factory & Abstract Factory Β· Decorator & Proxy Β· Strategy & State.
  • For each ask: what is the problem? which pattern solves it? how does it apply in real code?
  • Code 2 patterns a day, even with print statements.
  • Real-world anchors help: Google Maps β‰ˆ Flyweight + Proxy.

OOP Relationships

Association vs Aggregation vs Composition β€” and the four questions that settle it every time.

The decision ladder

  1. Do the objects relate at all? If they know about / use each other β†’ at least an Association. (Teacher teaches Student.)
  2. Is one a whole and the other a part? No β†’ stay with Association. Yes β†’ go deeper.
  3. Who owns the lifecycle? Part dies with the whole β†’ Composition (Human β†’ Heart). Part lives independently β†’ Aggregation (Library β†’ Books).
  4. Association vs Aggregation β€” both allow independent lifecycles. Ask: is one logically "part of" the other? Yes β†’ Aggregation (Classroom–Students). No, just a link β†’ Association (Teacher–Student).

Mental shortcut

If "X has Y" sounds natural β†’ whole–part (Aggregation / Composition). If only "X works with Y" sounds natural β†’ Association.
RelationshipWhole–part?LifecycleExample
AssociationNo β€” link onlyIndependentTeacher ↔ Student, Bank employs Employees
AggregationYesIndependent (weak ownership)Library β†’ Books, Classroom β†’ Students
CompositionYesDependent (strong ownership)Human β†’ Heart, House β†’ Rooms

Related vocabulary

  • Upcasting β€” superclass reference pointing at a subclass object.
  • Loose coupling β€” code written against an interface; swap the implementation without touching callers.
  • High cohesion β€” interfaces define clear, focused responsibilities.

Machine Coding Round

90–120 minutes, working code, clean structure. Here's the order of operations and the shortcuts that save time.

Order of operations

  1. List all entities β†’ see how they link β†’ implement only the basic requirement set first.
  2. Keep code clean while creating objects β†’ Factory for entity creation, Builder when there are many optional fields.
  3. Keep SOLID intact β†’ corresponding interfaces, Dependency Inversion, Strategy for pluggable behaviour.

Don't overthink IDs

No database, no UUID complexity. A static counter inside the class is enough.

public class User {
  private static int counter = 0;      // class-level counter
  private final String id;
  private final String name;

  public User(String name) {
    this.id = "USR-" + (++counter);    // USR-1, USR-2, USR-3
    this.name = name;
  }
}

Checklist before you say "done"

  • Main flow demonstrable from a main() or test.
  • Interfaces for anything that could vary (pricing, notification, storage).
  • Thread-safety called out where shared state exists (even if not implemented).
  • Edge cases listed verbally: invalid input, duplicates, empty states.

C++ STL β€” things to care of

The traps that bite in interviews and production, plus the STL β†’ Java mapping for when you switch languages.

Things to care of

  • priority_queue is a max-heap by default. Min-heap: priority_queue<int, vector<int>, greater<int>>. (Java's PriorityQueue is the opposite β€” min-heap by default.)
  • Iterator invalidation. vector::push_back may reallocate and invalidate all iterators/pointers/references; erase invalidates from the erased point onward. unordered_map rehash invalidates iterators (not references). map/set/list only invalidate the erased element.
  • Comparators must be a strict weak ordering. Return true only when a is strictly before b. Using <= is undefined behaviour in sort and can crash.
  • operator[] on a map inserts. m[k] default-constructs a value if missing. Use find / count / at for read-only lookups.
  • unordered_map worst case is O(n). Adversarial inputs can trigger collisions β€” in contests use a custom hash or fall back to map.
  • lower_bound / upper_bound need sorted ranges. On set/map use the member versions (O(log n)), not std::lower_bound (O(n) on non-random-access iterators).
  • reserve() when you know the size β€” avoids repeated reallocation. emplace_back constructs in place; push_back copies/moves.
  • Erase-remove idiom: v.erase(remove_if(v.begin(), v.end(), pred), v.end()); β€” or std::erase_if(v, pred) in C++20.
  • size() is unsigned. v.size() - 1 on an empty vector wraps around. Compare with int carefully.
  • Prefer std::array / vector over raw arrays; prefer string_view for read-only string params.
  • Pass large containers by const&; return by value (RVO / move semantics make it cheap).
  • std::deque is the right default for queues/stacks (stack and queue are adaptors over it).

Complexity reminders

ContainerLookupInsert / eraseOrdered?
vectorO(1) by indexO(1) amortised at end, O(n) middleInsertion order
dequeO(1)O(1) both endsInsertion order
listO(n)O(1) with iteratorInsertion order
map / setO(log n)O(log n)Sorted (red-black tree)
unordered_map / setO(1) avg, O(n) worstO(1) avgNo
priority_queueO(1) topO(log n)Heap order

C++ STL β†’ Java mapping

C++ STLJavaNotes
vector<T>ArrayList<T>O(1) get, O(n) middle insert
list<T>LinkedList<T>Doubly linked
map<K,V>TreeMap<K,V>Sorted, O(log n)
unordered_map<K,V>HashMap<K,V>Default choice
set<T>TreeSet<T>Sorted
unordered_set<T>HashSet<T>Default choice
priority_queue<T>PriorityQueue<T>Min-heap by default in Java
deque / stack / queueArrayDeque<T>Don't use legacy Stack
pair<A,B>record / Map.EntryNo built-in Pair
multimap<K,V>Map<K, List<V>>Use computeIfAbsent

Java Essentials

The idioms and gotchas that matter most when you're writing Java under interview pressure.

Golden rule: declare with the interface type

List<String> names = new ArrayList<>();     // βœ…
Map<String, Integer> freq = new HashMap<>();
Set<String> seen = new HashSet<>();

ArrayList<String> names = new ArrayList<>(); // ❌ too specific

Swap ArrayList for LinkedList later by changing one word, not every signature.

HashMap β€” the patterns you'll use most

map.get("a");                       // returns null if absent β€” NOT an exception
map.getOrDefault("a", 0);           // safe get
map.merge("a", 1, Integer::sum);    // frequency count
map.computeIfAbsent("a", k -> new ArrayList<>()).add("item");  // multimap
for (Map.Entry<String,Integer> e : map.entrySet()) { e.getKey(); e.getValue(); }
map.get() returns null for missing keys. Always use getOrDefault() unless you're explicitly checking for null.

No built-in Pair β†’ use a record

record Point(int x, int y) {}
public record Pair<L, R>(L left, R right) {}

Point p = new Point(3, 5);  p.x();  p.y();          // accessors, no 'get'
Map<Point, String> grid = new HashMap<>();         // equals/hashCode auto-generated

Records are immutable, so they're safe as map keys and in sets.

Sorting

Collections.sort(nums);                        // ascending
nums.sort(Comparator.reverseOrder());          // descending
Arrays.sort(arr);                              // int[] ascending (no reverse for primitives)
cars.sort(Comparator.comparingInt(Car::price).thenComparing(Car::name));
cars.sort((a, b) -> b.speed - a.speed);        // lambda, descending by speed

Primitive vs reference fields

  • Primitive (int, boolean…) stores the value directly, fixed size, never null, no methods.
  • Reference (any class, interface, enum, array, String) stores an address into the heap; can be null; has methods.
  • Assigning a primitive copies the value; assigning a reference copies the address β€” both now point to the same object.

Java is strictly pass-by-value

What's passed by value for a reference type is the reference. So a method can mutate the object you passed, but reassigning the parameter inside the method doesn't affect the caller.

static void modify(List<String> list) {
  list.add("Orange");          // βœ… visible to caller β€” same object
  list = new ArrayList<>();    // ❌ only rebinds the local copy of the reference
  list.add("New Item");
}

Also know

java.util.function (Function, Supplier, Consumer, Predicate) Β· Stream API (map/filter/collect/groupingBy) Β· java.lang.Object contract (equals/hashCode/toString) Β· Generics (bounded types, wildcards) Β· JVM memory & GC Β· JAVA_TOOL_OPTIONS (JVM-level) vs application.properties (Spring-level).

Java Concurrency & Spring

The one mental model: a thread is needed to execute CPU work, but it does not need to stay occupied while waiting for non-blocking I/O.

Blocking vs non-blocking I/O

Blocking:      Thread β†’ send request β†’ WAIT ……………… response β†’ continue
               (thread occupied the whole time)

Non-blocking:  Event loop β†’ start A β†’ start B β†’ process C β†’ start D
               β†’ later: A's response arrives β†’ process A
               (no thread sits waiting on A)

Spring Boot (MVC) uses a multi-threaded thread pool β€” one thread per in-flight request. Spring WebFlux on Netty uses an event loop; the controller returns Mono/Flux and Spring subscribes as part of handling the request.

Singleton beans and thread safety

Spring creates one instance of a @Service and reuses it. Threads 1…N all call the same object.

@Service
public class PaymentService {
  public Payment getPayment(String id) {   // local variables only β†’ stateless β†’ thread-safe
    return fetchPayment(id);
  }
}
Stateless is one way to be thread-safe. But thread-safe β‰  stateless β€” you can hold state if it's protected (concurrent collections, atomics, locks).

Toolbox

NeedReach for
Counter / flagAtomicInteger, AtomicLong, AtomicBoolean
Shared mapConcurrentHashMap + computeIfAbsent
Critical sectionsynchronized, ReentrantLock (tryLock, fairness)
Readers ≫ writersReadWriteLock
Producer / consumerBlockingQueue
Thread poolExecutorService, CompletableFuture
Distributed lockRedisson (Redis), DB row lock / SELECT … FOR UPDATE SKIP LOCKED

Singleton pitfalls (LLD favourite)

  • Lazy initialisation needs double-checked locking with a volatile field β€” or just use an enum / static holder.
  • Reflection and serialization can create a second instance; guard the constructor and implement readResolve().

Database locking recap

Databases use shared locks for reads and exclusive locks for writes. Many shared locks coexist; an exclusive lock blocks both. Deadlocks are detected with wait-for graphs β€” on a cycle, one transaction is chosen as victim and rolled back.

πŸ’¬ Have a question about any of this?

Pick the topic, type your question, and hit send β€” it opens an email to me pre-filled with your question so I can reply directly. If it's a good one I'll add the answer to that page.

Can I suggest a correction or a new topic?

Yes β€” pick "Correction / new topic" in the dropdown. Corrections to anything on these pages are very welcome.