時光匆匆,2016年來了,此時的我已經工作了3年有餘。過去的三年,雖有坎坷,但總體順利,是個逐漸上升的線。
進入2016年後,我不再做那些技術探索方面的App了。部門的拳頭產品——加密通訊要新增IM即時訊息功能,類似微信的樣子,這個大功能由我來設計實現。
有了前面幾年的技術積累和探索,我們在眾多服務提供商中選擇了容聯雲通訊。
就在寫作這篇文章的時候,我還去容聯的官網逛了一圈,發現他們現在比之前提供的能力更大更強了。站在今天的視角,當時我們用的應該只是 敏捷連線->即時通訊->IM即時通訊 的能力。再加上App本身是資訊保安產品,因此並沒有採用公共伺服器,而是私有化部署方案。關於如何部署Server,我當然並不是很瞭解,直到今天其實我也不太懂,畢竟沒怎麼做過伺服器產品。
整個2016,我都在忙這個功能模組的開發。當時想法其實特別簡單,就仿著微信做就行了。功能儘可能都做出來,實在做不出來的話就算了。另外就是加上閱後即焚模式和傳送任意型別的檔案功能。沒錯,當時微信還不允許傳送任意型別的檔案。
雖然要求用這一兩句話就能說完,但實際做起來可就複雜多了。回想那段做開發的時光,有三件事讓我印象非常深刻,我慢慢說,您慢慢聽。
第一個事,就是深切地感受到程式設計基礎很重要。我記得好像是判斷一條訊息的狀態,然後更新UI顯示。就比如正在傳送、傳送失敗、已讀/未讀等等。這個過程中需要判斷兩個訊息實體是否為同一個。舉個例子,比如一條訊息是一個Message物件,傳送的時候構建了一個這樣的物件,名為textMessage,發出去了。然後Server端返回一個傳送成功的回執,也是Message物件,名為textMessageReceipt。此時,就需要定位到UI上的若干Message實體中的textMessage,只有它和textMessageReceipt是對應的。相信很多人會想到比對某個或某幾個成員變數,只要一致就代表它們二者指的是同一個訊息。我想到的是用equals()方法,但是直接用肯定不行。於是我便重寫了這個方法的實現,只比對唯一id,從而實現精準定位。類似地,還有方便Log輸出的,複寫toString()方法等等,我記不清太多,只記得複寫了這兩個。
得益於我實習期間攻讀那兩本Java大部頭,不然我也不會有這樣的思路,不會想到複寫物件的方法,很可能會卡在這個需求上很久。
所以如果正在看這篇文章的你,是入行不久的朋友。或許你已經可以透過呼叫各種API介面實現需求,併成功做成產品,然後上線,甚至還收穫了很多使用者。但要警惕的是,不要驕傲自滿,覺得自己很厲害。一旦這些API需要修改,或者碰到那些看似不可能的Bug,或是要進行效能調優等等,這些才是真正考驗技術能力的時候。單純很熟練地呼叫介面,只是“很厲害”的假象。
當然,後來這個方案又得到進一步最佳化。不再直接用兩個物件比對,而是更新本地資料庫,然後通知介面重新整理。
第二個事,就是訊息亂序。這個事,我印象極其深刻。不僅不好處理,而且是部門領導陪我一起改的。當時的我固執地認為是容聯那邊出了問題,因為我是根據時間排序顯示,電腦排序的結果總不會錯。再加上我儲存資訊的時候,就是伺服器端給了我什麼,我就存了什麼。於是乎便不認為我有什麼錯,認為是網路問題,導致後面發的訊息比前面發的訊息,提前到達對方那裡。但是部門領導還是堅持讓我檢查一下,認為這樣的結果不合理。
我抱著十分懷疑和千方百計要證明自己的想法,用容聯官方的Demo進行測試,竟然沒有問題。隨後便懷疑會不會是私有化部署的Server端才存在這個問題?於是還是用人家官方的Demo,設定伺服器地址,再次進行測試。還真別說,依然沒有問題。
這下子,我就開始迷惑了。同時,心態也變得踏實了。於是,開始腳踏實地從自己的程式碼中查詢原因了。
其實說到底原因特別簡單,我記得好像是一條訊息實體裡面有兩個時間欄位,一個是訊息建立時的,也就是傳送時的;另一個是狀態改變,或者是其它什麼操作後的時間。進行排序時,應該使用訊息建立時的時間,而不能是狀態改變的時間。
發現了問題,有了修改思路,到改的時候就變得輕鬆多了,也更有自信了。隨便測試,反正再也不會亂序了。
這個事情告訴我,出了問題時,先別管那些“看上去”就是怎樣的結論,首先在自己身上找原因。先問自己:“真的考慮了所有情況嗎?真的都做到位了嗎?真的沒有一點問題了嗎?”
其實,何止是程式設計,何止是工作。在生活中,對人對事我覺得也應該有這樣的態度。有了矛盾,就算是對方做得不好,也要先在自己身上找原因,激化矛盾只能讓事情變得更復雜難解。凡是矛盾,沒有一方是無辜的,因為“一個巴掌拍不響”。
第三個事,就是漏收訊息和來電。沒錯,這回不只是IM模組出問題,連之前的通話模組也出問題了。這就很奇怪,因為在之前,通話模組一直是不存在漏接的問題。
當然首先是查原因,無果。然後我們幾個人有點絕望,開始回滾程式碼到舊版本,還是無果。部門領導也來出主意,但是依然無果。
我記得黎明前最後的黑暗,是有一天,大家都熬到很晚,差不多晚上10點,或是11點,反正我到家之後,稍事休息就過12點了。為了測試這個Bug,還把測試機帶回家搞。搞到電池都快沒電了,於是先跑去衝個澡,順便給手機充電,繼續測試。
但是,神奇事情就發生了,我這邊就再也沒有漏接過電話,也沒有漏收訊息。我就開始分析,我好像什麼也沒做,唯一的變數就是插上了充電器。一開始我無論怎麼想,也不會猜到電池是問題的根源。我是抱著死馬當活馬醫的態度,拔了充電器。然後便又開始漏訊息了,電話也接不到了。這個時候,其實我就很接近事實真相了。我再次插上充電器,發現一切開始變得正常。
當時,我意識到,這個問題我就要解決了。我趕快到系統設定裡,調整智慧省電、新增App常駐白名單、黑屏後不自動斷開Wifi等等。隨後再怎麼折騰,也不會漏掉訊息和電話了。你看,最後的找到問題的根源,竟然是手機設定……
於是,後面便與手機廠商展開合作,將我們的App新增到預設白名單保活,這個嚴重的Bug就這樣被解決掉了。
現在看來,這個經歷告訴我兩個道理:一是堅持,就像拔蘿蔔那樣。就是很簡單又很經典的一句話:“堅持就是勝利”;二是開啟思路,問題的數量終歸是有限的,但解決問題的方法是多樣的。當局面陷入僵局時,不妨先冷靜一下衝個澡,隨後換個思路,也許就能找到問題的出口了。
說個題外話,也許是這段經歷,讓我竟然愛上了洗澡。大部分時候,洗完澡都會精神煥發,疲憊的身心又再次充了下電,比咖啡都好使。
新增IM模組,搞了一年。常規的單聊、群聊都已經實現。訊息的型別除了常見的文字、圖片、語音外,還支援名片、短影片、檔案、定位等等。當然,這些訊息內容都是經過加密處理的。
搞完這些,2016年其實就已經結束了。
另一方面,雖然工作漸漸變得飽和起來,但是我依然沒有停止探索和寫作。在這一年裡,我開始使用Markdown寫檔案,用墨刀設計產品原型,註冊了簡書賬號,開始產出內容。從當年的收件箱中,我發現我的文章不斷地被加入某些技術專題,不斷有新的人關注我的賬號。探索GitHub Page、GitBook、Mapbox等等。也似乎是在這一年,我在CSDN認證了部落格專家。
哦,對了,還有前一篇我提到的樹莓派。說到樹莓派,就不得不提2016年是我開始獨自生活的元年。從我上面說的經歷上講,這一年過得算是充實。但很拮据。房貸+車貸,真的有壓力。那段時間恰逢Uber和滴滴搶佔市場,無論是乘客還是司機,給的補貼都不少。於是我也出去當司機,企圖能多有一些生活補貼。
那個時候早上6點多出門,跑早高峰;下午5:30下班後就開始上班,跑晚高峰。到晚上10點後收工,週六日偶爾加班,不加班的時候偶爾也出去當司機。平均算下來,差不多7106的強度,比行業中常見的996稍微再辛苦一點點。直到有一天晚上,我準備收工,行駛在快速路高架橋上。實在太困了,就點了一下頭,再回過神來,車已經偏離了一個車道。一下子我就精神了,不困了。也正是有了這一次,我就不再那麼辛苦了,畢竟生命更重要。再之後好像經濟上就沒那麼緊張了,我也就不怎麼當司機了。
當時我自己住的家裡,因為沒多少錢置辦傢俱,其實有一點點家徒四壁的感覺。家裡只有沙發、衣櫃、床是新買的。像音響,是從父母家搬過來的。再也就沒有什麼其它的東西了。對,電視沒有,寬頻也沒有。我還清晰地記得我在次臥裡面打電話,房間裡都會有回聲。我還擔心對方聽起來我的聲音會奇怪,滿屋子找合適的沒有回聲的地方。
不過,也正是這樣的條件,讓我養成了獨處的習慣。正如《烏合之眾》一書說述,陷入集體情緒中的人是不理智的,會盲從,使一個民族的大部分人都處於同一水平。多個個人一旦形成群體,就會出現智力下降、易於衝動和自信倍增的心理特徵。所以有些時候,獨立+思考往往比待在群體裡,更冷靜,更清晰。再加上沒有短影片、遊戲等等消耗我的時間,雖然看上去我做了不少事,但是事情都能安排得很有條理,做起來有條不紊。
那個時候,我主要的娛樂活動就是聽音樂、看一些小說。聽各種古典音樂,與那些來自幾十甚至上百年前的作曲家/演奏家對話。樹莓派就是當作DLNA伺服器,給音響輸出音訊訊號用的;看《三體》、《解憂雜貨店》、《消失的地平線》之類的暢銷小說。還特意買了刻章,每本我讀過的書,都要印上“文翰藏書”四個字,表示這本書是我完整看過的。如果有一天,它從二手書市場上流轉,到了某個有緣人的手裡。又在某種機緣巧合下,我和那本書再度相見,那種感受,想來也是極好的吧。
2016這一年,雖然過的拮据了一些,但是精神上我很充實,很富有,養成了獨立思考、不盲從、愛讀書的好習慣。直到現在,我依然很懷念這一年的時光,它教會了我很多很多……