Gradle api与多模块项目实施的最佳实践

问题描述 投票:5回答:1

这不是关于apiimplementation之间差异的常见问题,并且从构建多模块项目的角度来看,希望会更加先进和有趣。

假设我在应用程序中有以下模块

  • library
  • base
  • feature1
  • feature2
  • app

现在模块之间的关系是:

base包裹library

feature1feature2base上使用(取决于)

app汇集了feature1feature2

这个多模块结构中的所有东西都应该能够使用Gradle的implementation依赖项工作,并且不需要在任何地方使用api子句。

现在,让我们说feature1需要访问base中包含的library的实现细节。

为了使library可用于feature1,据我所知,我们有两个选择:

  1. implementation中为api更改base以将依赖性泄露给依赖于base的模块
  2. 添加library作为implementation依赖feature1没有base泄漏对library的依赖

当然,为了解决这个问题,这个例子已经被简化了,但是你明白了这可能会成为一个具有4或5级依赖关系的大量模块的配置地狱。

我们可以创建一个base-feature中间模块,它可以包装base并为feature1提供另一层抽象而不会泄漏library,但是让我们将这个解决方案放在这个问题的范围之外,专注于依赖项的设置。


我在上述选项中检测到的一些权衡:

选项1)到

  • 较小的build.gradle的文件,因为不需要重复implementation条款
  • 更快的构建编程编辑。只需对api子句进行单一更改,并查看传播到所有使用者模块的更改

选项1)缺点

  • 类可能会出现在无法访问它们的模块中。
  • 很容易被开发人员使用,因为他们有可用的实现,而不仅仅是模块接口。

2)走向

  • 它清楚地表明模块具有哪些依赖关系。
  • 不要猜测类的来源(认为4或5级模块泄漏依赖关系),因为它们的起源总是在模块依赖项中声明。

选项2)缺点

  • 使更新依赖项更加繁琐,因为必须修改所有带有implementation子句的模块。即使我认为这是一件好事,因为它完全跟踪变更如何修改项目,我看到它可能需要更多时间。

现在的问题是:

  • 在编译这个多模块场景时是否有任何权衡取舍?
  • 是否一个模块泄漏依赖“更快”以便为消费者模块编译?
  • 它是否会在构建时间上产生重大影响?
  • 我还缺少哪些其他副作用,利弊?

谢谢你的时间。

android gradle android-gradle multi-module
1个回答
3
投票

Gradle forum线程重新发布。

您所描述的是关于分层架构系统的相当常见的讨论,也称为“严格”与“松散”分层,或“开放”与“封闭”层。从Software Architecture Patterns看到这个(希望对你来说也是免费的)章节中的一些符号学不太可能对你的选择有所帮助

从我的角度来看,如果一个模块需要打破分层,我会对项目结构进行建模,以最直接和最明显的方式公开它。在这种情况下,它意味着添加library作为feature1的实现依赖。是的,这使得图表更加丑陋,是的,它迫使您在升级时触摸更多文件,这就是重点 - 您的设计存在缺陷,现在可见。

如果很少有模块需要以相同的方式打破层封装,我可以考虑添加一个单独的基本模块来公开该功能,其名称如base-xyz。添加新模块是一件大事,不是因为技术工作,而是因为我们的大脑一次只能处理这么多“事物”(分块)。我相信当Gradle“变种”可用时,它们会同样适用,但我还没有声称,因为我没有尝试过它们。

如果base模块的所有客户端都需要访问library(即因为您在公共签名中使用来自library的类或异常),那么您应该将library作为base的API依赖项公开。其缺点是library成为base的公共API的一部分,它可能比你想要的更大,而且不在你的控制之下。公共API是您负责的事情,并且您希望将其保持小,记录和向后兼容。

此时你可能正在考虑拼图模块(好),osgi(错误...不要),或者包装你需要在自己的类中暴露的lib部分(也许?)

仅仅为了破坏依赖性而包装并不总是一个好主意。例如,它增加了您维护和(希望)文档的代码量。如果你开始在base层进行小的改编,并且library是一个众所周知的库,你引入(增值)不一致 - 人们需要始终警惕他们对lib的假设是否仍然成立。最后,瘦包装器通常会泄漏库设计,所以即使它们包装了API - 当你更换/升级lib时仍然会强迫你触摸客户端代码,此时你可能最好直接使用lib。

因此,正如您所看到的,是关于权衡和可用性。 CPU并不关心模块边界所在的位置,并且所有开发人员都是不同的 - 有些人会更好地处理大量简单的事情,有些人会更好地处理少量高度抽象的概念。

当任何好的设计都能奏效时,不要痴迷于最好的(就像在鲍勃叔叔那里做的那样)。为了引入顺序而合理的额外复杂性的数量是模糊量,并且是您负责决定的事情。让你最好的电话,不要害怕明天改变它:-)

© www.soinside.com 2019 - 2024. All rights reserved.