圓桌討論:大規模移動開發

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic"}],"text":"本文最初發表於 Increment 雜誌,經 Increment 官方授權,InfoQ 中文站翻譯並分享。"}]},{"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":"阿迪達斯(Adidas)Runtastic、Eventbrite 和 Citymapper 的工程負責人討論了應用程序的性能、移動端如何融入其組織結構以及原生與跨平臺開發。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"嘉賓介紹"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"Christian Orgler"},{"type":"text","text":",阿迪達斯 Runtastic 產品工程副總裁。現有 62000 多名員工,43 名移動工程師。"}]},{"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":"Natlia Gatti"},{"type":"text","text":",Eventbrite 工程經理。現有 600 多名員工,20 名移動工程師。"}]},{"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":"Jogre Cohen"},{"type":"text","text":",Citymapper 產品工程主管。現有 60 多名員工,10 名移動工程師。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"貴司如何看待移動業務?"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"阿迪達斯 Runtasic,Chrisian Orgler:"}]}]}]},{"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":"我們認爲,移動是我們業務的核心,也就是創造吸引人的運動體驗。說到底,你是不可能帶着筆記本電腦跑步的。但是,將移動設備與正確的平臺結合起來,會使你獲得最佳的體驗。舉例來說,你可以使用我們的應用程序和 Facebook 門戶網站,在你的客廳裏進行快速鍛鍊。"}]},{"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":"隨着我們的成長,我們經歷了幾個階段,從發佈和維護超過 30 個應用程序,到縮減爲 4 個伴隨網絡平臺的應用程序,再到 2015 年被阿迪達斯收購後,只專注於兩個應用程序,即 adidas Running 和 adidas Training。"}]},{"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":"Eventbrite,Natalia Gatti:"}]}]}]},{"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":"Citymapper,Jorge Cohen:"}]}]}]},{"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":"Citymapper 的宗旨是幫助人們在城市中導航,因此我們需要高度移動化。這些特性是從移動端開始的,隨後適應於 Web。儘管我們能夠快速適應新技術,但是我們通常不會採用新的框架,因爲新的框架對用戶並沒有明顯的好處。並非每個人都買得起最新的設備,因此我們歇盡全力支持舊的操作系統,讓我們的 API 向後兼容,這樣,更多的人就可以從我們的服務中獲益。五、六年前的 Citymapper 版本現在還可以用!"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"貴司在移動開發中使用了哪些工具和技術?"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"阿迪達斯 Runtasic,Chrisian Orgler:"}]}]}]},{"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":"我們的構建基礎設施使用 fastlane 和 Jenkins 等開源工具,這些都與我們的代碼管理系統 Bitbucket 相連。我們的監控工具包括標準的蘋果和谷歌控制檯儀表板,以及我們自己更爲定製的應用性能監控(App Performance Monitoring,APM)工具 New Relic,它與我們的後端服務相連。"}]},{"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":"發佈任何變更前,我們都要經過 alpha 測試(與員工一起)和 beta 測試(與真實用戶池),通過 App Center、TestFlight 或 Google Play 根據測試階段進行分發。由於有數以百萬計的活躍用戶,我們有時會觀察到一些問題,這些問題要求我們在模擬器不夠用的情況下重新創建用戶的確切硬件和數據環境,所以我們目前正在測試一個第三方遠程訪問工具,該工具將允許我們選擇任何物理設備,並重新創建一個出現問題的確切硬件。在應用程序中,我們把它與 QA 工程師使用的內部調試功能結合起來。"}]},{"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":"Eventbrite,Natalia Gatti:"}]}]}]},{"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":"對於 iOS,我們使用蘋果自己的開發者工具,比如 Xcode,因爲它們減少了與 iOS 更新的摩擦。我們使用 XCTest 框架編寫測試,並選擇了諸如 fastlane 和 SwiftLint 等社區標準來促進應用程序平臺之間的統一。對於 Android,我們使用 Android Studio 和 Kotlin 進行開發,使用 Firebase Test Labs 進行集成測試。爲了在 iOS 和 Android 應用程序中共享業務邏輯和工具,我們也建立了倉庫。我們依靠 Sentry 來追蹤問題和崩潰,依靠 Google Analytics 來追蹤應用的使用情況。CircleCI 是我們的持續集成管道,我們使用 Code Climate 來審查代碼質量,包括代碼覆蓋率。"}]},{"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":"Citymapper,Jorge Cohen:"}]}]}]},{"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":"基於 Github Actions 和 Bitrise CI,我們使用 fastlane 進行構建和部署,利用 Mixpanel 和 Crashlytics 進行客戶端監控,使用定製的 Grafana 儀表板對後端進行監控。我們的 Android 團隊 Firebase Test Labs 用於對設備進行測試。近期,我們也開始使用 Point-Free 的 swift-snapshot-testing、Airbnb 的 Showkase 和 Cash App 的 paparazzi 等開源工具進行快照測試組件。通過 Phabricator,我們進行所有的代碼審查,並使用特性標誌來避免交付未完成的特性。此外,我們也使用了各種工具進行配對編程,主要是 Pop。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"移動工程師如何融入貴司的團隊結構?"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"阿迪達斯 Runtasic,Chrisian Orgler:"}]}]}]},{"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":"我們的產品工程團隊是跨職能設立的,包括移動、後端和 QA 工程師,以及一名產品設計師和經理。"},{"type":"link","attrs":{"href":"https:\/\/www.atlassian.com\/agile\/agile-at-scale\/spotify#:~:text=will%20be%20used.-,Tribes,what%20we%20call%20Dunbar's%20Number","title":"","type":null},"content":[{"type":"text","text":"受 Spotify 模式的啓發"}]},{"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":"Eventbrite,Natalia Gatti:"}]}]}]},{"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":"我們的移動工程師分屬兩個團隊,即 iOS 和 Android,他們還包括專門的產品經理和產品設計師。這種結構的優點是更多地關注內部知識共享和支持,允許兩個應用程序之間的相互交流以及跨團隊的指導。這種結構也使產品團隊受益,因爲它向他們提供了對每個應用程序的整體視圖。但是,這的確需要與擁有後端服務的特性團隊進行高度協作和協調,這可能會導致在協調發布和調整路線圖時作出妥協和權衡。"}]},{"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":"Citymapper,Jorge Cohen:"}]}]}]},{"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":"很少有這樣的情況,我們會建立臨時的特性團隊,來幫助我們專注於一個特別具有挑戰性的項目,或者快速啓動一個新產品。近來我們在 B2B SDK 上做過類似的工作。這些團隊是臨時性質的,一旦我們解決了這個挑戰就會解散。隨後,我們通過文檔和內部討論,與團隊的其他成員分享關於新特性的知識。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"你的移動團隊是原生開發還是使用跨平臺框架?"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"阿迪達斯 Runtasic,Chrisian Orgler:"}]}]}]},{"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":"雖然我們的開發主要是基於原生平臺,但是我們偶爾也會探索、測試和驗證針對特定需求的跨平臺框架。舉例來說,我們使用 React Native 開發了我們的社交媒體源,但是出於幾個原因,其中包括穩定性、所需的領域知識以及我們必須採用的變通方法來實現與原生代碼的正確互操作性,我們決定過渡回原生開發的社交媒體源。"}]},{"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":"每個季度,在全公司的“新想法日”上,我們的工程師有時會用諸如 Flutter 這樣的跨平臺框架來開發內部應用,然後確定這種技術是否適合我們當前的企業規模需求。當前,我們正在對 Kotlin Multiplatform Mobile 進行評估,以共享平臺之間的某些特定業務邏輯。"}]},{"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":"Eventbrite,Natalia Gatti:"}]}]}]},{"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":"我們的移動團隊進行原生開發,因此我們可以提供最好的用戶體驗,並跟上最新的 iOS 和 Android 更新。儘管這樣做會導致工作上的重複,但是我們發現,我們在設計和用戶體驗方面必須做出的讓步,比使用非原生平臺要少得多。它還能讓我們更快地採用特定於平臺的新特性。雖然我們在同一平臺的應用程序之間共享了代碼,但是我們也在 iOS 和 Android 應用程序之間使用了嵌入式 Web 視圖,以提供相同的特性,當特性太難構建或無法產生投資回報時,就會進行原生開發。"}]},{"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":"Citymapper,Jorge Cohen:"}]}]}]},{"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":"我們的消費者應用程序是完全原生的,因此我們可以利用每個操作系統的最新特性,iOS 是用 Objective-C 和 Swift 編寫的,Android 是用 Java 和 Kotlin 編寫的。雖然我們有些屏幕是使用基於 Web 的技術構建的,但是我們通過結合設計、CSS 和 JavaScript,來確保這些屏幕儘可能地具有原生感。我們研究過 Kotlin 多平臺和 Swift,用於我們的 B2B SDK 中的跨平臺邏輯,但它們感覺還不夠成熟。爲了應對客戶項目結構的不可預測性,我們希望使 SDK 技術儘可能接近平臺供應商所使用的技術。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"你如何衡量移動應用的性能?"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"阿迪達斯 Runtasic,Chrisian Orgler:"}]}]}]},{"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":"在團隊層面上,我們衡量與我們的經驗相關的具體性能指標,例如我們的 GPS 跟蹤算法需要多長時間調整準確性和速度,並刪除異常值以補償硬件傳感器。在應用層面上,我們研究常見的指標,如崩潰和“應用程序無響應”(ANR)率,並將其轉化爲以用戶爲中心的指標,如“惱怒用戶率”和“無崩潰用戶率”,或根據用戶發生的時間進行分類,如在跑步或完成鍛鍊時。我們還測量用戶界面的時間、啓動速度、應用程序的大小等等,包括新興市場的一些關鍵指標,如蜂窩數據的使用和連接速度。"}]},{"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":"Eventbrite,Natalia Gatti:"}]}]}]},{"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":"爲保證發佈後每一個應用程序都能保持穩定,我們使用 Sentry 來監控無崩潰用戶會話率,我們的目標是將這個比率控制在 99.6% 以上。對於我們的 iOS 應用程序,我們使用 MetricKit 來監控啓動時間和掛起率。對於 Android 系統,我們在 Google Play Console 中測量 ANR 和崩潰率等核心指標。我們的重點是防止流量高峯期出現性能和網絡問題。"}]},{"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":"Citymapper,Jorge Cohen:"}]}]}]},{"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":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"在產品開發過程中,你的移動團隊如何優先考慮無障礙環境?"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"阿迪達斯 Runtasic,Chrisian Orgler:"}]}]}]},{"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":"我們的 UI\/UX 設計師和產品經理通過設計將無障礙環境納入產品特性開發。近三年來,我們在應用程序的基礎方面做了一些改進,比如爲屏幕閱讀器標註了按鈕等用戶界面組件,並創建了“輪椅”等專用運動類型,作爲參與挑戰或虛擬比賽的選項。"}]},{"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":"Eventbrite,Natalia Gatti:"}]}]}]},{"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":"我們成立了一個委員會,由 Web 和原生應用程序專家組成,收集用戶對無障礙環境問題的反饋意見,併爲更大的團隊起草指導方針。此外,我們使用 iOS 上的 Accessibility Inspector 和 Android 上的 Accessibility Scanner 來衡量當前的無障礙環境問題。最近,我們專注於解決我們的登錄流程,以解決對比度、動態字體和鏈接等問題。我們現在正計劃在我們的持續集成環境中建立無障礙環境測試,這樣我們就可以確信我們開發的新特性是無障礙環境。"}]},{"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":"Citymapper,Jorge Cohen:"}]}]}]},{"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":"2019 年,我們在一些城市(已有此類數據)增加了無障礙坡道,以支持輪椅使用者。由於我們希望進一步幫助有視覺障礙的人,所以改善 VoiceOver 支持也在我們的產品路線圖上。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"在移動開發過程或工作流中,有什麼出乎意料或獨特的東西讓你覺得特別有效?"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"阿迪達斯 Runtasic,Chrisian Orgler:"}]}]}]},{"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":"Eventbrite,Natalia Gatti:"}]}]}]},{"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":"Citymapper,Jorge Cohen:"}]}]}]},{"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":"許多移動應用程序至少有一個屏幕的廣告內容需要經常更換,Citymapper 也不例外。爲了在不涉及開發者的情況下保持內容的更新,我們使用了一個定製的 Sketch 插件,使我們的設計師和產品經理能夠在不需要編程的情況下構建整個特性屏幕。轉移到這個系統後,加快了信息和設計的實驗速度,並使移動團隊得以專注於更優先的工作。我們的應用程序目前有超過 10 個屏幕是用這個工具建立的。"}]},{"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":"作者介紹:"}]},{"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":"Increment 是一本關於團隊如何大規模構建和操作軟件系統的雜誌,該雜誌擁有印刷版和數字版。"}]},{"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":"原文鏈接:"}]},{"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:\/\/increment.com\/mobile\/mobile-development-at-scale\/"}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章