Friday, March 6, 2026

LeetCode C++ Cheat Sheet June

🎯 Core Patterns & Representative Questions

1. Arrays & Hashing

  • Two Sum – hash map → O(n)

  • Contains Duplicate, Product of Array Except Self, Maximum Subarray (Kadane) (byby.dev, prepinsta.com)

2. Binary Search (Sorted & Answer Space)

  • Search Insert Position, First Bad Version, Rotated Array Search, Find Minimum in Rotated Array, Peak Element, Split Array Largest Sum (kodnest.com)

3. Two Pointers & Sliding Window

  • Container With Most Water, 3Sum, Minimum Window Substring, Longest Substring Without Repeating Characters (lets-code.co.in)

4. Stacks & Queues

  • Valid Parentheses, Evaluate Reverse Polish Notation

5. Linked Lists

  • Merge Two Sorted Lists, Reverse Linked List

6. Trees & Graphs

  • Binary Tree Traversals, Number of Islands, Clone Graph, Course Schedule (lets-code.co.in)

7. Heaps & Priority Queues

  • Merge k Sorted Lists, Top K Frequent Elements, Median from Data Stream (lets-code.co.in)

8. Dynamic Programming

  • Climbing Stairs, Coin Change, Longest Increasing Subsequence, Word Break, Maximum Subarray

9. Backtracking

  • Permutations, Combinations, Generate Parentheses, Word Search

10. Intervals

  • Merge Intervals, Insert Interval, Minimum Number of Arrows to Burst Balloons


🚀 Why These?

  • They cover ~75–150 essential problems seen across tech interviews (#Blind75 guides this list) (csmaven.com, lets-code.co.in).

  • They're grouped by core techniques—key to pattern recognition during interviews.

  • Repositories (GitHub “Top 150…” etc.) are organized the same way for efficient drill-down (github.com).


📚 How to Use This Cheat Sheet

  1. Pattern Recognition: Read the problem prompt → map to a pattern above.

  2. Recall Template: Use your stored C++ template (e.g., two-pointer or sliding window).

  3. Implement & Discuss: Talk through:

    • Brute-force → point to inefficiencies.

    • Optimized solution → complexities, edge cases.

    • Time/Space tradeoffs.

  4. Validate: Test on examples (e.g., “Two Sum” → [2,7,11,15], target=9, output = [0,1]).


🛠 Suggestion: Build Your Personal Toolbox

Create a .cpp file or repo with sections:

// Two Sum
vector<int> twoSum(...) { ... }
// Binary Search Template
int binarySearchTemplate(...) { ... }
// Sliding Window Template
int minWindow(...) { ... }
// ...

Populate it with solutions and sample inputs. Over time, this will become your go-to during interviews.


✅ Next Steps

 

🎯 Top 10 Core Algorithmic Patterns (with Purpose)


1. 🔁 Hashing / Hash Maps

Pattern: Use a map, unordered_map, or set to:

  • Track frequencies

  • Store visited elements

  • Enable O(1) lookup

Used For:

  • Constant-time search

  • Duplicate detection

  • Pair matching

  • Frequency count


2. 🔍 Binary Search

Pattern: Divide the search space in half each time:

  • On sorted arrays

  • On “answer space” (e.g. min/max values)

Used For:

  • Search in sorted arrays

  • Finding first/last occurrence

  • Min/max problem solving (searching over results, not array)


3. 🔄 Two Pointers

Pattern: Use two pointers to scan array:

  • Either moving toward each other or in parallel

Used For:

  • Finding pairs

  • Sorting/merging arrays

  • Removing duplicates

  • Palindrome checks


4. 🚪 Sliding Window

Pattern: Expand + shrink a window over an array or string:

  • Typically uses two pointers with conditions

Used For:

  • Substring or subarray problems

  • Longest/shortest with a constraint

  • Minimum/maximum window containing elements


5. 🧱 Stack-Based Processing

Pattern: Use LIFO data structure to:

  • Track state

  • Handle nested operations

  • Reverse sequences

Used For:

  • Matching parentheses/brackets

  • Undo operations

  • Monotonic stacks (next greater/smaller)


6. 🔗 Linked List Manipulation

Pattern: Use pointer manipulation to:

  • Traverse

  • Reverse

  • Merge

  • Detect cycles

Used For:

  • In-place list operations

  • Pointer movement control

  • Fast/slow pointer tricks


7. 🌳 Graph & Tree Traversals (DFS/BFS)

Pattern:

  • Use recursion (DFS) or queue (BFS)

  • Traverse nodes, track visited, handle recursion stack

Used For:

  • Pathfinding

  • Island counting

  • Tree recursion

  • Cycle detection


8. 🥇 Greedy Algorithms

Pattern: Make local optimal choice at each step assuming it leads to global optimum

Used For:

  • Interval scheduling

  • Minimizing operations

  • Resource allocation


9. 💡 Dynamic Programming

Pattern: Break down problems into overlapping subproblems, memoize results

Used For:

  • Optimal subsequences (LIS, LCS)

  • Count ways (staircase, coin change)

  • Subarray/subset sum problems


10. 🧩 Backtracking

Pattern: Recursively build candidates and backtrack upon invalid state

Used For:

  • All combinations / permutations

  • Decision trees

  • Constraint satisfaction (sudoku, N-Queens)


✅ Bonus: Intervals & Sorting

Pattern: Sort by start or end time and:

  • Merge

  • Select non-overlapping intervals

  • Sweep line algorithms

Used For:

  • Time-based scheduling

  • Range merging

  • Event processing


 

LeetCode C++ Cheat Sheet MAY

🧠 LeetCode C++ Cheat Sheet for Problem Solving

🧱 Basic Techniques in C++

Technique When to Use C++ STL/Approach
Two Pointers Sorted arrays, find pair, reverse, remove duplicates int i = 0, j = n - 1;
Sliding Window Substrings, subarrays, max/min in window unordered_map, set, manual window
Hash Map / Set Frequency count, duplicates, lookups unordered_map, unordered_set
Stack Parentheses, next greater, monotonic problems stack<int>
Binary Search Sorted arrays, upper/lower bounds, min/max problem binary_search(), lower_bound()
Backtracking Permutations, subsets, N-queens Recursive + vector, manual tracking
DP Subproblems with overlapping states vector<vector<int>> dp(n, vector<int>(m))
Union Find Graph connectivity, components, cycle detection Custom DSU class with find() and union()

🧮 Useful STL Containers

Container Syntax Example
vector vector<int> v; v.push_back(1);
unordered_map unordered_map<int, int> mp; mp[key] = value;
unordered_set unordered_set<int> st; st.insert(x);
stack stack<int> s; s.push(x); s.top(); s.pop();
queue queue<int> q; q.push(x); q.front(); q.pop();
priority_queue (max heap) priority_queue<int> pq;
priority_queue (min heap) priority_queue<int, vector<int>, greater<int>> pq;

🧩 Problem Pattern Shortcuts

Problem Type C++ Trick
Two Sum Use unordered_map<int, int> to store index
Longest Unique Substring unordered_set<char> + two pointers
Valid Parentheses stack<char>
Binary Tree Traversal Recursive DFS or queue<TreeNode*> for BFS
Detect Graph Cycle DFS + visited or DSU with path compression
Kth Largest Element priority_queue<int, vector<int>, greater<int>> of size k
Merge Intervals sort(intervals.begin(), intervals.end()), then merge
Subsets / Permutations vector<int> path, backtracking with recursion

Time & Space Complexities

Operation Time Complexity
Access in vector O(1)
Insert in unordered_map O(1) avg
Insert in set O(log n)
sort() O(n log n)
Binary Search O(log n)
Heap insert/pop O(log n)
Graph BFS/DFS O(V + E)

🔧 Template Snippets (C++)

🔁 Sliding Window

int left = 0;
for (int right = 0; right < s.size(); ++right) {
    while (window_invalid_condition) {
        // shrink window
        left++;
    }
    // process window
}

🧭 DFS (recursive)

void dfs(TreeNode* root) {
    if (!root) return;
    dfs(root->left);
    dfs(root->right);
}

🔄 BFS

queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
    TreeNode* node = q.front(); q.pop();
    if (node->left) q.push(node->left);
    if (node->right) q.push(node->right);
}

🔁 Backtracking

void backtrack(vector<int>& path) {
    if (done_condition) {
        res.push_back(path);
        return;
    }
    for (int i = 0; i < choices.size(); ++i) {
        path.push_back(choices[i]);
        backtrack(path);
        path.pop_back();
    }
}

🧠 DP

vector<vector<int>> dp(n, vector<int>(m, 0));
// dp[i][j] = ...

🔗 Union Find

class DSU {
public:
    vector<int> parent;
    DSU(int n) { parent.resize(n); iota(parent.begin(), parent.end(), 0); }

    int find(int x) {
        if (parent[x] != x) parent[x] = find(parent[x]);
        return parent[x];
    }

    void unite(int x, int y) {
        parent[find(x)] = find(y);
    }
};

🔄 Common Patterns to Practice (C++ Versions)

Pattern Example Problem
Two Pointers LeetCode 167. Two Sum II
Sliding Window LeetCode 3. Longest Substring Without Repeating
Stack LeetCode 20. Valid Parentheses
Hash Map LeetCode 1. Two Sum, LeetCode 347. Top K Frequent Elements
BFS/DFS LeetCode 102. Binary Tree Level Order, LeetCode 200. Number of Islands
Backtracking LeetCode 46. Permutations, LeetCode 78. Subsets
DP LeetCode 198. House Robber, LeetCode 70. Climbing Stairs
Heap LeetCode 215. Kth Largest Element
Binary Search LeetCode 33. Search in Rotated Sorted Array

Thursday, February 12, 2026

Spring Boot: Security & Reliability

Spring Boot – Security & Reliability

1️⃣ JWT Authentication Flow

JWT (JSON Web Token) is a stateless authentication mechanism.

🔄 Flow

  1. Client sends login request (username + password)

  2. Spring Security authenticates user

  3. Server generates a JWT

  4. Client stores JWT (usually in memory or HttpOnly cookie)

  5. Client sends JWT in every request header:

    Authorization: Bearer <token>
    
  6. Server validates the token before processing request


🧱 Implementation Structure

  • SecurityConfig

  • JwtUtil

  • JwtFilter

  • UserDetailsService

  • Authentication Controller


🔹 Example: Security Configuration (Spring Boot 3)

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .csrf(csrf -> csrf.disable())
        .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS))
        .authorizeHttpRequests(auth -> auth
                .requestMatchers("/auth/**").permitAll()
                .anyRequest().authenticated()
        );

    return http.build();
}

🔹 JWT Structure

JWT contains:

  • Header

  • Payload (username, roles, expiry)

  • Signature


⚠️ Best Practices

  • Keep token expiry short (15–60 min)

  • Use refresh tokens

  • Store secret securely (not hardcoded)

  • Always validate expiration


2️⃣ Role-Based Authorization

Authentication = Who are you?
Authorization = What can you do?


🔹 Define Roles

public enum Role {
    ROLE_USER,
    ROLE_ADMIN
}

🔹 Secure Endpoints

@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/admin/data")
public String adminOnly() {
    return "Admin data";
}

🔹 Enable Method Security

@EnableMethodSecurity

🔐 Example Access Rules

.authorizeHttpRequests(auth -> auth
    .requestMatchers("/admin/**").hasRole("ADMIN")
    .requestMatchers("/user/**").hasAnyRole("USER", "ADMIN")
    .anyRequest().authenticated()
)

⚠️ Common Mistakes

❌ Forgetting ROLE_ prefix
❌ Not enabling method security
❌ Storing roles as plain strings without validation


3️⃣ Securing Endpoints Properly

🔹 Public vs Protected

Endpoint TypeExample
Public/auth/login
Protected/orders
Admin Only/admin/users

🔹 Additional Protections

  • Enable HTTPS (production mandatory)

  • Disable CSRF only for stateless APIs

  • Use CORS configuration carefully

  • Validate input (@Valid)


🔹 Global Exception Handling

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleException(Exception ex) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body("Something went wrong");
    }
}

Prevents leaking internal stack traces.


4️⃣ Idempotent APIs (Prevent Data Corruption)

Idempotent = Multiple identical requests → same result.


🔹 Safe Methods (HTTP Standard)

MethodIdempotent?
GET✅ Yes
PUT✅ Yes
DELETE✅ Yes
POST❌ No (usually)

🔹 Example Problem

User clicks “Pay” button 3 times → 3 payments processed ❌


🔹 Solution 1: Idempotency Key

Client sends unique key:

Idempotency-Key: 12345-abc

Server:

  • Store key in DB

  • If same key comes again → return previous response


🔹 Solution 2: Database Constraints

Use:

  • Unique constraints

  • Optimistic locking (@Version)

  • Transactions


🔹 Optimistic Lock Example

@Version
private Long version;

Prevents lost updates.


🔹 Transaction Best Practice

@Transactional
public void transferMoney(...) {
    ...
}

Ensures atomicity.


🔥 Security & Reliability Checklist

Stateless authentication (JWT)
✅ Role-based access control
✅ Proper endpoint restrictions
✅ Input validation
✅ Global exception handling
✅ Idempotent critical operations
✅ Use transactions
✅ DB constraints


🚨 Real-World Failures You Avoid

  • Unauthorized data access

  • Privilege escalation

  • Duplicate payments

  • Lost updates

  • Data corruption

  • Session hijacking


 ADVANCED SECURITY (Beyond Basic JWT)

1️⃣ Refresh Token Strategy (Very Important)

Access Token → short life (15–30 mins)
Refresh Token → long life (7–30 days)

Why?

  • Limits damage if token is stolen

  • Better UX

Two approaches:

  • Store refresh token in DB

  • Store in Redis

  • Rotate refresh tokens (more secure)


2️⃣ Password Security

Never store ra

w passwords.

Use:

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

BCrypt:

  • Automatically salts

  • Slow hashing (prevents brute force)


3️⃣ Rate Limiting (Prevent Brute Force / DDoS)

Protect:

  • /login

  • /register

  • /payment

Tools:

  • Bucket4j

  • Redis rate limiting

  • API Gateway throttling


4️⃣ CORS Proper Configuration

Bad CORS = anyone can call your API.

Example:

@Bean
public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurer() {
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**")
                    .allowedOrigins("https://yourfrontend.com")
                    .allowedMethods("GET", "POST", "PUT", "DELETE");
        }
    };
}

5️⃣ CSRF (When Needed)

  • Disable only for stateless APIs

  • Enable for session-based apps


6️⃣ Security Headers

Add:

  • HSTS

  • X-Content-Type-Options

  • X-Frame-Options

  • Content-Security-Policy

Spring Security handles many automatically.


🛡 RELIABILITY – More Than Idempotency

7️⃣ Circuit Breaker (Microservices)

If another service fails → prevent cascading failure.

Use:

  • Resilience4j

Prevents:

  • System-wide crash


8️⃣ Retry Mechanism

For temporary DB/network failures:

@Retryable(maxAttempts = 3)

9️⃣ Timeout Configuration

Never allow infinite waits.

Configure:

  • DB connection pool timeout

  • HTTP client timeout


🔟 Logging & Monitoring

You need:

  • Structured logging

  • Log levels

  • Correlation IDs

  • Metrics (Micrometer)

  • Health checks (/actuator/health)


1️⃣1️⃣ Audit Logging

Track:

  • Who changed data

  • When

  • What changed

Very important for financial systems.


1️⃣2️⃣ Database-Level Safety

  • Unique constraints

  • Foreign keys

  • Indexing

  • Proper isolation level

  • Avoid long transactions


🎯 Senior-Level Additions

  • OAuth2

  • OpenID Connect

  • API Gateway security

  • Token blacklisting (logout support)

  • Multi-factor authentication

  • Encryption of sensitive fields

  • Secure secrets management (Vault)


 

Thursday, February 5, 2026

Transactions & Performance (Spring Boot)

✅ Transactions & Performance — GOOD vs BAD Practices (with Examples)


1️⃣ Where to Put @Transactional

❌ BAD PRACTICE – Transaction in Controller

@RestController
public class OrderController {

    @Transactional
    @PostMapping("/order")
    public void placeOrder() {
        orderService.placeOrder();
    }
}

🚨 Why bad:

  • Controller shouldn’t manage transactions

  • Harder to test

  • Breaks separation of concerns


✅ GOOD PRACTICE – Transaction in Service

@Service
public class OrderService {

    @Transactional
    public void placeOrder() {
        orderRepo.save(order);
        stockRepo.updateStock();
    }
}

✔ Clean architecture
✔ Easier to manage & test


2️⃣ Transaction Scope (Length)

BAD – Long Transaction

@Transactional
public void processOrder() {
    callPaymentGateway();   // slow
    generateInvoicePdf();   // CPU heavy
    sendEmail();            // external I/O
    orderRepo.save(order);
}

🚨 Problems:

  • DB locks held too long

  • Poor throughput

  • Risk of deadlocks

  • Slow system under load


✅ GOOD – Short Transaction

public void processOrder() {
    callPaymentGateway();
    generateInvoicePdf();
    saveOrder();
}

@Transactional
void saveOrder() {
    orderRepo.save(order);
}

✔ Transaction only around DB work
✔ Better performance
✔ Scales well


3️⃣ Read APIs and Transactions

❌ BAD – No Read-Only Flag

@Transactional
public List<User> getUsers() {
    return userRepo.findAll();
}

🚨 Issues:

  • Unnecessary dirty checking

  • More memory usage


✅ GOOD – Read-Only Transaction

@Transactional(readOnly = true)
public List<User> getUsers() {
    return userRepo.findAll();
}

✔ Faster
✔ Optimized by Hibernate & DB


4️⃣ Exception Handling & Rollback

❌ BAD – Checked Exception Doesn’t Rollback

@Transactional
public void saveData() throws Exception {
    repo.save(entity);
    throw new Exception("Error"); // NO rollback!
}

🚨 Data gets committed unexpectedly.


✅ GOOD – Explicit Rollback Rule

@Transactional(rollbackFor = Exception.class)
public void saveData() throws Exception {
    repo.save(entity);
    throw new Exception("Error");
}

✔ Correct rollback behavior


5️⃣ Calling External Services in Transaction

❌ BAD

@Transactional
public void createUser() {
    userRepo.save(user);
    emailService.sendWelcomeMail(); // external call
}

🚨 Email failure can rollback DB
🚨 DB transaction waits on email server


✅ GOOD

@Transactional
public void createUser() {
    userRepo.save(user);
}

public void postCreateUser() {
    emailService.sendWelcomeMail();
}

✔ DB work isolated
✔ External failure doesn’t corrupt data


6️⃣ N+1 Query Problem

❌ BAD – N+1 Queries

List<Order> orders = orderRepo.findAll();

for (Order order : orders) {
    order.getItems().size(); // each call hits DB
}

🚨 1 + N queries → very slow


✅ GOOD – JOIN FETCH

@Query("SELECT o FROM Order o JOIN FETCH o.items")
List<Order> findAllWithItems();

✔ Single query
✔ Massive performance improvement


7️⃣ Pagination

❌ BAD – Load Everything

List<User> users = userRepo.findAll();

🚨 Memory heavy
🚨 Slow for large tables


GOOD – Pagination

Page<User> users = userRepo.findAll(PageRequest.of(0, 20));

✔ Faster
✔ Scalable


8️⃣ Transaction Propagation Misuse

❌ BAD – Everything in One Transaction

@Transactional
public void process() {
    saveMainData();
    saveAuditLog(); // should not rollback
}

🚨 Audit log lost if main tx fails


✅ GOOD – REQUIRES_NEW for Audit

@Transactional
public void process() {
    saveMainData();
    auditService.saveLog();
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveLog() {
    auditRepo.save(log);
}

✔ Audit always saved
✔ Proper transaction boundaries


9️⃣ Overusing @Transactional

❌ BAD

@Transactional
public void calculate() {
    int x = a + b;
}

🚨 No DB → unnecessary overhead


✅ GOOD

public void calculate() {
    int x = a + b;
}

✔ Simple
✔ Clean


🔟 Fetch Strategy

❌ BAD – EAGER Loading

@OneToMany(fetch = FetchType.EAGER)
private List<Item> items;

🚨 Heavy queries
🚨 Hidden performance issues


✅ GOOD – LAZY + Fetch When Needed

@OneToMany(fetch = FetchType.LAZY)
private List<Item> items;

✔ Controlled loading
✔ Better performance


🧠 Senior Dev Summary (Memorable)

❝ Transactions protect data, but bad transactions kill performance ❞

Always remember:

  • Keep transactions short

  • DB work only

  • Read-only where possible

  • Avoid external calls

  • Watch N+1 queries


prevent hidden performance bugs and transactional issues before production.


1. @Transactional Pitfalls

Common Issues

  • Self-invocation

    • @Transactional methods called within the same class do not start a transaction.

    • Reason: Spring uses proxies.

  • Wrong layer

    • @Transactional on controllers → ❌

    • Correct place: Service layer

  • Exception handling

    • Rollback happens only for unchecked exceptions by default.

    • Catching exceptions without rethrowing → transaction commits.

  • Long transactions

    • Mixing DB logic with external API calls causes locks and timeouts.

Best Practices

  • Keep transactions short

  • One business use-case per transaction

  • Use rollbackFor when needed

  • Use REQUIRES_NEW only when truly required


2. Lazy vs Eager Loading

Default Behavior

  • @ManyToOne → EAGER

  • @OneToMany / @ManyToMany → LAZY

Common Problems

  • LazyInitializationException

  • Over-fetching with EAGER relationships

Correct Solutions

  • DTO projections (preferred)

  • JPQL fetch joins

  • EntityGraph for controlled loading

Anti-Patterns

  • Setting everything to FetchType.EAGER

  • Returning entities directly from controllers


3. Pagination & Filtering

Why It Matters

  • Prevents memory issues

  • Improves query performance

  • Protects APIs from abuse

Best Practices

  • Always use Pageable for list endpoints

  • Apply filtering at the database level

  • Index frequently filtered and sorted columns

Rules

  • Never return unbounded lists

  • Paginate before mapping to DTOs

  • Avoid in-memory filtering


4. N+1 Query Problem

What It Is

  • One query to fetch parent entities

  • N additional queries for related entities

How It Happens

  • Accessing lazy relationships in loops

  • Returning entities instead of DTOs

Detection

  • SQL logs

  • Hibernate statistics

  • Repeating queries with different IDs

Fixes

  • Fetch joins

  • DTO queries

  • Batch fetching

  • Entity graphs


5. Performance Awareness (Lead Expectations)

Red Flags in PRs

  • findAll() without pagination

  • Lazy collections accessed in loops

  • EAGER relationships on large entities

  • Business logic inside transactions

  • Controllers returning entities

Lead Rule

Every DB call must be intentional, bounded, and observable.


6️⃣ Transaction Isolation & Locking

Why it matters

Race conditions, double payments, dirty reads.

You should know

  • READ_COMMITTED (default in most DBs)

  • REPEATABLE_READ

  • SERIALIZABLE

Practical tools

  • Optimistic locking

@Version
private Long version;
  • Pessimistic locking

@Lock(LockModeType.PESSIMISTIC_WRITE)

Lead rule

If money or inventory is involved, locking must be explicit.


7️⃣ Flush vs Commit (Hibernate trap)

  • save() ≠ SQL execution

  • SQL runs on flush, not commit

repo.save(x);
repo.flush(); // forces SQL

Why this matters:

  • Constraint violations appear late

  • Bugs surface only at commit time


8️⃣ Read-only Transactions

@Transactional(readOnly = true)

Benefits:

  • Prevents accidental writes

  • Optimizes Hibernate dirty checking

Lead expectation:

  • All pure read service methods are read-only


9️⃣ Batch Operations & JDBC Performance

Problem

save() in loop → 1000 INSERTs

Solutions

  • Hibernate batch size

hibernate.jdbc.batch_size=50
  • saveAll()

  • Periodic flush() + clear()


🔟 Connection Pool Awareness (HikariCP)

You should understand:

  • Max pool size

  • Connection leaks

  • Long-running transactions blocking pool

Red flag:

App is “slow” but DB CPU is idle


1️⃣1️⃣ Index Awareness (Performance ≠ Code Only)

  • Index FK columns

  • Index columns used in:

    • WHERE

    • ORDER BY

    • JOIN

Lead rule:

Pagination without indexes is fake performance.


1️⃣2️⃣ Observability Basics

You should be able to:

  • Enable SQL logging temporarily

  • Spot N+1 in logs

  • Measure query time

  • Correlate API latency ↔ DB calls



Sunday, February 1, 2026

Spring Boot API Design & Architecture

 

 API Design & Architecture

Outcome: design clean, predictable, boring-in-a-good-way APIs


1️⃣ Controller–Service–Repository Separation

Controller (HTTP layer)

Responsibilities

  • Request/response mapping

  • Validation trigger

  • HTTP status codes

Rules

  • No business logic

  • No try/catch

  • No repository access

@PostMapping("/orders")
@ResponseStatus(HttpStatus.CREATED)
public OrderResponse create(@Valid @RequestBody CreateOrderRequest req) {
    return orderService.create(req);
}

Service (Business layer)

Responsibilities

  • Business rules

  • Transactions

  • Orchestration

Rules

  • No HTTP concepts

  • Throws domain exceptions

@Transactional
public OrderResponse create(CreateOrderRequest req) {
    if (!productExists(req.productId())) {
        throw new ResourceNotFoundException("Product not found");
    }
    return mapper.toResponse(orderRepo.save(mapper.toEntity(req)));
}

Repository (Data layer)

Responsibilities

  • DB access only

Rules

  • No business logic

  • No DTOs

Optional<Order> findById(Long id);

📌 Lead rule:

If it depends on HTTP → Controller
If it depends on DB → Repository
Everything else → Service


2️⃣ DTO vs Entity (Strict boundary)

Never expose Entities

Reasons:

  • DB coupling

  • Lazy loading issues

  • Security leaks

  • Versioning pain

✅ Use DTOs

Request DTO

record CreateOrderRequest(
    @NotNull Long productId,
    @Min(1) int quantity
) {}

Response DTO

record OrderResponse(
    Long id,
    int quantity,
    BigDecimal total
) {}

📌 Lead rule:

Entities never cross the service boundary


3️⃣ HTTP Status Codes (Intentional, not random)

CaseStatus
Create201 CREATED
Read / Update200 OK
Delete204 NO CONTENT
Validation error400 BAD REQUEST
Not found404 NOT FOUND
Duplicate409 CONFLICT
Auth required401
Forbidden403
Server error500

📌 Lead rule:

Status code tells the story before the body


4️⃣ Error Model (Single, consistent shape)

✅ Standard error response

{
  "timestamp": "2026-02-02T10:15:30",
  "status": 400,
  "error": "VALIDATION_ERROR",
  "message": "Invalid request",
  "path": "/orders",
  "details": {
    "quantity": "must be greater than 0"
  }
}

📌 Lead rule:

Errors are for machines first, humans second


5️⃣ Global Exception Handling

✅ Centralized handling

@RestControllerAdvice
public class GlobalExceptionHandler {

  @ExceptionHandler(MethodArgumentNotValidException.class)
  public ResponseEntity<ApiError> validation(...) {}

  @ExceptionHandler(ResourceNotFoundException.class)
  public ResponseEntity<ApiError> notFound(...) {}

  @ExceptionHandler(Exception.class)
  public ResponseEntity<ApiError> fallback(...) {}
}

Rules

  • No try/catch in controllers

  • Domain exceptions map to HTTP here

📌 Lead rule:

Controllers must be tiny and boring


6️⃣ Validation (Fail fast)

Bean Validation

@NotBlank
@Email
private String email;

Rules

  • Validation at DTO level

  • Service assumes valid input

  • Custom validators only when needed

📌 Lead rule:

Invalid data never reaches business logic


7️⃣ PR Review Checklist (Week 1)

Reject if you see

  • Entity in controller response

  • try/catch in controller

  • 200 for every response

  • Validation inside service

  • Repository logic in controller

Approve when

  • Thin controllers

  • Clear DTOs

  • Centralized errors

  • Correct status codes

  • Consistent error model


 Spring Boot API Design & Architecture

1️⃣ Package Structure (Feature-based, not layer-dump)

❌ Bad (layer-based)

controller/
service/
repository/
dto/

Good (feature-based)

user/
 ├─ UserController
 ├─ UserService
 ├─ UserRepository
 ├─ dto/
 │   ├─ CreateUserRequest
 │   ├─ UserResponse
 └─ exception/
     └─ UserNotFoundException

📌 Lead rule:

Features scale, layers rot.


2️⃣ Controller–Service–Repository (Spring way)

Controller

@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
public class UserController {

  private final UserService service;

  @PostMapping
  @ResponseStatus(HttpStatus.CREATED)
  public UserResponse create(@Valid @RequestBody CreateUserRequest req) {
    return service.create(req);
  }
}

Rules

  • @Valid only here

  • No try/catch

  • No entities


Service

@Service
@RequiredArgsConstructor
@Transactional
public class UserService {

  private final UserRepository repo;

  public UserResponse create(CreateUserRequest req) {
    if (repo.existsByEmail(req.email())) {
      throw new DuplicateResourceException("Email exists");
    }
    return UserMapper.toResponse(repo.save(UserMapper.toEntity(req)));
  }
}

Repository

public interface UserRepository extends JpaRepository<User, Long> {
  boolean existsByEmail(String email);
}

3️⃣ DTO vs Entity (Spring JPA safe)

❌ Entity

@Entity
class User {
  @Id @GeneratedValue
  Long id;
}

🚫 Never return this

DTO

public record UserResponse(
  Long id,
  String name,
  String email
) {}

📌 Rule:

Entity never leaves service layer.


4️⃣ Validation (Hibernate Validator)

public record CreateUserRequest(
  @NotBlank String name,
  @Email String email,
  @Size(min = 8) String password
) {}
  • Runs before the controller method

  • Fails fast with 400


5️⃣ Global Exception Handling (@RestControllerAdvice)

@RestControllerAdvice
public class GlobalExceptionHandler {

  @ExceptionHandler(MethodArgumentNotValidException.class)
  ResponseEntity<ApiError> handleValidation(MethodArgumentNotValidException ex) {
    return ResponseEntity.badRequest().body(ApiError.from(ex));
  }

  @ExceptionHandler(EntityNotFoundException.class)
  ResponseEntity<ApiError> handleNotFound(EntityNotFoundException ex) {
    return ResponseEntity.status(404).body(ApiError.notFound(ex));
  }
}

6️⃣ Standard Error Model

public record ApiError(
  Instant timestamp,
  int status,
  String error,
  String message,
  String path,
  Map<String, String> details
) {}

📌 Rule:

One error shape for the entire API.


7️⃣ HTTP Status Codes (Spring defaults)

CaseSpring
Create@ResponseStatus(CREATED)
Delete@ResponseStatus(NO_CONTENT)
ValidationMethodArgumentNotValidException
Not foundEntityNotFoundException
ConflictResponseStatusException(409)

8️⃣ Pagination (Spring Data)

@GetMapping
public Page<UserResponse> list(Pageable pageable) {
  return service.list(pageable);
}

Frontend-friendly, zero effort.


9️⃣ API Versioning

@RequestMapping("/api/v1/users")

📌 Never skip this.


🔟 Logging & Correlation ID (Must-have)

@Component
public class CorrelationIdFilter extends OncePerRequestFilter {
  protected void doFilterInternal(...) {
    MDC.put("correlationId", UUID.randomUUID().toString());
    filterChain.doFilter(req, res);
    MDC.clear();
  }
}

1️⃣1️⃣ Time & Serialization

spring:
  jackson:
    time-zone: UTC
    serialization:
      write-dates-as-timestamps: false

Always ISO-8601.


1️⃣2️⃣ OpenAPI / Swagger

springdoc-openapi-starter-webmvc-ui

Auto-docs your DTOs + validation.

📌 Rule:

Swagger is part of the API, not optional.


1️⃣3️⃣ Tests (Week-1 scope)

  • @WebMvcTest → controller

  • Plain JUnit → service

  • No DB in unit tests


 

Tuesday, January 13, 2026

Angular Project Structure & Code Reviews

1️⃣ Feature-based Folder Structure (Non-Negotiable)

❌ Red flag (junior mindset)

/components
/services
/models
/utils

➡️ Files are grouped by type, not by business meaning.

✅ Lead-approved structure

/features
  /orders
    orders.routes.ts
    orders.component.ts
    orders.service.ts
    orders.store.ts
    orders.model.ts
  /payments
    ...

🔍 PR review checklist

  • Can I delete a feature folder without breaking others?

  • Does this feature own its UI + logic + state?

  • ❌ Reject PRs adding files to generic /shared/services by default

📌 Rule: Features should be isolated, portable, and cohesive.


2️⃣ Shared vs Core — Most PRs Get This Wrong

🧠 Core Module (App-wide, once)

What belongs here

  • Auth service

  • HTTP interceptors

  • Global error handler

  • App configuration

  • Logging

/core
  auth.service.ts
  error-handler.ts
  http.interceptor.ts

🚨 PR Red Flags

  • CoreModule imported into a lazy module ❌

  • Stateful services inside SharedModule


🧠 Shared Module (Stateless & reusable)

What belongs here

  • UI components (buttons, modals)

  • Pipes

  • Directives

/shared
  /ui
    button.component.ts
  /pipes

📌 Rule:

Shared = reusable & stateless
Core = singleton & global


3️⃣ Lazy Loading — Architectural Decision, Not Performance Hype



Lazy Loading in Angular — what it REALLY means

Lazy loading in Angular is NOT a performance trick.

It is an architectural decision about feature isolation.

Performance improvement is just a side-effect.


❌ Wrong Angular thinking (very common in PRs)

“I lazy-loaded this module because performance”

🚫 This tells a reviewer:

  • You don’t understand why this module exists

  • You’re cargo-culting Angular features


✅ Correct Angular thinking

“This feature is isolated, optional at startup, and has its own navigation boundary — therefore it is lazy-loaded.”


What lazy loading ACTUALLY does in Angular

When you lazy load:

{
  path: 'admin',
  loadChildren: () =>
    import('./admin/admin.routes').then(m => m.ADMIN_ROUTES)
}

Angular:

  • ❌ Does not load admin components

  • ❌ Does not register admin routes

  • ❌ Does not create admin injectors

until the user navigates to /admin

👉 This is isolation, not speed.


When should a feature be lazy loaded? (Angular rules)

1️⃣ Feature is NOT part of the initial route

Ask:

Can the user complete their main task without this feature?

If yes → lazy load

Examples:

  • Reports

  • Settings

  • Admin

  • History

  • Analytics

❌ Dashboard, Login, Shell → usually eager


2️⃣ Feature has its OWN routing

If a feature has:

/admin
/admin/users
/admin/roles

That’s a routing boundary → perfect for lazy loading.

If it doesn’t have its own routes → don’t force lazy loading.


3️⃣ Feature has its OWN state

If the feature owns:

  • Facade

  • Effects

  • Signals store

  • API calls

Lazy loading means:

  • State is created when entering

  • State is destroyed when leaving

This is CLEAN.

❌ Eager loading keeps dead state forever.


4️⃣ Feature is role-based

Angular guard example:

{
  path: 'admin',
  canMatch: [adminGuard],
  loadChildren: () => import('./admin/admin.routes')
}

👉 Angular won’t even download the admin bundle if the role fails.

This is security + architecture, not performance.


PR Review Questions — what a lead REALLY checks

❓ Is this reachable from the initial route?

If yes:

  • Why is it lazy?

  • Are we delaying critical UX?


❓ Does lazy loading simplify or complicate state?

Good lazy loading:

  • Feature-local services

  • No cross-feature injections

Bad lazy loading:

  • Shared services hacked through CoreModule

  • Tight coupling


❓ Is preloading used correctly?

Bad:

PreloadAllModules

Good:

data: { preload: true }

👉 Only preload what is important but not initial.


The golden Angular rule (remember this)

Lazy loading is about isolation first, performance second.

If a feature:

  • Can stand alone

  • Has its own routes

  • Has its own state

  • Is not needed at startup

➡️ Lazy load it.


One-line test (lead-level)

“If I delete this feature folder, will the rest of the app still make sense?”

If yes → lazy load
If no → eager load


Bad PR justification

“I lazy-loaded it because performance”

✅ Lead thinking

Lazy load when:

  • Feature is not needed on app start

  • Feature is large

  • Feature is role-based

  • Feature has independent navigation

🔍 PR review questions

  • Is this feature reachable from the initial route?

  • Does lazy loading simplify or complicate state sharing?

  • Is preloading strategy used correctly?

📌 Rule: Lazy loading is about isolation first, performance second.


4️⃣ Global Error Handling (No try/catch soup)

❌ Red flags in PR

  • catchError everywhere

  • console.log(error)

  • Silent failures

Lead-approved pattern

  • Centralized error handling

  • User-friendly messages

  • Logged + observable-safe

@Injectable()
export class GlobalErrorHandler implements ErrorHandler {
  handleError(error: unknown) {
    // log
    // notify user
    // fail gracefully
  }
}

🔍 Review checklist

  • Are HTTP errors normalized?

  • Are UI errors surfaced properly?

  • Is business logic polluted with error UI logic?

📌 Rule: Errors are architecture, not implementation details.


5️⃣ Reviewing PRs for Design (This is where leads shine)

🧠 Don’t ask:

  • “Why didn’t you use map?”

  • “Why not signals instead of RxJS?”

🧠 DO ask:

  • ❓ Is responsibility clear?

  • ❓ Is state leaking across layers?

  • ❓ Can this scale to 10x complexity?

  • ❓ Is this testable without the UI?

  • ❓ Does this follow existing patterns?


6️⃣ PR Review Mental Model (Lead Lens)

AreaLead Focus
Components     Dumb UI vs Smart containers
Services     Single responsibility
State     Ownership & lifecycle
Modules     Boundaries respected
Imports     Directional (no cycles)
Naming     Business-driven

📌 Golden Rule:

If a new dev joins, can they understand this feature in 15 minutes?


7️⃣ Common PR Comments You Should Start Writing

  • “This logic belongs to the feature, not shared.”

  • “This component is doing too much — consider a container.”

  • “Why is this service global?”

  • “This breaks lazy-loading isolation.”

  • “What owns this state?”

👆 These comments signal senior/lead thinking.


8️⃣ Graduation Test (Self-check)

  • Reject a PR even if it “works”

  • Explain why structure matters

  • Protect boundaries without being dogmatic

  • Optimize for future developers, not today’s speed

 Below are more lead-level PR review tips that most coders never learn 👇


9️⃣ Watch for Hidden Coupling (Silent Architecture Killers)

❌ PR smell

this.router.navigate(['/orders', order.id]);
this.sharedService.selectedOrder = order;

➡️ Feature A silently depends on Feature B’s internal behavior.

✅ Lead thinking

  • State must be explicit

  • Navigation should not carry hidden context

  • Use route params / resolvers / facades

🔍 PR question

“If I remove Feature B, will Feature A still compile?”

📌 Coupling doesn’t show in tests — it shows in production.


🔟 Kill “Convenience Services”

❌ Red flag names

  • UtilsService

  • CommonService

  • HelperService

  • SharedDataService

🧠Rule

If a service has no clear business name, it’s a design failure.

Replace with

  • OrderPricingService

  • PaymentAuthorizationFacade

  • UserSessionStore

🔍 PR comment

“What business capability does this service represent?”


1️⃣1️⃣ Guard Against Smart Components Drift

❌ PR pattern

ngOnInit() {
  this.route.params.subscribe(...)
  this.service.getData().subscribe(...)
  this.store.update(...)
}

➡️ Component becoming a mini-controller.

✅ Lead correction

  • Move orchestration to:

    • Facade

    • Store

    • Container component

📌 Rule

Components render state, not decide state.


1️⃣2️⃣ Naming Is Architecture (Not Cosmetics)

❌ Red flag

handleData()
processStuff()
doAction()

✅ Lead-approved

loadOrders()
submitPayment()
confirmDelivery()

🔍 PR check

  • Method names must reflect business verbs

  • Avoid technical verbs (handle, process, manage)

📌 If naming is vague, design is vague.


1️⃣3️⃣ Lifecycle Ownership Review

❌ PR smell

ngOnInit() {
  this.interval = setInterval(...)
}

No cleanup.

🧠 Lead questions

  • Who owns this subscription?

  • When should it stop?

  • What happens on navigation?

✅ Expect

  • takeUntilDestroyed

  • Signals auto cleanup

  • Store-driven lifecycles

📌 Memory leaks are leadership failures.


1️⃣4️⃣ Watch for State Duplication

PR smell State calculated in multiple places.

this.items$ = this.store.items$;
this.total = this.items.reduce((a, b) => a + b.price, 0);

❌Derived state lives next to source

@Component(...)
export class CartComponent {
  items$ = this.store.items$;
  total$ = this.items$.pipe(
    map(items => items.reduce((a, b) => a + b.price, 0))
  );
}

Why wrong:

  • Component now owns business logic

  • Logic is duplicated if reused

  • Hard to test

🧠 Lead response

“Where is the single source of truth?”

Correct place: Store / Facade 

@Injectable()

export class CartStore {

  private itemsSubject = new BehaviorSubject<Item[]>([]);

  items$ = this.itemsSubject.asObservable();


  total$ = this.items$.pipe(

    map(items => items.reduce((a, b) => a + b.price, 0))

  );

}

Now:

  • items = source

  • total = derived next to it

  • Components stay dumb

✅ Same rule with Angular Signals

@Injectable()
export class CartStore {
  readonly items = signal<Item[]>([]);

  readonly total = computed(() =>
    this.items().reduce((a, b) => a + b.price, 0)
  );
}

✅ Rule

  • Derived state lives next to source

  • Never recalc in components

  • If state is derived in more than one place, your design is already broken.

📌 Duplicated state = guaranteed bugs.


1️⃣5️⃣ Review Imports Like a Hawk 🦅

Red flags

../../../../shared/utils

➡️ Module boundary violation.

Why ../../../../ is a problem (not aesthetics)

This is not about ugly paths.

It means:

  • The file escaped its own module

  • Reached into another layer

  • Bypassed the architecture

That’s a directional dependency violation.

🧠 Lead rule

  • Imports must flow downward

App
 ├─ Core
 ├─ Shared
 └─ Features
      ├─ Orders
      ├─ Payments
      └─ Reports

  • Features don’t import from other features

Allowed imports ✅

  • Feature → Shared

  • Feature → Core

  • App → everything below

Forbidden imports ❌

  • Feature → Feature

  • Shared → Feature

  • Core → Feature

🔍 PR rejection reason

“This breaks directional dependency.”

 Golden rule (memorize this)

If you need ../../../../, you are in the wrong layer. 


1️⃣6️⃣ Async Code Smell Radar

❌ PR smell

subscribe(() => {
  subscribe(() => {
    subscribe(() => {})
  })
})

🧠 Lead response

  • Flatten streams

  • One subscription per component

  • Prefer effects / stores

📌 Nested subscriptions = junior panic coding.


1️⃣7️⃣ Flags, Booleans & Explosion Risk

❌ PR smell

isLoading
isSaving
isEditing
isUpdating

🧠 Lead solution

Replace booleans with:

state: 'idle' | 'loading' | 'saving' | 'error'

📌 Boolean hell grows exponentially.


1️⃣8️⃣ Review Tests for Meaning, Not Coverage

Useless test

it('should create component')

🧠 Lead expectation

  • Tests describe business behavior

  • Test state transitions

  • Test edge cases

🔍 PR comment

“What behavior would break if this test fails?”


1️⃣9️⃣ Beware of “Just One More Input()”

PR smell

Component with 8+ @Input()s

@Component({...})

export class OrderCardComponent {

  @Input() order!: Order;

  @Input() isSelected = false;

  @Input() showActions = true;

  @Input() canEdit = false;

  @Input() canCancel = false;

  @Input() highlight = false;

  @Input() currency!: string;

  @Input() locale!: string;

}

🧠 Lead insight

  • Too many inputs = leaky abstraction

  • Signals broken responsibility

Fix

  • Pass a ViewModel

@Input() vm!: OrderCardVM;

export interface OrderCardVM {

  order: Order;

  isSelected: boolean;

  canEdit: boolean;

  canCancel: boolean;

  currency: string;

  locale: string;

}

  • Or split component

  • ask:

    • ❓ Can this component be rendered with a single object?

    • ❓ Are these inputs flags or real data?

    • ❓ Do multiple parents need different combinations?

    • ❓ Is this UI or business logic leaking?

    • ❓ Would removing one input break unrelated behavior?

📌 If a component needs too much context, it’s too big.


2️⃣0️⃣ Watch How Errors Are Named

PR smell

throw new Error('Something went wrong');

Why this is bad:

  • ❌ No meaning

  • ❌ Cannot be handled differently

  • ❌ UI can only show a generic message

  • ❌ Breaks refactoring safety

  • ❌ Error string becomes a hidden contract


PR review checklist

ask:

  • ❓ Is this error meaningful to the domain?

  • ❓ Can UI react differently to each error?

  • ❓ Is the error name stable over time?

  • ❓ Does this leak backend / HTTP details?

  • ❓ Is this string-based logic hiding a contract?

🧠 Lead expectation

  • Domain-specific errors

  • Typed error handling

throw new PaymentDeclinedError();

📌 Errors are part of your API.


🧠 PR Review Checklist 

Before approving:

  • Does this change add a new pattern?

  • Does it respect existing architecture?

  • Will this age well in 1 year?

  • Is the complexity proportional?

  • Could a junior maintain this safely?



  • =Review a real Angular route config

  • Show good vs bad lazy loading PR examples

  • Explain lazy loading + signals + facades

  • Explain why some features should NEVER be lazy

Wednesday, January 7, 2026

Angular Performance & Forms

 


Performance & Forms


1️⃣ Change Detection Basics (What ACTUALLY happens)

Angular checks bindings → template expressions → pipes → functions
This happens when:

  • Any event (click, input)

  • setTimeout, Promise

  • HTTP response

  • Observable emits

  • Parent component updates

❌ Performance killer

<div>{{ getTotal() }}</div>
getTotal() {
  return this.items.reduce((a, b) => a + b.price, 0);
}

👎 Runs on every change detection, even mouse move.


Fix (Derived value)

total = computed(() =>
  this.items().reduce((a, b) => a + b.price, 0)
);

computed() is NOT executed on every change detection.

it is:

  • Reactive

  • Memoized

  • Dependency-tracked

  • Runs once

  • Cached value

  • Re-runs ONLY when items changes

📌 Rule:
Templates must be dumb
No logic, no functions.


2️⃣ OnPush Strategy (Stop unnecessary checks)

Default behavior (what Angular does normally)

  • Parent changes → ALL children checked

  • Angular keeps checking everything again and again.

  • That’s why big apps feel slow.

  • Parent change

     └─ Child A checked

     └─ Child B checked

     └─ Child C checked

     └─ Grandchildren checked

OnPush behavior (the “smart” mode)

Angular says:

“I will NOT check this component again unless I have a GOOD reason.”

  • OnPush Strategy - Checked me ONLY IF:
        @Input() reference changes 
      this.user = { ...this.user, name: 'Kamal' }; // ✅ new objec

  • Event inside component
        <button (click)="increment()">+</button>

    increment() {
      this.count++;
    }
  • Observable emits (async)
        <div>{{ orders$ | async }}</div>

  • Signal changes

    count = signal(0);

    increment() {

      this.count.update(v => v + 1);

    }
    <p>{{ count() }}</p>
  • When should YOU use OnPush?
    • Container components
    • ✅ Table-heavy UIs
    • ✅ Dashboard screens
    • ✅ Anything using Observables / Signals

✅ Use OnPush ALWAYS unless proven otherwise

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class OrderRowComponent {}

❌ Common OnPush bug

this.orders.push(newOrder); // ❌ reference unchanged

✅ Correct

this.orders = [...this.orders, newOrder];

📌 Immutability = OnPush works


3️⃣ trackBy (Fix DOM thrashing)

Without trackBy, Angular:

  • Angular thinks like this 👇

    “Hmm… array changed.
    I DON’T KNOW which item is which.
    Safer to destroy everything and rebuild.”

  • Destroys ALL rows

  • Recreates ALL rows

❌ Bad

<tr *ngFor="let o of orders">

✅ Good

<tr *ngFor="let o of orders; trackBy: trackById">
trackById(_: number, o: Order) {
  return o.id;
}

  • Now Angular thinks:

“Ah! Each row has an identity (id).
Let me match old DOM with new data.”

 

Old DOM:
    Row(id=1)
    Row(id=2)

New data:
    Row(id=99)
    Row(id=1)
    Row(id=2) 

📌 Result:

  • DOM reused

  • Scroll position preserved

  • Inputs don’t reset

  • ✅ Only ONE new row created

  • ✅ Others reused

  • ✅ Fast

  • ✅ No flicker



4️⃣ Reactive Forms Architecture (How pros design forms)

❌ Anti-pattern (God Form)

this.form = this.fb.group({
  name: [],
  email: [],
  address: [],
  payment: [],
  shipping: []
});
And in the SAME component:
  • Builds the form

  • Renders HTML

  • Handles submit

  • Calls API

  • Does validation

  • Shows errors

  • Manages loading

Why this is BAD (real reasons)

❌ File becomes 600–1000 lines
❌ Impossible to reuse UI
❌ Unit tests are painful
❌ One tiny UI change breaks logic
❌ You can’t split the form later

This is called a God Component.

Hard to validate, test, and reuse.


✅ Correct Architecture

Container (smart)

  • Responsibilities

    • Creates the FormGroup

    • Owns business rules

    • Handles submit

    • Talks to API

    • Decides what happens

@Component({ ... })
export class UserFormContainerComponent {
  form = this.fb.group({
    name: ['', Validators.required],
    email: ['', Validators.email],
    address: this.fb.group({
      city: [''],
      zip: ['']
    })
  });

  submit() {
    if (this.form.valid) {
      this.api.save(this.form.value);
    }
  }
}

  • This component does NOT care about HTML details.

Presentational (dumb)

  • Receives FormGroup

  • Emits UI events

@Component({ ... })
export class UserFormComponent {
  @Input() form!: FormGroup;
  @Output() submitForm = new EventEmitter<void>();
}
<form [formGroup]="form" (ngSubmit)="submitForm.emit()">
  <input formControlName="name">
  <input formControlName="email">
  <button type="submit">Save</button>
</form>

📌 This component:

  • ❌ Does NOT create the form

  • ❌ Does NOT call API

  • ❌ Does NOT know backend exists

📌 Same rule as components → separation of concerns

🔁 How data flows (THIS IS THE KEY)

Container

  ↓ FormGroup (state)

Presentational

  ↓ User types

FormGroup updates

  ↓ Submit event

Container handles logic


5️⃣ Custom Validators (Real-world)

Field-level validator

function strongPassword(control: AbstractControl) {
  return control.value?.length >= 8 ? null : { weak: true };
}
password: ['', strongPassword]

6️⃣ Cross-field Validators (Very important)

Example: password & confirm password

function passwordMatch(group: AbstractControl) {
  const p = group.get('password')?.value;
  const c = group.get('confirm')?.value;
  return p === c ? null : { mismatch: true };
}
this.form = this.fb.group(
  {
    password: [''],
    confirm: ['']
  },
  { validators: passwordMatch }
);

📌 Cross-field = group validator, not control validator


7️⃣ Performance Debugging (No guessing anymore)

Tools you MUST use

  • Angular DevTools

  • Change Detection Profiler

  • Chrome Performance tab

Debug checklist

Ask:

  1. Is this component OnPush?

  2. Are functions called in template?

  3. Is trackBy missing?

  4. Are objects mutated?

  5. Is form recalculating on every keystroke?


Mental Model (Remember this)

❌ Slow Angular = too many checks + DOM recreation
Fast Angular = OnPush + immutable data + derived values


✔ “This component re-renders because input reference changed”
✔ “This list is slow because no trackBy”
✔ “This validator belongs to group, not control”
✔ “This performance fix is correct — not a guess”

Advanced Angular Performance & Forms – Extra Techniques 🔥


8️⃣ Kill Change Detection at the Source (Zone tricks)

❌ Problem

Angular runs change detection for:

  • scroll

  • mousemove

  • resize

  • 3rd-party libraries

Solution: NgZone.runOutsideAngular

constructor(private zone: NgZone) {}

ngAfterViewInit() {
  this.zone.runOutsideAngular(() => {
    window.addEventListener('scroll', () => {
      // no change detection triggered
    });
  });
}

📌 Use ONLY when UI doesn’t need updates
(ex: analytics, infinite scroll listeners)


9️⃣  Detach Change Detection (Rare but deadly effective)

constructor(private cdr: ChangeDetectorRef) {}

ngOnInit() {
  this.cdr.detach();
}

Manually reattach:

this.cdr.detectChanges();

📌 Use cases:

  • Large dashboards

  • Static reports

  • Read-only views

⚠️ Use carefully (senior-level tool)


🔟  Signals + OnPush = Near-zero CD

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class DashboardComponent {
  data = signal<Data[]>([]);
}

📌 Signals update only consumers
No tree-wide checking like Observables.


1️⃣2️⃣ Don’t Subscribe in Components (Hidden performance bug)

❌ Bad 

this.service.data$.subscribe(v => {
  this.data = v;
});
Angular does NOT know when to stop checking.

Every time:

  • mouse moves 🖱️

  • key pressed ⌨️

  • timer ticks ⏱️

  • ANY async event

Angular runs change detection
👉 your component gets checked even if data didn’t change

If you forget this 👇

ngOnDestroy() {

  this.sub.unsubscribe();

}

The subscription:

  • keeps running

  • keeps memory

  • keeps CPU busy

In large apps → slow app, random bugs, crashes

You’re doing Angular’s job manually

You are:

  • managing lifecycle ❌

  • managing cleanup ❌

  • triggering UI updates ❌

Angular already solved this.

Good  - The RIGHT way (what async pipe really does)

data$ = this.service.data$;
<div *ngFor="let d of data$ | async"></div>

You are saying:

“Angular, YOU handle the subscription. I only care about display.”

📌 async pipe:

  • auto unsubscribe

  • optimized CD

ThingResponsibility
Component     Expose streams
Template     Render streams
async pipe     Subscribe + unsubscribe
Angular     Optimize change detection

1️⃣3️⃣ Smart Debouncing Forms (Critical)

❌ Bad

this.form.valueChanges.subscribe(v => {
  this.search(v);
});

✅ Good

this.form.valueChanges.pipe(
  debounceTime(300),
  distinctUntilChanged()
).subscribe(v => this.search(v));

📌 Reduces API calls by 90%+


1️⃣4️⃣ updateOn – Hidden Form Performance Weapon

this.form = this.fb.group({
  email: ['', {
    updateOn: 'blur'
  }]
});

Options:

  • 'change' (default)

  • 'blur'

  • 'submit'

📌 Perfect for:

  • Heavy validators

  • Expensive async validators


1️⃣5️⃣ Async Validators Done Right

❌ Bad

email: ['', null, this.checkEmail]

Triggers on every keystroke.

✅ Good

email: ['', {
  asyncValidators: [this.checkEmail],
  updateOn: 'blur'
}]

1️⃣6️⃣ Lazy Load Forms & Heavy Components

loadComponent: () =>
  import('./big-form.component').then(m => m.BigFormComponent)

📌 Huge win for enterprise apps.


1️⃣7️⃣ Virtual Scroll (Lists > 100 items)

Use cdk-virtual-scroll-viewport

<cdk-virtual-scroll-viewport itemSize="50">
  <div *cdkVirtualFor="let item of items">
    {{ item.name }}
  </div>
</cdk-virtual-scroll-viewport>

📌 Renders only visible rows.


1️⃣8️⃣Avoid Pure Pipe Abuse

❌ Misuse

{{ data | heavyCalculation }}

Runs often.

Better

  • Precompute

  • Use computed signal

  • Or map in stream


1️⃣9️⃣ Split Huge Forms (Very underrated)

Instead of one massive form:

  • Step forms

  • Nested FormGroup

  • Load sections lazily

📌 Faster validation + easier debugging.


2️⃣0️⃣ Use readonly & disabled correctly

control.disable({ emitEvent: false });

📌 Prevents unnecessary valueChanges emissions.


2️⃣1️⃣ ChangeDetection Debug Trick

Add temporarily:

ngDoCheck() {
  console.log('CD ran');
}

📌 You’ll immediately see what causes re-renders


2️⃣2️⃣ Profiling Checklist (Memorize this)

When Angular is slow:

  1. List or form?

  2. OnPush?

  3. trackBy?

  4. Mutation?

  5. Template functions?

  6. Unnecessary subscriptions?

  7. Too many validators?

  8. No debouncing?

  9. Heavy DOM?

  10. Change detection triggered by zone?



Angular performance problems are 80% architecture mistakes, not framework limits


After mastering this, you can:

✔ Optimize without trial-and-error
✔ Explain why a fix works
✔ Design forms that scale to 100+ controls
✔ Debug CD like a profiler, not a guesser



LeetCode C++ Cheat Sheet June

🎯 Core Patterns & Representative Questions 1. Arrays & Hashing Two Sum – hash map → O(n) Contains Duplicate , Product of A...