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项目实践清单
虽说工作就是简单的事情重复做,但不是所有简单的事你都能有机会做的. 我们平日工作里,大部分时候都是在做修修补补的工作,而这也是非常重要的.做好修补工作,做好优化工作,足够让你升职加薪! 但是如果有机会 ...
随机推荐
- gitlab配置邮件通知功能操作记录
之前已经介绍了gitlab的部署http://www.cnblogs.com/kevingrace/p/5651402.html但是没有配置邮箱通知功能,今天这里介绍下gitlab安装后的邮箱配置操作 ...
- 深入运用js
1,eval()函数 这个函数是获取参数的字符串,并将其作为js来处理,所以这里就有可能有人用这个来搞破坏(比如注入JS脚本文件等),所以最好的是方法是尽量少用,或者可以用new function() ...
- 2795: [Poi2012]A Horrible Poem
2795: [Poi2012]A Horrible Poem Time Limit: 50 Sec Memory Limit: 128 MBSubmit: 484 Solved: 235[Subm ...
- nfs客户端报错解决Stale file handle
NFS故障: 场景:客户端挂载是好的.服务端磁盘满了,重新给挂了一快.客户端df -h nfs挂载消失. 客户端报错:Stale file handle 现象如下: [root@test63-spri ...
- UML类图归纳
作为一个程序员,掌握UML类图是开发和阅读程序的基础. 转载请注明地址http://www.cnblogs.com/zrtqsk/p/3739288.html,谢谢! 一.基本介绍 UML是一种标准的 ...
- Java类加载和类反射回顾
今天学习Spring,突然想重新复习一下Java类加载和类反射的.巩固一下底层原理.部分参考了李刚老师的<疯狂Java讲义>和陈雄华.林开雄的<Spring3.x企业应用开发实战&g ...
- windows命令行下简单使用javac、java、javap详细演示
最近重新复习了一下java基础,在使用javap的过程中遇到了一些问题,这里便讲讲对于一个类文件如何编译.运行.反编译的.也让自己加深一下印象. 如题,首先我们在桌面,开始->运行->键入 ...
- nodejs实现Websocket的数据接收发送
在去年的时候,写过一篇关于websocket的博文:http://www.cnblogs.com/axes/p/3586132.html ,里面主要是借助了nodejs-websocket这个插件,后 ...
- struts 2.3.14.1 包详解
1.struts2-convention-plugin-2.3.14.1.jar: @ParentPackage(default-package) @Namespace("/") ...
- 【JQuery】 ajax 无效的JSON基元
[如题]个人理解就是 你向传数据[josn格式]了,但是后台接受确不是json格式的 数据, 贴段代码 var strJson = '{ "usercode": "123 ...