作為一個前端使用 React Native 開發新產品的半年小心得

Standard

本文大綱

  1. 前言
  2. 團隊組成
  3. React Native
    1. 跨界踩坑
    2. 從 Web 到 App
    3. 升級 – 停看聽
    4. 團隊使用的工具與套件
  4. 其他:專案流程

前言

最近滿忙碌的,租屋約到期搬家、恢復長途通勤的日子,而工作上的話,則是團隊終於釋出新增社交元素的新版 App。雖不是什麼劃時代的產品,這個階段也只增加了一些留言討論、按讚等功能(接下來還是有其他新的功能的 :P),不過仍算是個小里程碑,忙碌的事情也暫時告一段落了,便想藉本文記錄一下這半年多*來使用 React Native 開發新產品的心得。

*半年多:實際上,新產品的開發期、基礎建設等約在三個月內,而前三個月是我輪調至 App Team 進行既有的 App 功能開發與維護

歡迎有興趣的朋友歡迎下載試玩看看!



我對投資沒什麼涉獵,也沒閒錢投資 😭 因此本文僅作為一名前端開發者的角度來記錄心得~

團隊組成

App team 團隊組成是 1 Director(也有參與前端開發)、3 名前端 (其中 1 名是 0.5 DevOps + 0.5 前端)、3 名後端、1 名設計、1 名 PM。

沒有 QA,也沒有原生 Mobile App 工程師。

前端的部份是純寫 JavaScript(React Native),不涉及後端開發。前端們原本都有用 React 開發 web 專案經驗。

另外有專門負責 Web 產品的團隊,配置有同等人數的前、後端工程師。

React Native

跨界踩坑

雖然沒那麼美好,但越來越好了

記得剛輪調去 App team 的時候,才剛要把專案跑起來就遇到很多問題,例如環境問題啦(node 套件、ruby 之類的)、Xcode 的設定問題、Apple Developer 的憑證等等的。

雖說現在要寫一個 Web 的前端專案,使用的工具、事前的準備也越來越複雜,但作為一個 Frontend,初接觸到 React Native 的專案真是頗挫折的,當時面對 Xcode 的 IDE 嘗試了兩天,當時的 OS 是 「…連要跑起一個專案都跑不起來,人生好難…」 ,結果發現是一個很蠢的步驟問題而已 😂

記得聽已經接觸半年的同事說,這時候其實 React Native 的專案開發已經不像更早期的「蠻荒時代」了。坑是越走越少,一些常踩的雷也因為前人的踩坑心得筆記累積而能夠避開。嗯,為此我也補了很多血淚筆記到專案的 README 中 😆

不過這些問題對原生 App 工程師來說應該是小菜一碟,如果團隊內有可以請教的 App 工程師那應該能少走上不少冤枉路 😆 若要更能隨心所欲地開發,也許還是得要補上原生開發的相關知識/人力吧。

現在若問我覺得用 React Native 專案的開發感想如何呢?以一個前端工程師來說,半年過去了,我覺得雖然開發體驗沒那麼美好,也的確會遇到意想不到的坑,但比起一年前,React Native 的確越來越好了,生態圈也越來越成熟。

前陣子批踢踢相關專版也有討論非原生開發手機 App 的議題,我想就是看團隊的目的與資源吧,也許原生寫的好好的、專案類型也不適合,那可能就會覺得用 React Native 來開發是很糟糕的選擇了。

踩坑的心理準備

醜話也是要說在前頭的,在製作專案的過程中的確踩過許多意想不到的坑(也許是我學藝不精?😆):

_chrisUK, Pothole, Flickr

像是 ScrollView + FlatList + 觸底(onEndReached)載入更多資料的實作,會造成 FlatList 功能失準而一進頁面就把觸底 load more 的 API 一次打完。相關 Issue 傳送門

此外,在一段文字中,有將特定中文文字加上 fontWeight 的樣式,但在某些手機(Android & iPhone 皆有)上會出現某一段文字就是無法正確顯示該樣式的問題,但前一段就可以正常顯示該樣式,但改了 fontWeight 就正常…。

另外 FlatList 內的資料 row 內容字數若大於某個數量,在 iOS 11 實機上就必定 crash(Android、iOS 10 與 iOS 模擬器不會,神奇吧,iOS 舊版的 10 反而沒問題),不過若改用 ListView 實作卻一切正常,最後是採用 initialNumToRender 設為 1 的 workaround 避開…。我在官方開了 Issue 發問 卻也都沒得到回應 QQ

沒踩過實在很難預知會有這些坑(攤手),而沒有原生 App 開發能力的我們也只能解到 JavaScript 這一層了。雖然用 React Native 讓前端工程師實作 App 雙平台真的很快,但一旦遇到預料之外的坑,可能就要花上不少時間尋找解答或 workaround,因此事前 survey、做 prototype 探探路,以及預留實作 plan B 的時間都是需要考慮進去的成本交換。

從 Web 到 App – 以一個小前端的視角來說

然而批評總是簡單的,選擇沒有絕對的好壞,只有適不適合,React Native 還是帶給我不少很棒的體驗,所以接下來講講正面點的心得吧 XD

Learn Once, Write Anywhere

React Native 的出現,讓我們可以使用 React 累積下來的經驗用來繼續開發 App(而且可同時開發 iOS & Android 雙平台!)。在 React Native 的專案開發中,仍可看到諸如 react life cycle、jsx、redux、reselect、lodash、moment.js、axios、jest 等在 React Web 專案中這些熟悉的好朋友,並用 JavaScript 進行開發。(雖然有時候還是得開 Xcode 進行設定,但也不用真的會寫 Objective-C/Swift/Java)

專案中要是有一些 Web 有、App 也有的資料,我們所用到的 redux 程式碼亦可搬來使用。

不過 UI 層就無法這樣照搬了,我想 Web 跟 App 的 UI 也不該這樣照搬,畢竟操作行為還是有些不同。此外,寫樣式、排版的方式雖說是像 CSS(排版是用「類」Flexbox),但也只能說是「類似 CSS」,但實際上滿多細節不一樣的。

另外,以 Android/iOS 而言,雖說大概有八九成的部分可以共用,但 Android 與 iOS 仍有相異之處,先不論 design guideline 的部份,狀態列的高度、是否有 Back 按鍵、要求權限允許的方式這些東西還是得個別思考與處理。然後,依經驗來說,iOS 上的異常情況要比 Android 少上許多。

總的來說,開發經驗跟開放 React 的 Web 專案頗有相似之處,有機會能用上熟悉的 JavaScript 的套件、Debug tool、慣用的編輯器、開發與效能優化知識等。

另外推薦一下 Stephen Grider 在 Udemy 開的 React/React Native 相關課程,講解的有條有理、且語速也不會太快,是新手入門的好課程。

前端團隊有機會能接觸 App 領域的專案了

承上節,由於在有些 React Web 的經驗可以轉移、帶到 React Native 的 App 開發經驗中,所以要是公司的策略(例如暫時沒有聘用原生 App Developers 的打算)、產品的屬性(提供資訊、打打 API之類的,但遊戲或是用到低階 API 等功能可能就不大合適)等方面都符合的話,那麼前端團隊是滿有機會把觸角伸向 App 產品開發的領域的,也在人力調配上更多彈性。

Michael Pereckas, Amphibious, Flickr
在水裡寫 Web 寫膩了,也可以寫 App 飛上天滑行一下 XD

作為一個 Front-end Developer 也能從 Web 的世界慢慢跨足 App 開發真是件有趣且令人興奮的事! 🎉 by the way, 不管別人怎麼評價前端,迄今我還是很喜歡前端的工作內容的 ❤️

元件 – 社群資源豐富,但有撰寫 Native Code 能力更佳

如 React 在 Web 上面一樣,React Native 也有廣大的生態圈,有開源社群貢獻了很多相關的工具、元件可自由選擇取用,讓我們不必自己造輪子。

不過同樣地,要是想要用的元件 React Native 官方未提供的的話,只能尋找第三方的元件,也沒有的話只能自己包或另尋解決方案了,所以若是沒有撰寫原生層的能力的話,想實作某些功能就只能乾瞪眼了 QQ 另外有些常用的元件官方是沒有提供的,例如 Radio button,不過聽說 iOS 原本也就沒提供的樣子(? 🤔

而元件又會分成兩種,原生元件跟純 JavaScript 達成的元件。一般來說原生的會比 JavaScript 的效能好上許多。

UI – 遵從規範(Guideline) vs. 統一設計

以 navigation 為例,過去 React Native 官方有 Navigation Experimental 這套,但後來就被宣告停用了(雖然因為一些歷史因素,我們還在繼續使用它,並將它續命、自行打包以讓它能在 0.48 繼續使用),目前比較有名的解決方案有社群維護的 react-navigation,以及由 wix 維護的 react-native-navigation;後者是橋接原生的 navigation 解決方案,其對於 Android 與 iOS 平台的呈現就如同平台的原生樣式,而不是兩個平台都一模一樣,要改成一模一樣似乎還比較麻煩。

因為資源與時程考量,現在我們的產品是兩種平台皆使用同一種設計,而非依照 iOS/Android 的 design guideline 實作,不然讓 iOS/Android 的用戶有其平時慣用的操作介面、行為應該會更理想。

※ 延伸閱讀:iOS 與 Android,App 的 UI 設計該一致嗎?

React Native 升級 – 停看聽

React Native 還是個年輕的開源專案,幾年過去了,Major 版號仍在 0 :P

現在 React Native 的改版週期大概是一個月會升一次 minor 版號,不過這不代表每次都有 Breaking Change,有時候順順地一升就上去了。

Stop, Igor Spasic, Flickr

但升級前,請停看聽:

Features & Bugs

Features 有時會伴著 Bug 一起出現 XD 例如 0.46 版時 React Native 新增了 ImageBackground 這個標籤,是為了取代用作背景的 Image 標籤(Image 標籤裡面包內容,那麼 Image 的圖片就是被當做背景圖),不過其中的雷在於 ImageBackground0.46 時,其中若包含了 Touchable* 元素,一 render 就會 Crash,而這個 bug 在我發了 PR 被 merge 後,直到 0.48 才真正被收進去 :P

所以建議在 rc 版推出、或是新版本推出後,先觀察一下 Issues 的風向,有沒有重大、對專案影響甚鉅的問題,再來決定要不要升版吧。

我覺得在使用 React Native 的開發中,必須時常關注 React Native GitHub 專案中 Issues 的議題,甚至有些東西比看官方文件還來得有用 😭

此外,遇到問題時也記得先將問題單純化,可以使用 Expo Snack 做一個 POC(Proof of Concept)看看是否能將問題重現,接下來再一步步解決,或是去報 Issue 給 React Native team 噢。

檢查一下第三方套件有沒有升級災情

有時候一升級,第三方套件也會跟著炸裂,像升級到 0.47 時,官方捨棄了 createJSModules,而許多第三方套件(例如 react-native-facebook-loginreact-native-google-analytics-bridgereact-native-share 等)仍會試圖 @Override 該方法,必須一一處理,也讓我爽賺了一波 PR XD。

還有最近 0.49 中引用的 React 已經不包含 PropTypes 了,必須改用 prop-types 提供的,所以一堆第三方套件又要跟著改版囉。

專案使用的工具與套件

此節分享一些專案使用到的工具與套件,有些也是從其他 Open Source 的專案中看到覺得不錯而選用的。若有您覺得不錯的套件,也歡迎跟我分享~

Debug 工具

React Native 的 debug 頗方便,可以透過 react-devtools 直接觀察 UI 結構,如果有用 redux 的話更可以用以下兩個工具解析與觀察。

其中 reactotron 甚至能在 inspector 中列出 API response 哦,相當方便!

Reactotron

Tracking

而追蹤統計,我們使用的是 Google Analytics 與 Fabric。

蒐集這些資訊能更了解使用者數據,以及 Crash 的狀況,這邊可以搭配下面錯誤處理的機制以蒐集更多資訊。

錯誤捕捉

當在 React Native 中發生例外時,通常就直接噴紅畫面(開發時)或直接閃退(Production)了,也無法在此時塞入追蹤事件,甚至是給使用者回報的機會。

錯誤捕捉

透過這個 package 讓我們可以捕捉錯誤事件,並讓使用者有機會回報錯誤。

環境設定檔

好的開發流程中都會準備不同的環境以便開發期、測試期與正式釋出的環境。透過這個 package 可以設定不同環境的環境變數,例如測試與正式釋出時希望使用不同的 API URI 之類的。

熱更新

熱更新真是很變態的功能,能不用一定要等審核通過就能更新 App 的部份程式碼。不過使用前請詳閱相關規範與使用注意事項。

不過更新與開發的流程滿需要好好事前規劃的,不然很容易亂掉,也許未來有機會再寫一篇分享吧。

圖示

專案裡的圖示都是由設計師設計並提供 SVG 格式的檔案,前端會使用 react-native-svg 來讓 React Native 能夠直接使用這些圖檔,而且是向量格式,不用擔心必須輸出幾倍的問題了。


其他:專案流程

這部份跟 React Native 沒什麼關係,沒興趣的可以上一頁離開了 😆😆😆

前端與前端

團隊成員依照 priority 與經驗,各自認領 user story 來實作其下的 sub task,通常在執行前大家會簡單討論一下執行的思路,像是想要怎麼規劃這次的 redux store、元件要怎麼拆分、可能有哪些 solution 與誤區。

而實作完需求與 unit test 後(少部分有寫 E2E Test,我們是用 Appium,正在考慮 detox。但 E2E 真的很花時間成本,priority 只能排後面了),都會在 Bitbucket 開 Pull request,盡可能經過其他 1 ~ 2 名前端同事 review 過後才會 merge。之後會透過 Jenkins 依據環境推版/跑 CI(test、Fastlane 等),並搭配 Hockey App/TestFlight/Google Play 測試版 等管道,供其他成員一起測試。

約莫每隔一週的週期(累積足夠量,且大家沒有忙得焦頭爛額),有個下午時間(固定約一小時左右)會在會議室投大螢幕進行 frontend code review meeting,彼此說明這週實作的 pull request(無論 merge 與否),其中值得分享的、或是想提出來討論的部份。我覺得這個方式挺不錯的,不致於有「太被刁難的被 review 感」,而是大家當面一起討論出可以怎麼做更好、實作中用上了什麼奇技淫巧之類的。

前端與後端

後端是用 PHP (Laravel) 開發的。呃~詞窮了,只覺得後端同學們都很可靠,也很樂於跟前端一起討論最佳的解法 👍 個人非後端專業就不在這詳述囉,這邊僅記錄前後端的合作方式:

前後端透過 Postman 產出的 API Documentation 討論,並在 Slack 上或當面進行溝通。感謝後端同學的 survey 👍 這個文件產出的真是美觀實用,在事前溝通、事後查閱上體驗相當好(不過未來當 API 數量越來越多的時候,也許要想想怎麼整理才能更便於查閱)。另外它無法像 Swagger 一樣直接在介面上測試,所以我們就直接使用 Postman Client 測試。

討論出 API 格式後,前端可以先行開發。有些較複雜的需求,後端也會視情況先出 Dummy API 給前端串。

而有新的 API 改動推版後,後端同學們一樣會在 Slack 開發頻道上通知大家幫忙驗證與確認。

前端與設計

設計師使用 Sketch 進行 UI 設計,然後把各個畫面(包含不同的狀態,例如 Empty State、Load more…)放到 Zeplin,需要特別注意的地方亦會標註,並在 Slack 或面對面討論溝通。

而專案的圖像都是使用 SVG 格式,搭配 react-native-svg 呈現,所以前端這邊都是請設計提供 SVG 格式的圖片。

此外,推版之後設計也會主動去安裝新版玩玩看,有什麼 UI 上的錯誤便會在 Slack 上立即反饋給前端,並擷圖開票備查。

專案流程

現在的玩法

這邊不討論產品規劃面向的東西,就站在開發端的觀點記錄一下~

聽說現行採用的叫 Scrum + Kanban 混合體的 Scrumban,當初團隊導入時的介紹是 Kanban 搭配彈性的 Scrum,例如沒有固定 Sprint 與 Demo day 的時間,只有限制一個 column 中的最高數量(目的是希望不要在一個 column 卡一堆東西,大家專注在那幾張票上做完),另外是比較事件驅動一些 😛

eiji ienaga, かんばん, Flickr
看板 (無誤)

在 Planning 會議時會依照 PM 整理好的 user story 來了解需求、估 story point、切 sub tasks 與估時數(這些也有可能在 refinement 會議中完成,就看數量跟時間),並放入 Backlog 中,PM 再依據綜合考量排出第一次 release 要做哪些 story。其中 story 的描述相當考驗 PM 的邏輯與敘事能力,為什麼要做這張 story、怎麼算是符合完成條件、怎麼 demo、各種狀態下的差異等等。反之亦然,工程師怎麼把考量點、困難點、做技術 story 的價值,言簡意賅地用白話文(例如舉出易懂的例子)讓非技術背景的 PM 與設計師了解也是很重要的。

題外話,我覺得非 full stack 型的團隊在估 story point 的時候,感覺滿像默契猜心遊戲的,因為有些部分對非專長職能的人來說難以估計(像我就很難估計後端看起來很複雜的 story point 有多大),只能看對方的「用詞」跟「表情」來猜大小,這樣不就徒具形式了嗎?🙁

所以後來團隊衍生出另一個方式進行,我覺得比較有實質意義一些:先依點數大小排好 point cards,接著放上幾張用來參考點數的舊 story,大家再輪流放上新的 story 到 point card 旁邊,下一個人亦可選擇調整與否,並說明為什麼覺得在這邊。

而平時會用 JIRA 跟得來不易(?)的實體白板將 user story 排在不同的 column 中,例如「Selected to Develop」、「開發中」、「Review」、「Done」等,每日早上的站立會議大家會更新這些票的進度,並提出困難或疑問給其他成員知道。

有新開發好的 feature 也會利用這時間快速地給大家看一下,並請大家可以下載測試版(TestFlight & Google Play Beta)玩玩看有沒有什麼問題。不過 scope 太大的 story 就不大適合在這時間 demo 了,會另行安排比較長的 Demo 時間,不然大家要站很久 XD

隔一~兩週的週五下午有 retrospective 會議,讓大家配著零食自由發表感謝,以及在 Google Spreadsheet 上自由寫下「Happy」、「Unhappy」、「Do More」與「Do Less」。由於是自由發言,所以也比較不會像以前被規定一定要依序發言,容易為了講而講、變得流於形式(例如每次都講一樣的感謝與問題)。

retrospective
Retrospective

我覺得關於反映問題,問題真的有被認真思考與解決才是重點,也許不用一次到位,但總願意嘗試與調整;此外某些問題也需要公司的支持才能解決,並不是只有部門或小組有這種思維就會萬事 OK,不然應該會一直看到一樣的問題被提出(也有可能提出者放棄再次提出了 XD)

個人觀點

比較可惜的是沒有專職 DevOps,所以前期的基礎建設花了比預期更多的時間,有些同事的 task queue 也被佔滿了。另外也沒有專職的 QA 工程師,所以驗證這件事只能靠團隊成員自己測,而忙於開發衝刺的時候,常常就沒空去做測試驗收了。而且真正專業 QA 的手法與深度又是另一個等級了(很感謝之前公司合作過的 QA 同事們,相當專業盡責,列出的 issues 都很詳盡),對於問題的重現方式也更清楚,對於抓出問題、解決問題應該會更有效率。

個人比較隨性自由,討厭不知改進死亡行軍式的加班、討厭開一堆冗長的會(自我滿足式的忙碌?XD),不喜歡小鼻子小眼睛的一堆規定、為了做而作的流程與制度,想要快速、結果反而被一堆莫名的事情拖慢效率 🙄。大家溝通清楚就快速行動,看卡關卡在哪、有什麼錯就趕快提出趕快找出解決方案。

gnsk, junya, flickr
快速調整突破障礙吧!

過去在數位代理商(接案)工作時,時常要面對上午跟你說 A、下午說我要 B 的奇葩客戶,還有各種火燒屁股又沒做過的專案需求,被訓(ㄐㄧㄚ)練(ㄅㄢ)地不得不找出最快速應變的做事(get shits down)方式,雖然一開始幾乎沒有制度流程可言、RD 僅被當成產出部門而已,不過後來慢慢調整後有逐步改善,早些溝通、嘗試,並用手上僅剩的時間與資源做最佳的選擇;或是在 start-up 也經歷過用稀少的人與資源做事,健康的 組織扁平能「少很多 report line 與不同部門間 KPI 的利益糾葛」、「非常彈性自由」的優點吧,不該隨著組織變大,而少了透明度與內外意見反饋的速度。基本上都是希望能夠小步快跑、快速應變、盡早發現問題並解決。

先前跑過很完整的 Scrum 流程,好處的確是很嚴謹,規範讓團隊不易失控、專案不易崩潰,但很多的遊戲規則跟會議,真是滿消耗精力的 😩;現在彈性一些我個人覺得也好些,只要成員自律,團隊默契也可以優於規則、不役於物。的確還有需要磨合、以及可以改進的地方(越近上線就越忙亂 XD),不過就一步步來吧。

即便是同一個名詞、方法,由於情境與文化不同,每個地方定義的、真正執行起來都各有滋味與風格,所以我覺得沒有「用了某某方式、某某流程、某某績效評估方式,團隊就會好棒棒」的最佳 solution 這種事情,也別被 buzzword 迷惑了,失控的信仰不是件好事。如同這篇 文章 所說, 「…很像閱讀偉人傳記,從中讀者並無法藉由模仿書中案例來邁向成功人生…」 ,沒有放諸四海皆準的最佳方案,端看當下所處的實際情況與條件,誠實地面對問題、快速找出適合團隊的解決方式才是真的 👍

共勉之。

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *