- Sự khác biệt giữa code bẩn và code sạch
- Hàm bạn đã viết có “đúng chuẩn” Clean code ?
- Ngộ ra comment code phải chăng đều là thừa thãi
Chào mọi người, tiếp tục với series những gì mà mình đã học được từ sách Clean code. Không biết mình đã nói chưa, toàn bộ các bài viết trong series này đều do mình mới vừa học được trong tuần vừa rồi. Nên viết luôn vào đây cho nóng kẻo não cá vàng nhanh quên lắm :))
Như tiêu đề, vấn đề nóng nhất ngày hôm nay là coder-nào-cũng-từng-viết-rồi-đấy đó chính là hàm.
Bạn thử nhìn lại xem mỗi hàm của bạn có kích thước bao nhiêu, có đến 20 hay 30 dòng chưa hay là hơn nữa ? Bạn đã từng nghĩ việc phải chia nhỏ nó ra chưa ? Những câu hỏi này nghe đơn giản nhưng nó cực kỳ hữu ích nếu bạn muốn nâng tầm cỡ những dòng code của mình. Một ví dụ nhỏ như sau:
public void changePassword(String oldPass, String newPass, Database db) { // kiểm tra xem passmới có giống pass cũ không // kiểm tra xem có đủ 8 ký tự // kiểm tra xem có ký tự số chưa // kiểm tra xem có chữ hoa chưa // kiểm tra xem có ký tự đăc biệt chưa // nếu đúng hết thì đi tiếp, ko thì thôi // connect to database // cập nhật password mới } }
Cái nhìn đầu tiên cực kỳ quan trọng, mỗi cái dấu comment kia là một đoạn code và khi đó nhìn vào hàm changePassword() đó thì khá là mệt khi đó hàm này rất dài và rối mắt. Hơn hết chúng đã vi phạm nguyên lí SOLID, cụ thể là nguyên lí Single Responsibility Đây là một trong những nguyên lí quan trọng, mình đã viết thành một series SOLID. Như vậy bạn cần chia ra các hàm nhỏ để nhìn được dễ hơn và thân thiện hơn. Do đó bạn cần đến một yêu cầu cho các dòng code này là “DO ONE THING“, nghĩa là sao, mỗi hàm chỉ thực hiện 1 công việc duy nhất và đương nhiên nếu bạn muốn thay đổi nó thì bạn chỉ có 1 lí do duy nhất để thay đổi vì nó chỉ thực hiện đúng 1 nhiệm vụ nào đó. Như vậy mình sẽ chia nhỏ hàm này ra thành các hàm như sau:
if (checkNewPasswordIsOK(oldPass, newPass)) { changePassword(newPass); } public void changePassword(String oldPass, String newPass, Database db) { String SQL_CHANGE_PASS = "UPDATE ..."; new Database().update(SQL_CHANGE_PASS); } public String checkNewPasswordIsOK(String oldPass, String newPass) { //chạy các hàm check password bên dưới } public boolean checkOldPassSameAsNewPass(String oldPass, String newPass) { } public boolean checkPasswordIncludeNumber(String pass) { } public boolean checkPasswordLength(String pass) { } public boolean checkPasswordIncludeUpperLetter(String pass) { }
Mỗi hàm chỉ có một nhiệm vụ duy nhất, nếu bên trong nó đang làm nhiều hơn 1 việc thì bạn hãy chia nhỏ nó ra, và đương nhiên các hàm được chia nhỏ hãy cố gắng để chúng có chung một mức độ, và đặt ngay dưới hàm lớn. Bạn hãy nhớ lấy điều này:
FUNCTIONS SHOULD DO ONE THING. THEY SHOULD DO IT WELL. THEY SHOULD DO IT ONLY.
Bạn có thể nhìn các hàm mình viết bên trên, hoàn toàn không cần comment hay document cho mấy hàm này làm gì cả, cùng lắm là document cho cả cái class là chính thôi. Tại sao vậy, tên các hàm của mình rất là dài, viết rất là lâu nên đương nhiên rõ nghĩa rồi, dài ngang cái comment luôn rồi. Nhưng bạn đừng lo lắng chuyện này, bạn chỉ viết dài lần đầu và các IDE thông minh sẽ gợi ý code cho bạn lần sau, do vậy mà đừng ngần ngại viết một cái tên rõ nghĩa, một cái tên dài thì tốt hơn cái tên ngắn thiếu nội dung, một cái tên dài cũng tốt hơn một dòng comment dài. Hãy chú ý dùng những cái tên này với một quy ước nhất định để có thể dễ đọc và dễ nhớ hơn. Đừng ngần ngại việc mất thời gian để chọn một cái tên tốt, mình cũng cần thay đổi tên một vài lần trước khi có cái tên cuối cùng và dùng tổ hợp phím trong các IDE để thay đổi toàn bộ tên trong toàn bộ project. Thông thường, một hàm sẽ biểu thị một hành động nào đó, ví dụ như changePassword(), runAway()… do đó cấu trúc chung thường là động từ + danh từ và tránh các từ thừa thãi, ví dụ như trong môn cơ sở dữ liệu có việc dư thừa gì đấy mình không nhớ mà khi bỏ một vài ký tự thì không làm ảnh hưởng đến nội dung của hành động mà hàm thực hiện.
Đừng bao giờ lặp lại những gì đã viết. Có thể trong một function bạn làm rất dài và khó đọc, bạn khó có thể nhận ra được điểm chung của các dòng code vì chúng không hẳn có một cấu trúc hoàn toàn giống nhau nhưng hãy cố gắng đưa chúng vào một hàm khác. Giả sử bạn có 5 đoạn code giống nhau thì nếu cần sửa bạn sẽ phải tìm đủ 5 đoạn này và sửa chúng, thật bất tiện và không khoa học. Đây chính là nguồn gốc của những thứ gọi là “rác” trong đóng code đó của bạn.
Như vậy các function cần có một vài yếu tố quan trọng đó là ngắn, một cái tên mang đầy đủ ý nghĩa và có một cấu trúc tốt, dễ đọc. Mỗi developer giỏi đều coi mỗi hệ thống như một câu chuyện được kể hơn là nó được viết bởi lập trình viên. Một câu chuyện khó hiểu thì chẳng ai thèm đọc cả, hãy cố gắng làm nó trở nên thân thiện với con người hơn. Nếu bạn đang gặp phải những điều mình nói ở trên thì mình khuyên bạn nên nghiền ngẫm series nguyên lí SOLID của mình và đọc thêm sách Clean Code, chắc chắn khả năng của bạn cũng sẽ tăng đáng kể.