Trong quá trình phát triển phần mềm, việc xử lý lỗi không chỉ là một phần quan trọng mà còn ảnh hưởng trực tiếp đến tính ổn định, dễ bảo trì và trải nghiệm người dùng của ứng dụng. Một đoạn mã xử lý lỗi không rõ ràng, rối rắm có thể dẫn đến các hệ quả nghiêm trọng như lỗi khó phát hiện, mất thời gian debug và tăng rủi ro khi mở rộng hoặc chỉnh sửa.
1. Sử dụng exception thay vì trả về mã lỗi
Sử dụng cách trả về mã lỗi để báo lỗi phát sinh trong hàm sẽ làm cho người đọc dễ bị rối do không nhanh chóng xác định được giá trị trả về đó là lỗi hay giá trị thực sự. Vì vậy hãy trả về exception khi gặp phải lỗi thay vì trả về một mã lỗi nào đó.
Ta có ví dụ sau đây:
Việc trả về mã lỗi thường đòi hỏi người gọi phải liên tục kiểm tra giá trị trả về và xử lý từng trường hợp, điều này làm tăng độ phức tạp của mã và dễ dẫn đến các lỗi không mong muốn nếu các mã lỗi không được xử lý triệt để. Thay vào đó, ta nên sử dụng exception:
Exception cho phép tách biệt rõ ràng giữa luồng xử lý chính và xử lý lỗi, giúp mã tập trung vào logic cốt lõi thay vì xử lý lỗi từng bước. Exception còn có khả năng “bubble up,” tức là lan truyền lên các lớp cao hơn mà không cần qua từng hàm trung gian, giúp cho việc xử lý lỗi trở nên linh hoạt hơn.
2. Sử dụng Try-Catch-Finally ngay đầu hàm
Khi sử dụng try-catch-finally, chúng ta có vẻ như đang mong muốn thực hiện một transaction với các hành động chính sẽ nằm trong block của try, còn trong block của catch giống như việc đảm bảo cho trạng thái của hệ thống vẫn giữ được sự nhất quán ngay cả khi có lỗi xảy ra. Vì vậy nên đặt try-catch-finally ở đầu hàm, điều này sẽ làm cho người đọc hiểu được ý định của bạn ngay khi đọc những dòng đầu tiên.
Ta có ví dụ sau:
Hàm sau có thể xảy ra lỗi khi chưa vào bên trong khối try, có thể gây thất thoát lỗi. Do đó ta nên xử lý như sau:
Nhờ cách thực hiện này ta có thể xử lý lỗi sớm và tránh việc chương trình bị gián đoạn.
3. Thêm thông tin về ngữ cảnh cho exception
Khi gặp lỗi, chúng ta nên thêm những thông tin hữu ích về ngữ cảnh mà lỗi đó xảy ra để khi lưu lại thông tin về lỗi đó, lập trình viên sẽ dễ dàng lần theo các thông tin đã lưu và từ đó có thể nhanh chóng xác định nguyên nhân gốc rễ xảy ra lỗi.
+ Định nghĩa các class riêng cho lỗi, người đọc có thể dựa vào tên class hoặc các thuộc tính trong class để có thể hiểu thêm về ngữ cảnh khi xảy ra lỗi.
+ Thêm thông tin vào chuỗi mô tả lỗi.
Ta có ví dụ sau:
Nhờ cách triển khai như vậy, ta có thêm nhiều thông tin về lỗi hơn và dễ dàng xử lý.
4. Không nên trả về null
Khi một hàm có thể trả về null, thì nơi gọi hàm đó sẽ cần phải kiểm tra xem kết quả nhận được có phải null hay không rồi mới có thể xử lý tiếp được. Việc này tạo ra nhiều đoạn kiểm tra trong code mà không thể hiện được các ý định và nội dung chính mà tổng thể của đoạn code đó đang muốn thể hiện.
Ta có ví dụ sau:
Hàm có thể dẫn đến nhiều vấn đề khó kiểm soát như NullPointerExceptions, logic không rõ ràng và dễ gây lỗi trong quá trình phát triển. Thay vào đó ta nên sửa lại:
Thay vì trả về null thì kết quả sẽ trả về dưới dạng một đối tượng kết quả. Từ đó ta dễ kiểm tra, tránh các lỗi của null.
Kết luận
Xử lý lỗi trong Clean Code không chỉ là một phần quan trọng trong việc duy trì tính ổn định và bảo mật của ứng dụng mà còn giúp nâng cao chất lượng mã nguồn. Cần phải tập trung vào việc làm cho mã dễ hiểu, tránh các kỹ thuật gây nhầm lẫn và cung cấp các phản hồi lỗi rõ ràng, chi tiết để người phát triển có thể dễ dàng xử lý và sửa chữa khi cần thiết.