Có thể quá nhiều trừu tượng là xấu?


46

Là lập trình viên, tôi cảm thấy rằng mục tiêu của chúng tôi là cung cấp sự trừu tượng tốt về mô hình miền và logic kinh doanh nhất định. Nhưng sự trừu tượng này nên dừng lại ở đâu? Làm thế nào để đánh đổi giữa sự trừu tượng và tất cả lợi ích của nó (tính linh hoạt, dễ thay đổi, v.v.) và dễ hiểu mã và tất cả lợi ích của nó.

Tôi tin rằng tôi có xu hướng viết mã quá trừu tượng và tôi không biết nó tốt như thế nào; Tôi thường có xu hướng viết nó giống như nó là một loại khung vi mô, bao gồm hai phần:

  1. Các mô-đun vi mô được nối trong khung vi mô: các mô-đun này dễ hiểu, được phát triển và duy trì dưới dạng các đơn vị. Mã này về cơ bản đại diện cho mã thực sự làm các công cụ chức năng, được mô tả trong các yêu cầu.
  2. Mã kết nối; Bây giờ ở đây tôi tin đứng vấn đề. Mã này có xu hướng phức tạp vì đôi khi nó rất trừu tượng và khó hiểu ngay từ đầu; điều này phát sinh do thực tế rằng nó chỉ là sự trừu tượng thuần túy, cơ sở trong thực tế và logic kinh doanh được thực hiện trong mã trình bày 1; từ lý do này, mã này dự kiến ​​sẽ không được thay đổi sau khi thử nghiệm.

Đây có phải là một cách tiếp cận tốt trong lập trình? Rằng, việc thay đổi mã rất phân mảnh trong nhiều mô-đun và rất dễ hiểu và mã không thay đổi rất phức tạp từ POV trừu tượng? Nếu tất cả các mã phải phức tạp đồng đều (đó là mã 1 phức tạp hơn và liên kết với nhau và mã 2 đơn giản hơn) để bất kỳ ai nhìn qua đều có thể hiểu nó trong một khoảng thời gian hợp lý nhưng thay đổi là tốn kém hoặc giải pháp được trình bày ở trên là tốt, trong đó "Thay đổi mã" rất dễ hiểu, gỡ lỗi, thay đổi và "mã liên kết" là loại khó.

Lưu ý: đây không phải là về khả năng đọc mã! Cả mã ở 1 và 2 đều có thể đọc được, nhưng mã ở 2 đi kèm với trừu tượng phức tạp hơn trong khi mã 1 đi kèm với trừu tượng đơn giản.


3
Nhận xét và tên rõ ràng được phát minh để đẩy nhanh thời gian cần thiết để hiểu mã phức tạp. Hoàn toàn ổn khi mã cấp thấp của bạn phức tạp hơn; Ở một mức độ nào đó, bạn gần như chắc chắn gọi một mức độ phức tạp hơn và thấp hơn nhiều.
DougM

25
Định nghĩa quá nhiều là xấu theo định nghĩa.
Jon Purdy

@JimmyHoffa: Phải giữ những kiểu đó ở vị trí của chúng. Và đừng ghen tị với tôi. Tôi không được viết Haskell cả ngày. Nó chủ yếu là PHP, JavaScript và OCaml.
Jon Purdy

Câu trả lời:


78

Những từ đầu tiên của TC ++ PL4:

Tất cả các vấn đề trong khoa học máy tính có thể được giải quyết bằng một mức độ gián tiếp khác, ngoại trừ vấn đề có quá nhiều lớp không xác định. - David J. Wheeler

(David Wheeler là cố vấn luận án của tôi. Câu trích dẫn không có dòng cuối cùng quan trọng đôi khi được gọi là "Định luật đầu tiên của Khoa học Máy tính.")


6
Và làm thế nào để bạn biết khi bạn có quá nhiều mức độ gián tiếp? Tôi có xu hướng nói rằng nó đi kèm với kinh nghiệm, nhưng một lập trình viên giàu kinh nghiệm hơn dễ dàng hiểu được sự thiếu quyết đoán hơn do đó không thấy vấn đề với quá nhiều cấp độ.
m3th0dman

2
@ m3th0dman - bạn có mức độ trừu tượng phù hợp khi dễ dàng thực hiện các thay đổi trong tương lai. Tất nhiên, bạn cũng có thể hỏi làm thế nào bạn biết khi nào điều đó sẽ xảy ra mà chỉ lặp lại chu kỳ câu hỏi theo một cách khác.


1
câu hỏi này giống như phụ thuộc ở cấp độ lập trình viên .. bạn sẽ có những lập trình viên phức tạp sẽ hiểu kiến ​​trúc lớp 8 điên rồ của bạn và thấy nó thật tuyệt vời, trong khi các lập trình viên đơn giản nhưng trơn tru khác sẽ thấy nó thật lố bịch & tranh cãi về tầng 8 điên rồ của bạn dự án lớp .. đây là nơi tài liệu được đền đáp, nó không chỉ cho phép bạn ghi lại mã của mình mà còn cho phép bạn bảo vệ nó
Ryan

1
tha thứ cho sự thiếu hiểu biết của tôi, nhưng tôi không hiểu "TC ++ PL4"
LastTribunal

30

Vâng chắc chắn. Điều này là, không có sự trừu tượng là hoàn hảo. Tất cả các chi tiết của lớp trừu tượng nằm ở trên đều có lý do và nó có thể đơn giản hóa rất nhiều thứ, nhưng nếu sự phức tạp đó không cần thiết ở một số điểm, thì có lẽ nó sẽ không ở đó ngay từ đầu. Và điều đó có nghĩa là tại một số điểm, mọi sự trừu tượng sẽ bị rò rỉ theo một cách nào đó.

Và đó là vấn đề thực sự nằm ở đâu. Khi trừu tượng thất bại, bạn càng đặt nhiều lớp giữa mã bạn đã viết và những gì đang thực sự xảy ra, càng khó tìm ra vấn đề và khắc phục nó, bởi vì có nhiều vấn đề hơn có thể xảy ra. Và càng có nhiều lớp, bạn càng phải biết để theo dõi nó.


1
"Và điều đó có nghĩa là tại một số điểm, mọi sự trừu tượng sẽ bị rò rỉ theo một cách nào đó.": Đúng. Một sự trừu tượng tốt hơn là một sự rò rỉ ít thường xuyên hơn.
Giorgio

11
Theo câu trả lời của Bjarne (và tham khảo trang wiki của David Wheeler ), có lẽ bạn có thể thay đổi thuộc tính trích dẫn của mình? :)
congusbongus

2
@CongXu: Btw Tôi đã đi đến nó từ đầu bên kia: googling cho "Bjarne Stroustrup trích dẫn" và không tìm thấy một tài liệu tham khảo nào về Bjarne đã thốt ra cụm từ "thêm một lớp khác làm cho nó rất khó có thể là người đầu tiên nói ra nó.
Marjan Venema

1
Nhiều lớp trừu tượng hơn có nghĩa là trừu tượng đơn giản và do đó ít rò rỉ trên mỗi trừu tượng. Vì vậy, trong một công thức toán học (tất nhiên, không có bất kỳ bằng chứng nào), tổng rò rỉ trừu tượng có thể không đổi khi số lượng mức độ trừu tượng thay đổi.
m3th0dman

2
Tôi đã từng ngây thơ lấy lời khuyên của một cấp cao để thêm một sự trừu tượng khi không cần thiết. Nó không bao giờ được sử dụng ngoài những gì tôi muốn làm ở nơi đầu tiên.
Cees Timmerman

15

Chắc chắn rồi.

Sự tương tự tôi muốn sử dụng để giải thích lập trình là của một Thợ may. Khi may một bộ đồ, một Thợ may giỏi sẽ luôn để một lượng nhỏ vải tại các vị trí chiến lược trong quần áo để cho phép quần áo được đưa vào, hoặc ra ngoài, mà không thay đổi hình dạng hoặc cấu trúc tổng thể của nó.

Good Tailor không để lại những dải vải ở mỗi đường may chỉ khi bạn tình cờ mọc cánh tay thứ ba hoặc mang thai. Quá nhiều chất liệu ở những vị trí không phù hợp sẽ khiến cho trang phục không phù hợp, và mặc không tốt, vải thừa chỉ đơn giản là cản trở việc sử dụng thông thường. Ít vải và quần áo dễ bị rách và sẽ không thể thay đổi để đối phó với những thay đổi nhỏ đối với vóc dáng của người mặc, ảnh hưởng đến cách mặc quần áo.

Có lẽ một ngày nào đó, Thợ may giỏi của chúng ta sẽ được giao nhiệm vụ làm cho một chiếc váy bó sát đến nỗi anh ta phải khâu nó vào đó. Và có lẽ Good Tailor của chúng tôi được yêu cầu làm cho bà bầu, trong đó phong cách và phù hợp là thứ hai để thoải mái và mở rộng khả năng. Nhưng trước khi thực hiện một trong những công việc đặc biệt đó, một Thợ may giỏi sẽ đủ khôn ngoan để khiến mọi người nhận thức được những thỏa hiệp đang được thực hiện để đạt được những mục tiêu đó.

Đôi khi những thỏa hiệp này là con đường chính xác cần thực hiện và mọi người sẵn sàng chấp nhận hậu quả của chúng. Nhưng trong hầu hết các trường hợp, cách tiếp cận để lại một chút trong đó nó được tính nhiều nhất sẽ vượt trội hơn bất kỳ lợi ích nhận thức nào.

Vì vậy, liên quan đến điều này trở lại trừu tượng. Nó hoàn toàn có thể có cách quá nhiều lớp trừu tượng, giống như có thể có cách để ít. Nghệ thuật thực sự của lập trình viên, giống như những người bạn thợ may của chúng tôi, là để lại một chút nơi mà nó quan trọng nhất.

Trở lại chủ đề.

Vấn đề với mã thường không phải là trừu tượng, mà là phụ thuộc. Như bạn đã chỉ ra, mã của nó kết nối các đối tượng rời rạc là một vấn đề, bởi vì có một sự phụ thuộc ngầm giữa chúng. Tại một số điểm giao tiếp giữa mọi thứ chỉ cần cụ thể, nhưng đánh giá điểm đó thường đòi hỏi một số phỏng đoán.

Điều đó được nói là "Micro" bất cứ điều gì thường là một dấu hiệu cho thấy bạn đã quá mức bố cục đối tượng của mình và có thể đang sử dụng Loại làm từ đồng nghĩa cho dữ liệu nên là Dữ liệu . Có ít thứ hơn cũng có nghĩa là ít phụ thuộc hơn cần thiết để giao tiếp giữa chúng.

Tôi là một fan hâm mộ lớn của nhắn tin không đồng bộ giữa các hệ thống vì lý do này. Bạn kết thúc với hai hệ thống phụ thuộc vào tin nhắn , chứ không phải là nhau. Cung cấp cho bạn ít khớp nối chặt chẽ giữa các hệ thống giao tiếp. Tại thời điểm đó, nếu bạn cần có sự phụ thuộc giữa các hệ thống, bạn cần xem xét liệu bạn có các bit phụ thuộc vào đúng vị trí hay không. Và nó thường là trường hợp mà bạn không.

Cuối cùng, mã phức tạp sẽ phức tạp. Thường không có cách nào khác. Nhưng mã có ít phụ thuộc thì dễ hiểu hơn nhiều so với mã dựa trên các trạng thái bên ngoài khác nhau.


2
+1 cho "Good Tailor's không để lại các dải vải ở mỗi đường may chỉ khi bạn tình cờ mọc cánh tay thứ ba hoặc mang thai". Chúng ta thường có xu hướng thiết kế phần mềm theo cách này, thật đáng buồn.
Kemoda

Cùng với sự dễ hiểu, người ta cũng có thể thấy sự trừu tượng hữu ích khi uốn một đường cong thành một đường thẳng. Có nghĩa là bạn đang giảm độ phức tạp và / hoặc entropy với sự trừu tượng. Có lẽ một cái gì đó giống như một trình xử lý dữ liệu kiểu Curry, nơi chất béo bạn cạo vẫn còn hữu ích sau này.
Cody

13

Tôi cảm thấy rằng mục tiêu của chúng tôi là cung cấp sự trừu tượng tốt về mô hình miền và logic kinh doanh nhất định.

Tôi có một quan điểm khác: mục tiêu của chúng tôi là giải quyết một vấn đề kinh doanh. Trừu tượng chỉ là một kỹ thuật để tổ chức một giải pháp. Một câu trả lời khác sử dụng sự tương tự của một thợ may làm quần áo. Tôi có một sự tương tự khác mà tôi muốn nghĩ đến: một bộ xương. Mã giống như một bộ xương và trừu tượng là khớp giữa các xương. Nếu bạn không có khớp, thì bạn chỉ cần cuộn một xương duy nhất mà không thể di chuyển được và vô dụng. Nhưng nếu bạn có quá nhiều khớp, bạn sẽ có một đống thạch mềm mại không thể tự đứng lên được. Bí quyết là tìm sự cân bằng phù hợp - đủ khớp để cho phép di chuyển, nhưng không nhiều đến mức không có hình dạng hoặc cấu trúc xác định thực tế.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.