我是雙週報主筆 Li [IG 連結]。在這一期開始前想跟大家分享 ExplainThis 最近除了 IG 帳號外 [連結],也經營了 Threads 帳號 [連結]。
除此之外,ExplainThis 另個共同創辦人 PJ 也將在 Threads 分享從 junior 邁向 senior 後端工程師的內容,推薦大家追蹤 PJ [連結]。
講完了 ExplainThis 的近期更新,接著讓我們進到本期的正式內容吧 🙂
[前端工程] StyleX 是什麼? 解決了什麼問題? 適用在什麼場景?
最近 Meta 開源了內部使用的 CSS 解決方案 StyleX,不意外地引來社群的一陣討論。事實上,StyleX 並不是什麼新東西,早在 React Conf 2019 時的《Building the New Facebook with React and Relay》講座中,Frank Yan 就已經提到了,只是當時這個工具還沒被開源。在這一期雙週報,我們從 Frank 當時的講座出發,來跟大家聊聊 StyleX。
在這之前,先請大家帶入兩個情境,首先,假如今天你要去面試前端工程師職位,當被問到「StyleX 解決了什麼問題? 適用在什麼場景?」你該如何回答? 假如你還沒辦法解釋、分析與比較,以及選擇是否用 StyleX,那就讓我們一起往下看吧。
首先,StyleX 是個樣式系統,它做的事情是透過編譯的方式,把樣式轉成原子 CSS (atomic CSS)。原子 CSS 解決了許多問題,而對於程式碼可維護性上帶來一些好處。
其中一大好處是 《淺談 Atomic CSS 的發展背景與 Tailwind CSS》提到的「在改樣式的時候,你可以直接把 class name 刪掉而不用怕影響到其他的元素,這是多麽美好的一件事情,你再也不用擔心改 A 壞 B,因為 class name 都跟 context 無關了」,這是 StyleX 文件中提的 colocation 能帶來的好處。
讀到這你可能會問說,寫純 HTML 或用 Svelte 這類框架,把 <style>
跟 HTML 放在同個檔案,又或者用 CSS Modules 這類工具,也可以確保 scope 被限縮,不用擔心改 A 影響到 B。但這仍會存在一個問題,就是不容易規模化。
在《淺談 CSS 方法論與 Atomic CSS》有提到原子 CSS 的另一個核心是「Define once, use everywhere」意即定義一次後全局都可以使用。這裡說的定義一次,代表著不改 stylesheet 又能改樣式。
這也是為什麼 Svelte 核心團隊的成員在這則推文提到「Imagine if svelte's style tag could be turned into atomic styling, sort of what Vanilla Extract and StyleX do!! ....... Like, instead of the same css coming out, compiler inserts atomic css classes into your markup, and extracts the most common styles out into atomic classes....... CSS will grow at O(logn) after this change」
原本 Svelte 的寫法看起來雖然有 colocation,但是 O(n) 的寫法,如果你要有新的樣式,就要在多定義一個新的。「原子化」的核心就是要做到 colocation 同時又能夠把「寫 CSS 這件事」從 O(n) 變成 O(logn)。
不過就像很多演算法,在測試案例小時,O(n) 解法可能還比較快。在這在寫 CSS 也是,小的專案用熟悉的方法,可能還比較快;但大型有超多人要一起維護,就是完全不同的狀況了。
這邊先稍微總結一下第一點好處,StyleX 讓你可以不用擔心改 A 結果弄壞 B,與此同是讓你可以定義一次就全局使用,修改樣式時不會動到樣式表,這些都對於寫樣式有很直接的幫助。
上面談了 colocation,接著來聊 StyleX 文件談到的另一個好處 deterministic resolution。談這點前要先了解在大型專案下寫傳統的香草 CSS 會有什麼問題。在 Frank Yan 的講座中用很具體的範例來講解。我們先來看這個簡單的 CSS 問題,大家覺得下面的 <span>
會是什麼顏色呢?
// css 文件中
.blue {color: blue;}
.red {color: red;}
// HTML 文件中
<span class="red blue">這會是什麼顏色?</span>
大家腦中有答案了嗎? 如果你覺得是藍色,可能是因為在 class
當中 blue
在後面,但是這邊會是紅色,因為在 CSS 的優先序上,文件後者會優先。所以如果你只看 HTML 是沒辦法判斷出會是哪個顏色。
這還不是最讓人困擾的,我們來看第二個例子。現在假如 blue
與 red
是在兩個不同的檔案中,下面的 <span>
會是什麼顏色呢?
// blue.css
.blue {color: blue;}
// red.css
.red {color: red;}
// HTML 文件中
<span class="red blue">這會是什麼顏色?</span>
這個案例作基本上沒辦法直接回答出來的,因為要解答這問題,需要去了解這兩個 CSS 檔案是基於什麼打包規則才能回答。對於開發者來說,沒辦法在寫的時候判斷,是個很大的問題,而這也正是 StyleX 文件當中提到的 Deterministic resolution 要解決的問題。
StyleX 本身的編譯器會幫你處理這問題,讓你確保在下方這個 <span>
一定會是後者的優先於前者,所以你可以很確定它會是藍色
<span {...styles.props(styles.red, styles.blue)}></span>
對比起來,同樣是原子 CSS 的 Tailwind,現在本身也還沒解決這問題,所以在下方的這個範例中,也仍存在不確定最終會是哪個顏色的問題。當然,目前社群中有 Tailwind Merge 這種好用的套件幫忙解決這件事。但這意味需要額外裝一個套件,有額外的維護成本。
// Tailwind 範例
<span class="text-red-100 text-blue-100">這會是什麼顏色?</span>
當然你可能會說,優先級在香草 CSS 的脈絡下,也不是沒辦法被處理。只是大型專案下,東西變多變複雜,若要解決優先度的問題,往往把類別定得很詳細,但這就會導致 Frank Yan 提的「優先級戰爭」,當專案一大一複雜、經歷多次重構,就會出現下面這種超長的類別,也就是 StyleX 文件中提到的 bloated CSS 問題,這會導致程式碼很難被維護。
.coolest-redesign .cooler-redesign .cool-redesign .cool {
// ...
}
以筆者自己的經驗來說,之前有處理過一個在微前端架構,主應用加東西,多數子應用都正常渲染,唯獨有幾個子應用,在該新功能的樣式蓋過主應用的樣式。這是《淺談 CSS 方法論與 Atomic CSS》有談到 「一但開發的專案龐大起來,並且有多位前端工程師在進行程式碼撰寫時,就很容易遇到命名衝突、stylesheet 過於龐大等問題,主因是在 CSS 的世界中,所有規則集都是全域的」
你可能會說,命名前跟別人溝通協調一下。當然可以這樣做,但這樣做就是額外的時間成本,而在大的專案下這麼做,就會耗費更多時間成本,這顯然是不樂見的。以筆者上面提到的問題來說,不同子應用是不同團隊維護,團隊在不同國家,溝通存在時差問題,來回可能就是一兩天過去。
因此不是說其他方法做不到,而是 StyleX 的作法,是用更簡單、更容易維護複雜專案的方式,來實現 deterministic resolution,讓大型、跨國跨時區的專案,可以省去這些成本。
除了上面提到的 colocation 與 deterministic resolution,StyleX 還有許多其他好處,例如型別檢查,這是 Tailwind 目前也還沒做到的,在開發上能有效避免開發者寫錯東西。但礙於電子報的篇幅,今天就先不多談這些其他好處,推薦大家可以到 StyleX 的官方文件了解 [連結]。
回到上面提的,如果面試中被問「StyleX 解決了什麼問題? 跟其他 CSS 解決方案分別適用在什麼場景?」希望這篇內容能讓大家講得出 colocation 與 deterministic resolution 這兩點。
至於適用的場景,確實若是在一個小型、沒有太多樣式要定義、不牽涉多人維護、不會頻繁迭代的專案的情境下,寫香草 CSS 其實很足夠。以 DHH 為例,他到現在開新的專案,還是選香草 CSS,也完全沒問題。但如果是大型、各種樣式複雜、跨團隊跨時區的協作、迭代很頻繁的專案,StyleX 能比上很大的忙。
不過你可能會問,比起其他的原子 CSS,例如 Tailwind,StyleX 的額外好處在哪? 整體比較起來,StyleX 多的好處是上面提到的 deterministic resolution 不需用額外裝一個 Tailwind Merge 就能做到,以及 Type-Safe 這點,也是在大型專案很有幫助的。
[後端與系統設計] Threads 團隊如何開發這款史上最快達成一億註冊的產品
有在用社群媒體的大家,不知有沒有發現,最近重新用 Threads 的人變多了。Threads 是今年 Meta 旗下的 Instagram 團隊推出的新產品,基本上可以理解成跟 Twitter 打對台的產品。狹帶 Instagram 的超大流量,Threads 成為超越 ChatGPT,以最快速度達成一億註冊用戶的 App。
但在 Threads 紅了兩週後,突然大家就不再討論,然後這個 App 猶如隕石般稍縱即逝。但在最近 Threads 終於通過歐盟法規監管,在歐洲上線了。這帶來新的一波使用者浪潮。不確定為什麼,在台灣 Threads 也默默地重新回溫,以 ExplainThis 自己來說,我們的 Threads 帳號 [連結] 追蹤數少過 Facebook 追蹤數超過八千人,但是目前發文的觸及與互動都跟 Facebook 差不多。
The Pragmatic Engineer 先前有寫過一篇訪談 Threads 工程師的文章《Building Meta’s Threads App (Real-World Engineering Challenges)》,非常推薦大家一讀。這期趁著 Threads 最近又重回勢頭上,來幫大家摘要這篇內容。
Threads 是由 Instagram 的團隊打造的。Instagram 本身是很大的組織,當 Instagram 決定開發這產品時,在內部招集了最頂尖的工程師與產品經理,同時刻意保持團隊規模不要太大,這麼做是為了加速新產品的開發。這個 Threads 創始團隊是由 3 個產品經理、3 個設計師,加上 60 個工程師組成,為了加速與確保團隊成員都是有極高自主性,創始團隊的招集都以資深工程師為主。
很多人可能以為在大公司開發新產品,可以直接拿既有的程式碼來改,但往往這樣更耗時。Threads 團隊在開發上也是走直接開發原型 (prototype) 而不是去基於原本的程式碼庫做修改。雖然產品是 Threads 團隊從頭開發,但在基礎設施上 (例如技術棧、UI 框架、伺服器架構等各類基礎設施) 仍是仰賴 Instagram 原有的基礎,這也是 Threads 能在短時間接收這麼大量用戶的關鍵。
以 Threads 團隊的規模,從寫第一行程式碼到提交 App 到蘋果 App Store,中間花了約五個月的時間。而 Threads 團隊選擇的技術棧如下。這個技術棧的選擇,很大一部分是延續 Instagram 原先的技術棧,因為 Instagram 基於這些技術棧已經有許多套件與框架,所以這能讓 Threads 團隊在開發上加快速度。
Python + Django 開發 REST API
在要跟 Meta 其他的後端服務溝通時,是透過 GraphQL,這部分是用 Meta 內部的 Hack 語言
iOS 主要由 Swift 寫,搭配部分 Objective C
Android 是用 Jetpack Compose (語言上是 Kotlin 與 Java 混合)
而為了加快上線的速度,Threads 團隊在開發上選擇先上再說,而先沒沒有花太多時間在自動化 E2E 測試上。Threads 團隊表示自動化測試很重要,但是在早期產品剛上線的時候,可能會在短時間根據用戶反饋做大量調整,這時自動化測試的價值相對比較低。而在後端的商業邏輯部分,Threads 團隊是依照 TDD 的方式來開發,確保商業邏輯部分都有完整被測試到。
Threads 團隊的觀點是「對於還沒有到達 PMF 的產品,自動化測試幫助不大」,因此在前期 Threads 主要仍是靠 dogfooding 與 QA 測試來協助確保品質。所謂 dogfooding 是指讓內部員工自己使用,自己從使用者的角度來試產品。Threads 的做法是在初期只有核心團隊來做,避免過多的反饋讓團隊忙不過來。等產品開發更趨於完整時,才開給整個 Instagram 團隊來 dogfooding。
在實際上線後,Threads 團隊有完整觀測 PREQ (Performance, Reliability, Efficiency, Quality) 指標,其中具代表性的指標包含
測量從 App 冷啟動到用戶能看見第一個貼文內容的時間
觀測用戶滑動時的掉禎狀況
QPS 與核心 API 的成功率
複雜任務的佇列 (queue) 長度
回頭看,Threads 團隊的工程經理認為,能在如此短時間開發出承載極高用戶的 App,他們做對了幾件事情。首先,以速度為優先,即使產品還有很多能完善的地方,但先上線後續持續迭代;第二,保持團隊規模不要過大,因為團隊規模小,動起來速度也快;第三,在過程中非常專注,這回扣到第一點,Threads 團隊把很多功能放在上線後再開發,確保上線前專注在最重要的事。
最後,補充一點,在上線五個月後的今天,Threads 變更完整,且有網頁版。而不意外地,Threads 的網頁版也是用上面介紹的 StyleX 作為 CSS 解決方案。
[職涯發展] 歐洲求職經驗談 — 為何我沒申請碩士
最近收到讀者來訊,詢問關於歐洲求職相關的問題。由於讀者與我的背景很相近,都是在台灣出生長大,沒有其他國家的公民或永居,以及在思考申請歐洲工作時,也同時思考要不要去讀個碩士,讓自己畢業後可以留在當地有利於申請。
由於我自己在來新加坡前,待過德國與荷蘭的公司,先前也拿到在英國公司的 offer,這些都有提供辦理簽證、幫忙 relocation,所以剛好能透過我的經驗來分享。以下為相對主觀的觀點,所以不必然適用於所有人,大家可以針對自己的狀況與情境來判斷。
我個人的當時考慮到歐洲讀碩士,但最後沒有申請,而是直接找到在歐洲的工作。會考慮歐洲的碩士是因為學費比較便宜 (相對美國來說),加上當時看到歐洲的工作簽證比起美國相對容易申請,相對不用擔心留學完沒抽到簽證所以沒能留下來的問題。另外就是先前一直聽人分享,說歐洲相對工作生活平衡比較好,更符合我理想的樣貌。
但是最後為何我沒有申請碩士呢? 因為看到不少人是直接投遞歐洲工作的職缺,然後也很順利錄取,並獲得簽證辦理、搬家等協助。在權衡下,由於我不是特別喜歡讀書,比較偏好工作,以及從工作中去學習與成長;加上即使歐洲學費相對便宜,但還是一筆錢,同時在讀研究所期間也會沒收入,所以比起直接工作,兩個選擇在對於財務上還是有不小的差別。
短期上來看,兩個選擇有財務上的差別,但長期呢? 這是當時我在思考的問題。假如多去讀碩士學位,對於長遠來說影響比起沒有會很大嗎? 可能有些職業會有,但對做應用程式的全端開發軟體工程師這個職業來說,基本上沒有差別。這點也在我實際待了荷蘭與德國的公司後有驗證到,碩士學歷在那邊,對於全端工程師真的不是太重要。
既然短期兩個選項有差,但長期沒差,那對我來說選短期我偏好的,是更合理的選擇。當時我想的是,反正先試試看,假如工作都沒申請上,那還是可以再開啟申請研究所這個選項。而幸運的是,我有順利直接在台灣,遠端申請、遠端面試,然後直接找到歐洲的工作。有興趣了解當時求職的人,可參考之前我寫過的這篇文章 [連結]
我是在 2021 年找到歐洲工作,當時是軟體業大爆發的一段時期,各家公司都大舉招募,所以可能當時這樣比較好找也有關。不過在經過 2023 年的裁員潮後,到了年底的今天,其實可以看到各大廠招人正在復甦,舉例來說,最近 Google、Amazon 與 Microsoft 等都開始重新招實習生與新鮮人。
假如針對歐洲來討論,目前歐洲的藍卡政策看起來比先前更寬鬆,對 IT 與軟體產業還有其他特別更寬鬆的調整,讓申請工作簽證變得更加容易 (估計是因為當地找不到人,所以才開放寬,藉此吸引來自全球的人才)。有興趣了解更多的可以參考這個新聞 [連結]。
我自己是文組轉職軟體工程師,只有大學的學歷。找到歐洲工作前有約三年非軟體工程師經驗,加上一年半軟體工程師經驗。基本上這個條件,荷蘭、德國、英國的公司,都是願意幫忙辦理工作簽證,以及協助搬家補助。
因此,如果你正在考慮去歐洲,在思考要透過留學途徑,或者直接找工作的方式,我覺得以軟體工程師的職業來說,相對比較容易評估。假如你想讓自己放一到兩年假,重新回到學生的身份,那回去讀個書挺不錯的;假如你跟我一樣比較偏好透過從工作中學習與成長,我認為是可以放手先申請 (畢竟歐洲的工作生活平衡真的很好,就算在職還是能好好照顧生活,也很多假可以放長假)。
順帶一提,找歐洲工作有個好處是,不用裸辭找工作。台灣的晚上是歐洲的下午,基本上他們很少面試是排早上,都是排當地下午,意即排在台灣的晚上;所以我當時都是台灣的下班後,晚上透過視訊方式遠端面試。這讓我一天假都沒請,在職完成面試與拿到工作 offer。
另外,假如拿到願意辦理簽證與支持搬家的工作,基本上該有的補助都會有。可以參考這篇我搬去新加坡時寫的文章 [連結],之前拿到歐洲工作開出的條件也都差不多。假如關於找歐洲或找新加坡工作有相關問題,也可以留言讓我知道,之後可以再寫內容與大家分享
[本期推薦]
過去兩週前端界有許多新的發布,包含 Svelte 發布了 SvelteKit 2 發布 [連結]、React 的 Waku 框架也正式發布 [連結]、以 Vite 出發的 Vitest 也發布 1.0 [連結]’靜態網站工具 Astro 三個月前發布 3.0,現在推出了 4.0 一次也發了非常多新功能 [連結]
以 Rust 來撰寫的 JavaScript 工具集合 Oxc 最近在社群也引起廣大討論。Vue 的創作者 Evan You 用 Oxc 來跑 Vue 3 有 200 個規則,且 590 個檔案的專案,只花 50 毫秒就完成。速度非常驚人 [連結]
Dan Abramov 離開 Meta 後,睽違一陣子發了新文章 《A Chain Reaction》[連結]
Turso 前陣子出了一個非常嚴重的事故,對於如何寫事故覆盤 (postmortem) 感興趣的人,他們寫的蠻值得參考的 [連結]。當然不確定這對於挽回使用者有多少幫助,畢竟這次事故確實相當影響使用者的信任度
前陣子 DHH 轉發 Paul Graham 分享的這個數據。Replit 的一百天學程式課程,從第一天到第一百天的人數大幅下降。他提到在現代要成功很簡單,自律與堅持,以及真的去做而不只是想做而已 [連結]
Postman 的這篇 API protocols 整理,非常的全面。在面試很常會被問各種不同 protocols 的異同,有全局的理解會很重要 [連結]
《An Introduction To Full Stack Composability》從全端的角度談組合性架構,推薦一讀 [連結]