着名的Best Practice Recommendations for Angular App Structure博客文章概述了新推荐的angularjs项目结构,该结构现在面向组件,而不是面向功能,或者在initial github issue - "由功能组织&#34中命名34。
博客文章建议每个模块中的每个文件都应以模块名称开头,例如:
userlogin/
userlogin.js
userlogin.css
userlogin.html
userlogin-directive.js
userlogin-directive_test.js
userlogin-service.js
userlogin-service_test.js
问题是:在模块中的每个文件名中重复模块名称的重点和缺点是什么,而不是命名功能的文件?例如:
userlogin/
userlogin.js
userlogin.css
userlogin.html
controllers.js
directives.js
services.js
我问的原因是我来自Django
世界,那里有projects and apps的某种类似想法。每个应用通常都拥有自己的models.py
,views.py
,urls.py
,tests.py
。脚本名称中没有重复的应用程序名称。
我希望我没有越过基于意见的界限,并且有合理的理由采用这种方法。
答案 0 :(得分:13)
有一个非常好的理由,它是为了改进任何非平凡的代码库的一个非常重要的方面(特别是当涉及大型开发团队时),即我们所称的"可概性"。
" Overviewability"是代码库组织(文件夹结构,文件命名,元对象等)的能力,以提供实施软件的快速和信息丰富的概述。
"概述""由于以下原因(非详尽列表),重要性随着代码库的大小和开发团队在项目*上的大小呈指数级增长:
当代码库很大时,代码的某些部分在特定时间段内保持不变的概率会增加(因为这会延长这个"寒冷"期间)。
当新成员加入团队时,您希望他们尽快加快速度(并且不会让他们在此过程中感到沮丧)。 " Overviewability"有助于提供整个项目的良好高级抽象,并且通常也能很好地理解事物是如何工作的(通常情况下它会产生一种熟悉感;它就好像你已经看到了代码库一样之前 - 虽然你没有'。
"所以,好的,"概述性"很重要这就是为什么我们有这个漂亮的,以组件为中心的结构等等。但为什么为每个文件添加组件名称前缀?"
嗯,听起来可能很有趣,但为所有与组件相关的文件名添加前缀可确保特定订单。例如。 HTML部分或CSS将始终出现在控制器等之前:
...
userlogin.html
userlogin-controller.js
...
如果不是前缀,则最终会有各种订单,具体取决于组件的名称。 E.g:
... ... ...
controller.js controller.js bookself.html
... ... ...
service.js VS service.js VS controller.js
... ... ...
userlogin.html zombi.html service.js
... ... ...
使用前缀可确保文件按特定顺序显示:控制器始终位于HTML部分,服务等之后。例如:
... ... ...
userlogin.html zombi.html bookself.html
... ... ...
userlogin-controller.js VS zombi-controller.js VS bookself-controller.js
... ... ...
userlogin-service.js zombi-service.js bookself-service.js
... ... ...
这可能看似微不足道,但事实并非如此;尤其是当人们习惯它时 请注意,人类的头脑非常善于识别视觉模式(如文件浏览器中文件夹和文件结构的树节点表示所创建的模式)。
即。控制器不驻留在名为"< component> -controllers.js" 的文件中。
它位于第一个文件中,其名称明显长于以前的文件
服务(如果有的话)驻留在末尾名称较小的文件等。
搞砸了(因为起始字母搞乱了订单或者由于长/短组件名称弄乱了它们的相对长度)并且你自己的情况类似于必须从硬盘读取内容,而不是只是从RAM读取它。 (没有开发人员想去那里:))
<子>
*:实际上,它就是我们所说的&#34; dev team flux&#34;这在这里很重要,即团队成员将多久离开(例如,为了其他事情,离开公司等)或新成员将被引入。
通常,团队越大,流量越大。
子>
答案 1 :(得分:5)
我发现名称和文件夹层次结构非常有价值 组织大型项目。同样,有意义的分层名称 非常帮助我。
来自 ASP.NET 世界,项目规模巨大,我们有:
解决方案 - &gt;管理 项目 (程序集) - &gt;使用 文件夹 - &gt;和 子文件夹 ,用于 文件 。
所以 ASP.NET MVC 项目将在Controllers
中有一个 主页 控制器 MVC演示项目 的文件夹,以及 视图 文件夹中的Views
。
在我的项目中使用 AngularJS 时,我喜欢命名的方法
App(Module)-type(directive/service)-(sometimes more detail)
除了为应用命名文件夹,还有 指令 和 服务 < / strong>在文件夹中,其文件夹的名称以 app 命名,应用程序通常在功能上命名,或者在 ASP.NET视图之后 (就像我的观点可能是Account-Login
)。
这一切都是因为我的项目非常庞大。我最终得到了许多 AngularJS apps
,疯狂的directives
,甚至是services
的公平数字。
当您的项目很小甚至中等规模时,优势是有争议的。但是当你的项目变得越来越大时,组织就变得至关两者都可以帮助您找到所需的代码,并继续传播更多代码。
答案 2 :(得分:5)
tl; dr; 虽然其他答案在大多数问题上都没有错,但他们却未能认识到今天可供开发人员使用的文件导航工具的重要性。 / strong>
一旦我们熟悉了一个项目,我们就会想要在不查看源树的情况下在文件之间导航。我们的命名方案将在允许我们快速导航方面发挥重要作用。我们可以通过输入文件名的片段来非常快速地导航到文件。例如,如果您的模块名称为forsee
,则可以在文件搜索框中输入forsee
来查看fo.js
javascript 文件列表(假设您的编辑器具有此功能)。 Chrome开发工具源选项卡内置了此功能。您可以看到它的实际效果, here (打开开发工具并按 Cmd + O ):
我曾经认为在模块名称前加上所有文件名是有效搜索所必需的,但后来意识到这根本不是真的。我们可以有效地搜索fo/js
:
所以现在应该清楚我们可以快速导航到文件,无论模块名称是否预先添加到文件名。
我同意ExpertSystem,将文件分组在一起可以让您一目了然地看到事物。但是,再次预先设置模块名称并不是必需的。而是在编辑器中激活相应的选项:
在上面的屏幕截图中,我激活了按类型排序选项,以便按文件扩展名对文件进行排序。
如果在小屏幕(即笔记本电脑)上编码并使用左侧导轨树视图导航文件夹结构,则较短的文件名将更好地服务于有限的屏幕空间。模块文件夹名称将是可见的,因此查看为每个文件重复的名称没有用。
显然,我上面提到的大部分内容确实依赖于开发人员使用正确的工具并且知道如何使用它们。如果您的团队没有这些工具,或者您怀疑他们有效地使用这些工具,培训他们,或坚持使用超详细的命名方案。
使用当今开发人员可用的高级工具,重复每个文件的模块名称是不合时宜的。但是,过于冗长的文件命名不会造成任何严重的危害或效率问题。在构建新项目时,我们必须做出许多其他架构决策,这些决策远比这个更重要。
BTW:我根据ExpertSystems建议命名 js 文件。也就是说,dialog.js
,dialog-ctrl.js
,dialog-services.js
等。这说明他说的理由是合理的,但是当一个模块有多个部分时,最好不要遵循这个命名 html 文件的模式。
答案 3 :(得分:1)
假设正在构建帐户设置页面。 admin 帐户可以sendNotifications
,其中用户帐户可以updateNotifications
。 admin 和用户帐户都可以updateAvatar
。
抽象为单独的模块,文件和文件夹的组件更易于使用。
包含所有这些模块的父级可以称为帐户。我们知道帐户将有两种不同的角色和三种不同的功能。如果 account 是“角色无关”,则您的定义可能类似于:
angular.module("account", [
"account.updateAvatar",
"account.sendNotifications",
"account.updateNotifications"
]);
但是,为这些功能定义父模块可以促进组织和继承:
angular.module("account", [
"account.common",
"account.admin",
"account.user"
]);
angular.module("account.common", [
"account.common.updateAvatar"
]);
angular.module("account.admin", [
"account.admin.sendNotifications"
]);
angular.module("account.user", [
"account.user.updateNotifications"
]);
功能模块可以遵循类似的模式:
angular.module("account.common.updateAvatar", [
"account.common.updateAvatar.services",
"account.common.updateAvatar.controllers",
"account.common.updateAvatar.directives",
"account.common.updateAvatar.filters"
]);
观点和资产:
account.common.updateAvatar.less
account.common.updateAvatar.tpl.html
account.common.updateAvatar.heading.tpl.html
account.common.updateAvatar.body.tpl.html
将所有HTML部分编译为缓存的JavaScript:
module.exports = function(grunt) {
grunt.initConfig({
html2js: {
partials: {
src: ["src/**/*.tpl.html"],
dest: "build/js/app.tpls.js",
module: "app.tpls"
}
}
)};
};
Concat所有 admin JavaScript独立于您的用户 JavaScript:
module.exports = function(grunt) {
grunt.initConfig({
concat: {
admin: {
src: ["src/**/*.admin.*.js"],
dest: "build/js/admin.js"
},
user: {
src: ["src/**/*.user.*.js"],
dest: "build/js/user.js"
}
)};
};
答案 4 :(得分:1)
正如ExpertSystem所述,您当前的目录结构与博客Best Practice Recommendations for Angular App Structure无关。
我与ExpertSystems以及Gil Birman合作,设计应用程序结构的方法应该是模块化的。如您所知,Angular本身遵循模块化结构,因此无论您是拥有多个模块还是单个Angular模块,您都需要根据您所服务的功能进行思考。例如,如果你有一个'CountDown'功能,它应该有自己的结构。
<强> 1。代码维护:随着代码的增加,您的维护成本也会增加。例如,如果在生产环境中,您的角度代码出现错误,并希望使用1小时的KRA进行纠正,则首先需要在本地复制场景,然后遍历该特定文件。如果它是模块,你会知道要定位哪个文件夹,并且你可以快速获得解决方案。
<强> 2。开发轻松:您可以在多个开发人员之间拆分多个功能,他们可以定位不同的功能文件夹,以便他们不会触及相同的文件。合并冲突可以减少。
第3。更快的评论:由于应用程序被分解为功能,因此可以更快地完成评论,并且可以轻松地知道该文件夹的代码是针对该特定功能的。
<强> 4。 TDD实施:该结构可用于启动测试驱动开发(TDD)。此article
中提到了TDD的好处在开发中,您可以根据功能获得结构。但是,为了提高Web应用程序(或混合移动应用程序)的性能,最好的方法是连接所有文件,缩小它并使用GRUNT对其进行模糊处理。将给出相同的GRUNT文件样本。您可以使用任何持续集成工具(例如Jenkins)在每次部署期间运行该脚本。