Trong phần trước, chúng ta đã cùng tìm hiểu clean code là gì, các nguyên tắc chung để viết clean code. Trong phần này chúng ta sẽ tìm hiểu một số nguyên tắc cụ thể để viết clean code:

3. Một số nguyên tắc clean code trong lập trình
3.1. Hiệu lực, hiệu quả và đơn giản

Bất cứ khi nào tôi cần nghĩ về cách triển khai một tính năng mới vào một cơ sở mã đã có sẵn hoặc cách giải quyết một vấn đề cụ thể, tôi luôn ưu tiên ba điều đơn giản này.

Hiệu lực
Đầu tiên, mã của chúng ta phải có hiệu lực, nghĩa là nó sẽ giải quyết được vấn đề cần giải quyết. Tất nhiên đây là kỳ vọng cơ bản nhất mà chúng ta có thể có đối với mã của mình, nhưng nếu việc triển khai của chúng ta không thực sự hiệu quả thì việc nghĩ về bất kỳ điều gì khác là vô ích.

Hiệu quả
Thứ hai, khi biết mã của mình giải quyết được vấn đề, chúng ta nên kiểm tra xem nó có hoạt động hiệu quả hay không. Chương trình có chạy bằng lượng tài nguyên hợp lý về mặt thời gian và không gian không? Nó có thể chạy nhanh hơn và có ít không gian hơn không?

Độ phức tạp của thuật toán là điều bạn cần lưu ý để đánh giá điều này. Nếu bạn không quen thuộc với nó, bạn có thể kiểm tra bài viết này tôi đã viết .

Để mở rộng tính hiệu quả, đây là hai ví dụ về hàm tính tổng của tất cả các số trong một mảng.

ví dụ

Việc triển khai hàm sumArrayInefficient lặp lại mảng bằng cách sử dụng một vòng lặp for và thêm từng phần tử vào biến sum. Đây là một giải pháp hợp lệ nhưng không hiệu quả lắm vì nó yêu cầu lặp lại trên toàn bộ mảng, bất kể độ dài của nó.

ví dụ 2

Việc triển khai hàm sumArrayEfficient sử dụng phương thức reduce để tính tổng các phần tử của mảng. Phương thức reduce này áp dụng một hàm cho từng phần tử của mảng và tích lũy kết quả. Trong trường hợp này, hàm chỉ cần thêm từng phần tử vào bộ tích lũy, bắt đầu từ 0.

Đây là một giải pháp hiệu quả hơn vì nó chỉ yêu cầu một lần lặp duy nhất trên mảng và thực hiện thao tác tính tổng trên từng phần tử khi thực hiện.

Sự đơn giản
Và cuối cùng là sự đơn giản . Đây là cách khó đánh giá nhất vì nó mang tính chủ quan, phụ thuộc vào người đọc mã. Nhưng một số hướng dẫn chúng ta có thể làm theo là:

  1. Bạn có thể dễ dàng hiểu được chương trình làm gì ở mỗi dòng không?
  2. Các hàm và biến có tên thể hiện rõ ràng trách nhiệm của chúng không?
  3. Mã có được thụt lề chính xác và cách đều nhau với cùng một định dạng dọc theo cơ sở mã không?
  4. Có tài liệu nào có sẵn cho mã không? Các chú thích có được sử dụng để giải thích các phần phức tạp của chương trình không?
  5. Bạn có thể xác định phần nào của cơ sở mã có các tính năng nhất định của chương trình nhanh đến mức nào? Bạn có thể xóa/thêm các tính năng mới mà không cần sửa đổi nhiều phần khác của mã không?
  6. Mã có tuân theo cách tiếp cận mô-đun, với các tính năng khác nhau được phân tách thành các thành phần không?
  7. Mã có được sử dụng lại khi có thể không?
  8. Các quyết định về kiến trúc, thiết kế và triển khai có được tuân thủ như nhau trong toàn bộ cơ sở mã không?

Bằng cách tuân theo và ưu tiên ba khái niệm về tính hiệu quả, hiệu suất và sự đơn giản này, chúng ta luôn có thể có một hướng dẫn để tuân theo khi nghĩ về cách triển khai một giải pháp. Bây giờ, hãy mở rộng một số nguyên tắc có thể giúp chúng ta đơn giản hóa mã của mình.

3.2. Định dạng và cú pháp

Sử dụng định dạng và cú pháp nhất quán trong toàn bộ cơ sở mã là một khía cạnh quan trọng của việc viết mã sạch. Điều này là do định dạng và cú pháp nhất quán giúp mã dễ đọc và dễ hiểu hơn.

Khi mã nhất quán, nhà phát triển có thể dễ dàng xác định các mẫu và hiểu cách mã hoạt động, điều này giúp việc gỡ lỗi, bảo trì và cập nhật cơ sở mã theo thời gian dễ dàng hơn. Tính nhất quán cũng giúp giảm thiểu sai sót vì nó đảm bảo rằng tất cả các nhà phát triển đều tuân theo các tiêu chuẩn và quy ước giống nhau.

Một số điều chúng ta nên suy nghĩ về định dạng và cú pháp là:

Thụt lề và giãn cách
thụt lề

Ở đây chúng ta có một ví dụ về cùng một hàm, một hàm được thực hiện không thụt lề và giãn cách, còn hàm kia được giãn cách và thụt lề hợp lý. Chúng ta có thể thấy rằng cái thứ hai rõ ràng là dễ đọc hơn.

Cú pháp nhất quán
cú pháp

Một lần nữa, ở đây chúng ta có các hàm rất giống nhau được triển khai với cú pháp khác nhau. Hàm đầu tiên là arrow function, không có dấu chấm phẩy và không trả về, trong khi hàm kia là hàm phổ biến sử dụng dấu chấm phẩy và trả về.

Cả hai đều hoạt động và đều ổn, nhưng chúng ta nên đặt mục tiêu luôn sử dụng cùng một cú pháp cho các hoạt động tương tự, vì nó trở nên đồng đều hơn và dễ đọc hơn trong cơ sở mã.

Linterns và trình định dạng mã là những công cụ tuyệt vời mà chúng ta có thể sử dụng trong các dự án của mình để tự động hóa các quy ước về cú pháp và định dạng trong cơ sở mã của mình. Nếu bạn không quen với công cụ này, hãy xem bài viết khác của tôi .

Quy ước trường hợp nhất quán
quy ước

Điều tương tự cũng xảy ra với quy ước về cách đặt tên mà chúng ta chọn tuân theo. Tất cả những cách này đều hiệu quả, nhưng chúng ta nên đặt mục tiêu sử dụng nhất quán cùng một thứ trong suốt dự án của mình.

3.3. Đặt tên

Đặt tên các biến và hàm một cách rõ ràng và mang tính mô tả là một khía cạnh quan trọng của việc viết clean code. Nó giúp cải thiện khả năng đọc và khả năng bảo trì của cơ sở mã. Khi tên được chọn tốt, các nhà phát triển khác có thể nhanh chóng hiểu biến hoặc hàm đó đang làm gì và nó liên quan như thế nào đến phần còn lại của mã.

Dưới đây là hai ví dụ trong JavaScript chứng minh tầm quan trọng của việc đặt tên rõ ràng và mang tính mô tả:

đặt tên

Trong ví dụ này, chúng ta có một hàm nhận hai tham số, thêm chúng vào giá trị được mã hóa cứng là 10 và ghi kết quả vào console. Tên hàm và tên biến được chọn kém và không đưa ra bất kỳ dấu hiệu nào về chức năng của hàm hoặc biến đại diện cho điều gì.

good naming

Trong ví dụ này, chúng ta có một hàm tính tổng giá của một sản phẩm bao gồm thuế. Tên hàm và tên biến được lựa chọn kỹ lưỡng và đưa ra dấu hiệu rõ ràng về chức năng của hàm và ý nghĩa của các biến.

Điều này giúp mã dễ đọc và dễ hiểu hơn, đặc biệt đối với các nhà phát triển khác có thể sẽ làm việc với cơ sở mã này trong tương lai.

3.4. Sự chính xác vs sự rõ ràng

Khi nói đến việc viết mã sạch, điều quan trọng là phải đạt được sự cân bằng giữa tính ngắn gọn và rõ ràng. Mặc dù điều quan trọng là phải giữ mã ngắn gọn để cải thiện khả năng đọc và bảo trì, nhưng điều quan trọng không kém là đảm bảo mã rõ ràng và dễ hiểu. Viết mã quá ngắn gọn có thể dẫn đến nhầm lẫn và sai sót, đồng thời có thể khiến các nhà phát triển khác khó làm việc với mã đó.

Dưới đây là hai ví dụ chứng minh tầm quan trọng của sự ngắn gọn và rõ ràng:

ngắn gọn

Ví dụ này sử dụng arrow function ngắn gọn và biểu thức chính quy để đếm số nguyên âm trong một chuỗi nhất định. Mặc dù mã rất ngắn và dễ viết nhưng các nhà phát triển khác có thể không hiểu rõ ngay cách thức hoạt động của mẫu biểu thức chính quy, đặc biệt nếu họ không quen với cú pháp biểu thức chính quy.

ví dụ 3;

Ví dụ này sử dụng hàm truyền thống và biểu thức chính quy để đếm số nguyên âm trong một chuỗi nhất định nhưng thực hiện theo cách rõ ràng và dễ hiểu. Tên hàm và tên biến mang tính mô tả và mẫu biểu thức chính quy được lưu trữ trong một biến có tên rõ ràng. Điều này giúp bạn dễ dàng xem chức năng này đang làm gì và hoạt động như thế nào.

Bằng cách sử dụng hàm mô tả và tên biến cũng như sử dụng định dạng và nhận xét mã rõ ràng và dễ đọc, bạn có thể viết mã rõ ràng và ngắn gọn, dễ hiểu và dễ làm việc.

3.5. Khả năng tái sử dụng

Khả năng sử dụng lại mã là một khái niệm cơ bản trong công nghệ phần mềm đề cập đến khả năng mã được sử dụng nhiều lần mà không cần sửa đổi.

Tầm quan trọng của khả năng sử dụng lại mã nằm ở chỗ nó có thể cải thiện đáng kể hiệu quả và năng suất của việc phát triển phần mềm bằng cách giảm số lượng mã cần viết và kiểm tra.

Bằng cách sử dụng lại mã hiện có, nhà phát triển có thể tiết kiệm thời gian và công sức, cải thiện chất lượng và tính nhất quán của mã, đồng thời giảm thiểu rủi ro phát sinh lỗi. Mã có thể tái sử dụng cũng cho phép kiến trúc phần mềm có thể mở rộng và mô-đun hơn, giúp duy trì và cập nhật cơ sở mã theo thời gian dễ dàng hơn.

3.6. Luồng thực thi rõ ràng

Có một luồng thực thi rõ ràng là điều cần thiết để viết mã sạch vì nó giúp mã dễ đọc, dễ hiểu và dễ bảo trì hơn. Mã tuân theo cấu trúc rõ ràng và hợp lý sẽ ít xảy ra lỗi hơn, dễ sửa đổi và mở rộng hơn cũng như hiệu quả hơn về thời gian và tài nguyên.

Mặt khác, mã spaghetti là một thuật ngữ dùng để mô tả mã phức tạp và khó theo dõi, thường có đặc điểm là các khối mã dài, rối rắm và không có tổ chức. Mã spaghetti có thể là kết quả của các quyết định thiết kế kém, sự ghép nối quá mức hoặc thiếu tài liệu và nhận xét phù hợp.

Dưới đây là hai ví dụ về mã JavaScript thực hiện cùng một tác vụ, một ví dụ có luồng thực thi rõ ràng và ví dụ còn lại có mã spaghetti:

ví dụ 4

Như chúng ta có thể thấy, ví dụ 1 tuân theo một cấu trúc rõ ràng và logic, với một hàm nhận các tham số cần thiết và trả về kết quả được tính toán. Mặt khác, ví dụ 2 phức tạp hơn nhiều, với các biến được khai báo bên ngoài bất kỳ hàm nào và nhiều câu lệnh if được sử dụng để kiểm tra xem khối mã có được thực thi thành công hay không.

3.7. Nguyên tắc trách nhiệm duy nhất

Nguyên tắc trách nhiệm duy nhất (Single Responsibility Principle) là một nguyên tắc trong phát triển phần mềm nêu rõ rằng mỗi lớp hoặc mô-đun chỉ được có một lý do để thay đổi, hay nói cách khác, mỗi thực thể trong cơ sở mã của chúng ta phải có một trách nhiệm duy nhất.

Nguyên tắc này giúp tạo mã dễ hiểu, dễ bảo trì và mở rộng.

3.8. Có một “nguồn thông tin chính xác duy nhất”

Có một “nguồn thông tin chính xác duy nhất” có nghĩa là chỉ có một nơi lưu trữ một phần dữ liệu hoặc cấu hình cụ thể trong cơ sở mã và mọi tham chiếu khác đến nó trong mã đều quay trở lại một nguồn đó. Điều này rất quan trọng vì nó đảm bảo dữ liệu nhất quán và tránh trùng lặp và không nhất quán.

Đây là một ví dụ để minh họa khái niệm này. Giả sử chúng ta có một ứng dụng cần hiển thị điều kiện thời tiết hiện tại trong một thành phố. Chúng ta có thể triển khai tính năng này theo hai cách khác nhau:

ví dụ 5

Trong tùy chọn này, khóa API được sao chép thành hai tệp khác nhau, khiến việc duy trì và cập nhật trở nên khó khăn hơn. Nếu cần thay đổi khóa API, chúng tôi phải nhớ cập nhật khóa đó ở cả hai nơi.

ví dụ 6

Trong tùy chọn này, khóa API được lưu trữ ở một nơi (trong tệp weatherAPI.js) và được xuất để các mô-đun khác sử dụng. Điều này đảm bảo rằng chỉ có một nguồn đáng tin cậy cho khóa API và tránh trùng lặp và không nhất quán.

Nếu cần cập nhật khóa API, chúng tôi có thể thực hiện việc đó ở một nơi và tất cả các mô-đun khác sử dụng khóa đó sẽ tự động nhận được giá trị cập nhật.

3.9. Chỉ hiển thị và sử dụng dữ liệu bạn cần

Một nguyên tắc quan trọng của việc viết mã sạch là chỉ hiển thị và sử dụng thông tin cần thiết cho một nhiệm vụ cụ thể. Điều này giúp giảm độ phức tạp, tăng hiệu quả và tránh các lỗi có thể phát sinh do sử dụng dữ liệu không cần thiết.

Khi dữ liệu không cần thiết bị lộ hoặc tiêu thụ, nó có thể dẫn đến các vấn đề về hiệu suất và khiến mã khó hiểu và khó bảo trì hơn.

Giả sử bạn có một đối tượng có nhiều thuộc tính nhưng bạn chỉ cần sử dụng một vài thuộc tính trong số đó. Một cách để làm điều này là tham chiếu đối tượng và các thuộc tính cụ thể mỗi khi bạn cần chúng. Nhưng điều này có thể trở nên dài dòng và dễ xảy ra lỗi, đặc biệt nếu đối tượng được lồng sâu. Một giải pháp sạch hơn và hiệu quả hơn sẽ là sử dụng tính năng hủy đối tượng để chỉ hiển thị và sử dụng thông tin bạn cần.

3.10. Mô-đun hóa

Mô-đun hóa là một khái niệm thiết yếu trong việc viết mã sạch. Nó đề cập đến việc chia nhỏ mã lớn, phức tạp thành các mô-đun hoặc chức năng nhỏ hơn, dễ quản lý hơn. Điều này làm cho mã dễ hiểu, kiểm tra và bảo trì hơn.

Việc sử dụng mô-đun hóa mang lại một số lợi ích như:

Khả năng sử dụng lại: Các mô-đun có thể được tái sử dụng trong các phần khác nhau của ứng dụng hoặc trong các ứng dụng khác, tiết kiệm thời gian và công sức trong quá trình phát triển.
Đóng gói: Các mô-đun cho phép bạn ẩn các chi tiết bên trong của một chức năng hoặc đối tượng, chỉ hiển thị giao diện thiết yếu với thế giới bên ngoài. Điều này giúp giảm sự ghép nối giữa các phần khác nhau của mã và cải thiện chất lượng mã tổng thể.
Khả năng mở rộng: Bằng cách chia nhỏ mã lớn thành các phần mô-đun nhỏ hơn, bạn có thể dễ dàng thêm hoặc xóa chức năng mà không ảnh hưởng đến toàn bộ cơ sở mã.

Đây là một ví dụ trong JavaScript về một đoạn mã thực hiện một tác vụ đơn giản, một đoạn mã không sử dụng mô-đun hóa và đoạn mã còn lại triển khai mô-đun hóa.

ví dụ 6

Trong ví dụ trên, hàm calculatePrice được sử dụng để tính tổng giá của một mặt hàng dựa trên số lượng, giá và thuế suất của nó. Tuy nhiên, chức năng này không được mô đun hóa và được kết hợp chặt chẽ với logic đầu vào và đầu ra của người dùng. Điều này có thể gây khó khăn cho việc kiểm tra và bảo trì.

Bây giờ, hãy xem một ví dụ về cùng một mã bằng cách sử dụng mô-đun hóa:

ví dụ 7

Trong ví dụ trên, hàm calculatePrice đã được chia thành hai hàm nhỏ hơn: calculateSubtotal và calculateTotal. Các hàm này hiện được mô-đun hóa và chịu trách nhiệm tính toán tổng phụ và tổng tương ứng. Điều này làm cho mã dễ hiểu, kiểm tra và bảo trì hơn, đồng thời giúp mã có thể tái sử dụng nhiều hơn trong các phần khác của ứng dụng.

Mô-đun hóa cũng có thể đề cập đến thực tiễn chia các tệp mã đơn lẻ thành nhiều tệp nhỏ hơn mà sau này được biên dịch lại thành một (hoặc ít tệp hơn). Việc thực hành này có những lợi ích tương tự như chúng ta vừa nói đến.

3.11. Cấu trúc thư mục

Chọn cấu trúc thư mục tốt là một phần thiết yếu của việc viết mã sạch. Cấu trúc dự án được tổ chức tốt giúp các nhà phát triển tìm và sửa đổi mã dễ dàng, giảm độ phức tạp của mã và cải thiện khả năng mở rộng và bảo trì dự án.

Mặt khác, cấu trúc thư mục kém có thể gây khó khăn cho việc hiểu kiến trúc của dự án, điều hướng cơ sở mã và dẫn đến nhầm lẫn và sai sót.

3.12. Tài liệu

Tài liệu là một phần thiết yếu của việc viết mã sạch. Tài liệu phù hợp không chỉ giúp nhà phát triển đã viết mã hiểu mã tốt hơn trong tương lai mà còn giúp các nhà phát triển khác đọc và hiểu cơ sở mã dễ dàng hơn. Khi mã được ghi chép đầy đủ, nó có thể tiết kiệm thời gian và công sức trong việc gỡ lỗi và duy trì mã.

Việc ghi lại tài liệu đặc biệt quan trọng trong những trường hợp không thể triển khai các giải pháp đơn giản và dễ hiểu, những trường hợp logic nghiệp vụ khá phức tạp và những trường hợp những người không quen với cơ sở mã phải tương tác với nó.

Một cách để ghi lại mã là sử dụng các nhận xét. Nhận xét có thể cung cấp ngữ cảnh và giải thích mã đang làm gì. Nhưng điều quan trọng là phải sử dụng bình luận một cách khôn ngoan, chỉ bình luận khi cần thiết và tránh những bình luận dư thừa hoặc không cần thiết.

Một cách khác để ghi lại mã là sử dụng tài liệu nội tuyến. Tài liệu nội tuyến được nhúng trong chính mã và có thể được sử dụng để giải thích chức năng hoặc đoạn mã cụ thể thực hiện. Tài liệu nội tuyến thường được sử dụng kết hợp với các công cụ như JSDoc , công cụ này cung cấp tiêu chuẩn cho việc ghi lại mã bằng JavaScript.

Các công cụ như Swagger và Postman có thể được sử dụng để ghi lại các API, cung cấp một cách dễ dàng để hiểu cách tương tác với chúng

Kết thúc
Như mọi khi, tôi hy vọng bạn thích bài viết này và học được điều gì đó mới.

Nguồn: https://www.freecodecamp.org/news/how-to-write-clean-code/#naming