1. Modular / Feature-based Packaging (Bounded Contexts)
Đóng gói theo module / theo feature (Bounded Context)
Thay vì tổ chức phẳng theo kiểu “controller / service / repository” cho toàn bộ hệ thống, senior dev sẽ nhóm theo domain nghiệp vụ hoặc feature. Ví dụ:
com.myapp.orders
├ api
├ domain
├ service
└ infracom.myapp.users
├ api
├ domain
├ service
└ infra
Why: Giúp dễ hiểu, dễ thay đổi, dễ test theo từng boundary của feature; giảm việc phụ thuộc lan sang các domain khác.
2. Externalize Config and Use Environment-Specific Properties
Tách cấu hình ra ngoài và dùng cấu hình theo môi trường
Duy trì các file như:
application-dev.properties
application-test.properties
application-prod.properties
thay vì trộn tất cả config vào một file hoặc hardcode. Sử dụng cơ chế cấu hình của Spring một cách đúng đắn.
3. Prefer @ConfigurationProperties over Many @Value
Ưu tiên @ConfigurationProperties thay vì dùng nhiều @Value
Dùng để nhóm các config liên quan, đảm bảo type-safe, dễ test và validate hơn. Việc dùng @Value rải rác khắp nơi sẽ khó quản lý.
4. Define Clear Layers / Separation of Concerns
Định nghĩa layer rõ ràng / tách biệt trách nhiệm
Sử dụng Controller – Service – Repository (hoặc tương tự), DTOs, domain entities; controller không chứa business logic; layer infra chỉ xử lý DB hoặc external APIs.
5. Avoid Exposing Internal Domain Entities Directly via API
Tránh expose trực tiếp domain entity ra API
Sử dụng DTO cho request/response; tránh việc gắn chặt contract API với model database nội bộ. Điều này giúp versioning và tránh lộ dữ liệu ngoài ý muốn.
6. Proper Error Handling & Centralized Exception Management
Xử lý lỗi đúng cách và tập trung
Sử dụng @ControllerAdvice, custom exception handler; tránh lộ stack trace hoặc thông tin nhạy cảm. Đảm bảo response lỗi có format nhất quán.
7. Secure by Default
Bảo mật ngay từ đầu
Authentication/Authorization phải được thiết kế kỹ; dùng Spring Security; tránh để endpoint mở; sử dụng security ở mức method. Xử lý các vấn đề như CSRF, CORS, injection,…
8. Infrastructure / External Integrations Abstracted & Interface-oriented
Trừu tượng hóa infra / external integration và thiết kế theo interface
Code tương tác với hệ thống bên ngoài (DB, messaging, external APIs) nên đi qua interface; giúp mock dễ, thay đổi implementation dễ, cải thiện testability. Senior thường tách riêng phần infra nặng. Điều này gắn liền với modularity và layering sạch.
9. Resilience & Fault Tolerance
Khả năng chịu lỗi và chống lỗi
Timeout, circuit breaker, fallback, retry. Đặc biệt trong microservices hoặc khi gọi external service. Luôn chuẩn bị cho trường hợp lỗi, không chỉ happy path.
10. Observability / Monitoring from Day One
Quan sát hệ thống / monitoring ngay từ đầu
Actuator, health endpoint, metrics; logging có cấu trúc (không chỉ System.out); traceability; correlation ID; alerting,… Senior đảm bảo khi hệ thống lỗi, có thể biết chuyện gì đã xảy ra.
11. Automated Testing (Unit + Integration + Possibly End-to-End)
Test tự động
Unit test cho business logic; integration test cho DB hoặc external system; môi trường test; sử dụng Testcontainers,… Tránh chỉ test thủ công.
12. Versioned APIs and Backward Compatibility (if public/external APIs involved)
Version API và tương thích ngược
Duy trì compatibility khi thay đổi API; dùng versioning; tránh làm hỏng client đột ngột. Không phải lúc nào cũng cần, nhưng senior luôn nghĩ trước.
13. Proper Dependency Injection Practices
Thực hành Dependency Injection đúng cách
Ưu tiên constructor injection thay vì field injection; tránh lạm dụng @Autowired; khai báo rõ dependency cần thiết; tránh static / singleton khi không thực sự cần.
14. Clean Up Dead Code & Keep Dependencies Lean
Dọn dẹp code chết và giữ dependency gọn nhẹ
Xóa code không dùng, bean không dùng, dependency dư thừa; tránh classpath phình to; giảm thời gian startup; giữ footprint bộ nhớ hợp lý.
15. Use of Design / Architectural Patterns Appropriately
Sử dụng design pattern / kiến trúc đúng cách
Không dùng pattern chỉ vì “cho có”, mà hiểu khi nào nên dùng Strategy, Factory, Template, Decorator,… hoặc các kiến trúc như clean architecture, hexagonal, onion khi cần.
16. Security and Data Protection in Code & Data
Bảo mật và bảo vệ dữ liệu
Sanitize input; validate ở boundary; tránh SQL injection / query injection; mã hóa dữ liệu nhạy cảm; hash password; masking; kiểm soát truy cập hợp lý.
17. Documentation & Architectural Decision Records (ADR)
Tài liệu và ghi lại quyết định kiến trúc (ADR)
Ghi lại các quyết định quan trọng: tại sao chọn kiến trúc đó, trade-off, cách các module giao tiếp, giả định hệ thống. Document API (Swagger/OpenAPI), contract, config properties.
Why These Matter & Trade-Offs
Tại sao những điều này quan trọng & đánh đổi
- Giúp hệ thống dễ maintain hơn: dễ onboard, dễ thay đổi mà không phá vỡ hệ thống
- Giúp scale tốt hơn: khi codebase, team, traffic tăng
- Giảm bug và hành vi không mong muốn, đặc biệt trên production
Trade-offs:
- Tốn công ban đầu nhiều hơn
- Có thể bị over-engineering nếu áp dụng quá sớm
- Tăng boilerplate
Senior dev sẽ cân bằng:
👉 chỉ áp dụng khi cần
👉 nhưng vẫn dự đoán trước những gì sẽ quan trọng về sau
Be First to Comment