[心得] BBS 後端實作期中報告

軟工

35340



各位 Soft Job 的版友大家好,我是 Pichu,半年前在這個版徵求關於 BBS 後端開發的
人力(#1W1OxYB8 (Soft_Job)),很感謝大家的支持


這篇文章主要是和大家分享這半年來我們大致上做了哪些事情,
影片整理則會於 7/31 釋出。


一月中的文章我們列了十三點需要處理的問題:

```
1. 介面/商業邏輯/資料庫的程式碼混在一起,造成調整使用者體驗上以及使用者介面
上調整困難。
2. 程式碼缺乏註解,可讀性極低。
3. 原先的程式碼完全沒有 testing code.
4. 程式碼完全沒有 benchmark 機制,修改架構仰賴設計者的威望而非科學證據。
5. 大部分的架構仍然使用 32 位元的時間表示方式,這會導致 2038 問題。
6. 密碼仍採用基於 DES 的雜湊方式,換句話說,強度不足。
7. 過度仰賴共享記憶體的設計造成伺服器分散困難。
8. 索引檔儲存方式彈性不足,不易新增新欄位。
9. 轉信機制死亡已久。
10. 站內訊息 (水球)、站內信無法透過手機即時通知使用者。
11. Current PTT 程式碼尚不支援 IPv6.
12. 站內文章仍然使用 Big-5 儲存,不支援 emoji 或是台羅拼音。
13. 不支援圖片上傳、音訊或是視訊通訊。
```

而目前大致上處理了這些問題


```
V 1. 介面/商業邏輯/資料庫的程式碼混在一起,造成調整使用者體驗上以及使用者介面
上調整困難。
V 2. 程式碼缺乏註解,可讀性極低。
V 3. 原先的程式碼完全沒有 testing code.
4. 程式碼完全沒有 benchmark 機制,修改架構仰賴設計者的威望而非科學證據。
5. 大部分的架構仍然使用 32 位元的時間表示方式,這會導致 2038 問題。
6. 密碼仍採用基於 DES 的雜湊方式,換句話說,強度不足。
7. 過度仰賴共享記憶體的設計造成伺服器分散困難。
8. 索引檔儲存方式彈性不足,不易新增新欄位。
9. 轉信機制死亡已久。
10. 站內訊息 (水球)、站內信無法透過手機即時通知使用者。
11. Current PTT 程式碼尚不支援 IPv6.
12. 站內文章仍然使用 Big-5 儲存,不支援 emoji 或是台羅拼音。
13. 不支援圖片上傳、音訊或是視訊通訊。
```

這篇文章會以兩個大的部分來介紹分別為 協作方式 以及 技術架構

協作方式會以技術上較淺顯的方式介紹,技術架構部分則適合想要加快上手時程的工程師



>>>>> 協作方式 <<<<<


: 但是我個人有個額外的請求,因為有先前在 Soft_Job 上提到的「東京都新冠肺炎對策
: 網站(https://stopcovid19.metro.tokyo.lg.jp/)」的經驗,我還是希望能做到是由社群
: 的多數人共同完成這個專案,而不是如同多數在台灣的開源專案,是由固定幾個「大神」
: 來完成的。
: 原則上軟體專案人數的增加並不會增加開發效率,反而還會降低效率,但是開發人數過
: 少的專案反而會有公車指數(bus factor)過低的問題,也就是少數幾個人離開專案就會導
: 致專案進度停擺或是沒有人能繼續維護。
: 因此我會希望邀請有興趣共同開發的工程師加入,大約一週兩到四個小時的時間就可以
: 了,而我自己扮演的角色會傾向專案管理的角色,準確有效率的分配任務給貢獻者們,同
: 時能確保工作進度和程式碼品質。這對我個人而言也算是具挑戰性的任務。


上面是這個專案另外重視協作方式的一個初衷,先前在台灣的開源專案中其實不少專案到
後來經常會變成只有一個人的專案,一個人的專案有可能變成什麼情形?


: When I wrote this code, only God & I understood what is did.
: Now... only God knows.


可能一開始寫的很順,然後到後來變成自己懂而已,程式碼放個半年一年之後換連自己都
不懂了。

那在原本 pttbbs 的 C 程式碼中其實他本身是運作良好的程式碼,只是到後來變成新進
的大學生其實不是很能完全看得懂上面的東西,也就造成了後人真的有辦法大規模去修改
他的人也變少了,因此在確立協作方式上面會是我希望達成的一個目標。


不管是在當時一月出的時候還是現在,我都覺得東京都的 covid19 專案還滿厲害的,因
爲他可以持續地保持多人協作,這點在台灣的開源專案來說是十分少見的,也因此這個
也是我目前持續投入這個專案的主因,因為我想找出來有沒有辦法找出一種讓專案可以
長期由工程師以及社群,透過個人可負擔的成本令這個系統可持續發展的機制。


也就是說,今天說叫一個工程師每天上班幾個小時後還要花幾個小時在這個專案上,長久
下來是沒辦法持續的,他還有其他工作,可能隨時間過去也會對其他的 side project 有
興趣。或者是說也不是所有人都和我一樣工作時間比較自由,不用上下班打卡,但是長久
下來其實還是有受到影響,像是我沒辦法花比較多的時間在有付錢的客戶上嘛。


可是如果說今天每個工程師都是每週花幾個小時,大概兩到四個小時這樣,這樣可以換到
什麼?換到一個可以和時代一起進步的 BBS 系統,然後不會說受到政府言論審查或是說
因為商業上的關係比需要做一些折衷的平台,那其實這樣換起來很划算不是嗎?

不過開源這件事情還真不是把程式碼公開在網路上後標示開源版權,接下來就會收到一堆
貢獻者提交程式碼的,在 Ptt-backend 這個專案之前我至少失敗了大概也有四五次,這次
看起來有稍微成功一點,因此在這邊和大家分享目前這個專案的協作方式:


首先是這個專案的數據部分,在發文的第一天我收到了極大量的站內信,後來做了基本的
問卷調查。

在第一天有回應的大約有 38 人,前十天從 1/20 ~ 1/30 報名的人數約 97 人,
截至 7/20 總共報名的人數是 119 人。

而參與者的時區除了在台灣以外,還有在日本、美西以及德國的,因此我們的做法是每週
會釋出一次影片,然後在影片後面附上問卷讓大家問看看本週有什麼問題,下週再作分享

目前每週影片到寫文時持續了 26 週沒間斷,下圖是各週回覆的問卷數據

https://imgur.com/a/tltilZE


┌──┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
│週次│ 1│ 2│ 3│ 4│ 5│ 6│ 7│ 8│ 9│10│11│12│13│14│15│
├──┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|人數│34│48│26│22│23│20│20│18│14│13│11│16│19│11│13│
├──┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
│週次│16│17│18│19│20│21│22│23│24│25│ │ │ │ │ │
├──┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|人數│ 8│ 8│11│ 9│ 6│ 8│ 6│ 4│ 5│ 2│ │ │ │ │ │
└──┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘


圖片上另外加了一條對數回歸線作為參考,顏色較深的是問卷回收數量較淺的為回歸線,
第十三週的部分人數有稍微變多,推測原因是 4/14 的時候因為前兩週回收數量即將低於
十人,因此在 4/14 的時候刷了一下存在感,所以有些參與者有另外和我要當週和前一週
的影片,因此在該兩週人數有小幅上升。

https://imgur.com/fFKTPjh


圖中這個是 Ptt-backend 也就是我本次負責的專案的提交 (Commit) 次數,上面那條線是
40 次,第二條是 20 次,每個柱狀單位是每週,因為在每次程式碼的修改後都會留下一次
提交紀錄,因此他可以代表這個程式碼倉庫實質上變動的活動量,可作為專案健康度的參
考指標。


https://imgur.com/bWvVJUL



那我們如果將這兩圖疊合的話就會發現到有微妙的關聯性

有關聯性的部分是在一開始人多的時候確實提交次數有比較多,但是開始沒多久後明明人
數還很多,但是提交次數卻下降了,目前的推測是這樣:在剛開始專案剛被介紹出去時,
會有許多人提出主觀的修改意見,其中包含許多有建設性的修改,因此在專案初期因為一
人專億造成的問題會得到緩解,舉例來說,這個專案一開始的 user id 這的變數名稱是用
userId 這樣的格式寫的,這是我個人平常習慣的拼法,但是有人提出修改建議說應該要用
userID 這樣的格式。當然他提出這個意見背後還有提出 Golang 官方的文件作支持,所以
就接受這樣的修改了。

另外還有像是調整程式碼架構便於未來可維護性等等的。

那像這樣的修改本身對於功能推進的實質幫助並不直接,不過確實可以呼應到我們專案一
開始的其中一個目標:「增加可讀性、減少技術債」。


不過當這些東西被處理到一個段落後大家就會陷入一種「不知道要做什麼」的困境,到了
二月多的時候實際上我們還在探索應該如何進行,然後新增程式碼檢查工具 (lint) ,然
後又產生大量修改,之後合併回去之後又不知道要做什麼了。


https://imgur.com/Clkc6qR


因此在第七週的時候我們最了一份問卷調查,詢問是不是需要有人幫忙指派任務這樣,大
概有四分之一的參與者回答需要,加上可以的話超過一半,所以後來我們做了一份表來紀
錄每個參與者目前狀態,例如在忙哪個項目,每週照順序分配這樣。

按照這個方法其實在四月初到五月的時候取得了還不錯的效率,因此就把一些簡單的功能
完成了。比較困難的部分例如進行整個系統的整合測試以及確認寫入文章的做法是從5/18
這週開始,此時在圖形上就很明顯看到一個洞,那也凸現分配法的大缺點:

如果沒人分配工作的話那工作進度會大幅度慢下來。


接著到六月多,六月多開始第一次整合測試完成了,因此測試出一大堆 Bug,
因為分配表名單和影片問卷回覆沒有連動的關係,所以後面又寄送了一些邀請給分配表的
參與者,所以看到整個提交次數又開始上升了這樣。


因此綜上所述,我們可以抓到幾個目前觀察到的小結論:


1. 專案一開始的參與者會時間自然流失,流失曲線大致上會呈現對數下降。
2. 實際上的提交數量和參加者目前的數量似乎只有在剛開始有明顯關係。
3. 明確地把任務分配出去確實可以增加專案執行的效率。



接下來在進入技術架構之前我想要先把這專案開始半年以來的貢獻者們放上來,
除了做個紀錄以外也感謝大家這段時間的配合這樣。

https://imgur.com/9DX6qb8



>>>>> 技術架構 <<<<<


接下來的部分會進入這半年來技術架構的簡單整理

從這邊後面的東西會比較困難,可能會需要有點工程師背景才會比較容易看得懂

這個專案分成兩個部分,第一個是做為資料庫管理系統 DBMS 的 go-bbs 函式庫,
以及作為應用系統的 Ptt-backend 兩個部分。

首先先介紹 go-bbs 的部分


Filesystem Controller Backend
Storage (Worker) Web
┌─────┐ ┌─────────┐ ┌─────────┐
│ BBS │ Ptt-official-app/ │Ptt-official-app/ │
│ Content │←────go-bbs ←──│Ptt-backend │
└─────┘ └─────────┘ └─────────┘


那在 BBS Content 裏面純放的是實際上例如大家的帳號密碼以及文章紀錄等
你可以把它想像成像是 MySQL 資料庫也有個 /var/lib/mysql 的資料夾存放原始資料


因此在業界謠傳 BBS 沒有用資料庫的這個說法基本上是錯的
正確的說法是目前使用 MySQL 或是 Oracle 這類基於 SQL 的資料庫系統的 telnet-based
BBS 十分稀少。


那除了 SQL-based 的 RDBMS 以外
https://imgur.com/8s19K2d



┌─────┬──────
│ 名稱 │ 資料模型 ...
├─────┼──────
... ...
├─────┼──────
│MariaDB │ RDBMS
├─────┼──────
│MongoDB │ NoSQL
├─────┼──────
│MySQL │ RDBMS
├─────┼──────
│PostgreSQL│ ORDBMS
├─────┼──────
│SQLite │ RDBMS
├─────┼──────
... ...

Src: https://reurl.cc/Nro2p9

這個世界基本上還存在著各式各樣不一樣的 DBMS ,就已上表為例,像是 MongoDB 我們
不會說他是 SQL 但是他確實也是一種資料庫,那他就是非關聯式資料庫架構的 DBMS。

因此在目前大多數的 telnet-based BBS 系統當中,其實資料庫是以索引檔和文章檔的方
式井然有序地放這著的,只是目前並沒有特別去開發一個程式介面來存取這些文字檔而已

因此我們需要一個抽象的程式介面讓大家能夠存取 BBS 系統中的這些檔案,這個就是
go-bbs 這個專案的目的。

順帶一提,也不是所有的 BBS 都排斥不使用關聯式資料庫,有些 BBS 系統還是有用到
SQLite 的喔。 eg: https://reurl.cc/3aQk4O


那在 go-bbs 裡面定義的基本上是操作 BBS 資料庫所支援的 Golang 介面,舉例來說像是
讀取文章、新增文章紀錄、讀取使用者資料等等的,並不包含實際上的權限管控。

另外在 go-bbs 的設計也不是只支援 pttbbs 這一套 telnet bbs 系統而已,在一開始的
設計預想中是希望他可以去支援其他種類例如 maple 3 的 bbs 系統。


這樣的設計和 Golang 的 database/sql 套件設計類似

https://imgur.com/Wlv6uMX


src: https://pkg.go.dev/database/sql

一個套件來定義介面含基本的操作,然後再由其他套件來實作符合這個介面的 driver ,
因此只要其他種類的 telnet bbs 實作了 go-bbs 的介面之後,基於 go-bbs 設計的應用
程式就能夠套在他上面了。


----------------------

接下來是 Ptt-backend 的部分

Filesystem Controller Backend
Storage (Worker) Web
┌─────┐ ┌─────────┐ ┌─────────┐
│ BBS │ │Ptt-official-app/ │ Ptt-official-app/
│ Content │←────│go-bbs │←──Ptt-backend
└─────┘ └─────────┘ └─────────┘


這是這個專案比較屬於應用層的部分,他負責商業邏輯判斷、轉成下一個客戶端聽得懂的
介面格式以及和 go-bbs 或是其他新的資料庫拿資料的任務。


那基本上 Ptt-backend 也會是新進來的參與者推薦先入門的地方。
如果要讀 Ptt-backend 程式碼的話,會推薦從 internal 這邊作為起點

Internal ───┬─── Delivery

├── Usecase

└─── Repository


internal 是在 go 1.4 開始的一個 feature ,在 internal 裏面的套件只能被他上層的
套件或是同個 internal 的套件給 import 進來,因此我們不用擔心修改了 internal 內
的程式碼會導致其他人 import Ptt-backend 這個專案時發生不相容或是 breaking
change 的狀況。


上面有提到 Ptt-backend 最重要的三個任務
存取 go-bbs 資料庫
商業邏輯
把資料轉給 Client 端



因此在進行功能開發或是修改的時候,可以先想一下這個功能牽涉的是 Ptt-backend 的
哪個任務,然後再點進去那裡面。

會這樣切的細節原因請參考 Ptt-backend 的 ISSUE#16 ,裏面原始的設計者有提到完整的
想法。
https://github.com/Ptt-official-app/Ptt-backend/issues/16



整體而言我們不會排除說未來的開發者有可能找到新的 repository 的儲存方式來取代掉
原有的 go-bbs ,舉例來說,可能把它改成分散式的系統。


Delivery 的部分則是實作目前的 RESTful API,不過我們也希望他可以回頭支援原本用上
下左右 VT100 的 BBS 介面,否則我們就沒有真正可以取代掉原有 C 程式碼的一天。
再來是目前其實也有效率比傳統 RESTful API 還要好的介面被發明了,像是 gRPC ,或者
是不斷有人希望使用特定的 HTTP Framework,這部分可以透過新增新的 Delivery 套件來
實現。


Usecase 切開的話則是我們就可以比較簡單的針對商業邏輯去寫 Unit Test 而不會被
HTTP 套件困住。

--------

Internal ───┬─── Delivery

├── Usecase

└─── Repository

Delivery

* 實作文件上的HTTP 介面
* E-tag, Authorization Header, if-not-modified
* 依照 HTTP 本身的特性去做流速限制

* 建議從 route.go 的第八行 build Route 開始看
* 文件檔案部分可以參閱 RESTful API 文件 (Google Docs) https://reurl.cc/R0o849


Delivery 目前是先實做 HTTP 的介面,因為 HTTP 的 RESTFul API 目前可以說是業界共
通語言了。

在 HTTP 的設計理念當中最重要的部分是快取機制,也就是 Body 在原文沒有更新的前提
下不需要重送,那目前在 Telnet BBS 系統中,即使是用 WebSocket 來瀏覽 PTT 文章,
使用者還是要左左右右進進出出才知道有沒有人在下面有新的回應或是在看板上發文,那
在這邊左左右右進進出出其實有很多資料是重覆傳送的,透過一些快取機制的話, HTTP
請求在同個資源第二次發出時會多幾個 Heade,和伺服器說「如果這個資源什麼時候以來
都沒有改變過,那就不用再送了,我這邊已經有了」

如果要讀這份套件的話,建議從 route.go 的第八行開始看,另外可以同時參考上面的放
在 Google Docs 的RESTful API 文件

--------

Internal ───┬─── Delivery

├── Usecase

└─── Repository

Usecase

* 實作權限檢查
* 檢查 repository 來的東西是否需要型別轉換
* 串接不同的功能

Usecase 裏面主要做權限檢查以及實作商業邏輯,例如說把文章轉寄回自己信箱、或者是
判斷某個文章發文 P 幣應該要如何計算等等的。

在這個地方的檔案會以功能來進行分類,像是 article, board, mail, user 這樣。


--------

Internal ───┬─── Delivery

├── Usecase

└─── Repository


Repository

* 檢查 repository 來的東西是否需要型別轉換
* bit 操作
* 資料庫層的快取


Repository 的部分主要是串接 go-bbs 然後把原本的東西轉回成 Ptt-backend 內部的資
料結構,例如在這邊做 bit 操作等等的。

另外由於 go-bbs 和 Ptt-backend 開發上的時間差,因此目前在 repository 中有不少
函式還是處於回傳假資料的狀況,需要有人幫忙串接實際上 go-bbs 已經開好的介面。


==================================


接下來是另外一個剛進入這個專案的常見問題:


為什麼 Ptt-official-app 下面會有這麼多 repo

https://imgur.com/uOH8mAx


間單來說就是發生了「一個中台各自表述」,一中各表的兢爭狀況...


首先這個問題本身是有歷史因素的,最早來說 PTT APP 的專案並沒有打算採用 Golang
,而是透過 ASP.Net 架設一個「中台」來暫存資料,接著手機 APP 發文的資料不一定會
寫回原有的 PTT 的站上,而是滯留於中台。主要原因在於當時沒有人可以幫忙讀懂
pttbbs 的 C 程式碼,再來是原本的系統站長比較忙,不一定會有時間幫忙處理 PTT
APP 的計畫。

因此最初打算在不更動後端的前提下透過中台的機制去實作這個 PTT APP 計畫。
後來 CodingMan 加入,他是知名的 Ptt Python 函式庫 PyPTT 的作者,因此中台的實作
就從原本的 ASP.Net 變多一個由 chhsiao1981 (老蕭) 用 Python 實作的中台,差不多我
是在這個時候我這邊加入。
因為先前管理 Formosa BBS 的關係,很早以前就認為 BBS 程式碼需要大的重構,因此就
提出用 Golang 來實作讀取 BBS 硬碟上檔案的計畫。

只是在這邊的計畫並不一定最終會被 PTT 系統站長那邊認可採用,因為直接讀取硬碟上
的檔案需要將程式跑在原有 PTT 的主機上面,因此一旦這套程式有漏洞的話,造成資安
上危害的風險相對來說也會比較大。

但是就如同最初提到的問題,包括 32-bit 的時間格式以及基於 DES 密碼系統導致強度
不足等問題,如果希望PTT能夠持續活下去的話,go-bbs 這個專案還是有發展的必要。
再加上初步測試從登入到讀取文章,證實基於 Golang + HTTP 的架構效能確實比 C +
VT100 快一點點之後,好像就更有投資的價值了?


後來老蕭也來幫忙送 PR 到 go-bbs 的 repo 來,不過基於他送的部分可以說是只是單
純的把 C 程式碼用 golang 改寫過,在可讀性上沒有改進多少以及大量不確定有沒有被用
到的變數還是被送入 PR 的前提下,在 code review 的時候變得十分尷尬,具體可以參見
go-bbs ISSUE#8 https://github.com/Ptt-official-app/go-bbs/pull/8


而在老蕭質疑說為什麼不把 go-bbs 的 Repo 移動到後來才開立的 Ptt-official-app
orgname 底下,最後他就直接從 go-bbs fork 出一份 go-pttbbs 了。
那原先老蕭要用 python 開發的中台變成了老蕭用 go 開發的中台,叫做
go-openbbsmiddleware 這個 repo ,串接老蕭自己的 go-pttbbs



Pichu Chen:

| go-bbs | <-- Golang function call -- | Ptt-backend |
Protocol 文件在 Google Docs 上

開發機: pttapp.cc



chhsiao1981:

| go-pttbbs | <-- go-pttbbs protocol -- | go-openbbsmiddleware |
文件在 https://api.devptt.site:8080/
文件在 https://api.devptt.site:5000/

開發機: www.devptt.site


所以大概是這樣,原先希望的架構是老蕭那邊用 Python 寫的中台可以直接透過
CodingMan 的 PyPtt 串接 PTT 主機的資料,後來變成了兩個「中台後端」的競爭狀況。
那兩套後端系統也各自有自己的開發測試環境,目前這個文章介紹的的主要是上面 Pichu
Chen 的版本,他的開發機是在 pttapp.cc 上面,下面老蕭的版本是在 devptt.site 上
面。


===========================================

那就目前的開發進度以及開發速度而言,要決定出採用何者的版本應該還需要半年到一年
以上的時間,畢竟現有的 C 程式的版本大致上還可以活至少十年 (到2038),如果希望提
早測試新的版本的話,可以到 pttapp.cc 上面註冊資料發文測試,1註冊時請注意嚴禁使
用真實個人資料,包括密碼也請不要和現有密碼相同,因為上面的資料會作為開發使用讓
大家自由下載,同時也有可能有漏洞導致資料外洩這樣。


目前我們能做的基本上就是維持每週都有小進度的節奏,然後把這個專案推廣出去,用這
樣的方式去達成這個新一代的BBS程式碼的永續開發目標。


--
我得了一種在BBS上發完文後會打:wq的病...
:wq

--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 36.230.206.42 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/Soft_Job/M.1627460397.A.2DB.html
ntpuisbest1樓首推 07/28 16:22
loadingN2樓文長 shift + g 07/28 16:37
y24681012163樓 07/28 16:45
BlazarArc4樓 07/28 16:49
duck107045樓推啊 讚 07/28 17:28
summerleaves6樓 07/28 18:05
SmallDruid7樓太多了吧 07/28 19:02
kewang8樓先推!7/31 所以是 coscup 今年的 talk 之一嗎? 07/28 19:11
kbjent804599樓 07/28 19:39
jack4210710樓重構BBS 太神了 07/28 19:42
Burwei11樓推 辛苦了 07/28 19:46
knme12樓 07/28 21:01
jack9130313樓先推 07/28 21:08
kuochuwon14樓偉業,只會python的我只能默默祝福 07/28 21:37
Chen33415樓不知道可不可以開放小額募款,想盡一點力 07/28 21:48
zero1199516樓 07/28 22:08
jasonwung17樓未看先推 07/28 22:21
wulouise18樓所以現在有三個專案同時在跑? 07/28 22:55
LEwww129019樓 07/29 00:41
tttkkk20樓優秀 07/29 01:33
MoonCode21樓看不懂但是覺得很厲害 07/29 01:40
taipoo22樓辛苦了 07/29 02:33
nicetw20xx23樓好厲害 07/29 07:16
WaterLengend24樓推推 07/29 10:09
ian9091125樓感謝分享 07/29 13:50
kcjgg26樓 07/29 16:39
Stoat27樓 07/29 17:01
oscarchichun28樓 07/29 22:37
markbex29樓推!從你們的討論也學到很多 07/30 01:47
ekong686230樓 07/30 19:29
更多心得
[心得] Leetcode 刷題解答與 Python 3 小技巧分享
[心得] 2021新鮮人面試心得(SDE/MLE/Quant)
[心得] golang 工程師半年無薪心得
[心得] Google TW SWE 面試心得(下)
[心得] 面試-Grab/Appier/Google/Facebook
[心得] Google TW SWE 面試心得(上)
[心得] 2021年-非本科系菜鳥前端面試心得
[心得] 非本科無經驗前端轉職心得