thảo luận Best practice cho việc throw exception?

//Mình code C#
Mình có 1 số thắc mắc về việc throw exception trong code sau.

Bài toán đặt ra là project mình là web api, có các layer là controller => service => repository.

1. Khi validate business logic, ví dụ validate mật khẩu user sai/ đúng thì khi sai có nên throw exception không ? Nếu không throw thì sẽ viết code xử lý trường hợp sai như nào

2. Mình hay nghe senior team mình nói throw sai có thể làm lost stack trace khó debug, mình không hiểu ý này có bác nào giải thích mình với

3. Nên viết catch exception ở layer nào? Khi nào nên re-throw lại exception?
 
Sửa lần cuối:
Với cá nhân mình :
1. Có, nhưng với case của bạn thì nên throw chung chung kiểu invalid credentials thôi

2. Chưa hiểu chỗ này lắm, dù là throw sai nhưng khi check stacktrace thì vẫn ra được line gây lỗi chứ? Chỉ là throw sai thì phán đoán sẽ sai thôi.
Ví dụ: Validate số tài khoản không hợp lệ nhưng lại báo thông tin khách hàng không hợp lệ chẳng hạn.

3. ở layer bussinese, mỗi loại exception sẽ là các class khác nhau được catch tại 1 ExceptionHander chung cho toàn hệ thống, đẻ đảm bảo throw ra theo format thống nhất ( error code, error message ) & có thể ngăn chặn việc throw ra các exception hệ thống như kiểu câu SQL chạy lỗi chẳng hạn

Thường thì mình sẽ có một cái catch thằng Exception chung (Java), log stack trace ra (phục vụ việc trace log) trước khi throw 1 lỗi chung dạng 500 Internal Server Error
 
Với cá nhân mình :
1. Có, nhưng với case của bạn thì nên throw chung chung kiểu invalid credentials thôi

2. Chưa hiểu chỗ này lắm, dù là throw sai nhưng khi check stacktrace thì vẫn ra được line gây lỗi chứ? Chỉ là throw sai thì phán đoán sẽ sai thôi.
Ví dụ: Validate số tài khoản không hợp lệ nhưng lại báo thông tin khách hàng không hợp lệ chẳng hạn.

3. ở layer bussinese, mỗi loại exception sẽ là các class khác nhau được catch tại 1 ExceptionHander chung cho toàn hệ thống, đẻ đảm bảo throw ra theo format thống nhất ( error code, error message ) & có thể ngăn chặn việc throw ra các exception hệ thống như kiểu câu SQL chạy lỗi chẳng hạn

Thường thì mình sẽ có một cái catch thằng Exception chung (Java), log stack trace ra (phục vụ việc trace log) trước khi throw 1 lỗi chung dạng 500 Internal Server Error
Chưa hiểu ý 3 của thím lắm. Có phải ý thím là mỗi loại exception sẽ có 1 class riêng kế thừa từ class Exception không ? Ví dụ mình sẽ tạo các class như InvalidCredentialException, NotEnoughAmountException => rồi sẽ có 1 class trong app bắt toàn bộ các exception này => sau đó ghi log từng lỗi 1, ví dụ không đủ tiền, sai thông tin đăng nhập => rồi trả về cho front end một lỗi chung chung kiểu internal error
 
Exception để bắt lỗi không lường trước được, chứ nó có dùng để bắt lỗi validate đâu bác. Mặt khác throw exception là 1 hành động tốn nhiều cpu resource

Gửi từ Xiaomi M2101K6G bằng vozFApp
 
Chưa hiểu ý 3 của thím lắm. Có phải ý thím là mỗi loại exception sẽ có 1 class riêng kế thừa từ class Exception không ? Ví dụ mình sẽ tạo các class như InvalidCredentialException, NotEnoughAmountException => rồi sẽ có 1 class trong app bắt toàn bộ các exception này => sau đó ghi log từng lỗi 1, ví dụ không đủ tiền, sai thông tin đăng nhập => rồi trả về cho front end một lỗi chung chung kiểu internal error
Xanh thì đúng rồi, nhưng cũng không cần quá chi tiết, có thể gom thành những nhóm lỗi chung kiểu DataInvalidException, AccountBussinessException, khi throw ra thì sẽ phân biệt chi tiết hơn bằng error code và message
Còn đỏ thì chưa đúng ý mình. trường hợp các exception mình định nghĩa riêng kia thì cứ throw ra như bình thường, còn các exception mà ko thuộc những cái mình định nghĩa, mình ko control được thì nên throw dạng lỗi chung

Anw, chủ đề này khá hay, cắm cọc chờ học hỏi từ cao nhân
 
Exception để bắt lỗi không lường trước được, chứ nó có dùng để bắt lỗi validate đâu bác. Mặt khác throw exception là 1 hành động tốn nhiều cpu resource

Gửi từ Xiaomi M2101K6G bằng vozFApp
Đúng rồi bác mình cũng từng nghe ông lead team mình nói không throw exception vô tội vạ vì tốn tài nguyên
 
nếu không throw thì làm sao các bác bắt lỗi trả về từ business layer cho api layer để xử lý nhỉ, cái này em không biết thật

trước gì dùng go nên xử lý lỗi khá cụ thể, c# với java thì chưa rõ đoạn này lắm
 
nếu không throw thì làm sao các bác bắt lỗi trả về từ business layer cho api layer để xử lý nhỉ, cái này em không biết thật

trước gì dùng go nên xử lý lỗi khá cụ thể, c# với java thì chưa rõ đoạn này lắm
bạn có thể tham khảo Result pattern, trả về status code + response thôi, ko throw exception
Nếu vậy thì 100% nên dùng throw à bác ? Thế thằng throw ex có ưu điểm gì hơn thằng kia vậy
ko phải 100% xài throw, mà một khi bạn đã throw new Exception() ở layer dưới cùng (Repository ở trường hợp của bạn) thì khi các layer bên trên (Service) muốn xử lý exception này (bắn event, audit...) nhưng ko muốn mất stacktrace khi log thì phải throw thay vì throw ex
 
bạn có thể tham khảo Result pattern, trả về status code + response thôi, ko throw exception

ko phải 100% xài throw, mà một khi bạn đã throw new Exception() ở layer dưới cùng (Repository ở trường hợp của bạn) thì khi các layer bên trên (Service) muốn xử lý exception này (bắn event, audit...) nhưng ko muốn mất stacktrace khi log thì phải throw thay vì throw ex
Đó là khi
bạn có thể tham khảo Result pattern, trả về status code + response thôi, ko throw exception

ko phải 100% xài throw, mà một khi bạn đã throw new Exception() ở layer dưới cùng (Repository ở trường hợp của bạn) thì khi các layer bên trên (Service) muốn xử lý exception này (bắn event, audit...) nhưng ko muốn mất stacktrace khi log thì phải throw thay vì throw ex
Ý mình hỏi là các tầng service sẽ báo cho tầng api có lỗi xảy ra kiểu gì
 
Đó là khi

Ý mình hỏi là các tầng service sẽ báo cho tầng api có lỗi xảy ra kiểu gì
bạn trả về status code + 1 response object cho API, API sẽ trả cho client status + response object.
Thay vì switch case exception thì bạn sẽ có 1 base controller và switch case status code.
Theo ngu kiến của mình thì API chỉ nên handle http code, exception sẽ để middleware xử lý, business/DA layer chỉ throw exception khi nó thật sự là "exception" (network error, 3rd party api tạch...)
 
có 2 loại lỗi là error/lỗi và exception/ngoại lệ. Error là cái dễ xảy ra hơn exception. Exception thì phải chạy 1000 lần có 1 lần bị lỗi thì mới gọi là exception. Có câu "exception must be exceptional". Ngoại lệ phải là chuyện gì thặc khó có thể xảy ra được mới gọi là ngoại lệ. Error thì sao cũng được.
Validate password sai mà bảo là ngoại lệ thì bị khùng à
3916-pepedumb.png
khác mẹ gì bảo viết hàm kiểm tra 1 số có phải số nguyên tố ko có nên trả về ngoại lệ ko khi số đó là số nguyên tố. Trả về đúng/sai hoặc error code valid/invalid rồi if else check thôi
Dcnffay.png


if/else vs try/catch thì có trade off cả. If else thì luôn tốn 1 so sánh, branch prediction gì đó có thể coi là 5-10 cpu cycle đi. Còn try/catch thì nếu ko có ngoại lệ sẽ ít hơn branch prediction, cho là mất khoảng 2-4 cycle đi, nhưng nếu gặp ngoại lệ sẽ tốn 1000 cycle. Nếu tỉ lệ gặp "ngoại lệ" lên tới 50% thì code chạy tốn 500 cycle mỗi lần try/catch, chậm hơn if/else 100 lần, nên mới có câu nói throw ngoại lệ chậm lắm. Vì vậy throw ngoại lệ phải thực sự là ngoại lệ tỉ lệ 1/1000 xảy ra thì mới throw để try/catch lẹ hơn if/else, mà code dễ đọc hơn, còn tỉ lệ lỗi cao quá thì trả về error code rồi dùng if/else mà check.
 
Sửa lần cuối:
có 2 loại lỗi là error/lỗi và exception/ngoại lệ. Error là cái dễ xảy ra hơn exception. Exception thì phải chạy 1000 lần có 1 lần bị lỗi thì mới gọi là exception. Error thì sao cũng được.
Validate password sai mà bảo là ngoại lệ thì bị khùng à
3916-pepedumb.png
khác mẹ gì bảo viết hàm kiểm tra 1 số có phải số nguyên tố ko có nên trả về ngoại lệ ko khi số đó là số nguyên tố. Trả về đúng/sai hoặc error code valid/invalid rồi if else check thôi
Dcnffay.png


if/else vs try/catch thì có trade off cả. If else thì luôn tốn 1 so sánh, branch prediction gì đó có thể coi là 5-10 cpu cycle đi. Còn try/catch thì nếu ko có ngoại lệ sẽ ít hơn branch prediction, cho là mất khoảng 2-4 cycle đi, nhưng nếu gặp ngoại lệ sẽ tốn 1000 cycle. Nếu tỉ lệ gặp "ngoại lệ" lên tới 50% thì code chạy tốn 500 cycle mỗi lần try/catch, chậm hơn if/else 100 lần, nên mới có câu nói throw ngoại lệ chậm lắm. Vì vậy throw ngoại lệ phải thực sự là ngoại lệ tỉ lệ 1/1000 xảy ra thì mới throw để try/catch lẹ hơn if/else, mà code dễ đọc hơn, còn tỉ lệ lỗi cao quá thì trả về error code rồi dùng if/else mà check.
Đúng này. Ngoại lệ là khi các đầu vào k có gì quá bất thường (vì bất thường mình đã validate) nhưng bằng cách nào đó nó lại throw ra Exception thế mới hay
sWrf7ov.png
 
nếu không throw thì làm sao các bác bắt lỗi trả về từ business layer cho api layer để xử lý nhỉ, cái này em không biết thật

trước gì dùng go nên xử lý lỗi khá cụ thể, c# với java thì chưa rõ đoạn này lắm

Trên Prod thì không cần xử lý nhiều, vì khi throw exception thì sẽ có middleware ghi log rồi. API chỉ cần đơn giản trả về error 500 rồi dev đọc log để xử lý thôi.
 
Trên Prod thì không cần xử lý nhiều, vì khi throw exception thì sẽ có middleware ghi log rồi. API chỉ cần đơn giản trả về error 500 rồi dev đọc log để xử lý thôi.
ý tầng business gặp lỗi kiểu validation, not found thì phải trả về api layer để nó trả lại status code phù hợp chứ bác, ý em là mấy cái lỗi như thế còn lỗi kiểu null, disconnect thì có 1 lớp middleware để catch là chắc chắn rồi
 
có 2 loại lỗi là error/lỗi và exception/ngoại lệ. Error là cái dễ xảy ra hơn exception. Exception thì phải chạy 1000 lần có 1 lần bị lỗi thì mới gọi là exception. Có câu "exception must be exceptional". Ngoại lệ phải là chuyện gì thặc khó có thể xảy ra được mới gọi là ngoại lệ. Error thì sao cũng được.
Validate password sai mà bảo là ngoại lệ thì bị khùng à
3916-pepedumb.png
khác mẹ gì bảo viết hàm kiểm tra 1 số có phải số nguyên tố ko có nên trả về ngoại lệ ko khi số đó là số nguyên tố. Trả về đúng/sai hoặc error code valid/invalid rồi if else check thôi
Dcnffay.png


if/else vs try/catch thì có trade off cả. If else thì luôn tốn 1 so sánh, branch prediction gì đó có thể coi là 5-10 cpu cycle đi. Còn try/catch thì nếu ko có ngoại lệ sẽ ít hơn branch prediction, cho là mất khoảng 2-4 cycle đi, nhưng nếu gặp ngoại lệ sẽ tốn 1000 cycle. Nếu tỉ lệ gặp "ngoại lệ" lên tới 50% thì code chạy tốn 500 cycle mỗi lần try/catch, chậm hơn if/else 100 lần, nên mới có câu nói throw ngoại lệ chậm lắm. Vì vậy throw ngoại lệ phải thực sự là ngoại lệ tỉ lệ 1/1000 xảy ra thì mới throw để try/catch lẹ hơn if/else, mà code dễ đọc hơn, còn tỉ lệ lỗi cao quá thì trả về error code rồi dùng if/else mà check.
tại sao thrown ex nó lại tốn tới 1000 cycle vậy thím, cái này hay nè, code thì đẹp hơn if/else mà performance thì tệ thế nhỉ ?

Có lẽ giờ CPU quá mạnh rồi, nên dev ko quan tâm vụ này lắm, trừ khi nó quá chậm.
 

Thống kê chủ đề

Ngày tạo
Lập Trình Viên Trẻ,
Người trả lời cuối
nchhnchh,
Trả lời
85
Lượt xem
16.464
Quay lại
Lên đầu trang