Khi nào team dev bắt đầu có vấn đề
Một team bắt đầu rối không phải khi code nhiều, mà khi ranh giới trách nhiệm mờ đi.
Dấu hiệu rất dễ thấy là:
- backend hỏi frontend nên làm API thế nào
- frontend đòi backend đổi API theo đúng cách frontend đang code
- tester hỏi dev logic rồi lấy câu trả lời miệng đó làm chuẩn để test
- khi lỗi xảy ra thì mọi người bắt đầu đổ qua đổ lại
Nếu để lâu, team sẽ không còn đang xây hệ thống nữa. Team chỉ đang vá từng yêu cầu nhỏ theo người nói to nhất ở thời điểm đó.
Vì sao phải tách bạch Backend, Frontend và Tester
Tách bạch ở đây không có nghĩa là mỗi người làm việc riêng, không nói chuyện với nhau.
Ý đúng là:
- mỗi vai trò có phạm vi quyết định riêng
- mọi trao đổi phải quay về source of truth
- không ai được ép người khác làm thay phần tư duy thuộc trách nhiệm của mình
Nếu không có ranh giới này, hệ thống rất dễ gặp 3 vấn đề:
- API bị thiết kế theo màn hình hiện tại thay vì theo domain
- dữ liệu đầu vào, đầu ra không có contract rõ ràng
- test case lệch với logic gốc của sản phẩm
Backend nên chịu trách nhiệm phần nào
Backend không chỉ là người “trả data ra JSON”.
Backend phải chịu trách nhiệm chính ở các phần:
- business logic
- data contract
- validation đầu vào
- rule xử lý lỗi
- tính nhất quán của API
- security, permission, audit nếu có
Nói ngắn gọn:
- backend quyết định API nên hoạt động ra sao
- backend không nên code theo kiểu “frontend đang muốn gọi thế này thì mình trả tạm thế này”
Frontend có quyền góp ý về tính tiện dùng của API, nhưng không phải người chốt business contract.
Frontend nên chịu trách nhiệm phần nào
Frontend không nên đi quyết định hộ backend logic domain.
Frontend nên chịu trách nhiệm chính ở:
- trải nghiệm người dùng
- flow màn hình
- state management
- cách hiển thị dữ liệu
- cách ghép nhiều API thành một trải nghiệm mượt
- xử lý input trên UI trước khi gửi đi
Nói cách khác:
- frontend có quyền nói
API này đang khó dùng cho màn hình này - nhưng frontend không nên ép backend đổi theo đúng cấu trúc component hoặc state hiện tại của frontend
Nếu frontend thấy API khó dùng, cách đúng là:
- nêu rõ use case
- nêu rõ pain point
- đề xuất thay đổi
- cùng backend review impact
Chứ không phải:
- “anh gộp lại đi để em đỡ code”
Tester nên chịu trách nhiệm phần nào
Tester không nên lấy câu trả lời miệng của dev làm chuẩn cuối cùng cho logic hệ thống.
Tester nên bám vào:
- spec
- acceptance criteria
- API contract
- expected behavior đã được chốt
Tester vẫn có thể hỏi dev để hiểu thêm. Nhưng câu hỏi đó chỉ để làm rõ, không phải để thay thế source of truth.
Nếu không, team rất dễ rơi vào trường hợp:
- tester hỏi backend “đoạn này chạy sao anh?”
- backend trả lời nhanh theo cách hiểu lúc đó
- tester test theo câu trả lời đó
- sau này PO hoặc business bảo logic gốc không phải vậy
Lúc đó bug không còn nằm ở code nữa. Bug nằm ở quy trình xác nhận logic.
Case 1: Frontend đòi gộp getAccount và getAccountDetail
Giả sử backend đang có:
GET /accounts/:idGET /accounts/:id/detail
Frontend nhìn vào và nói:
- “gộp lại thành một API đi cho em đỡ gọi 2 lần”
Đây là chỗ rất nhiều team xử lý sai.
Cách nghĩ sai
- frontend cần gì thì backend gộp theo ngay
- API bị kéo theo nhu cầu của một màn hình cụ thể
- sau vài sprint, backend có rất nhiều endpoint méo mó chỉ để phục vụ từng màn hình
Cách nghĩ đúng
Câu hỏi backend cần trả lời không phải là:
- frontend muốn gì
Mà là:
accountvàaccount detailcó thực sự là cùng một resource boundary không- dữ liệu detail có nặng không
- có phải mọi màn hình đều cần detail không
- gộp lại có làm API chậm, khó cache hoặc khó maintain hơn không
- có nên giải quyết ở query param như
?include=detailthay vì đổi logic resource không
Nói cách khác:
- frontend được quyền nêu vấn đề
- backend phải quyết định theo thiết kế hệ thống, không theo cảm xúc của màn hình
Một cách xử lý tốt hơn thường là:
- giữ
getAccountnhẹ - chỉ load thêm detail khi thật sự cần
- hoặc dùng contract rõ hơn như
GET /accounts/:id?include=detail
Như vậy:
- frontend có dữ liệu đúng lúc cần
- backend vẫn giữ được cấu trúc API sạch
Case 2: Backend không có DTO, frontend gửi sai format rồi đổ thừa nhau
Đây là lỗi rất phổ biến ở team nhỏ hoặc team chạy quá nhanh.
Ví dụ:
- frontend gửi
birthday: "17-06-2026" - backend ngầm nghĩ phải là ISO
2026-06-17 - không có DTO rõ ràng
- không có validation rõ ràng
- không có message lỗi rõ ràng
Kết quả là:
- frontend bảo backend khó tính
- backend bảo frontend gửi sai format
- tester không biết format nào mới đúng
Nếu backend không có DTO thì lỗi thuộc về ai
Trong case này, backend phải nhận phần trách nhiệm lớn hơn.
Lý do:
- backend là nơi chốt contract
- nếu contract không được mô tả rõ, team còn lại không có gì để bám
Backend tối thiểu phải có:
- DTO hoặc schema rõ ràng
- validation rõ ràng
- ví dụ request/response rõ ràng
- error message đủ hiểu
Frontend cũng có trách nhiệm:
- đọc đúng contract
- không tự đoán format
- không gửi dữ liệu “chắc là backend tự hiểu”
Nhưng nếu backend không đưa contract ra ánh sáng, thì việc đổ lỗi cho frontend thường không công bằng.
Case 3: Tester hỏi dev về logic rồi test lệch với logic gốc
Đây là một lỗi quy trình rất khó chịu vì nhìn bề ngoài không ai nghĩ mình làm sai.
Tester chỉ muốn làm nhanh nên hỏi:
- “đoạn này khi user chưa verify email thì có cho update profile không anh?”
Dev trả lời theo trí nhớ:
- “chắc là không”
Tester viết test case theo đó.
Nhưng logic thật trong tài liệu hoặc business rule lại là:
- vẫn cho update một số field
- chỉ chặn một số action nhạy cảm
Kết quả là:
- tester report bug
- dev bảo không phải bug
- PO bảo cả hai hiểu sai
Cách đúng để tránh lệch logic
Nếu logic quan trọng, tester không nên bám vào câu trả lời miệng làm chuẩn cuối cùng.
Thay vào đó nên có một trong các thứ sau:
- acceptance criteria
- API spec
- flow document
- comment xác nhận lại từ PO/BA trên ticket
Dev có thể giải thích để tester hiểu nhanh hơn, nhưng không nên trở thành source of truth duy nhất.
Team nên thống nhất source of truth là gì
Một hệ thống khỏe không dựa trên trí nhớ của từng cá nhân.
Nó phải dựa trên thứ đã được chốt và mọi người cùng nhìn vào.
Tùy team, source of truth có thể là:
- ticket có acceptance criteria rõ
- API spec
- OpenAPI / Swagger
- DTO + validation + sample payload
- flow document
- sequence diagram hoặc state diagram
Điều quan trọng không phải là dùng công cụ nào.
Điều quan trọng là:
- mọi người biết cái nào mới là chuẩn cuối cùng
Cách phối hợp đúng giữa Backend, Frontend và Tester
Một flow lành mạnh thường sẽ như sau:
- Business hoặc PO chốt behavior mong muốn
- Backend thiết kế contract, validation, error format
- Frontend review xem contract có đủ dùng cho UI không
- Nếu có pain point, frontend nêu rõ use case thay vì yêu cầu theo cảm tính
- Backend và frontend thống nhất thay đổi nếu hợp lý
- Tester viết test case dựa trên source of truth đã chốt
- Khi có thay đổi logic, spec phải được cập nhật trước hoặc cùng lúc với code
Flow này chậm hơn vài phút ở đầu, nhưng tiết kiệm rất nhiều giờ cãi nhau ở cuối.
Checklist để team tránh đổ lỗi nhau
- Backend có DTO hoặc schema rõ chưa
- Format date, enum, nullable field đã ghi rõ chưa
- API response có ví dụ cụ thể chưa
- Frontend đã bám đúng contract hay đang tự suy ra
- Tester đang test theo spec hay theo câu trả lời miệng
- Mỗi thay đổi API đã được chốt impact tới frontend và tester chưa
- API đang được thiết kế theo domain hay theo đúng một màn hình
Kết luận
Nếu muốn xây hệ thống bền, team phải tách rõ:
- backend chịu trách nhiệm về logic, contract và validation
- frontend chịu trách nhiệm về trải nghiệm và cách dùng contract đó
- tester chịu trách nhiệm verify theo source of truth đã chốt
Trao đổi giữa các bên vẫn rất cần. Nhưng trao đổi không có nghĩa là lấn vai.
Khi backend bắt đầu code theo cảm tính của frontend, frontend bắt đầu ép backend theo state hiện tại của UI, hoặc tester lấy lời dev làm spec, thì team không còn đang xây hệ thống theo tầm nhìn chung nữa.
Lúc đó hệ thống sẽ chạy theo người nói gần nhất, không chạy theo thiết kế đúng.