DoorDash 的後端服務如何從Python遷移到Kotlin?

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"美國外賣平臺DoorDash原先的代碼庫是基於Django的單體應用。之前這個平臺對業務的支持能力已逼近天花板。爲給送餐服務提供更堅實的基礎,DoorDash需要全新設計的技術棧。新平臺應能很好地支撐企業的未來增長,並支持團隊在構建中持續推陳出新,用上更好的模式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原系統的每次發佈都需更新大量的節點,這顯著增加了所需的發佈時間。並且每次部署中都有大量的提交,一旦部署存在問題,難以通過對分定位("},{"type":"link","attrs":{"href":"https:\/\/en.wikipedia.org\/wiki\/Bisection_(software_engineering)","title":"","type":null},"content":[{"type":"text","text":"Bisecting"}]},{"type":"text","text":")發現具體導致問題的某次或某些提交,問題定位耗時也更長。此外,原單體應用是基於"},{"type":"link","attrs":{"href":"https:\/\/www.python.org\/download\/releases\/2.0\/","title":"","type":null},"content":[{"type":"text","text":"Python 2"}]},{"type":"text","text":"和"},{"type":"link","attrs":{"href":"https:\/\/www.djangoproject.com\/","title":"","type":null},"content":[{"type":"text","text":"Django"}]},{"type":"text","text":"構建的,而舊版本Python正迅速進入壽命終止期(EOL,End of Life),難以繼續獲得可靠的支持。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲實現具有更好可擴展性的系統,DoorDash工程團隊需要去"},{"type":"link","attrs":{"href":"https:\/\/doordash.engineering\/2020\/12\/02\/how-doordash-transitioned-from-a-monolith-to-microservices\/","title":"","type":null},"content":[{"type":"text","text":"分解單體應用"}]},{"type":"text","text":",確定新服務的界面和交互行爲。接下來的首要問題是如何確定支持團隊工作的技術棧。通過對多種語言的調研,團隊選定了具有豐富的生態系統、與Java良好互操作性和對開發人員友好的"},{"type":"link","attrs":{"href":"https:\/\/kotlinlang.org\/","title":"","type":null},"content":[{"type":"text","text":"Kotlin"}]},{"type":"text","text":"。針對Kotlin逐漸暴露出來的痛點問題,團隊做出了一些改進。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"確定適用的技術棧"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當前存在多種可用的服務器端軟件構建方案。但是出於以下方面考慮因素,團隊考慮只使用單一語言。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有助於團隊聚力,推動最佳開發實踐在整個工程組織內的共享。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"支持針對企業場景構建優化的通用軟件庫,很好地適應企業規模和持續增長。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"極大降低工程人員在團隊間轉崗的摩擦,推動相互合作。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"綜合上述因素,對於團隊而言,問題並非是否應該使用單一的開發語言,而是應該選定哪一種語言。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"選擇適合的編程語言"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"選擇編程語言時,團隊要從企業的需求着手,考慮因素包括未來服務的體驗以及交互方式等。團隊很快取得一致,決定對服務間的相互同步通信機制使用"},{"type":"link","attrs":{"href":"https:\/\/grpc.io\/","title":"","type":null},"content":[{"type":"text","text":"gRPC"}]},{"type":"text","text":"、消息隊列使用"},{"type":"link","attrs":{"href":"https:\/\/kafka.apache.org\/","title":"","type":null},"content":[{"type":"text","text":"Apache Kafka"}]},{"type":"text","text":"。數據存儲將繼續使用"},{"type":"link","attrs":{"href":"https:\/\/www.postgresql.org\/","title":"","type":null},"content":[{"type":"text","text":"Postgres"}]},{"type":"text","text":"和"},{"type":"link","attrs":{"href":"https:\/\/cassandra.apache.org\/","title":"","type":null},"content":[{"type":"text","text":"Apache Cassandra"}]},{"type":"text","text":",因爲團隊成員對此經驗豐富、技能熟練,並且二者的技術成熟度也非常高,廣泛支持所有的現代編程語言。下面還需要考慮其它一些因素。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"無論選定何種技術,都需要滿足:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"高效利用CPU,可擴展到多核。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"易於監控"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"具有強大的軟件庫生態支持,使團隊可聚焦於業務問題本身。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"確保提供良好的開發人員生產率"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可靠的擴展性"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"面向未來,爲企業業務增長提供良好支撐。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"團隊基於上述需求考慮了各種語言,棄用了"},{"type":"link","attrs":{"href":"https:\/\/en.wikipedia.org\/wiki\/C%2B%2B","title":"","type":null},"content":[{"type":"text","text":"C++"}]},{"type":"text","text":"、"},{"type":"link","attrs":{"href":"https:\/\/www.ruby-lang.org\/en\/","title":"","type":null},"content":[{"type":"text","text":"Ruby"}]},{"type":"text","text":"、"},{"type":"link","attrs":{"href":"https:\/\/www.php.net\/","title":"","type":null},"content":[{"type":"text","text":"PHP"}]},{"type":"text","text":"和"},{"type":"link","attrs":{"href":"https:\/\/www.scala-lang.org\/","title":"","type":null},"content":[{"type":"text","text":"Scala"}]},{"type":"text","text":"等主流語言。儘管這些語言頗受歡迎,但它們難以支撐每秒查詢數(QPS)和用戶數的增長,不能滿足團隊對未來技術棧的一項或數項核心需求。基於上述需求,選擇範圍鎖定在"},{"type":"link","attrs":{"href":"https:\/\/kotlinlang.org\/","title":"","type":null},"content":[{"type":"text","text":"Kotlin"}]},{"type":"text","text":"、"},{"type":"link","attrs":{"href":"https:\/\/www.java.com\/en\/","title":"","type":null},"content":[{"type":"text","text":"Java"}]},{"type":"text","text":"、"},{"type":"link","attrs":{"href":"https:\/\/golang.org\/","title":"","type":null},"content":[{"type":"text","text":"Go"}]},{"type":"text","text":"、"},{"type":"link","attrs":{"href":"https:\/\/www.rust-lang.org\/","title":"","type":null},"content":[{"type":"text","text":"Rust"}]},{"type":"text","text":"和"},{"type":"link","attrs":{"href":"https:\/\/www.python.org\/","title":"","type":null},"content":[{"type":"text","text":"Python 3"}]},{"type":"text","text":"。爲比較和對比各語言相互之間的優劣之處,團隊形成了如下對比表。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Kotlin"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"優點:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"軟件庫生態系統強大"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對gRPC、HTTP、Kafka、Cassandr和SQL提供一等支持"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"繼承Java的生態系統,速度快,可擴展。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原生支持併發原語,避免了Java的繁瑣,去除了對複雜的"},{"type":"link","attrs":{"href":"https:\/\/howtodoinjava.com\/design-patterns\/creational\/builder-pattern-in-java\/","title":"","type":null},"content":[{"type":"text","text":"Builder"}]},{"type":"text","text":"\/"},{"type":"link","attrs":{"href":"https:\/\/www.tutorialspoint.com\/design_pattern\/factory_pattern.htm","title":"","type":null},"content":[{"type":"text","text":"Factory"}]},{"type":"text","text":"模式的依賴。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Java Agent提供強大的組件內省(introspection),僅需少量編碼,即可自動定義並導出度量和追蹤,以實現監控。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不足:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通常很少用於服務器端,開發人員缺少可供參考的示例代碼。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相比Go而言,併發實現相對繁瑣。Go在語言基礎層和標準軟件庫中集成了goroutine(譯者注:原文是“gothreads”)這一核心理念。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Java"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"優點:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"具有強大的軟件庫生態系統"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對gRPC、HTTP、Kafka、Cassandr和SQL提供一等支持"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"速度快、可擴展"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Java Agent提供強大的組件內省(introspection),僅需少量編碼,即可自動定義並導出度量和追蹤,以實現監控。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不足:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相對Kotlin和Go而言,"},{"type":"link","attrs":{"href":"https:\/\/en.wikipedia.org\/wiki\/Concurrency_(computer_science)","title":"","type":null},"content":[{"type":"text","text":"併發"}]},{"type":"text","text":"實現相對繁瑣。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"編碼存在極端冗長問題,難以編寫整潔的代碼。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Go"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"優點:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"具有強大的軟件庫生態系統"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對gRPC、HTTP、Kafka、Cassandr和SQL提供一等支持"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"速度快、可擴展"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原生支持併發原語,簡化了併發代碼的編寫。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"具有大量可用的服務器端例子程序和文檔。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不足:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於不熟悉Go語言的開發人員,配置數據模型並非易事。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"儘管Go最終會支持泛型(generics),但當前尚不支持。這意味着"},{"type":"link","attrs":{"href":"https:\/\/www.freecodecamp.org\/news\/generics-in-golang\/","title":"","type":null},"content":[{"type":"text","text":"一些軟件庫中的類相對難以在Go中構建"}]},{"type":"text","text":"。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Rust"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"優點:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"運行速度非常快"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"沒有垃圾回收機制,依然內存和併發安全。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一些大型企業開始採用該語言,因此具有大量投資及很好的發展。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相比其它語言,其提供強大的類型系統,更易於表達複雜理念和模式。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不足:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"語言較新,這意味着例子代碼、軟件庫以及具有模式構建和調試經驗的開發人員相對不足。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相比其它語言,生態系統不算強大。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當前async\/await尚未實現標準化。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要掌握內存模型,需要一定的學習時間。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Python 3"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"優點:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"提供強大的軟件庫生態系統"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"易用"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"團隊已經具有豐富的經驗"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"易於招聘開發人員"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對GRPC、HTTP、Cassandra和SQL提供一等支持"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"提供REPL,便於App運行時的測試和調試。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不足:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相比其它語言,運行速度較慢。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"解釋器全局鎖(GIL)難以完全高效利用團隊的多核機器。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"缺少強大的類型檢查特性。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當前對Kafka支持不夠,特性發布存在延遲。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"根據以上對比,團隊決定開發一個經過測試和擴展的Kotlin組件的“黃金標準”。kotlin本質上是一種更適合團隊的Java版本,但緩解了Java存在的痛點問題。由此團隊選擇了Kotlin,但必須要去解決進一步發展中經歷的一些問題。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"相對Java,Kotlin的優點"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相對Java,Kotlin的一個最大優點是“空值安全”("},{"type":"link","attrs":{"href":"https:\/\/kotlinlang.org\/docs\/null-safety.html","title":"","type":null},"content":[{"type":"text","text":"null safety"}]},{"type":"text","text":")。Kotlin中,開發人員必須明確定義可爲空值的對象,並強制開發人員採用安全方式處理,避免了必須處理大量潛在的運行時異常的痛點。也可使用"},{"type":"link","attrs":{"href":"https:\/\/kotlinlang.org\/docs\/null-safety.html#safe-calls","title":"","type":null},"content":[{"type":"text","text":"空值合併(null-coalescing)操作符"}]},{"type":"text","text":"“?.”,用單行代碼實現對可爲空值子域的安全訪問。例如,Java實現爲:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"int subLength = 0;\nif (obj != null) {\n if (obj.subObj != null) {\n subLenth = obj.subObj.length();\n }\n }"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用Kotlin實現爲:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"val subLength = obj?.subObj?.length() ?: 0"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"儘管上面給出的例子非常簡單,但已經足夠體現出空值合併操作符的強大之處,即大大降低了代碼中條件語句的數量,提高了代碼的可讀性。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相比其它語言,在實現服務度量的儀表盤監控中,使用Kotlin更易於遷移到"},{"type":"link","attrs":{"href":"https:\/\/prometheus.io\/","title":"","type":null},"content":[{"type":"text","text":"Prometheus"}]},{"type":"text","text":"事件監測系統。團隊開發了一個註解處理器(Annotation Processor),自動按度量生成相應的函數,確保正確數量的標註按正確的順序給出。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面例子給出了Prometheus軟件庫的標準集成代碼:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"\/\/ to declare\nval SuccessfulRequests = Counter.build( \n \"successful_requests\",\n \"successful proxying of requests\",\n)\n.labelNames(\"handler\", \"method\", \"regex\", \"downstream\")\n.register()\n\n\/\/ to use\nSuccessfulRequests.label(\"handlerName\", \"GET\", \".*\", \"www.google.com\").inc()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"修改爲如下代碼,API更不易出錯:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"\/\/ to declare\n@PromMetric(\n PromMetricType.Counter, \n \"successful_requests\", \n \"successful proxying of requests\", \n [\"handler\", \"method\", \"regex\", \"downstream\"])\nobject SuccessfulRequests\n\n\/\/ to use\nSuccessfulRequests(\"handlerName\", \"GET\", \".*\", \"www.google.com\").inc()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"採用如上的集成方式,不必再去記住某個度量所具有標註的數量和順序,而是由編譯器和所使用的IDE去確保標註的正確數量和名稱。DoorDash使用了分佈式追蹤,監控的集成可簡化爲類似於"},{"type":"link","attrs":{"href":"https:\/\/github.com\/open-telemetry\/opentelemetry-java-instrumentation#getting-started","title":"","type":null},"content":[{"type":"text","text":"在運行時添加Java Agent"}]},{"type":"text","text":"。。對於一個新服務,不需要代碼屬主團隊去修改代碼,可觀測性和架構團隊就能快速地推出對應的分佈式追蹤。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在團隊看來,Kotlin的另一個非常強大之處是協程("},{"type":"link","attrs":{"href":"https:\/\/kotlinlang.org\/docs\/coroutines-overview.html","title":"","type":null},"content":[{"type":"text","text":"Coroutines"}]},{"type":"text","text":")。協程模式讓開發人員無需糾結於回調這個天坑,能使用近乎命令式編程的方式去編寫代碼,這正是大部分開發人員更爲駕輕就熟的方式。協程也非常易於組合,必要時可並行運行。下面例子給出了團隊使用的某個Kafka消費者:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"val awaiting = msgs.partitions().map { topicPartition ->\n async {\n val records = msgs.records(topicPartition)\n val processor = processors[topicPartition.topic()]\n if (processor == null) {\n logger.withValues(\n Pair(\"topic\", topicPartition.topic()),\n ).error(\"No processor configured for topic for which we have received messages\")\n } else {\n try {\n processRecords(records, processor)\n } catch (e: Exception) {\n logger.withValues(\n Pair(\"topic\", topicPartition.topic()),\n Pair(\"partition\", topicPartition.partition()),\n ).error(\"Failed to process and commit a batch of records\")\n }\n }\n }\n}\nawaiting.awaitAll()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Kotlin協程支持在編碼中按分區快速地切分消息,並對每個分區啓動一個處理消息的協程,不破壞消息插入隊列時的順序。此後,在檢查偏移並返回Broker前,連接所有的Future。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Kotlin支持團隊以更可靠和可擴展的方式快速推進。從上面的例子中可見一斑。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"解決推廣Kotlin中遇到的問題"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲更好地利用Kotlin的全部特性,團隊必須要解決以下問題:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如何培訓團隊更高效地使用Kotlin"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"建立使用協程的最佳實踐"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"解決與Java互操作上的痛點"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"進一步簡化依賴管理"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面展開介紹團隊時如何解決上述問題的"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"培訓團隊使用Kotlin"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"採用Kotlin的一個最大問題,就是如何確保提升團隊的開發速度。團隊中大多數人具備優秀的Python開發背景,後端團隊具有一些Java和Ruby經驗。考慮到在後端開發中很少使用Kotlin,因此團隊必須要建立指導後端開發人員使用Kotlin的良好指南。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"儘管在線上可以找到大量的學習教程,但是大多數"},{"type":"link","attrs":{"href":"https:\/\/kotlinlang.org\/docs\/learning-materials-overview.html","title":"","type":null},"content":[{"type":"text","text":"Kotlin線上社區"}]},{"type":"text","text":"主要專注於安卓開發。團隊的高級開發人員編寫了“如何使用Kotlin編程”,其中給出了編程建議和代碼片段。我們團隊發佈了“碎片化學習教程”(Lunch and Learns session),告訴開發人員如何避免一些常見的坑,如何有效地使用IntelliJ IDE開展工作。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"團隊更多地傳授開發人員Kotlin的函數式編程方面內容,包括如何使用模式匹配、不可變性默認優先等理念。團隊建立了人人可加入、提問並獲得建議的線上交流小組(Slack Channel),形成了一個Kotlin工程互助指導社區。通過以上工作,團隊構建一個強大的、熟練掌握Kotlin的工程人員團隊,並在團隊進一步擴展時能傳承知識,形成可持續發展和改進的內循環。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"避免掉進協程中的坑"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"團隊在選擇Kotlin時,尚缺少對協程的支持(譯者注:"},{"type":"link","attrs":{"href":"https:\/\/blog.jetbrains.com\/kotlin\/2018\/10\/kotlin-1-3\/","title":"","type":null},"content":[{"type":"text","text":"2018年10月,Kotlin 1.3推出了coroutines穩定特性"}]},{"type":"text","text":")。因此團隊選定gRPC作爲服務間通信方法,爲充分利用Kotlin需做一定改進。當時gRPC-Java是Kotlin gRPC服務的唯一選擇,因爲Java中並不存在協程,因此gRPC-Java也缺少對協程的支持。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"兩個開源項目"},{"type":"link","attrs":{"href":"https:\/\/github.com\/marcoferrer\/kroto-plus","title":"","type":null},"content":[{"type":"text","text":"Kroto-plus"}]},{"type":"text","text":"和"},{"type":"link","attrs":{"href":"https:\/\/github.com\/daviddenton\/protokruft","title":"","type":null},"content":[{"type":"text","text":"Protokruft"}]},{"type":"text","text":"可以解決這個問題,團隊最終分別使用了這兩個解決方案的各一部分去設計服務,創建更具原生感的解決方案。最近"},{"type":"link","attrs":{"href":"https:\/\/github.com\/grpc\/grpc-kotlin","title":"","type":null},"content":[{"type":"text","text":"gRPC-Kotlin"}]},{"type":"text","text":"發佈了"},{"type":"link","attrs":{"href":"https:\/\/developers.googleblog.com\/2020\/12\/announcing-grpc-kotlin-10-for-android.html","title":"","type":null},"content":[{"type":"text","text":"一般可用(GA)版"}]},{"type":"text","text":"。爲提供更好的Kotlin構建系統體驗,團隊我們正在遷移服務以使用官方綁定版本。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於已轉向Kotlin的安卓開發人員,對協程中存在的其它坑應該並不陌生。例如,不要在請求中重用"},{"type":"link","attrs":{"href":"https:\/\/kotlinlang.org\/api\/latest\/jvm\/stdlib\/kotlin.coroutines\/-coroutine-context\/","title":"","type":null},"content":[{"type":"text","text":"CoroutineContexts"}]},{"type":"text","text":",因爲一旦取消或出現異常,CoroutineContext就會轉入“cancelled”狀態,這意味着任何進一步嘗試在此Context中加載協程將會產生失敗。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"正因爲此,需對服務器處理的每個請求新建一個CoroutineContext,不能再依賴於"},{"type":"link","attrs":{"href":"https:\/\/www.baeldung.com\/java-threadlocal","title":"","type":null},"content":[{"type":"text","text":"ThreadLocal變量"}]},{"type":"text","text":",因爲協程可在Context中換入換出,導致數據不正確或被覆蓋。另一個需要警惕的坑是避免使用未綁定的"},{"type":"link","attrs":{"href":"https:\/\/stackoverflow.com\/questions\/54335365\/why-not-use-globalscope-launch","title":"","type":null},"content":[{"type":"text","text":"GlobalScope"}]},{"type":"text","text":"加載協程,會導致資源上的問題。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"解決虛引用Java NIO問題"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"支持現代"},{"type":"link","attrs":{"href":"https:\/\/en.wikipedia.org\/wiki\/Non-blocking_I\/O_(Java)","title":"","type":null},"content":[{"type":"text","text":"Java非阻塞IO(NIO)"}]},{"type":"text","text":"標準的軟件庫,可以很好地與Kotlin協程互操作。但在選定Kotlin後,我們發現很多宣稱支持Java NIO的軟件庫的實現方式並非可擴展的。它們在底層協議和標準實現中並非基於NIO原語,而是使用線程池包裹阻塞IO。我們稱這種NIO實現策略爲“虛引用(Phantom)Java NIO”。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"虛引用NIO策略實現的副作用是線程池在協程環境中很容易耗盡,由於其本質上是阻塞IO,會導致高峯值延遲。爲確保線程池的規模能滿足團隊的需求,虛引用NIO軟件庫都需要對線程池做調優,恰當調優和資源維護的需求增加了開發人員工作量。因此,使用真正的NIO或Kotlin原生庫,通常會提供更好的性能、更易於擴展,實現更優的開發人員工作流。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"依賴項管理:使用"},{"type":"link","attrs":{"href":"https:\/\/gradle.org\/","title":"","type":null},"content":[{"type":"text","text":"Gradle"}]},{"type":"text","text":"頗具挑戰"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相比Rust Cargo和Go module等最新解決方案,構建系統和依賴管理無論對新手還是熟悉Java\/JVM生態者都相當不夠直觀。尤其是對於團隊而言,一些依賴直接或間接地對版本升級非常敏感。Kafka和Scala等項目並不遵循"},{"type":"link","attrs":{"href":"https:\/\/semver.org\/","title":"","type":null},"content":[{"type":"text","text":"語義化版本管理(semantic versioning)"}]},{"type":"text","text":",這會導致編譯成功而應用卻由於一些看上去毫不相干的奇怪回溯(backtrace)而啓動失敗的問題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"寸積銖累,團隊逐漸掌握了哪些項目通常會導致此類問題,積累了一些如何捕獲並過濾問題的例子。特別是,Gradle針對如何"},{"type":"link","attrs":{"href":"https:\/\/docs.gradle.org\/current\/userguide\/viewing_debugging_dependencies.html","title":"","type":null},"content":[{"type":"text","text":"查看依賴樹"}]},{"type":"text","text":"提供了一些有參考的頁面,非常適用於此類問題。掌握多項目代碼庫的進入導出情況,需假以時日,期間非常容易導致衝突需求和環形依賴。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"預先規劃多項目代碼庫的佈局,對項目的長期發展是大有裨益的。儘量確保依賴樹簡單,避免基礎代碼庫對任一子項目的依賴(並且永不依賴),進而在此基礎上做迭代構建,防止出現難以調試或釐清的依賴鏈。DoorDash主要使用了"},{"type":"link","attrs":{"href":"https:\/\/jfrog.com\/artifactory\/","title":"","type":null},"content":[{"type":"text","text":"JFrog Artifactory"}]},{"type":"text","text":",簡化了軟件庫在代碼庫間的共享。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Kotlin在DoorDash的未來發展"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"DoorDash服務標準將繼續完全採用Kotlin,平臺團隊正基於"},{"type":"link","attrs":{"href":"https:\/\/github.com\/google\/guice","title":"","type":null},"content":[{"type":"text","text":"Guice"}]},{"type":"text","text":"和"},{"type":"link","attrs":{"href":"https:\/\/armeria.dev\/","title":"","type":null},"content":[{"type":"text","text":"Armeria"}]},{"type":"text","text":"努力構建下一代服務標準,並通過預先部署監控、分佈式追蹤、異常追蹤、運行時配置管理工具和安全集成等工具和功能,簡化團隊的開發工作流。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這些工作有助於DooDash開發共享性更好的代碼,減輕開發人員查找依賴項、協同工作和維持最新依賴的負擔。構建此類系統的投資,已體現在團隊具備了針對湧現的需求而快速啓動新服務的能力。Kotlin支持開發人員聚焦於業務用例,減少了編寫Java生態中不可避免的"},{"type":"link","attrs":{"href":"https:\/\/en.wikipedia.org\/wiki\/Boilerplate_code","title":"","type":null},"content":[{"type":"text","text":"模板代碼"}]},{"type":"text","text":"所用的時間。總而言之,Kotlin是很好的選擇,我們期待這一語言和生態的持續改進。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於DoorDash的經驗,強烈推薦後端工程人員首選Kotlin。Kotlin是更好的Java語言,該理念在DoorDash得到了驗證,帶來了更大的開發人員生產率,降低了運行時發現的錯誤。這些優點支持團隊聚焦於解決業務需求,增加敏捷性和速度。未來DoorDash將繼續投資於Kotlin,希望繼續與更廣泛的生態合作,開發以Kotlin爲主的更強大服務器端用例。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"答疑"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"問題:爲什麼沒有選定Python 3?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"答:儘管Python 3具有更強大的生態,但整個生態系統依然不夠健壯。Pip在依賴管理上存在很多問題,而conda、poetry、pipend、pip-tools等工具也並未解決問題。對於構建和軟件包工具存在同樣問題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用協程時遇到的最大坑:取消或異常會導致CoroutineContext進入“cancelled”狀態,這意味着進一步嘗試在此上下文中加載協程將會失敗,對於服務器處理的每個請求,需要創建一個新的CoroutineContext。更壞情況時,新的上下文每次創建的代價很大。需要建立一類發生異常後無需取消的特殊任務類型,以及建立很好的協程異常處理。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"團隊使用Kotlin在Apache Flink中實現流處理。爲解決虛引用NIO問題,團隊擬出了一個符合“黃金準則”的軟件庫列表。其中軟件庫或是很好地實現了協程,或是提供預優化版本的庫。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"問題:非阻塞IO是如何實現的?DoorDash最終使用了第三方軟件庫,還是推出了自己的?DoorDash的主要IO是網絡調用、文件系統還是消息代理?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"答:DoorDash構建了自己的軟件庫,針對特定服務使用gRPC。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"問題:DoorDash在從Python遷移到Kotlin中,是如何解決CI\/CD問題的?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"答:團隊採用CI\/CD的層級和版本一直在演進,至少在今年就發生了不少變化,每次迭代都會向前推進一步。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文鏈接:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"https:\/\/doordash.engineering\/2021\/05\/04\/migrating-from-python-to-kotlin-for-our-backend-services\/"}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章