SOLID - Ghi nhớ nhanh
| S | Single 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. |
|---|---|
| O | Open/Closed — Mở để 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ũ. |
| L | Liskov 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. |
| I | Interface Segregation — Không ép client phụ thuộc vào interface mà nó không sử dụng. Chia nhỏ interface. |
| D | Dependency 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áp | Bản chất |
|---|---|---|
| Đọc nhiều (read-heavy) | Cache (Redis) + Read Replicas | Giảm tải DB bằng bản sao chỉ đọc + cache tầng ứng dụng |
| Ghi nhiều (write-heavy) | Message Queue + Sharding | Xếp hàng xử lý bất đồng bộ + chia nhỏ dữ liệu theo khóa |
| Cả đọc lẫn ghi | CQRS | Tách riêng mô hình đọc/ghi, mỗi bên tối ưu riêng |
| Người dùng toàn cầu | CDN + Multi-region | Đưa nội dung tĩnh gần người dùng, deploy nhiều vùng |
| Thời gian thực | WebSocket + Event-driven | Kết nối 2 chiều liên tục, server đẩy dữ liệu ngay khi có |
| Dữ liệu lớn | Stream processing + NoSQL | Xử 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-O | Tên gọi | Ví dụ | Bản chất |
|---|---|---|---|
O(1) | Hằng số | HashMap lookup, truy cập mảng theo index | Thời gian không đổi dù dữ liệu bao nhiêu |
O(log n) | Logarit | Tìm kiếm nhị phân, cây cân bằng BST | Mỗi bước loại bỏ một nửa dữ liệu |
O(n) | Tuyến tính | Duyệt mảng, linked list | Duyệt từng phần tử một lần |
O(n log n) | Tuyến tính logarit | Merge sort, Quick sort (trung bình) | Chia để trị + gộp kết quả |
O(n²) | Bình phương | Bubble sort, 2 vòng lặp lồng nhau | Mỗ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ĩa | Mã thường gặp |
|---|---|---|
| 1xx | Thông tin | 101 Switching Protocols (nâng cấp lên WebSocket) |
| 2xx | Thành công | 200 OK • 201 Đã tạo • 204 Không có nội dung trả về |
| 3xx | Chuyển hướng | 301 Chuyển vĩnh viễn • 302 Tạm thời • 304 Chưa thay đổi (dùng cache) |
| 4xx | Lỗi phía client | 400 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 |
| 5xx | Lỗi phía server | 500 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
| S | Cô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. |
|---|---|
| T | Tô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 |
| R | Hệ 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
| S | Hệ 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. |
| A |
• Stream 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 |
| R | Tố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
| S | Cầ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. |
|---|---|
| T | Xâ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 |
| R | Giá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
| S | Cổ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. |
|---|---|
| T | Tự xây dựng toàn bộ luồng eKYC từ đầu. |
| A |
• Facemesh: 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 |
| R | Luồ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)
• Đ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
• 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
• 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
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ì?
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
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
10 phút | Sơ đồ + Components
→
3. Đi sâu chi tiết
15 phút | DB + API + Scaling
15 phút | DB + API + Scaling
→
4. Điểm nghẽn & đánh đổi
5 phút | SPOF + Trade-offs
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án | Cơ chế | Khi nào dùng |
|---|---|---|
| Round Robin | Chia đều request luân phiên cho từng server | Các server cấu hình giống nhau |
| Weighted Round Robin | Server mạnh nhận nhiều request hơn (theo trọng số) | Server cấu hình khác nhau |
| Least Connections | Gửi đến server đang có ít kết nối nhất | Request xử lý lâu, thời gian không đều |
| IP Hash | Cùng IP luôn đến cùng server | Cầ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
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 writeDữ 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ộ sauGhi 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.
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 nhauKey-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ểm | Khi nào dùng |
|---|---|---|
| RabbitMQ | Message 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 |
| Kafka | Distributed log, throughput cực cao, lưu trữ message lâu dài | Event streaming, xử lý dữ liệu lớn, audit log |
| Redis Pub/Sub | Nhẹ, 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ậpScale 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)
• 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)
• 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ầnD — 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:
• NestJS:
• Constructor Injection là phổ biến nhất và dễ test nhất (truyền mock qua constructor)
• 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ột | Bản chất | Ví 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 BankAccount có private 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 / publicGetter / 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() và 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 Class | Interface |
|---|---|---|
| Chứa code thực thi? | Có — có thể có method có body | Không — chỉ khai báo method (Java 8+ cho phép default) |
| Kế thừa | Chỉ kế thừa 1 abstract class (đơn kế thừa) | Implement nhiều interface (đa kế thừa) |
| Constructor? | Có | Không |
| Access modifier? | Có thể dùng private, protected | Mặ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 class | Giữa lớp cha và lớp con |
| Tên method? | Giống nhau | Giố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ó là Độ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 có Độ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
Express, Spring, DB
→
Adapters
Controllers, Gateways
Controllers, Gateways
→
Use Cases
Nghiệp vụ ứng dụng
Nghiệp vụ ứng dụng
→
Entities
Nghiệp vụ cốt lõi
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ụ.
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
Khởi tạo
→
onBeforeMount
→
onMounted
DOM sẵn sàng, fetch data
DOM sẵn sàng, fetch data
→
onBeforeUpdate
→
onUpdated
DOM đã cập nhật
DOM đã cập nhật
→
onUnmounted
Dọn dẹp! (clearInterval...)
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) |
computed | computed() | Giá trị tính toán tự cập nhật khi dependency thay đổi |
methods | Hàm thường | Các hàm xử lý sự kiện, logic |
watch | watch(), watchEffect() | Theo dõi thay đổi dữ liệu. watchEffect tự detect dependency |
mounted | onMounted() | Chạy sau khi DOM render xong |
beforeUnmount | onBeforeUnmount() | 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
• 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
Khởi tạo logic
→
Bean sẵn sàng
→
@PreDestroy
Dọn dẹp
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
Auth, CORS
→
DispatcherServlet
→
Interceptor
Validation
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
• 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
• 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)
• 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ệm | Bản chất | Tương tự OOP | Chi tiết |
|---|---|---|---|
| Image | Template chỉ đọc, bất biến (immutable) | Class | Gồ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. |
| Container | Instance đang chạy từ image | Object | Có 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). |
| Dockerfile | File chỉ dẫn build image | Constructor | Mỗ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). |
| Volume | Lưu trữ bền vững | External storage | Dữ liệu tồn tại ngay cả khi container bị xóa. Dùng cho DB data, upload files, logs. |
| Network | Kết nối giữa containers | Mạng LAN ảo | Containers trong cùng docker-compose gọi nhau bằng tên service (VD: db:3306) |
| Registry | Kho lưu trữ images | Package registry | Docker 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 Container | Virtual Machine |
|---|---|---|
| Kiến trúc | Chia sẻ kernel OS của host, chỉ cô lập ở tầng ứng dụng | Mỗi VM có OS riêng hoàn toàn (Guest OS) |
| Kích thước | Nhẹ — vài chục MB (alpine image ~5MB) | Nặng — vài GB (cả OS) |
| Khởi động | Giây | Phút |
| Hiệu năng | Gần như native (không overhead ảo hóa phần cứng) | Chậm hơn do hypervisor |
| Cô lập | Cô 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 khi | Microservices, CI/CD, dev environment, deploy nhanh | Cầ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ệnh | Tác dụng | Lưu ý |
|---|---|---|
FROM | Base image để bắt đầu | Luôn dùng tag cụ thể (node:18-alpine, không dùng :latest) |
WORKDIR | Đặt thư mục làm việc | Tạo tự động nếu chưa có |
COPY | Sao chép file từ host vào image | Mỗi COPY tạo 1 layer mới |
RUN | Chạy lệnh trong quá trình build | Gộp nhiều lệnh bằng && để giảm layer |
CMD | Lệnh mặc định khi container chạy | Chỉ có 1 CMD cuối cùng có hiệu lực. Dùng dạng exec: ["node","app.js"] |
EXPOSE | Khai báo port ứng dụng lắng nghe | Chỉ 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ường | Tồn tại trong image, dùng cho config |
ENTRYPOINT | Lệnh cố định khi container chạy | CMD 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 Network | Phạm vi | Đặc điểm | Dùng khi |
|---|---|---|---|
| bridge (mặc định) | Cùng 1 host | Containers cô lập, gọi nhau qua tên service | Phần lớn trường hợp, docker-compose |
| host | Cùng 1 host | Container dùng trực tiếp network của host (không cô lập) | Cần performance network tối đa |
| overlay | Nhiều host | Kết nối containers trên các máy khác nhau | Docker Swarm, Kubernetes |
| none | — | Không có network | Container 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 serviceTruyề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ạnh | Giải pháp | Lý do quan trọng với Telecom |
|---|---|---|
| Mã hóa | AES-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ực | OAuth 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 |
| eKYC | Face matching + OCR + Liveness detection | Xác minh danh tính thuê bao theo quy định pháp luật |
| Audit Trail | Ghi 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 Limiting | Giới hạn tần suất request | Chống brute force, DDoS trên hệ thống OCS/BSS |
| Data Masking | Ẩn thông tin nhạy cảm trong log/UI | SĐ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
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)
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
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.
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.
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.
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.
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ớ) |
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
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ệm và tự luận. Trả lời xong bấm "Chấm điểm" để xem kết quả ngay.