Đừng trả lại mảng kết hợp!
Người dịch: Trần Thanh Dân Tôi ghét xử lý mảng kết hợp khi tôi phải viết code ở client. Vấn đề với mảng là không có văn bản định nghĩa. Không có kiến thức đặc biệt. Mảng kết hợp thông thường chỉ đóng gói theo một định dạng bất tiện. Tồi tệ nhất là chúng buộc ta vào một triển khai cụ thể. ...
Người dịch: Trần Thanh Dân
Tôi ghét xử lý mảng kết hợp khi tôi phải viết code ở client. Vấn đề với mảng là không có văn bản định nghĩa. Không có kiến thức đặc biệt. Mảng kết hợp thông thường chỉ đóng gói theo một định dạng bất tiện. Tồi tệ nhất là chúng buộc ta vào một triển khai cụ thể.
Tôi không có ý nói rằng bạn phải trả về mảng có dữ liệu thống nhất (return arrays that have uniform data). Trả về mảng của một số loại đối tượng là tốt (ish). Mặc dù bạn vẫn không thể báo trước thông qua API của bạn rằng nó sẽ chỉ chứa một số loại dữ liệu nhất định.
Mảng có thể hoạt động như dữ liệu đại diện nội bộ cho một số lớp (class), nhưng đó là cách chỉ nên được sử dụng ở nội bộ. Những gì tôi đang nói về sự khó chịu của mảng kết hợp với các chuỗi mã cứng (hardcoded strings) như các khóa.
Xem xét đoạn mã sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
class AcmeFileSender implements FileSender { public function sendFiles(FileCollection $files): array { $sent = 0; $errors = []; foreach ($files as $file) { try { $this->send($file); $sent++; } catch (SenderException $exception) { $errors[] = $exception->getMessage(); } } return [ "sent" => $sent, "failed" => count($errors), "errors" => $errors ]; } public function send(File $file): void {//...} } |
Vấn đề trong trường hợp này là, Chúng ta không thể biết được cấu trúc chính xác của mảng này. Điều này có nghĩa là khi chúng ta viết code ở phía client chúng ta sẽ phụ thuộc vào việc thực hiện phương thức sendFiles(). Chúng ta phải biết được chính xác khóa (key) là gì và loại dữ liệu (sort of data) của khóa đó.
Trong hướng đối tượng (OOP) chúng ta không nên quan tâm đến chi tiết thực hiện của các lớp khác, chúng ta chỉ cần quan tâm đến các phương thức hiện tại (interfaces method).
Gần đây tôi có bị vấp phải một điều gì đó có thể là một vi phạm nguyên trọng hơn:
1 2 3 4 5 6 7 8 9 10 |
public function processStuff($stuff): array { //... return [$someArray, $someObject]; } //... in client code list($someArray, $someObject) = $this->processor->processStuff($stuff); |
Bây giờ, nó là một cách để trả tồi tệ (this kind of abominations) từ phương thức riêng tư (private methods). Nhưng khi bạn đang bắt đầu thiết kế API công bố (API public) của bạn thì tất cả các hy vọng sẽ bị mất đi. Điều này có nghĩa là bạn đang xử lý với mã thủ tục (procedural code base). Trong mã thủ tục mọi thứ đều là dữ liệu và có thể sẽ bị chi phối.
Trong trường hợp trên vấn đề là thiếu định nghĩa văn bản (context). Điều này có nghĩa là khi nào bạn nhận một someArray và một someObject cùng thời điểm? Tại sao nó trả về cùng thời điểm? Rõ rang việc thực hiện phương thức processStuff() sẽ biết được về cách mà nó được sử dụng. Vì vậy nó không được thiết kế để dán cùng với một vài mã ở client. Mã client được kết hợp chặt chẽ với việc thực hiện của phương thức processStuff().
Trong nhiều trường hợp, có một số nhầm lẫn là cách xác định nhiệm vụ. Mã làm gì đó và trả về dấu hiệu thành công đến client. Không có nhiều sự tương tác giữa server và client.
Chúng ta cần làm gì để cho ví dụ ban đầu tốt hơn? Giá trị các đối tượng. sendFile() sẽ có nhiều ý nghĩa hơn bằng cách sử dụng giá trị của đối tượng.
1 2 3 4 5 6 7 8 9 |
interface SenderReport { public function sent(): int; public function failures(): int; public function errors(): Iterator; public function print(): string; } |
Chúng ta sẽ cập nhật FileSender và implementations nó.
1 2 3 4 5 6 7 8 9 10 11 |
class AcmeFileSender implements FileSender { //... public function sendFiles(FileCollection $files): SenderReport { //... return new FileSenderReport($sent, count($errors), $errors); } } |
Bây giờ chúng ta có thể dựa vào interface của SenderReport thay vì triển khai FileSender::sendFiles(). Bây giờ chúng ta đã có định nghĩa văn bản (context). Ngoài ra, chúng ta có thể thực hiện thay đổi việc triển khai (implementations) FileSender một cách tự do.
—
Tóm lại, làm ơn, đừng trả về mảng kết hợp cho API công bố. Hãy đánh giá lại kể cả khi phải return value. Và nếu bắt buộc thì cũng return cái khác có giao diện mà ban và user có thể tin tưởng dùng.
TopDev via dev.to