问题
The famous Best Practice Recommendations for Angular App Structure blog post outlines the new recommended angularjs project structure which is now component-oriented, not functionally-oriented, or as named in the initial github issue - "Organized by Feature".
The blogpost suggests that each file inside each module should start with the module name, e.g.:
userlogin/
userlogin.js
userlogin.css
userlogin.html
userlogin-directive.js
userlogin-directive_test.js
userlogin-service.js
userlogin-service_test.js
The question is: what is the point, pros and cons of repeating the module name inside each filename in the module as opposed to having the files named functionally? For example:
userlogin/
userlogin.js
userlogin.css
userlogin.html
controllers.js
directives.js
services.js
The reason I ask is that I'm coming from a Django world where there is a somewhat similar idea of having projects and apps. Each app usually has it's own models.py
, views.py
, urls.py
, tests.py
. There is no repeating app name inside the script names.
I hope I'm not crossing an opinion-based line and there is a legitimate reason for following the approach.
回答1:
There is a very good reason and it is for improving a very important aspect for any non-trivial codebase (especially when large teams of developers are involved), namely what we call "overviewability".
"Overviewability" is the ability of the codebase's organzation (folder structure, file naming, meta-objects etc) to provide a quick and informative overview of the implemented software.
The "overviewability's" significance increases exponentially with the size of the codebase and that of the developers team working on the project* for the following reasons (non-exhaustive list):
When a codebase is large, the probability of certain parts of the code to be left untouched for a specific time period increases (as increases the duration of this "cold" period).
When new members join the team, you want them to be brought up to speed as soon as possible (and not get them frustrated in the process). "Overviewability" helps provide a good high-level abstraction of the whole project and usually also gives a good sense of how things work (more often than not it creates a feeling of familiarity; it's as if you've seen the codebase before - although you haven't).
"So, OK, "overviewability" is important. That's why we have this nice, component-centric structure etc. But why prefixing each file with the component's name ?"
Well, it might sound funny, but prefixing all component-related filenames ensures a specific order. E.g. the HTML partial or the CSS will always appear before the controllers etc:
...
userlogin.html
userlogin-controller.js
...
Where it not for the prefix, you would end up with various orders depending on the name of the component. E.g.:
... ... ...
controller.js controller.js bookself.html
... ... ...
service.js VS service.js VS controller.js
... ... ...
userlogin.html zombi.html service.js
... ... ...
Using a prefix ensures the files appear in specific order: controller comes always after the HTML partial, service also etc. E.g.:
... ... ...
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
... ... ...
This might seem trivial, but it's not; especially as one gets used to it.
Note that the human mind is very good at recognizing visual patterns (like the ones created by a tree-node representation of the folder- and file-structure in a file-explorer).
I.e. the controllers do not reside in a file named "<component>-controllers.js".
It resides in the first file whose name is significantly longer than the previous files.
The service (if any) resides in the file with the smaller name at the end, etc.
Mess that up (i.e. mess the order up because of the starting letter or mess their relative lengths up because of long/short component names) and you have yourself a situation similar to having to read something from the hard-drive, instead of just reading it from the RAM. (No developer wants to go there :))
*: Actually, it's what we call the "dev team flux" that is important here, i.e. how often a team member will leave (e.g. to work on something else, leaving the company etc) or a new member will be introduced.
Usually, the larger the team, the greater the flux.
回答2:
tl;dr; While the other answers aren't wrong in most of their points, they fail to recognize the importance of the file navigation tools available today to developers.
Navigating Project Files Quickly
Once we are fairly well acquainted with a project, we will want to navigate between files without looking at the source tree. Our naming scheme will play an important part in allowing us to navigate quickly. We can navigate to a file extremely quickly by entering fragments of the file name. For example, if your module's name is forsee
you can see a list of forsee
javascript files by typing fo.js
in a file search box (assuming your editor has this feature). The Chrome Dev Tools Source tab has this feature built-in. You can see it in action, here (open the dev tools and press Cmd+O):
I used to think that prepending all file names with the module name was necessary to search effectively, but then realized that isn't true at all. We can just as effectively search for fo/js
:
So now it should be clear that we can just as quickly navigate to a file regardless of whether or not the module name is prepended to the filename.
Overviewability
I agree with ExpertSystem that grouping files together allows you to see things better at a glance. However, once again prepending the module name isn't really necessary. Rather, activate the appropriate option in your editor:
In the screenshot above, I activated the Sort by Type option to enable sorting files by their file extensions.
Why We Shouldn't
If coding on a small screen (ie., laptop) and using a left-hand rail tree view to navigate the folder structure, the limited screen real estate will be better served by shorter file names. The module folder name will be visible so it's not useful to see that name repeated for every file.
Caveats
Obviously, most of what I presented above does rely on developers using the right tools and knowing how to use them well. If your team does not have these tools or you doubt their ability to use them effectively, train them, or stick with the extra-verbose naming scheme.
Conclusion
With the advanced tools available to developers today, repeating the module name for every file is anachronistic. However, overly verbose file naming doesn't cause any great harm or efficiency problems. When structuring a new project, there are many other architectural decisions we'll have to make that are far more important than this one.
BTW: I do name js files according to ExpertSystems suggestion. Ie., dialog.js
, dialog-ctrl.js
, dialog-services.js
, etc. This makes sense for the reasons he stated, but when a module has multiple partials it's best not to follow this naming pattern for html files.
回答3:
It's all about organizing large Projects (code base):
I've found names and folder-hierarchies to be very valuable for organizing large projects. Similarly, meaningful, hierarchical names help me tremendously.
Coming from the ASP.NET world, where projects are huge, we have:
Solutions -> managing Projects (assemblies) -> with folders -> and sub-folders, for files.
So an ASP.NET MVC Project will have a Home Controller in the Controllers
Folder of the MVC Presentation Project, and Views
in the Views Folder.
When using AngularJS in my projects, I like the approach of naming
App(Module)-type(directive/service)-(sometimes more detail)
This is in addition to naming folders for apps, and having directives and services in folders for their types with the folder named after the app and the app often named functionally or after the ASP.NET View (like my View may be Account-Login
).
All this because my projects are very very big. I end up having many AngularJS apps
, crazy number of directives
, and even fair number of services
.
When your project is small or even medium size, the advantages are arguable. But when your project grows big, organization is critical! Both to help you find the code you need, and to continue propagating more.
回答4:
I wrote about this in one of my blog posts
Modules often have overlapping features
Let’s say were building an account settings page. The admin account can sendNotifications
where the user account can updateNotifications
. Both admin and user accounts can updateAvatar
.
Describes features as well as relationships
Components abstracted into separate modules, files, and folders are easier to work with.
A parent that encompasses all of these modules could be called account. We know that account will have two different roles and three different features. If account was "role agnostic", your definition might look something like:
angular.module("account", [
"account.updateAvatar",
"account.sendNotifications",
"account.updateNotifications"
]);
But defining parent modules to these features promotes organization and inheritance:
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"
]);
Feature modules can follow a similar pattern:
angular.module("account.common.updateAvatar", [
"account.common.updateAvatar.services",
"account.common.updateAvatar.controllers",
"account.common.updateAvatar.directives",
"account.common.updateAvatar.filters"
]);
Views and assets:
account.common.updateAvatar.less
account.common.updateAvatar.tpl.html
account.common.updateAvatar.heading.tpl.html
account.common.updateAvatar.body.tpl.html
Dot notation can enable easy globbing patterns
Compile all of your HTML partials into cached JavaScript:
module.exports = function(grunt) {
grunt.initConfig({
html2js: {
partials: {
src: ["src/**/*.tpl.html"],
dest: "build/js/app.tpls.js",
module: "app.tpls"
}
}
)};
};
Concat all of your admin JavaScript independent of your user 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"
}
)};
};
回答5:
As ExpertSystem stated, your current directory structure is not in relation to the blog Best Practice Recommendations for Angular App Structure.
I am in conjunction with ExpertSystems as well as Gil Birman, that the approach in order to design the app structure should be modular. As you know that Angular itself follows a modular structure so whether you have multiple modules or a single Angular module you need to think according to the functionality you catering to. For instance if you have a 'CountDown' functionality it should have its own structure.
Why this is important?
1. Code Maintenance: As your code will grow your maintenance costs grows. If for instance in the production environment you get an error in your angular code and want to rectify with a KRA of 1 hour, you would first need to replicate the scenario locally and then traverse to that particular file. If it had been module you would know which folder to target and boom you got the solution fast.
2. Development Ease: You can split multiple functionalities between multiple developers and they can target different functional folders so their wont be touching the same files. Merging conflicts can be reduced.
3. Faster Reviews: Since the app is broken down into functionality, reviews can be done faster and with ease knowing that the code for that folder is for that particular functionality.
4. TDD Implementation: The structure can be used to kick start Test Driven Development (TDD). Benefits of TDD are mentioned over here in this article
Difference between Development and Production Code/Structure
In Development you can have the structure according to the functionality. However in order to improve on the performance of your web application (or a hybrid mobile app), the best way to go about that is to concatenate all the files, minify it and obfuscate it using GRUNT. Will be giving a sample of the GRUNT file for the same. You can run the script every time during deployment using any continuous integration tool such as Jenkins for example.
来源:https://stackoverflow.com/questions/25005897/repeating-module-name-for-each-module-component