组织多个scala相互关联的sbt& git项目 - 最佳实践建议

时间:2014-10-21 12:07:58

标签: git scala sbt sbt-native-packager

使用scala,使用sbt进行构建,使用git进行版本控制,如果团队代码超出单个项目的范围,那么组织团队代码的好方法是什么?在某些时候,您开始考虑将代码分离到单独的库或项目中,并根据需要在它们之间进行导入。你会如何为此组织事情?或者你会避免诱惑,只管理同一个sbt和git单一“项目”下的所有包裹?

兴趣点是:(随意改变)

  • 避免发明新的“头痛”,过度设计想象中的需求。
  • 仍然可以在您仍然想要的时候,在给定的开发计算机或CI server上轻松构建所有内容
  • 生产包装:能够使用SbtNativePackager包装您的产品而不会产生太大的痛苦。
  • 轻松控制您在给定开发计算机上使用的每个库的哪个版本,并能够无缝切换它们。
  • 避免git操作变得比它通常更糟糕。

此外,您是否会使用某种“本地sbt / maven团队存储库”以及为实现这一目标可能需要做些什么?希望这不是必要的。

谢谢!

2 个答案:

答案 0 :(得分:11)

我在沙子中使用以下几行:

  • 最终进入不同可部署的代码在同一个存储库中的不同文件夹中,在一个伞形项目下 - SBT称之为multi-project build(我使用maven而不是SBT但是概念非常相似)。它将被构建/部署到不同的罐子里。

在制作有意义的划分时,我会尝试考虑最终的可展开性。例如,如果我的系统foosys有foosys-frontendfoosys-backend可部署,其中foosys-frontend进行HTML模板化,foosys-backend与数据库进行通信,两者通过REST API进行通信,然后我将这些项目作为单独的项目,并将foosys-core项目用于公共代码。 foosys-core不允许依赖于html模板库(因为foosys-backend不想要),也不允许依赖于ORM库(因为foosys-frontend不会我想要那个)。但我并不担心将与REST库一起使用的代码与核心域对象分离,因为foosys-frontendfoosys-backend都使用REST代码。 / p>

现在我要添加一个新的foosys-reports可部署的,它可以访问数据库来执行一些报告。然后,我可能会根据foosys-database创建一个foosys-core项目,以保存foosys-backendfoosys-reports使用的共享代码。由于foosys-reports没有使用REST库,我可能还应该从foosys-rest拆分foosys-core。所以我最终得到了一个foosys-core库,另外两个依赖它的库项目(foosys-databasefoosys-rest),以及三个可部署的项目(foosys-reports取决于{{ 1}},foosys-database取决于foosys-frontendfoosys-rest取决于两者。)

您会注意到,这意味着每个可部署组合的组合都有一个代码项目,可以使用该代码。所有三个可部署的代码都在foosys-backend。只有一个可部署的代码可以部署在可部署的项目中。三个可部署中的两个部署的代码位于foosys-corefoosys-rest。如果我们希望某些代码属于foosys-databasefoosys-frontend可部署的代码,但 foosys-reports可部署,我们必须创建该代码的另一个项目。从理论上讲,这意味着随着我们添加更多可部署项目,项目数量呈指数级增长。在实践中,我发现它并没有太大的问题 - 大多数理论上可能的组合实际上没有意义,所以只要我们只有在我们实际有代码放入它们时才创建新项目&# 39;好的。如果我们最终在foosys-backend中使用了几个在每个可部署中都没有实际使用过的课程,那么它就不是世界末日。

在此视图中,测试最好被理解为另一种可部署的。所以我会有一个单独的foosys-core项目,其中包含用于测试所有三个可部署项目的公共代码(取决于foosys-test),也许还有一个foosys-core项目(取决于{{1 } {和foosys-database-test)用于foosys-testfoosys-database之间通用的测试帮助程序代码(例如数据库集成测试设置代码)。最终,我们最终可能会得到foosys-backend项目的完整并行层次结构。

  • 只有在项目具有不同的发布生命周期时,才将项目移动到单独的git存储库(同时,将整个构建分开)。

不同存储库中的代码必须独立版本化,因此在某种意义上说这是一个空洞的定义。但我认为你应该继续将git存储库分开(只需要与this post类比:当你的数据太大而不能使用任何更友好的东西时,你应该只使用Hadoop)。一旦你的代码在多个git存储库中,你必须手动更新它们之间的依赖关系(在开发机器上你可以使用-SNAPSHOT依赖关系和IDE支持工作,就像版本仍然同步一样,但是你必须手动更新它每次与master重新同步时,都会增加开发的摩擦力。由于您正在异步执行发布和更新依赖项,因此您必须采用并强制执行语义版本控制等操作,以便人们知道何时更新foosys-reports上的依赖项以及何时不是{&...} #39;吨。您必须发布更改日志,并具有预警CI构建和更全面的代码审查过程。所有这一切都是因为反馈周期要长得多;如果你在下游项目中打破了某些东西,你就不会知道这一点,直到他们更新了对-test的依赖,几个月甚至几年之后(是的,几年 - 我已经目睹了这一点,并且在80-人创业,而不是大城市)。因此,您需要进程来防止这种情况发生,而且一切都变得相对不那么灵活。

执行此操作的有效理由包括:

  • 您项目的完整版本耗时太长,会降低您正在处理的代码的集成速度 - 尽管首先尝试加快速度。
  • 部署所有可部署的内容耗时太长 - 尽管如此,请尝试自动执行此操作并加快速度。保持所有内容同步是一个真正的优势,你不想放弃它,直到你绝对不得不放弃。
  • 单独的团队需要处理代码。如果您不是彼此不断地进行通信,那么您无论如何都需要进程开销(语义版本控制等),因此您可以获得更快的构建时间。 (要明确的是,我认为每个git存储库都应该拥有一个拥有并负责的团队,当团队分裂时,他们应该拆分存储库。我对发布流程和职责有进一步的想法,但这个答案已经很长了)

我会使用团队maven存储库,可能是Nexus。实际上我甚至在你进入多项目阶段之前就推荐这个。它非常容易运行(只是一个Java应用程序),你可以proxy your external dependencies通过它,这意味着你有一个可靠的依赖jar源,你的构建将是可重现的,即使你的一个上游依赖项消失。

我打算将我的团队工作方式写成博客文章,但与此同时,我很乐意回答任何其他问题。

答案 1 :(得分:3)

我在这里有点晚了,但我的2美分。

我在过去的工作中工作过的大多数scala项目和/或任何项目最终都采用了非常相似的结构。通常与其他团队成员达成共识(这有助于验证决策)。唯一的主要哲学区别是技术基础设施层或业务模块上的单独项目。以下示例:

Common Projects

  • App.Utils :所有其他项目使用的共享实用程序代码(最小化为0个依赖项)
  • App.Core :共享业务代码(模型,核心助手,接口,类型)

选项1:模块分离

  • App.Inventory :包含服务,数据库代码,帮助程序的广告资源模块
  • App.Orders :包含服务,数据库,帮助程序的订单管理模块

这可以非常方便且易于按业务区域进行管理,然后您可以根据需要部署单个模块。如果需要,您还可以决定将模块分离为单独的API(共享代码库仍在utils和core中)。这里的缺点是该方法可以使项目数量膨胀。

选项2:技术层分离

  • App.Database :数据库访问功能
  • App.Services :业务服务的核心实施

在这种方法中,所有区域的所有逻辑/服务都在服务项目中,同样也在数据库中。所以说库存的代码在数据库和服务项目之间分开。这允许通过传统技术层分离。对于较小的项目,这可能会快得多。

就个人而言,我更喜欢选项1中更模块化的分离。它更易于扩展,并且在进行代码更改时通常感觉更简单。

-K