Sherry L

[Projects] Twitter 專案_協作開發初體驗

banner

期待已久的 Twitter 專案終於來了!這次的協作專案就像是玩密室逃脫,行前會拿到任務道具,剩下只能靠自己與隊友合作、突破重圍!先來看看手上有什麼吧:

  1. 題目:請復刻一個推特 (Twitter) 網站
  2. 一份 user stories 、UI 設計稿
  3. 近 60 項單元測試的測試檔
  4. 開發時間:兩週,包含最後四天的黑客松挑戰賽
  5. 挑戰賽的內容當天才會公佈
  6. 可以選擇全端開發或前後端分離開發,請自己找隊友!

在這樣的前情提要下,我們從無到有生出了一個簡易版的推特社群網站,打造常見功能如推文、按讚、追蹤訂閱、即時聊天,也通過業界技術導師的肯定,成功過關!開發過程的酸甜苦辣,待我娓娓道來~

在開始前,先放上我們的成果連結吧 😎
- 專案 後端 repo
- 專案 前端 repo
- GitHub Pages Demo (可以使用體驗帳號或註冊一組帳號)
體驗帳號:user1
密碼:12345678

我們的開發方式

一直以來都很想體驗前後端分離協作,畢竟之前都是自己一個人做全端專案,很期待前後端合作上的碰撞。雖然與同學們不太熟,但也找到了隊友,組成前後端各2人的開發團隊。我們使用的技術有:

  • 後端:以 Node.js + Express 框架開發,搭配 MySQL 資料庫,將 API server 部署在 Heroku
  • 前端:以 Node.js + Vue.js 框架開發,取用後端 API 並部屬在 GitHub Pages

我在專案中的角色:

  • 共同規劃資料關聯、繪製 ERD
  • 研究測試檔與設計稿、擬定路由與回傳資料
  • 部分後端 API 開發 (推文、回覆、追蹤相關)、部分種子資料
  • API 文件的撰寫
  • 專案管理、安排會議與紀錄、前後端溝通
  • 專案規劃

在協作專案中,團隊間的溝通非常重要,尤其我們是臨時成軍,更必須在最短時間內熟悉彼此開發習慣,才能夠進行有效率的開發。第一次前後端會議前,我和後端夥伴 Ivy 就先就 user stories 討論出大致功能,並對照測試檔來實作,模擬 TDD 的開發方式:

研究測試檔

雖然我們事前已規劃了大致路由,但仍將測試檔中的 model 與 路由都整理成表格,再開始正式設計資料結構與 API,這讓我們在開發的過程中能夠確保基本功能都可通過測試:

ERD

而在這個過程中我們也學習閱讀測試檔的架構,之後有機會也可以利用 mocha + chai 撰寫自己的單元測試。

之後再根據 user stories 、UI 設計稿,在 excel 中統整所有路由,並決定回傳資料,再來就能進行工作分配了:

API

為了避免日後各自開發的功能合併回 master branch 遇到 merge conflict,決定由 Ivy 統一做專案基礎建設,包括建置 GitHub repo 、所有資料 model 與 passport 驗證,完成後才來認領各項 Controller 的開發。另外,我們也建立保護 master branch 的機制,任何人推送的 PR 都必須經過另一人 review & approve ,才能合併回主分支。

用 Trello 管理進度

規格都出來後,我們開始使用 Trello ,用敏捷的 Kan Ban 方式來推動團隊的開發工作:

trello

這裡每張 ticket 上都可以綁 GitHub branch、commit 與 PR,透過各種 label 與 member 的標示,讓整個專案流程一目瞭然,也清楚看到各組員負責的任務以及進度。

trello2

我也經常在 ticket 中利用 Checklist 來記錄一些細節或容易忘記的指令,並和 Ivy 約定好在每張 ticket 的留言區紀錄開發耗時,以利專案時程控管與互相支援。

開發過程 ─ 新知識與舊技能的碰撞

在這次開發過程中,我主要負責撰寫 user 與 admin 之外的所有路由,包括推文、追蹤、按讚、訂閱相關功能以及公開/私人聊天室。除了接觸了許多新工具,也重新認識了以前學過、但還沒有摸很熟的部分:

凡走過必留痕跡─透過練習加深印象

1. 非同步的 async / await 寫法

由於一開始是學習 promise-based 語法,很習慣資料用 .then() 來方式來傳遞,因此要轉換成 async/await 寫法時有一段陣痛期。這次由於我們在專案開始前就討論好一致的 coding style,包含 async/await 語法,趁這個機會好好練習。

本來以為改寫會很困難,寫了之後才發現整體程式碼的易讀性變高,架構更明確了。而用變數來接住非同步資料也比 promise-based 一直用 .then() 來傳遞資料直覺的多,其實也沒有那麼難,只是缺乏一試。

2. 利用單元測試來檢查重構時是否影響主程式

通常完成一道路由時我們就會先跑測試,確保沒有影響到原本寫好的功能,或是資料關聯等等,這也讓我們能夠隨時抓到可能的錯誤,避免問題滾雪球越滾越大才發現。

3. Status code 的使用情境

之前學習 Status code 時只有輕輕帶過,大概知道 200 是 ok,404 是 not found 等等,這次為了要將不同情境傳遞的資料與成功/失敗訊息都完整呈現給前端使用,跟 Ivy 一起研究了各種 status code 適用的情境,長知識了!

statuscode

不過後來在得到助教回饋時,有說到業界通常不會使用這麼多的 status code,每個技術團隊都會討論一套 status code 的情境與標準。

4. 熟悉 sequelize 資料關聯與撈資料方式

還記得我第一次學習 SQL 時有夠崩潰,搞不懂怎麼下指令撈到我想要的資料、也不會 JOIN table。現在雖然會撈了,但經常還沒辦法利用 ORM Sequelize 一次就撈到所需的資料,造成在一次 request 中呼叫資料庫多次,效能與資源運用上不佳。而後來發現用 sequelize.query() 下原生 SQL 的指令,能夠比較直覺地 JOIN 很多 table 或排除某些欄位:

query

5. Git & GitHub

過去做一人專案,幾乎都在 master branch 做 commit ,這次因為與人協作的關係,必須共同遵守版控方式。專案開始前,我和 Ivy 一起研究使用 Git 協作時常用的指令及流程,並和 Ivy 開了模擬的 repo 來做 Git flow 的實驗。

而在實際協作時,因為有這些準備,讓我們在開發時幾乎沒有遇到合併衝突,也能透過良好風格的 commit 得知大致上的改動內容,提升開發效率。

然而,這樣涵蓋範圍比較廣的一個專案,不可能都只有讓我們複習到過去有學的東西,如何學習面對不熟悉的事物才是這次最大的挑戰:

不熟悉很痛苦,看懂了很有成就感 ─ 那些新學到的東西

1. 使用 Swagger UI 打造 API 文件

swagger

以前在找許多第三方套件的官方文件時,都會有一個 API documentation 頁面,告訴我們如何使用它的 API 來抓取資料,也能夠現場模擬操作得知回傳 data 的長相。這次決定使用 Swagger 這個套件,除了這樣用顏色分類所有 API,整體風格鮮明易懂,也能夠搭配資料庫即時操作,就像用 POSTMAN 實測 API 一樣,十分方便。

第一次讀文件時幾乎都看不太懂在講什麼,也在到底要用 JsDocs 還是 yaml 、要用 swaggerAPI 還是 OpenAPI 格式來寫,卡了很久。官方文件的範例太過簡短、Youtube 上的教學也不是 100% 符合目前專案的架構,東湊西湊地臨摹教學,一下寫 swagger 一下寫 OpenAPI 格式,兜在一起就會有錯誤,反而把自己搞混了!

最後決定靜下心來好好研究 yaml 的寫法,並仔細閱讀 OpenAPI 官方文件,利用 Swagger UI 提供的編輯器範例,一步一步改寫成我想要的樣子,到後期要加入登入驗證時已經能夠熟悉寫法了,也就順利做出這個 Swagger UI 頁面,給前端參考。

2. 使用 socket.io 打造即時聊天系統(限時挑戰)

原本興致勃勃、戰力滿點,跟 Ivy 在專案開始三天就寫完所有路由,到黑客松之前主要在跟前端確認回傳資料跟寫 swagger,所以也提早兩天開始研究 socket.io ,沒想到我這次踢了個大鐵板,搞不懂就是搞不懂。
雖然官方文件用字平易近人,給的打造聊天室範例也很簡單清楚,但網路上搜尋到的大部份資料都是使用全端的方式來做開發,也就是寫個簡單的 html 頁面再搭配後端這邊來做 socket 的事件傳接,當時實在很難憑空想像前端如果使用框架開發,要用什麼跟後端做 socket 的傳輸。

後來 Ivy 非常有行動力的生出了一個實驗用的 chat.html 來模擬,並和前端開始討論,在這過程中我認真消化,但因為仍不夠熟悉,在時間緊迫(限時挑戰)下,Ivy 挑起即時聊天開發的大樑,我則負責撰寫聊天室頁面 API,與 debug /測試,回報問題、適時支援。

雖然中間看不懂>>找資料>>消化不良>>找資料的過程很痛苦,但還好最後是弄懂了概念,也能夠在大家一起 debug 聊天室功能時,幫助尋找問題點。

開發過程─前後端溝通

我們使用的溝通管道主要為 Slack,但也有使用 Basecamp 作為和助教約 office hour 、提問的管道。

Stand-up meetings

Basecamp 上除了可以即時討論問題外,我也利用每天的 check-ins,隨時掌握組員的狀態與個人進度,開會時就能夠直切重點討論,或是看到組員有任何 issue ,馬上聯繫討論:

standup

定期開會追蹤進度與回報問題

維持三天一小會,五天一大會的頻率,隨時關注專案時程與進度:

meeting1
meeting2

用資料溝通

透過這次的開發才發現前後分離的專案,雙向的事前溝通是超級無敵重要的。舉凡資料格式、路由、甚至 socket 的 event 都需要前後端統一,才能正確的呈現資料

而這次常常在前端提出串接問題時,發現有很多時候其實是撰寫時與後端提供的資料格式不同,造成取不到資料的情況,或是在 socket 傳接 event 時,event name 不一致或傳入的參數型別不同,造成功能失靈、資料無法正常呈現。或許是因為一開始後端沒有跟前端討論 API 怎麼做、需要哪些資料,直接寫好 API 文件給前端請他們照著上面的路由與回傳資料來設計串接格式,所以才會有後續來來回回確認的時間成本。

專案進度控管

另外在組員的工作分配、進度控管上,也體會到不能因為不了解前端開發方式、如何撰寫,就不去了解他們大概的流程架構,全權交辦自行處理。因為這樣到了後期才發現,沒有完善地根據組員時間、外務規劃工作分配,會造成專案時程延宕及組員負擔。

結語

學習程式時間總是過得特別快,一晃眼就到了做畢業專案的時候。從開始接觸程式到現在,這一路多的是自己全端開發,還沒跟人合作、甚至前後分離開發過,所以這次的協作經驗對我來說特別深刻。

在專案開始前其實有擔心過自己會不會頭腦一片空白,不知如何開始,但還好平常的累積都在這時候發揮,能夠順利的拆解問題並去解決它。比較可惜的是自己不熟的基礎建設這次沒負責這部分,但也透過觀摩 Ivy 的程式碼學到很多,不管是 sequelize 撈資料的方法、或是程式碼的重構等等,都是我可以再加強的部分。

這次的經驗真的滿難得,謝謝很罩的前後端隊友們,配合度超高,協作及開會都很自動也很認真,大家一起熬夜、一起試圖弄懂新技術、一起 live debugging 都是滿滿的回憶~

謝謝 後端夥伴 Ivy 、前端夥伴 Clement 與 Dennis 一起完成專案!