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

Rob*_*ill 7 android gradle multi-module android-gradle-plugin

这是不是之间的区别的常见问题apiimplementation,并希望将但从构建一个多模块项目的点更先进的和有趣的.

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

  • library
  • base
  • feature1
  • feature2
  • app

现在模块之间的关系是:

base 包装 library

feature1feature2使用(取决于)base

appfeature1feature2

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

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

为了使library提供给feature1我们有两个选择,据我可以告诉:

  1. 更改implementationapibase泄漏依赖于依赖模块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必须修改包含该子句的所有模块.即使我认为这是一件好事,因为它完全跟踪变更如何修改项目,我看到它可能需要更多时间.

现在的问题是:

  • 在编译这个多模块场景时是否有任何权衡取舍?

  • 是否一个模块泄漏依赖"更快"以便为消费者模块编译?

  • 它在构建时间方面有很大差异吗?

  • 我还缺少哪些其他副作用,利弊?

谢谢你的时间.

ddi*_*rov 5

Gradle论坛主题重新发布。

您所描述的是关于分层体系结构系统的相当普遍的讨论,也称为“严格”层与“松散”层,或“开放”层与“封闭”层。请参阅《软件体系结构模式》中的这一章(也希望对您免费),以了解一些符号学,这些符号学不太可能对您的选择有很大帮助

从我的角度来看,如果模块需要中断分层,则可以对项目结构进行建模,以最直接,最直观的方式展示它。在这种情况下,这意味着将添加library为的实现依赖项feature1。是的,它使图表更丑陋,是的,它迫使您在升级时触摸几个文件,这就是重点-您的设计有缺陷,现在可以看到。

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

如果base模块的所有客户端都需要访问library(即,因为您使用library公共签名中的类或异常),则应将libraryAPI 公开为base。缺点是library成为的公共API的一部分base,它可能比您想要的更大,并且不受您的控制。公共API是您要负责的事情,并且您希望使其保持小巧,文档化和向后兼容。

在这一点上,您可能正在考虑拼图模块(好的),osgi(错误的……不要),或者将需要公开的lib部分包装在自己的类中(也许吗?)

只为打破依赖关系而包装并不是一个好主意。一方面,它增加了您维护(以及希望)文档的代码量。如果您开始在该base层中进行少量修改,并且该library库是众所周知的库,则会引入(增值)不一致-必须始终警惕它们对lib的假设是否仍然成立。最后,薄包装器通常最终会泄漏库设计,因此,即使它们包装了API,当替换/升级lib时,仍然会迫使您触摸客户端代码,这时最好直接使用lib。

因此,正如您所看到的,是权衡和可用性。CPU不在乎模块边界在哪里,并且所有开发人员都不相同-有些可以更好地应对大量简单的事情,有些可以更好地应对少数高度抽象的概念。

当任何好的设计都可行时,不要着迷于最好的设计(就像鲍勃叔叔会做的那样)。为引入顺序而辩解的额外复杂性的数量是一个模糊的数量,您可以自行决定。给您最好的电话,不要害怕明天更改它:-)