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项目实践清单
虽说工作就是简单的事情重复做,但不是所有简单的事你都能有机会做的. 我们平日工作里,大部分时候都是在做修修补补的工作,而这也是非常重要的.做好修补工作,做好优化工作,足够让你升职加薪! 但是如果有机会 ...
随机推荐
- web cache server方案比较:varnish、squid、nginx
linux运维中,web cache server方案的部署是一个很重要的环节,选择也有很多种比如:varnish.squid.nginx.下面就对当下常用的这几个web cache server做一 ...
- PAT 1029. 旧键盘(20)
旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现.现在给出应该输入的一段文字.以及实际被输入的文字,请你列出肯定坏掉的那些键. 输入格式: 输入在2行中分别给出应该输入的文字.以及实际 ...
- PL/SQL Transaction Control
PL/SQL 基础 ( 下 ) 1. PL/SQL中的 SQL语句 - END语句与COMMIT等内容,没有任何关系. - PL/SQL does not directly support dat ...
- 開博客了, 因為搞Delphi 開發的關於Delphi學習
開博客了, 因為搞Delphi 開發的關於Delphi學習,之前都是用本地TXT文件保存,發現在本地電腦保存非常不方面,而且只能在一台電腦上保存,不容易查看和修改內容.便於以後的記錄只用,以及經驗交流 ...
- 用Myisamchk让MySQL数据表更健康
用Myisamchk让MySQL数据表更健康 2011-03-15 09:15 水太深 ITPUB 字号:T | T 为了让MySQL数据库中的数据表“更健康”,就需要对其进行定期体检.在这里笔者推荐 ...
- java多线程系类:基础篇:05线程的等待与唤醒
概要 本章,会对线程等待/唤醒方法进行介绍.涉及到的内容包括:1. wait(), notify(), notifyAll()等方法介绍2. wait()和notify()3. wait(long t ...
- C# Winform应用程序占用内存较大解决方法整理(转)
原文:http://www.jb51.net/article/56682.htm 背景: 微软的 .NET FRAMEWORK 现在可谓如火如荼了.但是,.NET 一直所为人诟病的就是“胃口太大”,狂 ...
- swift 集合类型(一)
基本的数组结构Array: var shoppingList: String[] = ["Eggs", "Milk"] 这个shoppingList和传统意义上 ...
- quartz.net 项目无法加载的问题
最近尝试试用一下quartz.net 做任务调度用. 下载了源代码后打开解决方案发现项目无法加载.错误如下 未找到导入的项目“C:\Users\****\Desktop\Quartz.NET-2.1. ...
- 清北学堂2017NOIP冬令营入学测试 P4744 A’s problem(a)
清北学堂2017NOIP冬令营入学测试 P4744 A's problem(a) 时间: 1000ms / 空间: 655360KiB / Java类名: Main 背景 冬令营入学测试题,每三天结算 ...