Rich Hickey说道:“ [接口/类/类型]的所有特殊性杀死了您的重用!”是什么意思?


41

在Rich Hickey 在第29分钟发人深省的goto会议主题演讲“ 值的价值 ”中,他谈论的是Java之类的语言的开销,并声明“所有这些接口都会破坏您的重用”。他什么意思?真的吗?

在寻找答案时,我遇到了:

  • 最少知识原则(又称为“德米特定律”)鼓励密闭的API接口。维基百科还列出了一些缺点。

  • 凯夫林·汉尼(Kevlin Henney)的《帝国服装危机》认为,使用而不是重复使用是适当的目标。

  • 杰克·迪埃德里奇(Jack Diederich)的“ 停止写作课 ”演讲反对一般的过度设计。

显然,任何写得不好的东西都是没有用的。但是,编写良好的API的接口将如何阻止使用该代码?整个历史上都有一些例子,出于一种目的制造东西被更多地用于其他目的。但是在软件世界中,如果您出于某种非预期目的使用某种东西,通常会破坏它。

我正在寻找一个好的界面的良好示例,该界面可以防止对某些代码的合法但无意的使用。是否存在?我无法想象。


1
还没有看/读过这些东西(我已经将“停止写作课”添加到了我的观察名单中:)),但是也许他们是从动态还是静态的打字角度争论的?...再次?
Andres F.

oO应用程序编程接口接口
Thomas Eding

感谢您的链接!我没发现杰克·迪德里里奇的讲话特别有启发性(注意他如何不能令人信服地回答观众的真实问题。“嗯,是的,在那种情况下……”。我确实觉得他似乎在为函数式编程而争论,甚至注意到它;))),但是“皇帝服装危机”非常好而且很有见地。
Andres F.

1
MPO是那些不相信重用的人不会将事情分解成足够小的单元。为特定目的而构建的一件大事不能重复使用。但是,小事物通常具有足够小的目的,因此小目的在多个环境中都是有用的。
艾米·布兰肯希

1
@AmyBlankenship我发现上面链接的“帝国服装危机”很有见地。作者认为“重用”是一个虚假的偶像(在实践中还没有被证明有用的东西,而且即使使用了这个词,大多数人甚至都不理解它)。他也不认为图书馆是“重用”的。你使用一个库,你不重用它。他还考虑设计一些可重复使用的东西“一把双刃剑”。人们通常认为这是双赢的情况,但实际上并非如此:当您设计可重复使用的东西时,这始终是一个折衷(例如,您可能会因为简单而失败)
Andres F.

Answers:


32

还没看完Rich Hickey的完整介绍,但是如果我正确理解他的话,并且从他对29分钟标记所说的内容来看,他似乎正在争论杀死重复使用的类型。他宽松地使用“接口”一词作为“命名类型”的同义词,这很有意义。

如果在Java领域中有两个{ "name":"John" }type Person{ "name": "Rover" }type的实体,则Dog它们可能无法互操作,除非它们共享一个公共接口或祖先(例如Mammal,这意味着编写更多代码)。所以接口/这里的类型是“杀死你重用”:尽管PersonDog外观相同,不能互换与其它使用,除非你写额外的代码来支持这一点。注意Hickey还开玩笑说Java项目需要很多类(“谁在这里只用20个类编写了Java应用程序?”),这似乎是上述情况的结果。

但是,在“面向价值”的语言中,您不会为这些结构分配类型。它们只是碰巧共享相同结构的值(在我的示例中,它们都具有name带有String值的字段),因此可以轻松地进行互操作,例如,可以将它们添加到相同的集合中,传递给相同的方法,等等。

综上所述,所有这些似乎都与结构相等 vs 显式类型/接口相等有关。除非我错过了部分视频,否则我还没看过:)


2
顺便说一句,杰克·迪德里里希(Jack Diederich)的演讲“停止编写类”似乎与该主题无关,它更多地与YAGNI有关,并且“不要编写代码,除非您需要它,然后才编写简单的代码”。
Andres F.

9
ERROR: Object doesn't have a property called "name"通常是value-oriented语言的结果,另一个问题是当您不想再调用该属性时name。祝您好运,因为可能有成百上千个具有属性的对象,name但并非全部是Personor Dog
Reactgular

2
@MathewFoscarini是的,我不一定同意它,这只是我对Hickey所说的解释:)我喜欢类型和静态类型;我刚刚开始不喜欢Java。我的不喜欢与interfaces 无关,但与典型的Java项目一团糟。
Andres F.

1
对于那些喜欢思考太多的人来说,Java是一种编程语言。它是使开发人员可以轻松隐藏他过度设计项目的几种语言之一。
Reactgular

“在“面向价值的”语言中,您不会为这些结构分配类型”-我认为您需要说“在动态的“面向价值的”中……” Haskell和Scala都是面向价值的,但是它们的静态类型系统给他们您正在描述的确切问题。我认为,解决此问题的方法与其说是值,不如说是使用映射将参数传递给函数。使用不可变的映射(值)更安全。
GlenPeterson

28

他可能指的是无法实例化接口的基本事实。您没有reuse接口。您只能实现支持它的代码,并且当您为接口编写代码时,不能重用。

Java具有提供许多以接口作为参数的API的框架的历史,但是开发API的团队从未实现过广泛的类供您用这些接口。

它有点像GUI框架,具有IWindow用于对话框的界面,然后您可以添加IButton控件的界面。除此以外,他们从没有给您Button实施好的课程IButton。这样您就可以创建自己的了。

具有大量提供核心功能的基类的抽象框架更可重用,并且当那些使用框架的抽象类可访问这些抽象类时,其效果最佳。

Java开发人员开始在只暴露其API层的情况下执行此操作interfaces。您可以实现这些接口,但是永远不能重用实现这些接口的开发人员提供的类。这有点像API开发的伪装和匕首样式。


4
感谢您的回答。我现在觉得我能理解问题答案了:)
MetaFight 2013年

2
+1非常感谢您的回答,它为该问题添加了有趣的信息。但是我认为安德烈亚斯·F·的回答可能更接近希基先生的意思,所以我改为接受他的回答。
GlenPeterson 2013年

@GlenPeterson没问题,我认为他也可能会获得成功。
Reactgular

1
好吧,这个和公认的答案突出了两种稍有不同但同样有趣的解释。我很好奇在谈论这个问题时,希基先生想到的是哪个。.–
大卫·考登

您不能重用接口,但是可以扩展它(并提供有价值的版本号)而无需更改旧类。您还可以从许多接口继承来为新类添加新的工作,或者在旧的重新编译的类中添加新的继承。您也可以扩展为新作业实现此接口的类。
cl-r

14

我认为幻灯片13在他的演讲(价值的价值)有助于理解这一点:

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


价值观

  • 不要需要方法
    • 我可以向您发送没有代码的值
      ,您也很好

我的理解是,Hickey建议,如果我需要将您发送给我的价值增加一倍,那么我只需编写如下代码

    MyValue = Double(YourValue)

您会发现,无论您发送何种值,上述代码都是相同的-一种完美的重用

现在,在具有对象和接口的语言中,情况看起来如何?

    Doublable MyValue = YourValue.Double()

等一下!如果YourValue不执行Doublable怎么办?不是不能将其加倍,而是完全可以,但是...如果没有方法 Double怎么办?(如果有一个叫做say的方法TwiceAsMuch呢?)

呃,我们有问题。YourValue.Double将无法工作,无法再使用了。根据我对以上幻灯片的阅读,这与Hickey所说的含义有关:“所有这些接口都会破坏您的重用!”

您会看到,接口假定对象“连同其方法”一起传递,并且对这些对象进行操作。要使用对象,需要了解如何调用该代码,调用哪种方法

当缺少期望的方法时,存在一个问题,即使从语义上来说,期望的操作对于对象来说也是完全有意义的。如演示文稿所述,值不需要方法(“我可以在没有代码的情况下向您发送值,您就可以了”),允许编写以通用方式处理它们的代码。


旁注:传递无代码值的想法使我想起了OOP 中的Flyweight模式

通过与其他类似对象共享尽可能多的数据来最大程度减少内存使用的对象;当简单的重复表示将使用不可接受的内存量时,这是大量使用对象的方式。Flyweight对象是按定义值对象。对象实例的身份无关紧要,因此,两个具有相同值的Flyweight实例被视为相等...

我见过的关于Flyweight的用法通常采用相同的方法,即从对象中剥离代码(方法,接口),并传递一些无代码的值,期望接收代码具有对这些代码进行操作所必需的手段。

感觉就像幻灯片上的一样:“值不需要方法。我可以不用代码就向您发送值,您就可以了”。


5
泛型几乎可以解决这个问题。在某些对象上加倍是有意义的,而在另一些对象上则没有意义。在Go语言中,存在隐式接口实现(鸭子输入的一种形式),因此您不必担心所有这些接口。另一方面,您必须知道方法签名将要击中哪个对象。否则,您可能会得到意想不到的结果。总会有权衡取舍。
罗伯特·哈维

1
一个有趣的观点。好答案!
maple_shaft

2
轻量级模式并不是Rich所说的。正如文章的第二句话所言,flyweight模式的目的是节省内存。Rich的方法并非试图做到这一点。

5
MyValue = Double(YourValue)如果YourValue是字符串,地址,用户,函数或数据库,则没有任何意义。否则,您的方法缺失论点是一个很强的论点。OTOH,访问器方法使您可以强制执行各种约束,以便您的值有效,并且仅使用明智的操作来产生新的值。如果您以后决定将地址与用户和公司分开,则访问器方法意味着您不会破坏代码的所有客户端。因此,即使有时在短期内阻碍重用,它们也可以长期帮助重用。
GlenPeterson

4
(另一方面,我确实同意在Java领域,类,接口和框架的爆炸是一场噩梦。Java中最简单的“企业”解决方案是一堆代码。因此,我确实从中汲取了宝贵的教训问题和答案,而不必一定同意动态打字的东西)
Andres F.

2

在一个(即我)理想的世界中,类和接口总是可以描述行为,但是事实是,它们和大多数情况下实际上只是描述数据。直到昨天,我才看到有人在视频中建立了一个所谓的BankAccount类,int它不过是一个荣耀的类(实际上,它比有用的少得多int,因此“杀死”了我本来只是作为一个类的重用int),都是以“好”设计的名义。不断重塑复杂的数据表示而浪费的代码,汗水和眼泪是惊人的。如果您没有以有意义的方式使用数据,那么就顺其自然。

现在,在这个阶段,里奇·希基(Rich Hickey)满意地将婴儿带出浴池,并说我们都应该生活在价值之地(名词王国的邻居)里。另一方面,我认为,明智地使用OOP可以并且确实会促进重用(并且重要的是发现性,我发现它在函数式编程中缺乏)。如果您正在寻找最能体现这种张力的OOP原则,我想可能是http://c2.com/cgi/wiki?TellDontAsk(当然这是Demeter的近亲)


可发现性是什么意思?与相似吗?

1
是的,我认为这涉及很多要点。这是一个微妙的要点,但是可发现性是一种平衡行为,使事情变得太透明也是不可取的,因为您会得到不好的信噪比。
CurtainDog
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.