Hướng dẫn php clean - php sạch

Giới thiệu

Đây là những nguyên lý kỹ thuật phần mềm, được trích từ cuốn sách Clean Code của tác giả Robert C. Martin [thường gọi là Uncle Bob] rất thích hợp cho ngôn ngữ PHP. Tài liệu này không phải là sách hướng dẫn về phong cách viết code, mà là hướng dẫn cách làm thế nào để viết phần mềm dễ đọc, dễ sử dụng lại, và dễ cải tiến trong PHP.

Bạn không cần phải tuân theo tất cả các nguyên tắc trong tài liệu này. Đây chỉ đơn giản là những hướng dẫn, nhưng dù sao nó cũng là đúc kết từ nhiều năm kinh nghiệm của tác giả.

Lưu ý: Dù nhiều lập trình viên còn sử dụng PHP 5, nhưng nhiều ví dụ trong đây chỉ chạy được trên PHP 7.1+.

Vì bài viết khá dài nên mình xin tách thành 2 phần, hi vọng bài viết sẽ có ích

Biến

Sử dụng tên biến có ý nghĩa và dễ hiểu

Chưa tốt:

$ymdstr = $moment->format['y-m-d'];

Tốt:

$currentDate = $moment->format['y-m-d'];

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

Chưa tốt:

getUserInfo[];
getUserData[];
getUserRecord[];
getUserProfile[];

Tốt:

getUser[];

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

Đặt tên sao cho dễ tìm kiếm [phần 1]

Chưa tốt:

// Oh man, 448 là cái gì vậy?
$result = $serializer->serialize[$data, 448];

Tốt:

$json = $serializer->serialize[$data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE];

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

Chưa tốt:

// Rồi, 69 nghĩa là cái gì đây? =]]
if [$user->access & 69] {
    // ...
}

Tốt:

class User
{
    const ACCESS_READ = 6;
    const ACCESS_CREATE = 9;
    const ACCESS_UPDATE = 69;
    const ACCESS_DELETE = 96;
}

if [$user->access & User::ACCESS_UPDATE] {
    // edit ...
}

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

Đặt tên sao cho dễ tìm kiếm [phần 1]

Chưa tốt:

$address = 'One Infinite Loop, Cupertino 95014';
$cityZipCodeRegex = '/^[^,]+,\s*[.+?]\s*[\d{5}]$/';
preg_match[$cityZipCodeRegex, $address, $matches];

saveCityZipCode[$matches[1], $matches[2]];

Tốt:

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

$address = 'One Infinite Loop, Cupertino 95014';
$cityZipCodeRegex = '/^[^,]+,\s*[.+?]\s*[\d{5}]$/';
preg_match[$cityZipCodeRegex, $address, $matches];

[, $city, $zipCode] = $matches;
saveCityZipCode[$city, $zipCode];

Tốt:

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

$currentDate = $moment->format['y-m-d'];
0

Đặt tên sao cho dễ tìm kiếm [phần 1]

Thường thì chúng ta sẽ đọc code nhiều hơn viết code. Nên điều quan trọng là code chúng ta viết ra phải dễ đọc và dễ tìm kiếm. Nếu không đặt tên biến có ý nghĩa và làm chương trình dễ hiểu, chúng ta sẽ gây khó cho những lập trình viên khác. Do đó mỗi khi đặt tên biến, hàm thì hãy đặt có ý nghĩa.

Chưa tốt:

$currentDate = $moment->format['y-m-d'];
1

Tốt:

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

Đặt tên sao cho dễ tìm kiếm [phần 1]

Chưa tốt:

$currentDate = $moment->format['y-m-d'];
3

Tốt:

$currentDate = $moment->format['y-m-d'];
4

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

Đặt tên sao cho dễ tìm kiếm [phần 1]

Chưa tốt:

$currentDate = $moment->format['y-m-d'];
5

Tốt:

$currentDate = $moment->format['y-m-d'];
6

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

Đặt tên sao cho dễ tìm kiếm [phần 1]

Chưa tốt:

$currentDate = $moment->format['y-m-d'];
7

Tốt:

$currentDate = $moment->format['y-m-d'];
8

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

Chưa tốt:

Tốt:

$currentDate = $moment->format['y-m-d'];
9

Tốt:

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

getUserInfo[];
getUserData[];
getUserRecord[];
getUserProfile[];
0

Tốt:

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

getUserInfo[];
getUserData[];
getUserRecord[];
getUserProfile[];
1

Đặt tên sao cho dễ tìm kiếm [phần 1]

Thường thì chúng ta sẽ đọc code nhiều hơn viết code. Nên điều quan trọng là code chúng ta viết ra phải dễ đọc và dễ tìm kiếm. Nếu không đặt tên biến có ý nghĩa và làm chương trình dễ hiểu, chúng ta sẽ gây khó cho những lập trình viên khác. Do đó mỗi khi đặt tên biến, hàm thì hãy đặt có ý nghĩa.

Chưa tốt:

Tốt:

getUserInfo[];
getUserData[];
getUserRecord[];
getUserProfile[];
2

Sử dụng cùng từ vựng cho cùng một loại biếnChuỗi '42' thì phải khác số 42 chứ đúng không.

Tốt:

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

getUserInfo[];
getUserData[];
getUserRecord[];
getUserProfile[];
3

Đặt tên sao cho dễ tìm kiếm [phần 1]

Thường thì chúng ta sẽ đọc code nhiều hơn viết code. Nên điều quan trọng là code chúng ta viết ra phải dễ đọc và dễ tìm kiếm. Nếu không đặt tên biến có ý nghĩa và làm chương trình dễ hiểu, chúng ta sẽ gây khó cho những lập trình viên khác. Do đó mỗi khi đặt tên biến, hàm thì hãy đặt có ý nghĩa.

Đặt tên sao cho dễ tìm kiếm [phần 2]

Đặt tên biến dễ hiểu

Chưa tốt:

getUserInfo[];
getUserData[];
getUserRecord[];
getUserProfile[];
4

Tốt:

getUserInfo[];
getUserData[];
getUserRecord[];
getUserProfile[];
5

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

Đặt tên sao cho dễ tìm kiếm [phần 1]

Chưa tốt:

getUserInfo[];
getUserData[];
getUserRecord[];
getUserProfile[];
6

Tốt:

getUserInfo[];
getUserData[];
getUserRecord[];
getUserProfile[];
7

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

Chưa tốt:

getUserInfo[];
getUserData[];
getUserRecord[];
getUserProfile[];
8

Tốt:

getUserInfo[];
getUserData[];
getUserRecord[];
getUserProfile[];
9

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

Đặt tên sao cho dễ tìm kiếm [phần 1]

Chưa tốt:

getUser[];
0

Tốt:

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

getUser[];
1

Tốt:

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

getUser[];
2

Đặt tên sao cho dễ tìm kiếm [phần 1]

Thường thì chúng ta sẽ đọc code nhiều hơn viết code. Nên điều quan trọng là code chúng ta viết ra phải dễ đọc và dễ tìm kiếm. Nếu không đặt tên biến có ý nghĩa và làm chương trình dễ hiểu, chúng ta sẽ gây khó cho những lập trình viên khác. Do đó mỗi khi đặt tên biến, hàm thì hãy đặt có ý nghĩa.

Chưa tốt:

getUser[];
3

Tốt:

getUser[];
4

Tránh tác dụng phụ

Một hàm sinh ra tác dụng phụ nếu nó thực hiện thêm việc khác ngoài việc lấy giá trị vào và trả về một hoặc nhiều giá trị khác. Tác dụng phụ có thể là viết vào một file nào đó, sửa đổi biến global, hoặc vô tình chuyển hết tiền của bạn cho người lạ nào đó.

Vậy nếu bây giờ bạn cần hàm thực hiện các tác dụng phụ đó thì sao. Giống như ví dụ trước, bạn cần ghi vào file. Điều bạn cần làm là tập trung những việc này lại một chỗ. Đừng viết vài hàm và vài lớp chỉ để ghi vào vài file cụ thể. Hãy viết một service để làm điều đó. Một và chỉ một service.

Hãy tránh những sai lầm phổ biến như: chia sẻ trạng thái giữa các object mà không tuân theo cấu trúc nào, sử dụng kiểu dữ liệu có thể thay đổi/bị thay đổi dễ dàng, không tổng hợp các tác dụng phụ có thể xảy ra khi viết hàm.

Chưa tốt:

getUser[];
5

Tốt:

getUser[];
6

Tránh tác dụng phụ

Một hàm sinh ra tác dụng phụ nếu nó thực hiện thêm việc khác ngoài việc lấy giá trị vào và trả về một hoặc nhiều giá trị khác. Tác dụng phụ có thể là viết vào một file nào đó, sửa đổi biến global, hoặc vô tình chuyển hết tiền của bạn cho người lạ nào đó.

Vậy nếu bây giờ bạn cần hàm thực hiện các tác dụng phụ đó thì sao. Giống như ví dụ trước, bạn cần ghi vào file. Điều bạn cần làm là tập trung những việc này lại một chỗ. Đừng viết vài hàm và vài lớp chỉ để ghi vào vài file cụ thể. Hãy viết một service để làm điều đó. Một và chỉ một service.

Hãy tránh những sai lầm phổ biến như: chia sẻ trạng thái giữa các object mà không tuân theo cấu trúc nào, sử dụng kiểu dữ liệu có thể thay đổi/bị thay đổi dễ dàng, không tổng hợp các tác dụng phụ có thể xảy ra khi viết hàm.

Chưa tốt:

getUser[];
7

Tốt:

getUser[];
8

Tránh tác dụng phụ

getUser[];
9

Một hàm sinh ra tác dụng phụ nếu nó thực hiện thêm việc khác ngoài việc lấy giá trị vào và trả về một hoặc nhiều giá trị khác. Tác dụng phụ có thể là viết vào một file nào đó, sửa đổi biến global, hoặc vô tình chuyển hết tiền của bạn cho người lạ nào đó.

Vậy nếu bây giờ bạn cần hàm thực hiện các tác dụng phụ đó thì sao. Giống như ví dụ trước, bạn cần ghi vào file. Điều bạn cần làm là tập trung những việc này lại một chỗ. Đừng viết vài hàm và vài lớp chỉ để ghi vào vài file cụ thể. Hãy viết một service để làm điều đó. Một và chỉ một service.

Hãy tránh những sai lầm phổ biến như: chia sẻ trạng thái giữa các object mà không tuân theo cấu trúc nào, sử dụng kiểu dữ liệu có thể thay đổi/bị thay đổi dễ dàng, không tổng hợp các tác dụng phụ có thể xảy ra khi viết hàm.

  1. Đừng viết hàm globalglobal instance, vì sao lại Chưa tốt? Bởi vì bạn ẩn dependencies của ứng dụng bên trong code của bạn, thay vì thông qua interfaces
  2. Dùng nhiều hàm global là bad practice với nhiều ngôn ngữ bởi vì có thể gây xung đột với thư viện khác và người sử dụng API của bạn không hề hay biết gì cho đến khi nhận được thông báo lỗi.chúng điều khiển những gì chúng tạo ra và vòng đời của nó
  3. Hãy xem xét ví dụ sau: bạn sẽ làm gì nếu muốn trả về một mảng.test khó khăn hơn.
  4. Bạn có thể viết hàm global như
    // Rồi, 69 nghĩa là cái gì đây? =]]
    if [$user->access & 69] {
        // ...
    }
    
    3, nhưng nó có thể xung đột với thư viện khác thực hiện cùng chức năng.

Tạo instance của lớp

// Rồi, 69 nghĩa là cái gì đây? =]]
if [$user->access & 69] {
    // ...
}
4

Chưa tốt:

// Oh man, 448 là cái gì vậy?
$result = $serializer->serialize[$data, 448];
0

Tốt:

// Oh man, 448 là cái gì vậy?
$result = $serializer->serialize[$data, 448];
1

Tránh tác dụng phụ

// Oh man, 448 là cái gì vậy?
$result = $serializer->serialize[$data, 448];
2

Một hàm sinh ra tác dụng phụ nếu nó thực hiện thêm việc khác ngoài việc lấy giá trị vào và trả về một hoặc nhiều giá trị khác. Tác dụng phụ có thể là viết vào một file nào đó, sửa đổi biến global, hoặc vô tình chuyển hết tiền của bạn cho người lạ nào đó.

Vậy nếu bây giờ bạn cần hàm thực hiện các tác dụng phụ đó thì sao. Giống như ví dụ trước, bạn cần ghi vào file. Điều bạn cần làm là tập trung những việc này lại một chỗ. Đừng viết vài hàm và vài lớp chỉ để ghi vào vài file cụ thể. Hãy viết một service để làm điều đó. Một và chỉ một service.

Chưa tốt:

// Oh man, 448 là cái gì vậy?
$result = $serializer->serialize[$data, 448];
3

Tốt:

// Oh man, 448 là cái gì vậy?
$result = $serializer->serialize[$data, 448];
4

Tránh tác dụng phụ

Chưa tốt:

// Oh man, 448 là cái gì vậy?
$result = $serializer->serialize[$data, 448];
5

Tốt:

// Oh man, 448 là cái gì vậy?
$result = $serializer->serialize[$data, 448];
6

Tránh tác dụng phụ

Một hàm sinh ra tác dụng phụ nếu nó thực hiện thêm việc khác ngoài việc lấy giá trị vào và trả về một hoặc nhiều giá trị khác. Tác dụng phụ có thể là viết vào một file nào đó, sửa đổi biến global, hoặc vô tình chuyển hết tiền của bạn cho người lạ nào đó.

Chưa tốt:

// Oh man, 448 là cái gì vậy?
$result = $serializer->serialize[$data, 448];
7

Tốt:

// Oh man, 448 là cái gì vậy?
$result = $serializer->serialize[$data, 448];
8

Tránh tác dụng phụ

Một hàm sinh ra tác dụng phụ nếu nó thực hiện thêm việc khác ngoài việc lấy giá trị vào và trả về một hoặc nhiều giá trị khác. Tác dụng phụ có thể là viết vào một file nào đó, sửa đổi biến global, hoặc vô tình chuyển hết tiền của bạn cho người lạ nào đó.

Vậy nếu bây giờ bạn cần hàm thực hiện các tác dụng phụ đó thì sao. Giống như ví dụ trước, bạn cần ghi vào file. Điều bạn cần làm là tập trung những việc này lại một chỗ. Đừng viết vài hàm và vài lớp chỉ để ghi vào vài file cụ thể. Hãy viết một service để làm điều đó. Một và chỉ một service.

Chưa tốt:

// Oh man, 448 là cái gì vậy?
$result = $serializer->serialize[$data, 448];
9

Tốt:

$json = $serializer->serialize[$data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE];
0

Tránh tác dụng phụ

Một hàm sinh ra tác dụng phụ nếu nó thực hiện thêm việc khác ngoài việc lấy giá trị vào và trả về một hoặc nhiều giá trị khác. Tác dụng phụ có thể là viết vào một file nào đó, sửa đổi biến global, hoặc vô tình chuyển hết tiền của bạn cho người lạ nào đó.

Vậy nếu bây giờ bạn cần hàm thực hiện các tác dụng phụ đó thì sao. Giống như ví dụ trước, bạn cần ghi vào file. Điều bạn cần làm là tập trung những việc này lại một chỗ. Đừng viết vài hàm và vài lớp chỉ để ghi vào vài file cụ thể. Hãy viết một service để làm điều đó. Một và chỉ một service.

Chưa tốt:

$json = $serializer->serialize[$data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE];
1

Tốt:

$json = $serializer->serialize[$data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE];
2

Tránh tác dụng phụ

Một hàm sinh ra tác dụng phụ nếu nó thực hiện thêm việc khác ngoài việc lấy giá trị vào và trả về một hoặc nhiều giá trị khác. Tác dụng phụ có thể là viết vào một file nào đó, sửa đổi biến global, hoặc vô tình chuyển hết tiền của bạn cho người lạ nào đó.

Chưa tốt:

$json = $serializer->serialize[$data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE];
3

Tốt:

$json = $serializer->serialize[$data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE];
4

Tránh tác dụng phụ

Một hàm sinh ra tác dụng phụ nếu nó thực hiện thêm việc khác ngoài việc lấy giá trị vào và trả về một hoặc nhiều giá trị khác. Tác dụng phụ có thể là viết vào một file nào đó, sửa đổi biến global, hoặc vô tình chuyển hết tiền của bạn cho người lạ nào đó.

//github.com/henryonsoftware/clean-code-php

Bài Viết Liên Quan

Chủ Đề