java项目的划分方式:模块优先还是层优先?
I've seen and had lots of discussion about "package by layer" vs "package by feature" over the past couple of weeks. They both have their benefits but there's a hybrid approach I now use that I call "package by component". To recap...
Package by layer
Let's assume that we're building a web application based upon the Web-MVC pattern. Packaging code by layer is typically the default approach because, after all, that's what the books, tutorials and framework samples tell us to do. Here we're organising code by grouping things of the same type.

There's one top-level package for controllers, one for services (e.g. "business logic") and one for data access. Layers are the primary organisation mechanism for the code. Terms such as "separation of concerns" are thrown around to justify this approach and generally layered architectures are thought of as a "good thing". Need to switch out the data access mechanism? No problem, everything is in one place. Each layer can also be tested in isolation to the others around it, using appropriate mocking techniques, etc. The problem with layered architectures is that they often turn into a big ball of mud because, in Java anyway, you need to mark your classes as public for much of this to work.
Package by feature
Instead of organising code by horizontal slice, package by feature seeks to do the opposite by organising code by vertical slice.

Now everything related to a single feature (or feature set) resides in a single place. You can still have a layered architecture, but the layers reside inside the feature packages. In other words, layering is the secondary organisation mechanism. The often cited benefit is that it's "easier to navigate the codebase when you want to make a change to a feature", but this is a minor thing given the power of modern IDEs.
What you can do now though is hide feature specific classes and keep them out of sight from the rest of the codebase. For example, if you need any feature specific view models, you can create these as package-protected classes. The big question though is what happens when that new feature set C needs to access data from features A and B? Again, in Java, you'll need to start making classes publicly accessible from outside of the packages and the big ball of mud will again emerge.
Package by layer and package by feature both have their advantages and disadvantages. To quote Jason Gorman from Schools of Package Architecture - An Illustration, which was written seven years ago.
To round off, then, I would urge you to be mindful of leaning to far towards either school of package architecture. Don't just mindlessly put socks in the sock draw and pants in the pants draw, but don't be 100% driven by package coupling and cohesion to make those decisions, either. The real skill is finding the right balance, and creating packages that make stuff easier to find but are as cohesive and loosely coupled as you can make them at the same time.
Package by component
This is a hybrid approach with increased modularity and an architecturally-evident coding style as the primary goals.

The basic premise here is that I want my codebase to be made up of a number of coarse-grained components, with some sort of presentation layer (web UI, desktop UI, API, standalone app, etc) built on top. A "component" in this sense is a combination of the business and data access logic related to a specific thing (e.g. domain concept, bounded context, etc). As I've described before, I give these components a public interface and package-protected implementation details, which includes the data access code. If that new feature set C needs to access data related to A and B, it is forced to go through the public interface of components A and B. No direct access to the data access layer is allowed, and you can enforce this if you use Java's access modifiers properly. Again, "architectural layering" is a secondary organisation mechanism. For this to work, you have to stop using the public keyword by default. This structure raises some interesting questions about testing, not least about how we mock-out the data access code to create quick-running "unit tests".
Architecturally-aligned testing
The short answer is don't bother, unless you really need to. I've spoken about and written about this before, but architecture and testing are related. Instead of the typical testing triangle (lots of "unit" tests, fewer slower running "integration" tests and even fewer slower UI tests), consider this.

I'm trying to make a conscious effort to not use the term "unit testing" because everybody has a different view of how big a "unit" is. Instead, I've adopted a strategy where some classes can and should be tested in isolation. This includes things like domain classes, utility classes, web controllers (with mocked components), etc. Then there are some things that are easiest to test as components, through the public interface. If I have a component that stores data in a MySQL database, I want to test everything from the public interface right back to the MySQL database. These are typically called "integration tests", but again, this term means different things to different people. Of course, treating the component as a black box is easier if I have control over everything it touches. If you have a component that is sending asynchronous messages or using an external, third-party service, you'll probably still need to consider adding dependency injection points (e.g. ports and adapters) to adequately test the component, but this is the exception not the rule. All of this still applies if you are building a microservices style of architecture. You'll probably have some low-level class tests, hopefully a bunch of service tests where you're testing your microservices though their public interface, and some system tests that run scenarios end-to-end. Oh, and you can still write all of this in a test-first, TDD style if that's how you work.
I'm using this strategy for some systems that I'm building and it seems to work really well. I have a relatively simple, clean and (to be honest) boring codebase with understandable dependencies, minimal test-induced design damage and a manageable quantity of test code. This strategy also bridges the model-code gap, where the resulting code actually reflects the architectural intent. In other words, we often draw "components" on a whiteboard when having architecture discussions, but those components are hard to find in the resulting codebase. Packaging code by layer is a major reason why this mismatch between the diagram and the code exists. Those of you who are familiar with my C4 model will probably have noticed the use of the terms "class" and "component". This is no coincidence. Architecture and testing are more related than perhaps we've admitted in the past.
相关参考网址:
http://www.codingthearchitecture.com/2015/03/08/package_by_component_and_architecturally_aligned_testing.html
http://java.dzone.com/articles/package-your-classes-feature
http://www.iteye.com/problems/97187
http://blog.csdn.net/scherrer/article/details/37935891
https://www.google.com.hk/search?newwindow=1&safe=strict&q=package-by-feature+style&oq=package-by-
feature+style&gs_l=serp.3...40621.40621.0.41030.1.1.0.0.0.0.0.0..0.0....0...1c..64.serp..1.0.0.AyIihZsCUS8
java项目的划分方式:模块优先还是层优先?的更多相关文章
- IDEA 学习笔记之 Java项目开发
Java项目开发: 新建模块: 添加JDK: 导入本地Jars: 从远程Maven仓库下载: 创建package: 新建类/接口/枚举等: 字体太小,改字体: Duplicate Scheme 修改编 ...
- springboot的maven多模块项目架构微服务搭建——构建多模块项目(依赖方式)
总想对微服务架构做一个小小的总结,不知如何下手,最近觉得还是从搭建微服务的过程来入手,对于springboot的maven项目从构建多模块架构进而衍化为常用的微服务架构来做个记录吧. 首先,创建多个s ...
- java项目部署Linux服务器几种启动方式总结经验
一:两种部署包: 部署之前先说下两种包,java项目部署到服务器一般有用war包的,也有用jar包的,微服务spring-cloud普及后大部分打包都是jar,部署之前先搞清楚自己要打war包还是ja ...
- Java项目打包方式分析
[TOC] 概述 在项目实践过程中,有个需求需要做一个引擎能执行指定jar包的指定main方法. 起初我们以一个简单的spring-boot项目进行测试,使用spring-boot-maven-plu ...
- Java项目开发中实现分页的三种方式一篇包会
前言 Java项目开发中经常要用到分页功能,现在普遍使用SpringBoot进行快速开发,而数据层主要整合SpringDataJPA和MyBatis两种框架,这两种框架都提供了相应的分页工具,使用 ...
- java项目的心得,java项目的代码层次的架构划分
java项目使用的架构是ssm(Spring+SpringMVC+MyBatis). 一.后台代码一般分三层,Controller,Service,Dao. 1.Controller层是对前端或者接口 ...
- Java内存区域划分和GC机制
Java 内存区域和GC机制 目录 Java垃圾回收概况 Java内存区域 Java对象的访问方式 Java内存分配机制 Java GC机制 垃圾收集器 Java垃圾回收概况 Java GC(Ga ...
- 一次从0到1的java项目实践清单
虽说工作就是简单的事情重复做,但不是所有简单的事你都能有机会做的. 我们平日工作里,大部分时候都是在做修修补补的工作,而这也是非常重要的.做好修补工作,做好优化工作,足够让你升职加薪! 但是如果有机会 ...
- 一份从0到1的java项目实践清单
虽说工作就是简单的事情重复做,但不是所有简单的事你都能有机会做的. 我们平日工作里,大部分时候都是在做修修补补的工作,而这也是非常重要的.做好修补工作,做好优化工作,足够让你升职加薪! 但是如果有机会 ...
随机推荐
- 移动开发webapp开发常用meta设置手机浏览器全屏模式
1.WebApp全屏模式: <meta name="viewport" content="width=device-width,initial-scale=1.0, ...
- iOS运行时Runtime浅析
运行时是iOS中一个很重要的概念,iOS运行过程中都会被转化为runtime的C代码执行.例如[target doSomething];会被转化成objc)msgSend(target,@select ...
- C#将JSON字符串对象序列化与反序列化
C#将对象序列化成JSON字符串 public string GetJsonString() { List<Product> products = new List<Product& ...
- 让Bootstrap轮播插件carousel支持左右滑动手势的三种方法
因为最近开发的项目涉及到移动设备上的 HTML5 开发,其中需要实现轮播效果.然后最快捷的方式,你知道的(Bootstrap),然后原生的 Bootstrap 的 carousel.js 插件并没有支 ...
- struts2使用Convention Plugin在weblogic上以war包部署时,找不到Action的解决办法
环境: struts 2.3.16.3 + Convention Plugin 2.3.16.3 实现零配置 现象:以文件夹方式部署在weblogic(10.3.3)上时一切正常,换成war包部署,运 ...
- addShutdownHook的用法
addShutdownHook作为一个正常关闭Java程序的途径,其实是非常有用的. 有JDK文档可知,当程序正常退出,或者为响应用户中断而终止虚拟机的时候,就会调用里面的线程,来作最后的退出处理. ...
- 前端见微知著番外篇:GIT舍我其谁?
在上一篇中,我们讲到了利用纯UI的软件如何实现代码的提交.但是在MAC机器上,是没有turtoiseGit这类软件的,所以利用命令行的方式就是我们的首选了. 下面我们来描述两种主要的Git使用场景: ...
- FineUI小技巧(3)表格导出与文件下载
需求描述 实际应用中,我们可能需要导出表格内容,或者在页面回发时根据用户权限下载文件(注意,这里的导出与下载,都是在后台进行的,和普通的一个链接下载文件不同). 点击按钮导出表格 由于FineUI 默 ...
- 【干货分享】JPager.Net MVC超好用轻量级分页控件
JPager.Net MVC好用的轻量级分页控件,好用到你无法想象,轻量到你无法想象. JPager.Net MVC好用的轻量级分页控件,实现非常简单,使用也非常简单. JPager.Net M ...
- 必须要会的技能(一) 如何实现设计时Binding
今天我们来分享一个主题:DesignTime Binding设计时绑定. 这一项技术可以使用在所有包括WPF及其衍生出来的技术上,比如Sliverlight,当然也包括UWP 先来说明一下设计时Bin ...