专栏首页TECH flower[译]按功能(特性)分包

[译]按功能(特性)分包

一种流行的方法是通过技术层面对项目进行分包。但是这种方法有一些缺点。相反,我们可以按功能分包并创建独立自治的程序包。结果是一个易于理解且不易出错的代码库。

整体分析

按照技术分包造成的缺点:

  1. 对属于某个功能的所有类的概述不佳。
  2. 通用代码、重用代码和复杂代码趋向于难以理解,并且由于难以把握变更的影响,因此变更很容易破坏其他功能用例。

按功能分包从而创建包含功能所需的所有类的程序包。好处是:

  1. 更好的可发现性和概览
  2. 独立且自治
  3. 更简单的代码
  4. 可测试性
  5. 便于团队协作开发

按照技术分层分包

项目结构的一种非常流行的方法是逐层分包。这将为每个技术组所属类提供一个软件包。

⚠️:按层分包从技术角度对所有类进行分组

让我们将调用层次结构添加到图片中,以“清楚地”了解哪个类取决于其他哪个类。

⚠️:调用层次结构遍及整个项目,涉及许多包

那么,按层分包的缺点是什么?

  1. 功能概述不佳。通常,当我们在项目中处理代码时,我们首先会想到要更改的特定领域或功能。因此,我们会从领域的角度出发。不幸的是,按技术分层分包迫使我们从一种软件包过渡到另一种软件包,才能掌握功能的概况。
  2. 通用,重用和复杂代码的趋势。通常,这种方法导致中心类包含每个功能用例的所有方法。随着时间的流逝,这些方法越来越抽象化(带有额外的参数和泛型)来满足更多用例。上图中仅一个示例是ProductDAO,其中放置了ProductController和ExportController的方法。结果是:
    • 当添加更多方法时,类将变得更大。因此,仅凭代码量,就很难理解它。
    • 更改通用重用代码很危险。尽管您只想处理一个用例,但您可以轻松地打破所有用例。
    • 由于以下两个原因,难以理解抽象方法和通用方法:首先,要通用,通常需要其他技术构造(例如,switch,参数,泛型),这使得查看与当前用例相关的业务逻辑更加困难。其次,认知需求更高,因为您必须了解所有其他用例,以确保您不会破坏它们。

桑迪·梅斯(Sandi Metz)指出:

“我觉得我必须了解所有内容才能提供帮助。”桑迪·梅斯(Sandi Metz)。请参阅我的帖子,了解我们的编码智慧墙。

⚠️:我们达到了DRY,但违反了KISS。


按功能(特性)分包

让我们将这些类重新排列成独立的功能包。

?用户管理功能包

新的包userManagement包含属于此功能的所有类:控制器,DAO,DTO和实体。

?产品管理功能包

新软件包productManagement包含相同的类类型,以及StockServiceClient和相应的StockDTO。这个事实清楚地表明:库存服务仅由产品管理人员使用。

userManagement和productManagement使用不同的域实体和表。将它们分成不同的包很简单。但是,当一个功能需要与另一个功能相似或甚至相同的域实体时,会发生什么?

?产品出口的功能包

现在,它变得越来越有趣。exportProduct包也处理产品实体,但具有不同的功能用例。

我们的目标是拥有独立自治的功能包。因此,exportProduct应该具有自己的DAO,DTO类和实体类,即使它们看起来与productManagement中的类相似。抵制重用productManagement中的类的冲动。

  • 我们可以使用针对出口用例量身定制的结构(DTO,实体)。它们仅包含相关字段,并且可以基于具有相关列的良好投影的查询来创建实体-别无其他。
  • 专用的ExportProductDAO包含特定于出口功能的查询和预测。

我们可能不得不再次编写更多代码,但最终会遇到非常有利的情况:

  • productManagement中的更改永远不会破坏exportProduct代码,反之亦然。它们可以独立发展。
  • 更改代码时,我们仅需牢记当前功能。
  • 代码本身将变得更加简单易懂,因为它不是通用的,并且不必在两个用例中都可以使用。

上面的功能包很棒,但实际上,我们将始终需要一个通用的包。

?通用软件包包含技术配置和可重复使用的代码

它包含技术配置类(例如用于DI,Spring,对象映射,http客户端,数据库连接,连接池,日志记录,线程池)

它包含可重用的有用代码片段。但是要非常小心代码的过早抽象。我总是先把代码放到尽可能接近它的用法的地方,也就是特性包,甚至是使用类。仅当片段确实有更多用途(⚠️:而不是我认为将来可能会使用)时,才将其移动到通用包中。三定律)提供了很好的指导。

在通用包中找到所有实体可能是有意义的。我们还对某些项目执行了此操作,其中许多功能包一次又一次地使用相同的实体。一些开发人员还希望将所有实体放在中心位置,以便能够整体查看数据库架构的映射。目前,我并不是教条,因为实体的两个位置都可以合理。不过,一开始我总是尽可能多地将代码转移到功能包中,并依赖于定制的特定于用例的实体和投影。


大图景

最终,我们的大图看起来像这样:

?按功能分包的大图

好处

让我们简要总结一下好处:

  1. 从域的角度来看,更好的可发现性和概述。属于业务功能的大多数代码位于一起。这很关键,因为我们通常会在考虑某个业务需求的情况下访问代码库。
  2. 独立的和自治的。功能所需的大多数代码都位于一个程序包中。因此,我们避免依赖其他功能包。结果是:在开发功能时,我们不太可能破坏其他功能。需要较少的认知能力来估计变化的影响。通常,我们只需要记住当前的软件包即可。
  3. 更简单的代码。由于我们避免使用通用和抽象的代码,因此代码变得更加简单,因为它只需要处理一个用例。因此,更容易理解和改进代码。
  4. 可测试性。通常,与试图满足所有用例的技术包中的“上帝类”相比,功能包中的类具有较少的依赖关系。因此,由于我们可以创建更少的测试依赖,因此测试变得更加容易。

缺点

  1. 我们必须编写更多代码。
  2. 我们可能会多次编写类似的代码。
  3. 决定何时才能更好地将代码移至通用软件包并重用它是很难的。有疑问时,“三定律)”很有用。我想强调指出,重用仍然是允许且有用的。
  4. 找出功能包的适当范围和大小也很棘手。有关详细信息,请参阅问题部分。

但是,我认为优点大于缺点。


背后的原理

拟议的按功能分包方法遵循的原则非常贴切:

KISS > DRY

再次,我想引用桑迪·梅斯(Sandi Metz)

“我觉得我必须了解所有内容才能提供帮助。”桑迪·梅斯(Sandi Metz)。请参阅我的帖子,了解我们的编码智慧墙。


按功能包装的方法

我们的团队记录了其遵循的编码准则和原则。关于按功能分包的部分如下所示:

我们基于功能分包。每个功能包均包含提供该功能所需的大多数代码。每个功能包都应独立且自治。

├── feature1
│   ├── Feature1Controller
│   ├── Feature1DAO
│   ├── Feature1Client
│   ├── Feature1DTOs.kt
│   ├── Feature1Entities.kt
│   └── Feature1Configuration
├── feature2
├── feature3
└── common
  1. 这种方法影响所有层。例如,每个程序包都有自己的DAO和客户端。不应有庞大的DAO类神。
  2. 一个程序包应该与其他程序包只有几个关系。该功能所需的所有逻辑事物都应放在程序包内。
  3. 经验法则:如果要删除功能,则只需删除相应的程序包。
  4. 尽管如此,也可以在通用软件包中重复使用东西,但它只应包含多次使用的代码(请参阅三定律))。它不应该包含业务逻辑。但是技术上有用是可以的。
  5. 如果存在特定于特性的Spring Bean,我们将把它们的配置放在特性包中。

问题

功能包中的结构如何?

这取决于项目和功能包的大小。

对于中小型项目,我喜欢避免定义可能会增加更多仪式而非价值的规则(例如,要求定义某些接口和子包)。只要您构建独立的、自治的、从您的特定业务领域派生的包,您就在正确的轨道上。

如果要处理更大的代码库,则可能需要定义有关子包结构和方式的更多规则,则允许一个功能包访问另一个功能包。“模块”或“组件”而不是“功能包”的概念可能更有帮助。例如,Tom Hombergs建议在每个组件包中添加api和内部包,这些组件包定义组件的哪些部分允许其他组件使用。有关详细信息,请参阅他的文章“使用Spring Boot和ArchUnit清理架构边界”。

我最终会一次又一次写相同的代码吗?

是的,会有一些重复,但是根据我的经验,您可能不会相信那么多100%相同的代码。由于相似的代码涵盖了不同的用例,因此通常是不同的。例如,两种方法可以按产品名称查询产品,但是它们在计划的字段,排序和其他条件方面有所不同。因此,最好将方法分开放在不同的程序包中。

而且,复制本身并不是邪恶的。在开始将代码提取到通用重用方法之前,我喜欢应用三定律)。

最后,我想强调指出,仍然允许集中使用可重用的代码,有时甚至是合理的,但是这些情况不再那么常见了。

Kotlin可以支持这种方法吗?

分包方法与语言无关。但是Kotlin使其易于遵循:

使用数据类,编写量身定制的特定于功能的结构(如DTO或实体)仅需几行,而无需样板。

Kotlin允许将多个类放在一个文件中。因此,我们可以使一个包含所有数据类定义的DTOs.kt或Entities.kt文件成为一个单独的DTOs.kt或Entities.kt文件,而不是有一个子包DTO或包含每个POJO类的许多Java文件的实体。

本文翻译自:https://phauer.com/2020/package-by-feature/

本文分享自微信公众号 - TECH flower(tech-flower),作者:东溪陈姓少年

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-05-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 「R」data.table 包功能特性学习

    data.table包提供了一个加强版的data.frame。它运行效率极高,而且能够处理适合内存的大数据集。它通过[ ]实现了一种自然的数据操作语法。

    王诗翔呀
  • Atlas功能特性

    对多字符集的支持是我们对原版MySQL-Proxy的第一项改进,符合国情是必须的。并且支持客户端在连接时指定默认字符集。

    dogfei
  • .NET 5.0正式发布,新功能特性(翻译)

      我们很高兴今天.NET5.0正式发布。这是一个重要的版本—其中也包括了C# 9和F# 5大量新特性和优秀的改进。微软和其他公司的团队已经在生产和性能测试环境...

    张传宁IT讲堂
  • Android 8.0新功能特性

    在2017年3月21日,Google 为开发者推出了新的 Android O 首个开发者预览版,接着再2017 Google I/O 开发者大会...

    分享达人秀
  • Android Studio 3.2新功能特性

    我就是马云飞
  • OpenIndiana功能及特性简介

       OpenIndiana是一个强大的操作系统,基于OpenSolaris,是开源操作系统,可以免费使用,由社区开发,适合做服务器操作系统,也适合做桌面版操...

    党志强
  • Zookeeper由来以及结构特性和功能特性

    早期我们是单一的应用架构,随着互联网的快速发展和体量的不断增长,后端的架构通过垂直伸缩的方式很难达到我们期望的性能要求,同时投入产出比也非常大,普通 PC 的性...

    名字是乱打的
  • 物种功能,多样性分解及功能多样性

    Ecol. Lett. | 普莱斯方程的生态学应用:解析群落组成变动对生态系统功能的影响

    Listenlii-生物信息知识分享
  • 常用图像分类功能包

    为了能够有效地识别位置,我们需要提取表征图像的特征,之后将相同的特征分成一组,并搜索相似的图像。当然位置识别也可以应用于其他程序,例如在图像恢复我们也需要查找相...

    小白学视觉
  • 新特性解读 | 部分权限回收功能的说明

    MySQL ACE,华为云MVP,专注于 Oracle、MySQL 数据库多年,Oracle 10G 和 12C OCM,MySQL 5.6,5.7,8.0 O...

    爱可生开源社区
  • JDK8 新增功能 ( Java 语言新特性 )

    在接口里可以写一个 “ 默认方法 ”,它可以在 不强制必须实现这个方法,从而很方便的往现存接口中添加新的方法。

    zhangyunfeiVir
  • FANUC常用按键以及特殊功能组合键说明!

    1)进入系统文件按屏幕下最右边软软键(next键)加其左傍的键加电源键,操作方法同时按下该两个软件加电源键开机

    UG数控编程
  • 简述PHP7.4 新特性和废弃的功能

    PHP7.4 上月 28 号已经发布了。又带来了一些新特性。可以让我们的代码写的更少了。

    砸漏
  • Laravel 8 新特性和功能优化速览

    Laravel 8.0 版本即将在 9 月 8 号发布,作者 Taylor Otwell 在 Twitter 中陆续透露了一些新特性和功能优化,下面我们一起来看...

    学院君
  • 如何分析功能优先性?

    某直播app规划上线多个功能(包含短视频、订阅主播游戏装备、直播间跳转、陪玩大神等)。

    猴子数据分析
  • 新特性解读 | 数组范围遍历功能

    资深数据库专家,专研 MySQL 十余年。擅长 MySQL、PostgreSQL、MongoDB 等开源数据库相关的备份恢复、SQL 调优、监控运维、高可用架构...

    爱可生开源社区
  • H5的Notification特性 - Web的桌面通知功能

    本文为joshua317原创文章,转载请注明:转载自joshua317博客 https://www.joshua317.com/article/49

    joshua317
  • LevelDB 入门 —— 全面了解 LevelDB 的功能特性

    本节我们将全面了解一下 LevelDB 的各种特性。LevelDB 的开发语言是 C++,考虑到会使用 C++ 语言的同学不是很多,在本节我们将使用 Java ...

    老钱
  • Oracle Database 20c新特性:PDB闪回功能增强

    数据库闪回技术在Oracle Database 10g就向大家提供了。因为闪回不需要对数据文件做restore的动作,所以数据恢复的时间相比传统RMAN进行恢复...

    jeanron100

扫码关注云+社区

领取腾讯云代金券