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项目实践清单
虽说工作就是简单的事情重复做,但不是所有简单的事你都能有机会做的. 我们平日工作里,大部分时候都是在做修修补补的工作,而这也是非常重要的.做好修补工作,做好优化工作,足够让你升职加薪! 但是如果有机会 ...
随机推荐
- python设计模式1:导言
<设计模式>一书总结了23个模式,依据各自的目的又被分为创建型模式(creational pattern).结构型模式(structural pattern)和行为型模式(behavior ...
- js双层动画幻灯
js双层动画幻灯 点击下载
- BZOJ 1030 【JSOI2007】 文本生成器
Description JSOI交给队员ZYX一个任务,编制一个称之为"文本生成器"的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生 ...
- CSS3 3D骰子
z zz zz zzzz zzzzz zzzzzz
- QT 常用控件一
QWidget 创建窗口 如果widget未使用腹肌进行创建,则在显示时视为窗口或顶层widget. 由于顶层widget没有父级对象类来确保在其不再使用时删除,所以需要开发人员在应用程序中对其进程跟 ...
- U3D屏幕空间到世界空间变换
using UnityEngine; using System.Collections; public class FPSCam : MonoBehaviour { Vector3 lastPos; ...
- 目录结构-内置(AJAX)帮助文档
Discuz common.js 内置(AJAX)函数帮助文档 作者:cr180 / 整理日期:1970-01-01 / 个人站点:www.cr180.com / Discuz超级管家 showMen ...
- C#执行XSL转换
xsl 可方便的将一种格式的xml,转换成另一种格式的xml,参考下面的代码: using System; using System.IO; using System.Text; using Syst ...
- hadoop家族之pig入门
昨天成功运行第一个在hadoop集群上面的python版本的wordcount,今天白天继续看网上提供的文档.下午上头给定的回复是把hadoop家族都熟悉一下,那就恭敬不如从命,开始学习pig吧- 这 ...
- UltraEdit 编译输出中文乱码的解决办法
配置UE的时候,都告诉大家javac %n%e 接可以了,但是再运行的时候,会出现乱码,再加上-J-Duser.language=GBK就可以了,也就是下面的样子. javac -J-Duser. ...