📚 Ôn tập phỏng vấn - Mobifone IT

Nguyễn Huy Hoàng • Web Developer • ~6 năm kinh nghiệm • Dùng phím ← → để chuyển tab

SOLID - Ghi nhớ nhanh

SSingle Responsibility — Mỗi class chỉ nên có một lý do duy nhất để thay đổi. Tách biệt trách nhiệm rõ ràng.
OOpen/ClosedMở để mở rộng, đóng để sửa đổi. Thêm tính năng mới bằng cách tạo class mới, không sửa code cũ.
LLiskov Substitution — Đối tượng của lớp con phải thay thế được lớp cha mà không làm sai hành vi chương trình.
IInterface Segregation — Không ép client phụ thuộc vào interface mà nó không sử dụng. Chia nhỏ interface.
DDependency Inversion — Module cấp cao phụ thuộc vào abstraction, không phụ thuộc vào module cấp thấp (concrete).

Khi nào dùng giải pháp nào? (Scaling Quick Decision)

Vấn đềGiải phápBản chất
Đọc nhiều (read-heavy)Cache (Redis) + Read ReplicasGiảm tải DB bằng bản sao chỉ đọc + cache tầng ứng dụng
Ghi nhiều (write-heavy)Message Queue + ShardingXếp hàng xử lý bất đồng bộ + chia nhỏ dữ liệu theo khóa
Cả đọc lẫn ghiCQRSTách riêng mô hình đọc/ghi, mỗi bên tối ưu riêng
Người dùng toàn cầuCDN + Multi-regionĐưa nội dung tĩnh gần người dùng, deploy nhiều vùng
Thời gian thựcWebSocket + Event-drivenKết nối 2 chiều liên tục, server đẩy dữ liệu ngay khi có
Dữ liệu lớnStream processing + NoSQLXử lý luồng liên tục, lưu trữ linh hoạt không cần schema

Độ phức tạp thuật toán (Big-O)

Big-OTên gọiVí dụBản chất
O(1)Hằng sốHashMap lookup, truy cập mảng theo indexThời gian không đổi dù dữ liệu bao nhiêu
O(log n)LogaritTìm kiếm nhị phân, cây cân bằng BSTMỗi bước loại bỏ một nửa dữ liệu
O(n)Tuyến tínhDuyệt mảng, linked listDuyệt từng phần tử một lần
O(n log n)Tuyến tính logaritMerge sort, Quick sort (trung bình)Chia để trị + gộp kết quả
O(n²)Bình phươngBubble sort, 2 vòng lặp lồng nhauMỗi phần tử so sánh với mọi phần tử khác
O(2ⁿ)Hàm mũFibonacci đệ quy (không tối ưu)Phân nhánh gấp đôi mỗi bước — rất chậm

HTTP Status Codes

NhómÝ nghĩaMã thường gặp
1xxThông tin101 Switching Protocols (nâng cấp lên WebSocket)
2xxThành công200 OK • 201 Đã tạo • 204 Không có nội dung trả về
3xxChuyển hướng301 Chuyển vĩnh viễn • 302 Tạm thời • 304 Chưa thay đổi (dùng cache)
4xxLỗi phía client400 Yêu cầu sai • 401 Chưa xác thực • 403 Không có quyền • 404 Không tìm thấy • 429 Quá nhiều yêu cầu
5xxLỗi phía server500 Lỗi nội bộ • 502 Gateway lỗi • 503 Dịch vụ không khả dụng

Design Patterns — Bản đồ nhanh

Khởi tạo (Creational)
Singleton — Chỉ tồn tại 1 instance duy nhất (DB connection pool, Logger, Config). Dùng khi tài nguyên đắt đỏ cần chia sẻ.

Factory Method — Tạo object mà không chỉ rõ class cụ thể. Client gọi factory, factory quyết định tạo loại nào.

Builder — Xây dựng object phức tạp từng bước. VD: QueryBuilder.select('*').from('users').where(...).build()
Cấu trúc (Structural)
Adapter — Bọc một interface thành interface khác mà client mong đợi. Giống ổ chuyển đổi phích cắm điện.

Proxy — Đại diện kiểm soát truy cập đến object thực (cache proxy, logging proxy, lazy loading).

Decorator — Thêm hành vi mới mà không sửa class gốc. VD: LoggingDecorator bọc service.

Facade — Cung cấp interface đơn giản cho hệ thống con phức tạp.
Hành vi (Behavioral)
Observer (Pub/Sub) — Khi trạng thái thay đổi, tự động thông báo tất cả subscriber. VD: EventEmitter, Vue reactivity.

Strategy — Đóng gói thuật toán thành class riêng, thay đổi tại runtime. VD: các chiến lược sắp xếp khác nhau.

Chain of Responsibility — Truyền request qua chuỗi handler. VD: Middleware chain trong Express/Koa.

💼 "Kể về dự án khó nhất bạn đã làm?" → iNET Drive

Phương pháp STAR: Situation → Task → Action → Result
SCông ty cần xây dựng nền tảng lưu trữ đám mây an toàn dành cho doanh nghiệp và cá nhân, bắt đầu từ con số 0.
TTôi chịu trách nhiệm thiết kế toàn bộ cấu trúc Backend, xây dựng luồng xác thực (Authentication) và cơ chế upload file dung lượng lớn.
A • Thiết kế kiến trúc Backend với NodeJS, tích hợp S3 Compatible Storage (Ceph/MinIO)
• Tự xây dựng AWS Signature V4 — cơ chế ký HMAC-SHA256 để xác thực mỗi request đến S3 API
• Triển khai Multipart Upload: chia file lớn thành nhiều phần (chunks), upload song song, hỗ trợ tiếp tục khi bị gián đoạn
• Xử lý các trường hợp biên: retry chunk thất bại, quản lý trạng thái upload chưa hoàn thành
RHệ thống hoạt động ổn định, phục vụ khách hàng doanh nghiệp. Xử lý file hàng GB mà không bị timeout hay tràn bộ nhớ.

⚡ "Bạn đã tối ưu performance như thế nào?" → Backorder Domain

SHệ thống cần xử lý file văn bản cực lớn chứa danh sách hàng triệu tên miền đăng ký trên toàn thế giới, cập nhật liên tục.
TĐọc/ghi file nhanh, phát hiện tên miền mới, gửi hàng ngàn yêu cầu đăng ký song song.
AStream I/O: Đọc file theo từng dòng (line-by-line) thay vì nạp toàn bộ vào RAM — nguyên tắc then chốt khi xử lý big data
File diff: So sánh kích thước file để phát hiện thay đổi, chỉ trích xuất các tên miền mới (tránh xử lý lại toàn bộ)
Đa luồng với Quartz: Cấu hình thread pool qua file config, đẩy nhanh tốc độ gửi request đăng ký tên miền
• Rate limiting: Kiểm soát tần suất request để tránh bị registry API chặn
RTốc độ xử lý tăng gấp nhiều lần nhờ đa luồng. RAM giảm đáng kể nhờ stream processing.

📡 "Kinh nghiệm về hệ thống real-time?" → Cloud Panel Agent

SCần giám sát hàng chục máy chủ Linux từ xa theo thời gian thực, thực thi lệnh và thu thập metrics liên tục.
TXây dựng agent cài trên mỗi server, giao tiếp hai chiều liên tục với hệ thống trung tâm.
A • Viết Agent bằng Golang — ngôn ngữ phù hợp cho system programming, nhẹ và nhanh
• Giao tiếp qua WebSocket — kết nối persistent, hai chiều, không cần polling liên tục
• Tích hợp PTY (Pseudo Terminal): cho phép thực thi lệnh từ xa như SSH — server gửi lệnh, agent thực thi và trả kết quả real-time
Heartbeat: Agent gửi tín hiệu mỗi 30s, server phát hiện offline nếu mất tín hiệu
• Metrics streaming (CPU, RAM, Disk) + Audit log gửi về trung tâm + Agent tự cập nhật phiên bản mới
RGiám sát hàng chục server real-time, phát hiện sự cố trong vòng 30 giây, giảm thời gian xử lý incident đáng kể.

🔒 "Kinh nghiệm về bảo mật / eKYC?" → iNET Portal

SCổng dịch vụ khách hàng cần xác minh danh tính điện tử (eKYC) để đảm bảo tính pháp lý, nhưng không muốn phụ thuộc dịch vụ bên thứ 3.
TTự xây dựng toàn bộ luồng eKYC từ đầu.
AFacemesh: Chụp ảnh khuôn mặt real-time, phát hiện người thật (liveness detection — chống ảnh giả, video giả)
OCR: Đọc tự động thông tin từ CMND/CCCD (họ tên, số ID, ngày sinh...)
• So khớp khuôn mặt chụp trực tiếp với ảnh trên giấy tờ tùy thân
• Phát triển Game SDK: hỗ trợ giao tiếp chéo qua iframe bằng postMessage API — cho phép nhúng mini-game vào portal
RLuồng eKYC hoạt động chính xác, tiết kiệm chi phí đáng kể so với thuê dịch vụ eKYC bên ngoài.

🎯 Câu hỏi hành vi thường gặp

💪 Điểm mạnh của bạn?
• Tự tay xây dựng hệ thống từ con số 0 (iNET Drive, eKYC) — chứng tỏ khả năng thiết kế kiến trúc và giải quyết vấn đề
• Đa dạng tech stack: Java, NodeJS, Golang, VueJS — linh hoạt chọn công cụ phù hợp bài toán
• Kinh nghiệm thực tế về system design và tối ưu hiệu năng (stream I/O, đa luồng, WebSocket)
• Chủ động học và áp dụng công nghệ mới (tự học Golang để viết agent, tích hợp PTY)
😬 Điểm yếu của bạn?
• Đôi khi quá tập trung vào chi tiết kỹ thuật mà chưa chú ý đủ trải nghiệm người dùng → đang cải thiện bằng cách làm việc sát hơn với team frontend/UX
• Chưa nhiều kinh nghiệm với dịch vụ cloud managed (AWS, GCP) → đang tự học để mở rộng kỹ năng
🏢 Tại sao muốn làm ở Mobifone IT?
• Mobifone là nhà mạng viễn thông lớn, hệ thống phục vụ hàng triệu thuê bao — thách thức về quy mô và hiệu năng rất hấp dẫn
• Ngành viễn thông đang chuyển đổi số mạnh mẽ (5G, IoT, dịch vụ số) — nhiều cơ hội ứng dụng công nghệ mới
• Kinh nghiệm về real-time monitoring, WebSocket, bảo mật (eKYC/SSO) phù hợp với yêu cầu của hệ thống viễn thông
• Muốn xây dựng hệ thống High Availability phục vụ lượng người dùng lớn — đúng với mục tiêu nghề nghiệp
🤝 Mô tả xung đột với đồng nghiệp?
S: Bất đồng về thiết kế API: dùng REST hay custom protocol
T: Cần thống nhất approach cho dự án mới
A: Trình bày ưu/nhược điểm từng cách, làm POC nhỏ so sánh performance và developer experience
R: Team chọn REST vì dễ bảo trì, team quen thuộc → Bài học: Quyết định dựa trên dữ liệu, không dựa trên cái tôi
❓ Câu hỏi nên hỏi ngược nhà tuyển dụng:
1. Team hiện tại đang sử dụng tech stack gì?
2. Quy trình CI/CD và code review như thế nào?
3. Dự án tôi sẽ tham gia là gì? Quy mô team bao nhiêu người?
4. Có cơ hội phát triển chuyên môn không? (đào tạo, hội thảo, chứng chỉ...)
5. Thách thức kỹ thuật lớn nhất của team hiện tại là gì?

Quy trình tiếp cận bài System Design (4 bước)

1. Làm rõ yêu cầu
3-5 phút | Chức năng + Phi chức năng
2. Thiết kế tổng quan
10 phút | Sơ đồ + Components
3. Đi sâu chi tiết
15 phút | DB + API + Scaling
4. Điểm nghẽn & đánh đổi
5 phút | SPOF + Trade-offs
Bước 1 quan trọng nhất: Hỏi rõ trước khi vẽ. VD: "Hệ thống cần phục vụ bao nhiêu người dùng? Yêu cầu về latency? Dữ liệu cần lưu bao lâu?"

Khả năng mở rộng (Scalability)

Scale dọc (Vertical / Scale Up)
Bản chất: Tăng sức mạnh phần cứng của 1 máy (thêm CPU, RAM, SSD)
Ưu Đơn giản, không cần sửa code
Nhược Có giới hạn vật lý, đắt đỏ khi lên cao
VD: Nâng DB server từ 16GB → 64GB RAM
Scale ngang (Horizontal / Scale Out)
Bản chất: Thêm nhiều máy chủ, phân tán tải
Ưu Scale gần như vô hạn, chịu lỗi tốt
Nhược Phức tạp hơn, cần Load Balancer, đồng bộ dữ liệu
VD: 1 web server → 10 servers + Load Balancer

Cân bằng tải (Load Balancing)

Thuật toánCơ chếKhi nào dùng
Round RobinChia đều request luân phiên cho từng serverCác server cấu hình giống nhau
Weighted Round RobinServer mạnh nhận nhiều request hơn (theo trọng số)Server cấu hình khác nhau
Least ConnectionsGửi đến server đang có ít kết nối nhấtRequest xử lý lâu, thời gian không đều
IP HashCùng IP luôn đến cùng serverCần session sticky (giữ phiên)
L4 (Transport layer): Phân tải ở tầng TCP/UDP — nhanh nhưng "mù" nội dung
L7 (Application layer): Phân tải ở tầng HTTP — thông minh hơn, route theo URL, header, cookie
Công cụ: Nginx HAProxy AWS ALB/NLB

Chiến lược Cache (Bộ nhớ đệm)

Cache-Aside (Lazy Loading)
Luồng: Ứng dụng đọc cache trước → nếu miss → đọc DB → ghi vào cache
Đơn giản, chỉ cache dữ liệu được yêu cầu
Cold start lần đầu chậm, dữ liệu có thể cũ (stale)
Write-Through
Luồng: Ghi DB và cache đồng thời mỗi lần write
Dữ liệu luôn nhất quán giữa cache và DB
Ghi chậm hơn, cache nhiều dữ liệu không ai đọc
Write-Behind (Write-Back)
Luồng: Ghi cache trước → ghi DB bất đồng bộ sau
Ghi rất nhanh, giảm tải DB
Nguy cơ mất dữ liệu nếu cache sập trước khi ghi DB
Các tầng cache: L1 In-memory (HashMap, Guava) → L2 Phân tán (Redis, Memcached) → L3 CDN (Cloudflare, CloudFront)
Redis vs Memcached: Redis hỗ trợ nhiều kiểu dữ liệu (String, Hash, List, Set, Sorted Set), có persistence và pub/sub. Memcached đơn giản hơn, đa luồng, chỉ key-value string.

Cơ sở dữ liệu: SQL vs NoSQL

SQL (MySQL, PostgreSQL)
Bản chất: Dữ liệu có cấu trúc bảng, quan hệ giữa các bảng, đảm bảo ACID
Ưu Query phức tạp (JOIN), giao dịch an toàn, schema rõ ràng
Nhược Khó scale ngang, schema cứng nhắc
Dùng khi: Dữ liệu có quan hệ, giao dịch tài chính, quản lý thuê bao viễn thông
NoSQL
Document (MongoDB): Schema linh hoạt, dữ liệu lồng nhau
Key-Value (Redis): Cache, session, bảng xếp hạng — cực nhanh
Wide-Column (Cassandra): Time-series, IoT — ghi cực nhanh
Graph (Neo4j): Mạng xã hội, hệ thống gợi ý
Dùng khi: Schema thay đổi thường xuyên, cần scale ngang, dữ liệu phi cấu trúc
Mở rộng DB: Read Replicas (bản sao chỉ đọc) | Sharding (chia dữ liệu theo key: user_id % N) | Partitioning (chia bảng trong cùng 1 DB)

Định lý CAP

Một hệ thống phân tán chỉ có thể đảm bảo 2 trong 3: Consistency (nhất quán) + Availability (khả dụng) + Partition Tolerance (chịu phân mảng mạng)

Thực tế: Partition (mạng bị chia cắt) luôn có thể xảy ra → bạn phải chọn giữa CP hoặc AP

CP — Ưu tiên nhất quán
Khi mạng bị chia, hệ thống từ chối trả lời (để đảm bảo dữ liệu đúng)
Phù hợp: Hệ thống tài chính, quản lý thuê bao
MySQL, MongoDB (majority write concern)
AP — Ưu tiên khả dụng
Khi mạng bị chia, hệ thống vẫn trả lời (dữ liệu có thể chưa cập nhật)
Phù hợp: Feed tin tức, analytics, log
Cassandra, DynamoDB

Hàng đợi tin nhắn (Message Queue)

Bản chất: Tách rời (decouple) giữa người gửi và người nhận. Người gửi đẩy message vào queue, người nhận lấy ra xử lý — không cần cả hai online cùng lúc.
Công cụĐặc điểmKhi nào dùng
RabbitMQMessage broker truyền thống, routing linh hoạt (exchange, binding)Nghiệp vụ cần routing phức tạp, đảm bảo delivery
KafkaDistributed log, throughput cực cao, lưu trữ message lâu dàiEvent streaming, xử lý dữ liệu lớn, audit log
Redis Pub/SubNhẹ, nhanh, không lưu message (fire-and-forget)Thông báo real-time, invalidate cache

Monolith vs Microservices

Monolith (Nguyên khối)
Bản chất: Toàn bộ ứng dụng là 1 codebase, deploy 1 lần
Đơn giản deploy, debug, test — phù hợp giai đoạn đầu
Hiệu năng tốt (không overhead mạng giữa services)
Khó scale từng phần — 1 module lỗi có thể sập toàn bộ
Microservices (Vi dịch vụ)
Bản chất: Chia thành nhiều service nhỏ, mỗi service làm 1 việc, deploy độc lập
Scale từng service riêng, team làm việc độc lập
Công nghệ đa dạng — mỗi service dùng ngôn ngữ/DB khác nhau
Phức tạp vận hành: monitoring, logging, distributed transactions
Các pattern quan trọng:
API Gateway — Điểm vào duy nhất, xác thực, rate limiting, routing
Circuit Breaker — Ngắt mạch khi service downstream lỗi, tránh lỗi lan truyền (cascade failure)
Saga Pattern — Quản lý giao dịch phân tán (choreography: event-driven hoặc orchestration: có điều phối viên)
CQRS — Tách mô hình đọc và ghi, mỗi bên tối ưu riêng
Event Sourcing — Lưu mọi thay đổi dưới dạng event (thay vì chỉ lưu trạng thái cuối)

Case Study: Thiết kế Cloud Storage (kinh nghiệm iNET Drive)

Client
API Gateway
Auth Service
File Service
S3/MinIO
Quyết định thiết kế then chốt:
Multipart Upload: Chia file thành chunks, upload song song — khôi phục được khi mất kết nối
Pre-signed URL: Client upload trực tiếp lên S3, giảm tải cho API server (server chỉ ký URL)
AWS Signature V4: Ký mỗi request bằng HMAC-SHA256 để xác thực
Tách metadata và file: Metadata lưu trong MySQL (dễ query), file data trên Object Storage (scale tốt)

Thiết kế API & Xác thực

GET    /api/v1/users          Lấy danh sách
GET    /api/v1/users/:id      Lấy chi tiết
POST   /api/v1/users          Tạo mới
PUT    /api/v1/users/:id      Cập nhật toàn bộ
PATCH  /api/v1/users/:id      Cập nhật một phần
DELETE /api/v1/users/:id      Xóa
Phân trang: Offset-based ?page=1&limit=20 (đơn giản) hoặc Cursor-based ?cursor=abc&limit=20 (tốt hơn cho dataset lớn — không bị trùng/sót khi dữ liệu thay đổi)

JWT & OAuth 2.0

JWT (JSON Web Token): Gồm 3 phần Header.Payload.Signature — server không cần lưu session, chỉ cần verify chữ ký. Access Token (15 phút, ngắn hạn) + Refresh Token (7 ngày, dùng để lấy access token mới). Lưu Refresh Token trong HttpOnly Cookie (chống XSS).

OAuth 2.0: Authorization Code (ứng dụng web có backend) | PKCE (SPA, mobile — không có backend an toàn) | Client Credentials (service gọi service)

SSO (Single Sign-On): Đăng nhập 1 lần, truy cập nhiều hệ thống (SAML cho enterprise, OpenID Connect cho web hiện đại)

S — Single Responsibility (Nguyên tắc đơn trách nhiệm)

Bản chất: "Mỗi class chỉ nên có một lý do duy nhất để thay đổi." Nếu class làm nhiều việc, khi sửa 1 chức năng có thể ảnh hưởng chức năng khác.
SAI — 1 class làm 3 việc
class UserService {
  createUser(data) { ... }       // Nghiệp vụ user
  sendEmail(user) { ... }        // Gửi email
  generateReport(user) { ... }   // Tạo báo cáo
}
// Sửa logic email có thể ảnh hưởng user
ĐÚNG — Tách riêng trách nhiệm
class UserService { createUser(data) { ... } }
class EmailService { sendEmail(user) { ... } }
class ReportService { generateReport(user) { ... } }
// Mỗi class độc lập, sửa 1 cái không ảnh hưởng cái khác
Áp dụng thực tế (từ CV): Dự án iNET Drive tách rõ AuthService, FileService, StorageService — mỗi service có trách nhiệm riêng biệt.

O — Open/Closed (Mở-Đóng)

Bản chất: "Mở để mở rộng, đóng để sửa đổi." Khi cần thêm tính năng mới, tạo class/module mới thay vì sửa code cũ đã chạy ổn định.
SAI — Thêm loại mới phải sửa hàm cũ
class PaymentProcessor {
  process(type) {
    if (type === 'credit') { ... }
    if (type === 'debit') { ... }
    // Thêm Momo? Phải sửa hàm này!
  }
}
ĐÚNG — Dùng interface + class mới
interface PaymentMethod { process(): void }
class CreditPayment implements PaymentMethod {...}
class DebitPayment implements PaymentMethod {...}
class MomoPayment implements PaymentMethod {...}
// Thêm Momo: chỉ tạo class mới, không sửa gì cũ

L — Liskov Substitution (Thay thế Liskov)

Bản chất: "Nếu S là subclass của T, thì object của S phải thay thế được object của T mà chương trình vẫn đúng." Lớp con không được phá vỡ hợp đồng (contract) của lớp cha.
SAI — Penguin thay thế Bird nhưng bay không được
class Bird { fly() { ... } }
class Penguin extends Bird {
  fly() { throw Error("Không biết bay!") }
}
// Code gọi bird.fly() sẽ bị lỗi bất ngờ
ĐÚNG — Thiết kế lại hierarchy
class Bird { move() { ... } }
class FlyingBird extends Bird { fly() { ... } }
class Penguin extends Bird { swim() { ... } }
// Penguin thay thế Bird hợp lệ (đều có move())

I — Interface Segregation (Phân tách interface)

Bản chất: "Không ép client phụ thuộc vào method mà nó không dùng." Interface nên nhỏ gọn, chuyên biệt — thay vì 1 interface to chứa mọi thứ.
SAI — 1 interface béo phì
interface Worker {
  code(); test(); design(); manage();
}
// Developer bị ép implement design(), manage()
// mà không bao giờ dùng
ĐÚNG — Chia nhỏ theo vai trò
interface Coder { code() }
interface Tester { test() }
interface Designer { design() }

class Developer implements Coder, Tester {...}
// Chỉ implement những gì thực sự cần

D — Dependency Inversion (Đảo ngược phụ thuộc)

Bản chất: "Module cấp cao không phụ thuộc vào module cấp thấp. Cả hai đều phụ thuộc vào abstraction (interface)." Điều này cho phép thay đổi implementation mà không ảnh hưởng business logic.
SAI — Phụ thuộc trực tiếp vào MySQL
class UserService {
  private db = new MySQLDatabase()
  // Muốn đổi MongoDB? Phải sửa UserService!
}
ĐÚNG — Phụ thuộc vào abstraction
interface Database { query(sql: string): any }
class MySQLDB implements Database { ... }
class MongoDB implements Database { ... }

class UserService {
  constructor(private db: Database) {}
  // Inject implementation nào cũng được!
}
Dependency Injection (DI) trong các framework:
• Spring Boot: @Autowired, @Inject — container tự động inject bean
• NestJS: @Injectable(), providers — tương tự Spring DI
• Constructor Injection là phổ biến nhất và dễ test nhất (truyền mock qua constructor)

4 trụ cột OOP — So sánh chi tiết

Trụ cộtBản chấtVí dụ thực tếTừ khóa / Cơ chế
Đóng gói
(Encapsulation)
Ẩn giấu chi tiết bên trong, chỉ để lộ interface cần thiết. Bảo vệ dữ liệu khỏi bị truy cập/sửa đổi tùy tiện từ bên ngoài. Class BankAccountprivate balance. Bên ngoài không thể gán trực tiếp balance = -100, phải gọi withdraw() — hàm này kiểm tra số dư trước. private / protected / public
Getter / Setter
Kế thừa
(Inheritance)
Lớp con thừa hưởng thuộc tính và phương thức của lớp cha. Quan hệ "is-a" (Chó là một Động vật). class Dog extends Animal — Dog tự động có name, eat() từ Animal mà không cần viết lại. extends (Java/TS)
: (C#)
Ưu tiên Composition over Inheritance
Đa hình
(Polymorphism)
Cùng một method/interface nhưng hành vi khác nhau tùy đối tượng cụ thể. "Nhiều hình dạng". shape.area() — Circle trả về πr², Rectangle trả về w×h. Code gọi giống nhau nhưng kết quả khác nhau. Compile-time: Overloading (cùng tên, khác tham số)
Runtime: Overriding (lớp con ghi đè lớp cha)
Trừu tượng hóa
(Abstraction)
Ẩn chi tiết phức tạp bên trong, chỉ hiển thị những gì cần thiết cho người dùng. Định nghĩa "hợp đồng" (contract). Bạn lái xe chỉ cần biết accelerate()brake(), không cần biết cơ chế động cơ đốt trong bên trong. Abstract class: có thể chứa code, đơn kế thừa
Interface: chỉ contract, đa kế thừa

So sánh: Abstract Class vs Interface

Tiêu chíAbstract ClassInterface
Chứa code thực thi? — có thể có method có bodyKhông — chỉ khai báo method (Java 8+ cho phép default)
Kế thừaChỉ kế thừa 1 abstract class (đơn kế thừa)Implement nhiều interface (đa kế thừa)
Constructor?Không
Access modifier?Có thể dùng private, protectedMặc định public
Khi nào dùng?Khi các lớp con có chung logic cần chia sẻKhi muốn định nghĩa contract mà không quan tâm implementation
Ví dụabstract class Vehicle { startEngine() {...} }interface Drivable { drive(): void }

So sánh: Overloading vs Overriding

Tiêu chíOverloading (Nạp chồng)Overriding (Ghi đè)
Xảy ra khi nào?Compile-time (static polymorphism)Runtime (dynamic polymorphism)
Ở đâu?Trong cùng 1 classGiữa lớp cha và lớp con
Tên method?Giống nhauGiống nhau
Tham số?Khác nhau (số lượng hoặc kiểu)Giống hệt lớp cha
Ví dụadd(int,int) vs add(double,double)Lớp con Cat.speak() ghi đè Animal.speak()

Composition vs Inheritance — Khi nào dùng gì?

Inheritance (Kế thừa) — Dùng ít hơn
Quan hệ "is-a" (Chó Động vật)
Vấn đề: Kế thừa sâu tạo "cây" phức tạp, thay đổi lớp cha ảnh hưởng tất cả lớp con, khó tái sử dụng logic giữa các nhánh khác nhau.
class FlyingFish extends Fish { fly() {...} }
// Fish không bay được → vi phạm logic
// Kế thừa cứng nhắc, không linh hoạt
Composition (Lắp ghép) — Ưu tiên dùng
Quan hệ "has-a" (Xe Động cơ)
Ưu điểm: Linh hoạt, thay đổi behavior tại runtime, tránh kế thừa sâu, dễ test (mock từng thành phần).
class Fish {
  constructor(
    private swimmer: SwimBehavior,
    private flyer?: FlyBehavior  // Tùy chọn!
  ) {}
}

Clean Architecture

Frameworks
Express, Spring, DB
Adapters
Controllers, Gateways
Use Cases
Nghiệp vụ ứng dụng
Entities
Nghiệp vụ cốt lõi
Quy tắc phụ thuộc: Mũi tên phụ thuộc chỉ hướng vào trong. Controller → UseCase → Entity. Entity KHÔNG biết gì về DB hay HTTP.
Lợi ích: Test business logic không cần DB/HTTP | Đổi MySQL sang MongoDB chỉ sửa Adapter layer | UI thay đổi không ảnh hưởng logic nghiệp vụ.

Vòng đời Component Vue 3 (Composition API)

setup()
Khởi tạo
onBeforeMount
onMounted
DOM sẵn sàng, fetch data
onBeforeUpdate
onUpdated
DOM đã cập nhật
onUnmounted
Dọn dẹp! (clearInterval...)
import { onMounted, onUnmounted, ref, watch } from 'vue'

setup() {
  const data = ref(null)     // ref() = reactive primitive
  let timer = null

  onMounted(async () => {   // DOM đã render xong
    data.value = await fetchData()
    timer = setInterval(pollData, 5000)
  })

  onUnmounted(() => {       // Component bị hủy
    clearInterval(timer)     // QUAN TRỌNG: tránh memory leak!
  })

  watch(data, (newVal, oldVal) => {
    console.log('Dữ liệu thay đổi:', newVal)
  })

  return { data }           // Trả về cho template sử dụng
}

Options API vs Composition API

Options API (Vue 2)Composition API (Vue 3)Giải thích
data()ref(), reactive()Khai báo dữ liệu phản ứng (reactive)
computedcomputed()Giá trị tính toán tự cập nhật khi dependency thay đổi
methodsHàm thườngCác hàm xử lý sự kiện, logic
watchwatch(), watchEffect()Theo dõi thay đổi dữ liệu. watchEffect tự detect dependency
mountedonMounted()Chạy sau khi DOM render xong
beforeUnmountonBeforeUnmount()Dọn dẹp trước khi component bị hủy
Ưu điểm Composition API:
• Tái sử dụng logic qua composables (thay thế mixins — không bị xung đột namespace)
• Hỗ trợ TypeScript tốt hơn nhiều
• Tổ chức code theo tính năng (feature) thay vì theo loại option — dễ đọc hơn khi component lớn

Composables (Custom Hooks trong Vue 3)

// useFetch.js — Đóng gói logic fetch dữ liệu, tái sử dụng ở nhiều component
export function useFetch(url) {
  const data = ref(null)
  const error = ref(null)
  const loading = ref(true)

  onMounted(async () => {
    try {
      const res = await fetch(url)
      data.value = await res.json()
    } catch (e) {
      error.value = e
    } finally {
      loading.value = false
    }
  })
  return { data, error, loading }
}

// Sử dụng trong bất kỳ component nào:
const { data, loading } = useFetch('/api/users')

React Hooks (Phòng trường hợp được hỏi)

// useState — Quản lý state cục bộ
const [count, setCount] = useState(0)

// useEffect — Xử lý side effects (tương đương lifecycle hooks)
useEffect(() => {
  fetchData()                         // Chạy khi mount + update
  return () => clearInterval(timer)   // Cleanup khi unmount
}, [dep])
// [] = chỉ chạy 1 lần (mount)
// [dep] = chạy lại khi dep thay đổi
// không có [] = chạy mỗi lần render

// useMemo — Cache giá trị tính toán đắt đỏ (tránh tính lại mỗi render)
const val = useMemo(() => heavyCompute(a, b), [a, b])

// useCallback — Cache tham chiếu hàm (tránh child re-render không cần thiết)
const fn = useCallback(() => doSomething(id), [id])
Quy tắc bắt buộc: Chỉ gọi hooks ở top level (KHÔNG trong if/for/nested function) | Chỉ dùng trong function component hoặc custom hook | Tên custom hook bắt đầu bằng "use"

Vòng đời Bean trong Spring Boot

Constructor
@Autowired (DI)
@PostConstruct
Khởi tạo logic
Bean sẵn sàng
@PreDestroy
Dọn dẹp
Tắt Container

Annotation quan trọng

Đánh dấu Bean
@Component — Bean chung chung
@Service — Tầng nghiệp vụ (business logic)
@Repository — Tầng truy cập dữ liệu
@RestController — API controller (= @Controller + @ResponseBody, trả JSON)
Tiêm phụ thuộc & Cấu hình
@Autowired — Tự động inject dependency
@Qualifier("name") — Chọn bean cụ thể khi có nhiều implementation
@Value("${config.key}") — Inject giá trị từ application.properties
@Profile("dev") — Kích hoạt khi chạy profile dev

Luồng xử lý Request trong Spring Boot

Client
Filter
Auth, CORS
DispatcherServlet
Interceptor
Validation
Controller
Service
Repository
DB
Filter vs Interceptor:
Filter (Servlet level): Chạy TRƯỚC DispatcherServlet — dùng cho auth, CORS, logging request/response
Interceptor (Spring level): Chạy SAU DispatcherServlet — dùng cho business validation, audit

Node.js Event Loop

Bản chất: Node.js là single-threaded nhưng xử lý I/O bất đồng bộ nhờ Event Loop + Thread Pool (libuv, mặc định 4 threads). Main thread không bao giờ bị block bởi I/O.
Các pha của Event Loop (chạy vòng lặp liên tục):

1. timers        — Thực thi callback của setTimeout, setInterval
2. pending       — I/O callbacks bị trì hoãn
3. poll          — Lấy sự kiện I/O mới (đọc file, network...)
4. check         — Thực thi setImmediate
5. close         — socket.on('close')

Microtask Queue (ƯU TIÊN CAO NHẤT — chạy hết trước khi sang pha tiếp):
  process.nextTick() > Promise.then()
// Đề thi kinh điển — đoán output:
console.log('1')                              // 1 (đồng bộ)
setTimeout(() => console.log('2'))            // (timers phase)
Promise.resolve().then(() => console.log('3'))// (microtask)
process.nextTick(() => console.log('4'))      // (microtask, trước Promise)
console.log('5')                              // (đồng bộ)

// Kết quả: 1, 5, 4, 3, 2
// Giải thích: Đồng bộ chạy trước (1,5) → nextTick (4) → Promise (3) → setTimeout (2)
Khi nào KHÔNG nên dùng Node.js: Tác vụ nặng CPU (xử lý ảnh, mã hóa nặng) sẽ block event loop. Giải pháp: Worker Threads, child_process, hoặc dùng Go/Java cho phần đó.

WebSocket Lifecycle

HTTP Upgrade Request
101 Switching Protocols
WS Open ⇄
Trao đổi Messages
Close
So sánh:
HTTP: Request-Response, client chủ động kéo (pull) — mỗi request tạo kết nối mới
WebSocket: Full-duplex, kết nối duy trì liên tục — server chủ động đẩy (push) dữ liệu
SSE (Server-Sent Events): Một chiều server → client — đơn giản hơn WS nhưng chỉ 1 chiều

Go Concurrency (Goroutine & Channel)

// Goroutine — "Luồng nhẹ" do Go runtime quản lý (~2KB stack, rất rẻ)
go func() {
    collectMetrics()  // Chạy đồng thời, không block main
}()

// Channel — Giao tiếp an toàn giữa các goroutine (thay thế shared memory + lock)
ch := make(chan string)
go func() { ch <- "dữ liệu" }()   // Gửi vào channel
result := <-ch                      // Nhận từ channel (block cho đến khi có data)

// Select — Lắng nghe nhiều channel cùng lúc (giống switch cho channel)
select {
case msg := <-ch1: handle(msg)
case <-time.After(5 * time.Second): fmt.Println("Timeout!")
}

// WaitGroup — Đợi nhiều goroutine hoàn thành
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
    wg.Add(1)
    go func() {
        defer wg.Done()
        doWork()
    }()
}
wg.Wait()  // Block cho đến khi tất cả Done()
Triết lý Go: "Đừng giao tiếp bằng chia sẻ bộ nhớ, hãy chia sẻ bộ nhớ bằng giao tiếp" — dùng Channel thay vì Mutex khi có thể.

CI/CD là gì?

CI (Tích hợp liên tục)
Bản chất: Mỗi khi dev push code, hệ thống tự động build và chạy test. Phát hiện lỗi sớm, tránh tình trạng "code trên máy tôi chạy được".
Merge thường xuyên
CD (Chuyển giao liên tục)
Bản chất: Code luôn ở trạng thái sẵn sàng deploy. Tự động deploy lên staging, nhưng lên production cần phê duyệt thủ công.
CD (Triển khai liên tục)
Bản chất: Tự động deploy lên production ngay khi test pass — không cần phê duyệt. Yêu cầu test coverage cao và monitoring tốt.

GitLab CI Pipeline (từ kinh nghiệm thực tế)

# .gitlab-ci.yml
stages: [build, test, security, deploy]

build:
  script: docker build -t $IMAGE:$CI_COMMIT_SHA . && docker push
  only: [main, develop]

test:
  script: npm install && npm run lint && npm run test -- --coverage

security:
  script: npm audit && docker scan $IMAGE

deploy_staging:
  only: [develop]
  script: docker-compose -f docker-compose.staging.yml up -d

deploy_production:
  only: [main]
  when: manual        # Cần người phê duyệt trước khi deploy production
  script: docker-compose -f docker-compose.prod.yml up -d
Các khái niệm then chốt:
Runner: Máy thực thi pipeline (shared/specific/group)
Stages: Nhóm jobs chạy tuần tự (build → test → deploy)
Artifacts: Output của job, truyền sang stage tiếp theo (VD: file coverage report)
Cache: Cache dependencies giữa các pipeline (VD: node_modules — tránh cài lại mỗi lần)

Docker — Kiến thức nền tảng

Docker là gì? Công cụ đóng gói ứng dụng cùng toàn bộ môi trường (OS, thư viện, config) vào một "container" cô lập. Đảm bảo ứng dụng chạy giống nhau ở mọi nơi — từ máy dev đến server production. Giải quyết triệt để vấn đề "trên máy tôi chạy được".
Khái niệmBản chấtTương tự OOPChi tiết
ImageTemplate chỉ đọc, bất biến (immutable)ClassGồm nhiều layer xếp chồng (layered filesystem). Mỗi lệnh trong Dockerfile tạo 1 layer. Layer được cache — build lần sau nhanh hơn.
ContainerInstance đang chạy từ imageObjectCó filesystem riêng, process riêng, network riêng. Container bị xóa thì dữ liệu bên trong mất (trừ khi dùng Volume).
DockerfileFile chỉ dẫn build imageConstructorMỗi dòng = 1 lệnh: FROM (base image), COPY (sao chép file), RUN (thực thi lệnh), CMD (lệnh mặc định khi chạy container).
VolumeLưu trữ bền vữngExternal storageDữ liệu tồn tại ngay cả khi container bị xóa. Dùng cho DB data, upload files, logs.
NetworkKết nối giữa containersMạng LAN ảoContainers trong cùng docker-compose gọi nhau bằng tên service (VD: db:3306)
RegistryKho lưu trữ imagesPackage registryDocker Hub (public), GitLab Registry (private). Push/pull image giống git push/pull.

Docker vs Virtual Machine (VM) — So sánh

Tiêu chíDocker ContainerVirtual Machine
Kiến trúcChia sẻ kernel OS của host, chỉ cô lập ở tầng ứng dụngMỗi VM có OS riêng hoàn toàn (Guest OS)
Kích thướcNhẹ — vài chục MB (alpine image ~5MB)Nặng — vài GB (cả OS)
Khởi độngGiâyPhút
Hiệu năngGần như native (không overhead ảo hóa phần cứng)Chậm hơn do hypervisor
Cô lậpCô lập process, network, filesystem (nhưng chung kernel)Cô lập hoàn toàn (OS riêng)
Bảo mậtÍt cô lập hơn VM (exploit kernel = ảnh hưởng host)An toàn hơn (OS riêng biệt)
Dùng khiMicroservices, CI/CD, dev environment, deploy nhanhCần cô lập OS hoàn toàn, chạy OS khác nhau

Dockerfile — Chi tiết từng lệnh & Best Practices

# === Multi-stage build — Giảm kích thước image đáng kể ===

# Stage 1: BUILD — cài đặt mọi thứ cần thiết để build
FROM node:18-alpine AS builder       # Alpine Linux ~5MB (vs node:18 ~900MB)
WORKDIR /app                         # Tạo và chuyển vào thư mục /app

# Trick tận dụng Docker cache layer:
# Copy package.json TRƯỚC, install, RỒI MỚI copy source code
# → Nếu source code thay đổi nhưng dependencies không đổi → layer npm ci được cache
COPY package*.json ./
RUN npm ci                           # ci = clean install, nhanh hơn npm install
                                     # + khóa chính xác version từ package-lock.json
COPY . .                             # Giờ mới copy toàn bộ source code
RUN npm run build                    # Build ứng dụng (TypeScript → JavaScript, v.v.)

# Stage 2: PRODUCTION — chỉ lấy kết quả build, bỏ hết devDependencies
FROM node:18-alpine AS production
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000                          # Khai báo port (tài liệu, không tự mở port)
USER node                            # KHÔNG chạy root! (bảo mật quan trọng)
CMD ["node", "dist/main.js"]         # Lệnh mặc định khi container khởi động

Các lệnh Dockerfile quan trọng

LệnhTác dụngLưu ý
FROMBase image để bắt đầuLuôn dùng tag cụ thể (node:18-alpine, không dùng :latest)
WORKDIRĐặt thư mục làm việcTạo tự động nếu chưa có
COPYSao chép file từ host vào imageMỗi COPY tạo 1 layer mới
RUNChạy lệnh trong quá trình buildGộp nhiều lệnh bằng && để giảm layer
CMDLệnh mặc định khi container chạyChỉ có 1 CMD cuối cùng có hiệu lực. Dùng dạng exec: ["node","app.js"]
EXPOSEKhai báo port ứng dụng lắng ngheChỉ là tài liệu, phải dùng -p khi docker run để mở port thực sự
ENVĐặt biến môi trườngTồn tại trong image, dùng cho config
ENTRYPOINTLệnh cố định khi container chạyCMD bổ sung tham số cho ENTRYPOINT

Docker Compose & Networking

# docker-compose.yml — Định nghĩa nhiều container chạy cùng nhau
version: '3.8'
services:
  app:
    build: .                         # Build từ Dockerfile trong thư mục hiện tại
    ports: ["3000:3000"]             # Map port host:container
    environment:
      - DB_HOST=db                   # Gọi service khác bằng TÊN (không cần IP)
    depends_on:
      db:
        condition: service_healthy   # Chờ db healthy rồi mới start app
    restart: unless-stopped          # Tự khởi động lại nếu crash

  db:
    image: mysql:8.0                 # Dùng image có sẵn từ Docker Hub
    volumes:
      - db-data:/var/lib/mysql       # Volume bền vững cho dữ liệu DB
    healthcheck:                     # Kiểm tra DB đã sẵn sàng chưa
      test: mysqladmin ping -h localhost
      interval: 10s

  redis:
    image: redis:7-alpine

volumes:
  db-data:                           # Khai báo named volume

Docker Network — So sánh các loại

Loại NetworkPhạm viĐặc điểmDùng khi
bridge (mặc định)Cùng 1 hostContainers cô lập, gọi nhau qua tên servicePhần lớn trường hợp, docker-compose
hostCùng 1 hostContainer dùng trực tiếp network của host (không cô lập)Cần performance network tối đa
overlayNhiều hostKết nối containers trên các máy khác nhauDocker Swarm, Kubernetes
noneKhông có networkContainer chạy offline, xử lý batch

Chiến lược triển khai (Deployment Strategies)

Blue-Green
Cách hoạt động: Duy trì 2 môi trường giống nhau (Blue = hiện tại, Green = phiên bản mới). Triển khai xong Green thì chuyển Load Balancer sang.
Rollback tức thì (chuyển lại Blue)
Tốn gấp đôi tài nguyên
Canary (Chim hoàng yến)
Cách hoạt động: Triển khai phiên bản mới cho 5% traffic. Theo dõi lỗi/latency. Nếu OK thì tăng dần 10%, 25%, 50%, 100%.
An toàn, phát hiện lỗi sớm
Phức tạp cấu hình
Rolling Update
Cách hoạt động: Cập nhật từng instance một. Instance cũ bị thay thế dần cho đến khi toàn bộ chạy phiên bản mới.
Zero downtime, mặc định trong K8s
Rollback chậm hơn Blue-Green

Git Workflow

Git Flow
main (production) + develop (dev)
+ feature/* + release/* + hotfix/*
Phù hợp dự án có chu kỳ release rõ ràng
Trunk-Based
main + feature ngắn hạn (<2 ngày)
Merge thường xuyên, dùng feature flags
Đang phổ biến — phù hợp CI/CD
GitHub Flow
main + feature branches + Pull Requests
Đơn giản nhất, phù hợp team nhỏ
Conventional Commits: feat: tính năng mới | fix: sửa lỗi | docs: tài liệu | refactor: tái cấu trúc | test: thêm test | chore: công việc phụ

Giám sát hệ thống (3 trụ cột Observability)

Logs (Chuyện gì đã xảy ra)
Structured logging (JSON)
Mức độ: ERROR > WARN > INFO > DEBUG
Công cụ: ELK Stack, Winston, Logback
Metrics (Bao nhiêu / Nhanh thế nào)
Hệ thống: CPU, RAM, Disk, Network
Ứng dụng: RED (Rate, Errors, Duration)
Công cụ: Prometheus + Grafana, TimescaleDB
Traces (Request đi đâu)
Distributed tracing xuyên service
Truyền Request ID qua các service
Công cụ: Jaeger, Zipkin, OpenTelemetry

Bảo mật — Ngữ cảnh Viễn thông (Mobifone IT)

Khía cạnhGiải phápLý do quan trọng với Telecom
Mã hóaAES-256 (lưu trữ), TLS 1.3 (truyền tải)Bảo vệ dữ liệu thuê bao, thông tin cước phí
Xác thựcOAuth 2.0 + MFA (OTP SMS, TOTP)Ngăn truy cập trái phép vào tài khoản khách hàng
eKYCFace matching + OCR + Liveness detectionXác minh danh tính thuê bao theo quy định pháp luật
Audit TrailGhi log mọi hành động (ai, gì, khi nào, ở đâu)Tuân thủ quy định Bộ TT&TT về quản lý thuê bao
Rate LimitingGiới hạn tần suất requestChống brute force, DDoS trên hệ thống OCS/BSS
Data MaskingẨn thông tin nhạy cảm trong log/UISĐT, CCCD, dữ liệu thuê bao phải được che khi hiển thị
SLA hệ thống viễn thông: 99.9% = 8.76 giờ downtime/năm | 99.99% = 52.6 phút | 99.999% = 5.26 phút (mục tiêu viễn thông "five nines")

Cơ sở dữ liệu

H: Index là gì? Khi nào nên dùng?
Bản chất: Index là cấu trúc dữ liệu phụ (thường là B-Tree) giúp tìm kiếm nhanh hơn — giống mục lục cuối sách, thay vì đọc từng trang.
Tăng tốc SELECT, WHERE, JOIN, ORDER BY
Đánh đổi Chậm lại INSERT, UPDATE, DELETE (vì phải cập nhật index)
Nên dùng: Cột thường được query, foreign key, unique constraint
Không nên: Cột ít query, bảng nhỏ, cột có nhiều giá trị NULL
H: Transaction và ACID là gì?
Transaction: Một nhóm thao tác DB phải thành công toàn bộ hoặc thất bại toàn bộ (VD: chuyển tiền = trừ A + cộng B, không được chỉ làm 1 trong 2).

Atomicity (Nguyên tử): Tất cả hoặc không gì cả — nếu 1 bước lỗi thì rollback toàn bộ
Consistency (Nhất quán): Dữ liệu luôn hợp lệ trước và sau transaction
Isolation (Cô lập): Các transaction không ảnh hưởng lẫn nhau khi chạy đồng thời
Durability (Bền vững): Dữ liệu đã commit thì không mất ngay cả khi server crash

Mức cô lập (Isolation Level) — từ thấp đến cao:
Read Uncommitted (đọc dữ liệu chưa commit → dirty read) →
Read Committed (PostgreSQL mặc định — chỉ đọc dữ liệu đã commit) →
Repeatable Read (MySQL mặc định — đọc lại cùng dữ liệu luôn giống nhau) →
Serializable (cô lập hoàn toàn — chậm nhất nhưng an toàn nhất)
H: Khi nào dùng SQL, khi nào dùng NoSQL?
SQL: Dữ liệu có cấu trúc rõ ràng, quan hệ phức tạp (JOIN), cần ACID → Quản lý thuê bao, giao dịch cước phí, tài chính
NoSQL: Schema linh hoạt, cần scale ngang dễ dàng, đọc/ghi nhanh → Log, session, analytics, dữ liệu IoT/5G

Mạng (Networking)

H: HTTP vs HTTPS khác nhau thế nào?
HTTPS = HTTP + TLS encryption. Mọi dữ liệu truyền tải đều được mã hóa.
Quá trình TLS Handshake: Kết nối TCP → Client gửi Hello (hỗ trợ mã hóa gì) → Server gửi Hello + Certificate (chứng chỉ số) → Trao đổi khóa (Key Exchange) → Bắt đầu truyền dữ liệu mã hóa.
H: TCP vs UDP?
TCP (Transmission Control Protocol): Kết nối trước rồi mới truyền, đảm bảo thứ tự và không mất gói tin. Dùng cho: HTTP, database, truyền file.
UDP (User Datagram Protocol): Gửi thẳng không cần kết nối, nhanh nhưng không đảm bảo. Dùng cho: Video streaming, DNS, game online, VoIP.
H: REST vs GraphQL vs gRPC?
REST: Dùng HTTP methods (GET/POST/PUT/DELETE), mỗi resource 1 URL. Đơn giản, cache tốt. Nhược: over-fetching (lấy thừa) hoặc under-fetching (lấy thiếu).
GraphQL: Client chỉ rõ muốn lấy trường nào, 1 endpoint duy nhất. Linh hoạt nhưng phức tạp hơn REST.
gRPC: Dùng Protocol Buffers (binary), nhanh gấp nhiều lần JSON. Hỗ trợ streaming 2 chiều. Phù hợp giao tiếp giữa các microservice.

Đồng thời (Concurrency)

H: Process, Thread và Goroutine khác nhau thế nào?
Process: Vùng nhớ riêng biệt, nặng, giao tiếp qua IPC (Inter-Process Communication). An toàn nhưng tốn tài nguyên.
Thread: Chia sẻ bộ nhớ trong cùng process, nhẹ hơn process. Cần đồng bộ (mutex/lock) để tránh xung đột.
Goroutine (Go): "Luồng siêu nhẹ" — chỉ ~2KB stack, do Go runtime quản lý (không phải OS). Có thể tạo hàng triệu goroutine trên 1 máy.
H: Race condition là gì? Cách xử lý?
Bản chất: Hai hoặc nhiều thread cùng truy cập và sửa đổi dữ liệu chung cùng lúc → kết quả không thể đoán trước, phụ thuộc vào thứ tự thực thi ngẫu nhiên.
Giải pháp: Mutex/Lock (khóa — chỉ 1 thread truy cập tại 1 thời điểm) | Atomic operations (thao tác nguyên tử) | Channel trong Go (giao tiếp thay vì chia sẻ bộ nhớ) | synchronized trong Java
H: Deadlock là gì? Cách tránh?
Bản chất: Hai hoặc nhiều thread chờ nhau giải phóng lock mãi mãi. Thread A giữ lock 1, chờ lock 2. Thread B giữ lock 2, chờ lock 1 → cả hai đứng yên vĩnh viễn.
Cách tránh: Quy ước thứ tự lock (luôn lock theo cùng 1 thứ tự) | Đặt timeout cho lock | Dùng try-lock (thử lock, nếu không được thì bỏ qua) | Tránh lock lồng nhau

🎯 Kiểm tra kiến thức — Random mỗi lần vào

Mỗi lần mở tab này, bộ câu hỏi được xáo trộn ngẫu nhiên. Gồm cả trắc nghiệmtự luận. Trả lời xong bấm "Chấm điểm" để xem kết quả ngay.