Rich Hickey có ý nghĩa gì khi anh ấy nói, về tất cả tính đặc thù đó [của giao diện / lớp / loại] giết chết việc tái sử dụng của bạn!


41

Trong bài phát biểu về hội nghị goto kích thích tư duy của Rich Hickey " Giá trị của các giá trị " vào lúc 29 phút, ông nói về sự vượt trội của ngôn ngữ như Java và đưa ra một tuyên bố như: "Tất cả các giao diện đó đều giết chết việc sử dụng lại của bạn." Ý của anh ta là gì? Điều đó có đúng không?

Trong quá trình tìm kiếm câu trả lời, tôi đã chạy qua:

  • Nguyên tắc tối thiểu của kiến ​​thức AKA Luật Demeter khuyến khích các giao diện API kín khí. Wikipedia cũng liệt kê một số nhược điểm.

  • Cuộc khủng hoảng quần áo hoàng gia của Kevlin Henney lập luận rằng sử dụng, không sử dụng lại là mục tiêu phù hợp.

  • Bài nói chuyện " Dừng viết lớp " của Jack Diederich , lập luận chống lại kỹ thuật quá mức nói chung.

Rõ ràng, bất cứ điều gì viết đủ xấu sẽ là vô ích. Nhưng làm thế nào để giao diện của một API được viết tốt ngăn chặn mã đó được sử dụng? Có những ví dụ trong suốt lịch sử của một thứ được tạo ra cho một mục đích được sử dụng nhiều hơn cho mục đích khác . Nhưng trong thế giới phần mềm, nếu bạn sử dụng thứ gì đó cho mục đích mà nó không nhằm mục đích, nó thường bị hỏng.

Tôi đang tìm kiếm một ví dụ điển hình về giao diện tốt ngăn chặn việc sử dụng một số mã hợp pháp nhưng ngoài ý muốn. Điều đó có tồn tại không? Tôi không thể hình dung nó.


1
Chưa xem / đọc nội dung (Tôi đã thêm "Dừng viết lớp" vào danh sách cần theo dõi của mình :)), nhưng có lẽ họ đang tranh luận từ góc độ động so với kiểu gõ tĩnh? ...lần nữa?
Andres F.

oO Giao diện giao diện lập trình ứng dụng
Thomas Eding

Cảm ơn các liên kết! Tôi không thấy bài nói chuyện của Jack Diederich đặc biệt sáng tỏ (xem cách anh ta không trả lời các câu hỏi thực sự của khán giả một cách thuyết phục .. "uh, vâng, có lẽ trong trường hợp đó ...". Tôi dường như anh ta đang tranh luận về Lập trình chức năng mà không thậm chí nhận thấy nó;)), nhưng "Khủng hoảng quần áo Hoàng gia" là rất tốt và sâu sắc.
Andres F.

1
MPO là những người không tin vào việc tái sử dụng sẽ không chia mọi thứ thành các đơn vị đủ nhỏ. Một thứ lớn được xây dựng cho một mục đích cụ thể không thể được sử dụng lại. Tuy nhiên, những điều nhỏ thường có một mục đích đủ nhỏ mà mục đích nhỏ có ích trong nhiều bối cảnh.
Amy Blankenship

1
@AmyBlankenship Tôi thấy "Khủng hoảng Quần áo Hoàng gia" được liên kết ở trên là sâu sắc. Tác giả coi "tái sử dụng" một thần tượng sai lầm (một điều chưa được chứng minh là hữu ích trong thực tế và hầu hết mọi người thậm chí không hiểu nó ngay cả khi họ sử dụng từ này). Ông cũng không xem xét các thư viện "tái sử dụng"; bạn sử dụng một thư viện, bạn không sử dụng lại nó. Ông cũng xem xét việc thiết kế một cái gì đó để tái sử dụng "con dao hai lưỡi"; một cái gì đó mà mọi người thường coi là một tình huống đôi bên cùng có lợi nhưng thực sự không phải là: khi bạn thiết kế một thứ gì đó để tái sử dụng, nó luôn luôn là một sự thỏa hiệp (ví dụ bạn có thể mất một cách đơn giản)
Andres F.

Câu trả lời:


32

Haven đã không xem bản trình bày Rich Hickey đầy đủ, nhưng nếu tôi hiểu anh ta một cách chính xác và đánh giá từ những gì anh ta nói về mốc 29 phút, anh ta dường như đang tranh cãi về các kiểu giết người tái sử dụng. Ông đang sử dụng thuật ngữ "giao diện" một cách lỏng lẻo như một từ đồng nghĩa với "loại được đặt tên", có nghĩa.

Nếu bạn có hai thực thể { "name":"John" }loại Person{ "name": "Rover" }loại Dog, trong vùng đất Java, chúng có thể không thể tương tác với nhau trừ khi chúng có chung giao diện hoặc tổ tiên (như Mammal, có nghĩa là viết thêm mã). Vì vậy, các giao diện / loại ở đây là "giết chết việc tái sử dụng của bạn": mặc dù PersonDogtrông giống nhau, một giao diện không thể được sử dụng thay thế cho nhau, trừ khi bạn viết mã bổ sung để hỗ trợ điều đó. Lưu ý Hickey cũng nói đùa về các dự án trong Java cần rất nhiều lớp ("Ai ở đây đã viết một ứng dụng Java chỉ bằng 20 lớp?"), Có vẻ như là một hệ quả của điều trên.

Tuy nhiên, trong các ngôn ngữ "định hướng giá trị", bạn sẽ không gán các loại cho các cấu trúc đó; chúng chỉ là các giá trị xảy ra để chia sẻ cùng một cấu trúc (trong ví dụ của tôi, cả hai đều có một nametrường có giá trị Chuỗi) và do đó có thể dễ dàng tương tác với nhau, ví dụ: chúng có thể được thêm vào cùng một bộ sưu tập, được truyền cho cùng một phương thức, v.v.

Tóm lại, tất cả điều này dường như là một cái gì đó về sự bình đẳng cấu trúc so với sự bình đẳng loại / giao diện rõ ràng . Trừ khi tôi bỏ lỡ điều gì đó từ các phần của video tôi chưa xem :)


2
BTW, bài nói chuyện "Dừng các lớp học viết" của Jack Diederich dường như không liên quan đến chủ đề này, và nói thêm về YAGNI và "không viết mã cho đến khi bạn cần nó, và sau đó chỉ viết mã đơn giản".
Andres F.

9
ERROR: Object doesn't have a property called "name"thường là kết quả của các value-orientedngôn ngữ và vấn đề khác là khi bạn không muốn gọi thuộc tính đó namenữa. Chúc may mắn tái cấu trúc vì có khả năng hàng trăm đối tượng có tài sản namenhưng không phải tất cả đều Personhoặc Dog.
Phản ứng

2
@MathewFoscarini Vâng, tôi không nhất thiết phải đồng ý với nó, đó chỉ là cách giải thích của tôi về những gì tôi nghĩ Hickey đang nói :) Tôi thích kiểu gõ và gõ tĩnh; Tôi mới bắt đầu không thích Java. Và sự không thích của tôi không liên quan đến interfaces nhưng với mớ hỗn độn đó là dự án Java điển hình.
Andres F.

1
Java là ngôn ngữ lập trình cho những người thích suy nghĩ quá nhiều. Đó là một trong số ít các ngôn ngữ cho phép nhà phát triển dễ dàng che giấu những nỗ lực của mình để thiết kế dự án.
Phản ứng

"Trong các ngôn ngữ" định hướng giá trị ", bạn sẽ không gán các loại cho các cấu trúc đó" - Tôi nghĩ bạn cần nói "Trong định hướng động" theo giá trị "..." Haskell và Scala là định hướng giá trị, nhưng hệ thống loại tĩnh của chúng cung cấp cho họ các vấn đề chính xác mà bạn đang mô tả. Tôi nghĩ rằng giải pháp cho vấn đề này không phải là giá trị nhiều như sử dụng bản đồ để truyền tham số cho các hàm. Sử dụng bản đồ bất biến (giá trị) chỉ an toàn hơn.
GlenPeterson

28

Anh ta có thể đề cập đến một thực tế cơ bản là một giao diện không thể được khởi tạo. Bạn không thể reusegiao diện. Bạn chỉ có thể triển khai mã hỗ trợ nó và khi bạn viết mã cho giao diện thì không có việc sử dụng lại.

Java có lịch sử cung cấp các khung của nhiều API lấy giao diện làm đối số, nhưng nhóm phát triển API không bao giờ triển khai một loạt các lớp để bạn sử dụng lại với các giao diện đó.

Nó giống như một khung GUI có IWindowgiao diện cho hộp thoại và sau đó bạn có thể thêm IButtongiao diện cho các điều khiển. Ngoại trừ, họ không bao giờ cho bạn một Buttonlớp học tốt mà thực hiện IButton. Vì vậy, bạn còn lại để tạo của riêng bạn.

Các khung trừu tượng có một loạt các lớp cơ sở cung cấp các chức năng cốt lõi có thể tái sử dụng nhiều hơn và hoạt động tốt nhất khi các lớp trừu tượng đó có thể truy cập được đối với những người sử dụng khung.

Các nhà phát triển Java đã bắt đầu thực hiện điều này khi các lớp API của họ chỉ hiển thị interfaces. Bạn có thể thực hiện các giao diện đó, nhưng bạn không bao giờ có thể sử dụng lại các lớp từ nhà phát triển đã triển khai các giao diện đó. Nó giống như một kiểu áo choàng và dao găm trong phát triển API.


4
Cảm ơn bạn cho câu trả lời này. Bây giờ tôi cảm thấy như tôi hiểu câu hỏi câu trả lời :)
MetaFight

2
+1 Tôi thực sự đánh giá cao câu trả lời của bạn và nó bổ sung một lớp thông tin thú vị cho câu hỏi này. Nhưng tôi nghĩ câu trả lời của Andreas F. có thể gần với trung tâm của ý nghĩa của ông Hickey, vì vậy tôi đã chấp nhận thay vào đó.
GlenPeterson

@GlenPeterson không có vấn đề gì, tôi nghĩ anh ấy cũng có thể được đánh dấu.
Phản ứng

1
Vâng, câu trả lời được chấp nhận này làm nổi bật hai cách giải thích hơi khác nhau, nhưng không kém phần thú vị. Tôi tò mò về điều mà ông Hickey đã nghĩ đến khi nói về điều này ..
David Cowden

Bạn không thể sử dụng lại một giao diện, nhưng bạn có thể mở rộng nó (và đưa ra số phiên bản có giá trị) mà không thay đổi các lớp cũ. Bạn cũng có thể kế thừa từ nhiều giao diện để thêm công việc mới cho các lớp mới hoặc thêm kế thừa mới trong các lớp được biên dịch lại cũ. Bạn cũng có thể mở rộng lớp thực hiện giao diện này cho công việc mới.
cl-r

14

Tôi nghĩ slide 13 trong bài thuyết trình của mình ( Giá trị của các giá trị ) giúp hiểu điều này:

http://i.stack.imgur.com/LVMne.png


Giá trị

  • Không cần phương pháp
    • Tôi có thể gửi cho bạn các giá trị mà không cần mã
      và bạn vẫn ổn

Hiểu biết của tôi là, Hickey gợi ý rằng nếu tôi cần, nói, nhân đôi giá trị bạn gửi cho tôi, tôi chỉ cần viết mã trông giống như

    MyValue = Double(YourValue)

Bạn thấy, mã ở trên là như nhau, cho dù bạn đã gửi loại giá trị nào - loại tái sử dụng hoàn hảo .

Bây giờ, làm thế nào điều này sẽ trông giống như trong ngôn ngữ có các đối tượng và giao diện?

    Doublable MyValue = YourValue.Double()

chờ đã Nếu YourValuekhông thực hiện Doublablethì sao? không phải là nó không thể được nhân đôi, nó hoàn toàn có thể nhưng ... nếu không có phương pháp Double thì sao? (nếu có một phương thức gọi là nói thì TwiceAsMuchsao?)

Uh oh chúng tôi có một vấn đề. YourValue.Doublesẽ không hoạt động, nó không thể được sử dụng lại nữa. Theo cách đọc của tôi về slide trên, đây là về ý nghĩa của Hickey khi anh ta nói, "Tất cả các giao diện đó đều giết chết việc tái sử dụng của bạn!"

Bạn thấy, các giao diện giả định rằng các đối tượng được truyền xung quanh "cùng với các phương thức của chúng", cùng với mã hoạt động trên các phương thức này. Để sử dụng các đối tượng, người ta cần hiểu cách gọi mã đó, phương thức nào để gọi.

Khi phương thức dự kiến bị thiếu, có một vấn đề, mặc dù về mặt ngữ nghĩa , hoạt động mong muốn có ý nghĩa hoàn hảo cho một đối tượng. Như đã nêu trong phần trình bày, các giá trị không cần phương thức ("Tôi có thể gửi cho bạn các giá trị mà không cần mã và bạn vẫn ổn"), cho phép viết mã xử lý chúng theo cách chung.


Lưu ý bên lề: khái niệm chuyển xung quanh các giá trị không có mã bằng cách nào đó nhắc nhở tôi về một mẫu Flykg trong OOP.

một đối tượng giảm thiểu việc sử dụng bộ nhớ bằng cách chia sẻ càng nhiều dữ liệu càng tốt với các đối tượng tương tự khác; đó là một cách để sử dụng các đối tượng với số lượng lớn khi một biểu diễn lặp lại đơn giản sẽ sử dụng một lượng bộ nhớ không thể chấp nhận được ... Các đối tượng có trọng lượng là theo các đối tượng giá trị định nghĩa . Nhận dạng của thể hiện đối tượng là không có kết quả, do đó hai trường hợp Fly trọng lượng có cùng giá trị được coi là bằng nhau ...

Các cách sử dụng Fly trọng lượng mà tôi đã thấy thường tuân theo cùng một cách tiếp cận là loại bỏ mã (phương thức, giao diện) khỏi các đối tượng và chuyển các thứ xung quanh, cũng như các giá trị không có mã , hy vọng rằng việc nhận mã có nghĩa là cần thiết để vận hành các mã này.

Điều này cảm thấy khá giống như trong slide, "các giá trị không cần phương thức. Tôi có thể gửi cho bạn các giá trị mà không cần mã và bạn vẫn ổn".


5
Generics sẽ khá nhiều vấn đề đó. Nhân đôi có ý nghĩa trên một số đối tượng, nhưng không phải trên các đối tượng khác. Trong ngôn ngữ Go, có triển khai giao diện ngầm (một dạng gõ vịt), vì vậy bạn không phải lo lắng về tất cả các giao diện đó. Mặt khác, bạn phải biết đối tượng nào sẽ bị tấn công bởi chữ ký phương thức của bạn; nếu không, bạn có thể nhận được kết quả bất ngờ. Luôn có sự đánh đổi.
Robert Harvey

1
Một mất thú vị. Câu trả lời tốt!
maple_shaft

2
Mô hình cân nặng không phải là những gì Rich đang nói đến. Như câu thứ hai của bài viết nêu rõ, mục đích của mô hình bay bổng là để bảo tồn bộ nhớ. Cách tiếp cận của Rich không tìm cách làm điều đó.

5
MyValue = Double(YourValue)sẽ không có ý nghĩa nếu YourValue là Chuỗi, Địa chỉ, Người dùng, Hàm hoặc Cơ sở dữ liệu. Mặt khác, đối số phương thức bị thiếu của bạn là một đối số mạnh. OTOH, các phương thức truy cập cho phép bạn thực thi các ràng buộc khác nhau để các Giá trị của bạn hợp lệ và chỉ các hoạt động hợp lý được sử dụng để tạo ra các Giá trị mới. Nếu sau này bạn quyết định tách Địa chỉ khỏi Người dùng và Công ty, các phương thức truy cập có nghĩa là bạn không phá vỡ tất cả các ứng dụng khách của mã của mình. Vì vậy, họ có thể giúp tái sử dụng trong dài hạn ngay cả khi đôi khi họ cản trở nó trong ngắn hạn.
GlenPeterson

4
(Mặt khác, tôi đồng ý rằng ở vùng đất Java, sự bùng nổ của các lớp, giao diện và khung là một cơn ác mộng. Giải pháp "enterprisey" đơn giản nhất trong Java là một mớ hỗn độn của mã. câu hỏi và câu trả lời, mà không nhất thiết phải đồng ý với công cụ đánh máy động)
Andres F.

2

Trong một lớp (giao diện thế giới lý tưởng) của tôi sẽ luôn mô tả hành vi, nhưng thực tế là tất cả quá thường xuyên họ thực sự chỉ kết thúc việc mô tả dữ liệu. Chỉ mới hôm qua tôi đã xem video về một người nào đó xây dựng một BankAccountlớp được gọi là không có gì khác hơn là được tôn vinh int(thực sự nó ít hữu ích hơn nhiều so với int, do đó, "giết chết" việc sử dụng lại mà tôi đã bỏ qua như một int), tất cả trong tên của thiết kế 'tốt'. Số lượng mã, mồ hôi và nước mắt bị lãng phí khi liên tục phát minh lại các biểu diễn dữ liệu phức tạp là đáng kinh ngạc; nếu bạn không sử dụng dữ liệu theo cách có ý nghĩa thì làm ơn hãy để nó.

Bây giờ, đây là giai đoạn Rich Hickey thỏa mãn ném em bé ra ngoài bằng nước tắm và nói rằng tất cả chúng ta nên sống trong vùng đất của những giá trị (một người hàng xóm của vương quốc danh từ). Tôi nghĩ, mặt khác, OOP có thể và không thúc đẩy việc tái sử dụng (và quan trọng là khả năng khám phá, điều mà tôi thấy thiếu lập trình chức năng) khi được sử dụng một cách thận trọng. Nếu bạn đang tìm kiếm một nguyên tắc OOP nắm bắt tốt nhất sự căng thẳng này, tôi nghĩ đó có thể là http://c2.com/cgi/wiki?TellDontAsk (tất nhiên là anh em họ thân thiết của Demeter)


Bạn có ý nghĩa gì bởi sự khám phá? Nó có giống với cái này không?

1
Vâng, tôi nghĩ rằng chạm vào rất nhiều điểm chính. Đó là một điểm tinh tế nhưng khả năng khám phá là một hành động cân bằng, làm cho mọi thứ quá minh bạch cũng là điều không mong muốn vì bạn sẽ nhận được tín hiệu xấu về tỷ lệ nhiễu.
RèmDog
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.