🔍 搜尋結果:結構

🔍 搜尋結果:結構

創作 RawJS 之後,我再也沒有碰過 React。

早在 2012 年 10 月,TypeScript 0.8 就發布了。當時我正在開發一個中型 JavaScript 專案。它發布的那天,我閱讀了最初的規範,在玩了大約 10 分鐘後,我確信這將是未來,因此我開始用 TypeScript 重寫我的整個應用程式。相對於標準無型別 JavaScript 的好處是巨大的。 我對 [RawJS](https://www.squaresapp.org/rawjs/) 也有同樣的感覺。 [RawJS 是一個小型函式庫](https://github.com/squaresapp/rawjs),它使普通 JavaScript 應用程式開發更符合人體工學。它不僅僅是當今最新的 Web 框架,可以與 React、Vue、Svelte 或其他框架競爭。 RawJS 是不同的。 RawJS 直觀地說明了為什麼框架本身的整個前提可能有點誤導。它表明大多數應用程式最好使用普通 JS 並採用某些程式模式。 我知道這是一個非常大膽的聲明。但我懇請您研究一下 RawJS 誕生背後的心態和想法。 ## React 往往會破壞專案的複雜性 我不認為我說 React 太複雜是太過分了。畢竟,Svelte 正是因此而專門建立的。 React 會導致應用程式臃腫。舉個例子——我最近接到了一項任務,負責監督一個 React 應用程式的開發,該應用程式的複雜性已經失控。我最終扔掉了整個應用程式,並使用 RawJS 重建了整個應用程式,使用了一個從未接觸過 RawJS 的團隊,甚至根本沒有做過很多直接的 DOM 操作。幾週之內,團隊就加快了速度,現在該應用程式比以前的 React 應用程式小了約 90%。不,這不是一個錯字。 我們現在已經到了這樣一個階段:React 是「沒有人會因為購買 IBM 而被解僱」的選擇。問題是——人們「應該」因為購買 IBM 而被解僱。這是一個隱喻,指的是那些懶得做充分的需求分析、默認從眾心態、出於恐懼和懶惰而盲目跟隨大多數其他人正在使用的東西的人。 一旦您有幸使用 RawJS 加速的普通 JavaScript 開發應用程式,React 的過度複雜程度就會變得更加清晰。 RawJS 對 props、state、hooks、JSX、從特定基礎強制繼承(React.Component)、虛擬 DOM、自動資料綁定以及 React 所做的一切的必要性提出了質疑。 React 的膨脹及其施加的限制(例如禁止您直接編輯 DOM)都集中在試圖維護其虛擬 DOM 系統的完整性,我認為這是針對特定領域問題的解決方案對於facebook.com,那些精心建置的應用程式根本不具備。 所謂的直接 DOM 操作的效能劣勢被嚴重誇大了。事實上,如果做得正確,直接 DOM 操作通常會提高效能。這是因為您能夠精確控制 DOM 的更新方式。它允許您根據需要使用手術刀更新 DOM 的微小區域。虛擬 DOM 與此相反。它是一個生硬的工具,在大量 DOM 子樹上執行複雜的比較演算法,以便自動計算需要更新的內容。 自動資料綁定和反應性的有用性也被誇大了。假設您的程式碼組織良好,那麼建立您的應用程式以便 DOM 由於資料變更而更新似乎不會比僅建置應用程式以在必要時明確更新 DOM 所需的程式碼少。但與前者的區別在於,它給你強加了一個巨大的難以除錯的黑盒子,並迫使你遵守他們的官僚機構層。除非您組裝了一個精心建置的普通 JS 應用程式(例如使用 RawJS!),否則很難體會到擺脫這種情況的好處。 ## 為什麼沒有人談論匿名控制器類別? 匿名控制器類別(ACC)是一種需要引起更多關注的模式。它們是將普通 JavaScript 應用程式從雜亂無章轉變為連貫且美觀的關鍵想法之一。 ACC 的基本前提是建立一個與 DOM 中單一元素鬆散連接的物件,並且其垃圾收集生命週期等於所連接元素的生命週期。這是對繼承 HTMLElement 的一個進步,HTMLElement 是另一種選擇(但我不喜歡這種選擇,原因我將在另一篇文章中討論)。 考慮以下程式碼: ``` class SomeComponent { readonly head; constructor() { this.head = document.createElement("div"); this.head.addEventListener("click', () => this.click()); // Probably do some other stuff to this.head } private handleClick() { alert("Clicked!") } } ``` ACC 是建立單一 .head 元素(可能還有其他巢狀元素)、連接事件偵聽器、分配樣式等的類別。它們具有通常是事件處理程序或其他輔助方法的方法。然後實例化該元件,並將元件的 .head 元素加入 DOM: ``` const component = new SomeComponent(); document.body.append(component.head); ``` 該類別被視為“匿名”,因為一旦元件實例附加到 DOM,您就可以丟棄該實例。一旦元素從 DOM 中刪除並被垃圾回收,該類別的實例就會被垃圾回收,因為 DOM 是唯一擁有對它的引用的東西。例如: ``` class SomeComponent { readonly head; constructor() { this.head = document.createElement("div"); this.head.addEventListener("click', () => this.remove()); // Probably do some other stuff to this.head } private remove() { // Remove the component's .head element from the DOM, // which will by extension garbage collect this instance of // SomeComponent. this.head.remove(); } } ``` ACC 的優點在於它們基本上不會施加任何限制。他們可以繼承任何東西(或什麼都不繼承)。它們只是一個想法——您可以將它們塑造成您喜歡的樣子。 當然,在許多情況下您可能想要取得與特定元素關聯的 ACC。例如,想像一下迭代 this.head 元素的祖先元素,並取得與其關聯的 ACC 以呼叫某些公共方法。有一個名為 [HatJS](https://github.com/squaresapp/hatjs) 的輕量級程式庫,旨在改善使用 ACC 的人體工學。 **編輯:我是 HatJS 的作者。 「匿名控制器類別」是我發明的一個術語。這是在實驗過程中出現的模式,儘管我懷疑我是第一個發現它的人,因為這個概念非常明顯。就像 JSON 之前有名字一樣。您不需要將 HatJS 與 RawJS 一起使用。許多人正在建立普通的JavaScript 應用程式(或者對於迂腐的人來說是「普通的TypeScript 應用程式」),並且僅僅透過建立繼承自HTMLElement 的自訂元素,有效地將元素和控制器合併到同一個實體中,就取得了巨大的成功。我已經用這種方法建置了一些應用程式,並認為 ACC 更好,原因我會在以後的文章中介紹。** ## 改進 document.createElement() 具有令人驚訝的強大影響 儘管本文試圖為直接使用 DOM API 提供最有力的案例,但這些 API 絕對失敗的一個領域是使用屬性、樣式和事件附件來建立複雜的 DOM 層次結構。 DOM API 的這一部分非常冗長,如果沒有一些外部幫助,您的程式碼將比所需的長度長約 10 倍。這就是 RawJS 的用武之地。 RawJS 的設計正是為了一個目的。它使 document.createElement() 的人體工學性能提高了 10 倍。呼叫函數並取得 HTMLElement 實例的層次結構。它沒有任何其他作用。沒有奇怪的背景魔法。您可能不認為這聽起來很有影響力。但你的評估是錯的。 事實證明,在過去 15 年圍繞框架模式的構思中,我們不需要虛擬 DOM、反應性、資料綁定預編譯器或任何其他野生科學專案。我們需要匿名控制器類別模式和更好的方法來建立 HTMLElement 實例。 使用這兩種技術,我可以肯定地說,我永遠不會再故意使用 React 或任何其他競爭框架。這類框架根本無法提供超出 JavaScript 已經可以完成的功能,無法保證它們所施加的巨大權重和官僚作風。 那麼 RawJS 程式碼是什麼樣的呢?對 RawJS 建立者函數的呼叫遵循以下形式: ``` const htmlElement = raw.div(...parameters); ``` 強大的人體工學來自於可接受的參數的廣度(在 RawJS 中輸入為“Raw.Param”)。 參數可以是字串、數字、布林值、陣列、函數、DOM 節點實例、對 `raw.on("event", ...)` 的呼叫(建立可移植事件附件)以及幾乎任何其他內容。 RawJS 總是做你所期望的。 我不會重申使用 RawJS 來建立層次結構可以做的很棒的事情。快速入門對此進行了詳細介紹。 主要想法是,因為幾乎任何東西都可以是 Raw.Param,所以您可以建立迷你函數庫來產生 Raw.Params 列表並返回它們。由此可實現的程式碼重用水準是前所未有的。再說一次,除非你真正使用過它,否則很難欣賞它。我討厭與 LISP / 閉包進行比較,但還是有相似之處。 ## 我見過的最好的 CSS-in-JS 解決方案 如果不建構對應的 CSS,HTML 元素層次結建置構器有什麼用呢? RawJS 還擁有一流的 CSS-in-JS 解決方案,它可以完成我在任何其他解決方案中未見過的功能。例如,RawJS 完全支援僅限於特定元素的 CSS。 ``` const anchor = raw.a( // This constructs CSS within a global style sheet, // and the rules below will be scoped to the containing // anchor element. raw.css( ":focus", { outline: 0 }, ":visited": { color: "red" } ), raw.text("Hyperlink!") ); ``` 使用 RawJS 的 CSS-in-JS 解決方案還可以做很多其他事情。本文並不是 RawJS 教程,但如果您正在尋找此類內容,這裡有一個快速入門和一個演示應用程式。 ## 使用 DOM 作為狀態管理器實際上很好。 我們收到的一個常見的反對意見是,您將應用程式狀態儲存在哪裡?答案是使用 DOM 作為狀態管理器。 在你對此感到不寒而慄之前,請記住tailwind 如何率先提出在HTML 元素上刪除數百萬個類名的想法,有效地重新建立內聯CSS 的等價物,多年來,內聯CSS 一直被認為是一種反模式,但開發人員堅持它其實是很好,現在大家都在做嗎?同樣的想法也適用於使用 DOM 作為狀態管理器。 如今,每個人決定建立應用程式的方式都是從某種被視為「真相來源」的資料結構開始,然後您需要以某種方式將其笨拙地投影到 UI 中。以另一種方式做這件事被認為是“天真的”,甚至是反模式。但是,我想建議擁有兩個需要保持同步的獨立表示本身就是一種反模式。 嘗試使用某種框架以宣告方式將資料對應到 DOM 會導致複雜度大幅增加。這種技術的問題在於,對同一件事物有兩種不同的表示自然會比假設的只有一種這種表示的替代技術更加臃腫。 事實證明,如果您讓 ACC 接受輸入資料以便自行渲染,效果實際上會好得多。然後,您可以使用某種保存函數來檢查 DOM 的狀態以產生可保存的資料塊。這樣,您的事實來源不必與 DOM 同步,因為您的事實來源就是 DOM。 檢查以下程式碼範例: ``` class FormComponent { readonly head; private readonly firstNameInput; private readonly lastNameInput; constructor(firstName: string, lastName: string) { this.head = raw.form( this.firstNameInput = raw.input({ type: "text", value: firstName }), this.lastNameInput = raw.input({ type: "text", value: lastName }), raw.button( raw.text("Save"), raw.on("submit", () => this.save()) ) ); } private save() { const firstName = this.firstNameInput.value; const lastName = this.lastNameInput.value; SomeDatabaseSomewhere.save({ firstName, lastName }); alert("Saved!"); } } ``` 看?您只需將值儲存在 DOM 中即可。在本例中,我們使用文字輸入的值,但您也可以將資料儲存為 HTML 屬性、類別名稱或任何有意義的內容。 當然,在某些情況下,您需要儲存無法分解為字串、數字和布林值的狀態。我還看到一些狀態儲存在 ACC 內的屬性中的情況。做任何對你有用的事。 ## 元件之間的通信 在某些情況下,您可能需要更新多個元件以回應一項操作,或更簡單地在 ACC 之間發送訊息。 HatJS 可以幫助解決這個問題。 請記住,ACC 建立了一種隱藏的控制器層次結構。您擁有典型的 DOM 元素層次結構,但只有某些元素是 ACC 的頭元素。因此,這將建立自己的 ACC 層次結構,它是整個 DOM 元素層次結構的嚴格子集。 [HatJS](https://github.com/squaresapp/hatjs) 具有遍歷 ACC 層次結構的功能,並快速擷取可能位於或不位於元素後面的 ACC 實例。 ``` class ParentComponent { readonly head; constructor() { this.head = raw.div( new ChildComponent().head ); // Call Hat.wear() to define the object as a "hat" // and make it discoverable by HatJS Hat.wear(this); } callAlert() { alert("Hello!"); } } class ChildComponent { readonly head; constructor() { this.head = raw.div( raw.on("click", () => { // Hat.over finds the "Hat" (or the ACC) that exists // above the specified element in the hierarchy. // And passing ParentComponent gives you type-safe // tells HatJS what kind of component you're looking // for, and also gives you type-safe access to it. Hat.over(this, ParentComponent).callAlert() }) ); } } ``` 除了「Hat.over()」之外,還有「Hat.under()」、「Hat.nearest()」等方法來尋找 DOM 相對中可能存在或不存在的特定類型的其他 ACC到指定的元素。 ## 興奮起來! 那麼,我是否說服您啟動您的 React 應用程式並使用 RawJS 來重建您一生的工作?如果您想開始使用,請造訪 [這裡是 RawJS 網站](https://www.squaresapp.org/rawjs/)。 RawJS 的儲存庫是[此處](https://github.com/squaresapp/rawjs),HatJS 的儲存庫是[此處](https://github.com/squaresapp/hatjs) --- 原文出處:https://dev.to/paulgordon/after-using-rawjs-im-never-touching-react-again-or-any-framework-vanilla-javascript-is-the-future-3ac1

全端工具箱🧰:Python🐍版

## 簡介 以下是專注於全端開發不同面向的 Python 函式庫;有些專注於 Web 應用程式開發,有些專注於後端,有些則兩者兼而有之。 ![Gif引言](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8eodxlxdlgr0xh6lrvhz.gif) --- ## 1. [Taipy](https://github.com/Avaiga/taipy) Taipy 是一個開源 Python 庫,用於建立生產就緒的應用程式前端和後端。 它旨在加快應用程式開發,從最初的原型到生產就緒的應用程式。 🔑特點: - 豐富的互動性 - 為您的佈局、樣式等提供更多自訂功能(無需 CSS) - 多頁和多用戶應用程式 - 圖形管道編輯器 - 與 Taipy 前端功能整合以實現端到端部署 - 日程安排 - 筆記型電腦相容 ![Taipy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1rk0w837hwaq0akybw6o.png) --- ![QueenB GIF](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0un08vhstrk6zpst5yti.gif) https://github.com/Avaiga/taipy 您的支持意義重大🌱,並且在許多方面為我們帶來了很大的幫助,例如寫文章! 🙏 --- ## 2.[Prefect](https://github.com/PrefectHQ/prefect) Prefect 是一個提供資料管道開發的框架。 它透過注重簡單性和用戶友好性而與 Airflow 等競爭對手區分開來。 如果您想要一個具有各種功能但比 Airflow 更容易學習的成熟產品,Prefect 是一個很好的中間產品。 🔑特點: - 直覺且使用者友好的控制面板 - 快取等智慧功能 - 以流程為基礎的架構,可輕鬆融入工作流程組織 - 動態參數化與依賴管理 - 混合執行(本地/雲端) ![完美](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p94g40hwv04gkfmvklda.png) --- ## 3. [Streamlit](https://github.com/streamlit/streamlit) Streamlit 是一個遊戲規則改變者,可以快速、簡單地建立 Web 應用程式。 此資料應用程式框架將其從更完整、更複雜的解決方案轉變為快速、用戶友好的解決方案。 🔑特點: - Pythonic框架 - 互動式小部件 - 使用者友善性 ![Streamlit](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ddntytwa95tgp37kykcc.png) --- ## 4.[氣流](https://github.com/apache/airflow) Apache Airflow 是一個開源平台,專為調度和監控工作流程而設計。 它是編排複雜資料管道和 ETL 流程的絕佳選擇,因為它在過去十年中一直是管道領域的重要參與者。 該庫的完整性與陡峭的學習曲線有關。 🔑特點: - 基於DAG的工作流程定義 - 包括 DAG 視覺化的完整介面,可追蹤故障並管理重試。 - 各種集成 - 動態任務執行和調度 - 以Python為中心的設計 - 社區支持 ![氣流](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lm89iyieg07c2rgzm2jb.png) --- ## 5. [Brython](https://github.com/brython-dev/brython) Brython 將 Python 帶到了前端,因為這個名字重新組合了「瀏覽器」和「Python」。 它引入了直接在 Web 應用程式中執行 Python 程式碼的獨特概念。 這種創新方法可讓您使用 Python 建立互動式 Web 體驗。 🔑特點: - 易於集成,因為它將 Python 邏輯直接整合到瀏覽器中 - 相容於不同的網頁瀏覽器 ![Brython](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9a7w7lqd9b5rtpahnolr.png) --- ## 6. [達世幣](https://github.com/plotly/dash) Dash 由 Plotly 建立,是一個利用 Plotlys 元件完整性的 Web 應用程式框架。 眾所周知,它是一個完整的解決方案,因此需要更長的時間來掌握。 🔑特點: - 基於元件的架構 - 強大的互動式儀表板 - 即時資料更新 ![破折號](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yp5xw24ulak6mnwwos69.png) --- ## 7. [Dagster](https://github.com/dagster-io/dagster) Dagster 是本次編譯中較新的函式庫之一,它是一個雲端原生資料管道編排,旨在統一資料整合、工作流程編排和監控。 與其他工具相比,Dagster 強調工作流程建立和管理的 DataOps 面向。 🔑特點: - 聲明式管道設置 - 固執己見的結構 - 版本控制 - 與 Hadoop 集成 - 全面的元資料跟踪 ![Dagster](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hz78m7rein4asbyp9buf.png) --- ## 8. [SQLAlchemy](https://github.com/sqlalchemy/sqlalchemy) SQLAlchemy 是一個用於處理資料庫互動的 Python 函式庫。 它是一個連接Python程式設計和關係資料庫的多功能工具包。 掌握這個庫的時間較長,但好處是實實在在的。 🔑特點: - SQL 表達式語言 - 物件關係映射(ORM) - 對資料庫的廣泛支持 - 複雜查詢支持 ![SQL](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/owtvt0kv5gt45r33ulra.png) --- ## 9. [芹菜](https://github.com/celery/celery) Celery 是一個 Python 函式庫,用作建立後端應用程式的框架。 它處理分散式任務處理、作業執行和工作流程。 它是一個完整的解決方案和廣泛的功能集,具有更陡峭的學習曲線。 🔑特點: - 平行處理 - 可擴展性 - 任務調度 - 非同步處理 ![芹菜](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p50my0xtbncfskb4y1ga.png) --- ## 10. [Peewee](https://github.com/coleifer/peewee) 與 SQAlchemy 一樣,Peewee 是一個簡化資料庫互動的 Python 函式庫。 它與競爭對手的不同之處在於用戶友好且簡單的設定。 該庫是中小型專案的最佳選擇。 🔑特點: - 輕量級框架 - 資料庫支持 - Python式文法 ![Peewee](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8tmvc7y9vkb2mdpj88jq.png) --- ## 11. [Kedro](https://github.com/kedro-org/kedro) Kedro 是一個開源 Python 框架。 它為生產就緒的資料科學管道提供了一個工具箱。 事實上,Kedro 可以輕鬆地與成熟的 Python ML 庫集成,並提供統一的方法來實現端到端框架。 🔑特點: - 資料目錄 - 筆記本集成 - 專案模板 - 有自己的觀點,因為它強制執行特定的約定 ![Kedro](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x2z12ofiibpd5c9ggs7s.png) --- ## 結論 Python 被認為是人工智慧和機器學習應用程式的首選語言。 為了簡化和自動化這些應用程式,Python 見證了框架庫的出現。 這些程式庫有助於 Web 應用程式開發、後端服務以及開源全端應用程式的建立。 --- ![新秀圖片](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/25oebh36ha622u74kpli.gif) 我剛開始我的內容創作之旅;如果您有任何問題或回饋,請隨時與我們聯繫! --- 原文出處:https://dev.to/taipy/full-stack-toolbox-python-edition-20h2

網頁反應慢,怎麼辦?

看更多文章: 1. [使用 gRPC 和微服務建立可擴展的通知系統](https://dev.to/suprsend/building-a-scalable-notification-service-with-grpc-and-microservices-l6d) 2. [在 React 網站中新增通知來源](https://dev.to/suprsend/adding-a-notification-feed-in-react-websites-4oa0) 4. [2023 年現代應用通知基礎設施完整指南](https://dev.to/suprsend/a-complete-guide-on-notification-infrastruct-for-modern-applications-in-2023-13b9) --- 應用程式通常可以分為兩種類型的效能瓶頸: 1. **I/O 限制:** 這些應用程式將大部分時間花在處理輸入和輸出上。 2. **CPU 限制:** 這些應用程式將大部分時間花在運算任務上。 現在,這些分類如何轉化為前端應用程式的上下文,特別是 React 應用程式? **React 中的 I/O 效能挑戰** 當涉及到 React 應用程式時,經常會出現 I/O 效能方面的問題,主要與非同步 HTTP 呼叫相關。無效地管理這些網路請求可能會導致應用程式速度減慢。雖然這篇文章主要關注 CPU 效能,但有必要簡要介紹一下可以找到 I/O 限制問題解決方案的關鍵領域: - 盡可能實施延遲載入。 - 在初始載入資產和後端請求時請務必小心。 - 減少載入高度靜態元素的頻率(例如,選擇選項、配置)。 - 去抖特定請求的次數。 - 使用 Promise.all 等技術盡可能並行化請求。 - 透過優化資料庫存取等措施來提高關鍵後端端點的效率。 **React 中的 CPU 效能挑戰** 這篇文章的主旨是解決 React 中的 CPU 效能挑戰。在深入研究細節之前,讓我們先對效能建立一個具體的定義: - 瀏覽器應用程式主要作為單執行緒程式執行。 - 腳本任務,例如 JavaScript 執行、DOM 渲染和事件處理,都發生在同一個執行緒。 - 緩慢的 JavaScript 模組可能會阻塞主執行緒。 - 如果主執行緒被阻塞,使用者介面將變得無回應,導致每秒幀數 (fps) 下降。 - 響應式 UI 的目標是至少 30 fps,理想情況下達到 60 fps,這意味著每幀的計算時間應在 30 毫秒或更短的時間內。 在 React 的背景下,這個問題變得至關重要。當觸發 React 元件更新時,整個子樹必須在 30 毫秒內渲染完畢。對於複雜而冗長的元件結構(例如表、樹和列表),這變得尤其具有挑戰性,可能需要大規模重新渲染。 **反應渲染和提交階段** 從高層次來看,React 分為兩個不同的階段: **渲染階段:** - 當元件更新時啟動,由 props 或 hooks 的變更觸發。 - React 遍歷元件子樹,渲染每個子樹並計算虛擬 DOM (VDOM) 子樹。 - 只有受更新影響的「髒」子樹需要重新計算;更新元件的父元件可能不需要重新渲染。 - 此階段的效率與每個子元件的大小和計算成本成正比。 - React.memo 可用於提供更有效率渲染流程的提示。 **提交階段:** - 渲染階段產生整個 UI 的新虛擬 DOM。 - 在提交階段,React 將新樹與前一棵樹進行比較(VDOM 比較)。 - React 計算反映新 VDOM 樹所需的最小 DOM 突變。 - 套用 DOM 突變,更新 UI。 - 預設情況下,此階段本質上是高效的。 - 整個過程必須在 30 或 16 毫秒內完成(分別針對 30 fps 和 60 fps),UI 才會被視為回應。工作負載與應用程式的大小成正比。 後續探索將聚焦在提升Render階段的效率。在深入研究優化技術之前,了解如何測量和辨識應用程式中的緩慢元件至關重要。 **測量** 我經常依賴的工具包括: 1. **Chrome 開發工具的效能標籤** 2. **React Dev Tool 的效能標籤** **Chrome 開發工具的效能標籤** 該工具作為適用於任何瀏覽器應用程式的綜合資源而脫穎而出。它提供對每秒幀數的洞察、捕獲堆疊追蹤、辨識程式碼的慢速或熱點部分等等。主要使用者介面由火焰圖表示。 若要深入了解套用於 React 的 Chrome 效能選項卡,請參閱此[文件](https://developers.google.com/web/tools/chrome-devtools/evaluate-performance)。 **React 開發工具的效能標籤** 若要利用此工具,您需要在瀏覽器中安裝 React Dev Tool 擴充功能。它專門針對 React 客製化了 Chrome 開發工具效能標籤中的資訊。透過火焰圖,您可以觀察不同的提交階段以及在對應渲染階段執行的 JavaScript 程式碼。 該工具有助於輕鬆確定: - 當元件進行重新渲染時。 - 哪些道具改變了。 - 哪些鉤子發生了變化,包括狀態、上下文等等。有關更多詳細訊息,請參閱[介紹性帖子](https://reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html)。 **測量方法** 這是我在評估前端應用程式時更喜歡的方法: 1. **確定問題:** - 找出導致 UI 回應問題的頁面互動。 2. **建立一個假設:** - (可選)產生有關問題的潛在位置的想法。 3. **測量:** - 透過測量每秒幀數 (fps) 等基本指標來驗證問題。 4. **測量(第二部分):** - 辨識有問題的程式碼部分; (可選)驗證您的假設。 5. **建立解決方案:** - 根據收集到的見解實施解決方案。 6. **測量解決方案:** - 透過檢查關鍵指標來驗證實施的解決方案是否解決或緩解了問題。 在沒有適當衡量的情況下進行最佳化會使努力實際上變得無效。雖然有些問題可能很明顯,但大多數問題都需要徹底的測量,從而構成性能增強過程的基石。 此外,測量可讓您向上傳達成果,向使用者、利害關係人和您的領導層通報應用程式特定領域內實現的效能改進(以百分比增益表示)。 **React 應用程式中 CPU 限制問題的通用解決方案** 現在有了測量結果並了解了問題領域,讓我們深入研究潛在的解決方案。優化 React 效能圍繞著改進渲染的元件和渲染的元件。 許多效能問題也源自於反模式。消除這些反模式(例如避免渲染方法中的內聯函數定義)有助於提高渲染時間。事實上,解決不良模式可以降低複雜性並同時提高效能。 **🤔 改進元件渲染** 辨識 React 應用程式中的緩慢元件通常指的是難以渲染或單一頁面上實例數量過多的特定元件。多種原因可能導致他們行動遲緩: - 元件內的阻塞計算。 - 渲染大型元件樹。 - 使用昂貴或低效率的函式庫。 大多數這些問題都歸結為提高元件渲染的速度。有時,關鍵元件不能依賴過於複雜的函式庫,需要回歸基本原則並實施更簡單的替代方案。 例如,我在複雜表格中每行的多個單元格中過度使用 Formik 時遇到了此類挑戰。雖然提高單一元件的效率還有很長的路要走,但注意力最終必須轉移到正在渲染的元件上。 **🧙 改進哪些元件渲染** 這方面提供了兩大類改進: 1. **虛擬化:** - 僅渲染視窗中可見的元件。例如,僅呈現使用者可以看到的表格行或清單專案。事實證明,這種方法對於複雜的 UI 是有益的,雖然可以在不解決「內容」步驟的情況下應用它,但建議這樣做。現代函式庫通常為虛擬化表和清單提供強大的支持,例如“react-virtualized”。虛擬化減少了 React 需要在給定幀中渲染的元件數量。 2. **道具優化:** - React 的目標是使元件類似於純函數,但可能會嘗試渲染不必要的次數。 **反應.備忘錄:** - React 中的大多陣列件都可以被記憶,確保使用相同的 props,元件返回相同的樹(儘管鉤子、狀態和上下文仍然受到尊重)。如果它們的 props 保持不變,則利用 `React.memo` 通知 React 跳過重新渲染這些已記憶的元件。 ``` import React from 'react'; const MyComponent = React.memo((props) => { // Component logic here }); export default MyComponent; ``` **假道具更改:useCallback:** - 解決虛假道具更改問題涉及道具內容保持不變但引用發生變化的情況。一個典型的例子是事件處理程序。 ``` import React, { useCallback } from 'react'; const MyComponent = () => { const onChange = useCallback((e) => console.log(e), []); return <input onChange={onChange} />; }; export default MyComponent; ``` **假道具更改:useMemo:** - 在將複雜資料結構作為 props 傳遞之前,在沒有適當記憶的情況下建立複雜的資料結構時,也會出現類似的挑戰。利用「useMemo」可確保僅在依賴項發生變更時才重新計算行,從而提高效率。 ``` import React, { useMemo } from 'react'; const MyComponent = ({ data, deps }) => { const rows = useMemo(() => data.filter(bySearchCriteria).sort(bySortOrder), [deps]); return <Table data={rows} />; }; export default MyComponent; ``` 雖然您可以靈活地自訂「React.memo」如何比較目前與先前的道具,但保持快速運算至關重要,因為它是渲染階段不可或缺的一部分。避免在每次渲染期間過於複雜的深度比較。 ## 現在看起來怎麼樣? ### 道具已更改 它在 React 開發工具中的樣子: ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k0wsxe16icfytqfamg3p.png) 他們真的嗎?它們是假的道具更改嗎?使用`useCallback`和`useMemo`。 ### 父渲染 它在 React 開發工具中的樣子: ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ilqb2astlchzto603anc.png) 使用“React.memo”來記住您的純元件。 ### 掛鉤已更改(狀態、上下文) 它在 React 開發工具中的樣子: ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k8beosx4hh1n90ejts3h.png) 這裡沒有什麼太明顯的事情要做。嘗試驗證更改的鉤子是否有意義。也許一個糟糕的上下文提供者正在以與假道具更改可能出現的方式相同的方式偽造更改。 --- > 與此類似,我個人在 Slack 上經營著一個由開發人員主導的社群。我們在其中討論這些類型的實現、整合、一些真相炸彈、奇怪的聊天、虛擬會議以及一切有助於開發人員保持理智的事情;)畢竟,太多的知識也可能是危險的。 > 我邀請您加入我們的免費社區,參與討論,並分享您的驚人經驗和專業知識。您可以填寫此表格,Slack 邀請將在幾天後收到您的電子郵件。我們擁有來自一些偉大公司(Atlassian、Scaler、Cisco、IBM 等)的出色人員,您一定不想錯過與他們的互動。 [邀請表](https://forms.gle/VzA3ST8tCFrxt39U9) --- 您可能想要查看整合通知基礎架構的無縫方式。 https://github.com/suprsend/suprsend-go --- 原文出處:https://dev.to/nikl/react-is-slow-what-to-do-now-369g

JS 設計模式:綜合指南

![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vukjahraekzzsj9e6h3x.png) JavaScript 以其廣泛的採用和多功能性,已成為現代 Web 開發的基石。隨著您深入研究 JavaScript 開發,理解和利用模式變得至關重要。在本文中,我們將踏上揭開 JavaScript 模式神秘面紗的旅程,並探索它們如何增強您的程式設計實踐。 ## 先決條件 要理解本文中討論的概念和技術,您需要了解 JavaScript 的基礎知識。熟悉變數、函數、資料類型、物件導向程式設計等概念至關重要。 在繼續之前,讓我們花點時間了解 JavaScript 作為程式語言的重要性。 ### JavaScript 作為程式語言 JavaScript 通常被稱為“網路語言”,是一種動態的高階程式語言。它主要用於 Web 瀏覽器中的客戶端腳本編寫,但隨著 Node.js 的出現,它也在伺服器端獲得了關注。 JavaScript 的主要功能包括操作 DOM、處理事件、為網頁提供互動性等的能力。 話雖這麼說,讓我們簡單討論一下 JavaScript 中模式的重要性和用途。 ### JavaScript 開發中模式的重要性 JavaScript 中的模式可以作為軟體開發過程中遇到的重複問題的經過驗證的解決方案。它們提供結構、改進程式碼組織、增強可維護性並促進可重複使用性。透過理解和應用模式,開發人員可以編寫更清晰、更有效率的程式碼並有效應對複雜的挑戰。 ### 理解 JavaScript 模式的目的 理解 JavaScript 模式不僅僅是記住文法或遵循最佳實踐。它使開發人員能夠批判性地思考軟體設計、選擇適當的解決方案並建立可擴展的應用程式。透過掌握 JavaScript 模式,您可以深入了解該語言及其生態系統,從而能夠編寫健全且可維護的程式碼。 現在我們知道了 JavaScript 模式的重要性和用途,讓我們深入研究 JS 設計模式的基礎知識。 ## 設計模式的基礎知識 在本節中,我們為理解 JavaScript 開發背景下的設計模式奠定了基礎。 ###設計模式的定義與特點 設計模式是可重複使用的模板,封裝了解決重複出現的軟體設計問題的最佳實踐。它們提供了一種結構化的方法來設計軟體系統,並促進模組化、靈活和可維護的程式碼。設計模式的共同特徵包括其目的、結構、參與者和協作。 ###設計模式的類型 設計模式可分為三種主要類型: - 創意 - 結構性 - 行為的 了解這些類別有助於確定給定問題的適當模式。 - **創作模式** 建立模式專注於物件建立機制,提供以靈活且受控的方式實例化物件的方法。 JavaScript 中一些常用的建立模式包括: - 辛格頓 - 工廠 - 建構函數 - 原型 - 建造者 - 模組 **單例模式** 單例模式確保一個類別只有一個實例,並提供對其的全域存取點。當您想要限制類別的實例數量並確保在整個應用程式中可以存取單一共用實例時,此模式非常有用。 ``` // Implementation example of the Singleton Pattern class Singleton { constructor() { if (!Singleton.instance) { // Initialize the instance Singleton.instance = this; } return Singleton.instance; } } const instance1 = new Singleton(); const instance2 = new Singleton(); console.log(instance1 === instance2); // Output: true ``` 在此範例中,Singleton 類別有一個建構函數,用於檢查該類別的實例是否已存在。如果實例不存在(“!Singleton.instance”條件),它將透過將其指派給「Singleton.instance」來初始化該實例。這確保了對建構函數的後續呼叫將傳回相同的實例。 當使用新的 Singleton() 語法建立實例 1 和實例 2 時,這兩個變數都會引用 Singleton 類別的同一個實例。因此,當使用嚴格相等運算子比較實例 1 === 實例 2 時,其計算結果為 true。 **工廠模式** 工廠模式提供了一種建立物件而無需指定其特定類別的方法。它將物件建立邏輯封裝在一個單獨的工廠方法中,允許建立者和建立的物件之間的靈活性和解耦。 ``` // Implementation example of the Factory Pattern class Car { constructor(make, model) { this.make = make; this.model = model; } } class CarFactory { createCar(make, model) { return new Car(make, model); } } const factory = new CarFactory(); const myCar = factory.createCar("Tope", "Model 1"); ``` 在此範例中,使用 new CarFactory() 建立了一個 CarFactory 實例,然後使用參數「Tope」和「Model 1」在工廠上呼叫「createCar」方法。這將建立一個新的 Car 物件,其品牌為“Tope”,型號為“Model 1”,並分配給 `myCar` 變數。 **建構函式模式** 建構函式模式使用“new”關鍵字從建構函式建立物件。它允許您在建構函數中定義和初始化物件屬性。 ``` // Implementation example of the Constructor Pattern function Person(name, age) { this.name = name; this.age = age; } const tope = new Person("Tope", 24); ``` 上面的程式碼定義了一個名為 Person 的建構函數,它帶有兩個參數:姓名和年齡。在函數內部,使用 this 關鍵字將名稱和年齡值指派給新建立的物件的對應屬性。 稍後,透過使用參數“Tope”和 24 呼叫 Person 函數來建立 Person 物件的新實例。這將建立一個新物件,其 name 屬性設為“Tope”,age 屬性設為 24,然後指派給變數top。這段程式碼的輸出是 Tope 持有一個物件,代表一個名為「Tope」、年齡為 24 歲的人。 **原型模式** JavaScript 中的原型模式專注於透過複製或擴展現有物件作為原型來建立物件。它允許我們建立新實例而無需明確定義它們的類別。在此模式中,物件充當建立新物件的原型,從而實現繼承以及在多個物件之間共享屬性和方法。 ``` // Prototype object const carPrototype = { wheels: 4, startEngine() { console.log("Engine started."); }, stopEngine() { console.log("Engine stopped."); } }; // Create new car instance using the prototype const car1 = Object.create(carPrototype); car1.make = "Toyota"; car1.model = "Camry"; // Create another car instance using the same prototype const car2 = Object.create(carPrototype); car2.make = "Honda"; car2.model = "Accord"; car1.startEngine(); // Output: "Engine started." car2.stopEngine(); // Output: "Engine stopped." ``` 在此範例中,汽車實例 car1 和 car2 是使用原型物件 carPrototype 建立的。 car1 的品牌為“Toyota”,型號為“Camry”,而 car2 的品牌為“Honda”,型號為“Accord”。當呼叫 `car1.startEngine()` 時,輸出“Engine started.”,當呼叫 `car2.stopEngine()` 時,輸出“Engine waiting.”。這示範如何利用原型物件在多個實例之間共用屬性和方法。 **建造者模式** 在建構器模式中,建構器類別或物件負責建構最終物件。它提供了一組方法來配置和設定正在建置的物件的屬性。建置過程通常涉及按特定順序呼叫這些方法來逐步建立物件。 ``` class CarBuilder { constructor() { this.car = new Car(); } setMake(make) { this.car.make = make; return this; } setModel(model) { this.car.model = model; return this; } setEngine(engine) { this.car.engine = engine; return this; } setWheels(wheels) { this.car.wheels = wheels; return this; } build() { return this.car; } } class Car { constructor() { this.make = ""; this.model = ""; this.engine = ""; this.wheels = 0; } displayInfo() { console.log(`Make: ${this.make}, Model: ${this.model}, Engine: ${this.engine}, Wheels: ${this.wheels}`); } } // Usage const carBuilder = new CarBuilder(); const car = carBuilder.setMake("Toyota").setModel("Camry").setEngine("V6").setWheels(4).build(); car.displayInfo(); // Output: Make: Toyota, Model: Camry, Engine: V6, Wheels: 4 ``` 在此範例中,「CarBuilder」類別允許建構具有不同屬性的 Car 物件。透過呼叫`setMake`、`setModel`、`setEngine`、`setWheels`方法,設定Car物件的屬性。 build 方法完成建置並傳回完全建置的 Car 物件。 Car 類別代表一輛汽車,並包含一個「displayInfo」方法來記錄其詳細資訊。透過建立「carBuilder」實例並連結屬性設定方法,可以使用特定的品牌、型號、引擎和車輪值來建構汽車物件。呼叫“car.displayInfo()”顯示汽車的資訊。 **模組模式** 模組模式將相關的方法和屬性封裝到單一模組中,提供了一種乾淨的方式來組織和保護程式碼。它允許私有和公共成員,從而實現資訊隱藏並防止全域名稱空間污染。 ``` const MyModule = (function() { // Private members let privateVariable = "I am private"; function privateMethod() { console.log("This is a private method"); } // Public members return { publicVariable: "I am public", publicMethod() { console.log("This is a public method"); // Accessing private members within the module console.log(privateVariable); privateMethod(); } }; })(); // Usage console.log(MyModule.publicVariable); // Output: "I am public" MyModule.publicMethod(); // Output: "This is a public method" "I am private" "This is a private method" ``` 在此範例中,程式碼使用立即呼叫的函數表達式來封裝私人和公共成員。該模組具有私有變數和方法,以及公共變數和方法。存取時,公共成員提供預期的輸出。此模式允許對封裝的私有成員進行受控存取,同時公開選定的公共成員。 - **結構模式** 結構模式著重於組織和組合物件以形成更大的結構。它們促進物件的組合,定義物件之間的關係並提供靈活的方法來操縱其結構。 JavaScript 中一些常用的結構模式包括: - 裝飾模式 - 立面圖案 - 適配器 - 橋 - 合成的 **裝飾器模式** 裝飾器模式可讓您動態新增行為或修改物件的現有行為。它透過用一個或多個裝飾器包裝物件來增強物件的功能,而無需修改其結構。 ``` // Implementation example of the Decorator Pattern class Coffee { getCost() { return 1; } } class CoffeeDecorator { constructor(coffee) { this.coffee = coffee; } getCost() { return this.coffee.getCost() + 0.5; } } const myCoffee = new Coffee(); const coffeeWithMilk = new CoffeeDecorator(myCoffee); console.log(coffeeWithMilk.getCost()); // Output: 1.5 ``` 在此範例中,「CoffeeDecorator」類別包裝了基本「Coffee」物件並新增了附加功能。它有一個「getCost」方法,透過將基礎咖啡的成本與 0.5 的附加成本相結合來計算總成本。 在使用部分,建立了「Coffee」類別的「myCoffee」實例。然後,實例化「CoffeeDecorator」類別的「coffeeWithMilk」實例,並將「myCoffee」作為參數傳遞。當呼叫“coffeeWithMilk.getCost()”時,它會返回咖啡的總成本以及裝飾器加入的成本,從而得到 1.5 的輸出。此範例說明了裝飾器模式如何透過動態新增或修改物件的屬性或方法來擴展物件的功能。 **立面圖案** 外觀模式為複雜子系統提供了一個簡化的接口,充當隱藏底層實現細節的前端接口。它透過提供高級接口,提供了一種與複雜系統互動的便捷方式。 ``` // Implementation example of the Facade Pattern class SubsystemA { operationA() { console.log("Subsystem A operation."); } } class SubsystemB { operationB() { console.log("Subsystem B operation."); } } class Facade { constructor() { this.subsystemA = new SubsystemA(); this.subsystemB = new SubsystemB(); } operation() { this.subsystemA.operationA(); this.subsystemB.operationB(); } } const facade = new Facade(); facade.operation(); // Output: "Subsystem A operation." "Subsystem B operation." ``` 在此範例中,程式碼由三個類別組成:「SubsystemA」、「SubsystemB」和「Facade」。 `SubsystemA` 和 `SubsystemB` 類別代表獨立的子系統,並具有各自的 `operationA` 和 `operationB` 方法。 「Facade」類別作為一個簡化的接口,聚合了子系統的功能。 在使用部分,建立了“Facade”類別的“facade”實例。呼叫「facade.operation()」會觸發「SubsystemA」中的「operationA」和「SubsystemB」中的「operationB」的執行。結果,輸出顯示“子系統 A 操作”。接下來是「子系統 B 操作」。這展示了外觀模式如何提供統一且簡化的介面來與複雜的子系統交互,抽像出它們的複雜性並使它們更易於使用。 **適配器模式** 適配器模式是一種結構設計模式,它允許具有不相容介面的物件透過充當它們之間的橋樑來進行協作。它提供了一種將一個物件的介面轉換為客戶期望的另一個介面的方法。 ``` // Implementation class LegacyPrinter { printLegacy(text) { console.log(`Legacy Printing: ${text}`); } } // Target interface class Printer { print(text) {} } // Adapter class PrinterAdapter extends Printer { constructor() { super(); this.legacyPrinter = new LegacyPrinter(); } print(text) { this.legacyPrinter.printLegacy(text); } } // Usage const printer = new PrinterAdapter(); printer.print("Hello, World!"); // Output: "Legacy Printing: Hello, World!" ``` 在此程式碼中,適配器模式用於彌合「LegacyPrinter」類別和所需的「Printer」介面之間的差距。 `PrinterAdapter` 擴展了 `Printer` 類,並在內部利用 `LegacyPrinter` 來適配 `print` 方法。當呼叫 printer.print("Hello, World!")` 時,它會有效地觸發舊版列印功能,並輸出「Legacy Printing: Hello, World!」。這展示了適配器模式如何透過提供標準化介面來整合不相容的元件。 **橋樑圖案** 橋接模式是一種結構設計模式,它將系統的抽象和實現分開,允許系統獨立發展。它透過使用介面或抽象類別在兩者之間引入了橋樑。下面是一個範例程式碼片段來說明橋接模式: ``` // Example class Shape { constructor(color) { this.color = color; } draw() {} } // Concrete Abstractions class Circle extends Shape { draw() { console.log(`Drawing a ${this.color} circle`); } } class Square extends Shape { draw() { console.log(`Drawing a ${this.color} square`); } } // Implementor class Color { getColor() {} } // Concrete Implementors class RedColor extends Color { getColor() { return "red"; } } class BlueColor extends Color { getColor() { return "blue"; } } // Usage const redCircle = new Circle(new RedColor()); redCircle.draw(); // Output: "Drawing a red circle" const blueSquare = new Square(new BlueColor()); blueSquare.draw(); // Output: "Drawing a blue square" ``` 在此範例中,我們有由 Shape 類別表示的抽象,它具有顏色屬性和繪製方法。具體抽象(圓形和方形)繼承自 Shape 類別並實現其特定的繪製行為。 「Implementor」由 Color 類別表示,該類別聲明了「getColor」方法。具體的「Implementors」、「RedColor」和「BlueColor」繼承自 Color 類別並提供各自的顏色實作。 在使用部分,我們建立具體抽象的實例,傳遞適當的具體實現者物件。這允許抽象化將與顏色相關的功能委託給實現者。當我們呼叫draw方法時,它會從Implementor存取顏色並相應地執行繪圖操作。 **複合模式** 組合模式是一種結構設計模式,可讓您統一處理單一物件和物件組合。它使您能夠建立層次結構,其中每個元素都可以被視為單個物件或物件集合。此模式使用通用介面來表示單一物件(葉節點)和組合(複合節點),允許客戶端與它們統一互動。 ``` // Implementation class Employee { constructor(name) { this.name = name; } print() { console.log(`Employee: ${this.name}`); } } // Composite class Manager extends Employee { constructor(name) { super(name); this.employees = []; } add(employee) { this.employees.push(employee); } remove(employee) { const index = this.employees.indexOf(employee); if (index !== -1) { this.employees.splice(index, 1); } } print() { console.log(`Manager: ${this.name}`); for (const employee of this.employees) { employee.print(); } } } // Usage const john = new Employee("John Doe"); const jane = new Employee("Jane Smith"); const mary = new Manager("Mary Johnson"); mary.add(john); mary.add(jane); const peter = new Employee("Peter Brown"); const bob = new Manager("Bob Williams"); bob.add(peter); bob.add(mary); bob.print(); ``` 在此範例中,我們有 Component 類別 Employee,它代表個別員工。 Composite 類 Manager 擴展了 Employee 類,並且可以包含員工的集合。它提供了在集合中新增和刪除員工的方法,並重寫 print 方法以顯示經理的姓名及其下的員工。 在使用部分,我們建立一個複合層次結構,其中 Manager 物件可以包含單一員工 (Employee) 和其他經理 (Manager)。我們將員工加入經理中,建構了一個層次結構。最後,我們呼叫頂級經理的 print 方法,該方法遞歸地列印層次結構,顯示經理及其各自的員工。 - **行為模式** 行為模式關注物件之間的互動和職責分配。它們為物件之間的通訊、協調和協作提供解決方案。以下是行為模式的類型。 - 觀察者模式 - 策略模式 - 命令模式 - 迭代器模式 - 調解者模式 **觀察者模式** 觀察者模式在物件之間建立一對多關係,其中多個觀察者會收到主體狀態變化的通知。它支援物件之間的鬆散耦合並促進事件驅動的通訊。 ``` // Implementation example of the Observer Pattern class Subject { constructor() { this.observers = []; } addObserver(observer) { this.observers.push(observer); } removeObserver(observer) { const index = this.observers.indexOf(observer); if (index !== -1) { this.observers.splice(index, 1); } } notifyObservers() { this.observers.forEach((observer) => observer.update()); } } class Observer { update() { console.log("Observer is notified of changes."); } } const subject = new Subject(); const observer1 = new Observer(); const observer2 = new Observer(); subject.addObserver(observer1); subject.addObserver(observer2); subject.notifyObservers(); // Output: "Observer is notified of changes." "Observer is notified of changes." ``` 在此範例中,「Subject」類別表示一個主題,它維護觀察者清單並提供新增、刪除和通知觀察者的方法。 「Observer」類別透過其「update」方法定義觀察者的行為。在使用部分,建立了「Subject」類別的「subject」實例。也使用“addObserver”方法建立兩個“observer”實例並將其新增至主題。 當呼叫“subject.notifyObservers()”時,它會觸發每個觀察者的“update”方法。結果,輸出「觀察者收到更改通知」。被記錄兩次,顯示觀察者已被告知主題的變化。 **策略模式** 策略模式可讓您將可互換的演算法封裝在單獨的策略物件中。它支援在執行時動態選擇演算法,從而提高靈活性和可擴展性。 ``` // Implementation example of the Strategy Pattern class Context { constructor(strategy) { this.strategy = strategy; } executeStrategy() { this.strategy.execute(); } } class ConcreteStrategyA { execute() { console.log("Strategy A is executed."); } } class ConcreteStrategyB { execute() { console.log("Strategy B is executed."); } } const contextA = new Context(new ConcreteStrategyA()); contextA.executeStrategy(); // Output: "Strategy A is executed." const contextB = new Context(new ConcreteStrategyB()); contextB.executeStrategy(); // Output: "Strategy B is executed." ``` 在此範例中,「Context」類別表示封裝不同策略的上下文,具有「strategy」屬性和「executeStrategy」方法。有兩個特定策略類,“ConcreteStrategyA”和“ConcreteStrategyB”,每個類別都有自己的“execute”方法來輸出特定訊息。 在使用部分,使用“ConcreteStrategyA”作為策略來建立“Context”類別的“contextA”實例。呼叫 `contextA.executeStrategy()` 會呼叫 `ConcreteStrategyA` 的 `execute` 方法,導致輸出「策略 A 已執行」。類似地,以「ConcreteStrategyB」為策略建立「contextB」實例,呼叫「contextB.executeStrategy()」會觸發「ConcreteStrategyB」的「execute」方法,從而輸出「策略 B 已執行」。這演示了策略模式如何透過將行為封裝在不同的策略物件中來允許在執行時動態選擇行為。 **命令模式** 命令模式將請求封裝為物件,允許您使用不同的請求對客戶端進行參數化、對請求進行排隊或記錄請求,並支援撤銷操作。它將請求的發送者與接收者解耦,從而促進鬆散耦合和靈活性。 ``` // Implementation class Receiver { execute() { console.log("Receiver executes the command."); } } class Command { constructor(receiver) { this.receiver = receiver; } execute() { this.receiver.execute(); } } class Invoker { setCommand(command) { this.command = command; } executeCommand() { this.command.execute(); } } const receiver = new Receiver(); const command = new Command(receiver); const invoker = new Invoker(); invoker.setCommand(command); invoker.executeCommand(); // Output: "Receiver executes the command." ``` 在此範例中,「Receiver」類別在呼叫時執行命令,「Command」類別封裝命令並將執行委託給接收者。 `Invoker` 類別設定並執行命令。在使用部分,建立了接收者、命令和呼叫者。此指令是為呼叫者設定的,呼叫「invoker.executeCommand()」會執行該指令,從而產生輸出「接收者執行該指令」。 **迭代器模式** 迭代器模式是一種行為設計模式,它提供了一種順序存取聚合物件的元素而不暴露其底層表示的方法。它允許您以統一的方式遍歷物件集合,而不管集合的具體實現如何。該模式將遍歷邏輯與集合分開,從而促進了一種乾淨而靈活的方法來迭代元素。 ``` // Implementation class Collection { constructor() { this.items = []; } addItem(item) { this.items.push(item); } createIterator() {} } // Concrete Aggregate class ConcreteCollection extends Collection { createIterator() { return new ConcreteIterator(this); } } // Iterator class Iterator { constructor(collection) { this.collection = collection; this.index = 0; } hasNext() {} next() {} } // Concrete Iterator class ConcreteIterator extends Iterator { hasNext() { return this.index < this.collection.items.length; } next() { return this.collection.items[this.index++]; } } // Usage const collection = new ConcreteCollection(); collection.addItem("Item 1"); collection.addItem("Item 2"); collection.addItem("Item 3"); const iterator = collection.createIterator(); while (iterator.hasNext()) { console.log(iterator.next()); } ``` 在此程式碼中,我們有由 Collection 類別表示的 Aggregate,它定義了用於建立迭代器物件的介面。具體聚合「ConcreteCollection」擴展了 Collection 類別並提供了迭代器建立的具體實作。 Iterator 由 Iterator 類別表示,它定義了存取和遍歷元素的介面。具體迭代器“ConcreteIterator”擴展了迭代器類別並提供了迭代邏輯的具體實作。在使用部分,我們建立一個 Concrete Aggregate 的實例“ConcreteCollection”,並向其中新增專案。然後我們使用 createIterator 方法建立一個迭代器。透過使用迭代器的“hasNext”和 next 方法,我們迭代集合併列印每個專案。 **調解者模式** 中介者模式透過引入充當協調物件之間互動的中心樞紐的中介者物件來簡化物件溝通。它封裝了通訊邏輯,並為物件提供了註冊、發送和接收訊息的方法。 ``` // Implementation class Mediator { constructor() { this.colleague1 = null; this.colleague2 = null; } setColleague1(colleague) { this.colleague1 = colleague; } setColleague2(colleague) { this.colleague2 = colleague; } notifyColleague1(message) { this.colleague1.receive(message); } notifyColleague2(message) { this.colleague2.receive(message); } } class Colleague { constructor(mediator) { this.mediator = mediator; } send(message) { // Send a message to the mediator this.mediator.notifyColleague2(message); } receive(message) { console.log(`Received message: ${message}`); } } // Usage const mediator = new Mediator(); const colleague1 = new Colleague(mediator); const colleague2 = new Colleague(mediator); mediator.setColleague1(colleague1); mediator.setColleague2(colleague2); colleague1.send("Hello Colleague 2!"); // Output: "Received message: Hello Colleague 2!" ``` 在此範例中,我們有一個 Mediator 類,它充當兩個 Colleague 物件之間的中介。中介者保存對同事的引用並提供在他們之間發送訊息的方法。 每個Colleague物件都有一個對中介者的引用,並且可以透過通知中介者來發送訊息。調解員又將訊息轉發給適當的同事。在這種情況下,同事 1 會向同事 2 發送訊息,後者接收並記錄該訊息。 ### 結論 我們探索了 JavaScript 中的一系列基本設計模式,包括建立模式、結構模式和行為模式。建立模式使我們能夠以靈活且高效的方式建立物件。結構模式有助於器官的靈活性和可擴展性。行為模式支援 JavaScript 物件之間的有效溝通和互動。透過利用這些設計模式,JavaScript 開發人員可以提高程式碼的可重複使用性、可維護性和整體系統效能。有了這些知識,我們就可以建立健壯且高效的 JavaScript 應用程式,以滿足現代軟體開發的需求。 --- 原文出處:https://dev.to/topefasasi/js-design-patterns-a-comprehensive-guide-h3m

🌌 31 個開源庫 + Good First Issues(開始你的旅程)⛰️

為優秀的開源庫做出貢獻是建立您的作品集並加入令人驚嘆的社群的最佳方式。 我編譯了 31 個開源程式庫和一些好的第一期,以幫助推動您的旅程。 不要忘記加星號並支持這些🌟 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/637xnt75fuwgfeaasdke.gif) --- #AI最愛🦾: ### 1. [CopilotKit](https://github.com/CopilotKit/CopilotKit) - 應用內 AI 聊天機器人與 AI 文字區域 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ox3mv8nmqzot6m4kvkdh.png) 開源平台,用於使用兩個 React 元件將關鍵 AI 功能整合到 React 應用程式中。 CopilotPortal:應用程式內人工智慧聊天機器人,可以「查看」當前應用程式狀態並採取行動。 CopilotTextarea:AI 驅動的 <textarea /'> 替換。具有自動完成、插入和生成功能。 ###[好第一期:](https://github.com/CopilotKit/CopilotKit/issues/62) ``` Gracefully fail if CopilotProvider is omitted The bug: Virtually every CopilotKit functionality depends on a CopilotContext provided by the CopilotProvider. e.g. CopilotTextarea autocompletions, chatbot, etc. However when a CopilotProvider does not wrap the component, functionality fails silently. To Reproduce 1. Omit <CopilotProvider>...</CopilotProvider> 2. trigger useMakeCopilotReadable, useMakeCopilotActionable, CopilotTextarea, CopilotSidebarUIProvider 3. See how functionality does not work, but no error is emitted Expected behavior An error is emitted, with clear description of the likely core issue and how to resolve it (namely, wrap the app in a CopilotProvider). Point to docs. ``` {% cta https://github.com/CopilotKit/CopilotKit %} Star CopilotKit ⭐️ {% endcta %} --- ###2.[PortKeyAI](https://github.com/Portkey-AI/gateway){% embed https://github.com/Portkey-AI/gateway no-readme %} ###3.[Pezzo.ai](https://github.com/pezzolabs/pezzo){% 嵌入 https://github.com/pezzolabs/pezzo no-readme %} ###4.[OpenVoice](https://github.com/myshell-ai/OpenVoice){% 嵌入 https://github.com/myshell-ai/OpenVoice no-readme %} ###5.[LLMCourse](https://github.com/mlabonne/llm-course){% 嵌入 https://github.com/mlabonne/llm-course no-readme %} --- &nbsp; #雲端和資料庫☁️ ### 6. [Winglang](https://github.com/winglang/wing) - 雲端導向的程式語言 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gvfykepsj1tszs8260wj.png) Wing 是一種用於雲端應用程式的程式語言。 它結合了雲端基礎設施和應用程式的程式碼,使雲端服務開發變得更加容易。 Wing 獨特的執行模型和測試模擬器有助於高效建置和部署雲端應用程式。 ###[第一期好:](https://github.com/winglang/wing/issues/4998) ``` Support Array.sort() method Feature Spec: let arr: MutArray<num>=[2, 1, 3, 9, 6, 4]; arr.sort(); log("${arr}"); // it should print sorted array in ascending order, eg: [1, 2, 3, 4, 6, 9] Component: Wing SDK Community Notes: If you are interested to work on this issue, please leave a comment. If this issue is labeled needs-discussion, it means the spec has not been finalized yet. Please reach out on the #dev channel in the Wing Slack. ``` {% cta https://github.com/winglang/wing %} 星翼朗 ⭐️ {% endcta %} --- ### 7. [StackQL](https://github.com/stackql/stackql) - 以 SQL 為基礎的雲端資源管理 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sdtf51ekap09idn80xnh.png) StackQL 提供了一個獨特的 SQL 為基礎的框架來管理和查詢跨不同提供者(例如 Google、AWS、Azure 等)的雲端資源和 API。 它允許使用類似 SQL 的命令來配置和操作雲端服務,從而簡化了雲端操作。 這使得 StackQL 成為雲端資源管理和互動的多功能工具,特別是對於熟悉 SQL 的人來說。 ###[好第一期:](https://github.com/stackql/stackql/issues/280) ``` Add unit testing to package writer Add unit testing for internal/stackql/writer . Description: add implementation for testing sql_writer.go modify sql_writer.go by adding function for dependency injection add implementation for testing generic.go modify generic.go by adding variable for patching GetDB function modify entryutil.go to adjust sql_writer.go ``` {% cta https://github.com/stackql/stackql/ %} Star StackSQL ⭐️ {% endcta %} --- ###8.[Appwrite](https://github.com/appwrite/appwrite){% 嵌入 https://github.com/appwrite/appwrite no-readme %} ###9.[Supabase](https://github.com/supabase/supabase){% 嵌入 https://github.com/supabase/supabase no-readme %} ###10.[SuperDuperDB](https://github.com/SuperDuperDB/superduperdb){% 嵌入 https://github.com/SuperDuperDB/superduperdb no-readme %} --- &nbsp; #開發實用程式🛠️ ### 11. [Firecamp](https://github.com/firecamp-dev/firecamp) - 多協定 API 協作工具 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/adt6n8uv5dseylmemng0.png) Firecamp 是一款多功能 API 開發工具,支援 Rest、GraphQL 和 WebSockets 等協定。 它簡化了 API 的設計、測試和記錄,並增強了 API 專案的團隊協作。 ###[好第一期:](https://github.com/firecamp-dev/firecamp/issues/137) ``` Help out with Manual Testing of Firecamp Responsibilities: Executing test cases and reporting results Logging bugs and issues in the Github issue tracker Providing feedback on usability and the testing process Suggesting improvements to tests and expanding test coverage. Benefits Benefits for your testing profile and career: Experience testing a real-world open source application Each release will include your name with bugs fixes. Exposure to different types of testing such as UI, API, integration, etc Opportunity to have your contributions and feedback incorporated into the product Collaborating with an open source community Having your testing work visible to potential employers Firecamp Swags (T-shirts and stickers) Community shoutout and promotion ``` {% cta https://github.com/firecamp-dev/firecamp %} 星際火營 ⭐️ {% endcta %} --- ###12.[Odigos](https://github.com/keyval-dev/odigos){% 嵌入 https://github.com/keyval-dev/odigos no-readme %} ###13.[Digger](https://github.com/diggerhq/digger){% 嵌入 https://github.com/diggerhq/digger no-readme %} ###14.[鏡像](https://github.com/metalbear-co/mirrord){% 嵌入 https://github.com/metalbear-co/mirrord no-readme %} --- &nbsp; #後端⚙️ ### 15. [Cerbos](https://github.com/cerbos/cerbos) - 可擴充、與語言無關的授權 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cljttnnxua54lyg4w65x.png) Cerbos 提供獨特、可擴展的解決方案,用於在應用程式中實施特定於上下文的使用者權限。 其靈活的、與語言無關的方法可以輕鬆整合和管理複雜的授權結構。 與眾不同的是,Cerbos 簡化了存取控制策略的開發,使其更能適應各種應用需求。 ###[第一期好:](https://github.com/cerbos/cerbos/issues/1920) ``` Produce output when the rule condition is not satisfied Currently the output block is only evaluated if the rule is actually activated (action, roles and conditions are satisfied). In certain situations, it's desirable to produce output when the rule is nearly activated (action and roles match but the condition is not satisfied). In order to maintain backward compatibility, reduce noise, and to keep policy execution as fast as possible (outputs incur a tiny overhead), the proposal is to let users add an optional when section to the output block to opt into this behaviour. - actions: ['view'] effect: EFFECT_ALLOW roles: ['user'] condition: match: expr: timestamp(R.expiry_date) > now() output: expr: > format("%d hours until expiry", (timestamp(R.expiry_date) - now()).getHours()) when: cond_fail: > format("expired on %s", R.expiry_date) When evaluating the above rule, if the action, roles and condition match, output will be the result of evaluating output.expr If the condition is not satisfied, output will be the result of evaluating output. when.cond_fail if it exists. Otherwise no output will be produced. ``` {% cta https://github.com/cerbos/cerbos %} 明星 Cerbos ⭐️ {% endcta %} --- ###16.[Novu](https://github.com/novuhq/novu){% 嵌入 https://github.com/novuhq/novu no-readme %} ###17.[Trigger.dev](https://github.com/triggerdotdev/trigger.dev){% 嵌入 https://github.com/triggerdotdev/trigger.dev no-readme %} ###18.[SuperTokens](https://github.com/supertokens/supertokens-core){% 嵌入 https://github.com/supertokens/supertokens-core no-readme %} ###19.[Wazuh](https://github.com/wazuh/wazuh){% 嵌入 https://github.com/wazuh/wazuh no-readme %} --- &nbsp; #UI/UX🦋: ### 20. [Flowbite](https://github.com/themesberg/flowbite) - 頂級 CSS 元件庫 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/98dwqyrhf1pbiqkpko8g.png) 最好、最受尊敬的 UI 元件庫之一。 基於實用優先的 CSS 框架。 易於使用,充滿重要的支援和模板。 {% cta https://github.com/themesberg/flowbite %} 明星 Flowbite ⭐️ {% endcta %} &nbsp; ###21.[MaterialUI](https://github.com/mui/material-ui) - 使用 Google 的 Material Design 實現的基礎 React 元件 {% 嵌入 https://github.com/mui/material-ui no-readme %} &nbsp; ###22。 [SwiperUI](https://github.com/nolimits4web/swiper) - 用於實現行動滑動 UI 的受人尊敬的庫 {% 嵌入 https://github.com/nolimits4web/swiper no-readme %} &nbsp; ###23.[ReactSpring](https://github.com/pmndrs/react-spring) - 在 React 中實現具有真實物理效果的動畫 {% 嵌入 https://github.com/pmndrs/react-spring no-readme %} --- &nbsp; #雜項🎨 ### 24. [SwirlSearch](https://github.com/swirlai/swirl-search) - 多源人工智慧資料搜尋器 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/thplxod3d4vh1qq5hhpa.jpeg) Swirl 是一款由人工智慧驅動的搜尋工具,可同時查詢多個資料來源,包括資料庫和公用資料服務。 它使用人工智慧對結果進行排名並產生見解,從而可以跨不同的資料儲存庫進行全面搜尋。 Swirl 一次簡化了對各種來源的資料的搜尋和分析,使其成為資料驅動洞察的獨特工具。 ###[第一期好:](https://github.com/swirlai/swirl-search/issues/789) ``` Add a Connector: Yahoo search It would help to search anything with Swirl on Yahoo effectively. Locate and read a bit in their search API first. You might just need to make a new SearchProvider configration vs. a new Connector. Their docs should help guide you a bit in which way you might need to go. ``` {% cta https://github.com/swirlai/swirl-search/ %} Star SwirlSearch ⭐️ {% endcta %} --- ### 25. [Wasp](https://github.com/wasp-lang/wasp) - 使用 React 和 Node.js 開發全端 Web 應用程式 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/54jp6j6r8ils6we97i0f.png) 使用 React 和 Node.js 進行快速全端 Web 應用程式開發。 Wasp 提供了一種建立現代 Web 應用程式的簡化方法,將前端的 React 和後端的 Node.js 結合在一個緊密結合的框架中。 ###[好第一期:](https://github.com/wasp-lang/wasp/issues/874) ``` Add images (or link to the example app) of auth UI helpers Wasp provides At this point in docs (also in the tutorial if we're using it), it would be nice to add an image of UI helpers for Auth (login/signup form, Google/GitHub button, ...) so developers can immediately see what they are getting and how nice it looks. ``` {% cta https://github.com/wasp-lang/wasp %} 星黃蜂 ⭐️ {% endcta %} ###26.[Logstash](https://github.com/elastic/logstash) {% 嵌入 https://github.com/elastic/logstash 無自述文件 %} ###27.[Snapify](https://github.com/MarconLP/snapify) {% 嵌入 https://github.com/MarconLP/snapify 無自述文件 %} --- &nbsp; #為了好玩🎭 ###28.[Twitter 的演算法](https://github.com/twitter/the-algorithm){% embed https://github.com/twitter/the-algorithm no-readme %} ###29.[十億行挑戰](https://github.com/gunnarmorling/1brc){% embed https://github.com/gunnarmorling/1brc no-readme %} ###30.【秘密知識之書】(https://github.com/trimstray/the-book-of-secret-knowledge){% embed https://github.com/trimstray/the-book-of -秘密知識無自述文件%} ###31.[GenAI 初學者](https://github.com/microsoft/generative-ai-for-beginners){% 嵌入 https://github.com/microsoft/generative-ai-for-beginners no -自述文件%} --- 原文出處:https://dev.to/copilotkit/31-open-source-libraries-to-kickstart-your-journey-4hhd

幫助我成為技術主管的書籍

## 為什麼是書籍? 在發展我的技能時,我喜歡結合使用會議演講、視訊教學、書籍、論文、部落格文章、邊做邊學和教學/部落格。書籍是從別人所犯的錯誤中學習、從他們的成功中受到啟發以及間接體驗他們的成就的好方法。 在這篇文章中,我想分享我最喜歡的書籍,這些書籍在我從高級軟體工程師到成為技術主管的過程中對我幫助最大。他們幫助我拓寬並加深了對軟體工程、軟體架構以及建構和經營軟體業務的理解。他們教我挑戰和塑造我的行為和習慣。其中一些深深影響了我的個人和職業生活。 不用說,閱讀這些書不會自動讓你升職或讓你擔任新的技術主管職位。當然,你還是需要自己的經驗,自己的錯誤,還需要一點運氣。根據您所從事的特定領域不斷提高您的技術知識和技能也很重要。此清單中的書籍並不關注特定技術,而是適用於任何技術堆疊和業務的一般原則和概念。 對於清單中的每本書,我都會附上一個簡短的摘要,可以幫助您判斷這本書是否與您相關。為了賦予它個人風格,我還將包括我從這本書中學到的最有價值的教訓。這不一定是這本書的主要訊息,也不是唯一重要的訊息,而是最能引起我共鳴的訊息。 ## 列表 ### 設計它! [*Design It!: From Programmer to Software Architect*]((https://www.oreilly.com/library/view/design-it/9781680502923/)) Michael Keeling 是一本針對有志向的軟體開發人員的綜合指南轉變為軟體架構師的角色。本書提供了一種實用且易於理解的軟體架構方法,強調了設計在建立有效的軟體系統中的重要性。 Keeling 涵蓋了廣泛的主題,從軟體架構的基本原理到設計可擴展和可維護系統的實用技術。 在整本書中,基林提倡採用實踐、迭代的軟體設計方法,鼓勵讀者批判性地思考他們所做的架構選擇。他介紹了各種架構風格和模式,並討論如何評估權衡並做出符合專案目標和限制的決策。本書充滿了現實世界的範例、練習和實用技巧,對於那些希望發展軟體架構和設計技能的人來說是一個寶貴的資源。 **我從書中學到的最有價值的教訓:** 不存在「沒有設計」這樣的事情。 「無設計」通常意味著在工程師的腦海中存在多種、隱含的設計,這些設計彼此不一致。明確、協作、迭代地設計,並以書面記錄設計! ### 釋放它! Michael Nygard 的[*Release It!: Design and Deploy Production-Ready Software*](https://www.oreilly.com/library/view/release-it/9781680500264/) 是軟體開發人員和架構師的重要指南討論建立在生產環境中可靠運作的軟體所面臨的挑戰。本書深入探討了設計、部署和維護能夠承受現實世界操作嚴苛的軟體的複雜性。 Nygard 強調從設計過程一開始就考慮生產現實的重要性,並提倡從僅僅編寫程式碼到提供彈性、可擴展和可維護的系統的思維方式轉變。 Nygard 提供了對軟體系統在生產中遇到的各種陷阱的見解,例如網路問題、不可預測的負載模式和硬體故障。他介紹了穩定性模式和反模式等概念,說明如何建立能夠優雅地處理故障並在壓力下保持穩健的系統。這本書充滿了現實生活中的故事和案例研究,展示了生產環境中不良系統設計所造成的災難性後果。 “放開它!”對於軟體專業人士來說,這是一個寶貴的資源,他們希望確保他們的系統不僅能正常執行,而且在面對現實世界的挑戰時具有彈性和可靠性。 **我從書中學到的最有價值的教訓:** 每個軟體工程師都應該在建立他們的軟體時考慮到生產。生產中的軟體負責營運您的業務、影響您的客戶並決定成功或失敗。 ### 站點可靠度工程 [*站點可靠性工程:Google 如何執行生產系統*](https://www.oreilly.com/library/view/site-reliability-engineering/9781491929117/) 作者:Betsy Beyer、Chris Jones、Jennifer Petoff 和 Niall理查德·墨菲(Richard Murphy) 對Google 用於管理其大規模、高度可靠系統的實踐和原則進行了富有洞察力的探索。本書介紹了站點可靠性工程 (SRE) 的概念,這是一門將軟體工程與 IT 營運相結合的學科,重點是建立可擴展且可靠的軟體系統。 作者都是 Google 的 SRE 領域經驗豐富的從業者,他們分享瞭如何建置、部署、監控和維護強大且有彈性的系統的專業知識。他們深入研究了 Google 使用的具體策略和技術,例如設定服務等級目標 (SLO)、有效管理變更以及平衡發布速度與服務可靠性的需求。這本書涵蓋了一系列主題,從 SRE 團隊的組織方面到事件管理和事後分析文化等技術實踐。這本書提供了對世界上最熟練的工程組織之一的內部運作的罕見了解,對於參與大型系統的操作、維護和擴展的任何人來說都是寶貴的資源。 **我從書中學到的最有價值的教訓:** 不存在完美的系統。透過明確定義和衡量 SLO 和錯誤預算,您可以就可靠性和速度之間的權衡做出明智的決策。 ### 改變你的問題,改變你的生活 [*改變你的問題,改變你的生活:領導力、指導和生活的 12 種強大工具*](https://www.goodreads.com/en/book/show/6665149),作者 Marilee Adams 探討了我們提出的問題可能會對我們的生活和職業生涯產生影響。亞當斯引入了「問題思維」的概念,這是一種透過深思熟慮和用心提問來轉變思維、行動和結果的方法。這本書強調了我們問自己的問題類型,從限制性的、判斷性的「判斷者」問題到更開放的、建設性的「學習者」問題,如何能顯著影響我們的觀點和結果。 亞當斯透過引人入勝的敘述闡述了她的想法,講述了一個人與生活挑戰作鬥爭並學習應用問題思維原則的故事。這種方法為個人提供了實用的工具和技術,以提高他們的溝通、決策和解決問題的能力。透過培養學習者心態並提出更好、更有說服力的問題,讀者可以被引導建立更積極、更有生產力的個人和專業關係。這本書對於領導者、教練以及任何希望增強與他人聯繫並更有效地駕馭複雜情況的能力的人來說特別有價值。 **我從書中學到的最有價值的教訓:**我意識到我經常處於「評判者」心態中。更加留意這一點,並有意識地選擇轉變為「學習者」心態,對我來說幾乎就像一種超能力,可以解決我面臨的任何挑戰。 ### 思考,快與慢 Daniel Kahneman 的 [*思考,快與慢*](https://www.amazon.de/-/en/Designing-Data-Intective-Applications-Reliable-Maintainable/dp/1449373321) 是對心理學與經濟學,深入研究我們如何思考和做出決策。卡尼曼介紹了兩種主導我們心理過程的不同思維模式:「系統1」(快速、直覺和情緒)和「系統2」(較慢、更深思熟慮和更邏輯)。卡尼曼在整本書中探討了這兩個系統對我們的判斷、決策以及我們感知周圍世界的方式的影響。 這本書全面探討了影響我們日常思維的各種認知偏見和啟發法。卡尼曼展示了我們的直覺系統 1(通常對我們很有幫助)也可能導致嚴重的錯誤和偏見。他也探討了系統 2 的功能和局限性,強調系統 1 的快速判斷如何影響和推翻它。這本書綜合了數十年的研究,提供了對人類思想和行為的複雜性的深入見解。對於任何有興趣了解我們在個人和職業環境中的選擇和行為背後的心理過程的人來說,這是一本必讀的書。 **我從書中學到的最有價值的教訓:**我了解到這兩種模式都很有價值,但也有其缺點。我學會了更了解影響我思考的偏見和啟發法,並有意識地選擇何時依賴系統 1,何時使用系統 2。 ### 原子習慣 James Clear 的[*原子習慣:一種簡單且行之有效的建立好習慣和改掉壞習慣的方法*](https://jamesclear.com/atomic-habits) 是一本變革性的指南,深入研究了習慣的科學以及習慣的小習慣改變可以帶來顯著的結果。作者提出了一個理解習慣如何形成的全面框架,並提供了培養好習慣和改掉壞習慣的實用策略。這本書的核心理念是,隨著時間的推移,微小的改進或「原子習慣」可以累積成重大的、改變生活的結果。 克利爾強調系統比目標更重要,他認為專注於實現目標的流程和系統比專注於目標本身更有效。他介紹了行為改變四定律──一套簡單、可操作的原則來引導習慣的形成。其中包括使線索明顯、渴望有吸引力、反應簡單以及獎勵令人滿意。透過結合科學研究、個人故事和現實世界的例子,克利爾闡述如何將這些原則應用於生活的各個方面,從健身和財務管理到生產力和個人成長。 《原子習慣》為培養持久的習慣提供了一個易於理解且引人注目的藍圖,對於任何想要在生活中做出積極、持久改變的人來說都是有價值的。 **我從這本書中學到的最有價值的教訓:** 透過對我的日常生活進行許多小改變,這些改變單獨地只會對我的生產力產生很小的影響,所有這些習慣結合起來會產生巨大的影響。 ### 有意識的商業 Fred Kofman 的 [*Conscious Business: How to Build Value Through Values*](https://www.amazon.de/-/en/Fred-Kofman/dp/1622032020) 是一本發人深省的書,探討了個人誠信和職業成功。作者提出了這樣的觀點:建立成功且可持續發展的企業的關鍵在於有意識的管理實踐,其中個人價值觀和道德原則處於決策過程的最前沿。該書認為,商業上的成功不僅在於經濟收益,還在於實現個人和職業成就。 科夫曼討論了有意識的商業的各個方面,包括問責制、責任、情緒智商、溝通技巧以及建設性解決衝突的能力。他強調領導者能夠激發信任、培養開放和誠實的文化並以同理心領導的重要性。透過現實世界的例子、實用的建議和練習,科夫曼指導讀者如何發展這些技能並將其應用到他們的職業生活中。 **我從書中學到的最有價值的教訓:**無條件回應能力的概念。我現在不斷提醒自己,無論情況如何,我都有權力和責任選擇對任何情況的反應。 「響應能力」是「響應」和「能力」的雙關語,強調自覺、主動回應的能力。 ### 首先,打破所有規則 [*首先,打破所有規則:世界上最偉大的管理者的不同做法*](https://store.gallup.com/p/en-us/10286/first-break-all-the-rules) 作者:Marcus Buckingham柯特·科夫曼(Curt Coffman)根據蓋洛普組織的研究提出了一種激進的管理方法。本書挑戰了有關領導力和管理的傳統智慧,提出最有效的管理者往往會違反標準做法。 本書的核心訊息是,偉大的管理者不會遵循單一模式或嚴格遵守傳統的管理原則。相反,他們透過專注於員工的個人優勢而不是試圖糾正他們的弱點來打破規則。作者認為,這種方法可以提高敬業度、生產力和整體工作滿意度。 白金漢和科夫曼確定了使世界上最好的管理者脫穎而出的關鍵見解和策略。其中包括選擇人才而不是簡單地填補職位的重要性,定義正確的結果而不是規定正確的步驟,關注優勢而不是沉迷於劣勢,以及為員工找到合適的人選而不是簡單地將他們晉升到下一個梯級。梯子。 **我從書中學到的最有價值的教訓:** 專注於優勢而不是劣勢的重要性。我學會了接受自己的弱點,並使用工具和策略來彌補它們,而不是試圖「修復」它們。相反,我投入時間和精力來發展自己的優勢,並嘗試為我所領導的人做同樣的事情。 ## 榮譽獎 在我從高級軟體工程師到技術主管的旅程中,我發現還有很多有價值的書籍。它們更專注於特定技術,這就是為什麼我沒有將它們包含在主列表中。儘管如此,我想在這裡提及它們,因為它們可能與您相關,具體取決於您所從事的領域/行業。 - [*資料庫內部架構*](https://www.databass.dev/),作者:Alex Petrov。我讀過的「最好的」資料庫書籍。它以一種非常容易理解的方式涵蓋了資料庫的所有基礎知識。對於任何使用資料庫的人來說,這是一本必讀的書。 - [*設計資料密集型應用程式*](https://www.amazon.de/-/en/Designing-Data-Intential-Applications-Reliable-Maintainable/dp/1449373321) 作者:Martin Kleppmann。建立資料密集型應用程式的綜合指南。它涵蓋了廣泛的主題,從資料庫和資料處理到分散式系統和串流處理。 - [*Oracle JRockit:權威指南*](https://www.packtpub.com/product/oracle-jrockit-the-definitive-guide/9781847198068),作者:Marcus Hirt 和 Marcus Lagergren。對於任何對 JVM 內部結構感興趣的人來說,這是一個很好的資源。 - [*Linux 程式介面*](https://man7.org/tlpi/) 作者:Michael Kerrisk。這是一本關於 Linux 的非常詳細的書,涵蓋了廣泛的主題,從基本的系統呼叫到進程組、訊號和套接字等高級主題。 ## 最後的想法 雖然書籍是個很好的學習工具,但它們並不能取代第一手經驗。你仍然需要犯自己的錯誤並從中學習。與他人討論你讀過的書,了解他們的觀點並挑戰你自己的觀點也很有幫助。也許您可以加入讀書俱樂部,或與同事或朋友一起閱讀。 我希望這份清單對您的職業生涯有所幫助。如果有一本書啟發了您並且您認為應該在此列表中,請在下面的評論中告訴我。 --- 原文出處:https://dev.to/frosnerd/books-that-helped-me-become-a-tech-lead-3831

🎉像專業人士一樣監控您的 Javascript 應用程式🧙‍♂️💫

## **簡介** 在本教程中,您將學習如何使用**現代工具**和**最佳實踐**來監控您的Javascript應用程式。 探索分散式追蹤的力量,並了解如何無縫整合和利用 Odigos 和 Jaeger 等工具來增強您的監控能力。 **您將學到什麼:✨** - 如何在 Javascript 中建立微服務🐜。 - 為微服務設定 Docker 容器📦。 - 配置 Kubernetes ☸️ 以管理微服務。 - 整合追蹤後端以可視化追蹤🔍。 您準備好成為監控 JS 應用程式的**專家**了嗎? 😍 說**是的,先生!**。 我聽不到你說話。大聲點說。 🙉 ![大聲點 GIF](https://media.giphy.com/media/8m5dizh7ghyEPIWIx1/giphy.gif) *** ## **讓我們設定一下 🦄** > 🚨 在部落格的這一部分中,我們將建立一個虛擬的 JavaScript 微服務應用程式並將其部署在本地 Kubernetes 上。如果您已經有一個並且正在跟進,請隨意跳過這一部分。 為您的應用程式建立初始資料夾結構,如下所示。 👇🏻 ``` mkdir microservices-demo cd microservices-demo mkdir src cd src ``` ### **設定伺服器** 🖥️ > 👀 出於演示目的,我將建立兩個相互通信的微服務,最終我們可以使用它來視覺化分散式追蹤。 - **建置與 Dockerize 微服務 1** 在「/src」資料夾中,建立一個新資料夾「/microservice-1」。在資料夾內初始化 **NodeJS** 專案並安裝所需的依賴項。 ``` mkdir microservice-1 cd microservice-1 npm init -y npm install --save express node-fetch ``` 建立一個新檔案“index.js”並新增以下程式碼: ``` // 👇🏻/src/microservice-1/index.js const express = require("express"); const fetch = require("node-fetch") const app = express(); const PORT = 3001; app.use(express.json()); app.get("/", async (req, res) => { try { const response = await fetch("http://microservice2:8081/api/data"); const data = await response.json(); res.json({ data: "Microservice 2 data received in Microservice 1", microservice2Data: data, }); } catch (error) { console.error(error.message); res.status(500).json({ error: "Internal Server Error" }); } }); app.listen(PORT, () => { console.log(`Microservice 1 listening on port ${PORT}`); }); ``` 伺服器正在偵聽連接埠“3001”,並且在對“/”發出請求時,我們從“microservice2”請求資料並將回應作為 JSON 物件返回。 📦 現在,是時候對這個微服務進行 docker 化了。在“/microservice-1”資料夾中建立一個新的“Dockerfile”並新增以下程式碼: ``` // 👇🏻/src/microservice-1/Dockerfile FROM node:18 # Use /usr/src/app as the working directory WORKDIR /usr/src/app # Copy package files and install production dependencies COPY --chown=node:node package*.json /usr/src/app RUN npm install --production # Copy the rest of the files COPY --chown=node:node . /usr/src/app/ # Switch to the user node with limited permissions USER node # Expose the application port EXPOSE 3001 # Set the default command to run the application CMD ["node", "index.js"] ``` 將我們不想推送到容器的文件加入到“.dockerignore”總是很好。使用我們不想推送的檔案的名稱來建立一個“.dockerignore”檔案。 ``` // 👇🏻/src/microservice-1/.dockerignore node_modules Dockerfile ``` 最後,透過執行以下命令來建構 🏗️ docker 映像: ``` docker build -t microservice1-image:latest . ``` 現在,這就是我們第一個微服務的完整設定。 ✨ - **建置與 Dockerize 微服務 2** 我們將有一個類似於“microservice1”的設置,只是在這裡和那裡進行了一些更改。 在「/src」資料夾中,建立一個新資料夾「/microservice-2」。在該資料夾內,初始化 **NodeJS** 專案並安裝所需的依賴項。 ``` mkdir microservice-2 cd microservice-2 npm init -y npm install --save express node-fetch ``` 建立一個新檔案“index.js”並新增以下程式碼: ``` // 👇🏻/src/microservice-2/index.js const express = require("express"); const fetch = require("node-fetch") const app = express(); const PORT = 3002; app.use(express.json()); app.get("/api/data", async (req, res) => { const url = "https://jsonplaceholder.typicode.com/users"; try { const response = await fetch(url); const data = await response.json(); res.json(data); } catch (error) { console.error(error.message); res.status(500).json({ error: "Internal Server Error" }); } }); app.listen(PORT, () => { console.log(`Microservice 2 listening on port ${PORT}`); }); ``` 伺服器正在偵聽連接埠 3002,根據對“/api/data”的“GET 請求”,我們從“jsonplaceholder”獲取資料並將回應作為 JSON 物件傳回。 📦 現在,是時候對這個微服務進行 docker 化了。複製並貼上「microservice1」的整個「Dockerfile」內容,然後將連接埠從 3001 變更為 3002。 另外,新增一個「.dockerignore」檔案並包含我們在建立「microservice1」時新增的相同檔案。 最後,透過執行以下命令來建構 🏗️ Docker 映像: ``` docker build -t microservice2-image:latest . ``` 現在,這也是我們第二個微服務的完整設定。 ✨ - **設定 Kubernetes** > 確保已安裝 **[Minikube](https://github.com/kubernetes/minikube)** 透過執行以下命令建立新的本機 Kubernetes 叢集。我們在設定 Odigos 和 Jaeger 時將需要它。 **啟動 Minikube:🚀** ``` minikube start ``` 現在我們已經準備好並 Docker 化了兩個微服務,是時候設定 Kubernetes 來管理這些服務了。 在專案的根目錄下,建立一個新資料夾「/k8s/manifests」。在此資料夾中,我們將為兩個微服務新增部署和服務配置。 - **部署設定📜**:用於在 Kubernetes 叢集上實際部署容器。 - **服務配置📄**:將 Pod 暴露給叢集內部和叢集外部。 首先,我們為「microservice1」建立清單。建立一個新檔案「microservice1-deployment-service.yaml」並新增以下內容: ``` // 👇🏻/k8s/manifests/microservice1-deployment-service.yaml apiVersion: apps/v1 kind: Deployment metadata: name: microservice1 spec: selector: matchLabels: app: microservice1 template: metadata: labels: app: microservice1 spec: containers: - name: microservice1 image: microservice1-image # Make sure to set it to Never, or else it will pull from the docker hub and fail. imagePullPolicy: Never resources: limits: memory: "200Mi" cpu: "500m" ports: - containerPort: 3001 --- apiVersion: v1 kind: Service metadata: name: microservice1 labels: app: microservice1 spec: type: NodePort selector: app: microservice1 ports: - port: 8080 targetPort: 3001 nodePort: 30001 ``` 此配置部署了一個名為「microservice1」的微服務,其資源限制為 **200MB 記憶體** 🗃️ 和 **0.5 個 CPU 核心**。它透過部署在連接埠 3001 上公開微服務,並透過服務在 **NodePort** 30001 上公開微服務。 > 🤔 還記得我們用名稱「microservice1-image」建構的「Dockerfile」嗎?我們使用相同的映像來建立容器。 可透過集群內的連接埠 8080 存取它。我們假設「microservice1-image」透過「imagePullPolicy: Never」在本地可用。如果沒有到位,它將嘗試從 Docker Hub 🐋 中提取映像並失敗。 現在,讓我們為「microservice2」建立清單。建立一個名為「microservice2-deployment-service.yaml」的新檔案並新增以下內容: ``` // 👇🏻/k8s/manifests/microservice1-deployment-service.yaml apiVersion: apps/v1 kind: Deployment metadata: name: microservice2 spec: selector: matchLabels: app: microservice2 template: metadata: labels: app: microservice2 spec: containers: - name: microservice2 image: microservice2-image # Make sure to set it to Never, or else it will pull from the docker hub and fail. imagePullPolicy: Never resources: limits: memory: "200Mi" cpu: "500m" ports: - containerPort: 3002 --- apiVersion: v1 kind: Service metadata: name: microservice2 labels: app: microservice2 spec: type: NodePort selector: app: microservice2 ports: - port: 8081 targetPort: 3002 nodePort: 30002 ``` 它與“microservice1”的清單類似,只有一些更改。 👀 此配置部署一個名為「microservice2」的微服務,並透過部署在連接埠 3002 上將其內部公開,並透過服務在 **NodePort** 30002 上將其外部公開。 可透過叢集內的連接埠 8081 進行存取,假設「microservice2-image」可透過「imagePullPolicy: Never」在本地使用。 全部完成後,請確保套用這些設定並使用這些服務啟動 Kubernetes 叢集。將目錄更改為`/manifests`並執行以下命令:👇🏻 ``` kubectl apply -f microservice1-deployment-service.yaml kubectl apply -f microservice2-deployment-service.yaml ``` 執行以下命令檢查我們的兩個部署是否正在**執行**:👇🏻 ``` kubectl get pods ``` ![Kubernetes Pod](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ywsvodcqqbx1wv0kede1.png) 最後,我們的應用程式已準備就緒,並使用必要的部署配置部署在 Kubernetes 上。 🎉 *** ## **安裝 Odigos 😍** > 💡 [**Odigos**](https://odigos.io/) 是一個開源可觀察性控制平面,使組織能夠建立和維護其可觀察性管道。 ![Odigos - 監控工具](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7c6i7wth5l3ey9frk0cx.jpg) > ℹ️ 如果您在 Mac 上執行,請執行以下命令在本地安裝 Odigos。 ``` brew install keyval-dev/homebrew-odigos-cli/odigos ``` > ℹ️ 如果您使用的是 Linux 計算機,請考慮透過執行以下命令從 GitHub 版本安裝它。確保根據您的 Linux 發行版更改該檔案。 > ℹ️ 如果 Odigos 二進位檔案不可執行,請在執行安裝指令之前執行此指令 `chmod +x odigos` 使其可執行。 ``` curl -LJO https://github.com/keyval-dev/odigos/releases/download/v1.0.9/cli_1.0.9_linux_amd64.tar.gz tar -xvzf cli_1.0.9_linux_amd64.tar.gz ./odigos install ``` ![Odigos 安裝](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/145z2j9fusgnbp41whcw.png) > 如果您需要有關其安裝的更多簡短說明,請按照此[**連結**](https://docs.odigos.io/installation)操作。 現在,Odigos 已準備好執行 🎉。我們可以執行它的 UI,配置追蹤後端,並相應地發送追蹤。 *** ## **將 Odigos 連接到追蹤後端 💫** > 💡 [**Jaeger**](https://github.com/jaegertracing/jaeger) 是一個開源的端對端分散式追蹤系統。 ![Odigos - 分散式追蹤平台](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b9bytdpf4wv1ncb0z52p.jpg) ### **設定 Jaeger!** ✨ 在本教程中,我們將使用 **Jaeger** 🕵️‍♂️,這是一個流行的開源平台,用於查看微服務應用程式中的分散式追蹤。我們將用它來查看 Odigos 生成的痕跡。 > 有關 Jaeger 安裝說明,請點選此 [**link**](https://www.jaegertracing.io/download/)。 👀 若要在 Kubernetes 叢集上部署 Jaeger,請執行下列命令:👇🏻 ``` kubectl create ns tracing kubectl apply -f https://raw.githubusercontent.com/keyval-dev/opentelemetry-go-instrumentation/master/docs/getting-started/jaeger.yaml -n tracing ``` 在這裡,我們建立一個「tracing」命名空間,並在該命名空間中為 Jaeger 應用部署配置📃。 此命令設定自託管 Jaeger 實例及其服務。 👀 執行以下命令來取得正在執行的 pod 的狀態:👇🏻 ``` kubectl get pods -A -w ``` 等待所有三個 Pod 都 **正在執行**,然後再繼續。 ![Kubernetes Pod](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n41rxtp8gcbe4cwsl6xx.png) 現在,要在本地查看 Jaeger Interface 💻,我們需要進行連接埠轉送。將流量從本機電腦上的連接埠 16686 轉送至 Kubernetes 叢集中選定 pod 上的連接埠 16686。 ``` kubectl port-forward -n tracing svc/jaeger 16686:16686 ``` 此命令在本機電腦和 Jaeger pod 之間建立一條隧道,公開 Jaeger UI,以便您可以與其互動。 最後,在瀏覽器上開啟「 http://localhost:16686 」並查看 Jaeger 實例正在執行。 ![Jaeger UI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gr6bcqph7nyxa7v0u01t.png) ### **設定 Odigos 與 Jaeger 一起工作!** 🌟 > ℹ️ 對於 Linux 用戶,請前往從 GitHub 版本下載 Odigos 二進位檔案的資料夾,然後執行以下命令來啟動 Odigos UI。 ``` ./odigos ui ``` > ℹ️ 對於 Mac 用戶,只需執行: ``` odigos ui ``` 造訪“ http://localhost:3000 ”,您將看到 Odigos 介面,您將在“default”命名空間中看到您的部署。 ![Odigos 登陸頁](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/14yqd2x41i9gqvwxdtsu.png) 選擇這兩個選項並點擊“下一步”。在下一頁上,選擇 Jaeger 作為後端,並在出現提示時加入以下詳細資訊: - **目的地名稱🛣️**:提供您想要的任何名稱,例如說**快速追蹤**。 - **端點🎯**:為端點加上`jaeger.tracing:4317`。 就是這樣 - Odigos 已準備好向我們的 Jaeger 後端發送痕跡。就是這麼簡單。 🤯 ![具有兩個微服務的 Odigos UI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qqmo7div92zngnkdwwyu.png) *** ## **查看分散式追蹤 🧐** 設定 Odigos 後,在 Jaeger 主頁「 http://localhost:16686 」上,您將已經看到列出的兩個微服務。 ![Jaeger UI 列出了兩個微服務](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nwb0qjdmxi4ydcvwjgr1.png) Odigos 已經開始向 Jaeger 發送我們的應用程式痕跡。 😉 請記住,這是我們的微服務應用程式。由於以「microservice1」為起點,因此再向「microservice1」發出一些請求,隨後它將向「microservice2」請求資料並傳回。最終,Jaeger 將開始填滿這些痕跡。 ![Jaeger 分散式追蹤](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u4kwzh854bsh5wga1or3.png) 點擊任一請求,您應該能夠觀察請求如何流經您的應用程式以及完成每個請求所需的時間。 這一切都是在沒有更改一行程式碼的情況下完成的。 🤯 一切都感謝 **Odigos**! 🤩 ![令人震驚的 GIF](https://media.giphy.com/media/l0NwHXQy3kUSfFF60/giphy.gif) 想像一下,這只是一個很小的虛擬應用程式,但對於一個執行著大量微服務並相互交互的更大的應用程式來說,分散式追蹤將非常強大! 💪 透過分散式跟踪,您可以輕鬆辨識應用程式中的瓶頸,並確定哪個服務導致問題或花費更長的時間。 🕒 *** ## **讓我們總結一下! 🥱** 到目前為止,您已經學習如何使用 **Odigos** 作為應用程式和追蹤後端 **Jaeger** 之間的 **中間件**,透過分散式追蹤來密切監控 👀 Javascript 應用程式。 👏 如果您已經做到了這一步,請拍拍自己的背。 🥳你值得擁有! 😉 本教學的源程式碼可在此處取得: https://github.com/keyval-dev/blog/tree/main/odigos-monitor-JS-like-a-pro > 如果您對本文有任何疑問或建議,請在下面的評論部分分享。 👇🏻 那麼,這就是本文的內容。感謝您的閱讀! 🎉🫡 --- 原文出處:https://dev.to/odigos/monitor-your-javascript-application-like-a-pro-581p

2024 年您必須嘗試的 25 個 Web 開發專案

毫無疑問,掌握 Web 開發最有效的方法之一就是透過實作。雖然學習理論概念很重要,但將您的知識應用到現實世界的專案中才能真正鞏固您的技能。無論您是想要打下堅實基礎的初學者,還是尋求新挑戰的經驗豐富的開發人員,這裡有 25 個 Web 開發專案可以提高您的能力。 ### 學生成績管理系統 學生成績管理系統旨在為學生和大學提供一種快速且用戶友好的方式來存取和管理考試成績。學生可以登入查看他們的成績,新生可以選擇註冊。該系統旨在以易於理解的方式呈現結果。 **如何做:** 掌握前端、後端和資料庫程式設計的基礎知識後,從建立全端應用程式開始。利用HTML、CSS、JavaScript、PHP和MySQL實現使用者認證、結果顯示和註冊功能。 ![學生成績管理系統](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4y9a2bm1exqbu34lsxph.png) ### 線上程式碼編輯器(React) 該專案涉及使用 React 建立線上程式碼編輯器,允許使用者用各種程式語言編寫和執行程式碼。目標是建立一個用戶可以無縫編輯和測試原始程式碼的平台。 **如何做:** 先使用 HTML、CSS 和 React 進行前端工作。實現程式碼輸入、執行和結果顯示功能。專注於建立用戶友好的介面,以獲得流暢的程式碼編輯體驗。 ![線上程式碼編輯器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/06jjz3v5sq7c6apc41d7.png) ### 使用 React 進行 Amazon 克隆 Amazon Clone 專案圍繞著使用 React 建立 Amazon 線上商店的工作副本。該專案將幫助您了解有效的電子商務網站所需的元件並將它們應用到您的應用程式中。 **如何做:** 從 HTML、CSS 和 JavaScript 開始。使用 React 建立電子商務網站的不同部分,例如產品清單、購物車和結帳流程。整合動態資料並增強使用者介面。 ![使用 React 的 Amazon 克隆](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pq55ml71nqntt4j07p1z.png) ### 客戶關係經理 客戶關係管理器專案涉及建立一個後端 Web 應用程式,該應用程式允許建立、讀取、更新和刪除 (CRUD) 客戶資料。這是了解後端 Web 開發的基礎專案。 **如何做:** 利用 Node.js、Express.js 和 MongoDB 等技術來建立後端基礎架構。實施 CRUD 操作來管理客戶資料。開發一個用戶友好的介面,用於與客戶資料庫互動。 ![顧客關係經理](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jfr25p8b2gzapen1l8ry.png) ### 排序展示台 排序可視化器專案旨在提供各種排序演算法的可視化表示。使用者可以觀察不同的演算法如何執行,並更深入地了解 JavaScript 的基本概念。 **具體操作方法:** 使用 HTML、CSS、Bootstrap 和 JavaScript 建立 Web 應用程式。實現冒泡排序、合併排序和快速排序等排序演算法的視覺化。允許用戶與視覺化進行交互,以增強他們的學習體驗。 ![排序視覺化工具](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/51wpf82samc6k9ggftgc.png) ### 多人遊戲 – Connect4 多人遊戲 – Connect4 專案專注於建立具有多人遊戲功能的著名 Connect4 遊戲。它提供了學習一些重要的網路和遊戲設計基礎知識的機會。 **如何做:** 如果您想知道多人遊戲是如何開發的,或者您曾經想為週末製作一款遊戲,那麼這個專案適合您。使用 PyGame、Sockets 和遊戲編程為您和您的朋友建立多人 Connect4 遊戲。 ![多人遊戲 – Connect4](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ktsz3ky4pj27b9q7mynm.png) ### YouTube 腳本摘要器 投入時間觀看可能比預期更長的電影變得相當具有挑戰性。有時,如果我們不能從他們那裡收集有用的訊息,我們的努力可能會徒勞無功。透過自動總結影片的文字記錄,我們可以輕鬆地發現這些影片中的關鍵主題,這節省了我們再次觀看整個影片的時間和精力。 **如何做到這一點:** 人們每天都會觀看 YouTube 影片,這些影片可以是指導性的、紀錄片的或任何其他持續時間較長的類型;考慮透過提供摘要資訊可以節省多少時間。該專案將是一個 chrome 擴展,它將向後端的 Rest API 發送請求,該 API 將向您發送 YouTube 腳本的摘要。 ![YouTube 腳本摘要](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k4kw614tpyvyrumjc1g8.png) ### OurApp – NodeJS 中的社交媒體 Web 應用程式 現實應用程式 OurApp 的用戶可以進行交流、相互關注以及發布簡短的推文。掌握 HTML、CSS 和 JS 後,專案最適合想要使用 Nodejs 和 MongoDB 深入研究完整堆疊的人。 **怎麼做:** 你想成為能夠超越 HTML、CSS 和 JS 的全端開發人員嗎?建立這個完整的堆疊應用程式,以了解如何使用 NodeJS、MongoDB 和其他技術來建立現代、快速且可擴展的伺服器端 Web 應用程式。如果您想在磨練 NodeJS 技能的同時開發一些有趣的東西,那麼這個專案就是適合您的。您還可以免費註冊全端 Web 開發課程,這將幫助您成為您所在領域的傑出開發人員。 ![OurApp – NodeJS 中的社交媒體 Web 應用程式](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/02qifmojncuvx27k6hyu.png) ### Codechef 通知 CodeChef 經常遇到伺服器過載問題,導致評審難以快速提供提交結果。留給編碼人員的唯一選擇是在一段時間後不斷檢查站點,看看結果是否存在。透過這個專案,我們希望消除審查提交頁面以確定提交結果的額外步驟。我們將自動執行檢索結果的過程並在準備好後立即通知使用者。 **如何操作:** Codechef 是一個流行的編碼實踐平台,但伺服器過載可能會導致結果延遲。此附加元件旨在透過自動化獲取結果並及時通知用戶的流程來節省時間。使用網路抓取或 API 來收集結果資訊並實作通知系統。 ![Codechef 通知程序](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4k7ru3ff3h7tgne8qpoi.png) ### 使用 Dash 來視覺化和預測股票 該專案涉及使用 Dash(一種用於建立分析 Web 應用程式的 Python 框架)來視覺化和預測股票資料。它提供了將資料視覺化和機器學習概念應用於金融資料的機會。 **如何操作:** 如果您對股票市場感興趣,該專案將簡化股票資料的可視化。利用Python、Dash和相關函式庫進行資料視覺化。實施基於歷史資料預測股票趨勢的功能。 ![使用 Dash 視覺化和預測股票](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ovs08g50etufj84gz6fd.png) ### 線上程式碼編輯器 (JQuery) 線上程式碼編輯器可透過瀏覽器存取,並位於遠端伺服器上。儘管一些線上程式碼編輯器更像是完整的 IDE,但其他編輯器更像是具有語法突出顯示或程式碼完成等基本功能的文字編輯器。 **如何操作:** 使用 HTML、CSS、JavaScript 和 JQuery 建立線上程式碼編輯器。專注於透過語法突出顯示和程式碼完成等功能來增強使用者體驗。確保程式碼輸入和執行順利。 ![線上程式碼編輯器 (JQuery)](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h1vxgxvbtf1rh578lauc.png) ### 模糊URL FuzzyURLs 涉及使用 Django(Python 的高級 Web 框架)建立 URL 縮短服務。它提供了建立 Web 應用程式的實務經驗,特別關注 URL 操作。 **如何做:** 從頭開始開發一個基於 Django 的 URL 縮短器。了解 URL 縮短服務的工作流程並實現建立、管理和重新導向短 URL 的功能。 ![FuzzyURLs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5uouta53v2suc8m27i14.png) ### 使用 React 進行 Slack 克隆 該專案旨在使用 React 建立 Slack 克隆,提供即時訊息和協作的平台。這是一個中高階專案,強調React-Redux和Firebase。 **如何做:** 應用 React-Redux 原理來建立一個類似 Slack 的 Web 訊息服務。利用 Firebase 實現即時資料庫功能。專注於建立響應靈敏且功能豐富的訊息傳遞應用程式。 ![使用 React 的 Slack 克隆](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kugsfjeblq934ceomlhs.png) ### Web 應用程式的 Node.js 驗證 了解使用 Node.js 為 Web 應用程式建立驗證系統。探索各種身份驗證技術,評估其優點和缺點,並實施改進。 **如何做:** 對於那些想要深入研究 Node.js 並了解建立安全身份驗證系統的複雜性的人來說,這個專案非常適合。實施使用者身份驗證、會話管理並探索增強安全性的方法。 ![Web 應用程式的 Node.js 驗證](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0fcet0kd7abf6xu57eh8.png) ### TinyMCE 同義詞插件 為 TinyMCE 富文本編輯器建立一個插件,用於搜尋單字的同義詞並允許使用者將它們插入編輯器中。 **如何做到這一點:** 為 TinyMCE 開發一個自訂插件,整合一項功能,使用戶能夠搜尋同義詞並輕鬆地將它們插入到富文本編輯器中。了解 TinyMCE API 以實現無縫整合。 ![TinyMCE 同義詞外掛](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nmr8y3x21l9g7vuwz5mi.png) ### 迷宮裡的老鼠 建立一個基本的 React Web 應用程式,顯示老鼠從帶有預設障礙的方形迷宮的左上角到右下角可以採取的所有可能路徑。 **具體操作方法:** 建立一個簡單的 React Web 應用程式來直觀地呈現經典的 Rat in the Maze 謎題。實施功能來展示老鼠穿過迷宮的所有潛在路徑。 ![迷宮中的老鼠](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jdcwf4cioua8fogrsp96.png) ### 簡歷產生器 Web 應用程式 使用 ReactJS 和 NodeJS 建立一個用於建立履歷的 Web 應用程式。該專案將指導您完成建立簡歷產生器的步驟,並提供一種實用的方法來支援個人製作簡歷。 **如何做:** 深入研究 ReactJS 和 NodeJS 來開發一個用戶友好的簡歷產生器。實施加入個人詳細資訊、教育背景、工作經驗和技能的功能。專注於建立動態且可自訂的履歷模板。 ![簡歷產生器 Web 應用程式](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ntwflc67s9kwi00plrti.png) ### Markdown 編輯器 建立一個 Markdown 編輯器,讓使用者編寫 Markdown 並預覽渲染的 HTML。 Markdown 是一種基於網路的文字格式化系統,廣泛用於部落格文章、文件等。 **如何做:** 使用 HTML、CSS 和 JavaScript 開發 Markdown 編輯器。使用戶能夠編寫 Markdown 程式碼並查看渲染的 HTML 的即時預覽。使用粗體文字、圖像和清單等功能增強編輯器。 ![Markdown 編輯器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ppv6gl6pzq7uetmkax5b.png) ### 450 DSA 追蹤器 450 DSA Tracker 旨在協助使用者追蹤解決 450 道資料結構和演算法問題的進度。它利用 TypeScript、React.js 的 reducer 和 context API 以及即時瀏覽器 IndexedDB 來快取資訊。 **具體操作方法:** 使用 TypeScript 和 React.js 實作 Web 應用程式,以追蹤解決資料結構和演算法問題的進度。利用reducer 和context API 進行狀態管理,並利用IndexedDB 進行即時瀏覽器快取。 ![450 DSA 追蹤器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ijhv2y4gx3f1l2ub7xnz.png) ### 待辦事項網頁應用程式 使用 Node.js 框架 Adonis.js 建立待辦事項 Web 應用程式。了解 HTTP、REST API 和 CRUD 操作,同時建立用於管理待辦事項清單的後端 API。 **如何操作:** 使用 Adonis.js 為待辦事項 Web 應用程式建立 CRUD API。使用 Postman 測試 API 並建立用於新增、更新和刪除任務的後端功能。獲得使用後端框架的經驗。 ![待辦事項 Web 應用程式](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3rajw8titifncb6la3e6.png) ### 兩個真相和一個謊言遊戲 Slack 機器人 開發一個 Slack 機器人,用於在 Slack 工作區中玩「兩個真相和一個謊言」遊戲。該專案利用 JavaScript 和 Node.js 為工作區成員建立一個有趣的互動式遊戲。 **如何做:** 建立一個 Slack 機器人,以促進「兩個真相和一個謊言」遊戲。使用 JavaScript 和 Node.js 處理 Slack 工作區中的互動。實現用戶共享陳述並猜測哪一個是錯誤的功能。 ![兩個真相與一個謊言遊戲 Slack 機器人](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kwocawujfx0219s6ho5c.png) ### 使用 Chromakey(綠幕)效果進行即時視訊處理 探索視訊處理中使用的色度(綠幕)效果。使用 HTML、CSS 和 JavaScript 建立 Web 應用程式,以背景影片或圖像取代綠幕。 **具體操作方法:** 開發一個處理即時視訊並應用色鍵效果的 Web 應用程式。使用 HTML、CSS 和 JavaScript 操作影片幀並用背景影片或圖像替換綠幕。 ![使用 Chromakey(綠幕)效果進行即時視訊處理](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b4yc5aauy13cthc6b2b3.png) ### WhatsApp 網頁克隆 使用 React 和 Firebase 開發具有即時訊息功能的 WhatsApp Web 克隆。 **如何操作:** 使用 React 建立使用者介面並使用 Firebase 實現即時資料庫功能,打造流暢的訊息體驗。 ![WhatsApp 網路克隆](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ggf6mpl4bssvzjrr97b3.png) ### WhatsApp 上的電子郵件提醒 設定新電子郵件的 WhatsApp 提醒以簡化電子郵件管理和通知。 **如何操作:** 使用自動化平台 Twilio 建立一個工具,從收件匣中獲取詳細資訊並在 WhatsApp 上發送警報。 ![WhatsApp 上的電子郵件提醒](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2zxhacxpysrlx2d78sb5.png) ### 天氣預報應用程式 使用 Streamlit 函式庫和 OpenWeatherMap API 為天氣預報應用程式建立響應式前端。 **如何操作:** 利用 Python 和 Streamlit 可視化天氣資料並與 OpenWeatherMap API 互動以獲取即時天氣資訊。 ![天氣預報應用程式](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cwm38a5vw8sj2iu17y57.png) ### 總結 這個 Web 開發專案的彙編提供了各種各樣的挑戰,使您能夠提高跨不同技術和概念的技能。無論您對全端開發、資料視覺化、遊戲設計還是自動化感興趣,這些專案都可以提供有價值的幫助 --- 原文出處:https://dev.to/mukeshkuiry/25-web-development-projects-you-must-work-on-2024-4onl

為什麼我不推薦 Robert C Martin 的《Clean Architecture》

*乾淨的架構*在許多方面都未能滿足我的期望。儘管 Martin 先生對這個主題表現出明顯的熱情,但「清潔架構」組織得很差,缺乏範例,並且對使用現有系統保持沉默。作者錯過了一個重要的機會來教導我們何時以及如何將這些經驗教訓應用到我們自己的系統中。讓我解釋。 ### *乾淨的架構*是一本組織得很差的書 這本書需要很長時間才能開始。關於設計範式(結構化、物件導向和函數式)的章節似乎特別不合時宜且不必要。 關於 SOLID 原則的章節很好。我很高興看到這些原則被分解並得到很好的解釋。我發現思考它們對系統架構的適用性很有趣。但鮑伯叔叔提出了諸如硬性規則之類的堅實原則,這讓我感到不舒服。事實上,我非常確定一個***從未***違反 SOLID 原則的系統將是一個巨大的混亂。 然而,第 137 頁的這一段很重要: >架構的主要目的是支援系統的生命週期。良好的架構使得系統易於理解、易於開發、易於維護、易於部署。最終目標是最小化系統的生命週期成本並最大化程式設計師的生產力。 這是一個很好的觀察。叔叔鮑伯為什麼不把它放在第一章呢? ### 例子不夠多 本書中幾乎沒有任何例子。第 33 章包含一個討論影片銷售電子商務應用程式的範例。沒關係。但我並沒有明確地知道如何將這些概念應用到我自己的系統中。 附錄講述了 Bob 叔叔如何提出 SOLID 原則和乾淨架構規則的故事。它載有過去專案的範例。我認為這是本書**最有趣的部分**。 ### 這本書沒有提到改進現有系統的架構 大多數開發人員將大部分時間花在現有系統上。因此,我期望 *[Clean Architecture](https://www.amazon.com/Clean-Architecture-Craftsmans-Software-Structure/dp/0134494164/)* 充滿有關改進現有系統的建議。但這本書在這個問題上顯然隻字不提。 ### 如何建立一個乾淨的架構? 在本書的前半部分中,您將了解如何透過遵循 SOLID 原則將系統沿系統邊界分解為元件來建立一個乾淨的架構(我是這樣解釋的)。如果你停止閱讀那裡,你可能會有這樣的印象:叔叔鮑伯不會批准你為建築所做的一切,這是可以理解的。如果你認為他提出的幾個選項是「正確」的做事方式,這也是情有可原的。然而,在本書的最後,您將在第 228 頁讀到: >這個例子旨在顯示架構邊界無所不在。作為建築師,我們必須小心地辨識何時需要它們。我們也必須意識到,如果完全實施這些邊界,其成本是昂貴的。 >同時,我們必須認識到,當這些邊界被忽略時,即使存在全面的測試套件和重構規則,以後加入它們的成本也會非常昂貴。 >那我們建築師該怎麼辦?答案令人不滿意。一方面,多年來,一些非常聰明的人告訴我們,我們不應該預見抽象的需要。這就是 YAGNI 的哲學:“你不會需要它。”這句話充滿智慧,因為過度設計往往比設計不足更糟。另一方面,當您發現確實需要一個不存在的架構邊界時,加入這樣一個邊界的成本和風險可能會非常高。 >所以你已經得到它了。軟體架構師啊,你必須看見未來。你必須聰明地猜測。您必須權衡成本並確定架構邊界在哪裡,哪些應該完全實現,哪些應該部分實現,哪些應該被忽略。 因此,在本書的一半以上,他說應該由我們來決定我們的系統的邊界在哪裡。這種界限可能無所不在。令人困惑,對吧? ### 這本書缺少什麼 因此,如果軟體架構的最終目標是最小化系統的生命週期成本,那麼一本關於架構的書不應該幫助架構師做出這些決策嗎? #### 未解答的問題 這本書給我留下了很多未解答的問題。各種選擇的經濟學討論在哪裡?如何找到最適合我的系統的架構?研究在哪裡? ![未解答的問題](https://thepracticaldev.s3.amazonaws.com/i/fll25irsu1xbd0268kq2.jpg) 我該如何決定水平分層、垂直切片或其他方式是否可以最大限度地降低系統的生命週期成本?或者,如果我沒有明確定義的層,我該如何決定哪種分層策略(如果有)可以最大限度地降低我的生命週期成本? 我還有更多問題。如果您改進現有系統架構的時間有限,您應該把精力放在哪裡?將資料庫與業務邏輯分開總是一個好主意嗎?您應該始終遵循哪些建議?哪些建議取決於系統? #### 讓*乾淨的架構*更有價值的細節 在*[Code Complete](https://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670/)*中,Steve McConnell 討論了不同非功能性需求(例如可靠性、可靠性)之間的權衡、正確性、可維護性、可讀性等。他解釋了一些需求如何協調一致而另一些需求如何衝突。我很樂意看到類似的東西用於本書中討論的架構決策。 在*清潔架構*中,專案規模、團隊規模、專案失敗的後果、預期程式碼生命週期和其他重要因素作為架構的驅動因素沒有得到足夠的重視。例如,Healthcare.gov 需要比您正在開發的個人待辦事項清單更多的架構,即使它們都是由資料庫支援的 Web 應用程式。 ### 這本書的真正內容是什麼 本書的大部分內容我都感到有些困惑。我有點明白叔叔鮑伯想說什麼。但直到讀了附錄才完全明白。那麼,讓我為您節省一些時間。 #### 一個例子 想像一下您正在為消費市場建立一台桌上型電腦(例如辦公室電腦)。您可以選擇硬件,然後為整個系統編寫軟體(韌體、作業系統、驅動程式、應用程式等)。 #### 你會寫一個整體嗎? 你會怎樣做呢?您會編寫一個巨大的程式(一個整體),其中電子表格的程式碼知道您為電腦選擇的磁碟類型嗎?您能否想像更新電子表格程式碼並在各處新增「if」語句,以便在您有 SATA 磁碟機時執行一件事,而在有 SCSI 磁碟機時執行另一件事?然後對 VGA、DVI 和 HDMI 視訊做同樣的事情? PS/2 與 USB 滑鼠輸入的不同路徑怎麼樣?然後對文字處理器和您打算與電腦捆綁的所有其他應用程式重複該過程? 維護這將是一場惡夢,對嗎?那麼解決方法是什麼呢?建築學!您的電子表格不應該知道您使用的是哪種滑鼠。也不知道你有什麼樣的顯示器。它應該完全忘記這些細節。 #### 計算機中的邊界 如果您查看計算機,您會發現這一點。您的滑鼠中有嵌入式軟體,可以與作業系統進行通訊。然而,詳細資訊對您的應用程式是隱藏的。您的電子表格接受標準化輸入,而無需知道或關心您使用的滑鼠類型。然後,當有人發明了新的輸入裝置(例如觸控板)時,它會自動與您的電子表格配合使用。 這只是計算機的邊界之一。您可能會想出數百個。您可以指派不同的團隊來處理系統的不同部分。您可以為不同元件互動的各種方式建立或採用不同的規格。 此時你可能會說「呃」。顯然,您不希望每次硬體發生變化時都更改並重新編譯電子表格。維護將是一場惡夢。並且我同意。 #### 邊界是你的朋友(如果你正確使用它們) 很容易看出硬體邊界。但使硬體邊界變得有價值的相同邏輯也適用於軟體邊界。軟體邊界更難看到。 因此,您可以從在螢幕上顯示電子表格的能力開始。但您可能還想將其儲存到磁碟、儲存為 PDF、儲存為 CSV 或列印。因此,電子表格程式的邊界之一可能是擁有代表每個電子表格的內部資料結構。然後將該結構傳遞給不同的程式碼,以所需的格式顯示、儲存或列印它。 如果您讓資料結構完全不知道它是如何顯示、保存或列印的,那麼您可以在以後加入「儲存到 XML」功能,而無需深入研究與電子表格資料結構相關的所有程式碼。如果電子表格資料結構有幾百萬行程式碼,您可以想像這會容易得多。 這就是鮑伯叔叔在本書中試圖告訴我們的全部。 **您可以使用 SOLID 原則在系統中建立邊界,隱藏實作細節、降低複雜度並幫助您降低系統的總生命週期成本**。 ### 一本更好的軟體架構書 在許多方面,Martin Fowler 的*[企業應用程式架構模式](https://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420/)* 遠遠優於*清潔架構* 。 Fowler 描述了他在企業應用程式中反覆觀察到的模式。他給出了每個模式的簡單範例,描述了它的工作原理以及在何處使用它。我發現“企業應用程式架構模式”非常可讀並且適用於我的系統。 ### 要點 *乾淨的架構*中有有價值的訊息,但你必須努力找到它。 我發現有關嵌入式軟體的章節是最容易理解的章節之一。直觀上,避免在整個程式碼庫中分散低階呼叫是有意義的。在沒有硬體的情況下使邏輯可測試也是有意義的(特別是因為嵌入式軟體通常是在硬體可用之前開發的)。如果您只能閱讀本書的兩章,我建議您閱讀這一章和附錄,無論您以編寫哪種軟體為生。 總的來說,《乾淨的架構》是一本很難讀的書,鮑伯叔叔留給我的問題比答案還多。我絕對不會推薦這本書作為您關於軟體架構的第一本書(請查看*[企業應用程式架構模式](https://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420/ )* 由馬丁·福勒取代)。 *同意還是不同意。我很想聽聽你的想法。* *喜歡這篇文章嗎?請在下面“喜歡”它。* --- 原文出處:https://dev.to/bosepchuk/why-i-cant-recommend-clean-architecture-by-robert-c-martin-ofd

我寫出易讀程式碼的 3 個原則

多年來圍繞著評論存在著許多爭論。許多人堅持認為“好的程式碼會自我註釋”,而其他人則贊成在程式碼中包含好的註釋,並認為應該需要它們。當我閱讀和聽到這些爭論時,我注意到他們經常關注程式碼的*什麼*和*如何*......即。程式碼*做什麼*,以及*如何*做到這一點。但「為什麼」的概念很少進入討論…即。 *為什麼*需要這段程式碼,或是*為什麼*要這樣寫。儘管雙方都有有效的論據,但很難知道該往哪個方向走。這促使我建立了 3 條規則,我相信這不僅有助於彌合兩者,而且還能鼓勵編寫更好的程式碼。我想與您分享我的 3 條規則,希望它們能像我一樣對您有所幫助。 ## 規則 1:名稱要解釋*什麼* ![一個抽象的人形機器人思考著頭上有問號的東西](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uj8crlt54k76jri1b0f7.png) 程式碼中的變數、參數、介面、函數、類別、方法或其他「事物」的名稱應提供足夠的訊息,以清楚地描述該事物的「什麼」功能或它所具有的「什麼」值。另一個開發人員應該能夠在幾週或幾個月後讀取該事物的名稱,並準確地知道它的功能或它所擁有的內容,而無需詢問、查看額外的程式碼或閱讀額外的文件。如果這樣做,則應更改名稱以使其更清晰。 為了在這裡澄清一點,重要的是要注意名稱不負責描述某些東西的“用途”。名稱僅負責描述該事物的“做什麼”,或該事物所具有的“什麼”價值。 讓我們來看一些我個人遇到的例子來幫助澄清這一點: ``` const derivatives = []; ``` 只知道這個名字,你就能知道這個陣列裡會保存什麼樣的資料嗎?顯然它包含了從其他東西複製或改編的東西......但是這些資訊足夠嗎?試著退一步思考,如果您在正在編寫的某些程式碼中遇到此問題,您會問自己或其他人甚麼樣的問題。 ``` function name(user) { // ... } ``` 這裡我們有一個函數正在執行與用戶名相關的操作...現在,無需閱讀其他程式碼或向某人詢問更多上下文,您能說出這個函數的作用嗎? 當我遇到這個問題時,我必須查看更多程式碼才能弄清楚它做了什麼......在我問“這是否返回名稱?”,“這是否會更新名稱?”或“這是否構造來自其他資料的名字?” 希望您能看到上面的範例不是好名稱,需要更改,因為它們不符合此規則的要求。您將不得不查看更多程式碼或詢問其他人來弄清楚他們做什麼或持有*什麼*。那什麼是更好的名字呢?顯然,我們可以使用很多不同的名稱,但這裡有幾個例子: ``` const derivativeUsers = []; ``` 透過這個更新後的名稱,我們現在可以知道該陣列將容納一定數量的從其他陣列複製或改編的用戶。無需閱讀額外的程式碼或詢問其他人。哈札! ``` function getFullName(user) { // ... } ``` 在這裡,我們更改了函數的名稱,以更清楚地說明該函數的*什麼*功能。透過這個簡單的更新,我們現在知道該函數傳回傳遞給它的使用者的全名。 因此,總結第一條規則,您在程式碼中命名的任何內容都應該清楚地描述該事物的*什麼*,或*什麼*值(如果成立)。這可能會讓你的名字變得更冗長一些,但在我個人看來,如果更冗長一點意味著程式碼對你和團隊來說更具可讀性和可維護性,那麼這是值得付出的代價。 ## 規則 2:程式碼應解釋*如何* ![一個人坐在辦公桌前寫下某件事是如何完成的](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pomudgtas0bt8drlh3wc.png) 雖然事物的名稱告訴了它“做什麼”,但它內部的程式碼應該描述它“如何”做到這一點。現在,這可能聽起來有點明顯,但它帶來了一些您必須考慮的事情。 為了讓其他人理解程式碼「如何」執行某些操作,它必須具有可讀性和可理解性。如果沒有人能夠理解執行*操作*的程式碼,那麼它的好處就會少很多。其中一部分來自於組成程式碼的各個部分的命名。但有助於程式碼可讀和理解的其他因素包括簡單性、組織和結構、格式和樣式,僅舉幾例。 這是一個很大的話題,有很多關於它的文章、書籍和課程,所以我不會在這裡討論太多細節。只需要知道,編寫乾淨的程式碼是編寫可讀且可理解的程式碼的一個非常重要的部分,它可以讓團隊的其他成員知道「如何」某件事是如何做到的。 另一個難題是模組化。如果某個東西很小並且只做一件事,那麼理解它是如何做的就容易多了。您可能在您的職業生涯中以某種形式聽說過這個概念。也許您熟悉單一職責原則,即 [SOLID 原則] 中的「S」(https://www.goodreads.com/book/show/25936819-design-principles-and-design-patterns) 。如果您還不熟悉,我強烈建議您研究一下,因為它是軟體開發領域的重要概念。但回到正題。如果一個函數、類別、方法、元件或其他任何東西執行不只一件事,則程式碼的複雜性會急劇增加,並且不僅辨識*如何*它是如何做到的,而且隨著時間的推移,維護它也會變得更加困難。 因此,為了使您的程式碼符合第二條規則,您或團隊的其他成員必須在幾個月後能夠理解它。他們應該能夠查看某些“事物”的程式碼,並能夠輕鬆辨識它“如何”執行其功能。為了實現這一點,我們必須編寫乾淨、可讀、可理解的程式碼。 ## 規則 3:評論應該解釋*為什麼* 最後,當需要更多資訊時,當我們需要了解「什麼」和「如何*」之外的內容時,我們需要「為什麼」…這就是評論來拯救世界的地方。當我們編寫程式碼時,有時我們需要傳遞更多訊息,例如「為什麼」做出決定、「為什麼」需要一段程式碼或與之相關的一些其他上下文。這些都是應該評論的事情。 在編輯不是立即顯而易見的特定程式碼區塊時,可能需要考慮一些晦澀的用例。這應該被清楚地註釋,這樣當下一個開發人員下週、下個月甚至明年返回這段程式碼時,他們也會考慮到這些訊息,而不是重新引入一些錯誤,或破壞其他一些部分的功能。 也許由於某些第三方依賴項的工作方式,必須在程式碼的特定區域執行一些不「正常」的操作。與其期望團隊的其他成員遇到同樣的問題並必須自己解決,不如對情況進行評論,以節省他們以後的時間(可能是幾個小時甚至幾天)。 理解「為什麼」某件事以這種方式完成可以提供巨大的洞察力,特別是當有多種路徑可供選擇時,或者如果存在影響決策的間接背景。在我個人看來,評論“為什麼”不僅僅是程式碼中的“很好”,而且至關重要。它對於可維護性、知識共享至關重要,最重要的是對於幫助團隊其他成員成功至關重要。 知道何時應包含“為什麼”有時可能很困難。大多數人,包括我自己,都忘記了我們擁有別人所沒有的知識和理解。我們在生活中假設或期望其他人要么知道這些東西,要么很容易弄清楚……即使我們花了幾個月的時間收集不同的資訊來獲得這些知識。因此,當您編寫下一段程式碼時,請真正退一步思考一下,您認為下一個開發人員將擁有哪些資訊來理解它?然後,在評論中寫下這些內容。 ## 結論 嗯,就是這樣…保存程式碼的 3 個簡單規則。因此,下次當您在流程中編寫下一個重要功能時,請嘗試記住... 1. 命名應該解釋您的程式碼的*什麼*功能。 2. 程式碼本身應該是可讀且易於理解,以便您和其他人可以輕鬆辨識它*如何*執行它正在執行的操作。 3. 使用註解提供所有額外訊息,以便每個人都知道*為什麼*程式碼是這樣編寫的。 希望這3條規則對你的職涯有幫助!下次見,駭客快樂! --- 原文出處:https://dev.to/wraith/my-3-rules-for-documenting-code-2f54

2024 年掌握前端開發的 9 個專案點子

想要 **在 2024 年掌握前端 Web 開發?** 無論您是渴望開始前端開發之旅還是希望提升您的技能,我們都能滿足您的需求。 這裡有 9 個令人興奮的專案,它們將使您能夠在 2024 年掌握前端開發。為了加速您的學習過程,每個專案都配有專用資源。 讓我們深入研究並將您的編碼願望變成現實! 🚀 ### 1. 說故事作品集網站 建立一個引人入勝的說故事作品集網站來展示您的技能和專案。使用動畫和過渡來吸引訪客。 **您將學到什麼:** 該專案將提高您建立個人作品集、將動畫與 CSS 和 JavaScript 結合的能力。您還將透過網頁設計深入了解如何有效地講述故事。 **技術堆疊:** HTML、CSS、JavaScript、GSAP(GreenSock 動畫平台)。 **資源:** [說故事作品集教學](https://youtu.be/0fYi8SGA20k?si=lgzXlqL7m2aK3nzg) ![說故事組合](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k2smmhfqq2g7qx1yune1.png) ### 2. 電影搜尋應用程式 使用 React Hooks 建立電影搜尋應用程式。用戶可以搜尋電影、查看詳細資訊並發現新上映的電影。 **您將學到什麼:** 透過這個專案,您將掌握使用 React Hooks 進行狀態管理、非同步資料擷取和響應式設計。此外,您還將深入了解如何處理使用者輸入和管理複雜的資料結構。 **技術堆疊:** React Hooks、Axios、CSS(flexbox/grid)和電影資料庫(IMDB)API。 **資源:** [電影搜尋應用程式教學](https://www.freecodecamp.org/news/how-to-build-a-movie-search-app-using-react-hooks-24eb72ddfaf7/) ![電影搜尋應用程式](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6wtwna67o253uusbpoj9.png) ### 3. 任務管理應用程式 開發具有任務建立、完成追蹤和類別組織等功能的任務管理應用程式。 **您將學到什麼:** 該專案將加深您對 React 中的狀態管理、CRUD 操作以及用於任務管理的使用者友好介面的實現的理解。 **技術堆疊:** React、useState、useEffect、localStorage、CSS。 **資源:** [任務管理應用教學](https://youtu.be/m4MDt7UUu1w?si=EcCbIMtkmHZIsWPS) ![任務管理應用程式](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/49wmxw4xcfzlig2mrmk4.png) ### 4. 互動式履歷表產生器 建立一個互動式履歷產生器來展示您的職業歷程。包括教育、工作經驗和技能部分。 **您將學到什麼:** 透過這個專案,您將掌握表單處理、動態內容呈現和建立互動式使用者介面的藝術。這是提高你的 React 技能的絕佳機會。 **技術堆疊:** React、表單處理、CSS(樣式元件)。 **資源:** [互動式履歷產生器播放清單](https://youtube.com/playlist?list=PLrL9i_Ka3T0caA37TXSlicITQl1pp_3Ry&si=UhftAkbYr_eYaxJZ) ![互動式履歷產生器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kqsmo0bflp7x9juv94br.png) ### 5.產品落地專案 開發一個產品登陸頁面,重點宣傳特定產品或服務。針對各種螢幕尺寸實施響應式設計。 **您將學到什麼:** 本專案將加深您對響應式網頁設計的理解,包括媒體查詢、Flexbox 和網格佈局。您還將提高建立具有視覺吸引力的登陸頁面的技能。 **技術堆疊:** HTML、CSS(Flexbox/Grid)、響應式設計。 **資源:** [產品登陸頁面教學](https://youtube.com/playlist?list=PL07efmqYWHZ8jroJAkkFB2s4ZKpVNCOQa&si=ZI375j0QMaN7rpdn) ![產品登陸頁](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oqpejqx835m7zxgs585u.png) ### 6. 使用 GitHub API 的個人資料頁面 建立一個個人資料頁面,從 GitHub API 取得資料,顯示使用者資訊、儲存庫和貢獻熱圖。 **您將學到什麼:** 該專案將增強您使用 API、處理非同步資料以及建立具有視覺吸引力的使用者設定檔的技能。您還將獲得將第三方 API 整合到應用程式中的經驗。 **技術堆疊:** React、GitHub API、CSS。 **資源:** [GitHub API 設定檔教學](https://dev.to/falanatolu/using-github-api-to-fetch-and-display-a-github-user-profile-26g6) ![使用 GitHub API 的個人資料頁面](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t5qvthy4yzgx60a5omp4.png) ### 7.響應式部落格網站 開發一個響應式部落格網站,其中包含針對各種裝置優化的文章清單、單一文章頁面和導航選單等功能。 **您將學到什麼:** 該專案將提高您建立複雜佈局的技能,並專注於回應能力。您將獲得建立導航結構和優化不同螢幕尺寸的使用者體驗的經驗。 **技術堆疊:** HTML、CSS (Flexbox/Grid)、JavaScript。 **資源:** [響應式部落格網站教學](https://youtu.be/NNQuhOeM0mI?si=RjNPOIm-otDhMTsE) ![響應式部落格網站](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/potx6blzf3if4cfp4wv7.png) ### 8. 使用 Lottie 檔案的動畫天氣應用程式 使用 Lottie 檔案建立帶有動畫天氣圖示的天氣應用程式。提供與當前天氣狀況對應的即時天氣資訊和動畫。 **您將學到什麼:** 該專案將擴展您將外部庫 (Lottie) 整合到專案中的技能。您還將獲得使用即時資料 API 和實現動態動畫的經驗。 **技術堆疊:** React、Lottie、OpenWeatherMap API、CSS。 **資源:** [動畫天氣應用教學](https://youtu.be/pFvWwFua6mw?si=Xut6cKy10rV1DpFd) ![動畫天氣應用程式](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x392uay0fjf8kypyrtoy.png) ### 9.SaaS 登陸頁面 設計並建置軟體即服務 (SaaS) 產品的登陸頁面。強調簡潔的設計、有效的文案和引人注目的號召性用語元素。 **您將學到什麼:** 該專案將提高您建立以行銷為導向的登陸頁面的技能,並專注於用戶轉換。您還將深入了解有說服力的設計和有效使用配色方案的原則。 **技術堆疊:** React、Tailwind CSS、文案。 **資源:** [SaaS 登陸頁面教學](https://youtube.com/playlist?list=PLz_5rPRIvGEBDvyf-HIIDHjsPppnuXtFG&si=JIpCCIbz4QW8v9o4) ![SaaS 登陸頁](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cl16te1dbqsp5np73bh2.png) 踏上這些令人興奮的專案,在 2024 年掌握前端 Web 開發。每個專案都提供一系列獨特的挑戰和學習機會,讓您具備在動態 Web 開發領域脫穎而出所需的技能。快樂編碼! 🚀 --- 原文出處:https://dev.to/mukeshkuiry/9-projects-to-master-frontend-web-development-in-2024-with-resource-d0k

🔥 NextJS 專案的 12 個頂級庫 🏆

![保存](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/szi0gw4l049yctxjeu1p.png) 在過去的十年裡,我一直是一名全端開發人員,建置了像[gitup](https://gitup.dev/) 這樣的較小專案和像[crosspublic](https://github.com/github-20k/) 這樣的更大專案跨公共)。 多年來,我測試了不同的工具: 1. 提高工作效率 2. bug 更少 3. 少寫程式碼 我整理了一系列庫來幫助您開發我每天使用的優秀 NextJS 東西,並解釋了您可以用它們做什麼。 **讓我們深入了解一下。** ![變得更好](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ap38q1ej3tqypjuebg3u.gif) --- # 1. [Trigger.dev](https://github.com/triggerdotdev/trigger.dev) 使用 NextJS,我總是需要幫助來處理與後台作業相關的所有事情。 它可以是在背景執行的 cron 作業,用於傳送電子郵件或處理系統中的新使用者管道。 這導致我執行另一台伺服器來處理這些作業,無論是外部 EC2 伺服器還是帶有事件橋的無伺服器功能。 這會導致我支付額外的服務費用(管理更多服務)並自行管理水平擴展(在某些時候)。 [Trigger.dev](http://Trigger.dev) 改變了這一點,在 NextJS(以及許多其他)之上提供後台作業。 他們也知道如何解決 NextJS 無伺服器逾時限制來處理長時間執行的作業。   ![TriggerDev](https://nevdav2.dreamhosters.com/wp-content/uploads/2023/12/triggertop.gif) --- ## 2. [Prisma](https://www.prisma.io) Prisma 不是 NextJS 特有的。它是一個與資料庫一起使用的 ORM。 ORM 是資料庫查詢的統一包裝器。 它保持良好的結構,並允許您在不同的資料庫提供者之間快速更改。 雖然您可以使用很多 ORM,但 Prisma 的獨特之處在於為您的查詢提供 Typescript 支持,使一切速度提高 100 倍。 NextJS 在預設配置中使用了 typescript,使其成為完美的匹配。   ![prisma.gif](https://nevdav2.dreamhosters.com/wp-content/uploads/2023/12/prisma.gif) --- ## 3. [NextAuth.js](https://next-auth.js.org) 假設您要實現任何服務提供者身份驗證,例如 Facebook / Google / GitHub (oAuth)。 在這種情況下,您必須為每個提供者建立實作或使用外部服務,例如 [Auth0](https://auth0.com/) 或 [Clerk](https://clerk.com/)。 如果您打算自行執行此操作,NextAuth 提供了豐富的實現,以便您只需提供正確的金鑰即可輕鬆新增它們。 一旦您登錄,他們也會處理授權。 *Next.JS auth 可以與 Prisma 開箱即用。*   ![authjs.gif](https://nevdav2.dreamhosters.com/wp-content/uploads/2023/12/authjs.gif) --- ## 4. [下一個網站地圖](https://github.com/iamvishnusankar/next-sitemap) 在伺服器上部署 NextJS 後,您需要協助 google 索引所有頁面。 如果您可以告訴 Google 您網站上的所有頁面,那就更好了。 為此,您可以建立一個列出所有頁面的 sitemap.xml 檔案。 您可以輕鬆地使用 Next-Sitemap 來實現這一點。   ![sitemap.gif](https://nevdav2.dreamhosters.com/wp-content/uploads/2023/12/sitemap.gif) --- ## 5. [下一步 SEO](https://github.com/garmeeh/next-seo) SEO 是透過向您的網站預覽提供關鍵字、描述和圖像,使您的網站出現在 Google Feed 上以進行不同查詢的過程。 如果您使用新的 NextJS 應用程式路由器,則可能不需要使用它。 您可以使用他們的“導出元資料”方法或“生成元資料”, 但如果您使用舊的應用程式路由器,這是為您的網站加入 SEO 的最佳方式。   ![seo.gif](https://nevdav2.dreamhosters.com/wp-content/uploads/2023/12/seo.gif) --- ## 6. [Zod](https://github.com/colinhacks/zod) Zod 是一個物件驗證器(伺服器和客戶端)。 您可以在物件上放置不同的規則並稍後對其進行驗證,例如使用者名稱和密碼,或更複雜的內容(例如陣列長度或其他鍵上的條件)。 *Zod 不是 NextJS 特定的。* 多年來,我看過很多物件驗證器,例如 [Yup](https://github.com/jquense/yup) 和 [class-validator](https://github.com/typestack/class-validator)。 是的,它看起來不像 Zod 那樣維護,並且在使用 NestJS 之類的東西時,類驗證器非常強大 - 所以你最好使用 Zod。   ![zod.gif](https://nevdav2.dreamhosters.com/wp-content/uploads/2023/12/zod.gif) --- ## 7. [React-hook-form](https://github.com/react-hook-form/react-hook-form) 雖然 Zod 可以驗證物件,但如果沒有自訂邏輯,它不會影響您的用戶端和後端。 React-hook-form 是優秀的用戶端驗證專案(顯示輸入錯誤、管理輸入狀態和提交)。 當然,您可以使用 Zod 作為 React-hook-form 的驗證器。   ![hookform.gif](https://nevdav2.dreamhosters.com/wp-content/uploads/2023/12/hookform.gif) --- ## 8. [tRPC](https://github.com/trpc/trpc) 我承認我以前從未使用過 tRPC,但今天它似乎吸引了許多人的目光。 它與 Prisma 有類似的概念;它們為您的請求和回應產生一個接口,因此當您使用前端呼叫時,您會獲得自動完成功能。 這很好,因為它減少了錯誤的機會 - 假設您修改了後端路由,您將無法編譯專案 - 客戶端將返回不存在的參數或回應鍵的錯誤。   ![trpc.gif](https://nevdav2.dreamhosters.com/wp-content/uploads/2023/12/trpc.gif) --- ## 9. [SWR](https://swr.vercel.app) 和 [React-Query](https://github.com/TanStack/query) 多年來我一直使用 Axios 和 fetch 作為發送請求的基礎庫。 SWR 和 React-Query 增強了這些函式庫並提供鉤子、快取、轉換等。 強烈推薦用於每個專案。請注意,這些庫適用於客戶端元件(“使用客戶端”),而不是伺服器元件。   ![query.gif](https://nevdav2.dreamhosters.com/wp-content/uploads/2023/12/query.gif) --- ## 10. [lodash](https://lodash.com) 這不是 NextJS 特定的函式庫。 它是一個用於改變資料的函式庫,雖然這些年來 JavaScript 憑藉像 flatMap 這樣優秀的原生函數取得了很大的進步,但仍然缺少一些東西,例如按鍵或分塊和陣列的唯一陣列。 我發現自己幾乎在所有專案中都使用 lodash。   ![lodash.gif](https://nevdav2.dreamhosters.com/wp-content/uploads/2023/12/lodash.gif) --- ## 11. [dayjs](https://day.js.org/) day.js 是一個包含與日期、格式、時區等相關的所有內容的函式庫。 我可能會因為那件事而被烤。我多年來一直在使用“moment.js”。 現在它不再維護了,dayjs 是一個不錯的選擇。 有些人喜歡新的 JS 函數來處理日期,但我仍然覺得 dayjs 選項和原生 JS 日期函數之間存在很大的差距。   ![scrolldown.gif](https://nevdav2.dreamhosters.com/wp-content/uploads/2023/12/scrolldown.gif) --- ## 12. [jsdom](https://github.com/jsdom/jsdom) 這不是必須的,但我最近在許多專案中都使用它作為 [cheerio](https://github.com/cheeriojs/cheerio) 的替代品。 您可以取得整個頁面內容(`<html><body>....</html>)` 並將其轉換為稍後可以使用「本機」javascript dom 函數`querySelector`、`innerHTML` 等來操作的物件… 非常適合需要一些刮擦的專案。   ![jsdomer.gif](https://nevdav2.dreamhosters.com/wp-content/uploads/2023/12/jsdomer.gif) --- 我們在 X 上連接嗎? :) [我在這裡](https://twitter.com/nevodavid) 您是否為 NextJS 使用其他一些很酷的程式庫? 請在評論中讓我了解它們:) --- 原文出處:https://dev.to/nevodavid/top-12-libraries-for-your-nextjs-project-1oob

AI 程式碼產生與手動編碼 - 202X 的程式設計將會是什麼樣子 🤖 🤔

我們正在開發一個 [React 和 Node.js 的全端 Web 框架](https://github.com/wasp-lang/wasp),它使用簡單的設定語言來擺脫樣板檔案。很多次,我們被問到,*「為什麼你要費心去建立一個新的 Web 應用程式開發框架?無論如何,ChatGPT / LLM X 不是很快就會為開發人員生成所有程式碼嗎?」*。 這是我們對當前情勢的看法,也是我們相信未來的情況。 ## 為什麼我們需要(AI)程式碼產生? 為了讓開發速度更快,我們首先提出了 IDE 自動補全 - 如果您正在使用 React 並開始輸入 `use`,IDE 將自動向 `useState()` 或 `useEffect()` 提供補全。除了節省擊鍵次數之外,也許更有價值的是能夠查看目前範圍內有哪些方法/屬性可供我們使用。 IDE 對專案結構和程式碼層次結構的感知也使重構變得更加容易。 **雖然這已經很棒了,但是我們如何將其提升到一個新的水平?** 傳統的 IDE 支援是基於人類編寫的規則,例如,如果我們想讓 IDE 能夠為我們實現常用功能(例如, *使用API Y* 取得X,或*實現快速排序*),其中的數量太多,無法手動進行分類和維護。 如果有一種方法可以讓電腦分析我們迄今為止編寫的所有程式碼,並自行學習如何自動完成我們的程式碼以及如何對待人類,而不是我們做所有艱苦的工作... [除了美味又濕潤的蛋糕](https://www.youtube.com/watch?v=Y6ljFaKRTrI),我們其實已經做到了!由於機器學習的最新進展,IDE 現在可以做一些非常酷的事情,例如根據函數的名稱和頂部的簡短註釋來建議函數的完整實現: ![GPT 函數實作範例](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9p0mivtdpmjcskgt7qnl.gif) 這真是太神奇了!上面的範例由 [Github Copilot](https://copilot.github.com/) 提供支援 - 它本質上是一個在大量公開可用程式碼上訓練的神經網路。我不會深入了解其幕後工作原理的技術細節,但有很多精彩的文章和影片涵蓋了背後的科學知識。 **看到這一點,問題出現了 - 這對程式設計的未來意味著什麼?** 這只是 IDE 自動補全功能還是其他什麼?如果我們只需在註釋中輸入我們想要的內容就可以了,我們還需要繼續手動編寫程式碼嗎? ## 支持我們! 🙏⭐️ ![star_us](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j3a8gkl9fcs0a8rl4zsq.gif) 如果您想表達對我們正在做的事情的支持,請考慮[在 Github 上給我們一顆星](https://github.com/wasp-lang/wasp)!我們在 Wasp 所做的一切都是開源的,您的支持激勵我們並幫助我們不斷簡化 Web 應用程式開發並減少樣板程式碼。 ![丟一顆星](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lz3ok1dpfkscsoo0n2om.gif) ## 大問題:程式碼產生後由誰維護? 在思考 ML 程式碼產生如何影響整個開發過程時,有一點需要考慮,但在查看所有令人印象深刻的範例時,通常不會立即想到這一點。 問題是 - **生成程式碼後會發生什麼?誰負責,將來誰來維護和重構?** ![一直是](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4bzh9yp2ejwhu4zpio0e.png) 儘管 ML 程式碼產生有助於編寫特定功能的初始程式碼,但它不能做更多的事情 - 如果將來要維護和更改該程式碼(如果有人使用該產品,那麼開發人員仍然會這樣做)需要完全擁有並理解它。你可以再次使用人工智慧來幫助你,但最終,你是負責的人。 想像一下,我們擁有的只是一種彙編語言,但程式碼生成非常適合它,你可以說“實現一個對陣列進行升序排序的函數”,它將完美地生成所需的程式碼。一旦您需要將排序更改為降序,您是否仍想在將來返回該功能? 或者,更貼近我們的日常生活,如果產生的 React 程式碼使用舊的類別語法,或者函數式元件和鉤子,對你來說是否都是一樣的? **換句話說,這意味著GPT 和其他LLM 不會降低程式碼複雜性,也不會降低建置功能所需的知識量**,它們只是幫助更快地編寫初始程式碼並使知識/範例更接近程式碼(其中真的很有幫助)。 **如果開發人員盲目接受生成的程式碼,他們只是在創造技術債並推動其向前發展**。 ## 認識大 A - 抽象 👆 如果 ChatGPT 和這群人無法解決我們學習如何編碼和詳細理解(例如透過 JWT 進行會話管理)工作原理的所有麻煩,還有什麼可以呢? 抽象化——這就是程式設計師幾十年來透過建立庫、框架和語言來處理程式碼重複和降低複雜性的方式。這就是我們從普通 JS 和直接 DOM 操作到 jQuery,最後到 React 和 Vue 等 UI 函式庫的方式。 引入抽像不可避免地意味著放棄一定的功能和靈活性(例如,在 Python 中對數字求和時,您無法準確指定將使用哪些 CPU 寄存器),但重點是,如果如果做得好,在大多數情況下你不需要也不想要這樣的權力。 ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/75uhgmdu7fq5wcwhe6tw.jpg) **不對一段程式碼負責的唯一方法是它從一開始就不存在。** 因為一旦螢幕上的像素改變顏色,你就必須擔心,這就是為什麼所有框架、語言等的主要好處是_更少的程式碼==更少的決策==更少的責任_。 擁有更少程式碼的唯一方法是做出更少的決定,並向計算機提供更少的關於如何完成某項任務的細節- 理想情況下,我們只需要說明我們想要什麼,我們甚至不會關心它是如何完成的,只要它在我們擁有的時間/記憶體/成本邊界內(所以我們可能也需要說明這些)。 讓我們來看看網路應用程式世界中非常常見(也是每個人最喜歡的)功能 - 身份驗證(yaay ☠️ 🔫)!它的典型程式碼如下所示: ``` import jwt from 'jsonwebtoken' import SecurePassword from 'secure-password' import util from 'util' import prisma from '../dbClient.js' import { handleRejection } from '../utils.js' import config from '../config.js' const jwtSign = util.promisify(jwt.sign) const jwtVerify = util.promisify(jwt.verify) const JWT_SECRET = config.auth.jwtSecret export const sign = (id, options) => jwtSign({ id }, JWT_SECRET, options) export const verify = (token) => jwtVerify(token, JWT_SECRET) const auth = handleRejection(async (req, res, next) => { const authHeader = req.get('Authorization') if (!authHeader) { return next() } if (authHeader.startsWith('Bearer ')) { const token = authHeader.substring(7, authHeader.length) let userIdFromToken try { userIdFromToken = (await verify(token)).id } catch (error) { if (['TokenExpiredError', 'JsonWebTokenError', 'NotBeforeError'].includes(error.name)) { return res.status(401).send() } else { throw error } } const user = await prisma.user.findUnique({ where: { id: userIdFromToken } }) if (!user) { return res.status(401).send() } const { password, ...userView } = user req.user = userView } else { return res.status(401).send() } next() }) const SP = new SecurePassword() export const hashPassword = async (password) => { const hashedPwdBuffer = await SP.hash(Buffer.from(password)) return hashedPwdBuffer.toString("base64") } export const verifyPassword = async (hashedPassword, password) => { try { return await SP.verify(Buffer.from(password), Buffer.from(hashedPassword, "base64")) } catch (error) { console.error(error) return false } } ``` 這只是後端程式碼的一部分(僅適用於用戶名和密碼方法)!正如您所看到的,我們在這裡有很大的靈活性,可以執行/指定以下操作: - 選擇身份驗證的實作方法(例如會話或基於 JWT) - 選擇我們想要用於令牌(如果使用 JWT)和密碼管理的確切 npm 套件 - 解析 auth 標頭並指定每個值(授權、承載等)如何回應 - 為每個可能的結果選擇回傳程式碼(例如 401、403) - 選擇密碼的解碼/編碼方式 (base64) 一方面,在我們的程式碼中擁有這種程度的控制和靈活性確實很酷,但另一方面,需要做出很多決定(==錯誤),特別是對於像身份驗證這樣常見的事情! 如果後來有人問“_那麼你到底為什麼選擇secure-password npm 包,或者為什麼到底是base64 編碼?_”,我們可能應該用其他東西來回答,而不是“_好吧,2012 年有一篇看起來相當合法的帖子,它有近 50 票贊成。嗯,不過現在找不到了。另外,它的名字裡有‘安全’,聽起來不錯,對吧?_” 另一件要記住的事情是,我們還應該追蹤事情如何隨著時間的推移而變化,並確保幾年後,我們仍然使用最佳實踐,並且軟體包定期更新。 如果我們嘗試應用上面的原則(更少的程式碼,更少的詳細說明,說明我們想要什麼**而不是需要做什麼**),身份驗證的程式碼可能如下所示: ``` auth: { userEntity: User, externalAuthEntity: SocialLogin, methods: { usernameAndPassword: {}, google: {} }, onAuthFailedRedirectTo: "/login", onAuthSucceededRedirectTo: "/dashboard" } ``` 基於此,計算機/編譯器可以處理上面提到的所有內容,然後根據抽象級別,提供某種接口(例如表單元件或函數)來“掛鉤”我們自己的接口,例如React/Node.js 程式碼(順便說一句,這就是它實際上[在 Wasp 中工作](https://wasp-lang.dev/docs/auth/overview) 的方式)。 我們不需要關心底層使用了什麼確切的套件或加密方法 - 這是我們信任抽象層的作者和維護者的責任,就像我們相信 Python 最了解如何將兩個數字相加一樣裝配水平,並與該領域的最新進展保持同步。當我們依賴內建資料結構或依靠垃圾收集器來很好地管理程式記憶體時,也會發生同樣的情況。 ## 但是我產生的漂亮程式碼😿💻!那麼會發生什麼事呢? 別擔心,一切都還在這裡,您可以產生您想要的所有程式碼!這裡要理解的要點是,人工智慧程式碼生成和框架/語言開發是相互補充而不是替代,並且將繼續存在,這最終對開發人員社群來說是一個巨大的勝利——它們將繼續讓我們的生活更輕鬆,讓我們能夠做更多有趣的事情(而不是第 n 次實作 auth 或 CRUD API)! 我將這裡的演變視為一個循環(或實際上是螺旋式上升,但這超出了我的繪圖能力): 1. **語言/框架:存在**,是主流,很多人使用它 2. **模式開始出現**(例如實作身份驗證,或進行 API 呼叫)→ AI 學習它們,透過自動完成提供 3. **其中一些模式成熟**並變得穩定→抽象的候選者 4. **新的、更抽象的語言/框架**出現 5. **返回步驟 1。** ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9na8wwmaqfabhx1dkuaf.png) ## 結論 這意味著我們雙贏——當語言成為主流時,我們可以從人工智慧驅動的程式碼產生中受益,幫助我們更快地編寫程式碼。另一方面,當我們不想重複/處理的程式碼模式出現並變得穩定時,我們就得到了一種全新的語言或框架,它允許我們編寫更少的程式碼並關心更少的實作細節! ![嘶嘶聲停止](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fistx8x0w8ee62nr1kl5.gif) 感謝您的閱讀,並希望您發現這篇文章內容豐富!我很想聽聽您是否同意(或不同意)這一點,以及您如何看待人工智慧工具驅動的程式設計的未來。 --- 原文出處:https://dev.to/wasp/ai-code-generation-vs-coding-by-hand-what-programming-is-going-to-look-like-in-202x-1idh

Pipeline 🛠️Repos 對決⚔️:Python 🐍 版

## **簡介** 在不斷發展的資料工程和自動化領域,Python 已經出現了多種工作流程編排器。在本文中,我將介紹 6 個 Python 函式庫及其一些主要功能。 ![介紹 GIF](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d09jxm34esmawmnv93lt.gif) --- ## 1. [Taipy](https://github.com/Avaiga/taipy) Taipy 是一個開源 Python 庫,用於建立生產就緒的應用程式前端和後端。 對於 Python 開發人員來說,Taipy 是建立管道最簡單的框架之一,這要歸功於它的管道圖形編輯器 (Taipy Studio)。 然後,您可以透過 Python 腳本輕鬆執行和編排管道。一個非常酷的核心功能是每個管道執行都是註冊的。 這可以輕鬆實現假設分析、KPI 監控、資料沿襲等。 🔑特點: - 圖形管道編輯器 - 與 Taipy 前端功能整合以實現端到端部署 - 日程安排 - 管道的版本控制 - 快取等智慧功能 ![太比圖解](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/28kg5av8pk2sdrvi3bl8.png) --- ![QueenB](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ovcc5kqd8xr9uihrggbb.gif) 您的支持意義重大🌱,並且在許多方面為我們帶來了很大的幫助,例如寫文章! 🙏 --- ## 2. [Kedro](https://github.com/kedro-org/kedro) Kedro 是一個開源 Python 框架。 它為生產就緒的資料科學管道提供了一個工具箱。 事實上,Kedro 可以輕鬆地與成熟的 Python ML 庫集成,並提供統一的方法來實現端到端框架。 🔑特點: - 資料目錄 - 筆記本集成 - 專案模板 - 有自己的觀點,因為它強制執行特定的約定 ![Kedro 圖](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w5zfgz36ogrixa1mfqre.png) --- ## 3. [Airflow](https://github.com/apache/airflow) 十多年來,Airflow 一直是管道領域的知名參與者。 Airbnb 建立了 Airflow 來解決資料處理和工作流程需求的內部挑戰。 眾所周知,這個強大的開源平台具有陡峭的學習曲線,但具有廣泛的功能。 該平台允許您透過建立 DAG(有向無環圖)來建立和管理工作流程。 🔑特點: - 基於DAG的定義 - 豐富的基於 Web 的監控 UI:DAG、故障、重試的可視化… - 各種集成 - 動態任務執行和調度 - 由於其以 Python 為中心的特性而具有靈活性。 - 強大的社區 ![氣流圖](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i7a5qgpcnawim32gudhd.png) --- ## 4. [Prefect](https://github.com/PrefectHQ/prefect) Prefect 是一個資料管道開發框架。 Prefect 在策略上將自己定位在與 Airflow 的直接競爭中,以基於簡單性、用戶友好性和靈活性的獨特身份脫穎而出。 如果您想要一個具有各種功能但比 Airflow 更容易學習的成熟產品,Prefect 是一個很好的中間產品。 🔑特點: - 控制面板 - 快取 - 基於流程的結構 - 動態參數化與依賴管理 - 混合執行(本地/雲端) ![完美插畫](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ejmhma39rkmpjg1lwu6z.png) --- ## 5. [Dagster](https://github.com/dagster-io/dagster) Dagster 是本次編譯中較新的函式庫之一,它是一個雲端原生資料管道編排,旨在統一資料整合、工作流程編排和監控。 與其他工具相比,Dagster 強調工作流程建立和管理的 DataOps 面向。 🔑特點: - 聲明式管道設置 - 固執己見的結構 - 版本控制 - 與 Hadoop 集成 - 全面的元資料跟踪 ![Dagster 圖](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/soebsxs4wfwxayzql8wr.png) --- ## 6. [Luigi](https://github.com/spotify/luigi) Luigi 提供了一個資料處理管道框架。 Spotify 與 Airflow 大約在同一時間開發了這個程式庫,以解決其複雜的資料工作流程和管道。 Luigi 專為管理批次作業的複雜通道而設計。如果您正在尋找簡單的東西並且必須快速上手,Luigi 是一個不錯的選擇。 🔑特點: - 內建 Hadoop 支援 - 基於任務的工作流程定義 - 用於依賴管理的中央調度程序 - 任務依賴關係視覺化 ![Luigi 插圖](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bxx0ty0vsldbk8unyhqv.png) --- ##結論 隨著 Python 工作流程編排環境的不斷發展,這些工具展示了主要的共同特徵和特定的差異化因素。 所有這些工具都有不同程度的複雜性,了解您的專案和團隊的需求至關重要。 我建議使用非常簡單的範例來測試一些選項,以獲得對每個框架可用性的第一手了解。 --- 希望您喜歡這篇文章! 我是一名新手作家,歡迎任何改進建議! ![新秀圖片](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/25oebh36ha622u74kpli.gif) 如果您有任何疑問,請隨時與我們聯繫。 --- 原文出處:https://dev.to/taipy/the-pipeline-repos-showdown-python-edition-39i5

程式設計師的 100 個願望清單想法

科技愛好者常有遠大的夢想,渴望實現突破創新和個人發展界限的目標。為了幫助建立這些雄心壯志,我為科技愛好者量身定制了廣泛的願望清單。此清單不僅概述了各種目標,還包括「靈感」、「如何」、「年份」、「狀態」和「紀念品」等附加欄,為您的技術之旅提供全面的路線圖。 ## 清單中有什麼? 該清單涵蓋了廣泛的目標,從培養特定技能(例如達到 150 WPM 的打字速度)到雄心勃勃的專案(例如製作 DIY 電動滑板或自行車)。它包括參加重大活動,例如參加大型技術會議,以及個人發展的里程碑,例如指導初級開發人員。每個目標都經過分類以便於參考,涵蓋 DIY 專案、程式設計、開發、學習等領域。 ## 列表 [我的遺願清單進度](https://syki.dev/bucket-list) |目標|類別|靈感|年份|狀態|紀念品| |---------------------------|----------------|----------------| ----|------|--------| |成為大型專案的貢獻者 |開發 |[如何像專業人士一樣開源](https://www.youtube.com/watch?v=MT6M_sqAuZo) | | | | |建立新聞聚合器 |開發 |[Feedly](https://feedly.com/) | | | | |建立實體引擎 |開發 |[我正在從頭開始編寫整個實體引擎](https://www.youtube.com/watch?v=iSMbRGTBOHU) | | | | |建立推薦系統 |開發 |[推薦系統如何運作 (Netflix/Amazon)](https://www.youtube.com/watch?v=n3RKsY2H-NE) | | | | |建構情緒分析工具 |開發 |【2023 如何掌握人工智慧驅動的情緒分析?】(https://brand24.com/blog/sentiment-analysis/) | | | | |建立擴增實境 (AR) 應用程式 |開發 |[關於如何在 2023 年建立擴增實境應用程式的指南](https://www.tekrevol.com/blogs/how-to-build-an-augmented-reality -應用程式/) | | | | |建置與部署聊天伺服器 |開發 |[IRC](https://en.wikipedia.org/wiki/Internet_Relay_Chat) | | | | |建立網路安全工具|開發|[Kali Tools](https://www.kali.org/tools/) | | | | |建立多人線上遊戲|開發|[Dani](https://www.youtube.com/watch?v=_ze26M_Fm6g) | | | | |建立 PWA(漸進式 Web 應用程式)|開發 |[PWA](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps) | | | | |建立 AI 影響者 |開發 |[AI 影響者變得非常富有...讓我們建立一個](https://www.youtube.com/watch?v=ky5ZB-mqZKM&t=11s) | | | | |開發區塊鏈應用程式 |開發 |[使用以太坊智能合約和 Solidity 建置您的第一個區塊鏈應用程式](https://www.youtube.com/watch?v=coQ5dg8wM2o) | | | | |開發一種加密貨幣 |開發 |[您需要立即建立一種加密貨幣!!](https://www.youtube.com/watch?v=befUVytFC80) | | | | |開發VR 應用程式|開發|[教學 - 在Meta Quest 耳機上建立您的第一個VR 應用程式](https://developer.oculus.com/documentation/unity/unity-tutorial-hello-vr/) | | | | |開發一個電子商務網站 |開發 |[Next.js Commerce](https://nextjs.org/commerce) | | | | |開發開源遊戲引擎 |開發 |[C++ 中的 GameDev](https://www.youtube.com/watch?v=LyJkcv_rL9Y&list=PLpM-Dvs8t0Va6RoHkaLuPbRh7Fwpy4nbV) | | | | |開發瀏覽器擴充 |開發 |[Chrome 擴充應該會嚇到你。](https://www.youtube.com/watch?v=xIKwkPWUgOA) | | | | |在 github 上有一個擁有 100 顆星的專案 |開發 |[Linus Torvalds](https://github.com/torvalds?achievement=starstruck&tab=achievements) | | | | |擁有自己的 Tor 頁面 |開發 |[我在 Raspberry Pi 上放置了一個 DARK WEB 網站!!](https://www.youtube.com/watch?v=bllS9tkCkaM) | | | | |發明手勢控制介面 |開發 |[鋼鐵人](https://www.youtube.com/watch?v=P5k-4-OEuTk) | | | | |建立持續整合/持續部署管道|開發|[自動化您的工作流程](https://github.com/features/actions)從想法到生產]| | | | |設定 Kubernetes 叢集 |開發 |[為什麼要建置 Raspberry Pi 叢集?](https://www.youtube.com/watch?v=8zXG4ySy1m8) | | | | |贊助開源專案 |開發 |[投資為您的世界提供動力的軟體](https://github.com/sponsors) | | | | |使用查詢機制編寫自己的資料庫|開發|[製作我們自己的資料庫](https://acmiitr.medium.com/making-our-own-database-part-1-6cd9c49ed924) | | | | |在靜態網站產生器中撰寫頁面 |開發 |[Gatsby](https://www.gatsbyjs.com/) | | | | |編寫單頁應用程式 |開發 |[React](https://react.dev/) | | | | |使用 Raspberry Pi 專案實現家居自動化 |DIY |[我建立了一個更聰明的智慧家庭](https://www.youtube.com/watch?v=0rIvB3LZiKA) | | | | |建立自訂鍵盤 |DIY |[建立自己的機械鍵盤......正確的方式](https://www.youtube.com/watch?v=bBon6WwkdJE) | | | | |DIY電動滑板或自行車 |DIY |[我做了一個電動滑板!](https://www.youtube.com/watch?v=3bcvFzecg2Q) | | | | |以自訂遊戲建立迷你街機 |DIY |[終極 DIY 街機指南](https://www.youtube.com/watch?v=oTydZBIGAuk) | | | | |組裝一台 PC |DIY |[為 Minecraft 組裝一台價值 100,000 美元的 PC](https://www.youtube.com/watch?v=AHR80l7od2Q) | | | | |建立個人雲端儲存系統 |DIY |【這是我的終局之戰 - Mother Vault 伺服器機房更新】(https://www.youtube.com/watch?v=pLC0FUnko-M) | | | | |利用 IoT 建造自動澆水花園系統 |DIY |[Arduino 花園控制器 - 自動澆水和資料記錄](https://www.youtube.com/watch?v=O_Q1WKCtWiA) | | | | |打造小型自動駕駛汽車或機器人 |DIY |[快速巡線機器人](https://www.youtube.com/watch?v=lnP32gzHdvI) | | | | |建造水下ROV |DIY |[建造一艘DIY潛水艇](建造一艘DIY潛水艇) | | | | |搭建並飛行 FPV 無人機 |DIY |[為什麼要以 800mW 功率自由式飛行? | [FPV](https://www.youtube.com/watch?v=bBb_kSO3vTo) | | | | |設計具有互動功能的智慧鏡子|DIY |[DIY智慧鏡子 - 完整教學](https://www.youtube.com/watch?v=OYlloiaBINo) | | | | | 以 3D 方式設計和列印一些東西 |DIY |[我在房間中央製作了一個機器人手臂!](https://www.youtube.com/watch?v=nRsaf16EdNM) | | | | |設計您自己的 PCB |DIY |[PCB 建立初學者 - 10 分鐘內開始完成教程](https://www.youtube.com/watch?v=MsdJgEinb34) | | | | |修復損壞的電子產品 |DIY |[ElectroBOOM](https://www.youtube.com/@ElectroBOOM) | | | | |在本地擁有自己的伺服器 |DIY |[為什麼要建立 Raspberry Pi 叢集?](https://www.youtube.com/watch?v=8zXG4ySy1m8) | | | | |實現智慧家庭|DIY |[我建造了一個更聰明的智慧家庭](https://www.youtube.com/watch?v=0rIvB3LZiKA) | | | | |製作機械手臂 |DIY |[我在房間中央製作了機械手臂!](https://www.youtube.com/watch?v=nRsaf16EdNM) | | | | | 用 Flipper Zero 開啟一些東西 |DIY |[這讓駭客攻擊太容易了 - Flipper Zero](https://www.youtube.com/watch?v=nLIp4wd0oXs) | | | | |成為智慧型手機應用程式的擁有者|創業|[VoidLog](https://www.youtube.com/watch?v=LY4rxYe-jKI&list=PLN3n1USn4xllDDLwgJ4avEqgj4dWynofp) | | | | |開發 SaaS 產品 |創業精神|[我如何在一天內建立一個新的 SaaS 產品](https://www.youtube.com/watch?v=v_3lcqUOaOA) | | | | |在店裡擁有自己的遊戲 |創業|[Dani](https://www.youtube.com/watch?v=_ze26M_Fm6g) | | | | |在新創公司工作 |創業精神|[新創工程師在家工作的一天](https://www.youtube.com/watch?v=TLysAkFM4cA) | | | | |一週多相睡眠|創業|| | | | |參加播客 |創業|[Lex Fridman](https://www.youtube.com/lexfridman) | | | | |完全存取伺服器 - 黑客 |黑客 |[先生。機器人](https://www.youtube.com/watch?v=QqknSms8VVI&t=16s) | | | | |獲得錯誤賞金 |駭客 |[HackerOne](https://www.hackerone.com/) | | | | |在奪旗大賽中進行駭客攻擊 |駭客攻擊 |[Mr.機器人](https://www.youtube.com/watch?v=6MrQ-mN8HM8) | | | | |編寫惡意軟體 |駭客 |[惡意軟體開發:進程、執行緒與句柄](https://www.youtube.com/watch?v=aNEqC-U5tHM) | | | | |150 wpm 速度打字 |程式設計 |[Monkeytype](https://github.com/monkeytypegame/monkeytype) | | | | |使用 Python 腳本自動化您的日常任務 |程式設計 |[開始使用 Python 自動化您的生活! (Python檔案管理教學)](https://www.youtube.com/watch?v=NCvI-K0Gp90) | | | | |建立 Twitter 機器人 |程式設計 |[如何使用人工智慧發布熱門推文 // Twitter 機器人教學](https://www.youtube.com/watch?v=V7LEihbOv3Y) | | | | |編譯您自己的 Linux 核心 |程式設計 |[如何編譯自訂 Linux 核心](https://www.youtube.com/watch?v=APQY0wUbBow) | | | | |建立聊天機器人 |程式設計 |[使用深度學習、Python 和 TensorFlow 建立聊天機器人 p.1](https://www.youtube.com/watch?v=dvOnYLDg8_Y&list=PLQVvvaa0QuDdc2k5dwtDTyT9aCja0on8j) | | | | |使用 D3.js 建立資料視覺化專案 |程式設計 |[使用 D3.js 進行資料視覺化 - 完整教學課程](https://www.youtube.com/watch?v=_8V5o2UHG0E) | | | | |建立照片編輯工具 |程式設計 |[如何製作照片編輯應用程式的完整指南](https://www.cleveroad.com/blog/how-to-build-a-photo-editing-app-like-棱鏡並使其蓬勃發展/) | | | | |開發數位藝術作品產生器 |程式設計 |[如何為初學者產生瘋狂的人工智慧藝術(Midjourney V4)](https://www.youtube.com/watch?v=zf4z8A-OWBY) | | | | |開發檔案加密工具 |程式設計 |[製作您自己的加密程式](https://www.youtube.com/watch?v=TZT7wvTeVyY) | | | | |開發影片編輯軟體|程式設計|[我寫了一個影片編輯器(有點糟糕)](https://www.youtube.com/watch?v=iydG-e1dQGA) | | | | |開發語音助理應用程式 |程式設計 |[建立由 OpenAI 和 Python 驅動的 Jarvis | ChatGPT](https://www.youtube.com/watch?v=BEw5EFqCCEI) | | | | |開發智慧手錶應用程式 |程式設計 |[使用 Android Studio 在 WearOS 上建立並執行穿戴式應用程式](https://www.youtube.com/watch?v=-JO5oHRkybk) | | | | |開發您自己的 Slack/Discord 機器人 |程式設計 |[使用 Python 編寫 Discord 機器人 - 在雲端免費託管](https://www.youtube.com/watch?v=SPTfmiYiuok) | | | | |實現臉部辨識系統 |程式設計 |[從紙張到程式碼建立深度臉部辨識應用程式](https://www.youtube.com/watch?v=bK_k7eebGgc&list=PLgNJO2hghbmhHuhURAGbe6KWpiYZt0AMH) | | | | |學習函數式程式語言 |程式設計 |[函數式程式設計 - 概述](https://www.youtube.com/watch?v=8z_bUIl_uPo) | | | | |學習古老的語言 |程式設計 |[100 秒內的 COBOL](https://www.youtube.com/watch?v=7d7-etf-wNI) | | | | |學習並使用 Docker 進行容器化 |程式設計 |[Docker](https://www.docker.com/) | | | | |學習極快的語言 |程式設計 |[ThePrimeagen](https://www.youtube.com/@ThePrimeagen) | | | | |學習一門不尋常的語言(例如 Brainfuck) |程式設計 |[100 秒內完成 Brainfuck](https://www.youtube.com/watch?v=hdHjjBS4cs8) | | | | |學習量子運算基礎 |程式設計 |[在量子電腦上編碼](https://www.youtube.com/watch?v=q3ecPsMd4tA) | | | | |掌握高階演算法與資料結構(100道LeatCode) |程式設計|【569道 Leetcode 題後的我的大腦】(https://www.youtube.com/watch?v=8wysIxzqgPI) | | | | |對自訂語音控製家庭助理進行程式設計 |程式設計 |[建立由 OpenAI 和 Python 提供支援的 Jarvis | ChatGPT](https://www.youtube.com/watch?v=BEw5EFqCCEI) | | | | |對微控制器進行程式設計 |程式設計 |[微控制器程式設計駭客指南 [教學]](https://www.youtube.com/watch?v=XlFO5Iat178) | | | | |在 Vim 中編程 |程式設計 |[Vim 作為你的編輯器](https://www.youtube.com/watch?v=X6AR2RMB5tE&list=PLm323Lc7iSW_wuxqmKx_xxNtJC_hJbQ7R) | | | | |使用分離式鍵盤|編程|[拆箱新鍵盤!!! (也進行打字測試!)](https://www.youtube.com/watch?v=nh-BAxbithc&t=156s) | | | | |網頁抓取資料 |程式 |[使用 AI 和代理網路進行工業規模的網頁抓取](https://www.youtube.com/watch?v=qo_fUjb02ns) | | | | |用組合語言寫程式 |程式設計 |[Tsoding](https://www.youtube.com/watch?v=WnBXLmKk_qw&t=82s) | | | | |寫一個 NPM 模組 |程式設計 |[NPM](https://www.npmjs.com/) | | | | |編寫伺服器端應用程式 |程式設計 |[Next.js](https://nextjs.org/) | | | | |編寫您自己的人工智慧模型 |程式設計 |[讓我們建立 GPT:從頭開始,用程式碼,拼寫出來。](https://www.youtube.com/watch?v=kCc8FmEb1nY) | | | | |編寫您自己的作業系統 |程式設計 |[Linus Torvalds](https://github.com/torvalds) | | | | |寫你自己的程式語言 |程式設計 |[我製作了自己的程式語言](https://www.youtube.com/watch?v=pgeSGBwtHW8&t=132s) | | | | |擁有私人部落格 |教學 |[Dan Abramov](https://overreacted.io/) | | | | |對學生的講座 |教學 |[馬克·祖克柏的 CS50 講座 - 2005 年 12 月 7 日](https://www.youtube.com/watch?v=xFFs9UgOAlE&t=807s) | | | | |指導初級開發人員 |教學 |[如何正確指導初級開發人員](https://stablekernel.com/article/how-to-properly-mentor-a-junior-developer/) | | | | |寫一篇關於科技主題的論文並發表 |教學 |[兩分鐘論文](https://www.youtube.com/@TwoMinutePapers) | | | | |編寫技術書籍或電子書 |教學 |[編寫技術書籍](https://paulcunningham.me/writing-technical-books/) | | | | |參加大型科技會議 |旅遊 |[CES](https://www.ces.tech/) | | | | |參加黑客松 |旅行 |[我挑戰自己贏得黑客馬拉松](https://www.youtube.com/watch?v=mAJlZUKhOGs) | | | | |參觀電腦歷史博物館 |旅行 |[工程師的旅行願望清單](https://www.mwrf.com/community/article/21848496/the-engineers-travel-bucket-list) | | | | |參觀 NASA 約翰遜航天中心 |旅行 |[工程師的旅行願望清單](https://www.mwrf.com/community/article/21848496/the-engineers-travel-bucket-list) | | | | |參觀國家航空暨太空博物館 |旅行 |[工程師的旅行願望清單](https://www.mwrf.com/community/article/21848496/the-engineers-travel-bucket-list) | | | | |參觀歷史科學儀器收藏 |旅行 |[工程師的旅行願望清單](https://www.mwrf.com/community/article/21848496/the-engineers-travel-bucket-list) | | | | |參觀大型強子對撞機 |旅行 |[工程師的旅行願望清單](https://www.mwrf.com/community/article/21848496/the-engineers-travel-bucket-list) | | | | |參觀麻省理工學院博物館 |旅行 |[工程師的旅行願望清單](https://www.mwrf.com/community/article/21848496/the-engineers-travel-bucket-list) | | | | |參觀國家核科學與歷史博物館 |旅行 |[工程師的旅行願望清單](https://www.mwrf.com/community/article/21848496/the-engineers-travel-bucket-list) | | | | ### 下載列表 [下載 CSV](https://syki.dev/uploads/bucket-list.csv) [下載 JSON](https://syki.dev/uploads/bucket-list.json) ## 附加列解釋 ### 靈感 本專欄反映了是什麼激發了追求特定目標的想法或願望。它可以是一個人、一個事件、一本書,甚至一部電影,點燃了人們對特定成就的熱情。例如,DIY 電動滑板的靈感可能是對永續交通的熱情或最喜歡的科技影片部落客的專案。 ### 年 本專欄提出了實現該目標的時間表或目標年份。它有助於規劃和設定現實的時間表。例如,您可能計劃在 2025 年之前參加一次大型技術會議。 ### 地位 狀態追蹤您的進度。它可以是“未開始”“進行中”“已完成”或“暫停”這有助於追蹤您的旅程並保持動力。 ### 紀念品 本專欄是一個獨特的補充,旨在紀念這一成就。它可以是實體、數位徽章、部落格文章,甚至是照片。例如,組裝 PC 的紀念品可能是已完成設定的第一張照片。 ## 結論 技術愛好者的願望清單不僅僅是目標的集合;這是技術領域個人和職業成長的路線圖。透過附加專欄提供靈感、方法、計時、追蹤和紀念成就的框架,此列表對於任何熱衷於技術的人來說都是一個動態工具。 快樂的科技冒險! --- 原文出處:https://dev.to/syki/100-bucket-list-ideas-for-programmers-506m

每次開發正確的東西並成為 10 倍工程師🏆:編寫 RFC 的藝術🥋

想像一下,您的任務是在您正在開發的產品中實現一項重要的新功能。這就是您一直在等待的機會 - 每個人都會看到您是多麼出色的 10 倍開發人員!你打開一個你想要嘗試的最酷的新庫和設計模式的列表,然後直接進入它,完整的“地下室”模式。一週後,你勝利地出現並提出了你完美的拉取請求! **但是,團隊中的高級開發人員立即拒絕了** - ***「太複雜了,你應該簡單地使用庫 X 並重用 Y。」***。什麼!?顯然,他們不明白你的解決方案有多天才,很快,你就會看到關於你的 PR 的 100 條評論以及接下來幾天的重構。 如果有一種方法可以在實施一切之前了解 X 和 Y 就好了。是的,它就是 RFC! ![RFC發明漫畫](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z50pl0vodfeisluten8n.png) 我們將透過[關於在 Wasp 中實現身份驗證的 RFC](https://www.notion.so/RFC-Auth-without-user-define-entities-6d2925439627456ab01b74ff4b4cd087?pvs=21) 的範例來了解它。 **[Wasp](https://kdta.io/github-wasp-lang-wasp_4) 是一個建置在 React、Node.js 和 Prisma 之上的全棧框架,提供了大量開箱即用的功能這是建置和部署應用程式的最快方法**。它還附帶一個免費的 GPT 支援的程式碼庫產生器 [MAGE](https://usemage.ai/),已用於建立超過 30,000 個應用程式。 讓我們深入了解一下! ## 支持我們! 🙏⭐️ ![GH 星星點擊](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/id9s6t8rcvfxty40bv2m.gif) 如果您覺得這篇文章有幫助,請[考慮在 Github 上給我們一顆星](https://github.com/wasp-lang/wasp)!我們在 Wasp 所做的一切都是開源的,您的支援幫助我們使 Web 開發變得更容易,並激勵我們撰寫更多這樣的文章。 ![支持我們](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qgbmn45pia04bxt6zf83.gif) ## 那麼,什麼是 RFC? ![RFC 概述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gno8rt4o3ffxhcj72nmk.png) RFC 代表 *Request For Comments*,簡單地表示 **「**提議更改程式碼庫以解決特定問題的文件。」。 **其主要目的是在實施開始之前找到解決問題的最佳方法。** RFC 最初由開源社群採用,但如今,它們幾乎被用於任何類型的開發者組織。 您在業界可能會遇到此類文件的其他名稱,例如 TDD(*技術設計文件*)或 SDD(*軟體設計文件*)。有些人會爭論它們之間的區別,但我們不會。 **有趣的事實**:RFC 是由 IETF(*網路工程任務組*)發明的,該組織是我們今天使用的一些最重要的網路標準和協議背後的工程組織!不算太寒酸吧? ## 什麼時候該寫 RFC,什麼時候可以跳過? ![RFC meme 只需編碼](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d1kvwj97oaduwczudc1b.png) 那麼,為什麼要費勁去寫你最終將要編碼的內容,而不是節省時間並簡單地去做呢? **如果您正在處理錯誤或相對簡單的功能,非常清楚必須做什麼並且不會影響專案結構,那麼就不需要 RFC - 啟動 IDE 並開始破解!** 但是,如果您要引入一個全新的概念(例如,引入基於角色的權限系統)或更改專案的架構(例如,新增對執行後台作業的支援),那麼您可能需要在輸入「git」之前退一步checkout -b my-new-feature` 並深入到那個甜蜜的編碼區域。 綜上所述,有時很難確定是否應該編寫該 RFC。也許這是一個更突出的功能,但你以前做過類似的事情,並且你已經在頭腦中規劃好了一切,而且幾乎沒有任何疑問。為了解決這個問題,我喜歡使用以下一個簡單的啟發式方法:**是否有不只一種明顯的方法來實現此功能?我們是否必須選擇一個新的庫/服務?** 如果這兩個問題的答案都是“否”,那麼您可能不需要 RFC。否則,需要進行討論,而 RFC 是解決問題的方法。做吧。 ![RFC 流程圖 - 何時撰寫](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2a956hqeyai31igbl92q.png) ## 這對我有什麼好處? 我們已經確定瞭如何決定「何時」編寫 RFC,但這也是您應該這樣做的「原因」: - **你將整理你的想法並變得清晰**。如果您決定編寫 RFC,則表示您正在處理一個不平凡的開放式問題。把事情寫下來將有助於提煉你的想法並客觀地看待它們。 - **與剛開始編碼相比,你會學到更多**。你會給自己空間去探索不同的方法,常常會發現一些你原本沒有想到的東西。 - **您將眾包團隊的知識。** 透過向您的團隊尋求回饋(因此請求評論),您將全面了解您正在解決的問題並填補任何剩餘的空白。 - **您將增進團隊對程式碼庫的理解。** 透過在 RFC 上進行協作,團隊中的每個人都會了解您正在做什麼以及最終是如何做到的。這意味著下次有人必須接觸那部分程式碼時,他們將需要問你更少的問題(===更多不間斷的程式碼時間!)。 - **公關審查將會*更*順利**。還記得本文開頭的情況嗎?當你的 PR 因為「太複雜」而被拒絕時?這是因為審閱者忽略了上下文,並且您在沒有獲得團隊其他成員事先支持的情況下進行了相當大的更改。透過先編寫 RFC,您將永遠不會再遇到這種情況。 - **您的文件已經完成了 50%!** 需要明確的是,RFC 不是最終文件,您不能簡單地指出它,但您可以重複使用很多內容 - 圖像、圖表、段落等。 哇,這聽起來太棒了,我現在就想提出一個新功能,這樣我就可以為其編寫 RFC!開個玩笑,首先瀏覽 RFC 會讓編碼部分變得更加有趣 - 你確切地知道你需要做什麼,並且你不需要質疑你的方法以及建立 PR 後將如何接收它。 ## 好吧,好吧,我被賣了!那麼,我該如何寫一篇呢? 很高興你問了!使用了許多不同的格式,或多或少是正式的,但我更喜歡保持簡單。我們在 Wasp 編寫的 RFC 不遵循嚴格的格式,但有一些共同的部分: - **元資料** - 標題、日期、審稿人等… - **問題/目標** - 你要解決什麼 - **建議的解決方案**(或更多) - **實施概述** - **評論/開放式問題** 這幾乎就是它的要點!其中每一個都可以進一步細分和細化,但這是您可以開始的基本輪廓。 ## 元資料 ⌗ ![RFC 元資料範例](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5e894wa2xsw57or0q8oa.png) 這是非常不言自明的 - 您可能想要追蹤有關 RFC 的一些基本資訊 - 狀態、建立日期等。 一些模板還明確列出了審查者以及他們對RFC 的「批准」狀態- 我們沒有它,因為我們是一個溝通速度很快的小團隊,但對於不是每個人都認識每個人的大型團隊來說,它可以很方便,並且您希望有更多的流程(例如,在指導初級開發人員時)。 ![RFC 明確審閱者範例](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0l4elf6a5xtpa567bfg3.png) ## 問題🤔 這就是事情變得有趣的地方。 **您對問題或需要實現的目標/功能以及為什麼需要這樣做的定義越好,以下所有步驟就會越容易**。因此,即使在開始編寫 RFC 之前,這也是值得投資的事情 - 確保與所有相關方(例如產品所有者、其他開發人員,甚至用戶)進行交談,以加深您對要解決的問題的理解。 透過這樣做,您也很可能獲得有關可能解決方案的初步提示和指示,並對您所處的問題空間有一個粗略的認識。 ![RFC 問題定義](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cx3bm2x24hf2z22sl88n.png) 以下是上面範例中的一些提示: - **從高級摘要開始** - 這樣,讀者可以快速決定這是否與他們相關以及是否應該繼續閱讀。 - **提供一些背景** - 解釋一下世界的現狀。這可以是單一句子或整個章節,這取決於目標受眾。 - **清楚地陳述問題/目標** - 解釋為什麼會出現問題並將其與用戶/公司的痛苦聯繫起來,以便動機明確。 - **如果可能的話,提供額外的細節** - 圖表、程式碼範例… → 任何可以幫助讀者更快到達「頓悟」時刻的內容。使用可折疊部分的額外要點是,RFC 的中心部分保持可消化的長度。 如果您完成了所有這些,那麼您已經踏上了通往優秀 RFC 的道路!由於明確定義問題至關重要,所以不要害怕加入更多問題並進一步分解問題。 ### 非目標🛑 這是“問題”的子部分,有時非常有價值。在此程式碼庫變更中編寫我們不想要或不會做的事情可以幫助設定期望並更好地定義其範圍。 例如,如果我們正在努力為我們的應用程式加入基於角色的身份驗證系統,人們可能會認為我們還將為其建立某種管理面板來管理使用者和新增/刪除角色。透過明確聲明不會完成(並簡要解釋原因 - 不需要,這會花費太長時間,...),審查者將更好地理解您的目標是什麼,並且您將跳過不必要的討論。 ## 解決方案與實作🛠️ 一旦我們知道我們想做什麼,我們就必須找出最好的方法!您可能已經在“問題”部分暗示了可能的解決方案,但現在是更深入研究的時候了 - 研究不同的方法,評估它們的優缺點,並概述它們如何適合現有系統。 這一部分可能是最自由的形式 - 因為它很大程度上取決於您正在做的事情的性質,所以在這裡施加許多限制是沒有意義的。您可能希望停留在更高的水平,例如係統架構,或者您可能需要深入研究程式碼並開始編寫您需要的部分程式碼。因此,我沒有一個確切的格式供您遵循,而是一組指南: ### 寫偽程式碼 RFC 的目的是傳達想法和原則,而不是編譯和涵蓋所有邊緣情況的生產級程式碼。隨意發明/想像/草繪任何您需要的東西(例如,想像您已經有一個發送電子郵件的功能並使用它,即使您沒有),並且不要用實現細節來妨礙您自己或讀者(除非這正是RFC 的內容)。 最好從較高的級別開始,然後當您意識到需要它或其中一位審閱者建議時再深入。 ### 了解其他人是如何做到的 ![尋找現有解決方案](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ab8elwlb8o2ap85wi72r.png) 根據您正在開發的產品類型,您發現這一點的方式可能會有所不同,但幾乎總是有一種方法可以做到這一點。如果您正在開發像 [Wasp](https://github.com/wasp-lang/wasp) 這樣的開源工具,您可以簡單地查看其他流行的解決方案(也是開源的)並了解它們是如何做到的它。如果您正在開發 SaaS,並且需要弄清楚是否使用 cookie 還是 JWT 進行身份驗證,您可能有一些朋友以前這樣做過,您可以詢問他們。最後,只需 Google/GPT 即可。 為什麼這麼有幫助? **原因是它讓您(和審閱者)對您的解決方案充滿信心。如果其他人以這種方式成功做到了,這可能是一個有前途的方向。**它還可能幫助您發現以前沒有想到的方法,或者作為您可以建置的基礎。當然,永遠不要認為任何事情都是理所當然的,並考慮到您情況的具體需要,而一定要利用他人的知識和專業知識。 ### 留下未完成的事情並保持骯髒 RFC 的要點是「C」部分,因此協作(是的,我知道它實際上代表「_comments_」)。這不是一個你必須獲得滿分並且不問任何問題的測試 - 如果發生這種情況,你可能一開始就不應該編寫 RFC。 解決問題需要團隊的努力,而你只是第一個嘗試解決問題並推動事情向前發展的人。您的任務是盡可能合理地奠定基礎(完善問題,探索解決問題的多種方法,辨識發現的新子問題),以便審閱者可以快速掌握狀態並提供有效的反饋,指導需要的地方最多。 **RFC 的主要工作是確定最重要的問題並將審閱者的注意力引導到這些問題上,而不是解決它們。** 您正在編寫的 RFC 應該被視為一個討論區和一個正在進行的工作,而不是一件在展示在觀眾面前之前必須完善的藝術品。 ## 評論和開放式問題 🎯 在文件的最後一部分中,您可以總結主要思想並突出顯示最大的未決問題。在瀏覽所有內容之後,提醒讀者他的注意力在哪裡最有價值可能會有所幫助。 ## 現在我知道何時以及如何寫 RFC!您有任何我可以用作起點的模板嗎? 當然!如前所述,我們的格式非常輕量級,但請隨意查看[我們用作示例的 RFC](https://wasp-lang.notion.site/RFC-Auth-without-user-define-entities-6d2925439627456ab01b74ff4b4cd087?pvs=4) 獲得靈感。您的公司也可能已經有他們推薦的現成範本。 以下是您可以使用和/或適應您的需求的一些內容: - [Squarespace RFC 範本](https://engineering.squarespace.com/s/Squarespace-RFC-Template.pdf) - _您有推薦的範本嗎?我很高興將其列在這裡!_ ## 我應該使用什麼工具來寫 RFC?有這麼多選擇! 您使用的確切工具可能是 RFC 中最不重要的部分,但它仍然很重要,因為它圍繞它設置了工作流程。如果您的公司已經選擇了一種工具,那麼當然要堅持使用。如果沒有,以下是我遇到的最常見的選擇,以及快速評論: - **Google 文件** - 經典選擇。超級容易對文件的任何部分進行評論,這是最重要的功能。 - **概念** - 也非常適合協作,此外還提供一些 Markdown 元件,例如可折疊和表格,這可以使您的 RFC 更具可讀性。 - **Github 問題/PR** - 有時會使用它,特別是對於 OSS 專案。缺點是很難對文件的特定部分進行註釋(只能對整行進行註釋),而且插入圖表也相當笨拙。優點是所有內容(程式碼和 RFC)都保留在同一個平台上 我們目前使用 Notion,但以上任何一個都可以是不錯的選擇。 ## 概括 ![這是包裝](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yq0qybvnkxbu9awz35bw.gif) 正如在 RFC 末尾編寫摘要是最佳實踐一樣,我們也會在這裡做同樣的事情!這篇文章比我預期的要長,但是有很多東西要提到 - 我希望你會發現它有用! 最後,**能夠清楚地表達你的想法,提出問題,並根據團隊的反饋客觀地分析可能的解決方案,這將幫助你開發正確的東西,這是最終的生產力黑客**。 這就是您成為真正的 10 倍工程師的方法。感謝您的閱讀,下次再見! --- 原文出處:https://dev.to/wasp/develop-the-right-thing-every-time-and-become-a-10x-engineer-the-art-of-writing-rfcs-2mc6

每個開發者都應該收藏的 19 個 GitHub 儲存庫 📚👍

在當今動態的軟體開發世界中,保持最新的工具、程式庫和框架對於開發人員來說至關重要。 GitHub 提供了寶貴的儲存庫寶庫,可顯著提高您的開發技能和專業知識。 我整理了每個開發人員都應該了解的 19 個 GitHub 儲存庫的列表,為學習、實踐和靈感提供了豐富的資源。 每個儲存庫都分為子類別,以便於導航。我還加入了直接連結和描述,以便立即獲得印象。 --- ## 1\. [集算器SPL](https://github.com/SPLWare/esProc)(贊助) 集算器SPL是新一代資料處理語言,整合SQL資料庫,支援進階分析與平行處理。 透過集算器SPL,您可以輕鬆轉換和分析大量資料集,發現隱藏的模式和趨勢,並從資料中獲得可操作的見解。一些主要功能包括: **⚡ 頂級效能:** 透過集算器SPL的最佳化演算法和高效率的記憶體管理體驗快速的處理速度。 **🚀 豐富的函數庫:** 存取全面的預先建構函數集合,滿足各種資料操作任務。 **✨ 直覺的語法:** 享受清晰簡潔的語法,提升程式碼的可讀性和可維護性。 **👨‍💻 Java整合:** 透過JDBC將集算器SPL腳本無縫整合到Java程式中,縮小資料分析和應用開發之間的差距。 **🧙‍♀️獨立執行:**獨立執行集算器SPL腳本,超越傳統限制,擴展您的資料處理能力。 ![esProc SPL](https://cdn.hashnode.com/res/hashnode/image/upload/v1679824673641/82f843e0-72a1-44a4-bd99-68616f322534.png?w=1600p=84cro格式&格式=webp&自動=壓縮,格式&格式=webp) ⭐ 支援他們的 GitHub 倉庫:[https://github.com/SPLWare/esProc](https://github.com/SPLWare/esProc) --- ## 🌱 學習編碼 ### 2\. [awesome-roadmaps](https://github.com/liuchong/awesome-roadmaps) >***⭐*** *GitHub 星數 3k+* 各種程式語言、框架和工具的路線圖集合。 ### 3\. [awesome-courses](https://github.com/prakhar1989/awesome-courses) >***⭐*** *GitHub 星數超過 50k* 用於學習程式設計、網路開發和其他技術技能的精選線上課程清單。 ### 4\. [free-certifications](https://github.com/cloudcommunity/Free-Certifications) >***⭐*** *GitHub 星數 12k+* 各種技術主題的認證和培訓課程的綜合清單。 ### 5\. [awesome-algorithms](https://github.com/tayllan/awesome-algorithms) >***⭐*** *GitHub 星數超過 15k* 用於學習和練習演算法和資料結構的資源集合。 ### 6\. [awesome-interview-questions](https://github.com/DopplerHQ/awesome-interview-questions) >***⭐*** *GitHub 星數 59k+* 軟體開發角色的常見面試問題彙編。 --- ## 🧑‍💻 建設專案 ### 7\. [awesome-for-beginners](https://github.com/MunGell/awesome-for-beginners) >***⭐*** *GitHub 星數 58k+* 適合初學者的專案想法和資源清單。 ### 8\. [應用程式想法](https://github.com/florinpop17/app-ideas) >***⭐*** *GitHub 星數 69k+* 適用於各種程式設計平台和技能水平的大量應用程式創意。 ### 9\. [邊玩邊學](https://github.com/lmammino/awesome-learn-by-playing) >***⭐*** *GitHub 星數 115+* 一系列遊戲和互動專案,可提高編碼技能。 ### 10\. [專案為基礎的學習](https://github.com/practical-tutorials/project-based-learning) >***⭐*** *GitHub 星數 123k+* 針對各個技術領域的基於專案的學習資源清單。 ### 11\. [build-your-own-x](https://github.com/codecrafters-io/build-your-own-x) >***⭐*** *GitHub 星數 229k+* 關於如何建立您自己的程式語言、工具和框架的指南集合。 --- ## 🚀 工具和資源 ### 12\. [免費開發](https://github.com/ripienaar/free-for-dev) >***⭐*** *GitHub 星數 76k+* 為開發人員提供的免費工具和資源的精選清單。 ### 13\. [awesome-selfhosted](https://github.com/awesome-selfhosted/awesome-selfhosted) >***⭐*** *GitHub 星數 157k+* 用於各種目的的自託管軟體應用程式的集合。 ### 14\. [棒設計工具](https://github.com/goabstract/Awesome-Design-Tools) >***⭐*** *GitHub 星數超過 30k* 用於各種設計目的的設計工具的綜合清單。 ### 15\. [awesome-stock-resources](https://github.com/neutraltone/awesome-stock-resources) >***⭐*** *GitHub 星數 11k+* 免費和付費庫存照片、圖標和其他設計資源的集合。 --- ## 💯 模式與最佳實踐 ### 16\. [awesome-sre](https://github.com/dastergon/awesome-sre) >***⭐*** *GitHub 星數超過 10k* 用於學習和實施站點可靠性工程實踐的資源集合。 ### 17\. [棒設計模式](https://github.com/DovAmir/awesome-design-patterns) >***⭐*** *GitHub 星數 33k+* 軟體設計模式及其應用的目錄。 ### 18\. [美麗文件](https://github.com/matheusfelipeog/beautiful-docs) >***⭐*** *GitHub 星數 8k+* 用於建立美觀且有效的文件的資源和最佳實踐的集合。 ### 19\. [很棒的可擴展性](https://github.com/binhnguyennus/awesome-scalability) >***⭐*** *GitHub 星數 49k+* 有關軟體系統可擴展性、效能和優化的精選資源清單。 --- 寫作一直是我的熱情,幫助和激勵人們讓我感到很高興。如果您有任何疑問,請隨時與我們聯繫! 透過訂閱[我的電子報](https://madzadev.substack.com/),確保獲得我發現的最好的資源、工具、生產力技巧和職業發展技巧! --- 原文出處:https://dev.to/madza/19-github-repositories-every-developer-should-bookmark-13bd

如何成為 10 倍速明星開發人員

如今,每個人都想成為我們所謂的「10 倍開發人員」。然而,這個術語經常被誤解和高估。 從本質上講,在我看來,高效或10 倍開發人員是指能夠利用所有可用工具來發揮其優勢的人,讓這些工具處理冗餘和重複性的任務,並使他能夠專注於複雜和創造性的工作。以下是成為 10 倍開發人員的一些提示和技巧: ## 使用腳本自動執行重複任務: 對於尋求優化工作流程的開發人員來說,透過腳本自動執行重複任務是一個遊戲規則改變者。 透過弄清楚哪些任務可以自動化,例如測試和部署,然後讓腳本處理它們,開發人員可以專注於工作中更具挑戰性的部分,並在過程中節省大量時間。 例如,此腳本建立一個新的專案資料夾,由使用者輸入命名,並在檔案總管中開啟它: ``` import os import subprocess def create_project_folder(project_name): # Create a new folder for the project os.makedirs(project_name) # Open the project folder in the file explorer subprocess.run(['explorer', project_name]) # Get the project name from the user project_name = input("Enter the name of your new project: ") # Call the function to create and open the project folder create_project_folder(project_name) ``` ## 鍵盤快速鍵掌握: 掌握程式碼編輯器或 IDE 中的鍵盤快速鍵對於加快編碼工作流程至關重要。 VS 程式碼的一些快捷方式範例: `Ctrl + P`:快速檔案導航,讓您可以按名稱開啟檔案。 `Ctrl + Shift + L`:選取目前單字的所有出現位置。 `Ctrl + /`:切換行註釋 `Ctrl + A`:選擇目前檔案中的所有行 `Ctrl + F`:尋找程式碼中的特定文本 `Ctrl + Shift + P`:開啟各種指令的指令面板。 `Alt + 向上/向下箭頭`:向上或向下移動目前行。 `Shift + 右箭頭 (→)`:選擇遊標右側的字元。 `Shift + 向左箭頭 (←)`:選擇遊標左側的字元。 「Alt + 點擊」:按住 Alt 鍵並點擊程式碼中的不同位置以建立多個遊標,從而允許您同時在這些位置進行編輯或鍵入。 ## 不要過度設計: 避免過度設計解決方案的誘惑。加入不必要的程式碼或架構複雜性是許多工程師和程式設計師遇到的常見陷阱。 然而,保持簡單不僅有利於您目前的工作流程,而且還可以讓其他人在將來更容易理解您的程式碼並就您的程式碼進行協作。 ## 掌握版本控制工作流程: 善於使用版本控制工作流程(例如使用 Git)將極大地提高您的工作效率,並幫助您的團隊在不妨礙彼此的情況下協同工作。 特別是使用 GitKraken 等工具或任何其他 GUI 替代品,提供直覺的介面,簡化分支、合併和追蹤變更等任務,使協作更加順暢。 ![GitKraken 網站圖片](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ggegydp0qnryv7cbszuk.png) 如果出現問題,您可以輕鬆恢復到先前的狀態。這就像有一個安全網,可以確保每個人的工作順利配合,從而使建立軟體的整個過程更快、壓力更小。 ## 利用現有元件和函式庫: 不要重新發明輪子,而是使用經過嘗試和測試的可用解決方案。這不僅節省時間,而且使您的程式碼更加可靠和有效率。 這種方法使您能夠更多地關注專案的獨特方面。這是一種明智的策略,可以提高生產力並建立強大的軟體,而無需從頭開始。 ## 採用 HTML Emmet 進行快速原型設計: Emmet 是一個針對 Web 開發人員的工具包,可透過縮寫快速且有效率地進行編碼。 如果您使用 HTML,Emmet 可以顯著加快建立 HTML 結構的過程。 例子: ``` div>(header>ul>li*2>a)+footer>p ``` 輸出: ``` <div> <header> <ul> <li><a href=""></a></li> <li><a href=""></a></li> </ul> </header> <footer> <p></p> </footer> </div> ``` ## 利用人工智慧協助: - **GitHub 副駕駛:** 是 GitHub 與 OpenAI 合作開發的人工智慧驅動的程式碼補全工具。它透過在開發人員鍵入時產生智慧建議和自動完成來改變開發人員編寫程式碼的方式。這是迄今為止我嘗試過的最好的人工智慧工具之一。 ![GitHub Copilot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/822ubh3qe2lyezubbva5.png) - **標籤九:** 是一個人工智慧驅動的程式碼編輯器自動完成擴充。它超越了傳統的自動完成功能,使用機器學習模型來預測和建議整行或程式碼區塊。 用戶可以選擇免費使用 TabNine,但有一些限制,也可以透過訂閱來選擇專業版以獲得高級功能。 [TabNine](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/68un8zingjmsvnuk5pyl.png) - **聊天gpt :** ChatGPT 可以真正改變您的工作效率。例如,它可以提供有用的範例,例如建議用於測試的陣列或幫助重建程式碼片段。 ![Chatgpt 範例](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hi8hskndin82w2vgx10l.png) 如果您在程式設計概念上遇到困難或需要澄清,ChatGPT 可以提供快速且易於理解的解釋。這就像擁有一位知識淵博的編碼夥伴,24/7 全天候幫助您應對編碼挑戰,使您的開發過程更加順暢和高效。 ## VS 程式碼中的擴充: VS Code 中的擴充功能可以透過加入功能、自動化任務和增強開發環境來顯著提高工作效率: - **更漂亮:** Prettier 是一個固執己見的程式碼格式化程序,它會自動格式化您的程式碼,使其看起來乾淨且一致,從而使您免於手動格式化的麻煩。有了 Prettier,您的程式碼變得更加賞心悅目,您可以更加專注於編寫邏輯,而不必擔心樣式。 ![更漂亮的擴充](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gurx061173zhqjd8lvvq.png) - **自動重新命名標籤:** 自動重命名標籤擴充就像 HTML 或 XML 的編碼助手。當您變更開始標記的名稱時,此擴充功能會自動更新結束標記以符合。 ![自動重新命名標籤擴充](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q31o7ljpjl3ciysch7b5.png) - **更好的評論:** Better Comments 擴充功能將幫助您在程式碼中建立更人性化的註解。透過此擴展,您將能夠對註釋進行分類。 ![更好的評論擴充](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t4f45e3cjl34mcs94rx6.png) - **智慧感知:** IntelliSense 是您的程式設計助手,可在您鍵入時提供智慧程式碼補全和建議。它預測您的需求並提供相關選項,使編碼更加有效率。一些範例: ![Tailwind CSS IntelliSense 擴充](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kcjdqgwg5n6dgn4naeuz.png) ![路徑智慧感知擴充](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9c1hvrb4l60mx6l2mp32.png) ![npm Intellisense 擴充](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yo40qrvwsplnbvzc2wn3.png) - **孔雀:** 當您處理大量專案並在 VSCode 視窗之間跳轉時,Peacock 非常有用。它允許您將顏色連結到每個專案,因此每當您打開它時,您都可以透過顏色快速查看您所在的視窗。 ![孔雀擴充](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gncbyqxup6iwa353q3vt.png) --- **總而言之**,結合這些策略和工具可以真正徹底改變您的編碼方法,將您轉變為更有效率、更有效率的開發人員。擁抱 10 倍思維不僅可以提高個人生產力,還可以為您的團隊做出積極貢獻。因此,繼續實施這些技巧,並觀察您的編碼之旅進入一個全新的水平。 --- 原文出處:https://dev.to/idboussadel/how-to-become-a-10x-dev-ake

✨ 用您的文件訓練 ChatGPT 🪄 ✨

# 簡介 ChatGPT 訓練至 2022 年。 但是,如果您希望它專門為您提供有關您網站的資訊怎麼辦?最有可能的是,這是不可能的,**但不再是了!** OpenAI 推出了他們的新功能 - [助手](https://platform.openai.com/docs/assistants/how-it-works)。 現在您可以輕鬆地為您的網站建立索引,然後向 ChatGPT 詢問有關該網站的問題。在本教程中,我們將建立一個系統來索引您的網站並讓您查詢它。我們將: - 抓取文件網站地圖。 - 從網站上的所有頁面中提取資訊。 - 使用新資訊建立新助理。 - 建立一個簡單的ChatGPT前端介面並查詢助手。 ![助手](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ekre38der95twom33tqb.gif) --- ## 你的後台工作平台🔌 [Trigger.dev](https://trigger.dev/) 是一個開源程式庫,可讓您使用 NextJS、Remix、Astro 等為您的應用程式建立和監控長時間執行的作業!   [![GiveUsStars](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bm9mrmovmn26izyik95z.gif)](https://github.com/triggerdotdev/trigger.dev) 請幫我們一顆星🥹。 這將幫助我們建立更多這樣的文章💖 --- ## 讓我們開始吧🔥 讓我們建立一個新的 NextJS 專案。 ``` npx create-next-app@latest ``` >💡 我們使用 NextJS 新的應用程式路由器。安裝專案之前請確保您的節點版本為 18+ 讓我們建立一個新的資料庫來保存助手和抓取的頁面。 對於我們的範例,我們將使用 [Prisma](https://www.prisma.io/) 和 SQLite。 安裝非常簡單,只需執行: ``` npm install prisma @prisma/client --save ``` 然後加入架構和資料庫 ``` npx prisma init --datasource-provider sqlite ``` 轉到“prisma/schema.prisma”並將其替換為以下架構: ``` // This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema generator client { provider = "prisma-client-js" } datasource db { provider = "sqlite" url = env("DATABASE_URL") } model Docs { id Int @id @default(autoincrement()) content String url String @unique identifier String @@index([identifier]) } model Assistant { id Int @id @default(autoincrement()) aId String url String @unique } ``` 然後執行 ``` npx prisma db push ``` 這將建立一個新的 SQLite 資料庫(本機檔案),其中包含兩個主表:“Docs”和“Assistant” - 「Docs」包含所有抓取的頁面 - `Assistant` 包含文件的 URL 和內部 ChatGPT 助理 ID。 讓我們新增 Prisma 客戶端。 建立一個名為「helper」的新資料夾,並新增一個名為「prisma.ts」的新文件,並在其中新增以下程式碼: ``` import {PrismaClient} from '@prisma/client'; export const prisma = new PrismaClient(); ``` 我們稍後可以使用“prisma”變數來查詢我們的資料庫。 --- ![ScrapeAndIndex](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fc05wtlc4peosr62ydnx.png) ## 刮擦和索引 ### 建立 Trigger.dev 帳戶 抓取頁面並為其建立索引是一項長期執行的任務。 **我們需要:** - 抓取網站地圖的主網站元 URL。 - 擷取網站地圖內的所有頁面。 - 前往每個頁面並提取內容。 - 將所有內容儲存到 ChatGPT 助手中。 為此,我們使用 Trigger.dev! 註冊 [Trigger.dev 帳號](https://trigger.dev/)。 註冊後,建立一個組織並為您的工作選擇一個專案名稱。 ![pic1](https://res.cloudinary.com/practicaldev/image/fetch/s--B2jtIoA6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bdnxq8o7el7t4utvgf1u.jpeg) 選擇 Next.js 作為您的框架,並按照將 Trigger.dev 新增至現有 Next.js 專案的流程進行操作。 ![pic2](https://res.cloudinary.com/practicaldev/image/fetch/s--K4k6T6mi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e4kt7e5r1mwg60atqfka.jpeg) 否則,請點選專案儀表板側邊欄選單上的「環境和 API 金鑰」。 ![pic3](https://res.cloudinary.com/practicaldev/image/fetch/s--Ysm1Dd0r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ser7a2j5qft9vw8rfk0m.png) 複製您的 DEV 伺服器 API 金鑰並執行下面的程式碼片段來安裝 Trigger.dev。 仔細按照說明進行操作。 ``` npx @trigger.dev/cli@latest init ``` 在另一個終端中執行以下程式碼片段,在 Trigger.dev 和您的 Next.js 專案之間建立隧道。 ``` npx @trigger.dev/cli@latest dev ``` ### 安裝 ChatGPT (OpenAI) 我們將使用OpenAI助手,因此我們必須將其安裝到我們的專案中。 [建立新的 OpenAI 帳戶](https://platform.openai.com/) 並產生 API 金鑰。 ![pic4](https://res.cloudinary.com/practicaldev/image/fetch/s--uV1LwOH---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ashau6i2sxcpd0qcxuwq.png) 點擊下拉清單中的「檢視 API 金鑰」以建立 API 金鑰。 ![pic5](https://res.cloudinary.com/practicaldev/image/fetch/s--Tp8aLqSa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4bzc6e7f7avemeuuaygr.png) 接下來,透過執行下面的程式碼片段來安裝 OpenAI 套件。 ``` npm install @trigger.dev/openai ``` 將您的 OpenAI API 金鑰新增至「.env.local」檔案。 ``` OPENAI_API_KEY=<your_api_key> ``` 建立一個新目錄“helper”並新增一個新檔案“open.ai.tsx”,其中包含以下內容: ``` import {OpenAI} from "@trigger.dev/openai"; export const openai = new OpenAI({ id: "openai", apiKey: process.env.OPENAI_API_KEY!, }); ``` 這是我們透過 Trigger.dev 整合封裝的 OpenAI 用戶端。 ### 建立後台作業 讓我們繼續建立一個新的後台作業! 前往“jobs”並建立一個名為“process.documentation.ts”的新檔案。 **新增以下程式碼:** ``` import { eventTrigger } from "@trigger.dev/sdk"; import { client } from "@openai-assistant/trigger"; import {object, string} from "zod"; import {JSDOM} from "jsdom"; import {openai} from "@openai-assistant/helper/open.ai"; client.defineJob({ // This is the unique identifier for your Job; it must be unique across all Jobs in your project. id: "process-documentation", name: "Process Documentation", version: "0.0.1", // This is triggered by an event using eventTrigger. You can also trigger Jobs with webhooks, on schedules, and more: https://trigger.dev/docs/documentation/concepts/triggers/introduction trigger: eventTrigger({ name: "process.documentation.event", schema: object({ url: string(), }) }), integrations: { openai }, run: async (payload, io, ctx) => { } }); ``` 我們定義了一個名為「process.documentation.event」的新作業,並新增了一個名為 URL 的必要參數 - 這是我們稍後要傳送的文件 URL。 正如您所看到的,該作業是空的,所以讓我們向其中加入第一個任務。 我們需要獲取網站網站地圖並將其返回。 抓取網站將返回我們需要解析的 HTML。 為此,我們需要安裝 JSDOM。 ``` npm install jsdom --save ``` 並將其導入到我們文件的頂部: ``` import {JSDOM} from "jsdom"; ``` 現在,我們可以新增第一個任務。 用「runTask」包裝我們的程式碼很重要,這可以讓 Trigger.dev 將其與其他任務分開。觸發特殊架構將任務拆分為不同的進程,因此 Vercel 無伺服器逾時不會影響它們。 **這是第一個任務的程式碼:** ``` const getSiteMap = await io.runTask("grab-sitemap", async () => { const data = await (await fetch(payload.url)).text(); const dom = new JSDOM(data); const sitemap = dom.window.document.querySelector('[rel="sitemap"]')?.getAttribute('href'); return new URL(sitemap!, payload.url).toString(); }); ``` - 我們透過 HTTP 請求從 URL 取得整個 HTML。 - 我們將其轉換為 JS 物件。 - 我們找到網站地圖 URL。 - 我們解析它並返回它。 接下來,我們需要抓取網站地圖,提取所有 URL 並返回它們。 讓我們安裝“Lodash”——陣列結構的特殊函數。 ``` npm install lodash @types/lodash --save ``` 這是任務的程式碼: ``` export const makeId = (length: number) => { let text = ''; const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; for (let i = 0; i < length; i += 1) { text += possible.charAt(Math.floor(Math.random() * possible.length)); } return text; }; const {identifier, list} = await io.runTask("load-and-parse-sitemap", async () => { const urls = /(http|ftp|https):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])/g; const identifier = makeId(5); const data = await (await fetch(getSiteMap)).text(); // @ts-ignore return {identifier, list: chunk(([...new Set(data.match(urls))] as string[]).filter(f => f.includes(payload.url)).map(p => ({identifier, url: p})), 25)}; }); ``` - 我們建立一個名為 makeId 的新函數來為所有頁面產生隨機辨識碼。 - 我們建立一個新任務並加入正規表示式來提取每個可能的 URL - 我們發送一個 HTTP 請求來載入網站地圖並提取其所有 URL。 - 我們將 URL「分塊」為 25 個元素的陣列(如果有 100 個元素,則會有四個 25 個元素的陣列) 接下來,讓我們建立一個新作業來處理每個 URL。 **這是完整的程式碼:** ``` function getElementsBetween(startElement: Element, endElement: Element) { let currentElement = startElement; const elements = []; // Traverse the DOM until the endElement is reached while (currentElement && currentElement !== endElement) { currentElement = currentElement.nextElementSibling!; // If there's no next sibling, go up a level and continue if (!currentElement) { // @ts-ignore currentElement = startElement.parentNode!; startElement = currentElement; if (currentElement === endElement) break; continue; } // Add the current element to the list if (currentElement && currentElement !== endElement) { elements.push(currentElement); } } return elements; } const processContent = client.defineJob({ // This is the unique identifier for your Job; it must be unique across all Jobs in your project. id: "process-content", name: "Process Content", version: "0.0.1", // This is triggered by an event using eventTrigger. You can also trigger Jobs with webhooks, on schedules, and more: https://trigger.dev/docs/documentation/concepts/triggers/introduction trigger: eventTrigger({ name: "process.content.event", schema: object({ url: string(), identifier: string(), }) }), run: async (payload, io, ctx) => { return io.runTask('grab-content', async () => { // We first grab a raw html of the content from the website const data = await (await fetch(payload.url)).text(); // We load it with JSDOM so we can manipulate it const dom = new JSDOM(data); // We remove all the scripts and styles from the page dom.window.document.querySelectorAll('script, style').forEach((el) => el.remove()); // We grab all the titles from the page const content = Array.from(dom.window.document.querySelectorAll('h1, h2, h3, h4, h5, h6')); // We grab the last element so we can get the content between the last element and the next element const lastElement = content[content.length - 1]?.parentElement?.nextElementSibling!; const elements = []; // We loop through all the elements and grab the content between each title for (let i = 0; i < content.length; i++) { const element = content[i]; const nextElement = content?.[i + 1] || lastElement; const elementsBetween = getElementsBetween(element, nextElement); elements.push({ title: element.textContent, content: elementsBetween.map((el) => el.textContent).join('\n') }); } // We create a raw text format of all the content const page = ` ---------------------------------- url: ${payload.url}\n ${elements.map((el) => `${el.title}\n${el.content}`).join('\n')} ---------------------------------- `; // We save it to our database await prisma.docs.upsert({ where: { url: payload.url }, update: { content: page, identifier: payload.identifier }, create: { url: payload.url, content: page, identifier: payload.identifier } }); }); }, }); ``` - 我們從 URL 中獲取內容(之前從網站地圖中提取) - 我們用`JSDOM`解析它 - 我們刪除頁面上存在的所有可能的“<script>”或“<style>”。 - 我們抓取頁面上的所有標題(`h1`、`h2`、`h3`、`h4`、`h5`、`h6`) - 我們迭代標題並獲取它們之間的內容。我們不想取得整個頁面內容,因為它可能包含不相關的內容。 - 我們建立頁面原始文字的版本並將其保存到我們的資料庫中。 現在,讓我們為每個網站地圖 URL 執行此任務。 觸發器引入了名為“batchInvokeAndWaitForCompletion”的東西。 它允許我們批量發送 25 個專案進行處理,並且它將同時處理所有這些專案。下面是接下來的幾行程式碼: ``` let i = 0; for (const item of list) { await processContent.batchInvokeAndWaitForCompletion( 'process-list-' + i, item.map( payload => ({ payload, }), 86_400), ); i++; } ``` 我們以 25 個為一組[手動觸發](https://trigger.dev/docs/documentation/concepts/triggers/invoke)之前建立的作業。 完成後,讓我們將保存到資料庫的所有內容並連接它: ``` const data = await io.runTask("get-extracted-data", async () => { return (await prisma.docs.findMany({ where: { identifier }, select: { content: true } })).map((d) => d.content).join('\n\n'); }); ``` 我們使用之前指定的標識符。 現在,讓我們在 ChatGPT 中使用新資料建立一個新檔案: ``` const file = await io.openai.files.createAndWaitForProcessing("upload-file", { purpose: "assistants", file: data }); ``` `createAndWaitForProcessing` 是 Trigger.dev 建立的任務,用於將檔案上傳到助手。如果您在沒有整合的情況下手動使用“openai”,則必須串流傳輸檔案。 現在讓我們建立或更新我們的助手: ``` const assistant = await io.openai.runTask("create-or-update-assistant", async (openai) => { const currentAssistant = await prisma.assistant.findFirst({ where: { url: payload.url } }); if (currentAssistant) { return openai.beta.assistants.update(currentAssistant.aId, { file_ids: [file.id] }); } return openai.beta.assistants.create({ name: identifier, description: 'Documentation', instructions: 'You are a documentation assistant, you have been loaded with documentation from ' + payload.url + ', return everything in an MD format.', model: 'gpt-4-1106-preview', tools: [{ type: "code_interpreter" }, {type: 'retrieval'}], file_ids: [file.id], }); }); ``` - 我們首先檢查是否有針對該特定 URL 的助手。 - 如果我們有的話,讓我們用新文件更新助手。 - 如果沒有,讓我們建立一個新的助手。 - 我們傳遞「你是文件助理」的指令,需要注意的是,我們希望最終輸出為「MD」格式,以便稍後更好地顯示。 對於拼圖的最後一塊,讓我們將新助手儲存到我們的資料庫中。 **這是程式碼:** ``` await io.runTask("save-assistant", async () => { await prisma.assistant.upsert({ where: { url: payload.url }, update: { aId: assistant.id, }, create: { aId: assistant.id, url: payload.url, } }); }); ``` 如果該 URL 已經存在,我們可以嘗試使用新的助手 ID 來更新它。 這是該頁面的完整程式碼: ``` import { eventTrigger } from "@trigger.dev/sdk"; import { client } from "@openai-assistant/trigger"; import {object, string} from "zod"; import {JSDOM} from "jsdom"; import {chunk} from "lodash"; import {prisma} from "@openai-assistant/helper/prisma.client"; import {openai} from "@openai-assistant/helper/open.ai"; const makeId = (length: number) => { let text = ''; const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; for (let i = 0; i < length; i += 1) { text += possible.charAt(Math.floor(Math.random() * possible.length)); } return text; }; client.defineJob({ // This is the unique identifier for your Job; it must be unique across all Jobs in your project. id: "process-documentation", name: "Process Documentation", version: "0.0.1", // This is triggered by an event using eventTrigger. You can also trigger Jobs with webhooks, on schedules, and more: https://trigger.dev/docs/documentation/concepts/triggers/introduction trigger: eventTrigger({ name: "process.documentation.event", schema: object({ url: string(), }) }), integrations: { openai }, run: async (payload, io, ctx) => { // The first task to get the sitemap URL from the website const getSiteMap = await io.runTask("grab-sitemap", async () => { const data = await (await fetch(payload.url)).text(); const dom = new JSDOM(data); const sitemap = dom.window.document.querySelector('[rel="sitemap"]')?.getAttribute('href'); return new URL(sitemap!, payload.url).toString(); }); // We parse the sitemap; instead of using some XML parser, we just use regex to get the URLs and we return it in chunks of 25 const {identifier, list} = await io.runTask("load-and-parse-sitemap", async () => { const urls = /(http|ftp|https):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])/g; const identifier = makeId(5); const data = await (await fetch(getSiteMap)).text(); // @ts-ignore return {identifier, list: chunk(([...new Set(data.match(urls))] as string[]).filter(f => f.includes(payload.url)).map(p => ({identifier, url: p})), 25)}; }); // We go into each page and grab the content; we do this in batches of 25 and save it to the DB let i = 0; for (const item of list) { await processContent.batchInvokeAndWaitForCompletion( 'process-list-' + i, item.map( payload => ({ payload, }), 86_400), ); i++; } // We get the data that we saved in batches from the DB const data = await io.runTask("get-extracted-data", async () => { return (await prisma.docs.findMany({ where: { identifier }, select: { content: true } })).map((d) => d.content).join('\n\n'); }); // We upload the data to OpenAI with all the content const file = await io.openai.files.createAndWaitForProcessing("upload-file", { purpose: "assistants", file: data }); // We create a new assistant or update the old one with the new file const assistant = await io.openai.runTask("create-or-update-assistant", async (openai) => { const currentAssistant = await prisma.assistant.findFirst({ where: { url: payload.url } }); if (currentAssistant) { return openai.beta.assistants.update(currentAssistant.aId, { file_ids: [file.id] }); } return openai.beta.assistants.create({ name: identifier, description: 'Documentation', instructions: 'You are a documentation assistant, you have been loaded with documentation from ' + payload.url + ', return everything in an MD format.', model: 'gpt-4-1106-preview', tools: [{ type: "code_interpreter" }, {type: 'retrieval'}], file_ids: [file.id], }); }); // We update our internal database with the assistant await io.runTask("save-assistant", async () => { await prisma.assistant.upsert({ where: { url: payload.url }, update: { aId: assistant.id, }, create: { aId: assistant.id, url: payload.url, } }); }); }, }); export function getElementsBetween(startElement: Element, endElement: Element) { let currentElement = startElement; const elements = []; // Traverse the DOM until the endElement is reached while (currentElement && currentElement !== endElement) { currentElement = currentElement.nextElementSibling!; // If there's no next sibling, go up a level and continue if (!currentElement) { // @ts-ignore currentElement = startElement.parentNode!; startElement = currentElement; if (currentElement === endElement) break; continue; } // Add the current element to the list if (currentElement && currentElement !== endElement) { elements.push(currentElement); } } return elements; } // This job will grab the content from the website const processContent = client.defineJob({ // This is the unique identifier for your Job; it must be unique across all Jobs in your project. id: "process-content", name: "Process Content", version: "0.0.1", // This is triggered by an event using eventTrigger. You can also trigger Jobs with webhooks, on schedules, and more: https://trigger.dev/docs/documentation/concepts/triggers/introduction trigger: eventTrigger({ name: "process.content.event", schema: object({ url: string(), identifier: string(), }) }), run: async (payload, io, ctx) => { return io.runTask('grab-content', async () => { try { // We first grab a raw HTML of the content from the website const data = await (await fetch(payload.url)).text(); // We load it with JSDOM so we can manipulate it const dom = new JSDOM(data); // We remove all the scripts and styles from the page dom.window.document.querySelectorAll('script, style').forEach((el) => el.remove()); // We grab all the titles from the page const content = Array.from(dom.window.document.querySelectorAll('h1, h2, h3, h4, h5, h6')); // We grab the last element so we can get the content between the last element and the next element const lastElement = content[content.length - 1]?.parentElement?.nextElementSibling!; const elements = []; // We loop through all the elements and grab the content between each title for (let i = 0; i < content.length; i++) { const element = content[i]; const nextElement = content?.[i + 1] || lastElement; const elementsBetween = getElementsBetween(element, nextElement); elements.push({ title: element.textContent, content: elementsBetween.map((el) => el.textContent).join('\n') }); } // We create a raw text format of all the content const page = ` ---------------------------------- url: ${payload.url}\n ${elements.map((el) => `${el.title}\n${el.content}`).join('\n')} ---------------------------------- `; // We save it to our database await prisma.docs.upsert({ where: { url: payload.url }, update: { content: page, identifier: payload.identifier }, create: { url: payload.url, content: page, identifier: payload.identifier } }); } catch (e) { console.log(e); } }); }, }); ``` 我們已經完成建立後台作業來抓取和索引文件🎉 ### 詢問助理 現在,讓我們建立一個任務來詢問我們的助手。 前往“jobs”並建立一個新檔案“question.assistant.ts”。 **新增以下程式碼:** ``` import {eventTrigger} from "@trigger.dev/sdk"; import {client} from "@openai-assistant/trigger"; import {object, string} from "zod"; import {openai} from "@openai-assistant/helper/open.ai"; client.defineJob({ // This is the unique identifier for your Job; it must be unique across all Jobs in your project. id: "question-assistant", name: "Question Assistant", version: "0.0.1", // This is triggered by an event using eventTrigger. You can also trigger Jobs with webhooks, on schedules, and more: https://trigger.dev/docs/documentation/concepts/triggers/introduction trigger: eventTrigger({ name: "question.assistant.event", schema: object({ content: string(), aId: string(), threadId: string().optional(), }) }), integrations: { openai }, run: async (payload, io, ctx) => { // Create or use an existing thread const thread = payload.threadId ? await io.openai.beta.threads.retrieve('get-thread', payload.threadId) : await io.openai.beta.threads.create('create-thread'); // Create a message in the thread await io.openai.beta.threads.messages.create('create-message', thread.id, { content: payload.content, role: 'user', }); // Run the thread const run = await io.openai.beta.threads.runs.createAndWaitForCompletion('run-thread', thread.id, { model: 'gpt-4-1106-preview', assistant_id: payload.aId, }); // Check the status of the thread if (run.status !== "completed") { console.log('not completed'); throw new Error(`Run finished with status ${run.status}: ${JSON.stringify(run.last_error)}`); } // Get the messages from the thread const messages = await io.openai.beta.threads.messages.list("list-messages", run.thread_id, { query: { limit: "1" } }); const content = messages[0].content[0]; if (content.type === 'text') { return {content: content.text.value, threadId: thread.id}; } } }); ``` - 該事件需要三個參數 - `content` - 我們想要傳送給助理的訊息。 - `aId` - 我們先前建立的助手的內部 ID。 - `threadId` - 對話的執行緒 ID。正如您所看到的,這是一個可選參數,因為在第一個訊息中,我們還沒有線程 ID。 - 然後,我們建立或取得前一個執行緒的執行緒。 - 我們在助理提出的問題的線索中加入一條新訊息。 - 我們執行線程並等待它完成。 - 我們取得訊息清單(並將其限制為 1),因為第一則訊息是對話中的最後一則訊息。 - 我們返回訊息內容和我們剛剛建立的線程ID。 ### 新增路由 我們需要為我們的應用程式建立 3 個 API 路由: 1、派新助理進行處理。 2. 透過URL獲取特定助手。 3. 新增訊息給助手。 在「app/api」中建立一個名為assistant的新資料夾,並在其中建立一個名為「route.ts」的新檔案。裡面加入如下程式碼: ``` import {client} from "@openai-assistant/trigger"; import {prisma} from "@openai-assistant/helper/prisma.client"; export async function POST(request: Request) { const body = await request.json(); if (!body.url) { return new Response(JSON.stringify({error: 'URL is required'}), {status: 400}); } // We send an event to the trigger to process the documentation const {id: eventId} = await client.sendEvent({ name: "process.documentation.event", payload: {url: body.url}, }); return new Response(JSON.stringify({eventId}), {status: 200}); } export async function GET(request: Request) { const url = new URL(request.url).searchParams.get('url'); if (!url) { return new Response(JSON.stringify({error: 'URL is required'}), {status: 400}); } const assistant = await prisma.assistant.findFirst({ where: { url: url } }); return new Response(JSON.stringify(assistant), {status: 200}); } ``` 第一個「POST」方法取得一個 URL,並使用用戶端傳送的 URL 觸發「process.documentation.event」作業。 第二個「GET」方法從我們的資料庫中透過客戶端發送的 URL 取得助手。 現在,讓我們建立向助手新增訊息的路由。 在「app/api」內部建立一個新資料夾「message」並新增一個名為「route.ts」的新文件,然後新增以下程式碼: ``` import {prisma} from "@openai-assistant/helper/prisma.client"; import {client} from "@openai-assistant/trigger"; export async function POST(request: Request) { const body = await request.json(); // Check that we have the assistant id and the message if (!body.id || !body.message) { return new Response(JSON.stringify({error: 'Id and Message are required'}), {status: 400}); } // get the assistant id in OpenAI from the id in the database const assistant = await prisma.assistant.findUnique({ where: { id: +body.id } }); // We send an event to the trigger to process the documentation const {id: eventId} = await client.sendEvent({ name: "question.assistant.event", payload: { content: body.message, aId: assistant?.aId, threadId: body.threadId }, }); return new Response(JSON.stringify({eventId}), {status: 200}); } ``` 這是一個非常基本的程式碼。我們從客戶端獲取訊息、助手 ID 和線程 ID,並將其發送到我們之前建立的「question.assistant.event」。 最後要做的事情是建立一個函數來獲取我們所有的助手。 在「helpers」內部建立一個名為「get.list.ts」的新函數並新增以下程式碼: ``` import {prisma} from "@openai-assistant/helper/prisma.client"; // Get the list of all the available assistants export const getList = () => { return prisma.assistant.findMany({ }); } ``` 非常簡單的程式碼即可獲得所有助手。 我們已經完成了後端🥳 讓我們轉到前面。 --- ![前端](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k3s5gks1j0ojoz11b93i.png) ## 建立前端 我們將建立一個基本介面來新增 URL 並顯示已新增 URL 的清單: ![ss1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ihvx4yn6uee6gritr9nh.png) ### 首頁 將 `app/page.tsx` 的內容替換為以下程式碼: ``` import {getList} from "@openai-assistant/helper/get.list"; import Main from "@openai-assistant/components/main"; export default async function Home() { const list = await getList(); return ( <Main list={list} /> ) } ``` 這是一個簡單的程式碼,它從資料庫中取得清單並將其傳遞給我們的 Main 元件。 接下來,讓我們建立“Main”元件。 在「app」內建立一個新資料夾「components」並新增一個名為「main.tsx」的新檔案。 **新增以下程式碼:** ``` "use client"; import {Assistant} from '@prisma/client'; import {useCallback, useState} from "react"; import {FieldValues, SubmitHandler, useForm} from "react-hook-form"; import {ChatgptComponent} from "@openai-assistant/components/chatgpt.component"; import {AssistantList} from "@openai-assistant/components/assistant.list"; import {TriggerProvider} from "@trigger.dev/react"; export interface ExtendedAssistant extends Assistant { pending?: boolean; eventId?: string; } export default function Main({list}: {list: ExtendedAssistant[]}) { const [assistantState, setAssistantState] = useState(list); const {register, handleSubmit} = useForm(); const submit: SubmitHandler<FieldValues> = useCallback(async (data) => { const assistantResponse = await (await fetch('/api/assistant', { body: JSON.stringify({url: data.url}), method: 'POST', headers: { 'Content-Type': 'application/json' } })).json(); setAssistantState([...assistantState, {...assistantResponse, url: data.url, pending: true}]); }, [assistantState]) const changeStatus = useCallback((val: ExtendedAssistant) => async () => { const assistantResponse = await (await fetch(`/api/assistant?url=${val.url}`, { method: 'GET', headers: { 'Content-Type': 'application/json' } })).json(); setAssistantState([...assistantState.filter((v) => v.id), assistantResponse]); }, [assistantState]) return ( <TriggerProvider publicApiKey={process.env.NEXT_PUBLIC_TRIGGER_PUBLIC_API_KEY!}> <div className="w-full max-w-2xl mx-auto p-6 flex flex-col gap-4"> <form className="flex items-center space-x-4" onSubmit={handleSubmit(submit)}> <input className="flex-grow p-3 border border-black/20 rounded-xl" placeholder="Add documentation link" type="text" {...register('url', {required: 'true'})} /> <button className="flex-shrink p-3 border border-black/20 rounded-xl" type="submit"> Add </button> </form> <div className="divide-y-2 divide-gray-300 flex gap-2 flex-wrap"> {assistantState.map(val => ( <AssistantList key={val.url} val={val} onFinish={changeStatus(val)} /> ))} </div> {assistantState.filter(f => !f.pending).length > 0 && <ChatgptComponent list={assistantState} />} </div> </TriggerProvider> ) } ``` 讓我們看看這裡發生了什麼: - 我們建立了一個名為「ExtendedAssistant」的新接口,其中包含兩個參數「pending」和「eventId」。當我們建立一個新的助理時,我們沒有最終的值,我們將只儲存`eventId`並監聽作業處理直到完成。 - 我們從伺服器元件取得清單並將其設定為新狀態(以便我們稍後可以修改它) - 我們新增了「TriggerProvider」來幫助我們監聽事件完成並用資料更新它。 - 我們使用「react-hook-form」建立一個新表單來新增助手。 - 我們新增了一個帶有一個輸入「URL」的表單來提交新的助理進行處理。 - 我們迭代並顯示所有現有的助手。 - 在提交表單時,我們將資訊傳送到先前建立的「路由」以新增助理。 - 事件完成後,我們觸發「changeStatus」以從資料庫載入助手。 - 最後,我們有了 ChatGPT 元件,只有在沒有等待處理的助手時才會顯示(`!f.pending`) 讓我們建立 `AssistantList` 元件。 在「components」內,建立一個新檔案「assistant.list.tsx」並在其中加入以下內容: ``` "use client"; import {FC, useEffect} from "react"; import {ExtendedAssistant} from "@openai-assistant/components/main"; import {useEventRunDetails} from "@trigger.dev/react"; export const Loading: FC<{eventId: string, onFinish: () => void}> = (props) => { const {eventId} = props; const { data, error } = useEventRunDetails(eventId); useEffect(() => { if (!data || error) { return ; } if (data.status === 'SUCCESS') { props.onFinish(); } }, [data]); return <div className="pointer bg-yellow-300 border-yellow-500 p-1 px-3 text-yellow-950 border rounded-2xl">Loading</div> }; export const AssistantList: FC<{val: ExtendedAssistant, onFinish: () => void}> = (props) => { const {val, onFinish} = props; if (val.pending) { return <Loading eventId={val.eventId!} onFinish={onFinish} /> } return ( <div key={val.url} className="pointer relative bg-green-300 border-green-500 p-1 px-3 text-green-950 border rounded-2xl hover:bg-red-300 hover:border-red-500 hover:text-red-950 before:content-[attr(data-content)]" data-content={val.url} /> ) } ``` 我們迭代我們建立的所有助手。如果助手已經建立,我們只顯示名稱。如果沒有,我們渲染`<Loading />`元件。 載入元件在螢幕上顯示“正在載入”,並長時間輪詢伺服器直到事件完成。 我們使用 Trigger.dev 建立的 useEventRunDetails 函數來了解事件何時完成。 事件完成後,它會觸發「onFinish」函數,用新建立的助手更新我們的客戶端。 ### 聊天介面 ![聊天介面](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0u7db3qwz03d6jkk965a.png) 現在,讓我們加入 ChatGPT 元件並向我們的助手提問! - 選擇我們想要使用的助手 - 顯示訊息列表 - 新增我們要傳送的訊息的輸入和提交按鈕。 在「components」內部新增一個名為「chatgpt.component.tsx」的新文件 讓我們繪製 ChatGPT 聊天框: ``` "use client"; import {FC, useCallback, useEffect, useRef, useState} from "react"; import {ExtendedAssistant} from "@openai-assistant/components/main"; import Markdown from 'react-markdown' import {useEventRunDetails} from "@trigger.dev/react"; interface Messages { message?: string eventId?: string } export const ChatgptComponent = ({list}: {list: ExtendedAssistant[]}) => { const url = useRef<HTMLSelectElement>(null); const [message, setMessage] = useState(''); const [messagesList, setMessagesList] = useState([] as Messages[]); const [threadId, setThreadId] = useState<string>('' as string); const submitForm = useCallback(async (e: any) => { e.preventDefault(); setMessagesList((messages) => [...messages, {message: `**[ME]** ${message}`}]); setMessage(''); const messageResponse = await (await fetch('/api/message', { method: 'POST', body: JSON.stringify({message, id: url.current?.value, threadId}), })).json(); if (!threadId) { setThreadId(messageResponse.threadId); } setMessagesList((messages) => [...messages, {eventId: messageResponse.eventId}]); }, [message, messagesList, url, threadId]); return ( <div className="border border-black/50 rounded-2xl flex flex-col"> <div className="border-b border-b-black/50 h-[60px] gap-3 px-3 flex items-center"> <div>Assistant:</div> <div> <select ref={url} className="border border-black/20 rounded-xl p-2"> {list.filter(f => !f.pending).map(val => ( <option key={val.id} value={val.id}>{val.url}</option> ))} </select> </div> </div> <div className="flex-1 flex flex-col gap-3 py-3 w-full min-h-[500px] max-h-[1000px] overflow-y-auto overflow-x-hidden messages-list"> {messagesList.map((val, index) => ( <div key={index} className={`flex border-b border-b-black/20 pb-3 px-3`}> <div className="w-full"> {val.message ? <Markdown>{val.message}</Markdown> : <MessageComponent eventId={val.eventId!} onFinish={setThreadId} />} </div> </div> ))} </div> <form onSubmit={submitForm}> <div className="border-t border-t-black/50 h-[60px] gap-3 px-3 flex items-center"> <div className="flex-1"> <input value={message} onChange={(e) => setMessage(e.target.value)} className="read-only:opacity-20 outline-none border border-black/20 rounded-xl p-2 w-full" placeholder="Type your message here" /> </div> <div> <button className="border border-black/20 rounded-xl p-2 disabled:opacity-20" disabled={message.length < 3}>Send</button> </div> </div> </form> </div> ) } export const MessageComponent: FC<{eventId: string, onFinish: (threadId: string) => void}> = (props) => { const {eventId} = props; const { data, error } = useEventRunDetails(eventId); useEffect(() => { if (!data || error) { return ; } if (data.status === 'SUCCESS') { props.onFinish(data.output.threadId); } }, [data]); if (!data || error || data.status !== 'SUCCESS') { return ( <div className="flex justify-end items-center pb-3 px-3"> <div className="animate-spin rounded-full h-3 w-3 border-t-2 border-b-2 border-blue-500" /> </div> } return <Markdown>{data.output.content}</Markdown>; }; ``` 這裡正在發生一些令人興奮的事情: - 當我們建立新訊息時,我們會自動將其呈現在螢幕上作為「我們的」訊息,但是當我們將其發送到伺服器時,我們需要推送事件 ID,因為我們還沒有訊息。這就是我們使用 `{val.message ? <Markdown>{val.message}</Markdown> : <MessageComponent eventId={val.eventId!} onFinish={setThreadId} />}` - 我們用「Markdown」元件包裝訊息。如果您還記得,我們在前面的步驟中告訴 ChatGPT 以 MD 格式輸出所有內容,以便我們可以正確渲染它。 - 事件處理完成後,我們會更新線程 ID,以便我們從以下訊息中獲得相同對話的上下文。 我們就完成了🎉 --- ![完成](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0half2g6r5zfn7asq084.png) ## 讓我們聯絡吧! 🔌 作為開源開發者,您可以加入我們的[社群](https://discord.gg/nkqV9xBYWy) 做出貢獻並與維護者互動。請隨時造訪我們的 [GitHub 儲存庫](https://github.com/triggerdotdev/trigger.dev),貢獻並建立與 Trigger.dev 相關的問題。 本教學的源程式碼可在此處取得: [https://github.com/triggerdotdev/blog/tree/main/openai-assistant](https://github.com/triggerdotdev/blog/tree/main/openai-assistant) 感謝您的閱讀! --- 原文出處:https://dev.to/triggerdotdev/train-chatgpt-on-your-documentation-1a9g

🏆Pythonista 必備的 10 個 VSCode 擴展

## **TL;博士** 對於使用 VSCode 的 Python 開發人員、資料科學家和分析師來說,此編譯提供了一些擴展,可以提高 Python 和一般編碼需求的編碼生產力和效率。 ![介紹 GIF](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lhcge6eywoumtc7hyuxr.gif) <小時/> ## 1. [Taipy Studio](https://marketplace.visualstudio.com/items?itemName=Taipy.taipy-studio) Taipy 是一個開源 Python 庫,用於建立 Web 應用程式前端和後端。 您只需使用 Python 即可為您的資料/機器學習用例建立多頁面、多用戶和可自訂的 GUI。 但它不止於此。 Taipy 還可以處理您的後端,因為它允許管道編排和管理。 現在,回到 Taipy Studio 的 VSCode 擴充功能。此擴充功能是兩個工具的包裝器,旨在加速 Taipy 應用程式的建立。 - Taipy Studio Configuration Builder:圖形管道編輯器,全部在點擊環境中; - Taipy Studio GUI 助手:在編寫 GUI 時包括 IntelliSense。 ![太比 PNG](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7bju9pbjeaap2tditivf.png) <小時/> ![QueenB](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ovcc5kqd8xr9uihrggbb.gif) {% cta https://github.com/Avaiga/taipy %} Star ⭐ Taipy 儲存庫 {% endcta %} 我們已經快有 2000 顆星了,沒有你我們無法做到這一點🙏 <小時/> ## 2. [Github Copilot](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot) 還需要出示副駕駛嗎?這個工具就是您自己的程式碼助手。 利用人工智慧,Copilot 可以無縫地自動完成您的程式碼。 另一個主要功能是能夠提供上下文感知建議。 對於開發人員來說,這是一個偉大的遊戲規則改變者,可以節省時間和提高效率,並且將其直接作為 VSCode 擴展使用是完全有意義的。 ![副駕駛 PNG](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6192xn9g47gn2693r4j2.png) <小時/> ## 3. [Rainbow CSV](https://marketplace.visualstudio.com/items?itemName=mechatroner.rainbow-csv) 光看名字,你就差不多能猜到這個工具的功能了。 Rainbow CSV 將透過以不同顏色突出顯示列來讓您的 CSV 檔案易於閱讀。 就這麼簡單,但對任何處理資料的人來說都很有幫助。真正改變使用者視覺體驗的遊戲規則。 ![RCSV PNG](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tdvs5fyi12tprdc3gch4.png) <小時/> ## 4. [待辦事項樹](https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.todo-tree) 對於需要在程式碼的待辦事項清單中進行組織的人來說,這個工具非常有用。使用此擴展,只需在需要時在程式碼中加入 TODO 或 FIXME 標記即可。 ToDo Tree 將會尋找這些標籤並將它們組織成樹狀結構。 現在您可以輕鬆返回標籤。 ![TODO 樹 PNG](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/csiyv0rnp81lod36ksw7.png) <小時/> ## 5. [Jupyter](https://marketplace.visualstudio.com/items?itemName=ms-toolsai.jupyter) 如果您想使用類似筆記本的 IDE 來啟動資料/ML 專案以促進探索和實驗,VSCode 透過 Jupyter 擴充功能提供此功能。 當筆記型電腦的限制(例如擴展、部署、測試和維護)使得有必要轉向更傳統的編碼實踐時,在 VSCode 上進行所有設定只會讓事情變得更容易。 ![Jupyter PNG](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dbw6rqi4y2sls2466r02.png) <小時/> ## 6. [Markdown 表情符號](https://marketplace.visualstudio.com/items?itemName=bierner.markdown-emoji) 這裡並沒有什麼真正令人驚訝的地方。此 VSCode 擴展為 VSCode Markdown 預覽提供表情符號支持,這是為任何 Markdown 專案加入表現和可讀性的好方法。 ![MKD 表情符號 PNG](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7oaj92h9s95e2mtt0vr0.png) <小時/> ## 7. [Pylint](https://marketplace.visualstudio.com/items?itemName=ms-python.pylint) Pylint 與 Python linter 同名,是其在 VSCode 中的擴充。它透過分析程式碼、檢查錯誤並為您提供改進建議來幫助您提高效率。 確保您的腳本遵循所有編碼標準是必須的。 ![Pylint GIF](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lv6mcilflhupaultx160.gif) <小時/> ## 8. [Pylance](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance) Pylance 是 Python 語言的支援。 它最初作為 Python 庫存在,但透過此擴充整合到 VSCode 中。 一些主要特點: - 程式碼完成 - 自動導入 - 與 Juypter 筆記本相容 - 語意突出顯示 ![皮蘭斯 PNG](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s04exzm5y61m6rwjvhru.png) <小時/> ## 9. [Liveshare](https://marketplace.visualstudio.com/items?itemName=MS-vsliveshare.vsliveshare) 使用此 VSCode 擴充功能可以輕鬆進行協作。無需配置任何東西;只需啟動 Liveshare 會話並繼續除錯會話即可。 Liveshare 也保留您所有的個人 IDE 首選項,讓協作更加輕鬆。 ![Liveshare PNG](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l0the1beedaze59z7qcl.png) <小時/> ## 10. [Markdown 多合一](https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one) 此擴充增強了 VSCode 中 Markdown 的使用,並具有各種不同的功能: - 內容表生成 - 鍵盤快速鍵 - 程式碼區塊插入 - 預覽功能 該工具非常適合編寫“README.md”檔案。 ![MD AIO PNG](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2yji1wmk9lvp9plqp631.png) <小時/> 由於各種原因,VSCode 已成為開發人員最常使用的 IDE 之一。 它的主要功能包括強大的 git 整合和跨平台支持,但擴展是一個突出的功能。 它們支援自訂您的環境,促進與各種工具的無縫整合。 <小時/> 希望您喜歡這篇文章! 我是一名新手作家,歡迎任何改進建議! ![新秀圖片](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/25oebh36ha622u74kpli.gif) 如果您有任何疑問,請隨時與我們聯繫。 --- 原文出處:https://dev.to/taipy/top-10-must-have-vscode-extensions-forpythonistas-561a