🏠 首頁

🏠 首頁

從 Next.js 到 Rails 再到 Elixir:我的 React.js 倦怠之旅

我自 2019 年以來一直是 Web 開發人員。我使用 React.js 和基於 React 的框架,如 Gatsby、Next、Remix、Astro 和 Hydrogen。我從來沒有對這些工具感到完全滿意,但是,作為一個深入 JS 生態系統的初學者,我從同行那裡聽到的都是這樣的話:「這就是方式,任何其他程式語言要么慢,要么老」。 ![就是這樣](https://media.giphy.com/media/stnjSj2vpLcM4rwmEH/giphy.gif) 結果,我習慣了巨大的複雜性:多個獨立的儲存庫、數千個函式庫和框架來實現簡單的事情、GraphQL、微服務、無伺服器、靜態網站產生、增量靜態再生、部分水化、 redux 、redux-thunk、babel、webpack、react 伺服器元件、伺服器操作等。這個清單還可以再持續 10 分鐘。 直到有一天我說**受夠了!** 讓我們來看看我慢慢發瘋的完整時間線。這需要一段時間,在閱讀長篇文章之前,請隨意煮點咖啡! --- ## 倦怠的時間表 ### [Gatsby.js](https://www.gatsbyjs.com/) 我記得完成我的訓練營並想:“我終於能夠建立我的作品集了!”,所以我做到了。只有一個小問題,我想在 Google 上建立索引,但是使用舊的「create-react-app」使這項任務幾乎不可能完成。很快我了解了 SEO 和 React 的水合循環,這讓我找到了這個問題的「解決方案」:Gatsby.js。靜態網站產生的想法對當時的我來說簡直是革命性的,畢竟沒有什麼比預先渲染 HTML 檔案更快了,對吧? 我決定透過閱讀文件來學習這個新框架,讓我告訴你,這**不是**一次有趣的體驗。我以前從未聽說過 GraphQL,顯然,您需要它來產生所有靜態檔案(到底是什麼???)。我問我的一些網友,很難學習這些過度設計的廢話是否正常,他們回答說「技能問題,再努力一點!」。於是我更加努力,終於學會了之後,我把我的個人網站移植到了Gatsby上。 ![再努力一點](https://media.giphy.com/media/gzRiZROEyDCznPofKj/giphy.gif) 我的大部分頁面都成功在 Google 上建立了索引,幾個月來,我對結果非常滿意。然後另一個問題出現了:我的**很多**開發者朋友開始說“Gatsby 死了!建立 Next 是為了簡化靜態站點生成並提供伺服器端渲染”。 ### [Next.js](https://nextjs.org/) 我快速瀏覽了 Next 文件並**立即**愛上了它。我能夠在沒有 GraphQL 的情況下用三分之一的程式碼做與 Gatsby 相同的事情!我再次將我的作品集移植到另一個框架:Next。 這次我確實有一次美好的經驗。部署到 Vercel 輕而易舉,「getStaticProps」和「getServerSideProps」功能很簡單,但功能非常強大,我可以選擇每個頁面的渲染樣式,整體來說非常靈活。 不幸的是,我透過慘痛的教訓學到了一些東西:在 JavaScript 生態系統中,所有美好的事情都會結束。 ### [混音](https://remix.run/) 我清楚記得 Remix 發佈時的情景。多名科技影響者開始發布有關它的內容(一如既往)。然而,當時我在主頁上看到它不支援靜態網站生成,只支援伺服器端渲染,所以我想「等一下,這些年來投資於 [JAMstack](https://jamstack.org/) 都被扔在這裡了嗎?不可能,這個框架不會長久」。然而,令我驚訝的是,Remix 不僅生存了下來,而且還被 Shopify 收購 https://shopify.engineering/remix-joins-shopify ,並成為 Next 的重要競爭對手。 幾個月過去了,我決定嘗試看看。我再一次感到驚訝,Remix 的主要座右銘是使用 Web 基礎知識,而不是像 Next 這樣過於複雜的快取系統。因此,在Remix 中編碼時,我腦中需要的思維模型要簡單10 倍:沒有全域狀態管理器,只需使用URL,更少的客戶端狀態,將所有邏輯移至伺服器,並使用cookie,無需使用完整堆疊中間的 REST API 非常簡單,只需將資料庫查詢移至「loader」函數即可。 ### 離開矩陣 ![離開矩陣](https://media.giphy.com/media/11e0gEWxYoSYTK/giphy.gif) 然後,突然間,真相呈現在我面前,我服下了紅色藥丸。我的腦海中開始浮現出多個問題:Remix 不就像所有其他「古老而無聊」的框架(如 Rails、Laravel 和 Django)一樣嗎?幾十年來,我們一直在使用伺服器端渲染進行全端 Web 開發,但 JavaScript 黑手黨集體認為這種方法是垃圾,將所有內容移至客戶端才是未來。難道同一個黑手黨認為 Rails 一直都是對的嗎?用 JS 框架做所有那些過度設計的怪物不是正確的舉動嗎?我開始質疑一切。這種「新」的 Web 開發方式更加簡單、快速。 ### 我已經完成了 Next 和 Vercel 我透過 [Next.js 應用程式路由器](https://nextjs.org/docs/app) 達到了臨界點。以下是 Vercel 向 Next 推送的所有錯誤的完整清單: - 曾經簡單的:「getStaticProps」和「getServerSideProps」函數現在變得複雜而麻煩。目前,沒有特定的位置來新增 API 呼叫或資料庫查詢,您可以將它們寫入任何您想要的位置!在多年前使用 PHP 犯了同樣的錯誤之後,我們開始再次將業務邏輯與 UI 混合。難道前端開發者不吸取過去的教訓嗎?如果我刪除按鈕會發生什麼事?這是否會破壞我的使用者身份驗證流程,因為資料庫呼叫位於其中?您的前端應該 100% 可廢棄且可更換。你相對於競爭對手的競爭優勢在於業務邏輯,它應該與 UI 層完全隔離。 ![可怕的 Next.js 程式碼](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kp41ds14loo21xgimcza.png) - 接下來是伺服器優先。這聽起來沒那麼糟吧?畢竟,這解決了 SEO 問題並立即向用戶展示新鮮內容。問題在於,大多數現有的 Next 程式碼庫都依賴客戶端程式庫,例如樣式元件和一些全域狀態管理器。這是什麼意思?隨著此類重大變化的不斷發生,您的應用程式將在幾週而不是幾年內變成遺留軟體。更多的時間花在保持所有依賴項最新上,而不是做重要的事情:發布功能。 - Vercel 從 Meta 聘請了多名 React 核心團隊成員。這帶來了嚴重的利益衝突,因為這些工程師現在(據稱)正在發布有利於 Next 的功能,而不是優先考慮那些可以幫助所有基於 React 的框架(如 Remix)的功能。 ![Vercel 正在破壞 React](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ye40ykjgrd3z10t5nx7.png) 我再也受不了了。我對自己說:你知道嗎?我厭倦了一遍又一遍地重新學習相同的框架,我完全不同意這種新的範式。 毫不奇怪,其他內容創作者也經歷了類似的情況: https://youtu.be/zkCBSz353fc?si=z3-FDVgcB3xfp06h https://youtu.be/Zt8mO_Aqzw8?si=10fy1d-ZoB7t3Uc_ --- ## 啟蒙之路 我非常累。在厭倦了所有的 React 工具後,我開始了尋找更簡單的 Web 框架的旅程。以下是我一直在尋找的先決條件: - 含電池 - 約定優於配置 - 良好的開發體驗 - 現代化且高性能的前端 我的第一個反應是查看 [Stack Overflow Survey 2023](https://survey.stackoverflow.co/2023/#section-most-popular-technologies-web-frameworks-and-technologies) 中的頂級框架。我立即從清單中刪除了所有與 JS、C# 和 Java 相關的內容。我從來沒有興趣學習後兩個,它們看起來醜陋且冗長。所以剩下的選項是:Laravel (PHP)、Django (Python)、Rails (Ruby) 和 Phoenix (Elixir)。 Python 是我在網路工程學位期間使用的語言,我獲得了非常愉快的體驗。 Django 似乎遵循約定優於配置的理念,但最終讓我放棄它的是沒有一個好的內建工具來在前端工作。論壇上的大多數人都說他們使用[HTMX](https://htmx.org/) 和[Alpine](https://alpinejs.dev/),但是,兩者都是您需要安裝的外部依賴項。 放棄Laravel 是非常困難的,因為它具有驚人的成本效益,有數百個官方軟體包可以處理新創公司可能需要的幾乎所有內容,例如託管、身份驗證、條紋支付等。對於前端,他們創造了[慣性。Node.js](https://inertiajs.com/),這是一種非常簡單而優雅的方式,可以在前端使用 React 的同時保持 Laravel 的高生產力和強大功能。百分之百誠實地說,我沒有選擇 Laravel 的唯一原因是 PHP 的語法,它看起來很難看,到處都是一堆 `$` 和 `->`。 ### Ruby on Rails Ruby on Rails 無需介紹。它是 Web 開發框架的元年,其革命性的「15 分鐘建立部落格」至今仍令人印象深刻。在我開始抱怨我發現的所有問題之前,讓我們先從好的方面開始。 與 Python 類似,Ruby 是一種可以向非技術人員展示的語言,他們會理解該軟體想要做什麼。它是**迄今為止**我見過的最容易閱讀和最美麗的語言。我很快就意識到,[編寫視覺上令人愉悅的程式碼](https://world.hey.com/dhh/a-writer-s-ruby-2050b634) 是Rails 團隊的首要任務,這對我來說來說是新的。 更不用說 Rails 幾乎發明了「包含電池」和「約定優於配置」的哲學,所以這不會是一個問題。在一份文件中,我提供了任何類型的 Web 應用程式所需的一切。 在前端,有 [Hotwire](https://hotwired.dev/),這是一種非常簡單且輕量級的方法,可以實現 SPA 框架提供的所有 UX 改進。我一直很好奇測試這個庫的極限,它看起來非常有前途。 好吧,Rails 在紙面上滿足了我想要的框架的所有先決條件。我們來試試吧!我在本地測試的第一件事是“railsscaffold”命令。我立即感到震驚。一個指令就能產生 CRUD 所需的一切?決不! ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/58lbioexmot9412kojr5.png) 在 Node + React 領域,要實現相同的目標,我需要手動編寫所有程式碼(這裡沒有生成器)並安裝一堆程式庫,例如:Vite、prisma、express、react router、redux、redux-thunk 、 vitest、cypress 、react 測試庫、zod、typescript、eslint、prettier、1000 個不同的插件,甚至可能還有GraphQL 或tRPC。基本上就是一個已經有 900 個依賴項的 package.json。 在“railsscaffold”最初的震驚之後,當我從控制器打開程式碼時,我再次震驚了: ``` class ArticlesController < ApplicationController def index @articles = Article.all end def show @article = Article.find(params[:id]) end def new @article = Article.new end def create @article = Article.new(article_params) if @article.save redirect_to @article else render :new, status: :unprocessable_entity end end def edit @article = Article.find(params[:id]) end def update @article = Article.find(params[:id]) if @article.update(article_params) redirect_to @article else render :edit, status: :unprocessable_entity end end def destroy @article = Article.find(params[:id]) @article.destroy redirect_to root_path, status: :see_other end private def article_params params.require(:article).permit(:title, :body) end end ``` 這是所有後端程式碼嗎?只需幾行?這不可能!這非常簡單,看起來就像一個「低程式碼」工具。它簡單、優雅、可讀性極強,這是我們在 JS 領域很少見的。 好吧,好吧,你現在一定在想:「這個來自網路的瘋狂 React 開發者說他最終使用了 Elixir,所以 ruby 一定有問題!」。你是對的,我的匿名朋友,有些事情讓我很惱火,讓我們談談。 首先,我們需要解決房間裡的大象:從 React + Typescript 轉向動態類型語言並不容易。從我開始編寫程式碼的那一刻起,我的 VScode 上就沒有出現智慧感知或充滿程式碼建議的下拉式選單,我感到盲目和迷失。這是一種可怕的感覺,我可能會在函數名稱上輸入錯誤,直到網站投入使用時才意識到!我知道我們可以編寫測試,但這是我希望在 IDE 上立即辨識的錯誤類型,而不是在測試或部署期間辨識。 另一件我以為我會喜歡但最終討厭它的事情是:太多的魔法。在 Typescript 程式碼庫中,我可以點擊任何類別或函數的頂部,前往原始程式碼並查看其實作方式。在 Rails 上,我到底在哪裡進行驗證(例如)?我是否在控制器內建立私有函數?有專門的資料夾嗎?不,正確的位置是在模型內部。為什麼?因為這就是它的工作原理,所以您要么採用該約定,要么很難編寫 Ruby 程式碼。我根本無法對一切在幕後如何運作產生“直覺”,我必須盲目地相信維護者在組織一切方面做得很好。 為了解決我的挫折感,我開始寫前端程式碼。如何建立元件? [部分](https://guides.rubyonrails.org/layouts_and_rendering.html#using-partials)。如何定義該元件的 prop 類型?沒有辦法做到這一點,您需要打開它並直觀地查找其中的所有變數。做一些互動怎麼樣?建立國家?嗯,有帶有 [Stimulus](https://stimulus.hotwired.dev/) 的 Hotwire,但是正如您所看到的,您需要手動建立“重新渲染”功能,它沒有找到一種方法像React 這樣改變狀態後自動重新渲染頁面。 ``` // src/controllers/slideshow_controller.js import { Controller } from "@hotwired/stimulus" export default class extends Controller { static targets = [ "slide" ] initialize() { this.index = 0 this.showCurrentSlide() } next() { this.index++ this.showCurrentSlide() } previous() { this.index-- this.showCurrentSlide() } showCurrentSlide() { this.slideTargets.forEach((element, index) => { element.hidden = index !== this.index }) } } ``` 我再一次感到沮喪。我非常接近找到完美的框架!如果 Rails 失敗,我想嘗試的下一個框架是什麼?靈丹妙藥。 ### 長生不老藥和鳳凰 我必須說實話,我已經沒有耐心了。我嘗試了多種不同的生態系統,我幾乎確信要堅持使用 Ruby on Rails,並放棄對完美的追求。直到我的 YouTube 推薦部分出現了一個影片: https://www.youtube.com/live/bfrzGXM-Z88?si=Xsa7yCKeVSY5R3sT 堅持,稍等!在這裡我們可以看到一位 React 開發人員說了很多關於函數式程式設計、Elixir 和 Phoenix Live View 的好話。也許我應該嘗試一下! 我做的第一件事就是打開Elixir 和Phoenix 的文件,我真的很喜歡這樣一個事實:所有包都使用[Hex Docs](https://hexdocs.pm/) 以相同的方式進行記錄,您只需要取得習慣於單一介面以學習新事物。 另一個好處是,您只需閱讀文件即可真正學習 Elixir,無需昂貴的課程!在其他所有生態系統中,我必須透過付費課程學習語言,然後透過閱讀文件來學習框架。 然後是時候開始編寫程式碼了。很快我就明白函數式程式設計與 OOP 有很大不同。我們來做一個小小的比較: ``` // JS const obj = {name: "daniel"} obj.age = 25 // result: obj = {name: "daniel", age: 25} ``` ``` # Elixir obj = %{name: "daniel"} obj = Map.put(obj, :age, 25) # result: obj = %{name: "daniel", age: 25} ``` 或者您可以使用管道運算子透過更簡單的語法實現相同的效果: ``` # Elixir with pipe operator obj = %{name: "daniel"} |> Map.put(:age, 25) # result: obj = %{name: "daniel", age: 25} ``` 最初,您可能會發現它的可讀性較差且更複雜,但我保證隨著時間的推移它會變得有意義!嗯,至少對我來說是這樣。身為 React 開發人員,我已經習慣了到處都可以看到多個函數,甚至前端元件也是函數!更不用說建立類別有時被 JavaScript 黑手黨視為一種程式碼味道。我的大腦已經針對這種新範式進行了“塑造”,這對我來說很自然。自從我在大學獲得網路工程學位以來,我上過幾門關於物件導向程式設計的課程,但它從來沒有「受歡迎」。我無法將複雜的問題建模為類別和物件。隨著時間的推移,使用多個函數來「改變」一個變數是我在腦海中建模的方式。 主要框架怎麼樣?包含鳳凰電池嗎?約定優於配置? **是的!** 老實說,生態系統與 Rails 不在同一水平,但已經達到了 95%。除非您需要非常具體的功能,Phoenix 都能滿足您的需求。 我幾乎被 Elixir 迷住了,我的清單中缺少兩件事:良好的開發人員體驗和現代/高效能的前端程式碼。 José Valim 宣布他正在嘗試為該語言加入類型,但 Elixir 目前還沒有這些類型,所以我很擔心。如何在沒有類型的情況下獲得智能感知和自動完成?很快我發現這些功能不一定相關。在 VScode 上安裝 [ElixirLS 擴充功能](https://marketplace.visualstudio.com/items?itemName=JakeBecker.elixir-ls) 後,我感到很驚訝。可以在隨機資料夾的隨機模組內定義函數,將其導入其他位置,並取得它的智慧感知和文件!我從靜態類型語言中獲得了這些好處,而無需編寫類型的麻煩,簡直太棒了! https://elixir-lang.org/blog/2022/10/05/my-future-with-elixir-set-theoretic-types/ 我對前端的最後一個擔憂是由 Phoenix [Live View](https://hexdocs.pm/phoenix_live_view/welcome.html) 解決的。在程式碼方面,這正是文件主頁中讓我信服的部分: ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5sjzj90khytebnk523fm.png) 您可以為每個元件定義“props”,如果類型不匹配,您的 IDE 中會出現錯誤,就像 React 一樣!感人的! 使用者體驗怎麼樣?每當使用者點擊連結時是否會載入整個頁面?一定不行!即時視圖與客戶端建立 WebSocket 連接,然後每次頁面轉換只是透過 Websocket 進行內容交換,不會發出新的 HTTP 請求。此外,所有狀態都在伺服器端進行管理,這意味著 Trello 等豐富的用戶體驗過去由於加載過多的 JavaScript 而在客戶端非常卡頓,現在變得非常快! Elixir 處理所有複雜的狀態邏輯並將頁面的更新部分傳送到前端。看看這裡的完整解釋: https://youtu.be/wrmVk2czqMg?si=ZoWAlPjQC-svmV3Y 由於我們使用 WebSocket 來建立 UI,因此建立像 Twitter 這樣的「即時」應用程式只需要幾行程式碼! https://youtu.be/MZvmYaFkNJI?si=gAow6oIjgf8_OTkg ## 結論 可以肯定地說,「完美的技術堆疊」並不存在。解決所有問題的靈丹妙藥是我們在腦中創造的幻覺,以不斷尋找和建構最優化的工具。 然而,在個人層面上,完美的堆疊確實存在。因為每個開發人員都有偏好,您可以輕鬆找到適合您標準的工具。如果你有和我類似的旅程,完美的可能就是長生不老藥和鳳凰!所以試試看吧,也許你會像我現在一樣喜歡它。 如果您讀到了這篇文章的結尾,那您就太棒了!非常感謝您抽出寶貴的時間,希望我能為您的職業生涯帶來一些價值。 ![結束](https://media.giphy.com/media/lD76yTC5zxZPG/giphy.gif) --- 原文出處:https://dev.to/danielbergholz/from-nextjs-to-rails-then-elixir-my-journey-through-reactjs-burnout-h8d

極為簡單的 Python 專案結構與導入

喜歡這些文章嗎?買書吧! [***Jason C. McDonald 的《Dead Simple Python》可從 No Starch Press 取得。](https://nostarch.com/dead-simple-python) --- 教程最糟糕的部分始終是它們的簡單性,不是嗎?您很少會發現一個包含多個文件的文件,更罕見的是包含多個目錄的文件。 我發現**建立 Python 專案**是語言教學中最常被忽略的部分之一。更糟的是,許多開發人員都會犯錯,在一堆常見錯誤中跌跌撞撞,直到他們得到至少「有效」的東西。 好訊息是:您不必成為他們中的一員! 在《Dead Simple Python》系列的本期中,我們將探索「import」語句、模組、包,以及如何將所有內容組合在一起而不費力氣。我們甚至會涉及 VCS、PEP 和 Python 之禪。係好安全帶! # 設定儲存庫 在我們深入研究實際的專案結構之前,讓我們先討論一下它如何適合我們的版本控制系統 [VCS]…從您*需要* VCS 的事實開始!有幾個原因是... * 追蹤您所做的每一個更改, * 弄清楚你什麼時候弄壞了東西, * 能夠查看舊版的程式碼, * 備份您的程式碼,以及 * 與他人合作。 您有很多選擇。 **Git** 是最明顯的,尤其是當您不知道還可以使用什麼時。您可以在 GitHub、GitLab、Bitbucket 或 Gitote 等上免費託管 Git 儲存庫。如果您想要 Git 以外的東西,還有許多其他選擇,包括 Mercurial、Bazaar、Subversion(儘管如果您使用最後一個,您可能會被同行視為恐龍。) 我將悄悄假設您在本指南的其餘部分中使用 Git,因為這是我專門使用的。 建立儲存庫並將「本機副本」複製到電腦後,您就可以開始設定專案了。您至少需要建立以下內容: - `README.md`:您的專案及其目標的描述。 - `LICENSE.md`:您的專案的許可證(如果它是開源的)。 (有關選擇一個的更多訊息,請參閱 [opensource.org](https://opensource.org/)。) - `.gitignore`:一個特殊文件,告訴 Git 要忽略哪些文件和目錄。 (如果您使用其他 VCS,則該檔案具有不同的名稱。請尋找。) - 包含您的專案名稱的目錄。 沒錯...**我們的Python 程式碼檔案實際上屬於一個單獨的子目錄!** 這非常重要,因為我們的儲存庫的根目錄將變得非常混亂,其中包含建置檔案、打包腳本、虛擬環境以及各種方式其他實際上不屬於原始碼的內容。 僅為了舉例,我們將虛構的專案稱為「awesomething」。 # PEP 8 和命名 Python 風格主要由一組稱為 **Python 增強提案**(縮寫為 **PEP**)的文件管轄。當然,並非所有 PEP 都被實際採納——這就是它們被稱為「提案」的原因——但有些是被採納的。您可以在Python官方網站上瀏覽主PEP索引。此索引的正式名稱為 [PEP 0](https://www.python.org/dev/peps/)。 現在,我們主要關注 [**PEP 8**](https://www.python.org/dev/peps/pep-0008/),它最初由 Python 語言建立者 Guido van Rossum 於2001 年。該文件正式概述了所有Python 開發人員應普遍遵循的程式設計風格。把它放在枕頭下!學習它,遵循它,鼓勵其他人也這樣做。 (附註:PEP 8 指出樣式規則總是有例外。它是*指南*,而不是*命令*。) 現在,我們主要關注標題為 [“包和模組名稱”](https://www.python.org/dev/peps/pep-0008/#package-and-module-names)的部分。。 > 模組應該有簡短的、全小寫的名稱。如果可以提高可讀性,可以在模組名稱中使用下劃線。 Python 套件也應該有短的、全小寫的名稱,儘管不鼓勵使用底線。 我們稍後會了解*模組*和*包*到底是什麼,但現在,請了解**模組由檔案名稱命名**,而**套件由其目錄名稱命名**。 換句話說,**檔案名稱應全部小寫,如果可以提高可讀性,則使用下劃線。**同樣,**目錄名稱應全部小寫,如果可以避免,則不使用下劃線**。換句話說... + 執行此動作:`awesomething/data/load_settings.py` + 不是這個:`awesomething/Data/LoadSettings.py` 我知道,我知道,這是一種冗長的表達方式,但至少我在你的步驟中加入了一點 PEP。 (*你好?這個東西開著嗎?*) # 套件和模組 這會讓人感覺虎頭蛇尾,但這裡是那些承諾的定義: **任何Python(`.py`)檔案都是一個*模組*,目錄中的一堆模組是一個*套件*。** 嗯……差不多了。要讓目錄成為包,您還必須做另一件事,那就是將名為「__init__.py」的檔案貼到其中。實際上,您不必將任何內容*放入*該文件中。它必須在那裡。 您也可以使用`__init__.py` 做其他很酷的事情,但這超出了本指南的範圍,因此[請閱讀文件以了解更多資訊](https://docs.python.org/3/tutorial/modules.html#packages)。 如果你*確實*忘記了套件中的`__init__.py`,它會做一些比失敗更奇怪的事情,因為這使它成為一個**隱式命名空間包**。您可以使用這種特殊類型的套件做一些有趣的事情,但我不會在這裡討論。像往常一樣,您可以透過閱讀文件來了解更多:[PEP 420:隱式命名空間包](https://www.python.org/dev/peps/pep-0420/)。 所以,如果我們看看我們的專案結構,`awesomething` 實際上是一個包,它可以包含其他包。因此,我們可以將「awesomething」稱為我們的*頂級包*,以及其*子包*下的所有包。一旦我們開始進口東西,這將非常重要。 讓我們看一下我的現實專案“遺漏”的快照,以了解我們如何建置東西... ``` omission-git ├── LICENSE.md ├── omission │ ├── app.py │   ├── common │   │   ├── classproperty.py │   │   ├── constants.py │   │   ├── game_enums.py │   │   └── __init__.py │   ├── data │   │   ├── data_loader.py │   │   ├── game_round_settings.py │   │   ├── __init__.py │   │   ├── scoreboard.py │   │   └── settings.py │   ├── game │   │   ├── content_loader.py │   │   ├── game_item.py │   │   ├── game_round.py │   │   ├── __init__.py │   │   └── timer.py │   ├── __init__.py │   ├── __main__.py │   ├── resources │   └── tests │   ├── __init__.py │   ├── test_game_item.py │   ├── test_game_round_settings.py │   ├── test_scoreboard.py │   ├── test_settings.py │   ├── test_test.py │   └── test_timer.py ├── pylintrc ├── README.md └── .gitignore ``` (如果您想知道的話,我使用 UNIX 程式“tree”來製作上面的小圖。) 您會看到我有一個名為“omission”的頂級包,它有四個子包:“common”、“data”、“game”和“tests”。我還有“resources”目錄,但只包含遊戲音訊、圖像等(為簡潔起見,此處省略)。 `resources` 不是一個包,因為它不包含 `__init__.py`。 我的頂層包中還有另一個特殊檔案:`__main__.py`。這是當我們直接透過「python -m omission」執行頂級套件時執行的檔案。我們稍後會討論「__main__.py」中的內容。 # 導入如何進行 如果您以前編寫過任何有意義的 Python 程式碼,那麼您幾乎肯定熟悉「import」語句。例如... ``` import re ``` 知道當我們導入模組時,我們實際上是在執行它是有幫助的。這意味著模組中的任何“import”語句也正在執行。 例如,[`re.py`](https://github.com/python/cpython/blob/3.7/Lib/re.py#L122) 有幾個自己的 import 語句,當我們說 `導入重新`。這並不意味著它們可用於我們從*導入“re”的文件,但這確實意味著這些文件必須存在。如果(由於某種不太可能的原因)“enum.py”在您的環境中被刪除,並且您執行了“import re”,它將失敗並出現錯誤... > 回溯(最近一次呼叫最後一次): > 檔案“weird.py”,第 1 行,位於 <module> 中 > 進口再 > 檔案“re.py”,第 122 行,位於 <module> 中 > 導入枚舉 > ModuleNotFoundError:沒有名為「enum」的模組 當然,讀到這裡,你可能會有點困惑。有人問我為什麼找不到外部模組(在本例中為“re”)。其他人想知道為什麼要導入內部模組(此處為“enum”),因為他們沒有直接在程式碼中請求它。答案很簡單:我們導入了 `re`,然後導入了 `enum`。 當然,上面的場景是虛構的:「import enum」和「import re」在正常情況下永遠不會失敗,因為這兩個模組都是Python核心庫的一部分。這只是一個愚蠢的例子。 ;) # 匯入註意事項 實際上有多種導入方式,但其中大多數應該很少使用(如果有的話)。 對於下面的所有範例,我們假設有一個名為「smart_door.py」的檔案: ``` # smart_door.py def close(): print("Ahhhhhhhhhhhh.") def open(): print("Thank you for making a simple door very happy.") ``` 例如,我們將在 Python 互動式 shell 中執行本節中的其餘程式碼,執行位置與「smart_door.py」相同。 如果我們想執行`open()`函數,我們必須先導入模組`smart_door`。最簡單的方法是...... ``` import smart_door smart_door.open() smart_door.close() ``` 我們實際上會說“smart_door”是“open()”和“close()”的**命名空間**。 Python 開發人員非常喜歡命名空間,因為它們讓函數和其他內容的來源一目了然。 (順便說一句,不要將 *命名空間* 與 *隱式命名空間包* 混淆。它們是兩個不同的東西。) **Python 之禪**,也稱為 [PEP 20](https://www.python.org/dev/peps/pep-0020/),定義了 Python 語言背後的哲學。最後一行有一個聲明解決了這個問題: > 命名空間是一個非常棒的想法——讓我們做更多這樣的事情! 然而,在某種程度上,命名空間可能會變得很痛苦,尤其是對於嵌套包來說。 `foo.bar.baz.whatever.doThing()` 太醜了。值得慶幸的是,我們確實有辦法避免*每次*呼叫函數時都必須使用命名空間。 如果我們希望能夠使用 `open()` 函數,而不必總是在其前面加上模組名稱,我們可以這樣做... ``` from smart_door import open open() ``` 但請注意,「close()」和「smart_door.close()」在最後一個場景中都不起作用,因為我們沒有直接匯入該函數。要使用它,我們必須將程式碼更改為這樣... ``` from smart_door import open, close open() close() ``` 在之前可怕的嵌套包噩夢中,我們現在可以說“from foo.bar.baz.whatever import doThing”,然後直接使用“doThing()”。或者,如果我們想要一點命名空間,我們可以說“from foo.bar.baz importwhatever”,然後說“whatever.doThing()”。 “導入”系統非常靈活。 但不久之後,您可能會發現自己說“但是我的模組中有數百個函數,我想全部使用它們!”這是許多開發人員偏離軌道的地方,這樣做... ``` from smart_door import * ``` **這非常非常糟糕!** 簡而言之,它直接導入模組中的所有內容,這是一個問題。想像一下下面的程式碼... ``` from smart_door import * from gzip import * open() ``` 你認為會發生什麼事?答案是,「gzip.open()」將是被呼叫的函數,因為這是在我們的程式碼中導入並定義的「open()」的最後一個版本。 `smart_door.open()` 已被 **shadowed** - 我們不能稱之為 `open()`,這意味著我們實際上根本無法呼叫它。 當然,由於我們通常不知道,或者至少不記得每個導入的模組中的*每個*函數、類別和變數,所以我們很容易陷入一堆混亂。 *Python 之禪* 也解決了這個情況... > 顯式優於隱式。 您永遠不必“猜測”函數或變數來自何處。文件中的某個位置應該有程式碼“明確”告訴我們它來自哪裡。前兩個場景證明了這一點。 我還應該提到,早期的 `foo.bar.baz.whatever.doThing()` 場景是 Python 開發人員不喜歡看到的。也來自 *Python 之禪*... > 扁平比嵌套更好。 一些包的嵌套是可以的,但是當你的專案開始看起來像一套精緻的俄羅斯娃娃時,你就做錯了。將模組組織到包中,但保持相當簡單。 # 在您的專案中匯入 我們之前建立的專案文件結構即將「非常方便」。回想一下我的「遺漏」專案... ``` omission-git ├── LICENSE.md ├── omission │ ├── app.py │ ├── common │ │ ├── classproperty.py │ │ ├── constants.py │ │ ├── game_enums.py │ │ └── __init__.py │ ├── data │ │ ├── data_loader.py │ │ ├── game_round_settings.py │ │ ├── __init__.py │ │ ├── scoreboard.py │ │ └── settings.py │ ├── game │ │ ├── content_loader.py │ │ ├── game_item.py │ │ ├── game_round.py │ │ ├── __init__.py │ │ └── timer.py │ ├── __init__.py │ ├── __main__.py │ ├── resources │ └── tests │ ├── __init__.py │ ├── test_game_item.py │ ├── test_game_round_settings.py │ ├── test_scoreboard.py │ ├── test_settings.py │ ├── test_test.py │ └── test_timer.py ├── pylintrc ├── README.md └── .gitignore ``` 在我的“game_round_settings”模組中,由“omission/data/game_round_settings.py”定義,我想使用“GameMode”類別。類別在「omission/common/game_enums.py」中定義。我怎樣才能到達它? 因為我將“omission”定義為包,並將模組組織到子包中,所以實際上非常簡單。在“game_round_settings.py”中,我說...... ``` from omission.common.game_enums import GameMode ``` 這稱為**絕對導入**。它從頂級包“omission”開始,然後進入“common”包,在其中查找“game_enums.py”。 一些開發人員向我提供更像「from common.game_enums import GameMode」的導入語句,並想知道為什麼它不起作用。簡而言之,「data」套件(「game_round_settings.py」所在的位置)不知道其兄弟包。 然而,它確實知道它的父母。正因為如此,Python 有一種叫做「相對導入」的東西,它可以讓我們做同樣的事情,就像這樣... ``` from ..common.game_enums import GameMode ``` `..` 表示“此套件的直接父包”,在本例中為“omission”。因此,導入後退一級,進入“common”,並找到“game_enums.py”。 關於是否使用絕對導入或相對導入有許多爭論。就我個人而言,我更喜歡盡可能使用絕對導入,因為它使程式碼更具可讀性。不過,您可以自己做決定。唯一重要的部分是結果是「顯而易見的」——任何東西的來源都不應該是神秘的。 (繼續閱讀:[Real Python - Python 中的絕對導入與相對導入](https://realpython.com/absolute-vs-relative-python-imports/) 這裡還隱藏著另一個陷阱!在 `omission/data/settings.py` 中,我有這一行: ``` from omission.data.game_round_settings import GameRoundSettings ``` 當然,由於這兩個模組都在同一個包中,我們應該可以直接說“from game_round_settings import GameRoundSettings”,對嗎? *錯誤!* 它實際上無法找到“game_round_settings.py”。這是因為我們正在執行頂級包“omission”,這意味著**搜尋路徑**(Python 查找模組的位置以及順序)的工作方式不同。 但是,我們可以使用相對導入來代替: ``` from .game_round_settings import GameRoundSettings ``` 在這種情況下,單一“.”表示“這個包”。 如果您熟悉典型的 UNIX 檔案系統,這應該開始有意義。 `..` 表示“後一級”,“.` 表示“目前位置”。當然,Python 更進一步:`...` 表示“後兩級”,`....` 表示“後三級”,依此類推。 但是,請記住,這些「等級」不僅僅是簡單的目錄。他們是包裹。如果在一個不是包的普通目錄中有兩個不同的包,則不能使用相對導入從一個包跳到另一個包。為此,您必須使用 Python 搜尋路徑,但這超出了本指南的範圍。 (請參閱本文末尾的文件。) # `__main__.py` 還記得我提到在我們的頂級包中建立一個 `__main__.py` 嗎?這是一個特殊的文件,當我們直接使用 Python 執行套件時會執行該文件。我的“omission”包可以使用“python -m omission”從我的存儲庫的根目錄執行。 這是該文件的內容: ``` from omission import app if __name__ == '__main__': app.run() ``` 是的,實際上就是這樣!我正在從頂級包“omission”導入我的模組“app”。 請記住,我也可以說「來自…」。改為導入應用程式。或者,如果我只想說“run()”而不是“app.run()”,我可以執行“from omission.app import run”或“from .app import run”。最後,只要程式碼可讀,我如何進行導入並沒有太大的技術差異。 (附註:我們可以爭論為我的主要`run()` 函數設定一個單獨的`app.py` 對我來說是否合乎邏輯,但我有我的理由......而且它們超出了本指南的範圍。 ) 首先讓大多數人感到困惑的部分是整個「if __name__ == '__main__'」語句。 Python 沒有太多**樣板** - 必須非常普遍地使用且幾乎不需要修改的程式碼 - 但這是那些罕見的位元之一。 `__name__` 是每個 Python 模組的特殊字串屬性。如果我將“print(__name__)”行貼在“omission/data/settings.py”的頂部,當該模組被導入(並因此執行)時,我們會看到“omission.data.settings”被打印出去。 當模組直接透過「python -m some_module」運作時,模組會被指派一個特殊值「__name__」:「__main__」。 因此,「if __name__ == '__main__':」實際上是在檢查該模組是否以 *main* 模組執行。如果是,它將在條件下執行程式碼。 您可以透過另一種方式看到這一點。如果我將以下內容加入到“app.py”的底部... ``` if __name__ == '__main__': run() ``` ……然後我可以直接透過 `python -m omission.app` 執行該模組,結果與 `python -m omission` 相同。現在`__main__.py`被完全忽略,`omission/app.py`的`__name__`是`"__main__.py"`。 同時,如果我只是執行“python -m omission”,“app.py”中的特殊程式碼將被忽略,因為它的“__name__”現在又是“omission.app”。 看看效果如何? # 總結 我們來複習。 * 每個專案都應該使用 VCS,例如 Git。有很多選項可供選擇。 * 每個 Python 程式碼檔案 (`.py`) 都是一個 **模組**。 * 將您的模組組織到**包**中。每個包必須包含一個特殊的「__init__.py」檔案。 * 您的專案通常應由一個頂級包組成,通常包含子包。該頂級包通常共享您的專案的名稱,並作為專案存儲庫根目錄中的目錄存在。 * **永遠不要**在導入語句中使用「*」。在考慮可能的例外之前,Python 之禪指出「特殊情況並沒有特殊到足以違反規則」。 * 使用絕對或相對導入來引用專案中的其他模組。 * 可執行專案的頂層套件中應該有一個`__main__.py`。然後,您可以使用「python -m myproject」直接執行該套件。 當然,我們可以在建立 Python 專案時使用許多更高級的概念和技巧,但我們不會在這裡討論。我強烈建議閱讀文件: + [Python 參考:導入系統](https://docs.python.org/3/reference/import.html) + [Python 教學:模組](https://docs.python.org/3/tutorial/modules.html) + [PEP 8:Python 風格指南](https://www.python.org/dev/peps/pep-0008/) + [PEP 20:Python 之禪](https://www.python.org/dev/peps/pep-0020/) + [PEP 240:隱式命名空間套件](https://www.python.org/dev/peps/pep-0420/) --- *感謝 `grym`、`deniska` (Freenode IRC `#python`)、@cbrintnall 和 @rhymes (Dev) 提出的修改建議。* --- 原文出處:https://dev.to/codemouse92/dead-simple-python-project-structure-and-imports-38c6

每個開發者都必須知道的 12 個網站 🤩

**開發者們大家好!** 歡迎來到我的另一篇博文。 在這篇文章中,我想分享一些每個開發人員都必須了解的基本網站或工具。 所以讓我們**開始**👇並且不要**忘記**“💖🦄🔥”。 --- ## 1. [omatsuri.app](https://omatsuri.app) 🍡 ![omatsuri](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ic3rw7rpncvtsbas0an9.jpeg) Omatsuri 是一個提供網頁開發人員資源的日本網站。 “Omatsuri”,一個漸進式 Web 應用程式 (PWA),提供 **12 個開源前端工具的集合**。 這些資源**免費使用**和自訂,這在您設計新網站或應用程式時非常有幫助。 --- ## 2. [htmlrev.com](https://htmlrev.com/) 📄 ![htmlrev](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qa8wq2cfu7bn12h34l85.jpeg) HTMLrev 是一個**尋找 HTML 範本**和設計資源的絕佳網站。 他們為網站、登陸頁面、部落格、作品集等提供免費的 html 模板。 這些模板隨時可用且易於自訂。這是滿足您所有範本需求的一站式場所。 --- ## 3. [Unicornicons.com](https://unicornicons.com/) 🦄 ![unicorcicons](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zb4alzy6dmxa67p4prfk.jpeg) Unicornicons 擁有**漂亮的動畫圖示**,您可以在專案中使用它們。 他們有高級圖標包,但也提供許多**免費圖標**。這些圖標有助於使介面更具吸引力和樂趣。 您還可以輕鬆自訂顏色。 --- ## 4. [UiVerse.io](https://uiverse.io/)✨ ![uiverse](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iko1dy9qzowtp0m2pxs4.jpeg) UiVerse 是一個使用 CSS 和 Tailwind 建立的 UI 元素社群。 他們擁有超過 **3000 個元素,可以在 MIT 許可下免費**使用。 這對於建立 UI 元件並節省開發時間非常有用。您可以搜尋、篩選元素並直接取得要複製的程式碼。 --- ## 5. [undraw.co](https://undraw.co/illustrations) 🖌 ![取消繪製](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ejqgeh89p0m4bxhqres4.jpeg) Undraw 是一個開源插圖函式庫。他們提供**美麗的 SVG 插圖**,您可以免費使用。 這些插圖很現代,可以輕鬆自訂。這對於登陸頁面、有關部分和產品行銷的內容非常有幫助。 他們也不斷加入新的插圖。 --- ## 6. [patternpad.com](https://patternpad.com/) 🎨 ![patternpad](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o1dmudn1m4qkn5kb4ukl.jpeg) PatternPad 讓您設計來自無限顏色和形狀變化的圖案。您可以在這裡非常輕鬆地**建立獨特的品牌模式**、簡報、社交貼文等。 圖案匯出為 SVG 以供靈活使用。這是一個很好的工具,可以為您的設計增添視覺吸引力。 --- ## 7. [shapeivider.app](https://www.shapeivider.app/) 🗺 ![shapeivider](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e2rofzquhdbh1rh0zd4z.jpeg) ShapeDivider 可協助您非常輕鬆地**在**標題、段落或部分之間新增曲線形狀。它是設計中經常使用的技術。 該網站允許您透過選擇形狀和顏色類型來產生程式碼。您可以**直接複製並貼上程式碼**。非常有用的工具! --- ## 8. [photopea.com](https://www.photopea.com/) 📸 ![photopea](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/811c325yaic55z5dyxnm.jpeg) Photopea 是一款線上照片編輯器,支援 PSD、XCF、Sketch、XD 和 CDR 格式。 **您可以免費開啟、編輯和儲存照片**,無需安裝任何軟體。 它具有類似於 Photoshop 的工具,但對初學者非常友好。這非常適合開發人員的基本影像編輯需求。 --- ## 9. [quickref.me](https://quickref.me/) 🧑‍💻 ![quickref](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/we3ozwf4mz5emjduqs9g.jpeg) QuickRef 是各種**開發人員工具、框架和技術**的備忘單集合。它們涵蓋了從程式語言、資料庫、設計工具到終端命令的所有內容。 這些備忘單可以幫助您更快學習,並且在開發過程中也非常方便。 **將此加入書籤!**。 --- ## 10. [devdocs.io](https://devdocs.io/) 📚 ![devdocs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dfm13a7p6avflurnp7kc.jpeg) DevDocs 為許多程式庫和框架提供 API 文件。 **它從各種來源收集文件**並以有組織的方式呈現它們。 在開發過程中,經常需要參考文件。該網站使您可以輕鬆快速地找到所需的內容。 --- ## 11. [devhints.io](https://devhints.io/) 📝 ![devhints](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/233ziqtf3v6e0w9lkgyn.jpeg) Devhints 包含各種技術和工具的簡明備忘單。這些就像**開發人員的袖珍參考卡**。該資訊清晰呈現,沒有額外的細節。 他們專注於最重要的功能。這是一個很棒的網站,可以找到快速提醒。 --- ## 12. [開發工具](https://developer.chrome.com/docs/devtools/) 🛠 Chrome 開發者工具或 DevTools 是一套強大但有時令人難以抗拒的 Web 開發者工具。 developer.chrome 上的文件可協助您掌握這些工具。它涵蓋了每個面板的使用、鍵盤快捷鍵以及提示和技巧。任何開發人員都不應忽略 Chrome DevTools 文件。 --- ## 就是這樣😁 感謝您閱讀這篇部落格🙏,我希望這能為您帶來一些新的去處! 如果您發現任何其他有用的網站,請發表評論📩。 並且不要忘記加上“💖🦄🔥” **快樂編碼👋** --- 原文出處:https://dev.to/random_ti/top-12-websites-that-every-developer-must-know-2a67

3 個讓你陷入困境、沮喪和薪資過低的程式設計神話 🔮

如果我告訴你,你覺得自己在開發者職涯中陷入困境的原因與你的技術技能無關,你會怎麼想? 它與資料結構、系統設計或軟體架構無關。 但這與你如何看待整個程式設計有關。 你看,自從你開始編碼以來,你就已經習慣於相信某些關於成為開發人員的神話,這些神話正在毀掉你的職業生涯。這就是為什麼你會患上冒名頂替症候群並懷疑自己的技能。讓你停留在同一水平,感到沮喪和工資過低。 更糟的是,這些信念深深植根於我們作為開發人員的日常生活中,以至於我們將它們視為理所當然。我們甚至不質疑他們。因為我們認為它們是現實。 事實上,它們只是社區流傳的神話。 尚未被揭穿的神話。部分原因是它們在紙上聽起來不錯。事實上,它們是危險的偏見,阻礙你走出去,建立你應得的未來。 在這篇文章中,我們將一一揭穿這些神話。 因此,您可以擺脫限制性信念,為最重要的目標採取行動,並釋放您作為開發人員的全部潛力。 讓我們從第一個讓你陷入困境的程式設計神話開始... # 1. 激情的神話 激情神話說,偉大的開發人員都非常熱情。他們在晚上編碼,在週末編碼。晚上,他們用程式碼做夢。 如此充滿熱情的程式設計師可以無休無止地編寫無數小時的程式碼。他們甚至沒有註意到這一點。當然,因為他們是如此熱情。 如果你沒有足夠的熱情去吃飯、睡覺、編碼和重複,那麼你應該收拾行李,找點別的事情做。我的朋友,開發人員不適合你。 去找點別的事做吧。聽說麥當勞要招募了 這是一個多麼糟糕的訊息,特別是對於剛開始的新開發人員。 開發人員和軟體公司都延續著激情的神話。 首先是那些試圖推銷自己並取得成功的開發商。部分是透過展示他們有多麼熱情。我不怪他們。我們都以某種方式這樣做。我所指出的只是這種行為的負面後果。 其次,激情的神話是由公司宣揚的。 充滿熱情的人對生意很有好處。因為他們願意廉價地出賣自己的時間。他們在辦公室度過數百個小時,讓別人變得富有。因為他們對自己所做的事情充滿熱情。 他們用這些無薪時間換取了什麼? 我想這與他們的工作有情感連結。一種歸屬感。欣賞和目的。這些都是非常強大的藥物。 但是,你猜怎麼著……你不需要把你的時間免費交給一些自稱是家庭的公司來獲得這些感覺。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jgar23217i4mys7obwa8.png) 把你的時間留給你真正的家人。當你沒有攪拌足夠多的程式碼行時,它不會把你踢出去。 擁有平衡的生活,編碼不會佔用您大部分時間。 交朋友並在工作之餘擁有自己的嗜好。你也會得到同樣的滿足。除了讓你的時間回來! 激情的神話是危險的,因為它以另一種方式告訴你,首先,你還不夠(在這種情況下不夠熱情)。 > ‍“程式設計不是一種“激情”或“天賦”,而是後天技能的集合。” - Jacob Kaplan-Moss(Django、Python 框架的共同建立者) 激情神話之所以如此危險,是因為它會觸動你作為開發人員最大的恐懼,特別是如果你是自學成才的話。 害怕「你還不夠」。 激情神話的第二個基本訊息是你工作不夠努力。 這會讓你越來越努力,忽視你的健康和家庭,導致倦怠。這就是為什麼有些公司是有毒的工作場所。 事實上,最好的軟體開發人員都非常懶惰。這就是為什麼他們嘗試設計事物並提高效率,而不是用蠻力解決問題。 根據我的經驗,開發人員成為高級開發人員的標誌之一就是不必在周末編碼。 **高級開發人員選擇一致性而不是熱情。** 生產力突飛猛進,穩定進步。他們知道「激情」來來去去。太多的熱情會導致倦怠。 當時間流逝時,經驗豐富的開發人員就會停止熱情。他們合上筆記型電腦並離開了辦公室。 有趣的部分? 透過暫時遠離編碼,他們第二天回來時會更加新鮮,並渴望親自動手。 如果您想充分發揮開發人員的潛力,請忘記激情的神話。 相反,要注重平衡和一致性。作為一個已經編碼十多年的人,我可以告訴你開發人員的職業生涯是一場馬拉松。 現在來談談阻礙程式設計師前進的第二個誤解… 🚨附言您是否希望透過優質資源、回饋和問責制快速晉升為高階職位? [點擊此處加入我們的免費社區 - 高級開發學院。](https://bit.ly/3So6BWF)🚨 # 2. 經驗的神話 如何晉升資深開發人員?如何獲得技術主管?您如何獲得更多責任或加薪? 傳統的建議會告訴你沒有靈丹妙藥。你只是需要更多的經驗。所以堅持住。當你的眼睛有皺紋、背部疼痛時,你可能會到達那裡。或者你可能不會。我們不確定。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8c80tlzipjx0uc2cusmb.png) _閱讀 LinkedIn 上的開發人員職位發布後的感受如何。圖片來源:Reedit._ 儘管經驗確實很重要,但這個神話被過度使用了。 首先,並非所有經驗都是平等的。 人們可以在快節奏的新創公司待一年,然後看到它成長。學習如何從幾百個用戶擴展到數百萬個。 或花一年時間維護公司中的一些遺留企業軟體。除了發送格式良好的電子郵件和辦公室政治之外,學到的東西很少。 **注意**:相反的情況也可能發生。你在新創公司中什麼也學不到,因為產品永遠不會受到關注,而你在企業中學到很多東西,因為他們已經擁有了規模。 以編寫程式碼年數表示的經驗並不能很好地顯示開發人員的資歷。單獨的時間並不能轉化為學習。重要的是你在這段時間裡做什麼。 雖然晉升高級可能沒有靈丹妙藥,但有一定的模式。 如果開發人員模仿這些模式,他們可以大大加速他們的成長。這就是為什麼你會發現擁有 3 年經驗的開發人員拿著 6 位數的薪水,而一些高級開發人員在月底仍然難以支付賬單。 這種經驗神話阻礙了你,因為傳達的訊息是相同的:你還不夠(以你沒有足夠的形式)。 我是說沒有經驗就能出人頭地嗎?沒有任何這些你就可以成為高級開發人員嗎? 不。 但不要高估時間的價值。相反,你應該看重的是執行力。當你划船時,船的移動速度比你只是等待水流時要快。 經驗神話長期存在有兩個主要原因。 ### 第一,缺乏知識。 當你問高級開發人員需要什麼才能達到下一個級別,而他們不知道所需的確切技術和軟技能時,他們只會遵循多年的經驗,而不會顯得愚蠢。 ### 第二,不安全感。 如果高級開發人員看到您試圖比他們更快地行動,那麼人類精神中醜陋的部分就會發揮作用。在一個聲稱如此開放和友好的行業中,嫉妒是很常見的。像軟體開發人員這樣非常聰明的人通常也非常雄心勃勃。 軟體開發是一個競爭非常激烈的行業。 我們同時合作和競爭。只要我們確保競爭公平並且不欺騙自己就可以了。 經驗神話是一種不公平的競爭方式。我們不關注人們的才能和技能,而是更關注他們履歷中的任意數字。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p1x8wzlhufxndjvnzfff.png)_雞生蛋蛋生雞的問題。圖片來源:theSeniorDev_ 為了擺脫體驗神話,轉移你的注意力。更關心你的技能而不是你在某項工作上花費的時間。 如果當你提出要求時,有人以沒有足夠的「多年經驗」為由,不要讓他們阻止你。完善你的履歷和技能,開始進行技術面試,然後讓市場來決定。 🚨附言您是否希望透過優質資源、回饋和問責制快速晉升為高階職位? [點擊此處加入我們的免費社區 - 高級開發學院。](https://bit.ly/3So6BWF)🚨 # 3.人工智慧的神話 現在是 2024 年,你學習如何編碼是沒有意義的。或如何成為更好的開發人員。很快,人工智慧將取代我們所有人!編碼工作即將結束,為什麼還要費心? 人工智慧的神話已經存在了幾十年。但直到 ChatGPT 和 Github Copilot 發布之前,它從未如此存在。 那麼,為什麼要費心去成為更好的開發人員呢? ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5p0bdqsgymof1l6p1197.png) 軟體開發本來就很困難,現在你有一個完美的藉口放棄它。 甚至不會被認為是失敗。你可以將其歸咎於開放人工智慧。 沒那麼快。 我會給你兩個理由說明為什麼你還是應該費心。 繼續程式設計的第一大原因是你正在學習的「元」技能。這些都是技能背後的技能。 當你學習如何編碼時,你就是在學習如何思考。以結構化的方式思考。您正在學習如何將業務需求建模為逐步說明。您正在學習如何集中註意力、如何過濾資訊以及如何在團隊中工作。 即使機器本身很快就會完成實施和編碼,這些「元技能」也非常有價值。 繼續敲擊鍵盤的第二個原因是,從我們迄今為止所看到的情況來看,人工智慧工具會犯下許多錯誤。它們是預測機器。他們無法思考。人類推理仍有需求。 這些人工智慧工具會變得更聰明嗎? 大概。 它們會在不久的將來取代人類嗎?可能不會。 你猜怎麼著,如果你不再閱讀那些關於人工智慧將如何取代你的偏執文章,而是真正在軟體開發方面做得更好,你很可能永遠不會被取代。 或者,當這種情況發生時,您已經在某個充滿異國情調的海灘上退休了。 ####老年的比喻。 想像一下你已經 50 歲了。機器贏了。他們將一切自動化。但是,你不斷學習、適應和學習新技能。賺大錢,投資養老。你現在很聰明,而且已經退休了。 假設你陷入了目前正在發生的人工智慧偏執狂。你放棄了編碼。你做了一些被標記為人工智慧免疫的事情(不知道是否存在,但建築工作是最重要的)。 你賺了一些錢,但沒學到多少東西,同時也毀了你的身體。你現在老了,想要一份辦公室工作。理想的情況是遙遠的事。 你對如何實現這一點的了解為零。您繼續編碼的開發人員夥伴在打高爾夫球方面表現得很好。 屈服於恐懼毀了你的生活。 不要因恐懼而屈服。永遠不要停止學習和進步。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cxbo16iwsvmot92oxinn.png)_圖片來源:theSeniorDev_ 繼續變得更好。提升整個堆疊的技能。熟悉人工智慧。幾個月後,你就會迎頭趕上,並慶幸自己沒有放棄。 **為什麼這些程式設計神話如此有效?** 因為它們觸及了身為開發人員最大的恐懼之一。 害怕你還不夠。還不足以得到那份工作。不足以讓拉取請求獲得批准。還不足以成為「真正的開發人員」。 希望讀完本文後,您能夠認清這些神話的真相。純粹的誤解阻礙了你。 不要屈服於恐懼,不斷提升你的技能。 直到下一篇, 德拉戈斯 🚨附言您是否希望透過優質資源、回饋和問責制快速晉升為高階職位? [點擊此處加入我們的免費社區 - 高級開發學院。](https://bit.ly/3So6BWF)🚨 --- 原文出處:https://dev.to/dragosnedelcu/3-programming-myths-that-keep-you-stuck-frustrated-and-underpaid-27bg

Deno 入門

如果你錯過了,Node 的建立者 Ryan Dahl 的新 Javascript 和 Typescript runtime[已發布](https://deno.land/)!它有一些非常酷的功能,可供公眾使用!讓我們來看看一些簡潔的功能,並開始建立一個簡單的 hello world! ## 什麼是 Deno? Deno 是 Typescript(和 Javascript)的新runtime,主要用 Rust 寫。它有一些[偉大的目標](https://deno.land/manual.html#goals)和一些非常有趣的“非目標”,例如不使用`npm`並且沒有package.json。 ## 安裝 安裝 deno 就像執行以下命令一樣簡單: `curl -fsSL https://deno.land/x/install/install.sh |噓` 然後複製“export”行並將其新增至“~/bashrc”或“~/bash_profile”中。 打開一個新終端並執行“deno”。您應該會收到“>”提示。輸入“exit”,讓我們深入研究一些功能! ## Deno 中的酷功能 ### 預設打字稿 預設情況下,整合 Deno 來執行 Typescript 檔案。它基本上使 Javascript 中的類型成為一等公民。不再需要透過 Babel 編譯來在伺服器端 Javascript 中使用 Typescript。 ### 從 URL 導入 Deno 允許您從網頁匯入,就像在瀏覽器中一樣。只需在您通常命名模組的位置新增一個 URL: ``` import { bgBlue, red, bold } from "https://deno.land/std/colors/mod.ts"; ``` ### 標準庫 此外,Deno 有一個易於導入和使用的標準函式庫。有些模組可以執行多種不同的操作,例如 HTTP 處理、日期時間工作和檔案系統工作。您可以在[此處](https://github.com/denoland/deno_std)查看。 ### 使用 ES 模組 最後,Deno 僅支援 ES 模組語法,這表示不再需要 `require()` 語句,只需良好的 ole' `import x from "y"`。 ## 你好世界範例 讓我們快速看一下 Hello World,其中重點介紹了其中一些功能! 將其複製到“hello-world.ts”檔案中。 ``` import { bgBlue, red, bold } from "https://deno.land/std/colors/mod.ts"; const sayHello = (name: string = "world") => { console.log(bgBlue(red(bold(`Hello ${name}!`)))); } sayHello(); sayHello("Conlin"); ``` 現在您可以使用“deno hello-world.ts”執行它,它應該會列印出一些內容。 將“sayHello”呼叫之一更改為“sayHello(15);”並重新執行它。您應該看到類型錯誤,因為 15 不是字串!太酷了! 您還會注意到如何從 URL 導入 - 它從標準庫中獲取一些控制台顏色內容! # 最後的想法 Deno 還沒有完全準備好用於生產 - 有幾個 [bug](https://deno.land/benchmarks.html#req-per-sec),但開發正在快速推進!這絕對是一個很酷的新開源專案,值得關注! --- 原文出處:https://dev.to/wuz/getting-started-with-deno-e1m

✨ 5 個被低估的開源專案 🫵🤐

## 簡介 本文列出了五個不太受歡迎的優秀專案,您應該嘗試一下。 🔥 這些工具旨在改進**資料處理**、**API 開發**、**後端測試**、**身份驗證**和**安全隧道**。 諸如此類的開源專案依賴社群支持🙏,因此請考慮探索並為這些儲存庫加註星標,以促進它們的發展。 ![擁抱 GIF](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rxhja1odmmx414wrts5a.gif) *** ## 1. [集算器](http://scudata.com) **- 資料處理** > 💡 集算器是一種用於資料處理的腳本語言,具有豐富的函式庫函數和強大的語法。 ![集算器資料處理腳本語言](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z9dts1lgr1zy96k6zveu.jpg) 集算器是一個針對結構化和半結構化資料的計算和處理引擎。集算器既不是SQL系統,也不是NoSQL技術(如MongoDB),而是採用自創的SPL(結構化處理語言)語法,編碼更簡單,可以利用現有的資料處理技術建立高效的程式。 集算器是**純Java**編寫的,可以輕鬆為您的Java🍵應用程式加入強大的資料處理功能,但非Java應用程式可以透過RESTful API呼叫集算器。 ### 熱門常見問題解答🤔 > **⬇️集算器可以執行在哪些平台上?** 由於它純粹是用 Java 建置,因此可以在任何配備 JVM(Java 虛擬機)、雲端伺服器甚至容器的作業系統中流暢執行。 😎 > **⬇️集算器可以基於現有資料庫運作嗎?** 是的當然!集算器支援數十種資料來源,包括資料庫、文字、excel、json/xml、web服務等。 > **⬇️ 為什麼要放棄 SQL 而選擇集算器?** 簡化的逐步程式碼,易於編寫和除錯。相較於SQL降低N倍的開發、硬體、維運成本。 > 🟢我最近寫了一篇關於這個工具的文章,重點介紹了它的強大功能。看看吧👇。 https://dev.to/shricodev/one-must-have-tool-for-anyone-in-data-field-2jek > 如果你想更深入地了解這個工具的潛力,**[jbx1279](https://dev.to/jbx1279)**分享了一些關於集算器和SPL本身的富有洞察力的文章。請務必也檢查一下它們。 https://github.com/SPLWare/esProc *** ## 2. [Firecamp](https://firecamp.dev/) **- 郵差替代方案** > 💡 API 開發平台,幫助開發人員輕鬆設計、開發、測試和記錄他們的 API。 ![Firecamp 工具 Postman 替代品](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uigr65jz5z6yh731x9gm.jpg) Firecamp 是開放原始碼 Postman 的替代方案,具有 VScode DX,這是一個優先考慮開發人員體驗的 API 開發平台,並為設計、測試和記錄 API 提供無縫環境。 🎯 借助 Firecamp,跨工作區和團隊就 API 集合進行協作,並更快地建立 API,而無需在工具和應用程式之間切換。文件、CLI、CI/CD 一站式提供。 > **⬇️ 從 Postman 切換到 Firecamp 對我來說有挑戰性嗎?** 您可以將 Postman 腳本和資料(例如 **API Collection** 和 **環境變數**)無縫傳輸到 Firecamp,沒有任何問題。 ![Firecamp Postman 替代方案](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q74wl17yc9b7clse6m3h.png) https://github.com/firecamp-dev/firecamp *** ## 3. [Keploy](https://keploy.io/) **- 後端測試** > 💡 為您的應用程式產生實際有效的測試和存根! ![Keploy 產生後端測試](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ry5awt5wtk5qyiqccbwp.jpg) Keploy 是您的開源、以開發人員為中心的後端測試工具。它使工程團隊的後端測試變得簡單且有效率。使用 Keploy,我們不必編寫手動測試用例。 它記錄 API 互動和預期回應,並產生測試案例和資料模擬,使我們的工作變得輕鬆高效,顯著加快發布速度並增強可靠性。 📈 > **⬇️ 它是一個單元測試框架嗎?還是它完全取代了單元測試?** Keploy 與「go-test」、「Pytest」或「Jest」等單元測試框架配合得很好,可簡化測試流程並節省高達 80% 的工作。雖然它涵蓋了大多數情況,但您仍然可以選擇為非 API 可呼叫方法編寫測試。 > **⬇️ 我需要更改程式碼才能將 Keploy 整合到我的應用程式中嗎?** 不需要。Keploy 可以很好地與您現有的程式碼庫配合,無需更改程式碼。 ![Keploy 後端測試示範](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kdsnkmq2efgxltzplfq9.gif) https://github.com/keploy/keploy *** ## 4. [Hanko](https://hanko.io) **- 金鑰驗證** > 💡 支援 FIDO2 和 WebAuthn 標準的無密碼身份驗證伺服器。 ![Hanko 金鑰驗證](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aqifvf1i536y0afh7nhe.jpg) Hanko 是一款輕量級開源用戶身份驗證解決方案,可帶您踏上超越密碼的旅程。它支援 FIDO2 和 WebAuthn 標準,提供安全、無縫的使用者身份驗證體驗。 > **⬇️ Hanko 如何運作?** Hanko 的工作原理是使用使用者自己的裝置(例如智慧型手機、筆記型電腦或安全金鑰)註冊和驗證使用者。這些裝置可作為加密令牌,無需密碼或其他憑證即可證明使用者的身分。 Hanko 還支援各種身份驗證方法,例如行動應用程式中的生物辨識或 OAuth 登入。 > **⬇️ 我該如何開始使用 Hanko?** 您可以透過註冊免費帳戶並按照文件和教學課程開始使用 Hanko。對於生產用途,請選擇 Hanko Cloud。 > 🟢 我最近使用 Hanko Passkeys 身份驗證建立了一個專案。查看**[此處](https://github.com/shricodev/pdfwhisper-openai)**。 ![Hanko 登陸頁](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/emte4gfglhdft8g8dlhh.png) https://github.com/teamhanko/hanko *** ## 5. [Zrok](https://zrok.io/) **- Ngrok 類固醇** > 💡 Ngrok 的替代品,提供增強的功能和免費的 SaaS 型號。 ![Zrok ngrok 替代方案](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x4n31emowwxoamfqzawm.jpg) Zrok 是一個建立在 **OpenZiti** 之上的工具,有助於共享正在執行的服務,例如 Web 伺服器或網路套接字,或安全地將靜態檔案目錄共享到網際網路。它是 Ngrok 的替代品,但具有一些增強功能和**免費 SaaS** 型號。 借助 Zrok,您可以為應用程式建立安全隧道,從而更輕鬆地共享和協作專案。 > **⬇️ 使用 Zrok 相對於 Ngrok 有什麼好處?** Zrok 擁有內建的身份驗證系統、用於管理隧道的 Web 儀表板以及免費的 SaaS 模型。它也是完全**可自我託管**。 > **⬇️ 我該如何開始使用 Zrok?** 若要開始使用 Zrok,請下載適合您平台的 Zrok 用戶端或使用 Web 介面建立隧道。您也可以使用 Zrok CLI 從命令列建立和管理隧道。 ![Zrok 安全隧道](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bp8bguor0wj3i8h6ail1.png) https://github.com/openziti/zrok *** > 如果您認為您使用的任何其他方便的專案沒有應有的受歡迎,請在下面的評論部分分享。 👇 非常感謝您的閱讀! 🎉🫡 --- 原文出處:https://dev.to/shricodev/top-5-underrated-open-source-projects-that-no-one-talks-about-2gki

🥇最好的 Web 框架並不存在 🚫

**簡介** 您選擇的 Web 應用程式框架並不重要。嗯,這很重要,只是不像別人希望你相信的那麼重要。 2024 年存在如此多的庫和框架,並且最好的庫和框架[仍在激烈爭論](https://joshcollinsworth.com/blog/self-fulfilling-prophecy-of-react)這一事實證明了我的觀點。這是網頁開發人員最大的「第一世界問題」——一個實際上並不是問題的問題。在馬斯洛的開發者需求層次結構中,它絕對接近頂部(好吧,這是我編的😅) ![開發需求](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/412awt20ksr3d44a4b7b.jpeg) 例如,根據 [StateOfJS](https://2022.stateofjs.com/en-US/libraries/front-end-frameworks/) 2022 年調查(我們仍在等待 2023 年結果),2018年留存率較高的前端框架有5個; 2022 年有 11 個。這在 4 年內增長了 120%,這甚至沒有考慮到像 NextJS、SvelteKit 或Astro ! ![多年來的框架](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/94zifqs2ui1rxt9kc0yw.png) 總體而言,這些都是該領域的巨大發展。它們提高了開發人員速度、捆綁包大小、效能和開發人員體驗等。但它們也讓開發人員和團隊在嘗試決定在下一個專案中使用哪一個時很難做出決定。對於初學者來說更糟糕,這可能是為什麼他們只選擇 React 這個最「主流」的解決方案。 我認為這一切都沒關係,因為最終你選擇哪一個並不重要。 **真正歸根結底,重要的是您選擇的框架**: - 穩定(足夠) - 讓你快速移動 - 讓您達到最終目標 為什麼?因為它們中的大多數都是圍繞著相同的概念建置的,已經證明自己有能力大規模執行,並且擁有可供您參與和學習的社區。 React 可能是職位描述中最突出的一個,但如果你正在尋找一個新角色並且只有 Vue 或 Angular 經驗,我無法想像你會花費一周以上的時間來建置一個副專案做出反應,向未來的雇主展示您的能力。 另一方面,如果您是初學者或初級開發人員,一旦您掌握了 HTML、CSS 和 JS 的基礎知識,學習什麼框架並不重要。我個人開始使用 PHP 學習後端開發,但後來轉向使用 Angular 進行前端開發。在我隨後的第二個角色中,我使用了React,現在我使用[Wasp](https://wasp-lang.dev)(一個基於React 和Node.js 建置的全棧框架)來開發我的副專案, https://reflectdaily.app/ - [開發人員永遠不會停止學習](https://www.youtube.com/watch?v=gl5HvBpUbt8),因此嘲笑任何特定框架都是毫無爭議的——除非它真的很糟糕,但沒有人會繼續這樣做無論如何使用它。 ![使用有效的方法](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bjbnn4xijtjrwxz8p9n4.jpeg) 所以,最後,使用有效的方法。因為在99.99%的情況下,你對Web框架的選擇並不會決定你專案的命運。 如果您做了一些研究並找到了適合您需求的框架並且您喜歡使用它 - **使用它**。確實沒有充分的理由不這麼做。 ## 支持我們! 🙏⭐️ ![GH 星星點擊](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/id9s6t8rcvfxty40bv2m.gif) 如果您喜歡這篇文章,[考慮在 Github 上給我們一顆星](https://kdta.io/github-wasp-lang-wasp_18)!我們在 Wasp 所做的一切都是開源的,您的支援幫助我們使 Web 開發變得更容易,並激勵我們撰寫更多這樣的文章。 ![支持我們](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qgbmn45pia04bxt6zf83.gif) --- 原文出處:https://dev.to/wasp/the-best-web-framework-doesnt-exist-2aom

网页文件加载失败如何重试

> 本文主要讲解脚本文件加载失败时的处理,对于其他类型的文件加载错误时,解决方向大致一样 ## 背景 在我们开发网站应用时,我们可能会遇到脚本加载失败的情况,导致脚本加载失败的原因有很多,比如用户的网络问题、终端设备问题、用户浏览器版本等诸多因素。 ## 解决方案 在 JavaScript 中,我们可以创建一个监听来监听脚本加载失败的情况,然后针对加载失败的脚本进行重新加载。 重新加载的方案,一般是通过更换域名来解决。我们给每个脚本添加一个映射关系表,用来在加载失败时匹配新的域名进行重试。 具体的解决方案,下面我一步一步讲解,另外希望大家可以仔细阅读注释中的内容 ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>脚本加载失败如何重试</title> <script> window.addEventListener( "error", // 监听全局错误 function (e) { console.log(e); }, true // 由于脚本加载失败不会冒泡,所以我们要在捕获阶段进行监听 ); </script> </head> <body> <script src="https://www.zowlsat.com/api/1.js"></script> <script src="https://www.qqqqqqq.com/api/2.js"></script> <script src="https://www.zowlsat.com/api/3.js"></script> </body> </html> ``` 此时我们可以在浏览器控制台看到以下效果 ![脚本加载失败如何重试](https://www.zowlsat.com/images/article/1.png) 但是这个监听方法会监听到很多其他的错误,我们只需要监听脚本加载失败的错误,所以我们要通过这个监听事件的参数 e 来判断了 ![脚本加载失败如何重试](https://www.zowlsat.com/images/article/2.png) 根据上图我们可以发现,普通错误的类型是 ErrorEvent,而脚本加载失败的类型是 Event,并且他的 target 会指向 script 标签,所以我们根据这个区别过滤掉其他的错误,这样剩下的情况才是我们需要处理的。 ```js window.addEventListener( "error", function (e) { if (e.target.tagName !== "SCRIPT" || e instanceof ErrorEvent) return; console.log(e); }, true ); ``` 接下来就是如何来实现重新加载,我们先给需要重新加载的域名建立一个映射关系,用于替换映射关系表中的域名。然后就是挨个匹配,当还是加载失败时继续匹配下一个,直到成功为止。 ```js const domainList = ["www.aaaaa.com", "www.bbbbb.com", "www.zowlsat.com"]; const retry = {}; window.addEventListener( "error", function (e) { if (e.target.tagName !== "SCRIPT" || e instanceof ErrorEvent) return; // 创建一个URL对象 const url = new URL(e.target.src); // 获取文件路径 const key = url.pathname; // 假如映射表中没有这个文件路径,那么就初始化一个映射键 if (!(key in retry)) { retry[key] = 0; } // 假如匹配完整个映射表都没重新加载成功,则放弃 const index = retry[key]; if (index >= domainList.length) { return; } // 获取新的完整路径 const domain = domainList[index]; // 替换域名 url.host = domain; // 创建新的script标签 const script = document.createElement("script"); script.src = url.toString(); // 将新的script标签追加到加载失败的script标签之前 document.body.insertBefore(script, e.target); retry[key]++; }, true // 由于脚本加载失败不会冒泡,所以我们要在捕获阶段进行监听 ); ``` 到此为止,我们功能已经基本实现,效果如下图 ![脚本加载失败如何重试](https://www.zowlsat.com/images/article/3.png) 但是有一个很关键的问题,就是假如我 2.js 这个文件中的内容,在 3.js 中要使用,那这样的话,2.js 就必须加载到 3.js 之前,否则就会报错。此时,我们就需要在 2.js 加载失败时,阻塞浏览器的解析,知道重新加载完成或者放弃重新加载时,再继续渲染之后的内容。 那这样的话我们该怎么做呢?🤔 其实很简单,在我们入门 js 时就学到过一个知识点,就是使用`document.write` `document.write`这个方法在解析期间使用的话,会阻塞浏览器的解析,而我们现在就是需要阻塞浏览器解析,那此时我们只需要将创建 script 标签的方法更换为`document.write`方法即可。 修改之后的代码如下: ```js const domainList = ["www.aaaaa.com", "www.bbbbb.com", "www.zowlsat.com"]; const retry = {}; window.addEventListener( "error", function (e) { if (e.target.tagName !== "SCRIPT" || e instanceof ErrorEvent) return; const url = new URL(e.target.src); const key = url.pathname; if (!(key in retry)) { retry[key] = 0; } const index = retry[key]; if (index >= domainList.length) { return; } const domain = domainList[index]; url.host = domain; // 此处加上转译是因为防止编译器识别script标签为结束标签报错 document.write(`\<script src="${url.toString()}">\<\/script>`); // const script = document.createElement("script"); // script.src = url.toString(); // document.body.insertBefore(script, e.target); retry[key]++; }, true ); ``` 现在我们再打开控制台查看,现在js文件按它原来的顺序执行了,这样既不会改变原有的代码逻辑,又可以在可控范围内进行重新加载。 效果如下图: ![脚本加载失败如何重试](https://www.zowlsat.com/images/article/4.png) 以上是简单实现了一个js文件重新加载错误的方案,其实这个方案也可以运用到其他很多类型的文件,不限于js文件。 然后我们还需要更加细化这个方法的话,我们可能还需要考虑到这个script标签是否带有`async`、`defer`等属性,还有诸多需要考虑的点,但是沿着这个方向解决的话,大体是没有问题的。

Ts中never类型的妙用

## 妙用一 当我们在一个项目中,可能会去改动一个在整个项目中应用很广泛的函数的参数类型,但是可能由于代码量比较庞大,我们不好排查改了之后哪些地方会出现问题,此时我们可以使用never类型来辅助我们的函数,当我们在原有的类型基础上添加了新的类型时,可能会导致else分支中的代码逻辑出现问题,此时我们可以向下面这样写来校验。 ```typescript // 当类型Method只有GET和POST时 type Method = "GET" | "POST" function request(method: Method) { if (method === "GET") { // ... } else if (method === "POST") { //... } else { // 此时的else分支是不可能执行到的,因为TypeScript会检查到所有的可能值,如果有其他值,则会报错。 const n: never = method; } } // 当我们新增一个类型PUT时 type Method = "GET" | "POST" | "PUT" function request(method: Method) { if (method === "GET") { // ... } else if (method === "POST") { //... } else { // 此时应该是进入到了PUT分支,所以method应该是PUT,此时把method赋值给n由于类型不符,会抛出一个编译错误 const n: never = method; } } ``` ## 妙用二 当我们需要对一个类型取反时,可以使用类型的三目运算和类型继承来实现,代码实现如下: ```typescript // 此类型意思为,当我们传入的value类型为string时,value的类型会定义为never,此时会抛出类型错误 function myFunction<T>(value: T extends string ? never : T): T { return value; } myFunction("hello"); // 报错:Argument of type 'string' is not assignable to parameter of type 'never'.ts(2345) myFunction(123); // 不报错 myFunction(true); // 不报错 ``` ### 我们可以把此类型单独做成一个类型工具,效果一样 ```typescript type BandType<T, U> = T extends U? never : T; function myFunction<T>(value: BandType<T, string>): T { return value; } ```

在vue中定义一个防抖ref

## 背景 在vue的开发过程中,我们通常会使用到ref,但在我们需要对一个频繁的赋值操作做防抖操作时,我们通常只能通过编写一个独立的防抖函数来实现,这样相对会多一些步骤(麻烦一些)。例如我们给一个即时搜索框的input实现防抖输入(即在输入文本n秒之后才触发搜索,避免频繁请求后端接口浪费资源)时,我们不仅不能使用`v-model`,而且还要定义一个input事件和防抖函数,非常之繁琐。 此时,我有一个简洁的方法,就是我们可以自定义一个带有防抖功能的ref函数来实现给响应式数据赋值时就实现防抖,这样不仅可以直接使用v-model来实现实时更新,而且不需要再编写任何方法。 ## 原理 在vue中,ref函数其实就是创建了一个代理对你定义的一个变量的操作进行拦截和更新。在vue3中,提供了一个`customRef`方法,这个方法可以自定义一个ref函数,我们只需要对这个ref函数进行小小的改造即可实现我们想要的效果。 ## 实现 ```typescript // utils/helper.ts import { customRef } from "vue"; export const debounceRef = (value: any, duration: number = 500) => { return customRef((track, trigger) => { let timeout: any; return { get() { track(); return value; }, set(newValue) { clearTimeout(timeout); // 延迟派发更新 timeout = setTimeout(() => { value = newValue; trigger(); }, duration); } } }) } ``` ## 使用 使用方式与原版ref无异,只是我们自定义的ref能实现防抖功能 ```typescript import { debounceRef } from '@/utils/helper' const value: string = debounceRef("") ```

SOLID 是你最需要的程式設計原則!

剛開始**物件導向程式設計**,不知道**SOLID**?別擔心,在本文中我將向您解釋它並舉例說明如何在開發程式碼時使用它。 - [什麼是 SOLID?](#什麼是 SOLID) - [S - 單一責任原則](#s-single-responsibility-principle) - [開閉原則](#the-開閉原則) - [L - 里氏替換原理](#l-里氏替換原理) - [I - 介面隔離原則](#i-interface-segregation-principle) - [D - 依賴倒置原則](#d-dependency-inversion-principle) - [結論](#conclusion) ##什麼是實體? 在物件導向程式設計中,術語 SOLID 是五個設計假設的縮寫,旨在促進理解、開發和維護軟體。 當使用這套原則時,可以顯著減少錯誤的產生,提高程式碼質量,產生更有組織的程式碼,減少耦合,改進重構並鼓勵程式碼重複使用。 ## S - 單一職責原則 ![單一責任原則範例](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oebel9z9m0pupvh0bg02.png) >*SRP - 單一職責原則* 這原則說**一個類別必須有一個且只有一個改變的理由** 就是這樣,不要建立具有多種功能和職責的類別。您可能已經完成或遇到一個可以做所有事情的類,例如“God Class”。在那一刻看起來一切都很好,但是當需要對這個類別的邏輯進行任何更改時,問題肯定會開始出現。 >**God Class - God Class:** 在物件導向程式設計中,它是一個知道太多或做太多事情的類別。 ``` class Task { createTask(){/*...*/} updateTask(){/*...*/} deleteTask(){/*...*/} showAllTasks(){/*...*/} existsTask(){/*...*/} TaskCompleter(){/*...*/} } ``` 這個 **Task** 類別透過執行 **四個** 不同的任務來打破 **SRP** 原則。它正在處理**任務**的資料、顯示、驗證和驗證。 ### 這可能導致的問題: - 「缺乏連結」-一個類別不應該承擔不屬於它自己的責任; - 「太多的資訊在一起」 - 你的類別將有很多依賴項並且很難進行更改; - 「實現自動化測試的困難」 - 很難[“mock”](https://pt.wikipedia.org/wiki/Objeto_Mock)這種類型的類別; 現在將 **SRP** 應用於 *Task* 類,讓我們看看這個原則可以帶來的改進: ``` class TaskHandler{ createTask() {/*...*/} updateTask() {/*...*/} deleteTask() {/*...*/} } class TaskViewer{ showAllTasks() {/*...*/} } class TaskChecker { existsTask() {/*...*/} } class TaskCompleter { completeTask() {/*...*/} } ``` >您可以將建立、更新和刪除放在單獨的類別中,但根據專案的上下文和大小,最好避免不必要的複雜性。 也許您問過自己「我只能將其應用於類別嗎?」不,相反,您也可以將其應用於方法和函數。 ``` //❌ function emailClients(clients: IClient[]) { clients.forEach((client)=>{ const clientRecord = db.find(client); if(clientRecord){ sendEmail(client); } }) } //✅ function isClientActive(client: IClient):boolean { const clientRecord = db.find(client); return !!clientRecord; } function getActiveClients(clients: IClient[]):<IClient | undefined> { return clients.filter(isClientActive); } function emailClients(clients: IClient[]):void { const activeClients = getActiveClients(clients); activeClients?.forEach(sandEmail); } ``` 更美觀、優雅、更有組織的程式碼。這個原則是其他原則的基礎,透過應用它,您將建立優質、易於閱讀和易於維護的程式碼。 ## O - 開閉原則 ![開閉原則範例](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qk0e24cnjefd5e8r0h6c.png) >*OCP - 開閉原則* 這個原則說的是**物件或實體必須對擴充功能開放,但對修改關閉**,如果需要加入功能,最好對其進行擴展而不是更改其原始程式碼。 想像一個學校辦公室的小型系統,其中有兩個班級代表學生的課程表:小學和高中。另外還有一個班級,定義了學生的班級。 ``` class EnsinoFundamental { gradeCurricularFundamental(){} } class EnsinoMedio {     gradeCurricularMedio(){} } class SecretariaEscola { aulasDoAluno: string; cadastrarAula(aulasAluno){ if(aulasAluno instanceof EnsinoFundamental){ this.aulasDoAluno = aulasAluno.gradeCurricularFundamental(); } else if(aulasAluno.ensino instanceof EnsinoMedio){ this.aulasDoAluno = aulasAluno.gradeCurricularMedio(); } } } ``` `SecretariaEscola` 類別負責檢查學生的教育程度,以便在註冊課程時應用正確的業務規則。現在想像一下,這所學校在系統中加入了技術教育和課程表,那麼就需要修改這個課程,對吧?但是,這樣你就會遇到一個問題,那就是違反了*SOLID 的「開閉原則” *。 我想到了什麼解決方案?可能在類別中加入一個“else if”,就這樣,問題解決了。不是小學徒😐,這就是問題所在! **透過更改現有類別以加入新行為,我們面臨著將錯誤引入到已經執行的內容中的嚴重風險。** >**記住:** **OCP** 認為課程必須針對更改關閉並針對擴充功能開放。 看看重構程式碼所帶來的美妙之處: ``` interface gradeCurricular {     gradeDeAulas(); } class EnsinoFundamental implements gradeCurricular {     gradeDeAulas(){} } class EnsinoMedio implements gradeCurricular {     gradeDeAulas(){} } class EnsinoTecnico implements gradeCurricular {     gradeDeAulas(){} } class SecretariaEscola {     aulasDoAluno: string;     cadastrarAula(aulasAluno: gradeCurricular) {         this.aulasDoAluno = aulasAluno.gradeDeAulas();     } } ``` 看到 `SecretariaEscola` 類,它不再需要知道要呼叫哪些方法來註冊該類別。它將能夠為建立的任何新型教學模式正確註冊課程表,請注意,我加入了“EnsinoTecnico”,無需更改原始程式碼。 >*自從我實作了 `gradeCurrarily` 介面以來。* >介面背後的獨立可擴展行為和反向依賴關係。 >鮑伯叔叔 - `開放擴充`:您可以為類別加入一些新功能或行為,而無需更改其原始程式碼。 -「修改關閉」:如果您的類別已經具有不存在任何問題的功能或行為,請勿變更其原始程式碼以新增內容。 ## L - 里氏替換原則 ![里氏替換原理範例](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eyrl3p96aqzowf72ipcb.png) >*LSP - 里氏替換原理* 里氏替換原則 — **A** **衍生類別必須可以被其基底類別取代**。 *兄弟* Liskov 在 1987 年的一次會議上介紹的這個原理在閱讀他的解釋時有點難以理解,但是不用擔心,我將向您展示另一個解釋和一個示例來幫助您理解。 > 如果對於 S 類型的每個物件 o1 都有一個 T 類型的物件 o2,這樣,對於用 T 定義的所有程式 P,當 o1 被 o2 取代時 P 的行為不變,那麼 S 是 T 的子類型 你明白了嗎?不,我第一次讀它時(或其他十次)也不明白它,但等等,還有另一種解釋: > 如果 S 是 T 的子類型,則程式中類型 T 的物件可以用類型 S 的物件替換,而不必變更該程式的屬性。 - [維基百科](https://pt.wikipedia.org/wiki/Princ%C3%ADpio_da_substitui%C3%A7%C3%A3o_de_Liskov)。 如果您更直觀,我有一個程式碼範例: ``` class Fulano { falarNome() { return "sou fulano!"; } } class Sicrano extends Fulano { falarNome() { return "sou sicrano!"; } } const a = new Fulano(); const b = new Sicrano(); function imprimirNome(msg: string) { console.log(msg); } imprimirNome(a.falarNome()); // sou fulano! imprimirNome(b.falarNome()); // sou sicrano! ``` 父類別和衍生類別作為參數傳遞,並且程式碼繼續按預期工作,神奇嗎?沒什麼,這就是我們利斯科夫兄弟的原則。 ### 違規範例: - 覆蓋/實作一個不執行任何操作的方法; - 拋出意外的異常; - 從基底類別傳回不同類型的值; ## I - 介面隔離原則 ![範例介面隔離原則](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p88do8ivd00s9aofo5yq.png) >*ISP - 介面隔離原則* 介面隔離原則 — **不應強迫類別實作它不會使用的介面和方法。** 該原則表明,建立更具體的介面比建立通用介面更好。 在下面的範例中,建立了一個「Animal」接口來抽象化動物行為,然後類別實作該接口,請參閱: ``` interface Animal { comer(); dormir(); voar(); } class Pato implements Animal{ comer(){/*faz algo*/}; dormir(){/*faz algo*/}; voar(){/*faz algo*/}; } class Peixe implements Animal{ comer(){/*faz algo*/}; dormir(){/*faz algo*/}; voar(){/*faz algo*/}; // Esta implementação não faz sentido para um peixe // ela viola o Princípio da Segregação da Interface } ``` 通用介面「Animal」強制「Peixe」類別具有有意義的行為,最終違反了 **ISP** 原則和 **LSP** 原則。 使用 **ISP** 解決此問題: ``` interface Animal { comer(); dormir(); } interface AnimalQueVoa extends Animal { voar(); } class Peixe implements Animal{ comer(){/*faz algo*/}; dormir(){/*faz algo*/}; } class Pato implements AnimalQueVoa { comer(){/*faz algo*/}; dormir(){/*faz algo*/}; voar(){/*faz algo*/}; } ``` 現在更好了,“voar()”方法已從“Animal”介面中刪除,我們將其加入到派生介面“AnimalQueVoa”中。這樣,行為就在我們的上下文中被正確隔離,並且我們仍然尊重介面隔離的原則。 ## D - 依賴倒置原則 ![依賴倒置原則範例](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9s5ywa9xijb41c1z2l1a.png) > *DIP — 依賴倒置原理* 依賴倒置原則 — **依賴抽象,而不是實現。** > 1. 高層模組不應該依賴低層模組。兩者都必須依賴抽象。 > > 2. 抽像不應該依賴細節。細節必須依賴抽象。 > > - *叔叔鮑伯* 在下面的範例中,我將展示一個簡單的程式碼來說明**DIP**。在此範例中,我們有一個透過不同方式(例如電子郵件和簡訊)發送訊息的通知系統。首先讓我們為這些通知方式建立具體的類別: ``` class EmailNotification { send(message) { console.log(`Enviando e-mail: ${message}`); } } class SMSNotification { send(message) { console.log(`Enviando SMS: ${message}`); } } ``` 現在,讓我們建立一個依賴這些具體實作的服務類別: ``` class NotificationService { constructor() { this.emailNotification = new EmailNotification(); this.smsNotification = new SMSNotification(); } sendNotifications(message) { this.emailNotification.send(message); this.smsNotification.send(message); } } ``` 在上面的例子中,`NotificationService`直接依賴`EmailNotification`和`SMSNotification`的具體實作。這違反了 DIP,因為高級 `NotificationService` 類別直接依賴低階類別。 讓我們使用 **DIP** 修復此程式碼。高級“NotificationService”類別不應依賴具體實現,而應依賴抽象。讓我們建立一個「Notification」介面作為抽象: ``` // Abstração para o envio de notificações interface Notification { send(message) {} } ``` 現在,具體的「EmailNotification」和「SMSNotification」實作必須實作此介面: ``` class EmailNotification implements Notification { send(message) { console.log(`Enviando e-mail: ${message}`); } } class SMSNotification implements Notification { send(message) { console.log(`Enviando SMS: ${message}`); } } ``` 最後,通知服務類別可以依賴「Notification」抽象: ``` class NotificationService { constructor(notificationMethod: Notification) { this.notificationMethod = notificationMethod; } sendNotification(message) { this.notificationMethod.send(message); } } ``` 這樣,「NotificationService」服務類別依賴「Notification」抽象,而不是具體實現,從而滿足**依賴倒置原則**。 ## 結論 透過採用這些原則,開發人員可以建立更能適應變化的系統,使維護變得更容易,並隨著時間的推移提高程式碼品質。 所有這些內容都是基於我學習 OOP 期間在網上找到的筆記、其他文章和影片,其中的解釋接近原理的作者,而示例中使用的程式碼是我根據自己對 OOP 的理解建立的。原則。讀者,我希望我對您的學習進程有所幫助。 --- 原文出處:https://dev.to/clintonrocha98/era-solid-o-que-me-faltava-bhp

✨ 十大工具,可以幫助你了解應用程式的運行狀況 🚀

假設您有一個或多個應用程式 - 它們都發送日誌 - 您如何知道它們內部發生了什麼? 通常有兩種方法: - **日誌記錄**:保存來自多個應用程式的日誌並提供見解和搜尋。這是老方法並且總是有幫助的。 - **追蹤**:專注於提供對應用程式效能的洞察;您可以針對它們建立準確的指標以進行監控和警報。 有些工具用於記錄,有些工具用於跟踪,有些工具兩者兼而有之! 以下是您必須了解的用於日誌和追蹤的開源工具: ![日誌](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/esar1pngxpw8z18zap74.gif) --- # 1. [Quickwit](https://github.com/quickwit-oss/quickwit)(日誌與追蹤)👑 Quickwit 是一個開源分散式搜尋引擎,專為大規模日誌管理和分析而設計。 Quickwit 是 Elasticsearch 的直接替代方案,具有更高的效能,尤其是在雲端原生和大規模分散式環境中,並且專注於優化儲存和搜尋效率。 通常,您會使用 OpenTelemetry、Fluentbit、Odigos(自動偵測追蹤工具)等工具來收集日誌和追蹤,將它們傳送到 Quickwit,然後使用 Jaeger(追蹤)或 Grafana(日誌和追蹤)將其視覺化。 **有趣的事實:** Elasticsearch 和 Kibana 都放棄了社區許可證,轉而採用更具限制性的許可證(從 Apache 2 到 Elastic 許可證,並遭到社區的強烈反對)。 Quickwit 是 AGPL 3。它對 FOSS(免費開源社群)更加開放。   ![Quickwit](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5azmt0hnhkj9oks3a93o.gif) --- # 2. [Grafana](https://github.com/grafana/grafana)(日誌和追蹤) Grafana 是 ELK 堆疊的開源替代品。對於日誌和跟踪,您必須設定兩個查詢引擎:Loki 和 Tempo,都由 Grafana 維護。 一旦您在 Loki 和 Tempo 中索引了所有日誌或跟踪,您將需要一個可視化工具來搜尋您的資料:Grafana 來了! Grafana 可讓您查詢、視覺化、警報和理解您的指標,無論它們儲存在何處。與您的團隊建立、探索和分享儀表板,並培養資料驅動的文化。   ![Grafana](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z0nsm0wfiqbnwcudksxr.gif) --- # 3. [Odigos](https://github.com/keyval-dev/odigos)(追蹤) Odigos 是一項獨特的技術,無需更改程式碼即可為 k8s 中的任何應用程式產生追蹤:然後可以將所有追蹤轉發到 Quickwit 或 Elasticsearch 等資料庫(它們有更多整合)。 如果您不知道,OpenTelemetry 是一個接收日誌和追蹤的協定。 Odigos 正在使用該標準,因此您可以在任何支援 OpenTelemetry 的資料庫中發送您的追蹤!   ![Odigos](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zo1qsgpt4glrro31n6fv.gif) --- # 5. [Jaeger](https://github.com/jaegertracing/jaeger)(追蹤) 與 Prometheus 不同,Jaeger 專注於追蹤。 Jaeger 支援跨分散式系統傳播上下文訊息,確保追蹤資料在服務網路中正確關聯。 它並不是為處理大量資料而設計的,您必須將其與強大的儲存引擎(如 Quickwit 或 Elasticsearch)一起使用。在這樣的設定中,Jaeger 可以根據您的服務進行擴展,使其適用於小型和大型系統。   ![Jaeger](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qzyo7fh4ete01pml8ea6.gif) --- # 6. [SigNoz](https://github.com/SigNoz/signoz)(日誌與追蹤) Signoz 提供日誌和追蹤管理功能。 您可以在單一管理平台中視覺化追蹤和日誌。 您可以透過尋找導致問題的確切追蹤並查看各個請求追蹤的詳細火焰圖來找到問題的根本原因。 ![Signoz](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wo47pgko3cluu9ufdxb3.gif)   --- # 7. [Keep](https://github.com/keephq/keep)(提醒) 保持與目前所有可觀察工具、資料庫和通訊管道的連接,並將所有內容聚合到一個平台中,在出現問題時提供頂級警報 😈   ![保留](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ofi0usc5qz9o8n0dc1d6.gif) --- # 8. [Uptrace](https://github.com/uptrace/uptrace)(日誌與追蹤) Uptrace 是一個基於 OpenTelemetry 的可觀察性平台,用於攝取日誌和追蹤。您可以監控您的應用程式並蒐索您的日誌。 由於其 OpenTelemetry 支援和眾多集成,可以輕鬆收集和發送資料 😈。請注意,您需要設定 Postgresql 和 Clickhouse 資料庫。   ![Uptrace](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ozdcpgz3a9anbqke5bo9.gif) --- # 9. [HyperDX](https://github.com/hyperdxio/hyperdx)(日誌與追蹤) HyperDX 是一個開源可觀察性平台,可讓您搜尋日誌並分析您的痕跡。您可以在一個平台上偵錯複雜的錯誤和使用者問題,而無需在多個工具之間跳轉。   ![HyperDX](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g3d0l1rkccv85gmqlqfn.gif) --- # 10. [普羅米修斯](https://github.com/prometheus/prometheus)(指標) 有趣的是,這個庫是以電影[普羅米修斯](https://www.imdb.com/title/tt1446714/)命名的(當然我是在開玩笑),但這是我的第一個假設(無論如何,這是一部好電影) 雖然 Prometheus 和 Elasticsearch 看起來很相似,但實際上它們非常不同。 Prometheus 只關注基礎設施的指標(例如 CPU、記憶體使用情況、磁碟使用情況…),但不太適合高基數指標。 Quickwit比較專注於Logs和Trace; Elasticsearch 可以做日誌、追蹤和指標! 他們傾向於攜手合作。 Prometheus 提供了一個原始的 UI,這很好,但它與 Grafana 儀表板最搭配。 有趣的是,Prometheus 提供了名為 PromQL(Prometheus Query Language)的查詢語言   ![普羅米修斯](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gougnoofwi5x2w2cz180.gif) --- 我們在 X 上連接嗎? :) [我在這裡](https://twitter.com/nevodavid) 您是否使用其他一些優秀的工具來記錄和追蹤? 請在評論中讓我了解它們:) --- 原文出處:https://dev.to/nevodavid/top-10-tools-to-learn-whats-going-on-in-your-app-20em

✨2024 我的決心:更以開源專案為中心思想!

## 簡介 當(幾乎)總是有一個開源替代品可以完成同樣的工作(如果不是更好的話)時,為什麼還要依賴專有軟體和服務呢? 以下是我一直在使用的 10 個開源替代方案,涵蓋從專案管理和通訊到資料分析的所有內容。 ![Gif 簡介](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ypv9s82s7843ecb1a36t.gif) --- ## 1- [Taipy](https://github.com/Avaiga/taipy) 而不是 Tableau Tableau 可能是資料視覺化領域的頂級參與者之一,但 Taipy 提供了強大的替代方案。 Taipy 是一個開源 Python 程式庫,可讓您建立全面的 Web 應用程式來展示資料視覺化。 Taipy 程式碼量低、高度可自訂,並且在建立儀表板時提供更大的靈活性。 ![Taipy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lai9u2uqawun2j5mf7ur.gif) --- ![QueenB GIF](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0un08vhstrk6zpst5yti.gif) 您的支持意義重大🌱,並且在許多方面為我們帶來了很大的幫助,例如寫文章! 🙏 --- ## 2- [Cal.com](http://Cal.com) 而非 Calendly Calendly 是簡化日程安排的變革者,但 [Cal.com](http://Cal.com) 成功地將其提升到了一個新的水平。這個開源 gem 有以下功能: - 團隊調度 - 整合視訊會議 - 自動時區偵測 ![Cal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9bjea3cr44s86z5deirt.gif) --- ## 3- [Plausible](https://github.com/plausible/analytics) 而非 Google Analytics 當然,Google Analytics 是一個大牌,但有時較小的工具也能提供同樣多的功能,一個很好的例子就是 Plausible。 這個開源工具提供像Google一樣的網站分析功能,不,他們不會損害資料隱私。 ![看似合理](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cmonhrmf5gch5kn6fe0e.gif) --- ## 4- [AppFlowy](https://github.com/AppFlowy-IO/AppFlowy) 而非 Notion Notion 是一個非常適合做筆記和專案管理的工作空間,但如果您想要一個更簡單的選項,請嘗試 AppFlowy。 該工具提供了一種極簡主義的替代方案,專注於簡單地建立和組織清單、註釋和任務。 介面非常人性化;您很快就會成為專業人士。 ![AppFlowy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wko5i9mphadcq1pa6bsh.gif) --- ## 5- [Penpot](https://github.com/penpot/penpot) 而非 Figma Figma 是一個設計巨頭,但它的開源表弟 Penpot 在過去一年中一直在增長勢頭。 以下是 Penpot 的主要功能: - 協同設計能力 - 向量編輯 - 互動式原型 - 成本效益 ![Penpot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pkg8ayeuw0y1q0tme50t.gif) --- ## 6- [Fonoster](https://github.com/fonoster) 而非 Twilio Twilio 是一個通訊平台,提供簡訊、語音、視訊和身份驗證 API,並提供無縫的客戶體驗。 讓我向您介紹 Fonoster,這是一種經濟高效的替代方案。 Fonoster 提供類似的語音和訊息服務。 Fonoster 專注於可擴展性,同時為您提供無縫的客戶體驗。 ![Fonoster](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1jk20ziqppgcpbfr6e37.gif) --- ## 7- [NextCloud](https://github.com/nextcloud/server) 而不是 Dropbox NextCloud 是 Dropbox 的開源競爭對手。 它提供文件託管、協作和同步功能,同時保持資料的隱私性並處於您的控制之下。 ![NextCloud](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/szichu2pjf9xzah9v64y.gif) --- ## 8- [Jitsi](https://github.com/jitsi/jitsi-meet) 而非 Google Meets Jitsi 是 Google Meets 的替代品,提供類似的視訊會議功能。 他們的主要特徵: - 端對端加密 - 螢幕分享 - 並且無需註冊! ![Jitsi](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xwnxa8hy6a0svqb4yo1d.gif) --- ## 9- [Padloc](https://github.com/padloc/padloc) 與 1Password 1Password 在密碼管理領域享有盛譽,但開源工具 Padloc 同樣注重隱私和安全性。 您可以使用 Padloc 安全地儲存和管理您的敏感和私人訊息,就像 1Password 一樣。 ![Padloc](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4st8nymwlf3wlslz029k.gif) --- ## 10- [Crowd.dev](https://github.com/CrowdDotDev/crowd.dev) 而非公共房間 Common Room 在社區建設領域一直勢頭強勁,但不要忽視他們的開源替代方案「crowd.dev」。 無論是專案管理、資金還是協作,「crowd.dev」對於建立和發展線上社群都是不可忽視的。 ![人群](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9j3mxkbk6wuwyt2g1fdh.gif) --- ## 結論 選擇工具時,請記住查看開源選項。 開源帶來了透明度、可自訂性和成本效益,在大多數情況下都是不錯的選擇。 ![GIF 結束](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rvimkpxsq91d6m1jfei1.gif) 恭喜你,你已經走到最後了!如果您有任何疑問,請隨時諮詢。 --- 原文出處:https://dev.to/taipy/2024-resolution-be-more-open-source-centric-1jje

如何製作精彩的 GitHub 個人資料

如果您是 GitHub 新手或主要使用私人 GitHub 儲存庫,那麼您可能還沒有 GitHub 個人資料。 GitHub 個人資料有助於為存取您個人資料的人提供基本資訊。擁有良好的個人資料甚至可以幫助您脫穎而出,尤其是當您開始為開源專案做出貢獻並且人們開始注意到您時。 在本文中,我將展示如何建立您自己的 GitHub 設定檔。我還將分享從哪裡獲得個人資料的靈感。最後,我將分享資源和技巧,幫助您建立出色的 GitHub 個人資料! ## 建立您的 GitHub 個人資料 在開始自訂 GitHub 個人資料之前,您首先需要建立一個。 這是一個[簡短指南](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-profile/customizing-your-profile/managing-your-profile-readme)來自 GitHub,了解如何設定您的個人資料。 但您需要做的就是: - 建立一個新的儲存庫,**與您的 GitHub 使用者名稱**相同。 - 將 `README.md` 檔案新增至您的新儲存庫。 例如,我的 GitHub 使用者名稱是 [kshyun28](https://github.com/kshyun28)。要建立我的個人資料,我需要建立一個也名為 [kshyun28](https://github.com/kshyun28/kshyun28) 的儲存庫,然後新增一個「README.md」檔案。 ![範例 GitHub 設定檔儲存庫](https://res.cloudinary.com/dlieqpdfd/image/upload/v1704616186/GitHub%20Profile/github-profile-repository-example_veplgh.png) 設定「儲存庫」和「README.md」檔案後,透過前往您的 GitHub 個人資料(網址為 https://github.com/YOUR-USERNAME )來驗證您的個人資料是否可見。 就我而言,它將是 https://github.com/kshyun28。 ## 自訂您的 GitHub 個人資料 現在您已經有了 GitHub 個人資料,是時候發揮創意了! 這裡的關鍵是**讓你的個性在你的個人資料上展現**。你的 GitHub 個人資料不必像 LinkedIn 那樣太正式。 我還建議**從簡單開始**。這有助於您的 GitHub 設定檔啟動並執行。當您有新想法時,您可以隨時改進您的個人資料。 ### GitHub 風格的 Markdown、格式和 HTML 為了自訂 GitHub 設定檔的“README.md”,您將使用 **GitHub Flavored Markdown**。如果您以前寫過 Markdown 內容,那麼格式化對您來說應該很容易。 如果你是第一次用Markdown 寫作,你可以去[GitHub 的文件](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax) 來熟悉可用的格式化選項。 您也可以使用 **HTML** 作為您的個人資料的其他格式選項。 我發現以下 HTML 標記很有用: - 不間斷空格:`nbsp;` - div 居中對齊:`<divalign="center"></div>` 您可以使用大多數 HTML 標籤,但 GitHub Flavored Markdown 會過濾掉以下 HTML 標籤: - `<標題>` - `<文字區域>` - `<樣式>` - `<xmp>` - `<iframe>` - `<無嵌入>` - `<無框架>` - `<腳本>` - `<明文>` > 💡:要了解更多訊息,請參閱與 HTML 區塊相關的 [GitHub Flavored Markdown Spec](https://github.github.com/gfm/#html-blocks)。 ### 尋找靈感 為了幫助您入門,我建議您查看其他很棒的 GitHub 設定檔以獲取想法。你可以造訪 [awesome-github-profile-readme](https://github.com/abhisheknaiidu/awesome-github-profile-readme),我在製作個人資料時找到了靈感。 由於設定檔是開源的,您可以將一些好主意用於您的精彩設定檔! 您也可以查看[我的個人資料](https://github.com/kshyun28)以獲取一些想法。 😉 ### 新增徽章 要為您的個人資料加入徽章,您可以查看 [markdown-badges](https://github.com/Ileriayo/markdown-badges)。該存儲庫有多種徽章可供選擇,從程式語言到 Netflix 等串流平台。 如果您找不到所需的內容或想要建立自訂徽章,可以前往 [shields.io](https://shields.io/),這就是 [markdown-badges](https://github.com/Ileriayo/markdown-badges) 使用。 這是我在個人資料中使用 [markdown-badges](https://github.com/Ileriayo/markdown-badges) 的範例。 ![Markdown 徽章範例](https://res.cloudinary.com/dlieqpdfd/image/upload/v1704616185/GitHub%20Profile/badges-example_t6jyr6.png) ### 新增圖標 要在您的個人資料中加入“技能”或“技術堆疊”部分,我建議使用 [skill-icons](https://github.com/tandpfun/skill-icons),它提供漂亮的圖標。 如果您的圖示不受支持,您可以造訪 [simpleicons](https://simpleicons.org/),其中包含超過 2900 個流行品牌的 SVG 圖示。 這是一個範例,我在個人資料的技術堆疊部分使用了 [skill-icons](https://github.com/tandpfun/skill-icons)。 ![圖示範例](https://res.cloudinary.com/dlieqpdfd/image/upload/v1704616185/GitHub%20Profile/icons-example_nyo1sn.png) ### 使用表情符號 在 GitHub Flavored Markdown 中,您可以使用表情符號。要查看支援的表情符號的完整列表,您可以存取此 [emoji-cheat-sheet](https://github.com/ikatyang/emoji-cheat-sheet)。 如果您想自己取得支援的表情符號列表,可以使用 [GitHub 的 Emoji API](https://docs.github.com/en/rest/emojis/emojis#get-emojis)。 在瀏覽器上造訪 https://api.github.com/emojis 應該會顯示所有支援的表情符號的 JSON 回應。 ``` { "+1": "https://github.githubassets.com/images/icons/emoji/unicode/1f44d.png?v8", "-1": "https://github.githubassets.com/images/icons/emoji/unicode/1f44e.png?v8", "100": "https://github.githubassets.com/images/icons/emoji/unicode/1f4af.png?v8", "1234": "https://github.githubassets.com/images/icons/emoji/unicode/1f522.png?v8", "1st_place_medal": "https://github.githubassets.com/images/icons/emoji/unicode/1f947.png?v8", "2nd_place_medal": "https://github.githubassets.com/images/icons/emoji/unicode/1f948.png?v8", "3rd_place_medal": "https://github.githubassets.com/images/icons/emoji/unicode/1f949.png?v8", "8ball": "https://github.githubassets.com/images/icons/emoji/unicode/1f3b1.png?v8", ... ``` 這是我在個人資料中使用表情符號的範例。 ![表情符號範例](https://res.cloudinary.com/dlieqpdfd/image/upload/v1704616185/GitHub%20Profile/emojis-example_yfzhef.png) ### 新增 GitHub 統計訊息 要為 GitHub 活動加入卡片和統計訊息,我建議使用 [github-readme-stats](https://github.com/anuraghazra/github-readme-stats)。您可以使用不同的版面配置和主題自訂統計卡。 以下是我將 GitHub 統計資料新增至我的個人資料的範例。 ![GitHub 統計資訊範例](https://res.cloudinary.com/dlieqpdfd/image/upload/v1704616186/GitHub%20Profile/github-stats-example_ndhxk3.png) ### 新增引號 在您的個人資料中加入隨機引用可以為訪客增添一抹亮色。我發現 [github-readme-quotes](https://github.com/PiyushSuthar/github-readme-quotes) 對於這樣做很有用。 這是我的個人資料上的樣子。我個人喜歡加入引號,為我的個人資料訪客提供一些價值。 ![報價範例](https://res.cloudinary.com/dlieqpdfd/image/upload/v1704616185/GitHub%20Profile/quote-example_dfvjrh.png) ### 提高可存取性 自訂您的個人資料時,請確保它**可供盡可能多的人查看**。並非每個人都可以查看或載入圖像。有些人有殘疾,而有些人的網路連線速度很慢。 提高個人資料的[輔助功能](https://developer.mozilla.org/en-US/docs/Learn/Accessibility/What_is_accessibility)的一種方法是向圖像加入描述性「替代文字」。 ``` <!-- Markdown Image --> ![Image Alt Text](image-source) <!-- HTML Image Tag --> <img alt="Image Alt Text" src="image-source" /> ``` 然後,要測試您的個人資料的可存取性,您可以嘗試停用網頁瀏覽器上的圖像載入。這是有關如何停用 Google Chrome 映像載入的[指南](https://www.wikihow.com/Disable-Images-in-Google-Chrome)。 這是我的個人資料在 Google Chrome 上停用圖片載入後的樣子。 ![GitHub 設定檔可存取性範例](https://res.cloudinary.com/dlieqpdfd/image/upload/v1704717170/GitHub%20Profile/github-profile-accessibility_vixcg8.png) ### 更多想法 要為您的個人資料加入更多資訊圖表,我建議查看 [metrics](https://github.com/lowlighter/metrics)。這是 GitHub 上最受好評的存儲庫之一,其中包含“github-profile”主題,因此我不能忽略它。 然後我發現了這個漂亮的資源 [beautify-github-profile](https://github.com/rzashakeri/beautify-github-profile),在這裡您可以找到更多自訂個人資料的方法。 如果您也喜歡冒險,可以在[此處](https://github.com/topics/github-profile)探索「github-profile」主題。預設情況下,儲存庫會按星數排序。 請隨意探索有「github-profile」主題的儲存庫。您甚至可能會發現那些使用頻率不高但正是您所需要的。 ### GitHub 簡介 成就 雖然這與自訂 GitHub 設定檔的「README.md」無關,但我覺得有必要包含它。 如果您前往 GitHub 個人資料,您會注意到左側邊欄上有一個「成就」部分。 ![GitHub 個人資料成就](https://res.cloudinary.com/dlieqpdfd/image/upload/v1704632356/GitHub%20Profile/github-profile-achievements_tlqp3p.png) 收集這些成就很有趣,並且可以改善您的整體 GitHub 檔案。 要了解有關可用成就以及如何獲得這些成就的更多訊息,請查看 [GitHub 個人資料成就列表](https://github.com/Schweinepriester/github-profile-achievements)。 ## 結論 回顧一下,我們演練如何建立 GitHub 個人資料。然後我展示瞭如何使用 GitHub Flavored Markdown 和 HTML 格式化您的個人資料。之後,我分享了您可以從哪裡獲得個人資料的靈感。最後,我提供了有關如何自訂個人資料的提示和資源。 我希望這可以幫助您製作精彩的 GitHub 個人資料。我很想看看你能想出什麼辦法! 感謝您的閱讀,請隨時發表評論或與我聯繫[此處](https://linktr.ee/kshyun28)。 --- 原文出處:https://dev.to/kshyun28/how-to-make-your-awesome-github-profile-hog

Kubernetes 變簡單 - Cyclops 簡介

如果您是開發人員,您很可能聽說過 Kubernetes。您聽說它是一個了不起的工具,可以幫助您擴展應用程式和管理微服務。但是,您可能也聽說過它**非常**複雜。它太複雜了,你可能會被嚇跑。我不怪你;這也是我的第一個反應。 如果您在此網站上搜尋帶有 Kubernetes 標籤的熱門帖子,您會發現大量教學和解釋 Kubernetes 的人員。 這些貼文是最熱門的,因為人們**想要**了解 Kubernetes,因為我們覺得,在當今的軟體開發世界中,Kubernetes 是不可避免的。某種程度上,這是真的… 軟體開發人員通常需要了解並使用 Kubernetes;如果您曾經在這個領域尋找過工作,您就會知道這一點。 但是,如果有一個工具可以最大限度地減少您與 Kubernetes 的接觸點呢?此工具可簡化流程並在您嘗試將應用程式部署到 Kubernetes 叢集時為您提供指導。一個高度可自訂的工具,可以讓組織中的某人(了解 Kubernetes,通常稱為 DevOps)為您建立使用者介面! 是的,你沒看錯,就是獨眼巨人! 😄 需要澄清的是,Cyclops 並不用於建立和管理 Kubernetes 叢集和其他基礎設施;而是用於建立和管理 Kubernetes 叢集和其他基礎設施。相反,Cyclops 用於在叢集內部署和管理應用程式。 ## 向我們展示您的支持🙏🏻 ![Github 明星](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zby3mjhcgvmvlpm9jtaa.gif) 我們正在將 Cyclops 打造為**開源**,您的支援對我們來說意味著一切。考慮在[GitHub](https://github.com/cyclops-ui/cyclops) 上給我們一顆星,並在我們預定的[ProductHunt](https://www.producthunt.com/products/cyclops)上關注我們我們的第一個版本! ## 在我們開始之前 為了測試 Cyclops,您需要一些東西。如果這不是您第一次使用 Kubernetes,那麼您很可能已經準備好了一切,但我們仍然會為 Kubernetes 領域的新手描述每個元件。這些工具不僅用於 Cyclops,您還可以將它們用於任何與 Kubernetes 相關的事情。 測試 Cyclops 需要的主要內容是 Kubernetes 叢集。如果你有一個可以用來玩的東西,那就太好了;如果沒有,我們將向您展示如何在您自己的電腦上啟動叢集。因此,做到這一點的三個先決條件是: - [**Docker**](https://www.docker.com/products/docker-desktop/) - [**Minikube**](https://minikube.sigs.k8s.io/docs/) - [**kubectl**](https://kubernetes.io/docs/tasks/tools/) Docker 是最受歡迎的容器化工具,我們將使用它來下載並啟動 Minikube 映像。下載 Docker 非常簡單:造訪他們的網頁並下載 Docker 桌面應用程式。 Minikube 在本機電腦上扮演 Kubernetes 叢集的角色。它是開發和測試 Kubernetes 應用程式的絕佳工具,非常適合這種場景。您可以在[此處](https://minikube.sigs.k8s.io/docs/start/)找到有關如何安裝它的指南。 最後缺少的是與 Kubernetes 叢集通訊的方式,這是透過名為「kubectl」的 Kubernetes 命令列工具完成的。它可用於部署應用程式、檢查和管理叢集資源以及檢視日誌。在本教程中,我們將使用它將 Cyclops 安裝到 Minikube 上的叢集中,並在叢集外部公開其功能。 ## 安裝獨眼巨人 一旦您準備好 Kubernetes 叢集(請查看*開始之前*部分),安裝 Cyclops 就是一個簡單的過程。使用“kubectl”,在終端機中執行以下命令: ``` kubectl apply -f https://raw.githubusercontent.com/cyclops-ui/cyclops/v0.0.1-alpha.5/install/cyclops-install.yaml ``` 它將建立一個名為「cyclops」的新命名空間,並部署 Cyclops 實例執行所需的一切。 現在,剩下的就是將 Cyclops 伺服器暴露在叢集之外。您需要使用以下命令公開後端和前端。 透過以下方式公開前端: ``` kubectl port-forward svc/cyclops-ui 3000:3000 -n cyclops ``` 並透過後端: ``` kubectl port-forward svc/cyclops-ctrl 8080:8080 -n cyclops ``` 就是這樣!現在您可以在瀏覽器中透過 [http://localhost:3000](http://localhost:3000/) 存取 Cyclops。 如果您在使用「port-forward」命令時遇到問題,您可能只需要在將 Cyclops 安裝到叢集中後等待幾秒鐘,可能需要一段時間才能啟動其所有資源。 ## 現在是示範時間💥 現在您已經啟動並執行了 Cyclops 實例,是時候看看它的功能了。 您應該會看到一個幾乎空白的螢幕,沒有顯示任何已部署的模組。 *模組* 是 Cyclops 的應用程式😎 的俚語。那麼,讓我們從建立我們的第一個模組開始吧! 點擊右上角的“新增模組”按鈕,您應該會進入一個新畫面。在這裡,Cyclops 詢問我們要部署哪個 Helm 圖。 不要太深入,但 [Helm](https://helm.sh/) 是一個非常流行的 Kubernetes 開源套件管理器。它可以幫助您建立在 Kubernetes 中執行的應用程式所需的設定檔。這些圖表讓 Kubernetes 知道如何處理叢集中的應用程式。 不用擔心;為了展示 Cyclops 的基礎知識,我們建立了一個簡單的 Helm 圖表,以便任何人都可以遵循。您可以在我們的 [GitHub 儲存庫](https://github.com/cyclops-ui/templates/tree/main/demo) 中找到它的樣子,以及您可以使用的更多 Helm 圖表範例! ![已載入圖表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mpcmtuvaasmmr30er318.png) 正如您所看到的,一旦您進入圖表存儲庫,Cyclops 將呈現一個使用者介面。 *如果您想了解渲染背後的魔力,請查看我們之前的[博客](https://dev.to/cyclops-ui/how-cyclops-utilizes-json-schema-to-deliver-dynamical-ui-49e ).* 您可以根據需要填寫字段,但請注意 [Kubernetes 命名約定](https://kubernetes.io/docs/concepts/overview/working-with-objects/names/)! 如果您想繼續,我的輸入如下: - 名稱:`演示` - 副本:`1` - 圖片:`nginx` - 版本:`1.14.2` - 服務:“真實” 我們還將模組名稱設定為“demo”。點擊“儲存”,Cyclops 將向您顯示新模組的詳細資訊。 ![單一 Pod 部署](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lzdg5f5vhq5qmptq62zh.png) 此畫面顯示您的應用程式目前正在使用的所有資源。它將列出所有部署、服務、pod 或任何其他資源。在這裡,我們可以看到 Cyclops 將一個 Pod 部署到您的叢集中,正如我們在副本欄位中指定的那樣。如果您想確保它確實在叢集中執行,可以使用以下“kubectl”命令進行檢查: ``` kubectl get pods ``` 但是,如果突然需要擴展您的應用程式或任何其他資源怎麼辦?好吧,別擔心;有了 Cyclops,這真的很容易! 透過點擊*編輯*按鈕,您可以變更應用程式資源的值。讓我們嘗試將應用程式擴展到 3 個副本,看看會發生什麼。 ![Tree Pod部署](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d3tx8a4bovw7evgx3iut.png) 您現在應該在 *Deployment* 選項卡中看到另外兩個 Pod;歡呼! 🎉 當然,這適用於您可能想要對應用程式進行的任何其他更改。也許是服務?如果我們意識到我們不再需要它呢?嗯,有了 Cyclops,如果需要的話,很容易將其關閉。 再次點擊“編輯”按鈕,這一次,關閉服務切換。 ![服務關閉](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8f9wzg7bvzx4ta2fx6pg.png) Cyclops 不會自動刪除它,但會警告您(透過警告三角形標誌)您將其關閉,並且它不再起作用。這意味著您可以安全地刪除它! 如果您厭倦了您的應用程式,您也可以刪除整個應用程式🗑️ 點擊刪除按鈕並填寫模組名稱以安全刪除它。您可以再次使用“kubectl”檢查它是否真的被刪除: ``` kubectl get pods ``` ## 結束 這就是它的全部內容! Cyclops 讓對 Kubernetes 有不同了解的人可以利用它的力量。如果您遵循本教程,您應該已經使用 Cyclops 部署了您的第一個應用程式;恭喜! 🎉 在我們的[網頁](https://cyclops-ui.com/)上,您可以找到另一篇教程,展示更多功能和更複雜的用例,以及我們的聯絡資訊和社群資訊。 如果您對如何讓 Cyclops 變得更好有任何回饋或想法,您可以填寫我們的簡短 [Google 表單](https://forms.gle/jrwcBHRtpwmK91v47)! --- 原文出處:https://dev.to/cyclops-ui/kubernetes-made-simple-introducing-cyclops-44g0

每個開發人員必須了解的 10 個 Git 指令

了解 Git 和 GitHub 對於任何開發人員都至關重要,因為它們可以提供有效的版本控制和程式碼管理。熟練這些工具可以讓您脫穎而出並提高您的工作效率。在這篇文章中,我們將探索一組 Git 指令來啟動您的軟體開發之旅。 ## Git 詞彙 在深入研究這些命令之前,讓我們先熟悉一些 Git 術語。這種理解不僅可以幫助你更好地掌握 Git,還可以為你的整體理解打下基礎。 ### 儲存庫 儲存庫或儲存庫充當儲存空間,用於儲存專案的原始程式碼及其版本歷史記錄。 ### 工作目錄 工作目錄是您目前對專案進行更改的位置,其中存放您正在處理的文件。 ### staging 暫存充當儲存庫和工作目錄之間的中間區域。您可以在其中新增更改,然後將其提交到主儲存庫。 ### commit 提交是對階段提出的更改的快照,由唯一辨識碼(SHA-1 雜湊)標識並附有提交訊息。 ### 分支 分支代表儲存庫的並行版本,有助於獨立地處理不同的功能或錯誤修復。 ### 合併 合併涉及將建議的變更合併到主儲存庫中,通常用於將新功能整合到主專案中。 ### 拉 拉取是指從任何遠端儲存庫取得程式碼並將其合併到本機儲存庫(即工作目錄)。 ### 推 推送涉及將本機變更傳送到任何儲存庫的任何遠端分支。 ### 複製 克隆是建立主儲存庫的本機副本、建立有效拉取和推送連線的過程。 ### pull 取得會將變更從任何遠端儲存庫下載到本機儲存庫,而不直接將它們合併到本機儲存庫中。它對於在合併之前檢查更改很有用。 ### fork Forking 在您的 GitHub 帳戶上建立其他人儲存庫的個人副本,從而可以在不影響原始儲存庫的情況下進行變更。 ### 衝突 當兩個或多個分支在程式碼的同一部分發生變更時,就會出現衝突,而 Git 無法直接合併它們。 ### head 在 Git 中,HEAD 是指標/引用,始終指向目前分支中的最新提交。當您進行新的提交時,HEAD 會移動到提交的頂部。   現在,讓我們一一探討 10 個 Git 指令。 ![開始迷因](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s5zias7tsgsdjokp5g9p.gif) ## 1 - 一起新增和提交文件 傳統上,在 Git 中,我們使用「git add *」指令來暫存所有已修改的檔案以供後續提交。隨後,我們使用 git commit -m "commitMessage" 指令來提交這些變更。然而,存在一個更簡化的命令,只需一步即可完成這兩項任務: ``` git commit -am "commitMessage" ``` 「-am」標誌允許我們暫存這些變更並在一次有效的操作中提交它們。 ## 2 - 建立並切換到 Git 分支 與前面的場景類似,另一個命令組合了兩個命令的功能。不要使用單獨的命令,而是使用 `gitbranchbranchName` 建立分支並使用 `gitcheckoutbranchName` 切換到它。使用以下命令一步即可完成這兩項任務: ``` git checkout -b branchName ``` 帶有“git checkout”命令的“-b”標誌允許我們建立一個新分支並立即切換到它。 ## 3 - 刪除 Git 分支 若要刪除 Git 中的分支,請使用 `gitbranch-d` 或 `gitbranch-D` 指令。 “-d”選項用於安全刪除,僅刪除完全合併到目前分支的分支。 “-D”選項用於強制刪除,無論是否完全合併。以下是命令: 安全刪除(檢查合併): ``` git branch -d branchName ``` 強制刪除(不檢查合併): ``` git branch -D branchName ``` ## 4 - 重新命名 Git 分支 若要重新命名分支,請使用「gitbranch-m」指令,後面跟著目前分支名稱和新的所需分支名稱。例如,要將名為“oldBranch”的分支重新命名為“newBranch”,請執行: ``` git branch -m oldBranch newBranch ``` 如果您想要重新命名您正在工作的目前分支,而不指定舊名稱,請使用下列命令: ``` git branch -m newBranchName ``` 在這裡,您不需要指定舊的分支名稱,因為 Git 會假設您要將目前分支重新命名為新名稱。 ## 5 - 取消暫存特定文件 有時,您可能希望從暫存區域中刪除特定文件,以便在提交之前進行其他修改。使用: ``` git reset filename ``` 這將取消暫存該文件,同時保持變更不變。 ## 6 - 放棄對特定檔案的更改 若要完全放棄對特定文件所做的變更並將其恢復到上次提交的狀態,請使用: ``` git checkout -- filename ``` 此指令可確保檔案回到先前的狀態,撤銷最近的修改。這是一種在不影響其餘更改的情況下重新開始處理特定文件的有用方法。 ## 7 - 更新您的最後一次 Git 提交 想像一下,您剛剛在 Git 儲存庫中進行了一次提交,但隨後您意識到您忘記了在該提交中包含更改,或者您可能想修復提交訊息本身。您不想為這個小更改建立一個全新的提交。相反,您想將其加入到先前的提交中。您可以在此處使用命令: ``` git commit --amend -m 'message' ``` 此命令修改您最近所做的提交,將任何分階段的變更與您的新評論結合以建立更新的提交。 要記住的一件事是,如果您已經將提交推送到遠端儲存庫,則需要使用「git push --force」強制推送變更來更新遠端分支。標準的「git push」操作會將新的提交附加到遠端儲存庫,而不是修改最後的提交。 ## 8 - 隱藏更改 假設您正在處理兩個不同的分支A 和B。在分支A 中進行更改時,您的團隊要求您修復分支B 中的錯誤。當您嘗試使用「git checkout B」切換到分支B 時,Git 會阻止它,顯示錯誤: ![無法更改分支](https://miro.medium.com/v2/resize:fit:809/1*SAEI_fhVWNDX-3FKtQG3SQ.png) 我們可以按照錯誤訊息的建議提交更改。但承諾是 更像是固定的時間點,而不是正在進行的工作。這是我們可以應用錯誤訊息的第二個建議並使用隱藏功能的地方。使用此命令來儲存您的變更: ``` git stash ``` `git stash` 暫時儲存您尚未準備好提交的更改,讓您可以切換分支或處理其他任務,而無需提交不完整的工作。 若要重新套用分支中隱藏的更改,請使用“git stash apply”或“git stash pop”。這兩個命令都會恢復最新隱藏的變更。儲存應用程式只是恢復更改,而彈出則恢復更改並將其從儲存中刪除。您可以[在這裡](https://opensource.com/article/21/4/git-stash)閱讀有關隱藏的更多資訊。 ## 9 - 恢復 Git 提交 想像一下,您正在開發一個 Git 專案,並且發現某個特定的提交引入了一些不必要的更改。您需要撤銷這些變更而不從歷史記錄中刪除提交。使用以下命令撤銷該特定提交: ``` git revert commitHash ``` 這是糾正專案中的錯誤或不需要的更改的安全且非破壞性的方法。 例如,假設您有一系列提交: - 提交A - 提交 B(此處引入了不需要的更改) - 提交C - 提交 D 若要逆轉提交 B 的影響,請執行: ``` git revert commitHashOfB ``` Git 將建立一個新的提交,我們將其稱為提交 E,它將否定提交 B 引入的更改。提交 E 成為分支中的最新提交,並且該專案現在反映瞭如果提交 B 從未發生過時的狀態。 如果您想知道如何檢索提交哈希,使用“git reflog”很簡單。在下面的螢幕截圖中,突出顯示的部分代表您可以輕鬆複製的提交哈希: ## 10 - 重置 Git 提交 假設您已經承諾了您的專案。然而,經過檢查,您意識到您需要調整或完全撤銷上次提交。對於這樣的場景,Git 提供了這些強大的指令: ### 軟重置 ``` git reset --soft HEAD^ ``` 當您使用“git reset --soft HEAD^”時,您正在執行軟重置。此命令允許您回溯上次提交,同時保留暫存區域中的所有變更。簡而言之,您可以使用此命令輕鬆取消提交,同時保留程式碼變更。當您需要修改上次提交(也許需要在再次提交之前加入更多更改)時,它會很方便。 ### 混合重置 ``` git reset --mixed HEAD^ ``` 這是當您使用“git reset HEAD^”而不指定“--soft”或“--hard”時的預設行為。它取消最後一次提交並從暫存區域中刪除其變更。但是,它將這些變更保留在您的工作目錄中。當您想要取消提交最後一次提交並從頭開始進行更改,同時在重新提交之前將更改保留在工作目錄中時,這會很有幫助。 ### 硬重置 ``` git reset --hard HEAD^ ``` 現在,我們來談談「git reset --hard HEAD^」。它會完全刪除 Git 歷史記錄中的最後一次提交以及所有相關變更。當您使用“--hard”標誌時,就沒有回頭路了。因此,當您想永久放棄最後一次提交及其所有變更時,請務必謹慎使用此選項。 感謝您的閱讀。我希望這篇文章對您有所幫助,並且您學到了一些新命令。如果您還有任何疑問,請隨時與我們聯繫。請隨意分享您在日常生活中經常使用的任何 Git 命令,您會發現它非常方便。 :) 與我聯繫 [LinkedIn](https://www.linkedin.com/in/mukeshkuiry) [X(以前的 Twitter)](https://twitter.com/mukeshkuiry7) --- 原文出處:https://dev.to/mukeshkuiry/10-must-know-git-commands-for-software-engineers-3733