Clean Code

Bất kỳ kẻ ngu ngốc nào cũng có thể viết code mà máy tính có thể hiểu

Lập trình viên giỏi là người viết code để con người có thể hiểu.

Martin Fowler, 2008

Chào mừng các bạn đã quay trở lại với thachleblog. Bài viết hôm nay mình sẽ nói về chủ đề Clean Code trong Java. Clean Code là chủ đề tuy không mới nhưng sẽ không bao giờ là cũ. Đối với mỗi người, chắc hẳn ai cũng có lúc “cảm thấy tự hào” với những dòng code của mình. Tuy nhiên, sau một thời gian vài tháng đến một năm, phần lớn khi đọc lại, chúng ta sẽ cảm thấy cái thứ mà mình tự hào trước kia giờ như đống shi* :))).

Do đó, bài viết hôm này mình mong muốn chia sẻ với các bạn 1 vài kinh nghiệm đã học được và áp dụng để code rõ ràng và dễ đọc hơn. Tất nhiên, sẽ rất thiếu sót, do đó, cũng rất mong các bạn cùng chia sẻ để mình cập nhật thêm. Nào, chúng ta cùng bắt đầu nhé.

Nói về lợi ích của Clean Code, rất đơn giản. Code sẽ dễ đọc, ít khả năng gây ra bug và dễ bảo trì, nâng cấp hơn. Vậy làm thế nào để code trở nên “clean”? Dưới đây là vài điều mình đã học được trong cuốn “Clean Code” và trong quá trình làm việc:

– Đặt tên

+ Class, Object nên là danh từ hoặc cụm danh từ

+ Method nên sử dụng động từ hoặc cụm động từ

Class, object, variable, method tốt nhất sẽ cần trả lời được 3 câu hỏi: nó là cái gì (what), nó để làm gì (why) và dùng như thế nào (how).

Tên rất quan trọng, tên rõ ràng sẽ giúp chúng ta hiểu được business của method, class, module một cách dễ dàng. Cùng xem ví dụ sau:

public List<int[]> getThem() {
	List<int[]> list1 = new ArrayList<int[]>();
	for (int[] x : theList)
		if (x[0] == 4)
		list1.add(x);
		return list1;
}

Giả sử bạn debug đến đoạn code này, bạn sẽ nghĩ gì? Các cái tên getThem(), x, list1 củ chuối rồi, còn thêm cái số 4 “huyền bí”, sao lại là “4”? Sẽ mất thời gian để hiểu logic của method trên.
Chúng ta đến với đoạn code khác:

public List<int[]> getFlaggedCells() {
	List<int[]> flaggedCells = new ArrayList<int[]>();
	for (int[] cell : gameBoard)
		if (cell[STATUS_VALUE] == FLAGGED)
		flaggedCells.add(cell);
		return flaggedCells;
}

Đoạn code này có gì khác biệt? Những cái tên rõ ràng hơn, method sẽ có chức năng lấy danh sách những “Cell” được đánh dấu (flagged). Đoạn for thì ra là duyệt tất cả các cell trên gameBoard nếu status là “flagged” thì sẽ “get”. Có vẻ rõ ràng và dễ hiểu hơn. Like!

Tuy nhiên vẫn còn chỗ có thể làm tốt hơn, ta cùng xem đoạn code sau

public List<Cell> getFlaggedCells() {
	List<Cell> flaggedCells = new ArrayList<Cell>();
	for (Cell cell : gameBoard)
		if (cell.isFlagged())
		flaggedCells.add(cell);
		return flaggedCells;
}

Đoạn code sẽ rõ ràng hơn khi ta tạo class Cell thay cho int[].

Chúng ta qua phần tiếp theo

– Không return null

List<Employee> employees = getEmployees();
	if (employees != null) {
		for(Employee e : employees) {
			totalPay += e.getPay();
		}
}

Đối với đoạn code trên, để code “clean” hơn và giảm khả năng xảy ra NullPointerException, chúng ta cần trị ở “gốc”, tức là sẽ không bao giờ return về 1 giá trị null.

Đoạn code getEmployees() sẽ có đoạn như sau:

public List<Employee> getEmployees() {
	if( .. there are no employees .. )
	return Collections.emptyList();
}

– Sử dụng các thư viện

Sử dụng các thư viện (libs) có sẵn NumberUtils, StringUtils, IOUtils, CollectionUtils…. sẽ giúp chúng ta giảm thiểu thời gian code và debug vì đối với libs tốt thì khả năng xảy ra lỗi là rất hiếm. Cùng xem ví dụ đơn giản sau:

 NumberUtils.toInt(studentId, 0)

Đoạn code trên sẽ trả về giá trị mặc định là 0 nếu studentId là null, empty hoặc không hợp lệ. Nếu tự viết, chúng ta sẽ mất thời gian để xử lý những điều trên và đôi khi phát sinh lỗi không đáng có.

– Một vài lưu ý khác

– Sử dụng properties hoặc final variable cho các instant

– Clean đúng nghĩa đen: xóa các packages, classes, methods, fields, parameters, variables không sử dụng. (tránh comment để đó, nhìn rất “gai” ^.^)

– Chia nhỏ method nhất có thể (mỗi method chỉ thể hiện 1 chức năng)

– Viết các method thường được sử dụng thành class Utils để sử dụng lại code, tránh trùng lặp code

Sẽ cập nhật thêm ….

Hẹn gặp lại các bạn ở các bài viết sau.

Tham khảo thêm: Clean Code – Robert C.Martin

 

 

Bảo mật trong Java với MD5 (phần 2)

Chào mừng các bạn đã quay trở lại với thachleblog. Ở bài viết trước, mình đã giới thiệu các cách để tạo MD5 hash trong Java. Mình đã có một ví dụ đơn giản về ứng dụng của MD5 đó là sử dụng để lưu trữ thông tin cho password. Bài viết hôm nay, mình sẽ giới thiệu đến với các bạn một tính năng rất phổ biến hash data đó là bảo đảm tính toàn vẹn của dữ liệu (checksum). Vậy checksum sử dụng như thế nào và cơ chế hoạt động của nó ra sao, chúng ta cùng bắt đầu nhé.

Giới thiệu

Có bao giờ bạn download phần mềm về để ý có phần checksum kèm theo, ví dụ:

checksum.png

Phần checksum này chính là đặc điểm nhận dạng của tập tin mà chúng ta tải về. Với mỗi tập tin này, thuật toán MD5 hoặc SHA256 sẽ tạo ra 1 mã duy nhất gửi kèm theo.

Khi tải về, chúng ta có thể sử dụng các phần mềm tạo mã MD5 hoặc SHA256 (MD5 & SHA Checksum Utility) để tạo ra mã MD5 hoặc SHA256 tương ứng. So sánh mã được cấp kèm theo và mã mà chúng ta tạo ra để đảm bảo là tập tin chúng ta tải về là đúng với tập tin gốc mà bên cung cấp đã gửi (ở trên là tập tin OpenOffice).

Ứng dụng

Trong các ứng dụng thực tế, đối với các request từ client lên server, chúng ta nên sử dụng checksum để bảo vệ tính toàn vẹn của dữ liệu trao đổi giữa client và server.

Ví dụ mình xài Restful với request như sau:

https://xxx.com?username=abc&size=20…&cs=6234a99f04a7077f0662fbb2f2650a00

Giá trị checksum (cs) 6234a99f04a7077f0662fbb2f2650a00 này sẽ được tạo ra từ dữ liệu gửi lên như username, size …. với một công thức nào đó. Trên server sau khi nhận dữ liệu cũng sẽ tạo ra giá trị checksum với công thức tương ứng để kiểm tra là dữ liệu gửi lên từ client không bị mất mát hay “thay đổi”  hay không.

Kết

Qua bài viết này, hy vọng các bạn đã hiểu được ứng dụng của checksum. Từ bây giờ có thể ứng dụng trong các trường hợp gửi file quan trọng (tạo ra hash key và gửi kèm theo cho bên nhận ^.^). Quan trọng hơn hết là hiểu được cơ chế để tạo checksum để tăng tính bảo mật trong ứng dụng client – server.

Ở bài trước, mình giới thiệu phương pháp hash MD5, vì nó đơn giản và được sử dụng rộng rãi (hiện tại dự án mình vẫn xài). Tuy nhiên, đã có phát hiện về lỗ hỗng của MD5, do đó, khi áp dụng các bạn cũng có thể áp dụng trong các phương pháp hash mới bảo mật cao hơn như SHA-2 hoặc SHA256. Cảm ơn ý kiến đóng góp của các bạn và hẹn gặp các bạn ở các bài viết sau.

Bài này cũng viết khá kỹ về checksum, các bạn cũng có thể tham khảo:

http://thegioitinhoc.vn/tin-hoc-can-ban/271557-thegioitinhoc-vn-checksum-la-gi-va-lam-the-nao-de-co-no-tot-nhat.html