Nhắc đến Ninja Code - họ là ai mà khiến cho nhiều người phải khiếp sợ?
Theo bạn, một đoạn mã tốt phụ thuộc vào những yếu tố nào? Code ngắn gọn, dễ hiểu, comment đầy đủ, cú pháp chuẩn, tuân thủ code style, dễ đọc, dễ bảo trì… Có hàng tá chỉ tiêu được nêu ra để định nghĩa một đoạn mã "tốt", trớ trêu thay để đạt được những thứ đó cùng lúc thì quả là một vấn đề nan giải nếu không muốn nói là không thể.
Đơn cử, bạn có thể rút ngắn mã lại để trông nó gọn gàng hơn nhưng có thể gây khó khăn cho quá trình bảo trì sau này, bởi vì cú pháp rút gọn thường sẽ mang đi cả tính minh bạch của code. Bạn có thể comment thật chi tiết nhưng có vẻ nó còn gây rắc rối cho người đọc code, vì comment nhiều quá còn gây nhiễu loạn thông tin…
Đối với tác giả bài viết, mã "tốt" là một thứ gì đó khó có thể đo đếm được. Tùy thuộc vào từng trường hợp mà mã được viết ra được đảm bảo một trong số chỉ tiêu đã nêu ra ở trên.
Trước đây, chúng ta có thể nghe đến nhiều phương pháp để cải thiện kỹ năng viết mã, khiến mã trở nên "tốt" hơn, như tuân thủ các "thực hành tốt nhất" (best practice), tên biến chuẩn chỉ, hàm "thuần khiết" (pure function), giảm thiểu side-effects… Chúng đều được áp dụng trong quãng thời gian viết mã. Tuy nhiên không phải bất kì đâu, bất kì lúc nào cũng có thể áp dụng được. Mà còn phải phụ thuộc vào tình hình thực tế. Ví dụ tính năng cần làm nhanh mà có thời gian giới hạn để kịp cho thời điểm phát hành thì không thể chỉn chu từng li từng tí được, cần phải có một sự hy sinh nào đó.
Hôm nay tình cờ tác giả bài viết đọc được một bài viết có tựa đề là "Ninja Code", lướt qua vài dòng đầu tiên còn không biết ý đồ của người viết là khen hay chê những người theo phong cách "Ninja". Tò mò tìm hiểu thêm về khái niệm này thì hóa ra cụm từ "Ninja Code" đang có ý mỉa mai những người đang theo phong cách này.
"Giống như những Ninja, mã của họ được che giấu một cách hoàn hảo" - đó là một trong những bình luận của người khác khi nhắc đến Ninja Code. Câu nói đó còn có ý nghĩa những người theo phong cách Ninja đang viết ra những dòng mã mà chỉ họ mới có thể hiểu được.
Vậy thì hãy điểm danh xem Ninja Code thường có những "phong cách" gì và sau khi đọc xong bài viết này, liệu bạn có đồng tình với chúng thì hãy đọc tiếp bài viết dưới đây nhé!
Những Ninja thích phong cách "ngắn gọn"#
Làm cho mã càng ngắn càng tốt, điều đó thể hiện trí thông minh của bạn. Đúng vậy, nếu có thể viết ra một logic phức tạp trong giới hạn mã nhất định, rõ ràng điều đó thể hiện khả năng tư duy thượng thừa. Nhưng khoan vội đắc ý, hãy dừng lại một chút để hình dung cảm xúc của người đọc code sau đó. Điều đó giống như là họ đang phải cố nghĩ xem bạn đang nghĩ gì, thay vì nghĩ xem họ nên làm gì. Quá trình đó tiêu tốn một lượng thời gian tỉ lệ thuận với độ phức tạp, và đôi khi nếu không thể luận ra được ý nghĩ thì có thể viết lại hoàn toàn là cách mà họ chọn. Vâng ý tác giả đang muốn nói đến là chúng ta mất quá nhiều thời gian chỉ để đọc hiểu những đoạn code như vậy.
Hãy nhìn đoạn mã dưới đây, bạn có biết nó đang làm gì?
i = i ? i < 0 ? Math.max(0, len + i) : i : 0;
Chắc là sẽ mất một chút thời gian để tính xem i bằng mấy. Việc kết hợp phong cách "ngắn gọn" với cả tên biến rút gọn như i còn làm nhiều người phải bối rối vì thực sự không thể biết đoạn mã trên làm gì.
Những tên biến ngắn gọn, không mang ý nghĩa biểu trưng như i, j, n… cũng là phong cách của Ninja. Nếu có thể, hãy hạn chế việc đặt những tên biến như vậy và thay vào đó đặt cho chúng những cái tên dễ hiểu hơn.
Đôi khi chúng ta còn hay bắt gặp kiểu rút gọn tên như thế này: list→ lst, userAgent→ ua, user -> u… Sẽ không có gì nếu như bạn là một lập trình viên dày dạn kinh nghiệm, hoặc chí ít là bạn đã từng thấy trước đó. Nhưng chuyện gì sẽ xảy ra với một người chưa từng thấy nó, chắc chắn là họ sẽ có thêm kinh nghiệm trước khi tiêu tốn một khoảng thời gian tìm hiểu về phong cách này từ chính các Ninja. Nguy hiểm hơn, nếu như họ thấy cách viết này "khá gọn", tiết kiệm được một chút thời gian gõ phím và quyết định làm theo… Bùm! Một cơ số Ninja nữa xuất hiện.
Việc đặt tên biến trong lập trình đôi khi là một "trở ngại" với nhiều lập trình viên. Không phải ai cũng có suy nghĩ giống nhau, cũng như vốn từ giống nhau, hoặc có thể họ thấy việc nghĩ ra tên biến là "tốn nhiều thời gian" cho những thứ tương tự nhau. Nhưng trên thực tế, tên biến lại đóng vai trò quan trọng cho khả năng đọc hiểu, một tên biến rõ ràng và cụ thể sẽ giúp cho người đọc biết được nó đang nắm giữ dữ liệu gì, từ đó dễ quan sát luồng dữ liệu hơn trong chương trình.
Những Ninja thích phong cách "trừu tượng"#
Biểu hiện này thể hiện ở chỗ họ cố gắng trừu tượng mọi thứ trong mã. Ví dụ đặt ra những tên biến như obj, data, value, item, elem…
Ninja cảm thấy khó khăn trong việc đặt tên biến, vì thế bất kì chỗ nào cần khai báo một đối tượng gì đó, ngay lập tức họ chọn data hoặc một đối tượng thay thế như là obj. Thoạt nhìn, tên biến này bao hàm ý nghĩa là nó chứa một "dữ liệu" gì đó quan trọng nhưng với một cái tên trừu tượng như thế ít nhiều sẽ gây ảnh hưởng đến người đọc code sau này.
Tồi tệ hơn, khi data, obj… đã được dùng mà lại cần thêm đối tượng mới nữa thì sao? Rất đơn giản, chỉ cần thêm số đằng sau tên biến: data1, data2… @@
Để khắc phục phong cách trừu tượng này của một Ninja, bạn có thể dành thời gian suy nghĩ một chút trong việc đặt tên biến, hãy gán nó với ngữ cảnh trong mã, hoặc đặt cho nó một cái tên mà người đọc nhìn vào ít nhất biết nó đang "chứa" cái gì. Ví dụ như listMessages để thể hiện một danh sách Message, messageObj để chỉ một đối tượng Message…
Từ đồng nghĩa#
Sử dụng từ đồng nghĩa cho các tính năng tương tự là một vấn đề không hiếm, nó có thể xuất phát từ việc nhiều người cùng tham gia phát triển, họ có vốn từ định nghĩa riêng để tạo ra các hàm theo suy nghĩ của họ. Nhưng nếu một mình bạn phát triển mà lại tạo ra được vô số hàm như vậy thì chắc chắn bạn là một Ninja.
Chẳng hạn, hãy xem xét đến các tên tiền tố trước mỗi tên hàm. Nếu một tính năng hiển thị thông báo ra màn hình như là một tooltips hay notification bắt đầu bằng display, ví dụ displayMessage. Và sau đó, một chức năng khác thay vì hiện message thì nó hiện ra tên người dùng, nhưng lại bắt đầu bằng show, showName… thế là chúng ta vừa có display và show cùng làm một việc hiển thị, chà có vẻ mọi thứ bắt đầu phức tạp lên rồi đấy.
Thời gian qua dần đi, bạn dần quên mất tiền tố khi xưa, lúc đó là những cái tên mới được thêm vào như render, paint… khiến những người khác khi đọc lại họ phải tự dằn vặt trong câu hỏi "bạn đang muốn làm gì vậy chứ?"
Tóm lại, với những chức năng tương đương, hãy dùng chung một tiền tố. Tiền tố càng rõ ràng càng tốt, ít nhất nó thể hiện được việc sắp làm và không gây nhầm lẫn.
Side-effects ở khắp mọi nơi#
Side-effects thể hiện ở trong các hàm làm thay đổi cả nội dung ở bên ngoài nó. Các hàm Side-effects đôi khi gây khó khăn trong việc đọc hiểu và bảo trì. Nếu đang còn mơ hồ về khái niệm này, bài viết Pure Function trong Javascript. Tại sao chúng ta nên biết càng sớm càng tốt? là dành cho bạn.
Hãy đảm bảo rằng hàm trả lại một giá trị thống nhất và không gây ra Side-effects. Sẽ thật ngạc nhiên nếu như một hàm có tên isAdmin, checkPermission… mà lại thay đổi bất kì dữ liệu gì bên ngoài chúng. Không ai muốn đoán liệu chạy xong một hàm thì những thứ gì bên ngoài đã thay đổi.
Để khắc phục, hãy tạo ra các pure function thay thế. Việc loại bỏ hoàn toàn Side-effects là một điều không thể trong một ứng dụng hiện đại, vì thế hãy tổ chức hàm sao cho phù hợp. Cái nào nên và không nên có Side-effects, cũng như hạn chế những chức năng "vượt mong đợi" như ở dưới đây.
Chức năng "vượt mong đợi"#
Ninja Code thường có xu hướng tạo ra một hàm mạnh mẽ vượt qua cả những gì bạn nghĩ.
Chẳng hạn một hàm có tên validateEmail(email) thay vì kiểm tra định dạng email nó có thể bao gồm cả việc hiển thị thông báo lỗi (alert) và yêu cầu cả nhập lại email!?
Điều gì xảy ra nếu ai đó chỉ muốn kiểm tra định dạng email, và khi họ thấy hàm validateEmail của bạn, họ sẽ dùng thử và nhanh chóng nhận ra nó "vượt ngoài mong đợi", buộc họ phải tạo ra một hàm mới.
Để khắc phục, hãy tập trung vào chức năng của hàm được tạo ra. Nếu tên hàm chỉ bao hàm ý nghĩa kiểm tra định dạng email, hãy để nó thực thi mỗi điều đó. Còn nếu muốn làm nhiều hơn, hãy tạo ra một hàm khác với ý nghĩa làm nhiều hơn so với mỗi việc kiểm tra định dạng.
Tổng kết#
"Ninja Code" là một cụm từ chỉ những lập trình viên viết mã không mấy dễ đọc và hiểu. Họ thường có xu hướng viết mã theo cách của riêng họ, khiến cho những người sau này đọc lại phải bỏ ra nhiều thời gian để hiểu xem thực sự họ đang muốn làm gì. Thú thật, tác giả bài viết đã từng và vẫn đang là Ninja trong một vài trường hợp bất đắc dĩ nào đó. Cái bóng của Ninja vẫn luôn chực chờ để xuất hiện bất cứ lúc nào, nhưng hãy là một Ninja "gà mờ" để đôi khi người khác thấy được bạn!