当我开始自学脚本语言时,我从Perl开始。OnePerl的座右铭是“TMTOWTDI”——“做这件事的方法不止一种”,读作“tim-toady”。这个想法是,可能有多种方法可以完成同一件事,并且语言文化鼓励寻找新颖的方法来做事。
我已经看到这个原则在任何地方和几乎所有可能的编程情况下都被使用,应用于逻辑操作、命名约定、格式设置,甚至项目结构。每个人都对这些主题有自己的看法,并可以自由发挥他们认为合适的实施能力,很少有两个开发人员会提出相同的约定。
TMTOWTDI是一个令人难以置信的自由和平等原则。
然而,多年来,我对TMTOWTDI的热爱有所减弱。事实上,自由也是拥有编码标准和惯例的驱动力——因为当每个人都按照自己的方式行事时,项目很快就会变得难以维护。每个人都发现自己根据自己的标准重新格式化代码,以便他们可以阅读它并遵循它的流程。
此外,TMTOWTDI实际上可能成为简单、优雅解决方案的敌人。
我为什么要声明这个?
最近,在讨论ZendFramework2中的模块结构时,一些人争论说我们推荐的目录结构调用了YAGNI原则:你不会需要它。我们的建议是这样的:
ModuleName/ autoload_classmap.php Module.php config/ module.config.php (other config files) public/ css/ images/ js/ src/ ModuleName/ (source files) test/ view/
论点是,由于大多数模块实现了单个命名空间,并且因为我们建议自动加载器遵循PSR-0,所以将源文件直接放在模块目录下是有意义的。
ModuleName/ autoload_classmap.php Module.php (other source files) config/ module.config.php (other config files) public/ test/ view/
我和其他人提出的论点是按职责对文件进行分组是有意义的。但是,模块系统最终并不关心您如何组织模块—我们已经接受了TMTOWTDI,我们唯一的要求是要使用您的模块,您必须定义一个ModuleName\Module
类,并通知模块管理器如何找到它。一切顺利。
这如何支持我关于约定重要性的论点?它没有。遵循推荐的结构使我能够做到。
关于拥有可重用模块系统的一个常见问题是,您应该能够轻松公开公共资产:诸如特定于模块的CSS或JavaScript,甚至图像。当你考虑这个时出现的第一个问题是:我应该把它们放在我的模块中的什么地方?这就是为什么建议包括一个public
目录。事实上,该建议更进一步,还建议使用css
、images
和js
目录。
现在,您的模块通常在文档根目录之外。这是基本的安全措施,并且在一定程度上简化了部署—您无需担心告诉Web服务器它不应该提供什么服务。但是如果模块在文档根目录之外,我怎么能公开它们的公共资产呢?
有两种可能性立即跳入脑海:
- 安装模块脚本,将文件复制到文档根目录。
- 将文件符号链接到文档根目录。
两者都是有效的,而且很容易实现。两者都提出了同样的问题:究竟在哪里?如果多个模块的公共资产名称相同怎么办?我如何使用视图脚本之类的东西来引用我的资产?
这就是制定约定开始有意义的地方:制定约定应该明确地回答这些问题。
我的回答:公共访问应该在/css/ModuleName/stylesheetname
或/js/ModuleName/scriptname
或/images/Modulename/imagename。这是满足用例的非常简单的规则。
但是,我现在不得不开发安装脚本或记住创建符号链接——呃。这就是约定让我找到一个简单、优雅的解决方案的地方。
我在我的Apache虚拟主机定义中添加了一行:
AliasMatch /(css|js|images)/([^/]+)/(.*) /path/to/module/$2/public/$1/$3
翻译:
当我遇到子目录中的CSS、JS或图像文件的路径时,将其别名为匹配模块目录的相应公共资产。
当我遇到子目录中的CSS、JS或图像文件的路径时,将其别名为匹配模块目录的相应公共资产。
我将其放入我的虚拟主机,重新启动Apache,现在不仅我创建的资产已经可用,而且我创建的任何新资产也立即可用。召开会议实际上简化了我的选择和解决方案。
最佳的快速应用程序开发。
我的观点是:当您进行编程时,做事的方法总是不止一种,您可能并不总是同意您的团队所做的决定,或者您所使用的组件库或框架所做的决定。但是,如果您四处看看并在这些范围内玩耍,您可能会发现这些决定会使其他决定变得更容易,或者完全消失。