“基于配置的约定”是否违反基本的编程原则?


51

我查看了WPF MVVM框架Caliburn.Micro,并阅读到很多标准内容都基于命名约定

例如,将视图中的属性自动绑定到视图模型中的属性。尽管这似乎很方便(删除了一些样板代码),但是我的第一个本能反应是,对于将要读取此代码的新程序员而言,这并不完全明显。换句话说,应用程序的功能并不能完全由其自己的代码来解释,而不能由框架的文档来完全解释。

编辑:

因此,这种方法称为约定优于配置。由于找不到与此相关的任何问题,因此我更改了问题:

我的问题是:

约定优于配置是简化事情的正确方法,还是违反了某些编程原则(如果是,则违反了哪些编程原则)?


8
大多数方法/原理在某种程度上违反了其他方法/原理。这主要是优先事项和权衡问题。
Joachim Sauer 2012年

1
是的,但是我发现我的问题中所述的区别有些奇怪,因此,我对使用约定而不是配置时的特定取舍和可能违反的原则感兴趣。
Geerten 2012年

软件可追溯性的概念在这里是相关的。程序员依赖于grep之类的工具,但需要更好的工具来跟踪生成代码的使用。例如,工具应使其更明确,使css类“ user-id”与生成的方法getUserId()和表列user_id相关联。
Macneil 2015年

Answers:


49

我不认为“应用程序应该用自己的代码充分解释”是基本的编程原理。有很多事情,仅通过查看应用程序的代码就无法解释。除了了解编程语言本身的基本知识(语法和语义)之外,您还需要了解约定。如果Java中的标识符以大写字母开头,则为类型。您需要了解许多这些约定。

约定优于配置是为了减少程序员必须做出的决定。在某些情况下这很明显-没有人会考虑使用一种语言,其中类型的大写字母是您需要在程序顶部声明的内容-但在其他情况下,这种情况并不那么明显。

平衡约定和配置是一项艰巨的任务。太多的约定会使代码混乱(例如,以Perl的隐式变量为例)。程序员一方的自由度过高会使系统难以理解,因为从一个系统获得的知识在研究另一个系统时很少有用。

编写Eclipse插件时,约定对程序员有帮助的一个很好的例子。在查看一个我从未见过的插件时,我立即了解到很多有关它的信息。依赖项列表在MANIFEST.MF中,扩展点在plugin.xml中,源代码在“ src”下,依此类推。如果这些事情要由程序员定义,那么每个Eclipse插件都会有所不同,并且代码导航会更加困难。


4
+1:软件开发非常复杂。如果可以避免您控制的事情变得复杂,请这样做。将复杂性保存在您绝对需要的地方。
scrwtp 2012年

1
感谢您对差异和平衡的清晰解释。
Geerten 2012年

3
“如果Java中的标识符以大写字母开头,则它是一种类型。” -是否是类型取决于语法上下文,而不取决于命名模式,Java命名约定不会影响“编译配置”。您确定这是一个有效的示例吗?最后一个示例也不正确-它是关于“配置约定”而不是“约定之上的配置”。您说的是正确的话,但与主题原则无关。

4
不要过度分析示例,它们只是示例。第一个只是约定的示例,最后一个是约定是一件好事的示例。Perl示例是太多约定(隐含)是不好的例子(IMO,我应该补充)。
JesperE 2014年

1
我讨厌的事情是,当配置时的约定变成没有配置的约定...在后一种情况下,您倾向于被代码库所困,很难与其他工具集成。
安迪

77

给+1给@JesperE,喜欢添加一些东西:

是否违反了一些编程原则

是的,“约定之上的配置”违反了“显式优于隐式”的原则(例如,查看“ Zen-Of-Python”)。

另一方面,相反的“配置优于约定”倾向于违反“简单胜于复杂”,并且更糟的是,它以微妙的方式违反了DRY原理,因为您还需要在配置中重复使用代码中使用的名称。 。


4
这是对该问题最直接的答案!
约阿希姆·绍尔

这是两个最受好评的实际正确答案。
2014年

+1代表“明确胜于隐含”
Justin Ohms 2014年

12
关于这个答案,我最喜欢的部分是,它隐含地强调了现实,而不是好的软件开发原则经常相互矛盾。工程是要针对您的特定上下文和应用适当地平衡那些紧张关系。
克里斯·克里乔

好答案。为了扩展@Chris Krycho的评论,关于软件标准或原则的好处是您有很多选择。:-)
user949300

9

一些“配置约定”只是归结为合理的默认值。您只需要配置一些东西即可将其用于非标准用途。我必须在这里比较Struts和Rails。在Rails中,您必须将“操作/屏幕”放在一个文件夹中,然后它们才能工作。在Struts中,您仍然必须将它们放在文件夹中,但是还必须提供一个动作名称,一个JSP文件,一个表单名称和一个Form Bean,并指定这三件事在Struts-config中如何协同工作。 xml,并指定该表单属于请求(RESTful)。如果这还不够,那么Form / form-b​​ean映射在Struts-config中具有其自己的部分,然后将其独立地映射到同一文件中的action部分,并且它们都依赖于JSP文件中的手写字符串才能工作正确地。对于每个屏幕,那至少是您不需要做的6件事,并且有很多机会犯错。我认为您可以根据需要在Rails中手动设置大多数或所有这些内容,但是Struts开发时间的2/3占用了构建和维护不必要的复杂性层的时间。

公平地说,Struts 1是在人们在桌面和Web之间移植应用程序时设计的。Struts具有的灵活性使其适用于Rails所做的一切,以及桌面应用程序所需的一切。不幸的是,对于那些只需要编写Web应用程序或桌面应用程序的人来说,实现灵活性的大量配置是一个巨大的障碍。

我在某个地方工作,他们采取了下一步,并提出了“基于代码的配置”的观点,但是看到这一点达到了逻辑上的极限,结果就是配置变成了一种新的编码语言。这是一个壳牌游戏,其中的复杂性没有受到任何重大方式的驯服。它使我对一种精心设计的编程语言所具有的所有类型检查和其他安全网表示赞赏。如果添加空格或撇号,某些未成熟的配置文件格式会炸掉而不会显示错误消息,这并不是对质量编程语言的改进,该语言具有一组编辑工具和一个为此编写的质量编译器。

我无法想象拥有合理的默认值会违反任何有关可扩展性和模块化的理论原理。Ruby / Rails程序员会比不转向像Struts 1这样的框架(该框架中的所有配置都在多个XML文件中显式进行构建)更早地盯上热门扑克。我不是在一般性地争论Rails vs.Struts,但是这种约定可以极大地提高生产力。这两种技术是我遇到的最极端的现实世界比较。

如果您完全使用Java进行工作,请查看Joshua Bloch的“有效Java”项目2:“面对许多构造函数参数时,请考虑构建器”(第11-16页)。对于大多数目的,某些参数(配置)是必需的,而某些参数是可选的。基本思想是仅需要必要的配置,并且仅使用户(可能是另一个程序)根据需要指定其他选项。一个月前,我用这种模式清理了一大堆代码,它的确闪闪发光。


7

换句话说,应用程序的功能并不能完全由其自己的代码来解释,而不能由框架的文档来完全解释。

使用框架的应用程序的功能始终取决于框架,关于配置的约定在这方面没有任何区别。

以我的经验,约定优于配置不仅使代码更具可读性,而且还减少了引入细微错误(尤其是复制粘贴错误)的可能性。

例如,假设在某个框架A中,事件FooBar触发了对的调用handleFooBar。在另一个框架B中,此关联配置在XMLfile中的某个位置。

因此,在A中,

handleFooBar() {
   ...
}

除非您拼错了FooBar,否则只要FooBar发生,它将被调用。

在B中,又是

handleFooBar() {
   ...
}

但是也

<eventconfiguration>
  <event>
    <type>FooBar</type>
    <handler>handleFooBar</handler>
  </event>
</eventconfiguration>

通过这种方式配置了数百种东西,很容易意外地产生一个细微的错误,例如

<eventconfiguration>
  <event>
    <type>BarFoo</type>
    <handler>handleFooBar</handler>
  </event>
</eventconfiguration>

因为复制粘贴后,我们只进行了更改,<type>但忘记了更改<handler>

由于这些配置文件又大又单调,因此与实际程序代码中发现类似错误的人相比,通过校对发现错误的可能性较小。


1
+1:避免重复,无聊,难以阅读,几乎总是显而易见的配置是约定优于配置主要优点。
约阿希姆·绍尔

-1

它可能违反了一些原则,但同时它遵循了最基本的设计原则之一,即SRP(单一责任原则)。


2
使用约定与单一职责无关。我可能正在使用约定并在其中执行100项操作。
Suamere
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.