23 câu chia 6 nhóm. Click từng câu để xem hint. Verbalize ra mồm trước gương.
useMemo và useCallback?A: Cùng concept (memoize). useMemo cache giá trị. useCallback cache function reference. useCallback(fn, deps) ≡ useMemo(() => fn, deps).
React.memo?A: Child re-render nhiều mà props ít đổi. Chỉ effective khi props primitive hoặc reference stable. Đo bằng DevTools Profiler trước — KHÔNG memoize mọi component.
A: Controlled — validate realtime, re-render mỗi keystroke. Uncontrolled (ref) — perf tốt cho form lớn. Thực tế: React Hook Form hoặc TanStack Form — uncontrolled internal + dev UX controlled.
A: Server Component (default trong app dir) — render server, không state/event, không ship JS. Bundle nhỏ, data fetch trực tiếp DB. Client Component — "use client". Rule: leaf interactive = client, parent = server.
A: (1) State local nhất có thể. (2) Split component giới hạn scope. (3) React.memo + stable props. (4) Context split (data vs dispatcher). (5) Đo Profiler trước, đừng premature.
A: staleTime = data còn fresh bao lâu (không auto-refetch). gcTime = giữ trong memory bao lâu sau khi không dùng (default 5m). Stale ≠ deleted — vẫn show cache, chỉ refetch background.
A: queryClient.invalidateQueries({queryKey:['tasks']}) trong onSuccess. Dùng key factory để invalidate chính xác. Optimistic: onMutate set cache trước, onError rollback.
useInfiniteQuery?A: Pagination kiểu "load more" hoặc infinite scroll. API trả cursor hoặc page number. getNextPageParam trả key cho lần fetch tiếp.
A: Cho server state — có (cache, sync tốt hơn). Cho UI state (modal, theme, form draft) — không. Dùng useState/Zustand. 80% Redux trong app thật ra là server state.
A: JWT không revoke được. Leak = hijack đến khi exp. Short-lived (5-15m) giới hạn exploit window. Refresh token dài hơn nhưng revoke được (lưu DB) + rotate mỗi lần dùng.
A: Access: memory — KHÔNG localStorage (XSS). Refresh: httpOnly + Secure + SameSite cookie. JS không đọc được. Reload page → /refresh → access mới.
A: PUT thay thế toàn bộ (full replace, idempotent). PATCH update partial. Cả 2 idempotent theo spec nhưng PATCH dễ implement non-idempotent.
A: Phát hiện: log SQL trong dev (Prisma log:['query']). Fix: include/select để JOIN. DataLoader cho GraphQL. Materialized view nếu query phức tạp lặp.
A: (1) Table có tenant_id. (2) Prisma middleware inject where:{tenantId} từ AsyncLocalStorage. (3) Postgres RLS làm safety net. (4) Integration test verify.
A: Redis INCR + TTL cho fixed window. Sliding window log chính xác hơn. Token bucket cho burst-friendly. Key = userId/IP. Trả 429 + Retry-After.
A: 401 — bạn là ai (chưa auth, token sai/hết hạn). 403 — biết bạn là ai nhưng không có quyền. FE: 401 → redirect login, 403 → "không có quyền".
A: Single responsibility, Open/closed, Liskov, Interface segregation, Dependency inversion. Xem page principles hoặc design patterns.
A: App nhỏ < 5 tables, không swap ORM, team 1-2 người. Prisma trực tiếp trong service đủ. Repository thừa layer, slow phát triển.
A: Default monolith. Split khi (1) team > 2-3 squad độc lập, (2) scale khác nhau (video vs API), (3) công nghệ khác (ML Python). Đừng split sớm — phải distributed transaction, eventual consistency.
A: PR → lint + typecheck + test → build → deploy preview. Merge main → migration → deploy prod → smoke test → rollback nếu fail. Cache deps + artifact. Secret qua env.
A: Mỗi index = write update index → chậm INSERT/UPDATE. Low-cardinality (boolean) — full scan rẻ hơn. Composite sai thứ tự (range trước equality) → miss. Đo EXPLAIN ANALYZE.
A: Expand-contract. (1) Add column nullable. (2) Code dual-write. (3) Backfill. (4) Switch read sang mới. (5) Drop cột cũ deploy sau. KHÔNG drop trong cùng deploy với code change.
A: Read Uncommitted, Read Committed (default Postgres), Repeatable Read, Serializable. Cao = ít concurrent. 99% case Read Committed đủ.
Framework: Situation (production bug, user impact) → Task (mình trực) → Action (reproduce, hypothesis, tool, root cause) → Result (số/metric, lesson). Pick bug có depth (race, leak, N+1, stampede) — không pick "typo".
A: Tránh "tôi đúng họ sai". Show: lắng nghe → data → compromise hoặc spike thử cả 2. Result: giải pháp tốt hơn cả ban đầu, hoặc nhường vì lý do hợp lý.
Talking points: Product impact (Base phục vụ hàng ngàn DN VN). Stack overlap (Next.js + NestJS + Postgres). Multi-tenant SaaS — bài toán hay. Sản phẩm thực không phải outsource. Muốn build domain HR/Work. Cá nhân hóa — đề cập 1-2 sản phẩm cụ thể.