30 ngày jav

Mình thấy bài viết hay quá nên đọc và viết lại, chủ yếu để mình và các bạn viết code có nguyên tắc, dễ đọc, dễ hiểu, dễ bảo trì và code tái sử dụng hơn, mình có tham khảo tại

https. //github. com/hienvd/clean-code-javascript/

https. //github. com/ryanmcdermott/clean-code-javascript

Giới thiệu

Các nguyên tắc kỹ thuật phần mềm, từ cuốn sách Clean Code của Robert C. Martin's, được áp dụng cho ngôn ngữ JavaScript. Đây không phải là một hướng dẫn về cách viết mã Javascript mà là hướng dẫn về cách viết các đoạn mã dễ đọc, tái sử dụng và tái cấu trúc được trong Javascript

Không phải mọi nguyên tắc nghiêm trọng ở đây đều phải được tuân thủ một cách nghiêm ngặt, và thậm chí chỉ có một số ít trong số đó được sử dụng phổ biến. Ở đây, nó chỉ là một hướng dẫn - không hơn không kém, nhưng chúng là hệ thống hóa thông tin qua kinh nghiệm được thu thập qua nhiều năm của các tác giả của cuốn sách Clean Code

Ngành kỹ thuật phần mềm chỉ phát triển đã hơn 50 năm, và chúng ta vẫn đang học rất nhiều. Một khi kiến ​​trúc phần mềm trở nên phổ biến, có thể sau đó chúng ta sẽ có thêm nhiều luật lệ khó hơn phải tuân theo. Còn lại đây, hãy đi theo những hướng dẫn này như một tiêu chuẩn để đánh giá chất lượng các đoạn mã Javascript mà bạn và nhóm của bạn tạo ra.

Biết những hướng dẫn này thôi sẽ không thể ngay lập tức khiến bạn trở thành một lập trình viên phần mềm tốt hơn được, và làm việc với họ trong nhiều năm cũng không có nghĩa là bạn sẽ không gặp bất kỳ sai lầm nào. Mỗi đoạn mã bắt đầu như một bản thảo đầu tiên, giống như đất sét được làm môi và cho đến cuối cùng thì nó sẽ lộ ra một hình hài. Cuối cùng, chúng ta gọt tỉa những điểm còn thiếu khi chúng ta xem xét lại nó cùng với các đồng nghiệp. Đừng để bản thân bạn bị đánh bại bởi những thảo luận đầu tiên, thứ mà vẫn cần phải được chỉnh sửa. Thay vào đó hãy đánh bại những dòng mã

Áp dụng

Variation

Sử dụng tên biến có nghĩa

  • không tốt
// yyyymmdd là cái gì ??
const yyyymmdd = moment[].format['YYYY/MM/DD'];
  • Tốt
// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];

Sử dụng cùng từ vựng cho cùng một loại biến

  • không tốt
getUserInfo[];
getClientData[];
getCustomerRecord[];
  • Tốt
getUser[];

Sử dụng các tên dễ hiểu và tìm kiếm được

Chúng ta sẽ đọc mã nhiều hơn là viết chúng. Điều quan trọng là mã chúng tôi viết có thể đọc được và tìm kiếm được. Việc đặt tên các biến không có nghĩa vì vậy với chương trình, chúng ta có thể sẽ khiến người đọc mã bị tổn thương tinh thần. Hãy làm cho tên biến của bạn có thể tìm kiếm được. Các công cụ như bạn thân. js và ESLint có thể giúp nhận ra các hằng số chưa được đặt tên

  • không tốt
// 86400000 là cái quái gì thế?
setTimeout[blastOff, 86400000];
  • Tốt
// MILLISECONDS_IN_A_DAY chúng ta hiểu phải không các bạn 
const MILLISECONDS_IN_A_DAY = 86400000;

setTimeout[blastOff, MILLISECONDS_IN_A_DAY];

Theo mình thì nên có 1 thư mục [ directory ] để định nghĩa các hằng số dùng chung này

Sử dụng các biến có thể giải thích được

  • không tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;

// mình đọc cái đống này thật ra cũng không hiểu
saveCityZipCode[address.match[cityZipCodeRegex][1], address.match[cityZipCodeRegex][2]];
  • Tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;
const [, city, zipCode] = address.match[cityZipCodeRegex] || [];

// đến đây thì mình hiểu đó là city và zipCode truyền vào
saveCityZipCode[city, zipCode];

Bảo vệ không gây hại cho người khác

Trước giờ, không riêng gì trong lập trình mà mọi vấn đề vẫn tồn tại trong cuộc sống, nếu rõ ràng thì tất nhiên nó vẫn sẽ dễ hiểu hơn

  • không tốt
________số 8
  • Tốt
const locations = ['Austin', 'New York', 'San Francisco'];
locations.forEach[[location] => {
  // ...
  // Hiểu cái `l` lúc nãy là cái gì rồi phải không các bạn :P
  dispatch[location];
}];

Don't add the contexts not essential

Nếu tên của lớp [ lớp ], tên của đối tượng đã nói lên điều gì đó, ít nhất nó là cái gì thì không cần phải lặp lại nó trong tên biến [ biến ]

  • không tốt
// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
0
  • Tốt
// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
1

Sử dụng các tham số mặc định còn hơn là kiểm tra

  • không tốt
// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
2
  • Tốt
// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
3

Giăm bông

Đối số của hàm [lý tưởng là ít hơn hoặc bằng 2]

Tham số number [ tham số ] truyền vào 1 hàm là điều cực kỳ quan trọng. Nó làm cho bạn ít nhất cũng dễ nhìn hơn, dễ test hơn, Trong trường hợp có nhiều hơn 3 thông số có thể khiến bạn phải test hàng tấn test case khác nhau với những đối số riêng biệt

1 hoặc 2 tham số là lý tưởng cho 1 hàm, nhưng có trường hợp bất khả kháng thì cũng đành chấp nhận, tốt nhất là nên tránh truyền nhiều hơn 2 tham số, những trường hợp từ 3 tham số, chúng ta nên hạn lại

Thông thường thì công việc truyền càng nhiều tham số cho hàm, hàm đó sẽ càng xử lý nhiều công việc hơn

Kể từ khi Javascript cho phép tạo nhiều Object một cách nhanh chóng, mà không cần nhiều class có sẵn, bạn có thể sử dụng một Object mà bạn cần truyền nhiều tham số

To wait for clear a function mong muốn thuộc tính gì, bạn có thể sử dụng cấu trúc phá hủy cấu trúc của ES6. Điều này có một số điểm ưu tiên

  1. Khi ai đó nhìn vào chức năng, những thuộc tính nào được sử dụng sẽ trở nên rõ ràng ngay lập tức
  2. Destructuring cũng sao chép lại các giá trị ban đầu được chỉ định của tham số đối tượng được truyền vào hàm. Điều này có thể giúp ngăn chặn ảnh hưởng phụ. Chú thích. các Object và mảng được hủy cấu trúc từ Object param thì không được sao chép lại
  3. Linter có thể sẽ cảnh báo bạn về những thuộc tính không sử dụng, điều không thể xảy ra nếu không có sự phá hủy
  • không tốt
// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
4
  • Tốt
// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
5

Hàm chỉ nên giải quyết một vấn đề

Đây là quy định quan trọng nhất của kỹ thuật phần mềm. Khi một hàm thực hiện nhiều hơn 1 công việc, chúng sẽ trở nên khó khăn hơn để viết code, test và suy luận

Khi bạn có thể tách biệt một hàm để chỉ thực hiện một hành động, thì sẽ dễ dàng hơn để tái tạo cấu trúc và mã của bạn sẽ dễ đọc hơn nhiều. Nếu bạn chỉ cần làm theo hướng dẫn này thôi mà không cần làm gì khác thì bạn cũng đã giỏi hơn nhiều nhà phát triển khác rồi

  • không tốt
// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
6
  • Tốt
// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
7

Tên chức năng phải nói ra được những gì họ làm

Nhìn vào tên hàm thôi mà chính bạn hay người khác cũng hiểu mục đích của hàm đó làm gì

  • không tốt
// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
8
  • Tốt
// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
9

Hàm chỉ nên có một lớp vật liệu

Khi có nhiều hơn một lớp phụ, chức năng của bạn đang làm quá nhiều. Chia nhỏ các hàm ra sẽ làm cho công việc kiểm tra và tái sử dụng dễ dàng hơn

  • không tốt
getUserInfo[];
getClientData[];
getCustomerRecord[];
0
  • Tốt
getUserInfo[];
getClientData[];
getCustomerRecord[];
1

Dimiting code

Việc có hai hàm xử lý cùng một chức năng như nhau thì là việc phải tránh, đó là mã trùng lặp. code trùng lặp thì không tốt bởi vì nếu bạn cần thay đổi cùng một logic, bạn phải sửa ở nhiều nơi hơn

Hãy tưởng tượng nếu bạn điều hành một nhà hàng và bạn theo dõi hàng tồn tại. bao gồm cà chua, hành tây, tỏi, gia vị, vv. Nếu bạn có nhiều danh sách quản lý, thì tất cả chúng phải được thay đổi khi bạn phục vụ một món ăn có chứa cà chua. Nếu bạn chỉ có 1 danh sách, thì việc cập nhật ở một nơi thôi

Thông thường, bạn có những dòng mã lặp lại bởi vì bạn có 2 hay nhiều hơn những thứ chỉ khác nhau một chút, mà chia sẻ nhiều thứ chung, nhưng sự khác nhau của chúng buộc bạn phải có 2 hay nhiều hàm riêng biệt để . Xóa đi những dòng mã trùng lặp có nghĩa là tạo ra một trừu tượng có thể xử lý các tập tin điểm khác biệt này chỉ với một hàm/mô-đun hoặc lớp

Có một sự trừu tượng đúng thì rất quan trọng, đó là lý do tại sao bạn nên chấp hành các nguyên tắc RẮN được đặt ra trong phần lớp. Những trừu tượng không tốt có thể còn tệ hơn cả những dòng mã bị lặp, vì thế hãy cẩn thận. Nếu bạn có thể tạo ra một sự trừu tượng tốt, hãy làm nó. Đừng quay lại chính mình, nếu bạn không muốn đi cập nhật nhiều nơi bất cứ khi nào bạn muốn thay đổi một thứ gì đó

  • không tốt
getUserInfo[];
getClientData[];
getCustomerRecord[];
2
  • Tốt
getUserInfo[];
getClientData[];
getCustomerRecord[];
3

Thiết lập các đối tượng mặc định với Object. giao phó

  • không tốt
getUserInfo[];
getClientData[];
getCustomerRecord[];
4
  • Tốt
getUserInfo[];
getClientData[];
getCustomerRecord[];
5

Don't use the flags as a number of function

Các biến cờ cho người dùng của bạn biết rằng chức năng thực hiện nhiều hơn một công việc. function only should doing a task. Vì vậy hãy tách hàm của bạn nếu chúng đang làm cho mã phụ dựa trên một biến boolean

  • không tốt
getUserInfo[];
getClientData[];
getCustomerRecord[];
6
  • Tốt
getUserInfo[];
getClientData[];
getCustomerRecord[];
7

Don't use the flags as a number of function

Một chức năng tạo ảnh hưởng phụ nếu nó làm bất kỳ điều gì khác hơn là nhận một giá trị ban đầu và trả về một hoặc nhiều giá trị. Ảnh hưởng phụ có thể là ghi một tệp, thay đổi một vài biến toàn cục hoặc vô tình bạn đã trả tất cả tiền cho một người lạ

Bây giờ, cũng có khi bạn cần ảnh hưởng phụ trong một chương trình. Giống như ví dụ trước, bạn cần ghi một tập tin. Những gì bạn cần làm là tập trung vào nơi bạn sẽ làm nó. Don't viết hàm và lớp riêng biệt để tạo ra một tệp cụ thể. Hãy có một dịch vụ để viết nó. One and only one

Điểm chính là để tránh những lỗi chung như chia sẻ trạng thái giữa các đối tượng mà không có cấu trúc bất kỳ, việc sử dụng các kiểu dữ liệu có thể thay đổi được mà có thể được viết bởi bất cứ thứ gì và không . Nếu bạn có thể làm được điều đó, bạn sẽ cảm thấy hạnh phúc hơn với phần lớn các lập trình viên khác đấy

  • không tốt
getUserInfo[];
getClientData[];
getCustomerRecord[];
8
  • Tốt
getUserInfo[];
getClientData[];
getCustomerRecord[];
9

Tránh những ảnh hưởng phụ [phần 2]

Trong JavaScript, các kiểu cơ bản được truyền theo giá trị và các đối tượng/mảng được truyền theo tham chiếu. Trong trường hợp các đối tượng và mảng, ví dụ: nếu hàm của chúng ta tạo ra thay đổi trong một mảng giỏ mua hàng, ví dụ: thêm một sản phẩm để mua, thì bất kỳ hàm nào khác mà sử dụng mảng 'giỏ hàng' sẽ . Điều này có thể tốt, tuy nhiên nó cũng có thể trở nên tồi tệ. Vui lòng tưởng tượng trường hợp xấu sau

Người sử dụng nhấp chuột "Mua hàng", nút mua hàng sẽ gọi tới hàm mua, cái mà sinh ra một yêu cầu mạng và gửi giỏ lên máy chủ. Do nối kết chậm, chức năng mua có thể tiếp tục thử lại yêu cầu. Bây giờ, nếu trong thời gian đó người sử dụng vô tình nhấn chuột vào nút "Thêm vào giỏ hàng" ở một sản phẩm mà họ không thực sự muốn trước khi mạng thực hiện yêu cầu?

Một giải pháp tốt là chức năng thêm sản phẩm vào giỏ hàng luôn luôn tạo ra một sao của giỏ, thay đổi nó và trả về bản sao đó. Điều này chắc chắn không có chức năng nào có phụ kiện giữ tham chiếu của giỏ mua hàng bị ảnh hưởng bởi bất kỳ sự thay đổi nào

Hai lưu ý cho cách tiếp cận này

  1. Có thể có những trường hợp mà bạn thực sự muốn thay đổi đối tượng ngay từ đầu, nhưng khi bạn áp dụng phương pháp này, bạn sẽ thấy những trường hợp này thì mới lạ. Hầu hết các vấn đề có thể được cấu trúc lại để không còn ảnh hưởng phụ
  2. Nhân bản các đối tượng lớn có thể ảnh hưởng đến hiệu năng. May mắn thay, đó không phải là một vấn đề lớn trong thực tế bởi vì có immutable-js cho phép cách tiếp cận này trở nên nhanh chóng và ít bộ nhớ hơn khi bạn tự sao chép các đối tượng và mảng
  • không tốt
getUser[];
0
  • Tốt
getUser[];
1

Don't write up the global functions

Việc lướt ảnh ảnh hưởng đến các biến toàn cục là một cách làm không tốt trong JavaScript vì bạn có thể xung đột với các thư viện khác và người dùng API của bạn sẽ không biết trước khi xảy ra sự cố trên sản phẩm.

Hãy suy nghĩ ví dụ này. Điều gì xảy ra nếu bạn muốn mở rộng phương thức của Array trong JavaScript gốc để có thể có một hàm

// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
84 chỉ khác nhau giữa hai mảng? . Điều gì xảy ra nếu thư viện đó chỉ sử dụng
// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
84 để tìm sự khác biệt giữa phần tử đầu tiên và phần cuối cùng của một mảng?

  • không tốt
getUser[];
2
  • Tốt
getUser[];
3

Ủng hộ lập trình chức năng hơn là lập mệnh lệnh

JavaScript không phải là ngôn ngữ lập trình hàm giống như Haskell, nhưng nó có chức năng đặc trưng của nó. Những ngôn ngữ lập trình hàm thì gọn gàng và dễ kiểm tra hơn. Vui lòng sử dụng cách thiết lập chương trình này khi bạn có thể

  • không tốt
getUser[];
4
  • Tốt
getUser[];
5

Đóng gói các điều kiện

  • không tốt
getUser[];
6
  • Tốt
getUser[];
7

Điều kiện hủy bỏ tiêu cực

  • không tốt
getUser[];
8
  • Tốt
getUser[];
9

Điều kiện thoát

This way as a job any time. Khi nghe điều này đầu tiên, hầu hết mọi người đều nói, "Làm sao tôi phải làm gì mà không có mệnh đề nếu?"

Câu hỏi thứ hai thường là "Đó là điều tốt nhưng tại sao tôi lại muốn làm điều đó?" . one function only should done a job. Khi bạn có nhiều lớp và hàm mà có nhiều mệnh đề

// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
87, bạn đang cho người dùng của mình biết rằng hàm của bạn đang làm nhiều hơn một công việc. Hãy nhớ, chỉ làm một công việc thôi

  • không tốt
// 86400000 là cái quái gì thế?
setTimeout[blastOff, 86400000];
0
  • Tốt
// 86400000 là cái quái gì thế?
setTimeout[blastOff, 86400000];
1

Checkout type [phần 1]

JavaScript không định dạng, có nghĩa là hàm của bạn có thể nhận bất kỳ đối số kiểu nào. Đôi khi bạn được cám dỗ bởi sự tự do này và dễ dàng dẫn đến công việc kiểm tra kiểu trong chức năng của mình. Có nhiều cách để tránh phải làm điều này. Điều đầu tiên là xem xét sử dụng các API quán nhất

  • không tốt
// 86400000 là cái quái gì thế?
setTimeout[blastOff, 86400000];
2
  • Tốt
// 86400000 là cái quái gì thế?
setTimeout[blastOff, 86400000];
3

Check type check [phần 2]

Nếu bạn đang làm việc với các kiểu cơ bản như chuỗi, số nguyên và mảng, và bạn không thể sử dụng đa hình nhưng bạn vẫn cảm thấy cần phải kiểm tra kiểu, bạn nên xem xét việc sử dụng TypeScript. Nó là một phương pháp thay thế tuyệt vời cho JavaScript thông thường, bởi vì nó cung cấp kiểu tĩnh bên ngoài cú pháp JavaScript chuẩn. Vấn đề liên quan đến việc kiểm tra kiểu thủ công là để làm tốt công việc này yêu cầu nhiều dòng dài mà "kiểu an toàn" giả mạo này không thay thế được cho việc mất tính dễ đọc của mã. Hãy giữ mã JavaScript của bạn sạch sẽ, viết bài kiểm tra tốt và có mã đánh giá tốt. Nếu không thì thực hiện tất cả những điều đó nhưng với TypeScript [giống như tôi đã nói, đó là sự thay thế tốt. ]

  • không tốt
// 86400000 là cái quái gì thế?
setTimeout[blastOff, 86400000];
4
  • Tốt
// 86400000 là cái quái gì thế?
setTimeout[blastOff, 86400000];
5

Don't too minimum

Các trình duyệt hiện đại làm rất nhiều tối ưu hóa bên dưới trong thời gian chạy. Rất nhiều lần, nếu bạn là người tối ưu, thì bạn đang làm thời gian của chính mình. Xem ở đây để biết khi nào công việc tối ưu hóa bị thiếu. Hãy thực hiện những điều tối thiểu đó và cho đến khi chúng được chỉnh sửa nếu có thể

  • không tốt
// 86400000 là cái quái gì thế?
setTimeout[blastOff, 86400000];
6
  • Tốt
// 86400000 là cái quái gì thế?
setTimeout[blastOff, 86400000];
7

Xóa mã chết [mã chết]

Mã chết tệ cũng như mã trùng lặp. Không có lý do gì để giữ chúng lại trong codebase của bạn. Nếu nó không được gọi nữa, hãy bỏ nó đi. Nó vẫn sẽ nằm trong lịch sử phiên bản của bạn nếu bạn vẫn cần nó

  • không tốt
// 86400000 là cái quái gì thế?
setTimeout[blastOff, 86400000];
8
  • Tốt
// 86400000 là cái quái gì thế?
setTimeout[blastOff, 86400000];
9

Object and Constructor data

Use getter and setter

JavaScript không có

// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
88 hoặc kiểu vì rất khó để thực hiện mô hình này, bởi vì chúng ta không có các từ khóa như
// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
89 và
// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
90. Vì vậy, sử dụng
// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
91 và
// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
92 để truy cập dữ liệu trên các đối tượng thì tốt hơn là chỉ đơn giản là tìm kiếm một thuộc tính trên một đối tượng. Bạn có thể hỏi "Tại sao?"

This is a list of lí do at sao

  1. Khi bạn muốn thực hiện nhiều hơn việc lấy thuộc tính của đối tượng, bạn không cần phải tìm kiếm và thay đổi từng
    // ít nhất thì mình vẫn hiểu đây là ngày hiện tại
    const currentDate = moment[].format['YYYY/MM/DD'];
    
    93 trong cơ sở mã của bạn
  2. Làm cho việc bổ sung các đơn xác nhận đơn giản khi thực hiện trên một tập hợp
  3. Đóng các gói biểu tượng nội bộ
  4. Nhanh chóng thêm nhật ký và xử lý lỗi khi
    // ít nhất thì mình vẫn hiểu đây là ngày hiện tại
    const currentDate = moment[].format['YYYY/MM/DD'];
    
    94 và
    // ít nhất thì mình vẫn hiểu đây là ngày hiện tại
    const currentDate = moment[].format['YYYY/MM/DD'];
    
    95
  5. Kế thừa lớp này, bạn có thể
    // ít nhất thì mình vẫn hiểu đây là ngày hiện tại
    const currentDate = moment[].format['YYYY/MM/DD'];
    
    96 các hàm mặc định
  6. Bạn có thể lazy load các thuộc tính của một đối tượng, lấy nó từ máy chủ
  • không tốt
// MILLISECONDS_IN_A_DAY chúng ta hiểu phải không các bạn 
const MILLISECONDS_IN_A_DAY = 86400000;

setTimeout[blastOff, MILLISECONDS_IN_A_DAY];
0
  • Tốt
// MILLISECONDS_IN_A_DAY chúng ta hiểu phải không các bạn 
const MILLISECONDS_IN_A_DAY = 86400000;

setTimeout[blastOff, MILLISECONDS_IN_A_DAY];
1

Làm cho các đối tượng có thành viên riêng tư

Điều này có thể được thực hiện thông qua các lần đóng [đối với ES5 và cũ hơn]

  • không tốt
// MILLISECONDS_IN_A_DAY chúng ta hiểu phải không các bạn 
const MILLISECONDS_IN_A_DAY = 86400000;

setTimeout[blastOff, MILLISECONDS_IN_A_DAY];
0
  • Tốt
// MILLISECONDS_IN_A_DAY chúng ta hiểu phải không các bạn 
const MILLISECONDS_IN_A_DAY = 86400000;

setTimeout[blastOff, MILLISECONDS_IN_A_DAY];
3

Class

Ưu tiên lớp ES2015/ES6 hơn các chức năng thuần ES5

Rất khó để có thể đọc được lớp kế thừa, lớp khởi tạo và định nghĩa phương thức trong các lớp ES5 cổ điển. Nếu bạn cần kế thừa [và lưu ý rằng bạn không thể], tốt hơn hết là nên sử dụng Lớp. Tuy nhiên, ưu tiên sử dụng những hàm nhỏ hơn là lớp cho đến khi bạn cần những đối tượng lớn và phức tạp hơn

  • không tốt
// MILLISECONDS_IN_A_DAY chúng ta hiểu phải không các bạn 
const MILLISECONDS_IN_A_DAY = 86400000;

setTimeout[blastOff, MILLISECONDS_IN_A_DAY];
4
  • Tốt
// MILLISECONDS_IN_A_DAY chúng ta hiểu phải không các bạn 
const MILLISECONDS_IN_A_DAY = 86400000;

setTimeout[blastOff, MILLISECONDS_IN_A_DAY];
5

Sử dụng các hàm liên tiếp

Đây là một mẫu rất hữu ích trong JavaScript và bạn đã thấy nó trong rất nhiều thư viện chẳng hạn như jQuery và Lodash

Nó cho phép mã của bạn có tính năng tải xuống và rút gọn. Vì lý do đó, theo tôi, hãy sử dụng phương pháp các hàm liên tiếp và hãy xem mã của bạn sẽ sạch sẽ như thế nào. Trong các hàm của lớp, đơn giản là trả về

// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
97 ở cuối mỗi hàm, và bạn có thể xâu chuỗi các phương thức khác nhau vào trong nó

  • không tốt
// MILLISECONDS_IN_A_DAY chúng ta hiểu phải không các bạn 
const MILLISECONDS_IN_A_DAY = 86400000;

setTimeout[blastOff, MILLISECONDS_IN_A_DAY];
6
  • Tốt
// MILLISECONDS_IN_A_DAY chúng ta hiểu phải không các bạn 
const MILLISECONDS_IN_A_DAY = 86400000;

setTimeout[blastOff, MILLISECONDS_IN_A_DAY];
7

Ưu tiên thành phần hơn là kế thừa

Như đã được nhấn mạnh nhiều trong Design Patterns của Gang of Four, bạn nên sử dụng cấu trúc thành phần hơn là kế thừa nếu có thể. Có rất nhiều lý do tốt để sử dụng kế thừa cũng như sử dụng thành phần. Điểm nhấn cho phương pháp châm cứu này là nếu tâm trí của bạn đi theo khả năng thừa kế, hãy thử nghĩ xem liệu các thành phần có thể mô phỏng vấn đề của bạn tốt hơn hay không. In a number of field it could

Bạn có thể tự hỏi, "khi nào tôi nên sử dụng thừa kế?"

  1. Kế thừa của bạn đại diện cho mỗi quan hệ "is-a" và không có mỗi quan hệ "has-a" [Human->Animal vs. Người dùng->Chi tiết người dùng]

  2. Bạn có thể sử dụng lại mã từ lớp cơ bản [Con người có thể chuyển đổi giống tất cả Động vật]

  3. Bạn muốn thay đổi toàn cục đến các lớp dẫn đầu ra bằng cách thay đổi lớp cơ bản. [Thay đổi lượng calo của tất cả động vật khi chúng di chuyển]

  • không tốt
// MILLISECONDS_IN_A_DAY chúng ta hiểu phải không các bạn 
const MILLISECONDS_IN_A_DAY = 86400000;

setTimeout[blastOff, MILLISECONDS_IN_A_DAY];
8
  • Tốt
// MILLISECONDS_IN_A_DAY chúng ta hiểu phải không các bạn 
const MILLISECONDS_IN_A_DAY = 86400000;

setTimeout[blastOff, MILLISECONDS_IN_A_DAY];
9

CHẤT RẮN

Nguyên lý đơn trách nhiệm [Single Responsibility Principle]

Như đã được đề cập trong cuốn sách Clean Code, "Chỉ có thể thay đổi một lớp vì lý do duy nhất". Thật là một đường dẫn hấp dẫn để ghép nhiều chức năng vào một lớp, giống như khi bạn chỉ có thể lấy một chiếc vali cho chuyến bay vậy. Vấn đề là lớp của bạn sẽ không hiểu được kết nối về mặt khái niệm của nó và sẽ có rất nhiều lý do để thay đổi. Việc làm giảm thiểu số lần bạn cần phải thay đổi một lớp là một công việc quan trọng. Nó quan trọng bởi vì nếu có quá nhiều chức năng trong một lớp và bạn chỉ muốn thay đổi một chút của lớp đó, thì có thể sẽ rất khó để hiểu được việc thay đổi đó sẽ ảnh hưởng đến những mô-đun khác trong cơ sở mã của bạn

  • không tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;

// mình đọc cái đống này thật ra cũng không hiểu
saveCityZipCode[address.match[cityZipCodeRegex][1], address.match[cityZipCodeRegex][2]];
0
  • Tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;

// mình đọc cái đống này thật ra cũng không hiểu
saveCityZipCode[address.match[cityZipCodeRegex][1], address.match[cityZipCodeRegex][2]];
1

Nguyên lý đóng mở [Open/Closed Principle]

Bertrand Meyer đã nói "có thể thoải mái mở rộng một mô-đun, nhưng hạn chế sửa đổi bên trong mô-đun đó". Điều đó nghĩa là gì?

  • không tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;

// mình đọc cái đống này thật ra cũng không hiểu
saveCityZipCode[address.match[cityZipCodeRegex][1], address.match[cityZipCodeRegex][2]];
2
  • Tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;

// mình đọc cái đống này thật ra cũng không hiểu
saveCityZipCode[address.match[cityZipCodeRegex][1], address.match[cityZipCodeRegex][2]];
3

Nguyên lí thay thế Liskov [Nguyên tắc thay thế Liskov]

Đây là một thuật ngữ đáng sợ cho một khái niệm rất đơn giản. Nó được định nghĩa một cách chính thức là. "If S is a type of T, then the objects of the type T could be instead by the objects of the type S [ví dụ các đối tượng của kiểu S có thể thay thế các đối tượng của kiểu T] that . ]. That even chí but is a định nghĩa đáng sợ hơn

Sự thật tốt nhất cho nguyên lí này là, nếu bạn có một lớp cha và một lớp con, thì lớp cơ sở và lớp con có thể được sử dụng thay thế cho nhau mà không làm thay đổi tính đúng đắn của chương trình. Có thể vẫn còn hơi rối ở đây, vì vậy hãy xem ví dụ cổ điển hình vuông-hình chữ nhật [Square-Rectangle] dưới đây. Về mặt toán học, một hình vuông là một hình chữ nhật, tuy nhiên nếu bạn mô hình hóa điều này sử dụng quan hệ "là" thông qua công việc kế thừa, bạn sẽ nhanh chóng gặp phải rắc rối đó.

  • không tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;

// mình đọc cái đống này thật ra cũng không hiểu
saveCityZipCode[address.match[cityZipCodeRegex][1], address.match[cityZipCodeRegex][2]];
4
  • Tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;

// mình đọc cái đống này thật ra cũng không hiểu
saveCityZipCode[address.match[cityZipCodeRegex][1], address.match[cityZipCodeRegex][2]];
5

Nguyên lý phân tách giao diện [Nguyên tắc phân tách giao diện]

JavaScript không có giao diện vì vậy nguyên lí này không áp dụng một cách chặt chẽ như các nguyên lí khác. Tuy nhiên, nó cũng quan trọng và liên quan ngay cả với hệ thống thiếu định dạng của JavaScript

Nguyên lý phân tách giao diện nhấn mạnh rằng "Người dùng không nên bị bắt buộc phải phụ thuộc vào các giao diện mà họ không sử dụng. " Giao diện là bắt buộc phải ẩn trong JavaScript bởi vì duck typing

Một ví dụ tốt để minh hoạ cho nguyên lí này trong JavaScript là các lớp yêu cầu cài đặt các đối tượng lớn. Việc không yêu cầu người dùng thiết lập một số lượng lớn các tùy chọn tùy chỉnh là một lợi ích, bởi vì đa số thời gian họ không cần tất cả các cài đặt. Làm cho chúng trở thành lựa chọn tùy ý giúp tránh được việc có một "giao diện béo"

  • không tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;

// mình đọc cái đống này thật ra cũng không hiểu
saveCityZipCode[address.match[cityZipCodeRegex][1], address.match[cityZipCodeRegex][2]];
6
  • Tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;

// mình đọc cái đống này thật ra cũng không hiểu
saveCityZipCode[address.match[cityZipCodeRegex][1], address.match[cityZipCodeRegex][2]];
7

Nguyên tắc đảo ngược phụ thuộc [Nguyên tắc đảo ngược phụ thuộc]

Nguyên lý này khẳng định hai điều kiện cần thiết sau

  1. Nhưng module cấp cao không nên phụ thuộc vào module cấp thấp. Cả hai nên phụ thuộc vào trừu tượng
  2. Trừu tượng [giao diện] không nên phụ thuộc vào chi tiết, mà ngược lại

Điều này có thể khó hiểu khi ban đầu, nhưng nếu bạn đã từng làm việc với Angular. js, bạn đã thấy sự thực thi của nguyên lí này dưới dạng của Dependency Injection [DI]. Khi chúng không phải là các khái niệm giống nhau, DIP giữ cho mô-đun cấp cao không biết chi tiết các mô-đun cấp thấp của nó và thiết lập của chúng. You can get this thing through DI. Một lợi ích lớn của DIP là nó làm giảm sự phụ thuộc lẫn nhau giữa các mô-đun. Sự phụ thuộc lẫn nhau là một kiểu mẫu không tốt, vì nó làm cho việc tái cấu trúc mã trở nên khó khăn

Như đã khẳng định ở trước, JavaScript không có giao diện vì vậy các trừu tượng mà bị phụ thuộc là các ràng buộc ẩn. Đó là để nói, các phương thức và thuộc tính mà một đối tượng/lớp làm hiển thị đối tượng/lớp khác. Trong ví dụ bên dưới, ràng buộc ẩn là bất kỳ mô-đun nào Request for a InventoryRequester will have a requestItems method

  • không tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;

// mình đọc cái đống này thật ra cũng không hiểu
saveCityZipCode[address.match[cityZipCodeRegex][1], address.match[cityZipCodeRegex][2]];
8
  • Tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;

// mình đọc cái đống này thật ra cũng không hiểu
saveCityZipCode[address.match[cityZipCodeRegex][1], address.match[cityZipCodeRegex][2]];
9

thử nghiệm

Testing thì quan trọng hơn shipping. Nếu bạn không kiểm tra hoặc không đủ, thì mỗi lần ship code bạn sẽ không chắc mình có làm hư hại gì không. Việc quyết định những gì để tạo ra số lượng kiểm tra đủ là do nhóm của bạn, nhưng việc có 100% mức độ bao phủ [tất cả các câu lệnh và rẽ nhánh] là cách để bạn đạt được sự tự tin cao. Điều này có nghĩa là bên ngoài công việc có khuôn khổ để kiểm tra điều tốt, bạn cũng cần sử dụng một công cụ bao trùm điều tốt

Không có lý do gì để không viết bài kiểm tra. Có rất nhiều điều tốt, vì vậy hãy thử tìm một khuôn khổ mà nhóm bạn thích. Khi đã tìm được một cái thích hợp với đội của mình, hãy đặt tiêu đề để luôn luôn viết bài kiểm tra cho từng tính năng hoặc mô-đun mới của bạn. Nếu phương pháp thử nghiệm ưa thích của bạn là Test Driven Development [TDD], thì điều đó thật tuyệt vời, nhưng điểm quan trọng là bạn phải đảm bảo rằng bạn đạt được mục tiêu về mức độ phủ trước khi khởi chạy một tính năng hoặc cấu trúc lại một tính năng cũ

Một khái niệm duy nhất cho mỗi bài kiểm tra đơn vị

  • không tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;
const [, city, zipCode] = address.match[cityZipCodeRegex] || [];

// đến đây thì mình hiểu đó là city và zipCode truyền vào
saveCityZipCode[city, zipCode];
0
  • Tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;
const [, city, zipCode] = address.match[cityZipCodeRegex] || [];

// đến đây thì mình hiểu đó là city và zipCode truyền vào
saveCityZipCode[city, zipCode];
1

Xử lý đồng thời

Please use Promise, don't use callback

Callback thì không được 'sạch sẽ' cho lắm, chúng gây ra quá nhiều đoạn code lồng nhau [callback hell]. Từ ES2015/ES6, Promise đã được đưa vào Javascript. Please use them

  • không tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;
const [, city, zipCode] = address.match[cityZipCodeRegex] || [];

// đến đây thì mình hiểu đó là city và zipCode truyền vào
saveCityZipCode[city, zipCode];
2
  • Tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;
const [, city, zipCode] = address.match[cityZipCodeRegex] || [];

// đến đây thì mình hiểu đó là city và zipCode truyền vào
saveCityZipCode[city, zipCode];
3

Async/Await thì 'sạch sẽ' hơn Promise

Hứa hẹn là một sự thay thế 'sạch sẽ' cho gọi lại, nhưng ES2017/ES8 giới thiệu không đồng bộ và chờ đợi, thậm chí chí chí còn là một giải pháp tốt hơn Promise nữa. Những gì bạn cần phải làm là một hàm có tiếp đầu ngữ là từ khoá không đồng bộ, và bạn có thể viết các logic lệnh mà không cần một chuỗi sau đó của các hàm. Hãy sử dụng điều này nếu bạn có thể tận dụng các tính năng của ES2017/ES8 ngay hôm nay

  • không tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;
const [, city, zipCode] = address.match[cityZipCodeRegex] || [];

// đến đây thì mình hiểu đó là city và zipCode truyền vào
saveCityZipCode[city, zipCode];
3
  • Tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;
const [, city, zipCode] = address.match[cityZipCodeRegex] || [];

// đến đây thì mình hiểu đó là city và zipCode truyền vào
saveCityZipCode[city, zipCode];
5

Xử lý lỗi

Don't bỏ qua những lỗi đã bắt được

Nếu không làm gì với lỗi đã bắt được, bạn sẽ không thể sửa hoặc phản hồi lại lỗi đã bắt được. Ghi lỗi ra

// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
98 [bảng điều khiển. log] cũng không tốt hơn bao nhiêu vì đa số nó có thể bị trôi mất trong một ngăn xếp thứ được hiển thị ra ở bảng điều khiển. Nếu bạn đặt bất kỳ đoạn mã nào trong một khối thử/bắt, tức là bạn nghĩ rằng một lỗi có thể xảy ra ở đây, thì bạn có nên có một giải pháp hoặc tạo một mã luồng để xử lý lỗi khi nó xảy ra không

  • không tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;
const [, city, zipCode] = address.match[cityZipCodeRegex] || [];

// đến đây thì mình hiểu đó là city và zipCode truyền vào
saveCityZipCode[city, zipCode];
6
  • Tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;
const [, city, zipCode] = address.match[cityZipCodeRegex] || [];

// đến đây thì mình hiểu đó là city và zipCode truyền vào
saveCityZipCode[city, zipCode];
7

Don't bỏ qua những lời hứa bị lỗi [bị từ chối]

With the integer kernel with on

  • không tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;
const [, city, zipCode] = address.match[cityZipCodeRegex] || [];

// đến đây thì mình hiểu đó là city và zipCode truyền vào
saveCityZipCode[city, zipCode];
8
  • Tốt
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+[.+?]\s*[\d{5}]?$/;
const [, city, zipCode] = address.match[cityZipCodeRegex] || [];

// đến đây thì mình hiểu đó là city và zipCode truyền vào
saveCityZipCode[city, zipCode];
9

format

Viewing code format mang tính chủ quan. Giống như nhiều quy tắc được trình bày trong tài liệu này, không có quy tắc nào khó nhắc và nhanh chóng mà bạn bắt buộc phải tuân theo. Điểm chính của phần này là KHÔNG BẢO GIỜ TRANH CÀI về việc định dạng mã như thế nào. Có hàng tá công cụ để tự động hóa công việc này. Hãy sử dụng bất kỳ công cụ nào. Thật thời gian và tiền bạc chỉ để tranh cãi về vấn đề định dạng mã

Đối chiếu với những thứ không thuộc phạm vi của mã định dạng tự động của công việc [thụt đầu dòng, tab và dấu cách, nháy đơn và nháy kép,. ] hãy xem một số hướng dẫn ở đây

Sử dụng hệ thống cách viết hoa tốt nhất

Javascript là một ngôn ngữ không định kiểu, vì vậy việc viết hoa sẽ nói lên rất nhiều về các biến, hàm,. của bạn. Những quy tắc này thì mang tính chủ quan, vì thế đội bạn có thể chọn quy tắc nào họ muốn. Tuy nhiên, điều quan trọng là cho dù bạn chọn cách viết như thế nào, thì hãy sử dụng hệ thống tốt nhất trong codebase của bạn

  • không tốt
const locations = ['Austin', 'New York', 'San Francisco'];
locations.forEach[[l] => {
  //...
  // Khoan, cái 'l' gì thế ?
  dispatch[l];
}];
0
  • Tốt
const locations = ['Austin', 'New York', 'San Francisco'];
locations.forEach[[l] => {
  //...
  // Khoan, cái 'l' gì thế ?
  dispatch[l];
}];
1

Các hàm gọi và hàm được gọi nên nằm gần nhau

Nếu một hàm gọi một hàm khác, hãy giữ các hàm này gần theo chiều dọc trong tệp. Lí tưởng là, hãy giữ cho hàm gọi ở trên hàm được gọi. Chúng ta có xu hướng đọc mã từ trên xuống, giống như đọc báo vậy. Do đó, hãy làm cho mã của chúng ta cũng được đọc theo cách đó

  • không tốt
const locations = ['Austin', 'New York', 'San Francisco'];
locations.forEach[[l] => {
  //...
  // Khoan, cái 'l' gì thế ?
  dispatch[l];
}];
2
  • Tốt
const locations = ['Austin', 'New York', 'San Francisco'];
locations.forEach[[l] => {
  //...
  // Khoan, cái 'l' gì thế ?
  dispatch[l];
}];
3

Viết chú thích

Chỉ nên viết chú thích cho những thứ có logic phức tạp

Các chú thích thông thường là lời xin lỗi, chứ không phải là yêu cầu. Những đoạn code tốt thì multi number nó đã là tài liệu rồi

  • không tốt
const locations = ['Austin', 'New York', 'San Francisco'];
locations.forEach[[l] => {
  //...
  // Khoan, cái 'l' gì thế ?
  dispatch[l];
}];
4
  • Tốt
const locations = ['Austin', 'New York', 'San Francisco'];
locations.forEach[[l] => {
  //...
  // Khoan, cái 'l' gì thế ?
  dispatch[l];
}];
5

Đừng giữ lại những đoạn mã được chú thích trong cơ sở mã của bạn

Những công cụ quản lý phiên bản sinh ra để thực hiện nhiệm vụ của họ. Please to your old code is back in tiền đi

  • không tốt
const locations = ['Austin', 'New York', 'San Francisco'];
locations.forEach[[l] => {
  //...
  // Khoan, cái 'l' gì thế ?
  dispatch[l];
}];
6
  • Tốt
const locations = ['Austin', 'New York', 'San Francisco'];
locations.forEach[[l] => {
  //...
  // Khoan, cái 'l' gì thế ?
  dispatch[l];
}];
7

Đừng viết nhật ký chú thích

Hãy nhớ, sử dụng công cụ quản lý phiên bản. Chúng ta không cần những đoạn mã vô dụng, chú thích và đặc biệt là những chú thích định dạng nhật ký. Sử dụng

// ít nhất thì mình vẫn hiểu đây là ngày hiện tại
const currentDate = moment[].format['YYYY/MM/DD'];
99 để xem lịch sử được mà

  • không tốt
const locations = ['Austin', 'New York', 'San Francisco'];
locations.forEach[[l] => {
  //...
  // Khoan, cái 'l' gì thế ?
  dispatch[l];
}];
8
  • Tốt
const locations = ['Austin', 'New York', 'San Francisco'];
locations.forEach[[l] => {
  //...
  // Khoan, cái 'l' gì thế ?
  dispatch[l];
}];
9

Undefault the position

Chúng thường xuyên làm nhiễu mã. Hãy để các tên hàm, biến tương tự với các định dạng thích hợp tự tạo thành cấu trúc trực quan cho mã của bạn

Chủ Đề