转载:Package by feature, not layer
原文地址:Package by feature, not layer
Package by feature, not layer
The first question in building an application is "How do I divide it up into packages?". For typical business applications, there seems to be two ways of answering this question.
软件开发首先要处理的事情包括对package进行划分
Package By Feature
Package-by-feature uses packages to reflect the feature set. It tries to place all items related to a single feature (and only that feature) into a single directory/package. This results in packages with high cohesion and high modularity, and with minimal coupling between packages. Items that work closely together are placed next to each other. They aren't spread out all over the application. It's also interesting to note that, in some cases, deleting a feature can reduce to a single operation - deleting a directory. (Deletion operations might be thought of as a good test for maximum modularity: an item has maximum modularity only if it can be deleted in a single operation.)
高内聚、模块化、和其它package之间最小耦合
In package-by-feature, the package names correspond to important, high-level aspects of the problem domain. For example, a drug prescription application might have these packages:
com.app.doctor
com.app.drug
com.app.patient
com.app.presription
com.app.report
com.app.security
com.app.webmaster
com.app.util
and so on...
Each package usually contains only the items related to that particular feature, and no other feature. For example, the com.app.doctor package might contain these items:
DoctorAction.java - an action or controller object
Doctor.java - a Model Object
DoctorDAO.java - Data Access Object
database items (SQL statements)
user interface items (perhaps a JSP, in the case of a web app)
It's important to note that a package can contain not just Java code, but other files as well. Indeed, in order for package-by-feature to really work as desired, all items related to a given feature - from user interface, to Java code, to database items - must be placed in a single directory dedicated to that feature (and only that feature).
In some cases, a feature/package will not be used by any other feature in the application. If that's the case, it may be removed simply by deleting the directory. If it is indeed used by some other feature, then its removal will not be as simple as a single delete operation.
That is, the package-by-feature idea does not imply that one package can never use items belonging to other packages. Rather, package-by-feature aggressively prefers package-private as the default scope, and only increases the scope of an item to public only when needed.
Package By Layer
The competing package-by-layer style is different. In package-by-layer, the highest level packages reflect the various application "layers", instead of features, as in:
com.app.action
com.app.model
com.app.dao
com.app.util
Here, each feature has its implementation spread out over multiple directories, over what might be loosely called "implementation categories". Each directory contains items that usually aren't closely related to each other. This results in packages with low cohesion and low modularity, with high coupling between packages. As a result, editing a feature involves editing files across different directories. In addition, deleting a feature can almost never be performed in a single operation.
Recommendation: Use Package By Feature
For typical business applications, the package-by-feature style seems to be the superior of the two:
Higher Modularity
As mentioned above, only package-by-feature has packages with high cohesion, high modularity, and low coupling between packages.
Easier Code Navigation
Maintenance programmers need to do a lot less searching for items, since all items needed for a given task are usually in the same directory. Some tools that encourage package-by-layer use package naming conventions to ease the problem of tedious code navigation. However, package-by-feature transcends the need for such conventions in the first place, by greatly reducing the need to navigate between directories.
Higher Level of Abstraction
Staying at a high level of abstraction is one of programming's guiding principles of lasting value. It makes it easier to think about a problem, and emphasizes fundamental services over implementation details. As a direct benefit of being at a high level of abstraction, the application becomes more self-documenting: the overall size of the application is communicated by the number of packages, and the basic features are communicated by the package names. The fundamental flaw with package-by-layer style, on the other hand, is that it puts implementation details ahead of high level abstractions - which is backwards.
Separates Both Features and Layers
The package-by-feature style still honors the idea of separating layers, but that separation is implemented using separate classes. The package-by-layer style, on the other hand, implements that separation using both separate classes and separate packages, which doesn't seem necessary or desirable.
Minimizes Scope
Minimizing scope is another guiding principle of lasting value. Here, package-by-feature allows some classes to decrease their scope from public to package-private. This is a significant change, and will help to minimize ripple effects. The package-by-layer style, on the other hand, effectively abandons package-private scope, and forces you to implement nearly all items as public. This is a fundamental flaw, since it doesn't allow you to minimize ripple effects by keeping secrets.
Better Growth Style
In the package-by-feature style, the number of classes within each package remains limited to the items related to a specific feature. If a package becomes too large, it may be refactored in a natural way into two or more packages. The package-by-layer style, on the other hand, is monolithic. As an application grows in size, the number of packages remains roughly the same, while the number of classes in each package will increase without bound.
If you still need further convincing, consider the following.
Directory Structure Is Fundamental To Your Code
"As any designer will tell you, it is the first steps in a design process which count for most. The first few strokes, which create the form, carry within them the destiny of the rest." - Christopher Alexander
(Christopher Alexander is an architect. Without having worked as programmer, he has influenced many people who think a lot about programming. His early book A Pattern Language was the original inspiration for the Design Patterns movement. He has thought long and hard about how to build beautiful things, and these reflections seem to largely apply to software construction as well.)
In a CBC radio interview, Alexander recounted the following story (paraphrased here): "I was working with one of my students. He was having a very difficult time building something. He just didn't know how to proceed at all. So I sat with him, and I said this: Listen, start out by figuring out what the most important thing is. Get that straight first. Get that straight in your mind. Take your time. Don't be too hasty. Think about it for a while. When you feel that you have found it, when there is no doubt in your mind that it is indeed the most important thing, then go ahead and make that most important thing. When you have made that most important thing, ask yourself if you can make it more beautiful. Cut the bullshit, just get it straight in your head, if you can make it better or not. When that's done, and you feel you cannot make it any better, then find the next most important thing."
What are the first strokes in an application, which create its overall form? It is the directory structure. The directory structure is the very first thing encountered by a programmer when browsing source code. Everything flows from it. Everything depends on it. It is clearly one of the most important aspects of your source code.
Consider the different reactions of a programmer when encountering different directory structures. For the package-by-feature style, the thoughts of the application programmer might be like this:
- "I see. This lists all the top-level features of the app in one go. Nice."
- "Let's see. I wonder where this item is located....Oh, here it is. And everything else I am going to need is right here too, all in the same spot. Excellent."
For the package-by-layer style, however, the thoughts of the application programmer might be more like this:
- "These directories tell me nothing. How many features in this app? Beats me. It looks exactly the same as all the others. No difference at all. Great. Here we go again..."
- "Hmm. I wonder where this item is located....I guess its parts are all over the app, spread around in all these directories. Do I really have all the items I need? I guess we'll find out later."
- "I wonder if that naming convention is still being followed. If not, I will have to look it up in that other directory."
- "Wow, would you look at the size of this single directory...sheesh."
Package-By-Layer in Other Domains is Ineffective
By analogy, one can see that the package-by-layer style leads to poor results. For example, imagine a car. At the highest level, a car's 'implementation' is divided this way (package-by-feature) :
- safety
- engine
- steering
- fuel system
- and so on...
Now imagine a car whose 'implementation' under the hood is first divided up according to these lower level categories (package-by-layer) :
- electrical
- mechanical
- hydraulic
In the case of a transmission problem, for example, you might need to tinker around in these three compartments. This would mean moving from one part of the car to another completely different one. While in these various compartments, you could 'see' items having absolutely nothing to do with problem you are trying to solve. They would simply be in the way, always and everywhere distracting you from the real task at hand. Wouldn't it make more sense if there was a single place having exactly what you need, and nothing else?
As a second example, consider a large bureacracy divided up into various departments (package-by-feature):
- front office
- back office
- accounting
- personnel
- mail room
If a package-by-layer style was used, the primary division would be something like :
- executives
- managers
- employees
Now imagine the bureacracy being divided physically according to these three categories. Each manager is located, for example, with all the other managers, and not with the employees working for them. Would that be effective? No, it wouldn't.
So why should software be any different? It seems that package-by-layer is just a bad habit waiting to be broken.
The example applications that come with WEB4J uses the package-by-feature style.
(本文使用Atom编写)
转载:Package by feature, not layer的更多相关文章
- [转载]Browser Link feature in Visual Studio Preview 2013
http://blogs.msdn.com/b/webdev/archive/2013/07/29/10430221.aspx Browser Link feature in Visual Studi ...
- 清晰架构(Clean Architecture)的Go微服务: 程序结构
我使用Go和gRPC创建了一个微服务,并试图找出最佳的程序结构,它可以用作我未来程序的模板. 我有Java背景,并发现自己在Java和Go之间挣扎,它们之间的编程理念完全不同.我写了一系列关于在项目工 ...
- 【论文阅读】Batch Feature Erasing for Person Re-identification and Beyond
转载请注明出处:https://www.cnblogs.com/White-xzx/ 原文地址:https://arxiv.org/abs/1811.07130 如有不准确或错误的地方,欢迎交流~ [ ...
- 转载 - CNN感受野(receptive-fields)RF
本文翻译自A guide to receptive field arithmetic for Convolutional Neural Networks(可能需要FQ才能访问),方便自己学习和参考.若 ...
- Layui 弹出层组件——layer的模块化开发实例应用
Layui 弹出层组件——layer的模块化开发实例应用 1.首先在package.json中引入layer组件依赖 2.在源码中应用这个依赖 3.在源码中编写代码应用此组件 4.效果验证:点击日历上 ...
- Paper | Recovering Realistic Texture in Image Super-resolution by Deep Spatial Feature Transform
目录 故事背景 空域特征转换 超分辨率网络 发表在2018年CVPR. 摘要 Despite that convolutional neural networks (CNN) have recentl ...
- (转载)人脸识别中Softmax-based Loss的演化史
人脸识别中Softmax-based Loss的演化史 旷视科技 近期,人脸识别研究领域的主要进展之一集中在了 Softmax Loss 的改进之上:在本文中,旷视研究院(上海)(MEGVII Re ...
- SSL (Secure Sockets Layer)
本文转载自SSL (Secure Sockets Layer) TLS简介 The Transport Layer Security (TLS) protocol aims primarily to ...
- java项目的划分方式:模块优先还是层优先?
I've seen and had lots of discussion about "package by layer" vs "package by feature& ...
随机推荐
- java基础 ----- 程序的调试
--- -- 什么是程序调试 当程序出错时,我们希望可以这样 逐条语句执行程序 ----- 观察程序的执行情况 ------ 发现问题 ----- 解决问题 但是,程序一闪就运行结束 ...
- Linux静态设置CentOS 7虚拟机的IP
进入root ,输入命令:# vi /etc/sysconfig/network-scripts/ifcfg-ens33 .将DHCP协议获取IP,改为static静态,加上想要设置的IPADDR即可 ...
- c#跨线程访问的代码和窗体关闭退出死循环的代码
一:一段跨线程访问,给页面内的控件赋值的代码找了半天没找到,还得找了以前写的程序. 在这记下来吧 . 这是其他程序内可以跨线程访问的代码 . if (gridControl1.InvokeRequi ...
- debian proftpd安装
- 20172306 2018-2019-2 《Java程序设计与数据结构》第六周学习总结
20172306 2018-2019-2 <Java程序设计与数据结构>第六周学习总结 教材学习内容总结 概述(了解一下树的一些概念) 树是一种非线性结构.树由一个包含结点和边的集构成,其 ...
- JS阻止事件冒泡的3种方法之间的不同
什么是JS事件冒泡?: 在一个对象上触发某类事件(比如单击onclick事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序或者事件返回true,那么这 ...
- vue2项目结构搭建
vue2项目结构初搭建与项目基本流程 一.开始项目结构搭建的重要性 决定项目是否能够健康成长 决定了项目是否利于多人协作开发 决定了项目是否利于后期维护 决定了项目是否性能良好 决定了代码是否重用率降 ...
- asp.net core部署到iis中出现 HTTP Error 502.5 - Process Failure的问题
环境是windows Server2012 问题的原因是缺少文件:api-ms-win-crt-runtimel1-1-0.dll, dotnet 启动程序失败. 解决方案1: 安装系统补丁: 20 ...
- ntelliJ IDEA 仿照vs2017快捷键设置,以及字体颜色设置
因后期工作需要使用java技术栈,所以近期抽空下载了intelliJ IDEA工具,但是作为一个Net开发者,在使用了vs以后,感觉在使用别的开发工具感觉就是没法和vs相比,毕竟vs被称为宇宙最强id ...
- svn的基本使用方法
一,svn的介绍 Subversion(SVN) 是一个开源的版本控制系統, 也就是说 Subversion 管理着随时间改变的数据. 这些数据放置在一个中央资料档案库(repository) 中. ...