@@ -7,7 +7,7 @@ Original Repository: [ryanmcdermott/clean-code-javascript](https://github.com/ry
7
7
2 . [ Biến] ( #biến )
8
8
3 . [ Functions] ( #functions )
9
9
4 . [ Đối tượng và Cấu trúc dữ liệu] ( #đối-tượng-và-cấu-trúc-dữ-liệu )
10
- 5 . [ Classes ] ( #classes )
10
+ 5 . [ Lớp ] ( #lớp )
11
11
6 . [ Testing] ( #testing )
12
12
7 . [ Xử lí đồng thời] ( #xử-lí-đồng-thời )
13
13
8 . [ Xử lí lỗi] ( #xử-lí-lỗi )
@@ -1025,18 +1025,18 @@ console.log(`Employee name: ${employee.getName()}`); // Employee name: John Doe
1025
1025
** [ ⬆ về đầu trang] ( #mục-lục ) **
1026
1026
1027
1027
1028
- ## ** Classes **
1029
- ### Single Responsibility Principle (SRP )
1030
- As stated in Clean Code, "There should never be more than one reason for a class
1031
- to change ". It's tempting to jam-pack a class with a lot of functionality, like
1032
- when you can only take one suitcase on your flight. The issue with this is
1033
- that your class won't be conceptually cohesive and it will give it many reasons
1034
- to change. Minimizing the amount of times you need to change a class is important.
1035
- It's important because if too much functionality is in one class and you modify a piece of it,
1036
- it can be difficult to understand how that will affect other dependent modules in
1037
- your codebase.
1028
+ ## ** Lớp **
1029
+ ### Nguyên lí đơn trách nhiệm ( Single Responsibility Principle)
1030
+ Như đã được nói đến trong cuốn Clean Code, "Chỉ có thể thay đổi một lớp vì một lí
1031
+ do duy nhất ". Thật là hấp dẫn để nhồi nhét nhiều chức năng vào cho một lớp, giống
1032
+ như là 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
1033
+ bạn sẽ không được hiểu gắn kết về mặt khái niệm của nó và sẽ có rất nhiều lí do
1034
+ để 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 việc
1035
+ 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
1036
+ chỉ muốn thay đổi một chút xíu của lớp đó, thì có thể sẽ rất khó để hiểu được việc
1037
+ thay đổi đó sẽ ảnh hưởng đến những module khác trong codebase của bạn như thế nào .
1038
1038
1039
- ** Bad :**
1039
+ ** Không tốt :**
1040
1040
``` javascript
1041
1041
class UserSettings {
1042
1042
constructor (user ) {
@@ -1055,7 +1055,7 @@ class UserSettings {
1055
1055
}
1056
1056
```
1057
1057
1058
- ** Good :**
1058
+ ** Tốt :**
1059
1059
``` javascript
1060
1060
class UserAuth {
1061
1061
constructor (user ) {
@@ -1081,15 +1081,15 @@ class UserSettings {
1081
1081
}
1082
1082
}
1083
1083
```
1084
- ** [ ⬆ back to top ] ( #mục-lục ) **
1084
+ ** [ ⬆ về đầu trang ] ( #mục-lục ) **
1085
1085
1086
- ### Open/Closed Principle (OCP )
1087
- As stated by Bertrand Meyer, "software entities (classes, modules, functions,
1088
- etc.) should be open for extension, but closed for modification." What does that
1089
- mean though? This principle basically states that you should allow users to
1090
- add new functionalities without changing existing code .
1086
+ ### Nguyên lí đóng mở ( Open/Closed Principle)
1087
+ Betrand Meyer đã nói "có thể thoải mái mở rộng một module, nhưng hạn chế sửa
1088
+ đổi bên trong module đó". Điều đó nghĩa là gì? Nguyên tắc này cơ bản nhấn mạnh
1089
+ rằng bạn phải cho phép người dùng thêm các chức năng mới mà không làm thay
1090
+ đổi các code đang có .
1091
1091
1092
- ** Bad :**
1092
+ ** Không tốt :**
1093
1093
``` javascript
1094
1094
class AjaxAdapter extends Adapter {
1095
1095
constructor () {
@@ -1132,7 +1132,7 @@ function makeHttpCall(url) {
1132
1132
}
1133
1133
```
1134
1134
1135
- ** Good :**
1135
+ ** Tốt :**
1136
1136
``` javascript
1137
1137
class AjaxAdapter extends Adapter {
1138
1138
constructor () {
@@ -1168,24 +1168,26 @@ class HttpRequester {
1168
1168
}
1169
1169
}
1170
1170
```
1171
- ** [ ⬆ back to top ] ( #mục-lục ) **
1171
+ ** [ ⬆ về đầu trang ] ( #mục-lục ) **
1172
1172
1173
1173
1174
- ### Liskov Substitution Principle (LSP)
1175
- This is a scary term for a very simple concept. It's formally defined as "If S
1176
- is a subtype of T, then objects of type T may be replaced with objects of type S
1177
- (i.e., objects of type S may substitute objects of type T) without altering any
1178
- of the desirable properties of that program (correctness, task performed,
1179
- etc.)." That's an even scarier definition.
1174
+ ### Nguyên lí thay thế Liskov (Liskov Substitution Principle)
1175
+ Đâ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
1176
+ một cách chính thức là: "Nếu S là một kiểu con của T, thì các đối tượng của kiểu
1177
+ T có thể được thay thế bằng các đối tượng của kiểu S (ví dụ các đối tượng của
1178
+ kiểu S có thể thay thế các đối tượng của kiểu T) mà không làm thay đổi bất kì thuộc
1179
+ tính mong muốn nào của chương trình đó (tính chính xác, thực hiện tác vụ, ..).
1180
+ Đó thậm chí còn là một định nghĩa đáng sợ hơn.
1180
1181
1181
- The best explanation for this is if you have a parent class and a child class,
1182
- then the base class and child class can be used interchangeably without getting
1183
- incorrect results. This might still be confusing, so let's take a look at the
1184
- classic Square-Rectangle example. Mathematically, a square is a rectangle, but
1185
- if you model it using the "is-a" relationship via inheritance, you quickly
1186
- get into trouble.
1182
+ Sự giải thích 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,
1183
+ 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
1184
+ đổi tính đúng đắn của chương trình. Có thể vẫn còn hơi rối ở đây, vậy hãy xem
1185
+ cái ví dụ cổ điển hình vuông-hình chữ nhật (Square-Rectangle) dưới đây. Về mặt
1186
+ 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 hoá điều
1187
+ này sử dụng quan hệ "is a" thông qua việc kế thừa, bạn sẽ nhanh chóng gặp phải
1188
+ rắc rối đấy.
1187
1189
1188
- ** Bad :**
1190
+ ** Không tốt :**
1189
1191
``` javascript
1190
1192
class Rectangle {
1191
1193
constructor () {
@@ -1239,7 +1241,7 @@ const rectangles = [new Rectangle(), new Rectangle(), new Square()];
1239
1241
renderLargeRectangles (rectangles);
1240
1242
```
1241
1243
1242
- ** Good :**
1244
+ ** Tốt :**
1243
1245
``` javascript
1244
1246
class Shape {
1245
1247
setColor (color ) {
@@ -1305,23 +1307,25 @@ function renderLargeShapes(shapes) {
1305
1307
const shapes = [new Rectangle (), new Rectangle (), new Square ()];
1306
1308
renderLargeShapes (shapes);
1307
1309
```
1308
- ** [ ⬆ back to top ] ( #mục-lục ) **
1310
+ ** [ ⬆ về đầu trang ] ( #mục-lục ) **
1309
1311
1310
- ### Interface Segregation Principle (ISP)
1311
- JavaScript doesn't have interfaces so this principle doesn't apply as strictly
1312
- as others. However, it's important and relevant even with JavaScript's lack of
1313
- type system.
1312
+ ### Nguyên lí phân tách interface (Interface Segregation Principle)
1314
1313
1315
- ISP states that "Clients should not be forced to depend upon interfaces that
1316
- they do not use." Interfaces are implicit contracts in JavaScript because of
1317
- duck typing .
1314
+ JavaScript không có interface vì vậy nguyên lí này không áp dụng một cách
1315
+ chặt chẽ như các nguyên lí khác. Tuy nhiên, nó cũng quan trọng và liên quan
1316
+ ngay cả với hệ thống thiếu định kiểu của JavaScript .
1318
1317
1319
- A good example to look at that demonstrates this principle in JavaScript is for
1320
- classes that require large settings objects. Not requiring clients to setup
1321
- huge amounts of options is beneficial, because most of the time they won't need
1322
- all of the settings. Making them optional helps prevent having a "fat interface".
1318
+ Nguyên lí phân tách interface nhấn mạnh rằng "Người dùng không nên bị bắt
1319
+ buộc phải phụ thuộc vào các interfaces mà họ không sử dụng." Interface là
1320
+ những ràng buộc ẩn trong JavaScript bởi vì duck typing.
1323
1321
1324
- ** Bad:**
1322
+ Một ví dụ tốt để minh hoạ cho nguyên lí này trong JavaScript là các lớp mà yêu
1323
+ 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ố
1324
+ lượng lớn các tuỳ chọn là một ích lợi, bởi vì đa số thời gian họ không cần tất
1325
+ cả các cài đặt. Làm cho chúng trở thành tuỳ chọn giúp tránh được việc có một
1326
+ "fat interface".
1327
+
1328
+ ** Không tốt:**
1325
1329
``` javascript
1326
1330
class DOMTraverser {
1327
1331
constructor (settings ) {
@@ -1347,7 +1351,7 @@ const $ = new DOMTraverser({
1347
1351
1348
1352
```
1349
1353
1350
- ** Good :**
1354
+ ** Tốt :**
1351
1355
``` javascript
1352
1356
class DOMTraverser {
1353
1357
constructor (settings ) {
@@ -1379,30 +1383,29 @@ const $ = new DOMTraverser({
1379
1383
}
1380
1384
});
1381
1385
```
1382
- ** [ ⬆ back to top ] ( #mục-lục ) **
1386
+ ** [ ⬆ về đầu trang ] ( #mục-lục ) **
1383
1387
1384
- ### Dependency Inversion Principle (DIP)
1385
- This principle states two essential things:
1386
- 1 . High-level modules should not depend on low-level modules. Both should
1387
- depend on abstractions.
1388
- 2 . Abstractions should not depend upon details. Details should depend on
1389
- abstractions.
1390
-
1391
- This can be hard to understand at first, but if you've worked with Angular.js,
1392
- you've seen an implementation of this principle in the form of Dependency
1393
- Injection (DI). While they are not identical concepts, DIP keeps high-level
1394
- modules from knowing the details of its low-level modules and setting them up.
1395
- It can accomplish this through DI. A huge benefit of this is that it reduces
1396
- the coupling between modules. Coupling is a very bad development pattern because
1397
- it makes your code hard to refactor.
1398
-
1399
- As stated previously, JavaScript doesn't have interfaces so the abstractions
1400
- that are depended upon are implicit contracts. That is to say, the methods
1401
- and properties that an object/class exposes to another object/class. In the
1402
- example below, the implicit contract is that any Request module for an
1403
- ` InventoryTracker ` will have a ` requestItems ` method.
1388
+ ### Nguyên lí đảo ngược dependency (Dependency Inversion Principle)
1389
+ Nguyên lí này khẳng định hai điều cần thiết sau:
1390
+ 1 . Nhưng module cấp cao không nên phụ thuộc vào những module cấp thấp. Cả
1391
+ hai nên phụ thuộc vào abstraction.
1392
+ 2 . Abstraction (interface) không nên phụ thuộc vào chi tiết, mà ngược lại.
1393
+
1394
+ Điều này có thể khó hiểu lúc ban đầu, nhưng nếu bạn đã từng làm việc với Angular.js,
1395
+ bạn đã thấy một sự hiện thực của nguyên lí này trong dạng của Dependency Injection
1396
+ (DI). Khi chúng không phải là các khái niệm giống nhau, DIP giữ cho module cấp
1397
+ cao không biết chi tiết các module cấp thấp của nó và thiết lập chúng. Có thể đạt
1398
+ được điều này thông qua DI. Một lợi ích to lớn của DIP là nó làm giảm sự phụ thuộc
1399
+ lẫn nhau giữa các module. Sự phụ thuộc lẫn nhau là một kiểu mẫu không tốt, vì nó
1400
+ làm cho việc tái cấu trúc code trở nên khó khăn.
1401
+
1402
+ Như đã khẳng định ở trước, JavaScript không có interface vì vậy các abstraction
1403
+ mà bị phụ thuộc là những ràng buộc ẩn. Đó là để nói, các phương thức và thuộc tính
1404
+ mà một đối tượng/lớp làm phơi bày đối tượng/lớp khác. Trong ví dụ bên dưới, sự ràng
1405
+ buộc ẩn là bất cứ module Request cho một ` InventoryRequester ` sẽ có một phương thức
1406
+ ` requestItems ` .
1404
1407
1405
- ** Bad :**
1408
+ ** Không tốt :**
1406
1409
``` javascript
1407
1410
class InventoryRequester {
1408
1411
constructor () {
@@ -1418,8 +1421,8 @@ class InventoryTracker {
1418
1421
constructor (items ) {
1419
1422
this .items = items;
1420
1423
1421
- // BAD: We have created a dependency on a specific request implementation.
1422
- // We should just have requestItems depend on a request method: `request`
1424
+ // Không tốt: chúng ta đã tạo một phụ thuộc vào một hiện thực của một request cụ thể
1425
+ // Chúng ta nên có những requestItems phụ thuộc vào một phương thức request `request`
1423
1426
this .requester = new InventoryRequester ();
1424
1427
}
1425
1428
@@ -1434,7 +1437,7 @@ const inventoryTracker = new InventoryTracker(['apples', 'bananas']);
1434
1437
inventoryTracker .requestItems ();
1435
1438
```
1436
1439
1437
- ** Good :**
1440
+ ** Tốt :**
1438
1441
``` javascript
1439
1442
class InventoryTracker {
1440
1443
constructor (items , requester ) {
@@ -1469,20 +1472,20 @@ class InventoryRequesterV2 {
1469
1472
}
1470
1473
}
1471
1474
1472
- // By constructing our dependencies externally and injecting them, we can easily
1473
- // substitute our request module for a fancy new one that uses WebSockets.
1475
+ // Bằng cách xây dựng các phụ thuộc ở ngoài và thêm chúng vào, chúng ta có thể
1476
+ // dễ dàng thay thế module request bằng một module mới lạ sử dụng WebSockets.
1474
1477
const inventoryTracker = new InventoryTracker ([' apples' , ' bananas' ], new InventoryRequesterV2 ());
1475
1478
inventoryTracker .requestItems ();
1476
1479
```
1477
- ** [ ⬆ back to top ] ( #mục-lục ) **
1480
+ ** [ ⬆ về đầu trang ] ( #mục-lục ) **
1478
1481
1479
1482
### Prefer ES2015/ES6 classes over ES5 plain functions
1480
1483
It's very difficult to get readable class inheritance, construction, and method
1481
1484
definitions for classical ES5 classes. If you need inheritance (and be aware
1482
1485
that you might not), then prefer classes. However, prefer small functions over
1483
1486
classes until you find yourself needing larger and more complex objects.
1484
1487
1485
- ** Bad :**
1488
+ ** Không tốt :**
1486
1489
``` javascript
1487
1490
const Animal = function (age ) {
1488
1491
if (! (this instanceof Animal)) {
@@ -1521,7 +1524,7 @@ Human.prototype.constructor = Human;
1521
1524
Human .prototype .speak = function speak () {};
1522
1525
```
1523
1526
1524
- ** Good :**
1527
+ ** Tốt :**
1525
1528
``` javascript
1526
1529
class Animal {
1527
1530
constructor (age ) {
@@ -1549,7 +1552,7 @@ class Human extends Mammal {
1549
1552
speak () { /* ... */ }
1550
1553
}
1551
1554
```
1552
- ** [ ⬆ back to top ] ( #mục-lục ) **
1555
+ ** [ ⬆ về đầu trang ] ( #mục-lục ) **
1553
1556
1554
1557
1555
1558
### Use method chaining
@@ -1559,7 +1562,7 @@ For that reason, I say, use method chaining and take a look at how clean your co
1559
1562
will be. In your class functions, simply return ` this ` at the end of every function,
1560
1563
and you can chain further class methods onto it.
1561
1564
1562
- ** Bad :**
1565
+ ** Không tốt :**
1563
1566
``` javascript
1564
1567
class Car {
1565
1568
constructor () {
@@ -1592,7 +1595,7 @@ car.setModel('F-150');
1592
1595
car .save ();
1593
1596
```
1594
1597
1595
- ** Good :**
1598
+ ** Tốt :**
1596
1599
``` javascript
1597
1600
class Car {
1598
1601
constructor () {
@@ -1632,7 +1635,7 @@ const car = new Car()
1632
1635
.setModel (' F-150' )
1633
1636
.save ();
1634
1637
```
1635
- ** [ ⬆ back to top ] ( #mục-lục ) **
1638
+ ** [ ⬆ về đầu trang ] ( #mục-lục ) **
1636
1639
1637
1640
### Prefer composition over inheritance
1638
1641
As stated famously in [ * Design Patterns* ] ( https://en.wikipedia.org/wiki/Design_Patterns ) by the Gang of Four,
@@ -1652,7 +1655,7 @@ relationship (Human->Animal vs. User->UserDetails).
1652
1655
3 . You want to make global changes to derived classes by changing a base class.
1653
1656
(Change the caloric expenditure of all animals when they move).
1654
1657
1655
- ** Bad :**
1658
+ ** Không tốt :**
1656
1659
``` javascript
1657
1660
class Employee {
1658
1661
constructor (name , email ) {
@@ -1675,7 +1678,7 @@ class EmployeeTaxData extends Employee {
1675
1678
}
1676
1679
```
1677
1680
1678
- ** Good :**
1681
+ ** Tốt :**
1679
1682
``` javascript
1680
1683
class EmployeeTaxData {
1681
1684
constructor (ssn , salary ) {
@@ -1698,7 +1701,7 @@ class Employee {
1698
1701
// ...
1699
1702
}
1700
1703
```
1701
- ** [ ⬆ back to top ] ( #mục-lục ) **
1704
+ ** [ ⬆ về đầu trang ] ( #mục-lục ) **
1702
1705
1703
1706
## ** Testing**
1704
1707
Testing thì quan trọng hơn shipping. Nếu bạn không có test hoặc không đủ,
0 commit comments