註:此為 Oursky 專案經理 Jim Chim 於 MOPCON 2020 (Mobile Open Platform Conference) 的演講稿。去年我們為立場新聞打造了 2019 香港區議會選舉專頁,透過簡潔俐落且流暢的 UI/UX 設計,將複雜的選舉資訊整合成最視覺化、容易吸收的方式呈現。網站上線後,concurrent users 最高峰超過 20 萬 ,選舉當天及隔日的總瀏覽量突破 1,700 萬。本議題將以此選舉專頁為案例,講解我們為了聚焦選情、提升社會參與度而去構思 UI/UX 時的各種考量;同時會講解在網站的建構方面,如何克服成本、開發時程、流量高峰或如何讓媒體記者更方便地轉載報導等種種技術難題。
我是誰?
大家好,我是 Jim,來自 Oursky 的 PM。我們公司是一家為開發者開發工具的公司,除此以外也會承接各類軟體開發專案。很榮幸受到 MOPCON 的邀請來到高雄。
去年,我們為客戶開發了一個網站。那個網站在一個晚上收到了來自 200 多萬個用戶、共一千多萬個 page view。而保持它整晚都在線、沒有當機的背後,就只有一台 GCP 上面的小型 application server。最後我們收到的帳單大概是在 3,000 元港幣上下,換算成台幣的話差不多是一萬兩千元左右。
在我繼續講我們是怎麼辦到之前,我想要多講一些背景資料幫助大家理解整個來龍去脈,還有這個案子是怎麼關連到我們今天關於社會參與的主題。
到這大家可能已經聽出來了,雖然在台灣這三年多來,我有努力想把國語講好,但還是會有一點香港的口音。如果有咬字不清楚的話,再請大家多多包涵。
技術外行
另一點關於我個人想要提一下的是,我其實並不是一個有強大技術背景的 PM。我大學主修的是人文學跟傳播而不是資工 / 資管,勉強只有在大學畢業前自學寫程式兩三個月。
我在畢業前幾個月開始學程式主要是有兩個原因:
- 我看了那部關於 Facebook 的電影,然後覺得,嗯,好像沒有很難。不然我也來寫下一個 Facebook 發大財好了。
- 但更重要的是,不知道剛才大家有沒有聽清楚,我大學唸的是人文學跟傳播,在香港相關的工作都不算很有前途。反正那時候是覺得,嗯,如果我真的跑去當記者的話,應該會餓死吧。
這算是有點在開玩笑啦,但我提起這點的原因是想要先講好,我今天沒有要很詳細地講關於技術實作的細節。我的重點會是講一下我們當初去做這個專案時,一些關於設計、功能的考量,還有 high level 講一下我們所用到的架構。
關於 PM 的工作
那大家可能會想問,我來到這個科技年會,但沒有要講技術細節,那你有甚麼好講的呢?
的確,在我的印象中,會有一些工程師不太知道 PM 到底是幹嘛的 — 畢竟 code 都是你們在寫嘛,設計都是設計師在做嘛。
作為一個 PM,我覺得我的工作是跟客戶合作,確定他們想要做的產品的需求跟具體的方向;再一步一步確定具體的要求跟細節。在這個過程中,有時候我會需要告訴客戶:吼,你這個需求可以,但那個不行啦太貴了,或者這個要求不 make sense 啦。那當然,有時候我們也需要告訴我們的工程師說,我們盡力了,但客戶就要求這樣嘛,不好意思,還是要這樣做。
但這都只是基本,對不對?除此以外,我覺得我的工作還有別的部份,或是說,我希望自己可以做到的更多 — 那就是站在不同人的立場,去為他們設想。
這些不同的「人」,包括客戶、開發團隊,還有更重要的,是產品推出後,最後的用戶們。
為他們設想,不止是提出我們需要開發哪些功能才能完成客戶想要的目標、或產品具體的 UX 跟介面的設計該怎麼樣才不會讓用戶覺得很難用。更多時候,為他們設想是去「保護」他們:比如說,保護客戶的預算,避免他們因為開發一個專案而做到要吃土;或是擋掉一些改來改去的要求,保護開發團隊的時間;還有更重要的,保護產品的用戶的利益跟隱私 — 例如當客戶要求在程式裡建立一個後門,或客戶要求我們盡可能多收集用戶的個人資料的時候,我們要跟他說不行,你這樣會被警察抓走。
我自己覺得,這一點還蠻重要的。雖然我們平常做事情的時侯,不一定會這樣覺得。但其實我們這些開發軟體的人,很大程度上決定了用戶會看到什麼和知道什麼。舉個例子,在 Facebook 做心理測驗的人,可能只是想要知道自己最像哈利波特裡面哪一個角色,而不太會想到他們其實正在把自己跟好友的個資送給背後的公司拿來操控選舉。
就因為用戶在一個應用程式裡點擊了一個按鈕後所發生的事,很多時候比他們想的要複雜許多;我認為,當我們在寫軟體的時候,為用戶設想更多,為自己做出來的產品負責,是我工作的一部份。正如在無人駕駛汽車開始出現在路上的這個時代,相信大家都會希望負責寫有關程式的那些工程師,除了思考要怎樣讓汽車在路上奔馳以外,也會想一下坐在汽車裡面的乘客,在外面的行人和其他的車輛吧。
講得好像跟我剛才提到的那個案子有點遠了— 但我可以負責任的說我等一下要講的案子裡的那個客戶,從來沒有要求我們收集別人的個資或是開發什麼殺人機器人,我剛才只是想要講一下我的工作裡,需要考量到用戶的利益。但其實今天要講的,更大程度上,是另一邊的故事 — 也就是我們考量到客戶有限的預算和時間下,如何做出一個還算成功的產品。
我們做了什麼?
講了那麼久,那我們做的到底是什麼,又做到了什麼呢?
好,那我們來看看 — 這就是我們最後做出來的產品。它除了很輕量、很耐操以外,也有一些人說它的設計一目了然,簡潔易懂。如果這個圖對你來說看起來很奇怪的話,其實它是一個像素版的香港地圖。這網頁本身是我們的客戶「立場新聞」為去年 2019 年香港的區議會選舉所做的網站。
假如你不是很熟悉香港網絡生態,立場新聞是其中一個比較多人在觀看的線上新聞媒體,我們也很榮幸跟他們合作好幾年了。我們主要是負責維護他們的線上服務,包括他們的網站和手機 app 等等。除此之外,當香港有一些重大事件的時候,他們也會找我們去打造一些特別的、具紀念性的,又或是為那些事件提供資訊的專題網站。
香港的選舉就是其中一種立場新聞一定會找我們做專題網站的事件。也就是說,這其實並不是他們第一次做選舉網站,我們也不是第一次幫他們做網站了。讓這一個選舉網站值得特別拿出來講的原因,在於去年的那次選舉受到香港人前所未有的關注。之所以大家會那麼在意這一次的選舉,主要的原因,還是跟選舉前後香港的反送中運動有關。
反送中運動、理大圍城
對今天的大家來講,在看過那麼多關於香港人走上街頭反送中的新聞以後,也許很難想像,其實在沒有很久以前,香港人其實是一群對政治非常冷漠的人。大部份人所關注的,只有上班、賺錢、花錢而已。甚麼政治啦、政府在幹什麼啦,其實並不是很多香港人會關注的事情。
但在去年夏天,香港政府試著要通過一項法律,讓香港人可以被送到中國大陸審判之後,香港人變了。或是說,香港人覺醒了。今天我並沒有要詳細地講反送中運動的來龍去脈,因為我相信在座很多人都已經知道那是怎麼一回事了。但如果有人想要了解更多的話,你們可以到這個網址 — 我準備了一些我覺得可以幫助大家更了解整個運動的連結給大家參考。
簡單來說,在去年選舉的時侯,香港的情況大概是這樣的:
第一、大概從去年的六月開始,很多香港人每週、甚至是每天都在發起示威遊行。所以說,到了去年十一月選舉的時候,香港在過去半年已經經歷了很多場大大小小的示威跟衝突,而衝突的規模跟鎮壓的力度也隨著事情的發展變得愈來愈暴力。也因為這些衝突,社會變得越來越分裂。一方面,有所謂的「黃絲」 — 也就是支持抗爭、對政府提出五大訴求的人;而另一方面也有支持政府、甚至是支持警察對示威活動武力鎮壓的、我們稱為「藍絲」的那些人。
第二、隨著政府對公眾集會的規定越來越收緊,警察也開始更大力度的鎮壓。在選舉前,已經發展到警察嘗試要進入香港不同大學的校園,去搜索學生們參與示威活動的證據。在這樣的情況下,很多抗爭者趕到大學校園支援,阻止他們進入大學校園來保護學生。雙方這樣的行動,最後演變成警察包圍了香港的兩間大學:香港中文大學和香港理工大學。
事實上,在選舉當天,有些人是沒有辦法去投票的 — 因為他們被包圍在理工大學內,沒有辦法離開。
第三點讓香港人那麼關注這次選舉的原因是,這次的選舉本身是蠻特別的。我剛才有提到說,在反送中運動之前,其實很多香港人對政治都是很冷漠的 — 比如說,他們根本就不在意之前的選舉。在 2015 年,前一屆的選舉裡面,很多香港的區議會是被親政府的議員控制的,甚至在不少地區,根本就沒有選舉。那是因為在那些地區就只有一個由親政府政黨派出來參選的候選人,因為沒有對手,所以直接自動當選。
但在去年的選舉,在那麼多場的示威後,很多人都希望看到香港的改變。其中一個改變,就是很多政治素人跑出來參選,起碼要那些親政府的議員不能自動當選。所以,總的來說,雖然去年的選舉只是要選出香港各分區的區議會議員,而這些議員其實實際上對香港政府的施政的影響是很有限的。但社會因為政見不一樣而變得越來越分裂和緊張;也因為當時不少的學生跟抗爭者被警察圍困在理工大學裡面,讓很多人覺得他們需要站出來,用選票表達自己的意向,所以去年的選舉,才會受到這麼多人的關注。
困難與挑戰
雖然話是這麼講,我們都知道很多人在關注這一場選舉,但去年我們準備做這個案子的時候,其實並不知道我們確實會需要應付多少用戶跟 page view。事實上,當我開始要計劃那個開發專案的時候,情況還蠻惡劣的。有多惡劣呢?
- 當客戶跟我們正式開始討論:「好,我們來做區議會選舉的網站吧」,那時候其實距離選舉只剩一個月了。而客戶又需要最晚在選舉前一週就發佈網站。也就是說,不包含我要確定需求跟方向的時間,只計算設計跟開發這兩部份,我們也只有三週的時間。
- 在我們準備開發的時候,香港已經有另外兩個關於選舉的網站推出了。一個是我們客戶的競爭對手做的,另一個是由一個民間團隊做的。
- 我們的客戶立場新聞主要的收入來源,其實是靠他們網站裡為數不多的廣告,還有一些小額捐款。也就是說,我們在開發跟 hosting 方面也沒有太多的預算。
簡單來說,這個案子在開始的時候,面對的是一個時間和預算不太充裕、而市場上已經有別人做好的網站的局面。這個狀況,在那時候其實真的不是很樂觀,甚至當時我有想過要不要直接把網站連結到那個民間團隊的網站了。
但因為我們的客戶已經準備好報導開票的人手跟資源,不可能白白放棄報導這個事件的機會。所以,我們最後還是硬著頭皮開始設計。
設計原案和最後的產品
我們一開始跟客戶商量的計劃是這樣的:因為選舉會有三個階段,一個是選舉前,一個是開票期間,還有最後當所有點票結果出來後的結果公佈。然後我們每一個階段都會有對應的一個版本,去提供對應的資訊。每一個版本,按照原來的設想都會有一些專屬於那個階段的功能,和稍微有點不一樣的頁面佈局。
但這個方案很快就被放棄了,因為實際上我們並沒有那麼多的時間跟人手。所以計劃就變成我們要抓出在三個階段都會有的,以用戶最需要看到的資訊作為我們要做的產品的主軸。
就算是精簡到最基本的功能後,我們還是決定把其中一部份功能設定成「有多餘的時間再去做」的目標。而到最後,那些功能我們還是沒有時間把它們做出來。所以…… 是的,你們現在看到的最後成品,並不是我們一開始所計劃的完整版本。一些我們覺得很酷的功能,例如讓那個地圖可以放大 / 縮小、或者讓用戶可以直接在網站上面看到候選人的簡介等等,都沒有被做出來。
除了這些以外,其實一開始我們的計劃是做一個類似的圖表,卻是做成真實的香港地圖的樣子。也就是說,如果一切都如一開始設想的那樣,大家看到的就不會是這個像素風格的分佈圖,而是一個真實比例的香港地圖。至於我們也是很早就決定要把這個功能卡掉,主要是兩個原因:
- 第一、香港有 18 個分區,但每個分區裡面,還會分成很多個小選區。問題是,這些選區並不是用面積的大小來劃分的,而是根據居民的人數來規劃。也就是說,如果我們按照實際的地圖來做圖表的話,會有一些微小的選區很難在一個真實比例的香港地圖上讓大家看得到。
- 第二、就是很簡單的,要用程式畫出整個香港、各個地區的邊界預估要花的時間實在是太多了,我們沒有辦法在期限內做出來。
而隨著我們放棄這個功能,我們做出了一個小小的改變。也就是我們不再把每一個選區準確的對應到它在地圖上的相對位置,而是把一個分區內所有同顏色的選區放在一起。
如果我們沒有做出這個改動的話,你們看到的那個圖,那些格子會變得沒有劃分得那麼整齊,也會出現很多不同顏色的格子混在一起的狀況。現在看來,這些累積起來的妥協和改動,卻讓我們的圖表變得更容易看懂一些。
所以,如果只看完成度的話,其實最後的產品並沒有百分之百按原來的計劃做出來。但從事後的結果看來,大家都有透過我們的產品獲取他們需要的資訊。不少用戶甚至很喜歡我們的設計,喜歡到在選舉結束後的一段時間內,都有人把它列印出來貼在店裡、或是在 minecraft 裡做出來的程度。
我覺得它會那麼受歡迎的原因,在於:
- 就我剛才提到的那些原因,當時在關注選舉的香港人其實並沒有很在意那些候選人的政見或想要推行的政策,單純比較關心哪一方的候選人會勝選。這也許並不是很健康的民主選舉,但這就是當時的情況。
- 也就是在這個情況下,經我們簡化後的香港地圖圖表,反而可以很直覺地被當成香港的勢力分佈圖來閱讀。
網站的架構
設計的部份差不多就講到這裡。接下來,雖然我不會深入到每一行代碼在做甚麼的程度,但我還是會大概解釋一下我們今天標題提到的,所謂低成本、高流量的選舉網站。
其實講到這裡,我想很多人大概都已經猜到我們如何只用了最便宜的一台雲端主機,在一個晚上就應付了那天一千多萬個 page view 的流量。答案其實很簡單,我們實際上提供給用戶的,是一個靜態的網站。
我在練習今天要講的題目時,我的一些朋友都有問到為什麼做成靜態的網站會是一個解決方法。在這邊為可能有差不多疑問的人解釋一下:一般而言,如果我們想要根據一些 database 裡面的資料產生一個網站的話,我們會需要有一個網頁伺服器來處理每一個對頁面的 request。而它在收到 request 後,會根據被請求的頁面,去查詢資料庫裡對應的資料,再用那些資料來產生最後需要回傳給用戶的頁面。雖然現代的伺服器在處理每一個 request 時都已經很快了,但在沒有特別處理過的情況下,對伺服器運算能力的需求是隨著用戶的數量而增加的。
可是,如果是做成靜態的網站的話,我們等於直接跳過了那些處理請求跟查詢資料庫後產生頁面的動作,就可以直接回傳一個已經預先產生好的頁面給用戶。這樣不只是讓網站反應的速度快了許多,也意味著我們不需要準備很多台伺服器。
但你們也會想到,欸,這是一個選舉耶,我們又不會提早知道結果。那天晚上 refresh 了我們網站快兩千萬次的用戶應該也不可能會等到隔天早上、整個選舉的結果都出來後再來看我們的網站吧。
所以,我們實際上需要做的,是一個可以動態更新的靜態網站。這聽起來有點矛盾,但其實原理也很簡單。
在選舉當天的晚上,立場新聞的記者會在各個選區的開票所看開票。同時,他們會把點算好的票數回傳到總部給編輯。而他們的編輯就會在後台輸入目前收集到的資料來更新網站。
但我們不可能一直手動幫他們更新資料再上傳新的網站版本,而我們在三週的時間內,也不太可能做出一個功能齊全的內容更新系統,還做出前端的網站。所以整個解決方案大概是這樣的:
我們用 Google 的試算表,也就是 Google Sheets,做出一個既定格式的表格,提供給客戶的編輯當成輸入資料的後台。要把 Google Sheets 當成資料庫用的話,Google 提供了幾種方法:
- 第一種是他們的 Google Sheets API:他們有一個 RESTful 的 API 可以把一個試算表的內容轉化成一個 endpoint,這個 endpoint 被 request 的時候會返回一個裝著數據的 JSON 回應。
- 第二種方法也差不多,它們有一個功能可以讓你發佈整個試算表到網路上。其中也有一個選項是把它轉換成 JSON 格式的。
不過,因為有一些需要在網站上面顯示的資料並不是直接人工輸入,例如雙方得票的佔比,和一方目前已經確定贏下來的議席數目等等,都需要經過一些計算後才會得到最後的數據,所以我們還得多做一步。
除了剛才提到的功能以外,Google 其實也提供了一個叫 google script 的功能。它的作用是讓我們可以寫 javascript 去直接讀取、甚至操控一個試算表。
還有一點要提一下的是,雖然直接用 Google Sheets API 拿到 JSON 是最簡單、最直接的方法,但 Google 也不是吃素的,直接讓前端網站去調用那個試算表的 API 的話,只要用戶的人數倍增,那個 API 的收費也是很可觀的。
所以,我們為了盡量為客戶節省預算,我們還要再省一點。具體的做法是,我們在 GCP 上面開啟了一台最便宜的伺服器,讓它只做一件事情:就是每分鐘去讀一下這個 Google Sheets 的 API,看看它有沒有什麼改動。如果有的話,就產生一個新的 JSON 檔案,然後把它上傳到 Google 的雲端檔案服務裡的一個 bucket。
這樣的做法讓我們可以確保我們對運算能力的需求不會隨著我們的用戶人數的增加而上升。事實上,只要 Google 的 cdn 還維持得住,無論有多少用戶來到我們的網站,我們所需要的,都只是一個每分鐘跑一次、用來產生新的 data file 的 worker。
這個就是整個架構裡面的關鍵,其他的部份就沒什麼特別了。前端的 web app 是用 reactjs 做的,至於那個 reactjs 的檔案,連同需要載入的 html、css,都是作為靜態的檔案被用戶的瀏覽器下載的,這基本上就是我們整個前端的架構了。而整個 reactjs 的部份要做的事情,其實也沒有很複雜。當它被載入到瀏覽器後,他就會馬上去下載那個 JSON 檔案,然後根據檔案裡面的參數跟數據來 render 整個頁面。最後,它還會每分鐘去查看一下有沒有新的檔案版本 ;如果有的話就會重新下載後更新頁面裡面的資料。雖然話是這樣講,就我們最後看到的數據分析來看,大部份人應該是沒有去等那每一兩分鐘的自動更新,都是直接給你 f5 下去的。
這部份最後來總結一下 — 我們可以在有限的時間內,只用到那麼少的預算,做到一個可以應付龐大流量的網站的關鍵就在於:
- 一、 我們避開了去寫自己的 cms,讓客戶直接用 Google Sheets 來更新資料。
- 二、我們是讓用戶去下載預先產生好的靜態網站,而不是建一些 application server 去應付每一個 page view。
- 三、最後就是不讓那個靜態網站直接去讀那個 Google Sheets 的內容,而是透過一個定時產生的資料檔來獲取新的數據。
為甚麼那麼多人最後選擇來用我們的網站
上面解釋了我們是怎麼把網站做出來的,但你們可能還有一些疑問 — 我剛才有說到,在我們開始做那個網站之前,其實已經有其他人把選舉資料做成網站了。那為甚麼選舉當天晚上,還是有那麼多用戶來到我們的網站,甚至最後變得有點 viral 呢?
確實的原因,我也沒有辦法確定。但那天晚上,香港的泛民主派候選人幾乎在每一個分區都贏到了決定數量的議席。大家或許可以想像,被政府冷處理、甚至是鎮壓了快半年的那些人,慢慢看到選舉的結果時會有多興奮。從後來看到的每小時流量來看,當他們開始為選舉結果高興的時侯,他們也一直在刷新有關的網站。據說那天晚上,我剛才提到的其中一個類似的網站就因為太多湧入的流量而變得很慢,甚至沒有辦法載入。當大家等了半分鐘、一分鐘都沒辦法看到新資訊的時候,他們自然就會開始尋找別的替代品。這大概就是我們這個最晚才發佈的網站,反而會在選舉當晚得到那麼多流量的原因吧。
總結
上面講完了我們是怎樣把網站建出來,又是怎樣讓它撐過那些流量的。但你們可能會想,這跟我們今天「社會參與」的主題有什麼關係呢?
對我來說,我在這一個專案學到最重要的一件事情是,就算我坐在離家一千公里的一台電腦前,作為一個科技業的人,居然還是有辦法參與到社會的事件上面。更重要的是,我其實也沒有額外多做了些什麼,只是盡我所能把我的工作做好;還有在工作的時候,把其他人放在心上。
像剛才提到的,在整個專案的過程裡,都沒有人告訴我這個網站最後會有那麼多用戶來使用。連我自己都覺得,我們那麼晚才發佈,大家應該都會用其他的網站。而在開始開發之前,時間跟預算的限制都讓這個案子蠻不樂觀的。到了最後,當天晚上當我打開 Google Analytics 的後台,看著從 4 位數,變成 5 位數,一直到最後,我其實是滿驚訝的 — 我幾乎以為我們又被國家級的 DDOS 攻擊了。
最後想要分享給各位的訊息是,我們作為科技行業裡面的人,可能都不是大家在提到「貢獻社會」時首先會想到的人。很多時候,我們可能也不知道自己在做的企劃,到最後會是誰在使用,或有多少人會接觸到我們的產品。
但有一點是不會改變的,那就是我們的社會,正在變得越來越依賴電腦和我們寫的程式來運作。而這一點,正是我們可以參與到社會的機會。我們不一定要跑到街上,跟大家宣傳要怎麼安全地上網,或當一個白帽駭客之類。這些當然都是很棒、很重要的工作,但在這個網絡化的社會裡,我們參與社會的方法就像我今天提到的那麼簡單 — 帶著良心,做好我們的工作,為我們寫的代碼、做出來的產品負責。無論我們做的是直接在用戶電腦跟手機裡面的 app,還是他們用的 app 背後會用到的 service 或 library。
在科技業裡,大家都很講求效率和管理方法。有時候我們可能會忘記我們的工作不只是為了把待辦清單裡的 ticket 清空,而我們寫的每一行代碼,都可能會突然被幾百萬、幾千萬的人用到。
所以,為了不要在未來被有 bug 的無人駕駛汽車撞死,希望大家可以在趕進度的同時,多想一下那些跟你一起工作的人,還有那些會使用到你的產品的人。為那些人而努力,而不只是為了完成手上的工作。
以上,就是關於這個主題我想要講的全部了。
另外也想要提一下,如果大家希望知道更多有關的技術細節的話,歡迎大家直接來我們的公司找當初負責這專案的工程師了解更多細節,我們一直都有在台灣徵才喔。
另一方面,香港現在的狀況真的沒有很好,新聞自由也越來越被收緊了。如果大家行有餘力的話,請幫忙斗內一下他們。我從 MOPCON 得到的講師費也會全數捐出。
謝謝大家!