ExplainThis 全端開發雙週報 #20
在 JavaScript 深拷貝為什麼推薦用 structureClone、CI/CD 是什麼 & 為什麼要 CI/CD、如何有效提高獲得面試的成功率
歡迎閱讀全端開發雙週報第 20 期。從去年開始雙週報後,一轉眼已經來到第二十期了!在進到本期的內容前,想先感謝目前已經訂閱 E+ 成長計畫的讀者。在本週一 (1/22),E+ 已經正式上線,目前已經有超過兩百位讀者一起在 E+ 一起成長。
E+ 第一週的全新深度內容也已經上線,我們有同步發行精簡版的在 ExplainThis 網站供讀者免費閱讀,推薦對《設計聊天系統 Designing a Chat System - 前端篇》感興趣的讀者可以一讀。
此外,我們在接下來也會陸續新增包含演算法白板題、前端手寫題的詳細解說。以前端手寫題來說,我們有在 ExplainThis 網站中新增題目與解答 [連結],而 E+ 則會有每個解答的詳細解說。
正式上線後,E+ 也正式進入早鳥階段,在 2/18 前使用 EARLY80,都可享有終身 8 折訂閱優惠,期待在 E+ 的專屬 Discord 社群中見到大家 (E+ 的介紹頁面可以點這看到)。
講完 E+ 後,讓我們進到本週的雙週報主題吧~
[前端] 在 JavaScript 深拷貝為什麼推薦用 structureClone?
在前端面試的題目中,介紹「淺拷貝與深拷貝」差別,以及「手寫潛拷貝與深拷貝」都是很常會考的題目。先前 ExplainThis 網站上有針對這兩個問題寫了《請實踐 JavaScript 淺拷貝 (shallow copy) 和深拷貝 (deep copy)》一文,因為剛好讀到 builder.io 的 Steve 寫的《Deep Cloning Objects in JavaScript, the Modern Way》,想說可以進一步摘要,來更完整講述深拷貝的概念。
深拷貝的定義是,當拷貝時,兩個物件具有相同的屬性名稱和順序,且每個屬性的值也具有相同的結構,且在原型鏈也具有相同的結構。Steve 給的例子如下,可以看到,拷貝完 copied
跟 calendarEvent
的物件屬性都相同,只是 cocalendarEvent.attendees === copied.attendees
會是 false
const calendarEvent = {
title: "Builder.io Conf",
date: new Date(123),
attendees: ["Steve"]
}
// 😍
const copied = structuredClone(calendarEvent)
//
copied.attendees // ["Steve"]
copied.date // Date: Wed Dec 31 1969 16:00:00
cocalendarEvent.attendees === copied.attendees // false
在我們先前寫的文章中有提到,要深拷貝,可以有幾個方法,一個是用 JSON.parse(JSON.stringify(obj))
另一個是用 structuredClone(obj)
。而在面試中,比較常會問到如何自己手寫 Lodash 的 _.cloneDeep(obj)
。
在 Steve 的文章中,他推薦使用原生的 structuredClone
函式,基本上如 Steve 所說,現在如果寫 JavaScript 要做深拷貝,structuredClone
都是最推薦的。你可能會問為什麼呢?
首先如我們先前的文章提到的,JSON.parse(JSON.stringify(obj))
的問題在於,沒辦法處理 JavaScript 原生類別、純陣列與純物件以外的東西,所以假如今天物件當中有放 Set
,則會被轉換成 {}
,或者 Date 物件會被轉換成某個時間字串,這顯然不理想。
而 Lodash 的 _.cloneDeep(obj)
雖然也能有效處理各種類別的東西,只是一個問題是,Lodash 一貫以來被人詬病導入的成本太高了,如果用 import cloneDeep lodash/cloneDeep
會佔用 17.4kb (或者 5.3kb gzipped),如果是用 import { cloneDeep } from 'lodash'
直接從 lodash
引入則會是 71.5kb (或 25.2kb gzipped)。
從效能的角度來講,如果可以用更少包體積的方式,做到一樣的事情,當然會選擇用成本少的。即使現在有 lodash-es
佔用更小的包體積空間,但額外引入還是多的。如果用原生的 structuredClone
就能免去這問題。
當然,structuredClone
遇到某些東西還是沒辦法直接拷貝,例如函式作為鍵的時候,或者 DOM 節點作為值的時候,都會遇到 DataCloneError
。在 Steve 的原文中有提到更細的點,有興趣的讀者可以再自行閱讀。
目前 structuredClone
在各大執行環境都已經被支援,包含 Chrome、Edge、Safari、Node.js、Deno。不過在 workers 的支援度上,有一些瀏覽器與 Node.js 還沒支援。除非你要用到 workers,不然現在要做深拷貝,structuredClone
是推薦首選。
[軟體工程] CI/CD 是什麼? 為什麼要 CI/CD?
CI/CD 是由 CI (Continuous Integration 持續整合) 以及 CD (Continuous Delivery/Deployment 持續交付/部署)兩個字所組成。 雖然現在部分公司都有專門的 DevOps 工程師會負責處理 CI/CD,但許多公司仍是仰賴負責開發的工程師,例如前端、後端、全端工程師來負責處理。
在接下來三期內容,我們會聊前後端工程師都需要知道的 CI/CD 基礎概念。在這一期,我們會先來聊「為什麼要有 CI/CD」。當你能更清楚理解某個技術或工具背後的脈絡,會對該技術或工具更有感。
假如從歷史的角度來看,CI/CD 是在軟體開發史中,相對新的一個詞。這個詞彙的出現,是因為軟體開發模式改變。假如大家還有印象,在以前軟體還是用光碟片來安裝的時期,軟體的更新都是一次大版本的更新。對於開發者來說,是一次把完整的功能都做完、測試完,才會上線交付給使用者。
但是在時代變化下,近年來軟體開發有了改變,最有名的是 2001 年時,在軟體開發業界有 17 位資深專家,齊聚一堂發佈了敏捷宣言(The Agile Manifesto) 倡議,進而衍伸出後來的敏捷開發,而 CI/CD 也可說是這之後出來的詞彙。
敏捷宣言中列舉了十二項原則 [連結]
竭誠歡迎改變需求,甚至已處開發後期亦然。 敏捷流程掌控變更,以維護客戶的競爭優勢。
經常交付可用的軟體, 頻率可以從數週到數個月, 以較短時間間隔為佳。
業務人員與開發者必須在專案全程中天天一起工作。
以積極的個人來建構專案, 給予他們所需的環境與支援, 並信任他們可以完成工作。
面對面的溝通是傳遞資訊給開發團隊及團隊成員之間效率最高且效果最佳的方法。
可用的軟體是最主要的進度量測方法。
敏捷程序提倡可持續的開發。贊助者、開發者及使用者應當能不斷地維持穩定的步調。
持續追求優越的技術與優良的設計, 以強化敏捷性。
精簡──或最大化未完成工作量之技藝──是不可或缺的。
最佳的架構、需求與設計皆來自於能自我組織的團隊。
可以看到,在這個宣言下,軟體開發不再是一次完成一整包後才交付,而是「及早」交付,且開發者需要持續接收回饋,根據持續演進與變化的需求持續地開發。在這個概念下,我們需要一個能夠落地的具體方式,而 CI/CD 正是落地的手段之一。而 CI/CD 可以定義如下
CI 是持續整合,意思是讓多個開發者,能夠共同在同個程式碼庫中開發不同的新功能,然後能夠持續整合到某個分支上面。之所要持續做這件事,是因為開發不同功能時,程式碼可能會有衝突,而持續地整合就能及早化解衝突。在 CI 的流程中,也會有自動化測試與建構,來避免等要上線前一次合併才發現有測試跑不過,或者建構有錯誤。
CD 則是持續交付/部署,在整合完後有自動化的部署流程。最理想的狀況,是當開發者把程式碼合併後,就會開始整合、測試,最終部署,整個流程不需用有人工介入,一切自動化完成,新的功能就會到最端使用者手上。
總的來說,CI/CD 的出現,是軟體開發往敏捷發展的脈絡下而生的一種手段,透過 CI/CD 我們可以自動化地完成程式碼整合、交付/部署,讓開發者可以專注在開發上。
讀到這可能對於具體來說,CI/CD 的整個流程該長什麼樣子,仍覺得很模糊。我們在下一期雙週報會進一步討論~
備註:可能有讀者會問 CI/CD 與 DevOps 的關係。在爬梳這段歷史時,看到 DevOps 約是 2008 - 2009 年左右被提出;而 CI/CD 則是更早之前就有,只是後來才逐漸在業界普及。目前 CI/CD 是 DevOps 中的重要元素。可以在 Atlassian 這篇介紹看到,建置 CI/CD 流程是 DevOps 工程師的重要能力之一 連結 ,但要成為 DevOps 工程師,還需要有其他技能。
[職涯] 如何有效提高獲得面試的成功率
要如何提高求職成功率,相信是多數人感興趣的議題。前 Google 工程師 NeetCode 先前分享了一個談論這主題的短片,看到後覺得挺不錯的,在此摘要同時加上我們的一些延伸想法與大家分享。
首先是要培養出對應的實力,包含軟實力 (溝通、領導等),以及硬實力 (技術能力) 的培養。對於許多工程師來說,能力培養的路徑是相對明確的,例如前端與後端工程師,分別需要具備什麼能力,都是有相對清晰的路徑可以一步步培養出來。
然而只是培養實力還不夠,同樣重要的是要能夠有訊號 (signal) 來證明自己實力好。這點反而是多數人會忽略的。雖然在理想的世界中,有多少實力,應該要得到相應的關注與回報,但在現實世界中,往往不是這樣。很有可能,你其實有實力,但別人完全不知道。
所以「如何傳遞自己是有實力的訊號」是找新工作時,跟培養實力同等重要的。假如把找工作的過程進一步拆解,在前面投履歷的關卡,以及後面實際進到面試後,需要透過不同方式展示訊號。
在履歷的關卡,最直觀可以獲得訊號的,便是來自你的工作成果。特別要注意,工作成果不該是用形容詞描述,而是要用具體佐證。舉例來說,「我用 JavaScript 開發了一個很有影響力的功能」,「很有影響力」是形容詞,但如果改成「我用 JavaScript 開發了一個帶來五千萬營收的功能」,「帶來五千萬營收」是佐證支持。
當今天你能端出具體的佐證,看到履歷的人就知道你所謂的「有影響力」究竟是多大的影響力,這能傳遞更有效的訊號。
訊號不必然只能從你目前的正職工作成果而來。特別是對軟體工程師,在你參與的社群,如果你持續貢獻,讓別人看到,就是最好的訊號。這也意味著,除了傳統的投遞履歷,你也可能透過其他方式傳遞訊號,讓人找你去面試。
前 React 核心團隊的 Dan Abramov 當年也是因為在開源社群貢獻,所以被 Meta 的人問說要不要加入 React 團隊。連履歷都沒有投,在技術會議上被邀約,然後直接在技術會議後的空擋面試並拿到工作機會 [連結]
對開源專案 Svelte 貢獻良多的開發者 @puruvjdev,先前直接在 X (推特) 上發一個推文,把它過去在開源貢獻的成果匯總起來 [連結] 這也是展示訊號的有效方式。
當然,除了在申請階段要展現訊號,在面試階段也需要。具體該怎麼做,我們將在下期雙週報與大家聊聊。另外,假如你在履歷的修改上,希望有人幫忙看、給回饋,E+ 有履歷回饋的專區,我們都會給回饋~
[本期推薦連結]
Cloudflare 前陣子裁員,有位員工錄下了自己被拉進與 HR 的裁員會議中。雖然因為可能觸犯公司保密規範,不推薦大家這樣側錄;但該員工在過程中積極為自己表現辯護,在社群中贏得許多人的掌聲 [連結]
Linux 與 Git 的發明者 Linus Torvalds 最近在訪談中被問到怎麼看 AI 對寫程式的影響,Linus 表示他覺得這件事已經在發生,他覺得這很美好 (原文是 wonderful),且他是樂觀看待這件事的,如果你好奇為什麼他這麼說,推薦可以看這個對談 [連結]
Zustand 核心維護者 Daishi Kato 先前在社群中分享 Zustand v5 alpha,核心的程式碼只有差不多五十行。在下期雙週報我們會來聊這個程式原始碼的解說,推薦大家可以先讀並與理解 [連結]
最近在 Reddit 的 Tailwind 討論區看到有人推薦 Gimli Tailwind 這個工具,對於有在寫 Tailwind 的人,非常推薦使用 [連結]
Google 主任工程師 Diane Hirsh Theriault 上週在社群上公開抨擊 Google 領導人缺乏眼見,引來社群許多討論 [連結]。先前我們有翻譯 Flutter 創作者離開 Google 時的發文,兩者有類似的觀點 [連結]
Turso 這篇《Is NoSQL dead?》討論最近 SQL 的使用趨勢上漲,並談論在 2010 年左右起來的許多 NoSQL 當時解決 SQL 的一些問題,現在 SQL 也有很好的解決方案,因此導致現在越來越多人,除非特定用途,不然不再用 NoSQL。這個趨勢蠻值得持續觀察 [連結]
突破一億次下載,同時月活用戶超過千萬,但最終仍因為,是去年十月的文章,但仍覺得很精彩,跟著讀的過程也覺得收穫很多。特別推薦最後一篇,談到收掉 Omlet 是因為營運上無法支撐,作者有分享在大流量下實際的各項成本,實在不是個小數目[連結]。 成本絕對是開發環節中不可忽略的,上期雙週報談到的節約架構,真的很重要 [連結]
I really like your weekly report and I respect you for continuing to do it.