Interviews love acronyms. SOLID, ACID, DRY, KISS, CAP, STAR. Each one is simple on its own, but under pressure they blur together. This post is the one-page refresh I wish I had before every interview: what each idea means, a small example, and the follow-up question you are likely to get.
Read the cheat sheet first, then jump to whatever feels rusty.
TL;DR cheat sheet
| Topic | One line | Where it applies |
|---|---|---|
| OOP vs FP | Model the world as objects with state, or as data flowing through pure functions | How you structure code |
| SOLID | Five rules for classes that are easy to change | Object-oriented design |
| ACID | Guarantees that keep a single database correct | Transactions in a database |
| DRY | One piece of knowledge, one place | Any code |
| KISS | The simplest thing that works | Any code |
| CAP | During a network split, choose consistency or availability | Distributed systems |
| List, Set, Map | Ordered items, unique items, key to value | Data structures |
| Design patterns | Named, reusable solutions to common problems | Object-oriented design |
| System design | Requirements, estimates, design, trade-offs | Architecture interviews |
| STAR | Situation, Task, Action, Result | Behavioural interviews |
1. OOP vs FP
Both are ways to organise code. Most modern languages, Java and JavaScript included, let you mix them.
Object-oriented programming (OOP)
You group data and the behaviour that changes it into objects. The four pillars:
- Encapsulation: keep state private and expose only safe operations.
- Abstraction: show what something does and hide how.
- Inheritance: reuse and extend behaviour from a parent type.
- Polymorphism: one interface, many implementations.
interface Shape {
double area();
}
class Circle implements Shape {
private final double radius; // encapsulation
Circle(double radius) { this.radius = radius; }
public double area() { return Math.PI * radius * radius; }
}
class Square implements Shape {
private final double side;
Square(double side) { this.side = side; }
public double area() { return side * side; }
}
// polymorphism: the caller does not care which shape it is
double total = shapes.stream().mapToDouble(Shape::area).sum();Functional programming (FP)
You build programs from pure functions applied to immutable data.
- Pure functions: same input, same output, no side effects.
- Immutability: create new values instead of changing existing ones.
- Higher-order functions: functions that take or return functions (
map,filter,reduce). - Composition: build big behaviour from small functions.
The same task, "total price of in-stock items", both ways:
// Imperative / OOP style: a loop that mutates a variable
double total = 0;
for (Item item : items) {
if (item.inStock()) {
total += item.price();
}
}
// Functional style: describe the result, no mutation
double total = items.stream()
.filter(Item::inStock)
.mapToDouble(Item::price)
.sum();When to use which? OOP shines when you model long-lived things with state and rules (accounts, orders, UI components). FP shines for transformations and pipelines (data processing, validation, reducers). Pure functions are also far easier to test.
Likely follow-up: "What is the difference between abstraction and encapsulation?" Abstraction hides complexity behind a simple interface; encapsulation hides state behind access control.
2. SOLID
Five principles that keep object-oriented code easy to change.
S: Single Responsibility
A class should have one reason to change.
// Bad: report logic and file saving mixed together
class Report {
String build() { /* ... */ return ""; }
void saveToFile(String path) { /* ... */ }
}
// Good: each class has one job
class Report { String build() { /* ... */ return ""; } }
class ReportWriter { void save(String content, String path) { /* ... */ } }O: Open/Closed
Open for extension, closed for modification. Add new behaviour by adding code, not by editing a growing if/else.
interface Discount { double apply(double price); }
class NoDiscount implements Discount {
public double apply(double price) { return price; }
}
class FestiveDiscount implements Discount {
public double apply(double price) { return price * 0.8; }
}
// A new discount is a new class; existing code stays untouched.L: Liskov Substitution
A subtype must be usable anywhere its parent is expected without surprises.
The classic trap: a Square that extends Rectangle. Setting the width of a square also changes its height, so code that expects a rectangle breaks. If a child cannot honour the parent's contract, it should not be a child.
I: Interface Segregation
Prefer small, focused interfaces over one large one.
// Bad: a robot is forced to implement eat()
interface Worker { void work(); void eat(); }
// Good
interface Workable { void work(); }
interface Eatable { void eat(); }
class Robot implements Workable { public void work() { /* ... */ } }D: Dependency Inversion
Depend on abstractions, not concrete classes. This is what makes code testable.
interface PaymentGateway { void charge(double amount); }
class CheckoutService {
private final PaymentGateway gateway; // depends on the interface
CheckoutService(PaymentGateway gateway) { this.gateway = gateway; }
void pay(double amount) { gateway.charge(amount); }
}
// In tests, pass a fake gateway. In production, pass the real one.Likely follow-up: "Which SOLID principle helps testing most?" Dependency Inversion, because it lets you inject fakes and mocks.
3. ACID (databases)
ACID describes the guarantees a database gives for a transaction: a group of operations that must succeed or fail together.
| Letter | Meaning | In one line |
|---|---|---|
| A | Atomicity | All or nothing |
| C | Consistency | Rules and constraints always hold |
| I | Isolation | Concurrent transactions do not interfere |
| D | Durability | Once committed, it survives a crash |
The classic example is a bank transfer:
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;
-- If anything fails before COMMIT, ROLLBACK undoes both updates.- Atomicity: you never end up with money debited but not credited.
- Consistency: a constraint like
balance >= 0is never violated. - Isolation: another transaction does not see the half-finished transfer.
- Durability: after
COMMIT, a power cut does not lose it.
Isolation levels
Isolation is a dial, traded against performance:
| Level | Dirty read | Non-repeatable read | Phantom read |
|---|---|---|---|
| Read Uncommitted | possible | possible | possible |
| Read Committed | prevented | possible | possible |
| Repeatable Read | prevented | prevented | possible (by the SQL standard) |
| Serializable | prevented | prevented | prevented |
PostgreSQL defaults to Read Committed; MySQL (InnoDB) defaults to Repeatable Read.
Likely follow-up: "Is the C in ACID the same as the C in CAP?" No. ACID consistency means rules and constraints hold. CAP consistency means every read sees the latest write.
4. DRY: Don't Repeat Yourself
Every piece of knowledge should live in one place.
// Repeated: the tax rule lives in two places and will drift
double invoiceTotal = subtotal + subtotal * 0.13;
double quoteTotal = amount + amount * 0.13;
// DRY: one source of truth
static final double TAX_RATE = 0.13;
static double withTax(double amount) { return amount * (1 + TAX_RATE); }Watch out: DRY is about knowledge, not about code that merely looks similar. Merging two things that only look alike creates the wrong abstraction. A good rule of thumb is the rule of three: duplicate once, abstract on the third time.
5. KISS: Keep It Simple
Choose the simplest solution that works. Simple code is easier to read, test and fix.
// Overthought
boolean isEven(int n) {
return n % 2 == 0 ? Boolean.TRUE.equals(true) : Boolean.FALSE.equals(true);
}
// Simple
boolean isEven(int n) { return n % 2 == 0; }A close cousin is YAGNI ("You Aren't Gonna Need It"): do not build features or abstractions for a future that may never come.
6. CAP theorem (distributed systems)
When data is copied across several machines, a network partition (machines unable to talk to each other) will eventually happen. During a partition, you can only keep one of:
- Consistency (C): every read sees the latest write.
- Availability (A): every request gets a response, even if it might be stale.
Partition tolerance (P) is not optional in a real distributed system, so the real choice is CP or AP:
| Choice | Behaviour during a partition | Typical fit |
|---|---|---|
| CP | Refuse or delay some requests to stay correct | Payments, inventory, leader election |
| AP | Keep answering, reconcile later | Social feeds, shopping carts, view counters |
Many databases let you tune this per operation (for example, Cassandra's consistency levels).
The PACELC extension adds the everyday case: if there is a Partition choose A or C, Else choose Latency or Consistency.
Likely follow-up: "Can a system be CA?" Only on a single machine, or if you assume the network never fails, which is not realistic for a distributed system.
7. Data structures: List, Set, Map
These three cover most interview problems. Know what each is for and its cost.
| Structure | What it stores | Java implementations | Typical cost |
|---|---|---|---|
| List | Ordered items, duplicates allowed | ArrayList, LinkedList | ArrayList: get O(1), contains O(n) |
| Set | Unique items | HashSet, LinkedHashSet, TreeSet | HashSet: add/contains O(1) average; TreeSet: O(log n), sorted |
| Map | Key to value pairs, unique keys | HashMap, LinkedHashMap, TreeMap | HashMap: get/put O(1) average; TreeMap: O(log n), sorted keys |
Quick picks:
- Need order and index access?
ArrayList. - Need "have I seen this?" checks?
HashSet. - Need counts or lookups by key?
HashMap. - Need things sorted?
TreeSetorTreeMap. - Need insertion order preserved?
LinkedHashSetorLinkedHashMap.
A classic: count word frequency, then find duplicates.
List<String> words = List.of("test", "build", "test", "ship", "build", "test");
Map<String, Integer> counts = new HashMap<>();
for (String w : words) {
counts.merge(w, 1, Integer::sum); // {test=3, build=2, ship=1}
}
Set<String> seen = new HashSet<>();
Set<String> duplicates = new LinkedHashSet<>();
for (String w : words) {
if (!seen.add(w)) duplicates.add(w); // add() returns false if present
}
// duplicates = [test, build]Likely follow-up: "How does a HashMap work?" Keys are hashed into buckets. Collisions share a bucket (a list, which Java turns into a balanced tree when a bucket gets large). That is why
equals()andhashCode()must agree.
8. Design patterns (quick refresh)
You rarely need all 23 classic patterns. These five come up most:
| Pattern | Problem it solves | One-line example |
|---|---|---|
| Singleton | Exactly one shared instance | A config or connection pool |
| Factory | Create objects without naming the concrete class | ShapeFactory.create("circle") |
| Builder | Construct complex objects step by step | new User.Builder().name("A").age(30).build() |
| Strategy | Swap an algorithm at runtime | Different discount or sorting rules |
| Observer | Notify many listeners when something changes | Event listeners, pub/sub |
Strategy is the one to be able to write from memory, and it is the Open/Closed principle in action:
interface SortStrategy { void sort(int[] data); }
class QuickSort implements SortStrategy { public void sort(int[] d) { /* ... */ } }
class MergeSort implements SortStrategy { public void sort(int[] d) { /* ... */ } }
class Sorter {
private SortStrategy strategy;
Sorter(SortStrategy strategy) { this.strategy = strategy; }
void setStrategy(SortStrategy s) { this.strategy = s; }
void sort(int[] data) { strategy.sort(data); }
}9. System design (SD)
System design interviews are less about one correct answer and more about how you think. A repeatable structure:
- Clarify requirements: functional (what it does) and non-functional (scale, latency, availability).
- Estimate: users, requests per second, storage. Rough numbers are fine.
- Define the API: the main endpoints and their inputs and outputs.
- Model the data: entities, and SQL vs NoSQL with a reason.
- High-level design: clients, load balancer, services, database, cache, queues.
- Deep dive: the hardest part (scaling reads, hot keys, consistency).
- Trade-offs: what you chose, what you gave up, and why.
A tiny example, a URL shortener:
- API:
POST /shortenwith a long URL returns a short code;GET /:coderedirects. - Data: a table of
code,longUrl,createdAt. - Design: generate a short unique code (for example, base62 of an ID), store it, and put a cache in front of reads because redirects are read-heavy.
- Trade-off: reads vastly outnumber writes, so optimise the read path; brief staleness of rarely changed data is acceptable, which leans AP for the cache layer.
The building blocks to name confidently: load balancer, cache (Redis), CDN, database replicas and sharding, message queue (Kafka, SQS), rate limiting.
10. STAR method (behavioural questions)
For "Tell me about a time whenโฆ" questions, answer with STAR:
- Situation: the context, briefly.
- Task: what you were responsible for.
- Action: what you did, specifically. Spend most of the time here.
- Result: the outcome, with numbers if possible, and what you learned.
A template example for "Tell me about a time you improved a process":
Situation: Our end-to-end suite was flaky and failed on roughly one in three runs, so the team had stopped trusting it.
Task: I was asked to make the suite reliable before the next release.
Action: I grouped failures by cause, replaced fixed sleeps with explicit waits, isolated test data per run, and added retries only for known network-dependent steps.
Result: Flaky failures dropped sharply, the team started using the suite as a release gate again, and I documented the patterns for new tests.
Tips: prepare four or five stories in advance (a challenge, a failure, a conflict, leadership, a big win) and reuse them across questions.
Rapid-fire recap
- OOP vs FP? Objects with state and behaviour, versus pure functions on immutable data.
- SOLID in one breath? Single responsibility, Open/closed, Liskov substitution, Interface segregation, Dependency inversion.
- ACID? Atomicity, Consistency, Isolation, Durability: correctness for one database.
- CAP? During a partition, choose consistency or availability.
- DRY vs KISS? Do not duplicate knowledge; do not overcomplicate.
- List vs Set vs Map? Ordered items, unique items, key-value lookups.
- System design? Requirements, estimates, API, data, design, deep dive, trade-offs.
- STAR? Situation, Task, Action, Result, with most of the time on Action.
This post is part of the Interview Essentials series. If you want to go deeper, the earlier parts cover coding patterns, Java and JavaScript basics, SQL and testing concepts.
