在我们的首发期间优步技术日,软件工程师Aimee Lucido提供了一个推介会在这一点Uber Engineering android Codebase的历史。在本文中,她拓展了优步落后的原因,决定建立一个Monorepo来支持我们的Android发展的增长。
今天是您要建立一个全新的Android应用程序的那一天-对你有好处,开始始终是最难的部分。你做的第一件事是什么?
如果您喜欢我,您将创建一个新项目Android Studio。你做了一个主要活动,联系起来译,也许甚至可以创造一个Git.存储库使您的朋友可以与您在应用程序上与您合作。恭喜!您的代码组织现在类似于Uber Android Rider App的第一个版本。
当我们在2010年推出我们的Android Rider应用程序时,我们是一家小公司。优步工程在十几个人下。我们有一个在Android平台上工作的承包商,-如果你能相信它-我们甚至没有拥有Android驱动程序应用程序。因此,我们的单个Android Engineer在单个存储库中写下了骑手应用程序的第一个版本:一大盒代码。
使用单个存储库创建新应用程序提前一些好处:
- 开箱即用的Android:单个repo是提供的免费代码结构蚀,用于第一个版本的Android Rider应用程序的IDE。今天在2017年,在单个存储库中构建早期代码库比2010年的早期代码库更容易,因为我们有Android Studio与Android库密切合作。但无论您使用哪种IDE,IDE都将提供单个存储库结构,其中包含一个框和基本工具,如构建脚本和Git集成
- 小组的快速发展:由于所有依赖项都在一个地方,你通过简化代码共享和重构,唱单个存储库允许事物快速移动一小组工程师团队。
几年来,优步拥有的Android状态是小规模。到2013年,我们聘请了我们的第一个全职Android工程师,而且在此期间,我们的工程团队的工程团队已增加一倍多。只有我们开始构建Android驱动程序应用程序。
构建驱动程序应用程序使我们有机会改进Codebase组织。骑手应用程序仍然存在于单个代码库中,但由于我们现在有资源和工具来提取可重复使用的组件,我们确实如此。核心伙伴代码存在于自己的单独存储库中,但我们也建立了一个图书馆为两个应用程序充满可重用组件。
这一综合结构为我们提供了一段时间,但2014年,我们随后的增长呼吁不同的解决方案。优步拥有超过一百名工程师。Android Engineering团队从一到八个工程师那里种植了大小。由于我们的工程师数量增长,我们的代码库也是如此。
我们看了看我们前往的方向,我们意识到,如果我们没有改变,我们将遇到以下问题:
- 长建设时间:我们使用的初始Eclipse项目蚂蚁作为其默认构建工具,具有趋势慢一点处理大的CodeBases时。
- 功能耦合:容易分享代码的缺点是它有时可以超过共享。随着Android App功能的数量增加,我们担心功能将开始不必要地耦合在一起。
- 破旧的大师:您多久将您的变更重建在最新状态掌握,击中构建失败......然后花一小时调试它。然后,您意识到您的构建失败与您自己的代码无关,以及与重新打造代码的人员的一切都与您在没有重新运行之前的人!如果你和我一样,你一直在那个方程式的两边。具有多个工程师,有助于相同的码比,而无需在持续的整合工具中投入大量投资(见提交队列以下),您冒着人们着陆差点与彼此相冲突的同时。这意味着一个破碎的大师和浪费的时间。
因此,在2013-2014时间段内,我们将一系列更改转换为多重码Base,以便抢占这些问题。2013年,我们从eclipse移动我们的骑手应用程序蚂蚁至Intellij.和Maven,允许我们从服务器中提取伪像并将库代码库打破到20多个更小的解耦Repos。(例如,网络被移动到自己的存储库,后来将通过编译时通过Maven Repositor删除到消费者应用程序。)同时,我们将建立脚本转移到Gradle,将我们的第一个FORY转换为MultiTepo World。
我们的UET Multirepo CodeBase由几个小型码字组成,每个代码库都代表单个离散的想法作为骑车者和驱动程序应用程序在编译时被拉入的工件。每个存储库都像一键的代码,具有自己的IDE项目,git存储库和构建脚本。通过移动到Multirepo,我们确保了一个坚实的未来架构,避免了长度建设时的问题,特征耦合和破碎的主人。
所以现在的问题变成了:为什么我们从一开始就没有以多媒体开头?在一个词:开销。在自己的存储库中打破功能需要大量的时间和专业知识来设置。它需要深入的知识,触摸多个区域,如maven,gradle,vpns., 和工件管理。随着公司规模的增加,这一知识下降只会变得有价值。
对于近三年,我们经营,缩放,并与多遥组织一起繁殖。但到2016年,我们的Multirepo设置开始达到其限制,我们的开发人员对抗以下新问题:
- 架构筒仓:通过强大的特征解耦,架构孤岛开始形成。我们建造了统一皮棉系统早期阻止风格艺术筒仓,但这没有任何东西可以防止不同的团队使用各种各样的模式活动和碎片那至MVC建筑和我们自己的本土建筑学。在某种程度上,预计建筑孤岛甚至是好:工程师应该能够选择适合其用例的架构。但正如我们缩放的那样,我们的团队越来越开始在图书馆之间工作。这反过来意味着定期学习新架构,这意味着陡峭和一致的学习曲线。作为一个推论,特定的库的架构实施错误地可以与消费者应用程序或其他功能进行集成,甚至不可能在没有重大代码重构的情况下。
- 依赖地狱:随着时间的推移,我们的依赖性图表变得越来越复杂,最终我们建立了一个工具,以确保新的差异不会导致破坏变化。这个解决方案肯定会降低依赖地狱的影响,但取决于您的更改影响的库,即使在Codebase上运行该工具可能会令人沮丧。此外,修复了我们发现的任何问题可能需要几天的工程工作:识别问题依赖性,修复违规代码,以及切割受影响的存储库的新版本。
- 长期建设:我们的Codebase Size开始达到Gradle可以快速构建的基础的限制。新的应用程序构建可能需要15分钟;一系列小XML调整可能会累积累计浪费时间的建筑时间在开发的一天内。
那么我们做了什么?
我们问题的答案:投资一个Monorepo,包含多个独立项目的单个存储库。一个CodeBase中存在monorepo,就像我们的初始骑手应用程序一样。但与我们的初始骑手应用程序不同,这一框中的所有代码的新实例化包含多个独立运行的逻辑组件。因此,我们现在可以将时间和资源投入有必要的工具和架构,以修复一个大型,单个repo的许多缺点:
- IDE支持:Android Studio现在被认为是默认的,轻量级的Android开发人员平台,但这几乎不是唯一的。凭借一个大的monorepo,我们发现了Intellij.适用于目前的规模-通过Intellij成为开源的一些调整。
- 长建设时间:优步最近从Gradle转换为buck那这是一个模块化构建系统。降压易于集成,因为我们的代码已被分解为离散组件。我们的家庭成长的Gradle Pluginokbuck.给了我们A.平滑过渡,导致建立十五分钟的建设时间,APP减少到5分钟的新增版本,以换成增量构建的一分钟。
- 破旧的大师:我们最近推出了一个调用的系统提交队列哪些rebases在master上更改,并在合并它们之前运行可自定义的测试集。这可以防止工程师推送打破构建的代码,让主吱吱声对其他人使用它清洁。
这看起来像很多开销,它是。没有开箱即用的方式来创建一个monorepo,因为现在只有少数公司的公司需要它需要它。但对于我们在2013年预测的每一个痛苦点,我们现在有时间,专业知识和资源来构建工具,以防止他们阻碍我们的生产力。
正如你所看到的,它需要多年的时间来实现这个最新的发展阶段。当我们是一支仅少数工程师的小型,陷入困境的团队时,我们没有创造的时间或资源提交队列或设置buck。但我们的早期绝抗鼓励建筑决定让我们尽快按照我们的方式缩放。现在我们进一步扩大了扩展,我们可以投资于开发的付款,以确保未来的服务增长无缝和高效。
D.Eveloper生产力是艰难的,但重要的工作,并且随着每个渐进的改进,我们不仅仅是更好的优步,而是android社区大。如果COMORAING UBER的Android Monorepo对你来说听起来很有趣,考虑加入我们的移动工程团队-我们正在招聘!
软件工程师JJ Ford和Gautam Korlam也为这篇文章做出了贡献。
照片标题信用:“休息reedbucks.下午晚些时候“由Conor Myhrvold,南都瓦国家公园,赞比亚。





