者 | Loraine Lawson
譯者 | 張衛(wèi)濱
策劃 | Tina
本文最初發(fā)表于The New Stack網(wǎng)站,由 InfoQ 中文站翻譯分享。
在 2024 年,前端領(lǐng)域會有怎樣的發(fā)展呢?因為沒有人能夠預見未來,所以 The New Stack 與來自 Angular、Next.js、React 和 Solid 的創(chuàng)建者和維護者討論了他們 2024 年的計劃。以下是前端開發(fā)者對未來一年的展望。
來自谷歌的 Angular DevRel 技術(shù)主管和經(jīng)理Minko Gechev說,在過去的一年里,Angular 的兩大成就是引入了基于Signals的細粒度反應(yīng)性和可延遲視圖。他告訴 The NewStack,新的一年將會在此基礎(chǔ)上進一步關(guān)注細粒度的反應(yīng)性,并使 Zone.js 成為可選的。
在 Angular 中,Zone 是一個執(zhí)行上下文,它能夠跨異步任務(wù)持續(xù)存在。在這個GitHub倉庫中詳細介紹了Zone,它有五個職責,包括攔截異步任務(wù)調(diào)度和包裝回調(diào)以便于進行錯誤處理,以及跨異步操作的 zone 跟蹤。Zone.js 可以創(chuàng)建跨異步操作而持久化存在的上下文,也可以為異步操作提供生命周期鉤子。
Gechev 說,“我們正在探索為現(xiàn)有的項目實現(xiàn)可選的 Zone.js,開發(fā)人員可以通過重構(gòu)現(xiàn)有的應(yīng)用程序來利用這一特性”。“借助可選的 Zone.js,我們期待加載時間能夠得以改善,并實現(xiàn)更快的初始渲染。對細粒度反應(yīng)式的處理將提升到一個新的層次,使我們能夠僅探測組件模板的部分變更。”
他說,這些特性將會帶來更快的運行時。
在關(guān)于性能的另一個方面,Angular 正在考慮是否默認啟用混合渲染。他補充說,選擇避免混合渲染是可能實現(xiàn)的,因為這會增加托管需求和成本。
Gechev 說,“我們看到了 SSG(靜態(tài)站點生成,static site generation)和 SSR(服務(wù)器端渲染,server-side rendering)的很多價值,而且在 v17 中奠定了堅實的基礎(chǔ),我們正在進行最后的潤色工作,以便從一開始就實現(xiàn)這種體驗。”
他補充到,另一個優(yōu)先事項是完成Signals請求的評論(Request for Comment)。
開發(fā)人員還可以看到 Angular 文檔的改進。根據(jù)對開發(fā)人員的調(diào)查,他們希望能有一個升級的學習體驗,其中包括讓 Angular.dev 成為該框架新的托管地。他補充說,開發(fā)人員還優(yōu)先考慮了初始加載時間(混合渲染、部分填充和可選的 Zone.js 應(yīng)該可以部分解決該問題)和組件編寫,Angular 計劃會進一步簡化組件的編寫。
Gechev 說,“我們致力于迭代式地交付特性,并隨著時間的推移逐步增強它們”。“開發(fā)人員將能夠從 2024 年的所有改進中受益,并在接下來的幾年里獲得更好的開發(fā)體驗和性能。”
Next.js 在 2023 年引入了一個新的應(yīng)用服務(wù)器,旨在支持 React 服務(wù)器組件(React Server Component,RSC)和Server Action。Vercel(該框架的監(jiān)管者)的產(chǎn)品負責人 Lee Robinson 說,該框架會繼續(xù)支持舊的服務(wù)器,并且其路由系統(tǒng)可以在兩者實現(xiàn)互操作性。這種互操作性意味著可以繼續(xù)花時間添加新的特性。
Robinson 說,“有些客戶已經(jīng)使用 Next.js 進行開發(fā)有五六年之久了,他們也會需要花費幾年的時間來采用這些新特性。在這個過程中,我們希望他們的工作能夠盡可能地順暢。”
在新的一年中,Next.js 希望要解決很多問題,其中一個優(yōu)先事項就是簡化緩存。他說,從開發(fā)人員的體驗來看,這可能會使其更加容易。
Robinson 說到,“通常情況下,生態(tài)系統(tǒng)中的許多開發(fā)人員必須引入一堆額外的包,或者學習如何使用其他的工具來進行數(shù)據(jù)抓取、緩存和重現(xiàn)校驗”。“現(xiàn)在,Next.js 已經(jīng)構(gòu)建了很多這樣的特性,而且非常強大,但是這也意味著需要學習更多的東西,我們得到的初步反饋是,‘這非常棒,也很強大,但是我們希望它能更簡單一些’”。
Next.js 團隊還將繼續(xù)關(guān)注性能的改進,他將其稱之為“我們的持續(xù)投資”。
他補充到,在新的一年里,這很可能會以新編譯器的形式出現(xiàn),它將加快在開發(fā)人員的機器上啟動 Next.js 的速度。該編譯器相關(guān)的工作已經(jīng)進行了大約一年的時間,Vercel 一直在其內(nèi)部產(chǎn)品和應(yīng)用中使用它。他說,這個使用 Rust 編寫的編譯器即便在沒有使用的緩存的情況下也比之前啟用緩存的編譯器更快。
Robinson 說,“距離推出這個功能已經(jīng)近在咫尺了,甚至到了每個人都可以默認啟用它的程度,而且它比現(xiàn)有基于 Webpack 的編譯方案更快”。“開發(fā)人員總是希望他們的工具能夠更快。他們對工具運行速度的追求永無止境。因此,很有意思的一件事是,工具的制造商,而不是工具的使用者在開始轉(zhuǎn)向像 Rust 這樣的底層工具,從而幫他們實現(xiàn)性能方面的最終勝利。”
他們的第三個目標是為未來十年的 Next.js 奠定基礎(chǔ)。
他說,“我們對這個新的路由系統(tǒng)感到非常興奮。我們相信這是未來的基礎(chǔ)。但是,這也需要時間。人們會嘗試使用,從而有特性方面的需求,并且希望能夠看到實際的改變。我們將其視為未來五年至十年的長期投資。”
他補充說,一個“某天”可能會實現(xiàn)的目標是在 Next.js 中找到更好方式來處理內(nèi)容,不過這應(yīng)該不會新的一年中實現(xiàn)。
他補充說,“現(xiàn)在,它依然能夠正常運行,你依然可以連接到任何你想要的內(nèi)容源,但是會有一些潛在的方式能夠簡化開發(fā)人員的體驗”。“這更像是一件錦上添花的事情,而不是必須要做的事情,這就是為什么我認為在 2024 年我們不會實現(xiàn)它,但我希望未來會為其做一些相關(guān)的工作。”
Meta 的 React 工程主管 Eli White 說,React 團隊希望在新的一年里會有更多的框架采用 React 服務(wù)器組件(RSC,React Server Component)。
White 說,“對大多數(shù)人來講,他們認為 RSC 是 React 領(lǐng)域的重要變化,從一個單純的 UI 層,變成對如何架構(gòu)應(yīng)用程序的方式都能產(chǎn)生更大的影響,以獲得最佳的用戶和開發(fā)人員體驗,特別是對于單頁應(yīng)用程序(SPA,single page application)方式表現(xiàn)不夠好的應(yīng)用程序。”
雖然他沒有明確說明 2024 年的新動向,但是 White 表示他們將發(fā)布和分享 2023 年相關(guān)事項的更多進展。比如,在 React Advanced 會議上,團隊向與會者展示了 React Forget,這是 React 的自動記憶編譯器。White 說,有了React Forget之后,將意味著開發(fā)者不再需要使用useMemo和useCallback。
White 補充說,“在 React Native EU 會議上,我們分享了從 0.73 版本開始將 web 開發(fā)人員熟悉的 Chrome 開發(fā)工具引入 React Native。我們還初步展示了對 Static Hermes 的研究成果,這是針對 JavaScript 的原生編譯器,它不僅有可能加快 React Native 應(yīng)用程序的速度,而且會從根本上改變 JavaScript 的用途。”
Solid 創(chuàng)始人 Ryan Carniato 表示,在 2024 年,Solid 開發(fā)人員可以期待即將推出的SolidStart 1.0和 Solid.js 2.0。SolidStart 是一個元框架,這意味著它建立在框架 Solid.js 之上。他說,這類似于Svelte的SvelteKit。
SolidStart的文檔是這樣描述的:
“Web 應(yīng)用程序通常包含很多組件,比如數(shù)據(jù)庫、服務(wù)器、前端、打包器、數(shù)據(jù)抓取/變更、緩存和基礎(chǔ)設(shè)施。編排這些組件很具挑戰(zhàn)性,并且通常需要跨應(yīng)用程序技術(shù)棧共享大量的狀態(tài)和冗余邏輯。這就是 SolidStart 的用武之地,它是一個元框架,提供了一個將所有這些組件組合在一起的平臺。”
由于 SolidStart 仍處于 beta 階段,Carniato 有機會利用生態(tài)系統(tǒng)中已有的東西將其變得更好。
Carniato 說,“其中很重要的一點是,我們現(xiàn)在不再需要編寫自己的部署適配器,而是可以使用 Nitro,它也支撐了 Nuxt 框架,這使得我們可以將其部署到所有的不同平臺上。”
另外一個樣例是任何 Solid 路由器都能在 SolidStart 中運行。
他說,“這意味著對路由器的底層部分進行了大量更新,這樣它們才能一起運行,但最終結(jié)果令我非常高興,因為我們小團隊的志愿者需要維護的代碼量要少得多,這給了開發(fā)人員很大的靈活性。”“他們不必被迫采用單一的解決方案,這對我來說非常重要,因為每個人都有自己的需求。正如我所言,如果你構(gòu)建了正確的組件并且能夠弄清楚構(gòu)建基塊(building block),那么人們可以做更多的事情。”
他說,最終的結(jié)果是由“可互換”的組件所組成的元框架,而不是具有很強的傾向性。Solid 團隊一直在思考,在由越來越多的元框架決定開發(fā)人員能夠使用什么的世界中,正確的基本元素所帶來的影響。
他說,“對我來講,最重要的一直是基本元素形成的構(gòu)建基塊,這是一個非常工程化的關(guān)注點,我認為這也是它與眾不同的原因之一。”“我一直喜歡給別人選擇的權(quán)力,并且我認為如果有正確的基本元素,正確的構(gòu)建基塊,就可以構(gòu)建出正確的解決方案。”
他表示,Solid 2.0 應(yīng)該會在 2024 年中后期發(fā)布。現(xiàn)在,他們正在實現(xiàn)如何處理異步系統(tǒng)的原型。
Carniato 說,“Solid 2.0 也將是一個非常重要的版本,因為我們正在重新審視反應(yīng)式系統(tǒng),并思考如何解決異步信號或異步系統(tǒng)的問題。”
他補充說,Solid 試圖在控制和性能之間取得平衡。
他說,“在我們的社區(qū)里,有很多非常熱情的人,非常有技術(shù)頭腦的人,他們關(guān)注性能,關(guān)心控制。”“我們確實吸引了很多人,他們真的想控制自己建造的每一個組成部分。”
原文鏈接:https://www.infoq.cn/article/7ciYZE56w7KENEGOjfQY
者 | Adrien Joly
譯者 | 張衛(wèi)濱
策劃 | 丁曉昀
有時候,JavaScript(甚至帶有類型檢查的 TypeScript)會因為其不可預測的特性和缺乏約定而遭到批評。對于那些知道 JavaScript 是為 web 瀏覽器設(shè)計的腳本語言的人來說,這就不足為奇了。
但是,現(xiàn)在它已經(jīng)成為開發(fā)全棧 web 的首選語言,也是跨平臺移動應(yīng)用的熱門方案。那么,當開發(fā)人員的 JavaScript/TypeScript 代碼庫開始老化,由此帶來的復雜性痛苦地增長時,他們該采取什么行動才能最大限度地減少資源浪費并保持工作滿意度呢?
本文將基于我 10 多年來編寫 JavaScript 代碼的經(jīng)驗和 5 年多拯救 JS/TS 項目的經(jīng)歷,向讀者介紹如下內(nèi)容:
在開發(fā)下一個特性時,每個警告、類型錯誤或非正常的測試都會讓開發(fā)人員浪費時間、精力和專注度。
代碼警告尤其令人討厭,因為開發(fā)人員會習慣性地忽略它們,“只要一切按預期運行就好”。因此,它們會迅速累積,當我們遇到缺陷、事故或系統(tǒng)的意外行為時,就很難將其作為有用的線索。
類型錯誤就是一個很好的樣例。當我們的用戶遵循“快樂路徑(happy path)”時,這些錯誤似乎無關(guān)緊要,因為軟件似乎能夠按照預期運行。所以,我們可能會使用@ts-ignore、any或類型斷言來暫時忽略它們。但是,這樣做的話,就意味著如果有一天用戶選擇不同的路徑,就會面臨運行時錯誤。
這樣的話,開發(fā)人員就需要調(diào)查、重現(xiàn)和修復一個新的缺陷,而這個缺陷恰恰是他們幾個月前允許走捷徑所造成的。如果你的代碼被各種警告和/或暫時忽略這些警告削弱了質(zhì)量,那么找到這個捷徑將耗費大量的時間。
當生產(chǎn)環(huán)境的數(shù)據(jù)庫因“內(nèi)存不足”錯誤而崩潰時,該警告可能會幫助開發(fā)人員找到崩潰的原因
警告和類型錯誤是查找缺陷和事故的線索。我們累積(或忽略)的警告和錯誤越多,開發(fā)人員就會花費越多的時間去調(diào)查。如果代碼是他們很久以前編寫的,那情況就會更糟糕了。
類型檢查器認為缺少一個預期的屬性。忽略這個錯誤將意味著要承擔持久化不一致數(shù)據(jù)的風險,在幾個月之后,你可能需要花費幾天的時間來調(diào)查和解決這個問題
有許多靜態(tài)代碼分析工具可供使用,最常用的包括:
警告也可能來自其他工具:依賴安裝器(如npm和yarn)、打包器(如webpack)、代碼處理器(babel、scss)和執(zhí)行環(huán)境(CI 運行器)。不要忽視它們!
如果遵循這些建議會讓你的代碼變得非常冗長和/或復雜(比如防御式代碼),你可以需要對其進行重新設(shè)計。
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"lint:errors": "eslint . --quiet",
"lint:typescript": "tsc --noEmit --skipLibCheck",
"lint:jsdoc-typing": "tsc --noEmit --allowJs `find ./ -name '*.js' -name '*.d.ts'`"
},
復制代碼
借助靜態(tài)代碼分析器和 npm 腳本,能夠讓開發(fā)人員輕松快速地探測有問題的代碼
安裝和配置靜態(tài)代碼分析工具是一個良好的開端,但這還不夠。
要想取得持續(xù)的成功,要確保開發(fā)團隊做到如下幾點:
如下幾種策略可能會提供幫助:
當某項職責沒有人負責時,集體責任往往會被其他“優(yōu)先事項”所取代(比如,本周多交付一個特性,但是代價是忽略一個警告)。
定期輪換角色,確保每個人都能參與其中并保持積極性。
現(xiàn)在,我們有了一支致力于保持代碼庫整潔的團隊,我們相信用戶很少會遇到編程錯誤。
但是,業(yè)務(wù)邏輯中的錯誤該怎么辦呢?
例如,如果一個新添加的功能破壞了另一個功能該怎么辦?如果開發(fā)人員從一開始就誤解了該功能的預期行為,又該怎么辦?如果這樣的錯誤最終導致了嚴重的收入損失又該如何處理?
與編程錯誤類似,業(yè)務(wù)邏輯問題可能會在生產(chǎn)環(huán)境由用戶發(fā)現(xiàn),但我們更希望盡早發(fā)現(xiàn)它們。因此,定期測試軟件非常重要,這個過程可以使用自動化和/或手動測試。
從業(yè)務(wù)角度看,測試有兩個作用:
確保功能性測試(也稱為“驗收測試”)涵蓋大多數(shù)關(guān)鍵業(yè)務(wù)特性,單元測試或集成測試涵蓋大多數(shù)關(guān)鍵技術(shù)組件。此外,確保持續(xù)集成在任何測試失敗時都能向開發(fā)人員提供可執(zhí)行的反饋。
對于有些開發(fā)人員來說,將測試工作委托給其他人(如產(chǎn)品負責人或 QA 團隊)是很有誘惑力的做法。在每個新特性完成后,進行一次這樣的委托測試,以確保特性實現(xiàn)符合功能性需求,并進行協(xié)作迭代,這樣做可能是合理的。
但是,委托他人進行回歸檢測并不是一個好主意,原因包括:
回歸測試是一項痛苦且可能代價高昂的負擔,尤其是需要不同角色(如產(chǎn)品負責人和開發(fā)人員)必須協(xié)作的情況下。從長遠來看,回歸測試自動化意味著可以節(jié)省大量的時間,而且開發(fā)人員具有編寫自動化測試的技能,所以,開發(fā)人員首先要承擔起檢測回歸的責任,而不必讓其他角色參與進來,這符合他們的利益。
從最關(guān)鍵的業(yè)務(wù)特性開始。要找出這些特性,你可以問自己:“就收益和/或減少成本而言,在生產(chǎn)環(huán)境中可能發(fā)生的最糟糕的事情是什么?”
例如,電子商務(wù)網(wǎng)站的回答可能是如下的特性:
基于這些業(yè)務(wù)關(guān)鍵的用例,從它們開始編寫端到端的自動化測試肯定就是非常有意義的。
在每次代碼更新或添加到代碼庫之時,在將其部署到生產(chǎn)環(huán)境之前。
借助git hook,在每次提交時運行測試可能就足夠了,因為它能可靠地運行,而且其持續(xù)時間不會導致開發(fā)人員編寫更少的測試。
不管是否使用git hook,都要確保每次推送可用于生產(chǎn)環(huán)境的代碼時,測試能在某處運行(例如,最好是在持續(xù)集成環(huán)境中)。
在持續(xù)集成環(huán)境中,每次提交都會運行代碼檢查和自動化測試。
需要優(yōu)化的變量包括:
如果你的團隊在編寫自動化測試和/或可測試代碼方面經(jīng)驗不足,那么可以從一些端到端測試開始。然后,逐步增加對范圍更小的代碼單元的測試。這樣做可以激勵開發(fā)人員編寫易于測試的代碼。例如,通過隔離責任、減少耦合和/或?qū)I(yè)務(wù)邏輯寫成純函數(shù)。遵循依賴注入架構(gòu)是實現(xiàn)這一目標的好方法。(參見六邊形架構(gòu)或簡潔架構(gòu))
自動化測試(如本文所述)的目的是探測團隊的功能性范圍內(nèi)的回歸,而不是第三方的功能。基于這一點,在測試中 Mock 第三方是合理的。
也就是說:
探測自己的代碼中的問題和第三方 API 中的問題并不遵循相同的生命周期:
你需要持續(xù)監(jiān)控第三方提供商是否能夠正常運行并達到預期效果。但是,第三方錯誤不一定能夠在發(fā)生之時就探測到,因此最好是定期監(jiān)控,而不是在開發(fā)人員每次推送代碼變更的時候進行監(jiān)控。
所以,需要搭建兩個專門的流水線:
為了編寫長期最有用、最健壯的測試,我建議遵循F.I.R.S.T.原則。確保開發(fā)人員不會濫用mock。
假設(shè)你的代碼庫已經(jīng)或者將要開發(fā)數(shù)年的時間,那么隨著時間的推移,它很可能會在代碼風格和質(zhì)量方面失去內(nèi)聚力。更糟糕的是,由于技術(shù)債務(wù)、缺乏測試或意外復雜性的積累,某些組成部分的維護可能會變得很復雜。
在這種情況下,要像上文所建議的那樣,在整個代碼庫中對代碼實現(xiàn)一致的內(nèi)聚預期可能會變得很復雜。不過,這也沒有關(guān)系。
你不希望看到的是期望值降低到一個最低的平均水準。這樣的話,你可以把代碼劃分為不同的范圍,并為每個范圍設(shè)置不同的期望水平。
例如,考慮一個即將為電子商務(wù)網(wǎng)站實現(xiàn)新特性的團隊。他們希望這個新特性能夠比代碼庫中的其他特性更健壯、更易于維護。為了實現(xiàn)這一點,他們在配置靜態(tài)代碼分析工具(如 ESLint 和 TypeScript)時采用比代碼庫的其他部分更嚴格的規(guī)則,并針對專門為該特性而創(chuàng)建的目錄使用覆蓋的方式啟用更多的規(guī)則。通過這種方式,團隊可以提高新代碼的質(zhì)量,而不必急于對代碼庫中“遺留”的部分進行現(xiàn)代化處理。
"rules": {
"prettier/prettier": "error",
"deprecation/deprecation": "warn"
},
"overrides": [
{
// Tolerate warnings on non critical issues from legacy JavaScript files
"files": ["*.js"],
"rules": {
"prefer-const": "warn",
"no-inner-declarations": ["warn", "functions"],
"@typescript-eslint/ban-ts-comment": "warn",
"@typescript-eslint/no-var-requires": "off"
}
},
{
// Enforce stricter rules on domain / business logic
"files": ["app/domain/**/*.js", "app/domain/**/*.ts"],
"extends": ["async", "async/node", "async/typescript"],
"rules": {
"prefer-const": "error",
"no-async-promise-executor": "error",
"no-await-in-loop": "error",
"no-promise-executor-return": "error",
"max-nested-callbacks": "error",
"no-return-await": "error",
"prefer-promise-reject-errors": "error",
"node/handle-callback-err": "error",
"node/no-callback-literal": "error",
"node/no-sync": "error",
"@typescript-eslint/await-thenable": "error",
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-misused-promises": "error",
"@typescript-eslint/promise-function-async": "error"
}
}
]
復制代碼
通過配置覆蓋,我們可以為不同的部分設(shè)置不同的 ESLint 規(guī)則
與之類似,如果要對整個代碼庫進行現(xiàn)代化改造,也要循序漸進。你可以創(chuàng)建一個具有更嚴格規(guī)則的專用目錄,并逐漸將遺留代碼遷移至該目錄,同時修復代碼的警告和類型錯誤。
有種方式是逐步將功能范圍中陳舊的部分遷移到更好的設(shè)計中。例如,選擇一個難以編寫自動化測試的特性,并將它的實現(xiàn)遷移到六邊形架構(gòu)中,將業(yè)務(wù)/領(lǐng)域邏輯根據(jù)輸入命令(即“API”)和副作用(即“SPI”)分離開來。通過編寫自動化測試來指導遷移,并將新的實現(xiàn)放在具有更嚴格靜態(tài)代碼分析規(guī)則的專用目錄中。
import { makeFeatures } = from './domain/features';
import { userCollection } from './infrastructure/mongodb/UserCollection';
import { ImageStorage } from './infrastructure/ImageStorage.js';
/** @type {import('./domain/api/Features').Features} Features*/
const features = makeFeatures({
userRepository: userCollection,
imageRepository: new ImageStorage(),
});
routes.post('/avatar', (request, response) => {
features
.setAvatar(request.session.userId, request.files[0])
.then(
() => response.json({ ok: true },
(error) => response.json({ ok: false })
);
});
復制代碼
setAvatar特性經(jīng)過了重新設(shè)計,由于采用了依賴反轉(zhuǎn),使其易于單獨進行測試。下面是我們遷移另一項特性的過程,即播放列表刪除
如果你決定遵循這一路徑,如下是一些建議:
在遷移完每個限界上下文之后,你將會得到一個代碼庫,在代碼庫中 100%的代碼都應(yīng)按照更嚴格的規(guī)則進行檢查。
盡管使用了靜態(tài)分析工具來檢測缺陷,使用了自動化測試來探測回歸,但用戶還是會在生產(chǎn)環(huán)境中發(fā)現(xiàn)問題。這是無法避免的。但是,有一種方法可以降低出現(xiàn)此類問題的概率,并縮短團隊修復問題的時間:
簡約版答案:因為DORA研究項目發(fā)現(xiàn),大多數(shù)執(zhí)行團隊每天都在進行部署,或者每天部署多次。
詳盡版答案:
在生產(chǎn)環(huán)境中出現(xiàn)意料之外的行為是可以的。在有些情況下,這甚至是一件好事。
當意料之外的行為給企業(yè)和/或開發(fā)團隊帶來巨大損失時(例如,網(wǎng)站中斷,導致幾個小時無法使用),開發(fā)人員應(yīng)該采取措施防止類似的事件再次發(fā)生。
有多種方式可以探測生產(chǎn)環(huán)境中的問題:
無論是哪種情況,開發(fā)人員都需要以下信息:問題是什么、問題的具體表現(xiàn)(如錯誤信息)、如何重現(xiàn)問題(如環(huán)境+過程),以及用戶的初衷和期望是什么。
但是,如何在最糟糕的情況下獲得這些數(shù)據(jù)呢?這就是錯誤監(jiān)控工具(如Sentry)的用武之地了。通過將它們注入到生產(chǎn)環(huán)境中運行的產(chǎn)品中,它們就能像探針一樣檢測運行時錯誤,并將它們匯總到已知錯誤的列表中,直到每個錯誤都被開發(fā)人員修復為止。此外,它們還會獲取有關(guān)錯誤上下文的數(shù)據(jù)(如用戶代理、所使用軟件的版本、操作系統(tǒng)、確切的時間戳等),以幫助開發(fā)人員重現(xiàn)錯誤。
但令人遺憾的是,與靜態(tài)代碼分析器類似,這些工具并不能解決問題。因此,與警告和類型錯誤一樣,要確保盡快處理每個錯誤。團隊讓錯誤累積得越多,使用這些工具的動力和效率就會越低。
此外,在使用這類監(jiān)控工具時,請確保個人和/或機密數(shù)據(jù)不會從系統(tǒng)中泄露出去。
從戰(zhàn)術(shù)上講,有許多方法可供選擇。你可以讓一名開發(fā)人員負責修復生產(chǎn)環(huán)境的錯誤,并將其作為最優(yōu)先的事項。這個角色可以定期輪換(比如每天),這樣可以激勵每個人都編寫更健壯的代碼。或者,也可以在每天的會議上將新錯誤單獨分派給志愿開發(fā)人員。
不必慌張!當生產(chǎn)環(huán)境中發(fā)生事故時,都要遵守如下程序:
避免重蹈覆轍的關(guān)鍵在于上述程序的最后一步。
這也是經(jīng)常被忽視的過程。大多數(shù)情況下,是因為沒人覺得自己有責任這樣做。很多時候,是因為產(chǎn)品負責人(或產(chǎn)品團隊)向開發(fā)人員施壓,要求他們優(yōu)先完成開發(fā)計劃中的特性,而不是保護現(xiàn)有代碼和/或調(diào)整開發(fā)流程。有時,開發(fā)人員自己也會決定開發(fā)更多的特性,而不是避免再次犯錯。
調(diào)查事故根本原因時的注意事項
在這個方面,“5 個為什么(5 WHY)”技巧是很有用的。例如:
在本例中,根本原因是整個網(wǎng)站都依賴于遺留的會話管理后端,這使得導航難以預測,有時還會導致生產(chǎn)環(huán)境崩潰。因此,除非團隊修復傳統(tǒng)的會話管理后端,否則類似的崩潰很可能很快就會在生產(chǎn)環(huán)境中再次發(fā)生。團隊現(xiàn)在應(yīng)該修復遺留的會話管理后端嗎?也許不用。但是他們應(yīng)該努力制定一個能夠?qū)崿F(xiàn)該目標的補救計劃。
讓一位開發(fā)人員負責確保盡快發(fā)現(xiàn)生產(chǎn)中的意外行為(如運行時錯誤、缺陷、事故……),盡快修復,并采取措施防止今后再次發(fā)生各類問題。
通過這種方式,開發(fā)人員能夠感受到有能力在良好的條件下開展工作。例如,在生產(chǎn)過程中設(shè)置恰當?shù)谋O(jiān)控和日志,確保撰寫有用的事后報告,并采取預防措施。
當信心達到良好水平時,逐步增加部署頻率。
此時,開發(fā)人員就具備了編寫高質(zhì)量軟件,并盡快發(fā)現(xiàn)缺陷的能力。這些缺陷最好是在設(shè)計或?qū)崿F(xiàn)時發(fā)現(xiàn),而不是在生產(chǎn)環(huán)境中。他們能夠快速發(fā)現(xiàn)并修正生產(chǎn)環(huán)境的錯誤,不會重復犯同樣的錯誤。他們對自己的代碼和開發(fā)流程充滿信心,因此每天都能在生產(chǎn)中實現(xiàn)改善。而且,他們在對軟件功能化范圍進行預期改善的同時,也會逐步改善代碼庫中最古老部分的設(shè)計和質(zhì)量,使其保持健康、穩(wěn)健并易于長期維護。
但是,令人遺憾的是,這種平衡很快就可能被瓦解。舉例來說:
防止或解決這類情況可能會非常困難,因為這需要良好的領(lǐng)導力和/或軟技能。
一個常見的錯誤是培養(yǎng)某種思維定式,即開發(fā)人員應(yīng)該主要致力于實現(xiàn)優(yōu)先的、計劃好的和設(shè)計好的特性。
這樣做是有問題的,因為:
下面是一些關(guān)于如何避免上述陷阱的建議:
JavaScript 語言及其不斷變化的軟件包和實踐組成的生態(tài)系統(tǒng)會使代碼庫迅速變得難以維護。正如我們在本文所討論的那樣,無需從頭重寫所有的內(nèi)容,也無需暫停新特性的開發(fā),就可以避免由此造成的開發(fā)速度和/或代碼質(zhì)量的下降。
關(guān)于如何在 TypeScript 和 JavaScript 項目中應(yīng)用這些推薦做法的更多實用建議,我建議你參考Yoni Goldberg的最佳實踐列表。它們是為 Node.js(后端)項目編寫的,但其中很多也適用于前端代碼庫。
原文鏈接:前端老手10年心得,JavaScript/TypeScript項目保養(yǎng)實用指南_架構(gòu)/框架_InfoQ精選文章
了在TypeScript中封裝一個獲取當前年前后十年的方法,您可以定義一個函數(shù),接受一個參數(shù)表示偏移量(正數(shù)表示未來年份,負數(shù)表示過去年份),并返回相應(yīng)年份的數(shù)組。以下是一個實現(xiàn)示例:
function getYearsAroundCurrentDecade(offset: number): number[] {
const currentYear = new Date().getFullYear();
const startYear = Math.floor(currentYear / 10) * 10 + offset;
// Ensure we don't go beyond the year range supported by JavaScript's `Date` object.
const minYear = 0;
const maxYear = 9999;
if (startYear < minYear || startYear > maxYear) {
throw new Error(`The specified offset ${offset} leads to an out-of-range year.`);
}
// Generate an array of years spanning the decade.
const years = [];
for (let year = startYear; year < startYear + 10 && year <= maxYear; year++) {
years.push(year);
}
return years;
}
// Usage examples:
console.log(getYearsAroundCurrentDecade(0)); // [2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029]
console.log(getYearsAroundCurrentDecade(-1)); // [2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019]
console.log(getYearsAroundCurrentDecade(1)); // [2030, 2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038, 2039]
這個函數(shù)首先獲取當前年份,然后根據(jù)偏移量計算出目標十年的起始年份。它確保起始年份在JavaScript `Date`對象支持的合理范圍內(nèi)(通常是從公元0年到公元9999年),超出范圍時拋出錯誤。接著,函數(shù)使用循環(huán)生成包含十年內(nèi)所有年份的數(shù)組,并返回該數(shù)組。
通過調(diào)用此函數(shù)并傳入不同的偏移量值(如`0`表示當前十年,`-1`表示前一個十年,`1`表示下一個十年),您可以輕松獲取所需年份范圍。
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。