“我对协程非常否定”:Artyom Zinnatullin谈Android开发



在Android开发人员中, Artyom Zinnatullin非常受人尊敬,因此您可以撰写关于他的“关于Chuck Norris的事实”的类似物-像这样:

  • Artyom如此苛刻,以至于当他见到他时,github本身就变成了绿色(我们中谁可以吹嘘这样的捐款时间表?)
  • 阿尔乔姆如此残酷,以至于吉特对他来说是使者
  • Artyom非常苛刻,以至于在他的应用程序上下文中都是播客

当我们在Mobius会议上采访他时,它是打算进行在线广播的。 但是,在看完他们在Android聊天中是如何使用它之后,我们决定让Habré上的许多人也对它感兴趣,并为您制作了一个文本版本(我们还附有视频录像)。

如何处理一百万行代码的项目? corotin Kotlin的缺点是什么? Google怎么了? 旧金山的发展与俄罗斯的发展有何不同? Mobius在说什么? 在削减-关于所有这一切。


Evgeny Trifonov :在此Mobius上,我想念您的演讲“ Lyft上的Android版本”,但之后我看到很多人希望在讨论区提出问题。 我想澄清一下:但是,毕竟,大多数观众不是在像Lyft这样的大型项目中工作,这种经历对他们是否有意义?

Artyom :这很有趣。 得益于您一流的计划委员会,我脑海中最初的报告大纲以及我最终执行该报告的方式都大不相同。

最初,我要告诉您这一切都是从Lyft开始的,为什么我们要使用某些技术解决方案。 他与节目委员会的谢尔盖·波什坦(Sergey Boishtyan)进行了两个小时的交谈,他听着说:“当然很酷,但是您做了主题演讲。” 最后,我意识到,这样的报告固然很有趣,但对任何人来说都没有关系。

然后我重做了,将重点从基本工程方法转移到装配系统和其他系统的选择上。 我的目标不是要明确使用哪些工具。 我不希望有人随便使用它们,然后给我写一封令人难以置信的信,说我不能告诉你所有的事情都行之有效。 我想准确传达有关如何做出选择以及在我看来(自然,主观)重要的事情的工程实践。 因此,我希望最终的经验对更多的人有意义,而不仅仅是“ Lyft的家伙出来并说了些什么”。

Oleg olegchir Chirukhin :是否有其他人很难做出的Lyft选择?

Artyom :是的,当然。 我们同时在项目中有两个构建系统,我绝对不推荐任何人(笑)

维护起来非常痛苦:您不断地用两只石头追逐两只鸟,但到最后,有些东西却无法奏效。 但这是我们的当前状态,从历史上看,因为一个构建系统开始关闭部分任务,所以我们不得不启动第二个。 我讨论了如何避免这种情况并正确迁移到其中之一。

奥列格(Oleg) :什么样的构建系统?

Artyom :我们使用Gradle和Buck,我谈到了如何从Google来到Bazel。

奥列格(Oleg) :这是一种走向邪恶的运动:从漂亮的Gradle到Bazel,甚至没有正常的依赖关系。

Artyom :现在或多或少。 好吧,是的,当然会有权衡取舍,当然,Gradle也有其优点。 这完全取决于项目的类型。 对于某些人而言,Gradle将比Buck和Bazel更适合,因为它们具有基本点,因此不会在同一模块内逐步收集,但是Gradle会,而且对于许多人来说,这非常重要。 Gradle可以做到这一点很酷。

另一件事是,当您添加模块(更多,更多的模块,八百,一千)时,Gradle进行了重新设计,以至于线性降低了某些地方的装配速度。 但是在我看来,如果社区向他们施加压力,Gradle可以解决所有这些问题-也许我正在这样做。 让我们看看。 (注意:面试几天后,Artyom写了一篇有关Gradle问题的长篇文章

奥列格(Oleg): Bazel仅仅是因为我要支持大量模块吗?

Artyom :让我们说,我们不喜欢这种感觉,但是将项目划分为多个模块可以使我们的业务发展更快。 基本上,据我了解,这是隔离,因此无法解决意大利面条的问题,因此难以维护。 模块可以更好地控制代码的哪些部分与哪些部分交互。 我们有将近一百万行代码。 如果在一个模块中,我将不得不吃意大利面。 因为在Java(即Kotlin)这一语言的基础上,有必要结束一些事情以禁止程序包之间的调用,而在此之间没有人期望它们进行调用。 另外,还会出现一个问题,那就是Gradle不会在一个模块中取出那么多代码。 它不会并行收集它,而是将其逐步组装到模块中。

每个解决方案都需要权衡取舍。 就我们而言,这似乎是正确的解决方案,但是存在一个问题-因为我们目前支持两个构建系统。

Oleg :那么对数百个模块(monorepo或许多存储库)有什么好处?

Artyom :这是一个很痛的地方。 从您不必考虑版本控制的角度来看,一个存储库可能更好,并且当您克隆十几个存储库以进行更改,然后打开一个拉取请求和之后的十二个存储库时,就没有这种依赖关系了。 “摩擦”已从系统中删除,人们不害怕更改代码。 对他们而言,变化是原子性的:将所有内容合并到一个项目中,并且来自一个模块的更改会在未经其明确同意的情况下自动转移到其他项目。 同时,将自动执行您在CI中自动编写的所有检查,并验证代码是否已编译,测试。

奥列格(Oleg) :而且,如果您不知道自己像喝一些铬一样,在喝茶的时候树枝会变两分钟?

Artyom :是的,当然有可能。 但是,这里的问题可能已经出现在产品尺寸上:Chrome是否需要包含这么多代码? 也许值得在单独的工具中突出显示某些部分,这些部分会在发生重大变化时定期收紧? 这可能是项目组织的问题。 顺便说一句,很酷的例子。 我有一个类似的例子:与Yandex.Browser的帅哥往来,他们那里也有很多人。

Chrome可以分为多个组件,如果您使用的是V8-我不是专家,但是据我了解,它通常是一个单独的项目,对吧? 那么,为什么GUI应该知道引擎,每次都重新组装引擎,并考虑附近的源代码呢? 顺便说一句,Bazel也支持这一点。

总的来说,现在所有大型构建系统(例如Gradle,Buck和Bazel)都支持诸如当您引用另一个Bazel装配体时的复合构建之类的东西。 这是一个棘手的情况,但是尽管如此,它仍然有效,它允许您从存储库中删除部分文件,减小大小。 例如,IDE会疯狂地为所有这些文件建立索引,因此我想以某种方式将它们与项目的常规组件分开。

但是,我们远非如此。 在我看来,我们可以冷静地再计算五年。 我们不太可能会遇到两分钟的结帐时间。 我们没有很多人。

Eugene :除了两个构建系统之外,Lyft是否还有自己的特点?

Artyom :是的,那里有一些非典型的故事。 碰巧的是,来到公司的人(来自Google,Facebook和其他地方)讨厌单一存储库。 因此,我们在Lyft拥有三个单一存储库:Android,iOS和L5(这些是我们的自动驾驶汽车 )。

其他所有内容都超过1500个git存储库:对于所有微服务,对于所有库都是单独的。 历史上就是这种情况。 这是我们要付出的巨大代价:很难通过变革来推动变革。 另一方面,与它们中的每一个一起使用时,您可以进行即时git clone,即时git push,一切都非常快,IDE索引每秒。 我可以说这确实是一个有趣的部分。 从旧金山的帅哥那里,我希望有一个单一的存储库。

奥列格(Oleg) :并且,当更新这些单独的存储库之一时(例如,API发生了更改),此更改如何应用于公司的其他部门?

Artyom:好痛。 (笑)好吧,我不是后端开发人员,因为我不编写功能后端,而是编写基础架构后端-在这方面,它们通常是非常自治的。

通常,这只是一堆集会,交叉互动然后进行计划。

奥列格:集会是集会系统的一部分吗? (笑)

Artyom :是的,首先我们需要组装一个集会,然后组装一个仓库。 另外,不幸的是,从历史上看,我们有许多这样的微服务-这是Python,它也有自己的笑话。

奥列格(Oleg) :对Python的一些不满有所下降。

Artyom :不太喜欢动态键入。 Python,而不是Python-没什么区别,但是动态类型是一件很痛苦的事情。



尤金(Eugene) :“对于旧金山的公司而言”下滑了,这很奇怪:但是就发展而言,旧金山的公司与俄罗斯的公司不同,是否有明显的不同?

Artyom :差异很大。 我不太喜欢这样分类,但在我看来这是一所更正确的工程学校。

奥列格(Oleg) :在这里-在哪里?

Artyom :在俄罗斯,在前苏联的国家中。 人们更加关注其系统组件如何工作的技术方面。 在美国,经常发生一些图书馆解决问题的情况,人们甚至不看它是如何实现的。 通常,他们绝对不关心它的速度变慢或使用不正确。

我将在那儿采访很多人,因为这是工作的一部分,而且一般的知识水平可能仍然较低。 有一些变化。 每次一个人来自东欧,在面试中都会变得更加有趣,因为人们不害怕反抗,在某个地方争论。 尽管美国候选人经常可能根本不回答任何问题或回答“我不记得我上次使用它的时间。” 对于诸如“ HTTP请求如何工作?”之类的问题 或“您将选择哪种数据格式?” 他们无法给出正常的工程答案,但会说:“嗯,最近五年来我一直在使用它。” 固然很酷,但主人不会拉扯。

另一方面,有些项目需要花费数年时间才能与我们在这里所做的比较。 人们生产更多的大众产品,而规模却更大。 例如,Chrome或Uber-他们那里已经有上千个模块。 这只是问题的严重性。 假设在Uber中有300名Android开发人员。 问题出现了:为什么? (笑)但是,尽管如此,他们还是设法使这种巨大的工作不断地释放了。 我想说这样的问题在这里不太常见。

Yandex是一个很好的例子。 我在Yandex.Maps上有一个朋友:十个人制作了一个Android应用程序。 在Google中,很可能有一百人坐着。 同时,Yandex.Mart具有更多功能。 我认为那是区别。

尤金(Eugene) :此外,硅谷还与初创企业有关,它们采取“快速行动,打破常规”的方法,看来这也应该影响发展:生活在前沿,使用最新的技术。 是真的吗

Artyom :我不是在初创公司工作,Lyft很难这样说:已经有303人,其中一千多人是工程师。 也就是说,它是一家已经成立的公司。

尖端技术很少使用。 如果这项技术被大肆宣传,那就可以。 如果技术是利基市场,但是很酷,通常不是。 直到所有会议都谈论它之前,很少有人会使用它。

但与此同时,我真正喜欢的(在旧金山,部分在硅谷)-由于两家公司的地理位置非常接近,因此许多问题得以解决。 通常,您在聊天室中给某人写信:“让我们在我们家或您的办公室一起吃午饭,然后决定,我们会提出一些问题”,然后一次-一个开源项目或请求请求出现在另一个项目中,固定的。

有趣的是:人们经常讨论实际上不应该在NDA上讨论的事情。 但这就是整个山谷运动的方式,最终每个人都知道其余的运动方向,整个行业齐心协力。 说,Lyft和Uber动员者经常谈论技术问题,因为我们使用Uber的开源软件。 当然,在某些技术上直接有核心专家。 这也很酷:您可以与他们交叉。

我喜欢这个,在我居住的某些城市中,这还不足以吸引我。 在圣彼得堡,这里有一个非常酷的Java用户组(我现在还不知道现在的情况):您下班后来了,而Shipilev竭尽全力,这很好!

然后它又出现了:例如,它也有自己的Java用户组,例如,经常有来自Oracle的家伙,他拍摄了一些新的Reactive JDBC。 您可以争论,因为Spring的一些Project Reactor负责人或Reactive负责人坐在同一地方,所以正在进行热烈的讨论,这很酷。

Oleg :我会问其他问题:我查看 Mainframer 存储库 ,并在其中使用Rust。 为什么所有这些都不写在有福的Javka上,而是写在某种Rust上?

Artyom :最近,我已经说过该程序应该具有最少的资源。 也就是说,我想非常接近铁如何消化字节。 在Java中,发生了很多事情(我什至没有在谈论垃圾回收),即JIT和所有这一切。 我真的很喜欢Java现在正朝着也将要进行提前编译的事实迈进。 在我看来,例如,通过从缓存中下载其提前编译(最初发生在其他计算机上)来启动微服务来启动微服务,并非常快速地启动它,而无需预热。 这很酷,但是Java有代价。 我不能只问正在构建iOS项目的人在系统上安装Java。

Mainframer最初是用Bash方言编写的。 但是我想用一种系统语言重写它以获得正常的多线程,编写正常的单元测试的能力,而不仅仅是在实用程序之上的集成测试……

奥列格(Oleg) :例如,Python。

Artyom :是的。 但是,随之而来的问题是,首先是动态类型,其次是...

奥列格(Oleg) :在Bash中也是动态键入。

Artyom :所以我想重写它。 除此之外,Python现在是两个存在一个问题:在macOS上,默认情况下是第二个,而在Linux上几乎所有现在都是第三个。 各种各样的笑话。 如果我需要某种上瘾的约束力,我会要求人们跑点子? 还是我必须撞她?

我想采用一种需要零依赖关系的系统语言,以便可以放入一个二进制文件,该二进制文件将有条件地小于一兆字节,并且以最小的开销工作。

奥列格(Oleg) :您可以带上Golang,至少有一个垃圾收集器。

Artyom :这就是我想要尝试Rust的原因。 而且有效。 另外,Golang对于泛型有点难过。

Eugene :自从他们开始讨论语言以来……在Android开发的背景下,“ Kotlin或Java”问题已经很累了,但仍然提出来以继续下一个问题。

Artyom :好的,Kotlin,当然。

尤金 :现在真正有趣的问题。 最近,在Kotlin,协程变得稳定起来,听到了“万岁,让我们远离RxJava”的声音。 因此,当我看到前面有一个非常接近RxJava的人时,我立即想问一下他对协程的看法。

Artyom :我对协程非常反感。 从原则上讲,它仍然基本上是负面的,但这部分地改变了与正在研究它们的罗马·伊丽莎罗夫的漫长对话。

作为程序的用户,我希望它们尽可能不受阻塞,以尽可能正确地使用资源。 我的意思是并行性和它们使用正确的操作系统API来无阻塞访问网络或文件的事实-操作系统中存在很多问题,但是,仍然有这样的API。 这到底能解决什么? 作为用户,对我来说没关系-如果只有开发人员才能以让他们感到舒适的方式解决此问题。 我对此没有大问题。 这就是罗马·伊里扎洛夫的愿景。 谈话之后,我莫名其妙地放手了。

在此之前,就像我的朋友Arthur Dremov一样 ,在生产中使用Java数年后,似乎又回到了我的一步:代码再次变得势在必行,不干净,失去了对管道的理解,再次变得一团糟,编译器为您变成了一个异步混乱。

我不使用协程,但是当您甚至看不到其中的哪一段代码是协程时,我现在观察的所有示例都已转换为结构化方法。 老实说,我很害怕看它。 因为我在GitHub上打开了pull请求,所以调用了一些方法来上传图片和配置文件,其中一种方法转到网络,另一种方法转到本地SQLite,在这里本地SQLite很容易被阻塞。 我在代码中看不到这一点,因为协程是经过精心设计的,因此您看不到它。 也许这很好,但是对我来说,这仍然是设计的缺点,因为在Rx方法中,这非常明显:您是否了解这是否是同步管道的一部分。

也许这是我对协程的唯一抱怨:我想看看何时发生异步,何时不发生。 理想情况下,当有少量可重用或至少可测试的片段与他人结合时,我希望人们编写更多的功能代码。 我们回到一个事实,将其全部内联到逻辑中,然后编译器将其翻转。

奥列格 :让我给你一点反对意见。 旧版代码不只是新的。 而且,如果我们采取诸如处理网络,处理文件等之类的事情,那么没人会迅速重写所有这些内容,例如使用RxJava。 而且,如果我们有自动协程,那么我们可以例如跟踪所有syscall,自动包装它们并将它们发送到锁中以进行停车。

Artyom :是的,无论如何,您都必须从corutin的上下文中调用函数。 但这是一个有趣的想法,是的。

奥列格(Oleg) :也许应该以某种方式将它们组合在一起? 顶级API将在RxJava上,而低级API在协程上。

Artyom :是的,现在有这样的转变。 但是随后出现了问题,因为目前,RxJava可以完成协程所做的一切,而协程不能完成RxJava所做的一切。 , — . , , , - Rx Kotlin. . forEach - map, . , , Java- , . .

, Kotlin — . , Go , , API, , : . , , , , legacy, , . , Java Kotlin — legacy, , . , . - , .

, , . , , , — . .



: , . , , : Android-? , .

: … . , Android- . , . , : , . RxJava , : - . , , .

, iOS. , Lyft iOS- dependency injection RxSwift. 2019-. iOS-, , , clean, . , Android — .

, , — Google. « opinionated, , : , , ». — , , .

, «RxJava — , ...» : «, LiveData». , — RxJava, , . , , Google , .

: «, Google MVVM». , MVVM , , , MVVM . , Google.

, , scope . .

: , Room . - Architecture Components — , . Google , ? .

: , . , . !

: .

下届莫比乌斯音乐节将于5月22日至23在圣彼得堡举行现在他的计划尚未公布,但这是购买机票最有利可图的时刻:2月1日,机票价格将上涨。而且,由于该程序尚未完成,因此现在也适合自己参与:我们正在全面接受报告的申请有关会议和门票的所有信息均在网站上

Source: https://habr.com/ru/post/zh-CN437948/


All Articles