clean code tiếng việt chap 6

Bản clean code tiếng việt chap 6. Mong mọi người để lại những góp ý về bản dịch này.

Chúng tôi có lý do khi muốn giữ các biến là private. Chúng tôi không muốn ai đó phụ thuộc vào chúng. Chúng tôi muốn giữ để thay đổi kiểu dữ liệu hoặc thực hiện các hành động tùy biến. Nhưng sau đó thì sao?  Đã có rất nhiều lập trình viên tự động thêm getter và setter vào class của họ, điều đó chẳng khác gì thay đổi các biến private thành public.

1. Trừu tượng hóa dữ liệu

Xem xét sự khác biệt giữa Listing 6-1 và Listing 6-2. Cả hai đều đại diện cho dữ liệu của một điểm trong hệ tọa độ. Tuy nhiên, một cái thì để lộ việc triển khai trong khi cái còn lại thì không.

Trừu tượng hóa dữ liệu
Trừu tượng hóa dữ liệu

Cái hay của Listing 6-2 là không có cách nào bạn biết được việc triển khai interface. Interface rõ ràng là một dạng cấu trúc dữ liệu.

Các phương thức tuân theo một chính sách duy nhất. Bạn có thể đọc các tọa độ riêng lẻ một cách độc lập, nhưng bạn phải đặt các tọa độ lại với nhau để tạo nên một cấu trúc đầy đủ.

Listing 6-1, mặt khác, thể hiện rất rõ ràng. Điều này làm lộ dữ liệu ngay cả khi các biến là private và chúng tôi đang sử dụng các getter/setter.

Ẩn việc triển khai không đơn giản là việc đặt một biến vào giữa các hàm, đó là vấn đề trừu tượng hóa. Một class không chỉ đơn giản là đẩy các biến của nó thông qua các getter/setter. Thay vào đó nó cung cấp các abstract interface cho phép người dùng thao tác với bản chất của dữ liệu mà không cần quan tâm đến cách mà chúng hoạt động.

Chúng tôi không muốn tiết lộ chi tiết về dữ liệu, thay vào đó chúng tôi muốn giữ dữ liệu của chúng tôi ở các dạng trừu tượng. Điều này không chỉ đơn thuần được thực hiện bằng cách sử dụng các interface và/hoặc getter và setter. Sử dụng getter/setter là tùy chọn tồi tệ nhất mà tôi sẽ thực hiện.

2. Cấu trúc dữ liệu và đối tượng

Hai ví dụ bên dưới cho thấy sự khác biệt giữa các dữ liệu có cấu trúc và đối tượng.

Các đối tượng ẩn dữ liệu của chúng bên dưới trừu tượng hóa và đưa ra các hàm dựa trên những dữ liệu đó.

Dữ liệu có cấu trúc phơi bày dữ liệu của chúng và không có các hàm có nhiều ý nghĩa.

Lưu ý bản chất của hai định nghĩa này. Chúng thực sự đối lập nhau. Sự khác biệt này có vẻ không đáng kể, nhưng nó có ảnh hưởng sâu đến hệ thống.

Ví dụ, xem xét ví dụ về các class liên quan đến hình học trong Listing 6-5:

Class Geometry hoạt động với dữ liệu của ba class khác, là các cấu trúc dữ liệu đơn giản mà không có bất kỳ phương thức nào. Các hành động đều thuộc về class Geometry.

cấu trúc dữ liệu đơn giản
cấu trúc dữ liệu đơn giản

Các lập trình viên hướng đối tượng có thể sẽ không đồng ý với điều này và cho rằng đó là một phương pháp của họ  và chúng đúng. Nhưng người khác có thể nhìn vào và chê cười vì chúng không được quan tâm và bảo trì.

Chuyện gì xảy ra nếu tôi thêm vào class Geometry một hàm nữa? Không sao cả, các class bên trên nó sẽ không bị ảnh hưởng. Nhưng nếu tôi thêm vào một class mới, tôi phải thay đổi các hàm trong class Geometry để phù hợp với nó.

Một lần nữa, chúng ta thấy sự đối lập giữa hai vấn đề này. Điều này chỉ ra sự khác biệt cơ bản giữa các đối tượng và cấu trúc dữ liệu:

Các dòng code sử dụng phương pháp cấu trúc dữ liệu giúp dễ dàng thêm vào các hàm mới mà không cần phải thay đổi cấu trúc của dữ liệu hiện tại.

Mặt khác, code theo phương pháp hướng đối tượng giúp dễ dàng thêm các class mới mà không thay đổi các hàm đã viết.

Bạn cũng có thể hiểu nó như sau:

Code theo cấu trúc dữ liệu làm bạn khó thêm dữ liệu mới vì phải thay đổi toàn bộ hàm. Code theo hướng đối tượng làm bạn khó thêm hàm vì phải thay đổi tất cả các class chịu ảnh hưởng.

Vậy là, ưu điểm của phương pháp này lại là nhược điểm của phương pháp kia, và ngược lại.

Trong bất kỳ hệ thống nào, có lúc chúng ta muốn bổ sung các kiểu dữ liệu mới thay vì các hàm mới. Trong trường hợp này phương pháp hướng đối tượng sẽ phù hợp hơn.

Nhưng cũng có lúc chúng ta muốn thêm hàm mới thay vì thêm dữ liệu. Trong trường hợp này, cấu trúc dữ liệu nên được ưu tiên hơn.

Các lập trình viên giàu kinh nghiệm biết rằng ý tưởng đối tượng hóa mọi thứ là chuyện hoang đường.

3. The Law of Demeter

Kỹ thuật Law of Demeter nói rằng một module không nên biết về thành phần bên trong của một đối tượng mà nó sử dụng.

Điều này có nghĩa là các đối tượng không nên phơi bày cấu trúc của chúng thông qua các getter/setter . Vì việc này làm lộ cấu trúc bên trong nó, điều chúng ta cần làm là ẩn chúng đi.

3.1 Train Wrecks

Dạng code này thường được gọi là train wreck  vì nó trông giống như một loạt các toa tàu được ghép lại với nhau.

Vấn đề này sẽ ít gây nhầm lẫn hơn nếu các cấu trúc đơn giản và chỉ có biến public và không có phương thức, trong khi các đối tượng có các biến private và các hàm public. Tuy nhiên, có một vài framework yêu cầu rằng ngay cả các cấu trúc dữ liệu đơn giản cũng cần phải có các hàm truy cập.

3.2 Con lai

Sự nhầm lẫn này đôi khi tạo nên các đứa con lai, mang nửa dòng máu đối tượng và một nửa còn lại là cấu trúc.

Chúng có các hàm làm những việc quan trọng, chúng cũng có các biến public hoặc các hàm truy cập public,… Với mục đích cuối cùng là hô biến các biến private thành public. Làm các hàm bên ngoài sử dụng các biến private (thông qua getter/setter) như một cấu trúc đơn giản.

Những đứa con lai này khiến cho việc thêm mới hàm trở nên khó khăn, và việc thêm thuộc tính mới cũng khó khăn nốt. Chúng là thứ tồi tệ nhất mà bạn sẽ tạo ra, vậy nên đừng tạo ra chúng.

4. Data Transfer Objects

Dạng thuần túy của cấu trúc dữ liệu là class có các biến public và không có hàm. Dạng này được gọi là một đối tượng truyền dữ liệu (Data transfer object), hoặc DTO. DTO là cấu trúc rất hữu ích, đặc biệt là khi giao tiếp với cơ sở dữ liệu hoặc chuyển đổi thông điệp từ các socket, v.v.

thuần túy của cấu trúc dữ liệu
thuần túy của cấu trúc dữ liệu clean code tiếng việt

4.1 Active Records

Active Record là các hình thức DTO đặc biệt. Chúng là các cấu trúc dữ liệu với các biến public, đôi khi có các phương thức như Save và Find. Thông thường các Active Record là dữ liệu được gửi trực tiếp từ các bảng trong cơ sở dữ liệu hoặc các nguồn dữ liệu khác.

chúng ta thường thấy các nhà phát triển đối xử với cấu trúc này như thể chúng là đối tượng bằng cách đặt các phương thức nghiệp vụ vào chúng. Điều này thật nguy hiểm.

5. Kết luận

Đối tượng hiển thị ra các hành động và ẩn dữ liệu. điều này giúp dễ dàng thêm các loại đối tượng mới mà không thay đổi các hành vi hiện có. Nhưng nó cũng làm cho việc thêm các phương thức mới vào đối tượng hiện có trở nên khó khăn.

Trong bất kỳ hệ thống nào, đôi khi chúng tôi sẽ muốn việc thay đổi dữ liệu trở nên linh hoạt. Vì vậy chúng tôi chọn đối tượng cho hệ thống. Nhưng thỉnh thoảng cần thêm những hàm mới, và vì vậy chúng tôi cần chọn kiểu cấu trúc. Các nhà phát triển phần mềm giỏi luôn biết cách tiếp cận tốt nhất trong những trường hợp này.

6. Tham khảo

clean code tiếng việt chap 1

Cảm ơn các bạn đã đọc. Mong nhận được những góp ý của các bạn để mình hoàn thiện hơn nữa

Leave a Reply