今年早些時候我要組建立一個數(shù)據(jù)工程團(tuán)隊,因而必須選擇一種編程語言。Scala看上去像是一個不錯的選擇(我們打算經(jīng)常與Spark打交道),但是有幾點讓我不得不停下腳步。我閱讀了很多與這個主題相關(guān)的意見,但沒有太多的收獲。我看到的東西要么是有明顯的偏見,要么是5年之前的,要么兩者都是。我寫這篇文章是希望它能幫助到其他身處同樣位置的人,來明晰和評估Scala對于數(shù)據(jù)科學(xué)和工程團(tuán)隊的價值。
在這篇文章中我將會從數(shù)據(jù)和人兩方面來探討Scala生態(tài)系統(tǒng)中的幾個核心組件的現(xiàn)狀。我從GitHub上抓取了相應(yīng)的時間序列數(shù)據(jù)來幫助進(jìn)行分析,并試圖解決我可以遇見的一些常見問題。我也咨詢了幾個Scala社區(qū)的領(lǐng)導(dǎo)者的意見,包括Martin Odersky。他們都非常樂意花時間來分享他們的觀點。
我嘗試著公平地闡述和分析,但是我應(yīng)該發(fā)表一個免責(zé)聲明,那就是這篇概述是從我個人角度出發(fā)寫的。我并沒有給Scala以及其生態(tài)系統(tǒng)提供任何可引用的開源貢獻(xiàn)。我之前主要是用Haskell寫代碼。我已經(jīng)在DataScience公司(一家位于洛杉磯的提供數(shù)據(jù)科學(xué)平臺的公司)成功招募并培訓(xùn)了一支完全使用Scala編程的6人團(tuán)隊。
專有的Java和SMACK技術(shù)棧的興起
Scala十分依賴Java生態(tài)系統(tǒng)。過去一年中可能是最重要的一個與Java相關(guān)的事件就是Oracle針對Google的訴訟。Java生態(tài)系統(tǒng)和整個工業(yè)界一直期待許可證只是在創(chuàng)建一個兼容的API的實現(xiàn)時才被需要。盡管Google在公平使用原則上勝訴,但是由于聯(lián)邦巡回法庭在API版權(quán)上的判決,核心問題還是沒有解決。
Java更大的問題是Oracle的專有性所帶來的語言的束縛以及相關(guān)管理維護(hù)工作的缺乏。在過去的十年中,Java演進(jìn)的很緩慢。Java 6和Java 7之間花了長達(dá)五年的時間,以至于甚至出現(xiàn)了一份寫給Larry Ellison(譯者注:Oracle的CEO)的請愿書,希望可以“將Java EE作為全球IT工業(yè)界的核心部分推進(jìn)”。這些問題導(dǎo)致Java語言開始失去市場,在某些應(yīng)用領(lǐng)域的用戶開始轉(zhuǎn)向諸如Scala的開源語言。根據(jù)Indeed.com收集的數(shù)據(jù),從2012年至2016年,Scala職位發(fā)布的增長超過500%以上,而同期Java的職位需求量下降了33%。
這種趨勢的早期信號比較明顯地表現(xiàn)在分布式數(shù)據(jù)處理領(lǐng)域,主要是SMACK?(Spark, Mesos, Akka, Cassandra, Kafka)技術(shù)棧的崛起,而這些技術(shù)和工具都是由Scala編寫的。Scala是在正確的時間出現(xiàn)的正確的語言,用它編寫的Spark正在幫助Scala的推廣。在語法上來說,Spark與Scala的集合API幾乎是相同的,用起來就像是一個力量倍增器。
除了Scala之外,以數(shù)據(jù)為中心的應(yīng)用和組合的并發(fā)原語與日俱增的重要性驅(qū)動了對于函數(shù)式編程語言的廣泛興趣,諸如?Clojure、Erlang和Haskell。
流計算、微服務(wù)和Scala
在流式數(shù)據(jù)和微服務(wù)的廣泛應(yīng)用中,Scala的重要性是顯而易見的。Lightbend最近針對2151名全球基于JVM的開發(fā)人員的調(diào)查顯示,在生產(chǎn)系統(tǒng)中使用微服務(wù)的Scala開發(fā)人員比Java開發(fā)人員多了50%。在生產(chǎn)系統(tǒng)中使用微服務(wù)的所有開發(fā)人員中,35%使用了Akka Streams,30%使用Kafka,19%使用Spark Streaming。
我通過從對應(yīng)的GitHub倉庫抓取每日的時間序列數(shù)據(jù)比較了Akka、Kafka和Spark。我分別觀察了3個數(shù)據(jù):新關(guān)注總數(shù)、拉取請求數(shù)和提交數(shù)。在每種場景下,數(shù)據(jù)都是3年的跨度,從2013年9月30日至2016年9月30日。為了可讀性,時間序列進(jìn)行了以2周為單位的移動平均處理。本文是通過谷歌的BigQuery SQL接口在開源GitHub檔案庫中查詢的。文中涉及的所有查詢的源代碼都可以在這里找到。

圖一 Spark、Akka和Kafka的GitHub庫每天的新關(guān)注數(shù)的時間序列數(shù)據(jù)。為了可讀性,數(shù)據(jù)都進(jìn)行了以14天為單位的移動平均處理。圖片由DataScience.com授權(quán)使用

圖二 Spark、Akka和Kafka的GitHub庫每天新增的拉取請求數(shù)的時間序列數(shù)據(jù)。圖片由DataScience.com授權(quán)使用

圖三 Spark,、Akka和Kafka的GitHub庫每天新增的提交數(shù)的時間序列數(shù)據(jù)。圖片由DataScience.com授權(quán)使用
Spark和Kafka的發(fā)展
Spark毫無疑問在關(guān)注人數(shù)和PR(拉取請求)數(shù)上是最為活躍的。這一點也不意外,它仍然是數(shù)據(jù)社區(qū)中最活躍的開源項目。從2015到2016年,其代碼庫的貢獻(xiàn)人數(shù)增長了67%。Scala繼續(xù)是Spark相關(guān)開發(fā)的首選語言,緊隨其后的是Python。
Kafka在PR數(shù)上快要追上Akka了。另外值得一提的是,隨著Confluent接管了Kafka的維護(hù)工作,一些開發(fā)轉(zhuǎn)向了Java。Kafka專注于用流式數(shù)據(jù)處理作為批處理ETL系統(tǒng)的替代品。
此外,Kafak讓你可以建立一個分布式系統(tǒng),提供一次且僅有一次的提交保證。并且,你可以發(fā)送強(qiáng)類型的二進(jìn)制數(shù)據(jù)(例如Avro格式)。如果你使用Scala這樣的強(qiáng)類型語言,你可以保留類型系統(tǒng)給予的所有保障。這與處理JSON時你需要把所有東西都重新解析一遍形成鮮明對比。(消費和產(chǎn)生JSON數(shù)據(jù)是批處理ETL系統(tǒng)中現(xiàn)成工具的主要用途。)
似乎許多Kafka的新使用者是像DataScience這樣的創(chuàng)業(yè)公司。一般把它作為一個可擴(kuò)展的微服務(wù)的管道。Jay Kreps 在今年早些時的一篇博客中解釋說,Confluent的想法也與此差不多。
分析中其他一些有趣的點:
- 每天新增的PR數(shù)量和發(fā)布日期的剩余時間相關(guān)聯(lián)。
- 2016年1月Akka的提交數(shù)到達(dá)一個極高的值(總共有2008次提交)。這看上去像是一次大掃除:維護(hù)人員合并了許多Akka Streams和HTTP組件的提交到了一個主分支中。
這當(dāng)然不是一個面面俱到的比較。這三個庫都是多面手。特別是Spark,它是一個多功能的框架。除了流計算之外, Spark還包含了一個基于內(nèi)存的分布式計算引擎、DataFrame、圖計算和機(jī)器學(xué)習(xí)庫。
Dotty——一個新的工業(yè)標(biāo)準(zhǔn)?
Martin Odersky一直在領(lǐng)頭推進(jìn)Dotty的發(fā)展。Dotty是一個新的基于依賴對象類型(DOT)運算(基本上是個簡化版的Scala)和來自于函數(shù)式編程(FP)數(shù)據(jù)庫社區(qū)的想法開發(fā)的研究用編譯器。
Dotty開發(fā)的團(tuán)隊協(xié)作顯示了基于目前技術(shù)的可觀的改進(jìn),特別是在編譯時間方面。我問Odersky關(guān)于Dotty架構(gòu)的創(chuàng)新點和可以幫助終端用戶的地方,他是這么回答的:
我想到的有兩點:首先,這跟之前的基礎(chǔ)非常相關(guān),使我們在如何設(shè)計一個健全的類型系統(tǒng)方面有更好的指導(dǎo)方向。這也使得用戶遇到更少的意外和困難。其次,它有一個本質(zhì)上是函數(shù)式的架構(gòu)。這使得它可以更容易地被擴(kuò)展、更容易地正確完成,使得該編譯器被當(dāng)作一個服務(wù)提供給IDE和元編程時,其API更加健壯。
盡管Dotty帶來了出現(xiàn)一些有趣的編程語言的可能性(尤其是完全依賴類型,諸如Agda和Idris),Odersky已經(jīng)選擇優(yōu)先考慮使這些語言立即對社區(qū)做出貢獻(xiàn)。這些語言之間的差別是很小的,大部分是為了簡化語言(比如移除過程語法)或是修復(fù)問題(不健全的模式匹配),或兩者都有(早期的發(fā)起者)。
有趣的是,Odersky其實有長時間構(gòu)建編譯器的經(jīng)驗。在博士畢業(yè)之前,他出售了一個Pascal編譯器給Borland公司。他師從Niklaus Wirth(Pascal語言的創(chuàng)立者)完成了博士學(xué)業(yè),隨后在IBM進(jìn)行一些博士后的工作(E語言,后來被商用),并發(fā)現(xiàn)了一些函數(shù)式編程的缺陷。隨后他繼續(xù)編寫Pizza(和以Haskell和Java泛型聞名的Philip Wadler一起合作)和Funnel語言,不過沒有人用這些,但是他和Wadler的工作產(chǎn)生了GJ編譯器,當(dāng)然也帶來了Java泛型。他也編寫過多個Scala編譯器(Dotty是第五或者第六個)。我有可能有地方?jīng)]提到,但是我想說的是他是十分值得信賴的。
當(dāng)然,我還是想問他全依賴類型是否有可能在某一時候在Scala中終結(jié),他是這么回答的:
永遠(yuǎn)不要否定可能性 :-)。事實上,我們正在和Viktor Kuncak一起將Leon程序與Scala整合起來,這需要比現(xiàn)在更加豐富的依賴類型。但是目前這僅僅是研究,其結(jié)果是完全不定的。
Scala和Dotty團(tuán)隊正在非常緊密地合作,來把Scala2.x和Dotty整合。并且表示他們非常注重其連續(xù)性。Scala 2.12 和 2.13有個語言標(biāo)記可以解鎖藏在Dotty中的特性(例如,存在性類型),并且Dotty編譯器有一個Scala 2的兼容模式。甚至還有一個遷移工具的存在。

圖四 每個編譯器的GitHub庫每日的新關(guān)注數(shù)的時間序列數(shù)據(jù)。圖片由DataScience.com授權(quán)使用

圖五 每個編譯器的GitHub庫每日的新PR數(shù)的時間序列數(shù)據(jù)。圖片由DataScience.com授權(quán)使用

圖六 每個編譯器的GitHub庫每日的提交數(shù)的時間序列數(shù)據(jù)。圖片由DataScience.com授權(quán)使用
我比較了這兩個編輯器(和Typelevel一起),分析了它們對應(yīng)的GitHub庫的時間序列數(shù)據(jù)??偟膩碚f,新的關(guān)注(很可能是來自于Dotty公告和黑客資訊)可能是這些數(shù)據(jù)中最有意思的。
Lightbend是由Odersky、前撲克冠軍以及軟件工程師Paul Phillips和Akka創(chuàng)始人Jonas Bonér創(chuàng)立的一家支持Scala和PLAY響應(yīng)式JVM框架的公司。該公司一開始叫做“Typesafe”,以此來表明它函數(shù)式編程的根源所在,在2016年2月才改名為“Lightbend”。我和Lightbend的CEO ?Mark Brewer聊了聊他們在Scala上的工作,他是這么說的:
Scala 2.12已經(jīng)是Lightbend以及許多其他貢獻(xiàn)者的一項重要的投資。它的后端利用Java 8的特性被完全重寫(以至于在編譯到Java字節(jié)碼時不需要從Scala翻譯到Java)。此外2.12引入了一個新的優(yōu)化器,進(jìn)行更加深層的靜態(tài)分析從而消除函數(shù)式編程中常見的高階代碼的開銷?,F(xiàn)在2.12版本(希望)是一個最終的發(fā)布候選,整個團(tuán)隊已開始在做2.13了。2.13的特性正在定義中,但是它會包含一個新的集合類(是由社區(qū)要求的)以及其他從Dotty來的特性。
特別是Lightbend在Scala 2.12版本的工作,一定程度展示了他們響應(yīng)了函數(shù)式編程社區(qū)的需求和建議。
最后,有趣的是,隨著Dotty正在逐漸能夠編譯大部分主要Scala生態(tài)系統(tǒng)中的東西,開發(fā)周期時間的顯著減少是可期的,這讓不少公司表示有興趣盡快地遷移過去。我們很期待當(dāng)Dotty與Scala碰撞在一起會發(fā)生什么。
行為準(zhǔn)則的戰(zhàn)爭
Scala是一種多范式的語言,它的社區(qū)當(dāng)然也反映出了這一點。Martin Odersky原本對Scala的目標(biāo)是證明函數(shù)式代碼可以按照面向?qū)ο蟮臏?zhǔn)則來組織。這一設(shè)計理論使得除了一些上面提到的項目中產(chǎn)生的Java變體語言之外的,從純函數(shù)式編程語言變化而來的語言(例如Haskell)被廣泛采用。
社區(qū)分裂:Cats和Scalaz
從歷史上來看,Scala函數(shù)式編程社區(qū)的代表是Scalaz,其目前仍然是GitHub上評分最高的Scala庫之一。有且總是有相當(dāng)一部分Haskell的開發(fā)人員投身在Scalaz上。從一開始,這個社區(qū)就全力倡導(dǎo)將Haskell這樣的函數(shù)式編程模板、語法引入到Scala中。
2014年底,在新的行為準(zhǔn)則(CoC)引入失敗后,社區(qū)開始分崩離析,正如Edward Kmett在這篇推文里所說。
事實上,Typelevel的人離開后創(chuàng)建了一個新的函數(shù)式編程庫(Cats)。盡管它并不是一個Scalaz的直接分支,但是依然使用了很多相同的概念,因此。

圖七 Cats和Scalaz的GitHub庫的每日新關(guān)注數(shù)的時間序列數(shù)據(jù)。圖片由DataScience.com授權(quán)使用

圖八 Cats和Scalaz的GitHub庫的每日新PR數(shù)的時間序列數(shù)據(jù)。圖片由DataScience.com授權(quán)使用

圖九 Cats和Scalaz的GitHub庫的每日新提交數(shù)的時間序列數(shù)據(jù)。圖片由DataScience.com授權(quán)使用
從PR的活動指標(biāo)的整體幅度來看,Cats比Scalaz要大。盡管部分原因可能是因為它的庫的建立時間較晚。然而,從每天的提交數(shù)和新關(guān)注數(shù)來看,隨著時間的變化,Scalaz并沒有表現(xiàn)出明顯的下降。所以說,社區(qū)中的一些人的恐懼已經(jīng)淡化了。事實上,Scalaz和Cats的并存已經(jīng)給下游的庫帶來了很多頭疼的問題,盡管大部分似乎都有可行的解決方案。比如可以通過包含所有的必須的函數(shù)式編程依賴(像FS2和scodec所作的那樣),或是通過使用shimes工具,或是進(jìn)行源代碼預(yù)處理。
另一方面,可能Tony Morris,Scalaz項目在動機(jī)上和Cats是截然不同的,最終兩者都會有空間來演化并服務(wù)于Scala社區(qū)的不同需求。Cats一直努力保持輕量級和模塊化(參見這里和這里),同時避開了Scalaz中相對復(fù)雜的語法。
言論自由碰上非暴力傳播
Scalaz行為準(zhǔn)則(CoC)引入失敗的幾個可能的原因包括:第一個是因為其引入而被禁止的人正好是項目的創(chuàng)始人。然而,更主要的原因可能是CoC是在一個七年之久的社區(qū)內(nèi)被提出的,而不是在剛開始階段就被引入的一個社區(qū)。以這種方式改變?nèi)后w話語的模式,可以說等于要求參與者加入一個完全獨立的運動。從而出現(xiàn)兩個最有可能的結(jié)果,或者對CoC的直接拒絕,或者CoC直接被忽視(這是在Scala內(nèi)部發(fā)生的事情)。并且持續(xù)的消極情緒拖累論壇活動,導(dǎo)致其趨于停滯。
Scalaz的鬧劇暴露出來的主要鴻溝是在開源軟件開發(fā)上的行為準(zhǔn)則的哲學(xué)分歧(同樣的問題最近在Scala辯論論壇上也發(fā)生了)。一方覺得想法都是差不多的,這些想法如何溝通不怎么重要(這個辯論發(fā)生在今年的LambdaConf會議上)。他們覺得只是簡單的因為傳遞方式是粗魯和無禮的就無視批評是不可接受的。
另一方覺得暴力溝通拖累了整個社區(qū),因此可接受的溝通是要被CoC所限制的。從個人的經(jīng)驗來說,我與Typelevel的人的交互是相當(dāng)積極的,我們團(tuán)隊中的每個人都是這樣。Typelevel對于新加入的人的耐心對于我們使用它們的項目是十分有幫助的,特別是Cats。
你應(yīng)該用Scala嗎?回應(yīng)一些恐懼、不確定和懷疑
像任何主流語言一樣,Scala已經(jīng)吸引了相當(dāng)數(shù)量的權(quán)威的支持,但同時也伴隨著“Scala太棒了”和“Scala正在死亡”(像這一條,顯然是一個Java開發(fā)者寫的)的話語。如果你正在考慮學(xué)習(xí)Scala或者是雇用一個Scala團(tuán)隊,你應(yīng)該兩方面都要考慮并且有自己判斷。同時也要了解一些已經(jīng)被揭秘的明顯的恐懼、不確定和質(zhì)疑。我想要來討論幾個最常見的顧慮(這里是一個不錯的關(guān)于其他幾個顧慮的討論)。
1. 關(guān)于Typesafe的更名和Scala的維護(hù)管理的擔(dān)憂
大家可能不知道,今年2月份,Scala的母公司Typesafe更名為Lightbend。這個擔(dān)憂對我來說有點過于夸大了。Lightbend的CEO Mark Brewer在一篇博客中講的很清楚,Lightbend將繼續(xù)致力于這一語言和Scala相關(guān)社區(qū)的貢獻(xiàn)。當(dāng)我跟Brewer提到這一長期存在的擔(dān)憂時,他回復(fù)到:
我們很幸運能有這樣一個非常吸引人(也是很喧囂)的Scala社區(qū),這意味著對于Lightbend在做什么的會得到非常多的反饋。盡管沒有抱怨,但是我們寧愿有抱怨而是沒有關(guān)注。
2. 關(guān)于開發(fā)人員上手難易的擔(dān)憂
這一擔(dān)憂是成立的。Scala跟其他語言相比有著陡峭的學(xué)習(xí)曲線。且缺乏集中式的入門材料和社區(qū)論壇(像Rust有的那樣)一直是一個問題。今天3月,EPFL宣布為Scala成立一個開源基礎(chǔ)社區(qū),叫做Scala Center(由Lightbend、IBM、Verizon等公司支持)。
3. 需要更好的文檔
希望Scala Center的引入也可以帶來更多在文檔上的改進(jìn)。我跟Heather Millar——Scala Center的執(zhí)行董事談到文檔時,她是這么說的:
我一直覺得文檔是一個問題,公司應(yīng)該招聘一個技術(shù)寫作人員來解決這個問題。作為一個親自編寫了大部分基礎(chǔ)Scala文檔的人,我過去五年對此都十分有激情,現(xiàn)在這不應(yīng)該再是一個志愿任務(wù)了。然而由于Scala Center的管理運作模式,我個人不能決定Scala Center是否需要出資招聘一個專業(yè)的寫手來改進(jìn)文檔。在我可以進(jìn)行招聘之前,需要在最近的顧問委員會會議上提出來討論,并由大家投票決定。
Scala Center有3.5個全職員工。作為EPFL的一部分,他們是有非常嚴(yán)格的招聘限制的(員工必須是聯(lián)邦大學(xué)的一部分,薪資是不具有競爭力的等)。該中心每周從非官方途徑聽取來自個人、公司、顧問委員會成員的意見。這些建議被提煉成提案,每3個月在顧問委員會會議上提交。然后顧問委員會對這些提案進(jìn)行投票,考慮所有涉及的利益相關(guān)者的最迫切的需求。Scala Center會盡全力讓他們的人來實現(xiàn)這些提案。
4. 對于Scala社區(qū)流程的擔(dān)憂
這一擔(dān)憂某些程度上來看是成立的。除了(與之有關(guān))Scalaz的小插曲,已經(jīng)有更多的人抱怨隨意瀏覽的行為以及隨之而來的論壇的參與度的下降。Miller說很多人聯(lián)系她說(大部分是女性):她們覺得,
不僅是害怕,而且感到丟臉?;蛘咚齻兛吹饺藗兓ハ嘀肛?zé),這使得她們甚至不想?yún)⑴c。她們覺得這是一個充滿敵意的環(huán)境,遠(yuǎn)甚于其他她們參與的社區(qū)。
目前,Scala Center主要關(guān)注于像緩解Scala/Dotty遷移的復(fù)雜度以及改進(jìn)高層監(jiān)管這樣的項目(他們最近重啟了Scala的改進(jìn)流程)。他們正在準(zhǔn)備一個關(guān)于新的Scala平臺流程和一個關(guān)聯(lián)類庫的重構(gòu)的重要聲明。
5. 對于招聘Scala開發(fā)人員的擔(dān)憂
這一擔(dān)憂是很有道理的。如果你預(yù)期需要建立和培養(yǎng)一個非常大的團(tuán)隊或是快速培養(yǎng)一個團(tuán)隊,Scala可能對你來說并不合適的。相對于其他主流函數(shù)式語言開發(fā)人員來說,Scala開發(fā)人員的需求量也比較大。
專家技術(shù)人員某種程度上來說是分布良好的,有很多人在主要的技術(shù)中心地區(qū)工作,小部分人分散在全美各地。然而,出了灣區(qū)、洛杉磯、紐約和西雅圖地區(qū),你可能要去適應(yīng)進(jìn)行遠(yuǎn)程合作。有經(jīng)驗的Scala開發(fā)人員也充分意識到了自己的價值。盡管招聘一些有經(jīng)驗的Scala開發(fā)人員是可能的,但是想在你團(tuán)隊里填滿成熟的Scala人才可能不是簡單和高性價比的。相比于通過標(biāo)準(zhǔn)的Java招聘策略來招聘成熟的Java人才來建立一個開發(fā)團(tuán)隊,Scala的情況是不一樣的。

圖十 2016年8月美國Scala職位分布。圖片由DataScience.com授權(quán)使用
一個語言的成長
Scala社區(qū)已是前所未有的高生產(chǎn)效率。我們也看到工業(yè)界往函數(shù)式編程的轉(zhuǎn)向,這豐富了現(xiàn)在技術(shù)棧的內(nèi)容,可能是一個好事情。Scala發(fā)現(xiàn)了分布式數(shù)據(jù)處理上的一個明確的缺口,并且正在推動技術(shù)主流去使用函數(shù)式技術(shù)。從這方面來看,Scala從一個有激情的函數(shù)式編程社區(qū)中獲益良多。
我不認(rèn)為大部分的Scala社區(qū)希望看到Scala完全商業(yè)化。然而,在大部分與我交談的人中,有一個共識,就是像Java一樣的趨勢發(fā)展是不健康的。Java達(dá)成了完全的統(tǒng)治地位,而后十年幾乎停滯不前,這對編程界來說不是一個好事。所以,(Scala社區(qū)將)繼續(xù)實驗和力爭健康成長。抵制早期的標(biāo)準(zhǔn)化,并簡化擴(kuò)展而不是堆砌語言。隨著對Scala理解的深入,去弄清楚和不斷修正它,并且向一個更接近可變和不可達(dá)之間的最佳效果不斷迭代前進(jìn)。
感謝Janie Chen?和?Dave Goodsmith?在我撰寫本文時對我的幫助。
Chris McKinlay
Chris McKinlay 是DataScience公司的工程師總監(jiān)。Chris于2013年在加州大學(xué)洛杉磯分校獲得數(shù)學(xué)博士學(xué)位,以攻破OkCupid網(wǎng)站而著名。Chris很高興能跟他的第88個約會對象結(jié)婚,并且住在洛杉磯??梢酝ㄟ^推特@cem3394 聯(lián)系他。


更多內(nèi)容可以參考Strata北京2017的相關(guān)議題。