[IT] Clean Architecture - 第2章 - 兩個價值維度

Ch2. 兩個價值維度 每個軟體系統都為利益相關者(stakeholders)提供兩種不同的價值維度:行為(behavior)與結構(structure)。軟體開發人員負責確保這兩種價值保持高水準。不幸的是,他們往往只關注其中一個而忽略另一個,更不幸的是,他們往往只關注較低價值的那一個,最終使軟體失去價值。 行為 歉體的第一個價值來自於行為。程式設計師被聘請來使機器以一種能為利益相關者帶來獲利或節省成本的方式運作。我們透過協助利益相關者制定功能規格或者需求文件,然後編寫程式碼,使利益相關者的機器滿足這些需求。當機器違反這些要求時,程式設計師便開始除錯以修復這些問題。 結構 軟體的第二個價值來自於結構,軟體之所以為「軟」體,是因為它被創造出來是為了方便改變機器的行為。為了實現其目的,軟體必須要有足夠的彈性,易於修改。當利益相關者對某項功能改變主意時,這種改變應該要是可以簡單且容易進行的。進行這種改變的困難程度應該只與改變的範圍成比例,而不是與改變的形式成比例。 然正是範圍和形狀之間的差異常常推動軟體開發成本的增長。這就是為什麼成本與所需求的變更規模不成比例。這也是為什麼開發前期比開發後期便宜得多的原因。 從利益相關者的角度來看,他們只是提供了一系列大致相似範圍的變更。從開發者的角度來看,利益相關者給予他們一系列拼圖碎片,他們必須將其放入日益複雜的拼圖中。每個新的要求都比上一個更難擬合,因為系統的形狀與要求的形狀不匹配。 我在這裡以一種非傳統的方式使用「形狀」這個詞,但我認為隱喻很貼切。軟體開發人員常常感覺自己被迫將方形木塊塞進圓洞中。 問題當然在於系統的架構。如果這個架構偏好某種形式,那麼新功能愈來愈難以適應這種結構。因此,架構應該盡可能地不受形式的限制。 更大的價值 行為與架構,何者提供更大的價值?對軟體系統來說,它的功能更重要,還是易於修改更重要? 如果你問企業經理,他們通常會說軟體系統的工作更重要。開發人員通常也會贊同。但這是錯誤的態度,我們可以用簡單的邏輯工具來證明它是錯誤的,那就是檢查極端情況。 如果你有一個完美運作但無法更改的程式,那麼當需求改變時它將無法運作,意謂著這個程式將變得沒有用處;然而一個不起作用但容易修改的程式,那麼我們可以透過簡單的修改使其運作起來,並在需求變化時保持運作,因此這個程式將持續保持有用。 也許這個論點對有些人來說不那麼具有說服力,畢竟沒有什麼程式是真的不能改變的。但是,有些系統在實際上是幾乎不可能改變的,因為改變的成本大過於了改變的好處。許多系統在某些功能或配置上達到了這一點。 如果你問企業經理們是否希望能夠進行變更,他們當然會說是,但可能會在回答中指出目前的功能比任何後續的靈活性更重要。相反地,如果企業經理們向你提出變更要求,而你估計的成本過高而無法負擔,他們很可能會對你允許系統達到變更變得不切實際的程度感到憤怒。 艾森豪威爾矩陣 下圖為艾森豪威爾(Dwight D. Eisenhower)總統的重要性(importance)與緊迫性(urgency)的矩陣,艾森豪是這麼說的: 我有兩種問題,一種是緊急的,一種是重要的。緊急的問題並不重要,而重要的問題從不緊急。 軟體的第一個價值 - 行為,是緊迫但並非總是特別重要。 軟體的第二個價值 - 架構,重要但從不特別緊迫。 當然,有些事情既緊急又重要,或有些事情既不緊急又不重要。故最終,我們可以將這四種問題安排成優先順序: 緊急且重要 不緊急但重要 緊急但不重要 不緊急也不重要 需要注意的是,程式碼的架構位於前兩個位置,而程式碼的行為則佔據第一與第三的位置。商業經理和開發人員常犯的錯誤是將第三位的事項提升至第一位。換句話說,他們未能將那些緊急但不重要的功能與真正緊急且重要的功能區分開來。這種失誤導致忽視系統的重要架構,而偏好系統中不重要的功能。 軟體開發人員面臨的困境是,商業經理無法評估架構的重要性。這就是軟體開發人員被聘用的原因。因此,軟體開發團隊有責任強調架構的重要性,而不是功能的緊迫性。 為架構而戰 履行這個責任意味著投入一場戰鬥,或者也許更好的詞是「奮鬥」。坦白說,這些事情總是這樣做的方式。開發團隊必須為他們認為對公司最好的事情而奮鬥,管理團隊、市場團隊、銷售團隊和運營團隊也是如此。這總是一場奮鬥。 有效的軟體開發團隊會毫不畏懼地與其他利益相關者平起平坐地爭論。請記住,作為一名軟體開發者,您也是一個利益相關者。您需要保護您所需的軟體。這是您的角色和責任的一部分,也是您被雇用的重要原因之一。 如果你是一位軟體架構師,這個挑戰對你來說尤其重要。軟體架構師根據他們的工作描述,更關注系統的結構而非其特性和功能。架構師創建一個架構,使得這些特性和功能能夠容易地開發、修改和擴展。 只要記住:如果架構放在最後,那麼系統的開發成本將會愈來愈高,最終對系統的某個部分或整個系統的變更幾乎變得不可能。如果這種情況發生,那意味著軟體開發團隊沒有為他們知道的必要事項進行足夠的努力。

September 4, 2023 · 1 分鐘 · Rain Hu

[IT] Clean Architecture - 第1章 - 設計與架構到底是什麼

Ch1. 設計與架構到底是什麼? 對初學者而言,設計(Design) 與架構(Architecture) 基本上是沒有差別的。 「架構」這個詞常常用在高層次的情境,而與低層次的細節脫節;而「設計」則更常用於暗示著低層次的結構和決策。但事實上底層的細節與高層次的架構往往是伴隨而生的。(作者以建築設計作為範例,在建築設計圖中,會包含房屋形狀、外觀設計、高度、房間佈局等等,但同時也具備大量的設計細節,如每個插座、開關以及每個電燈具體的安裝位置,甚備某個開關與所控制的電燈的具體連接訊息等等。) 總而言之,底層設計細節和高層架構資訊是不可分割的。它們共同定義了整個軟體系統,缺一不可。所謂的底層和高層本身就是一系列決策組成的連續體,並沒有清晰的分界線。 目標是什麼? 軟體架構的終極目標是,用最小的人力成本來滿足構建和維護該系統的需求。 一個軟體架構的優劣,可以用它滿足用戶需求所需要的成本來衡量。如果成本很低,並且在系統整個生命週期內一直都能維持這樣的成本,那麼這個系統的設計就是優良的。反之如果該系統的每次發布都會提升下一次變更的成本,那麼這個設計就是不好的。 案例分析 下面為書中的一個真實案例,該案例中的數據均來源於一個匿名的真實公司。 該公司的工程人員數量的增長 由圖可見,人員的增長肯定是顯示了產品重大的成功。 2. 該公司同一時段的生滻力 從第二張圖可以發現一些端倪,雖然開發者愈來愈多,但程式碼的增長似乎接近了一個漸近線。 3. 隨著時間推移每行程式碼的成本 從第三張圖可見,成本快速的增加,大量地消耗利潤,將公司推向停滯,甚至是完全崩潰的境地。 凌亂系統的特點 當系統匆忙地拼湊在一起,當程式設計師的數量成為唯一的驅動力,而沒有考量程式碼的整潔度與設計結構時,必定會走向醜陋的結局。 每次版本發布的生產力 這張圖顯示了開發人員對這條曲線的看法。一開始的生產力接近100%,但隨著每次發布,生產力逐漸下降,最後趨近於零。 從開發者的角度來看,真是令人沮喪,因為每個人都在努力工作,但實際上已經無法完成更多。所有努力都被轉移到處理混亂上了,而不是開發新功能。 管理層視角 每次版本發布時的薪資支出 由圖明顯可見,後期投入的資金幾乎沒有帶來任何東西。但其中發生了什麼問題呢? 問題到底在哪裡? 現代的程式開發者,大腦中有一部分是在沉睡的,儘管它們知道「好的、乾淨的、設計良好的程式碼是重要的」。 這些程式開發者通常相信一個熟悉的謊言:「我們可以之後再整理,我們現在更需要趕快上線。」實際上是,在未來,程式從來不會被整理,因為市場上的壓力永遠不會減輕。所以開發人員從來不會切換模式,他們無法回頭整理事情,因為他們被逼著完成下一個任務,一而再再而三。於是混亂愈來愈多,生產力逐漸趨近於零。 程式開發者還相信一個更大的謊言:「沒有秩序的程式碼可以讓他們在短期內快速前進,且只會在長期才會反應出速度的變慢」,他們認為可以在未來的某個時刻從製造混亂轉換成整理混亂,但事實是,無論使用哪種時間尺度,製造混亂總是比保持整潔更慢。 完成任務所需的時間(With TDD/No TDD) 圖6是傑森戈爾曼(Json Gorman)進行的一個實驗。傑森在六天的時間內反覆進行這項測試,每一天他會完成一個整數轉羅馬數字的簡單小程式,當他通過了他預定義好的ATDD(Acceptance Tests),他可以清楚知道他完成了程式。在過去六天內,每天的任務都花不到30分鐘。在第一、第三、第五天使用了 TDD(Test Driven Development),而另外三天則沒有遵守。結果顯示,後期工作完成速度比前期快,而在實施 TDD 的日子裡,工作進展大約比沒有實施的日子快了 10%,即使是最慢的TDD日子也比非TDD的日子還快。 結論 在每一種情況下,最好的選擇是開發組織要認識到並避免自己的過度自信,並且開始認真對待軟體架構的質量。 要認真對待軟體架構,你需要知道什麼是良好的軟體架構。為了構建一個設計和架構能夠最大程度減少工作量並提高生產力的系統,你需要知道哪些系統架構的特性能夠達到這個目標。 這本書就是在談這個,它描述了好的乾淨架構和設計的樣貌,讓軟體開發者能夠建立具有長期盈利生命力的系統。

September 3, 2023 · 1 分鐘 · Rain Hu

[IT] Clean Architecture - 第一部分 概述

 採用好的軟體架構可以大大節省軟體項目構建與維護的人力成本。讓每次變更都短小簡單,易於實施,並且避免缺陷,用最小的成本,最大程度地滿足功能性和靈活性的要求。

September 3, 2023 · 1 分鐘 · Rain Hu

[IT] Clean Architecture - Catalog

Clean Architecture A Craftsman’s Guide to Software Structure and Design 中文翻譯: 無瑕的程式碼 - 整潔的軟體設計與架構 原著: Robert C. Martin(Uncle Bob) 目錄 第一部分 概述 第1章 - 設計與架構到底是什麼 第2章 - 兩個價值維度 第二部分 從基礎構件開始: 程式設計範式 第3章 - 程式設計範式總覽 第4章 - 結構化程式設計 第5章 - 物件導向程式設計 第6章 - 函數式程式設計 第三部分 設計原則 第7章 - SRP 單一職責原則 第8章 - OCP 開放封則原則 第9章 - LSP 里氏替換原則 第10章 - ISP 介面隔離原則 第11章 - DIP 依賴反轉原則 [第四部分 組件構建原則)(/clean_arch/sec4) 第12章 - 元件 第13章 - 元件聚合 第14章 - 元件耦合 第五部分 軟體架構 第15章 - 什麼是軟體架構 第16章 - 獨立性 第17章 - 劃分邊界 第18章 - 邊界剖析 第19章 - 策略與層次 第20章 - 業務邏輯 第21章 - 尖叫的軟體架構 第22章 - 整潔架構 第23章 - 展示器和謙卑物件 第24章 - 不完全邊界 第25章 - 層次與邊界 第26章 - Main 元件 第27章 - 服務: 宏觀與微觀 第28章 - 測試邊界 第29章 - 整潔的嵌入式架構 第六部分 實現細節] 第30章 - 數據庫只是實現細節 第31章 - Web 是實現細節 第32章 - 應用程式框架是實現細節 第33章 - 案例分析: 影片銷售網站 第34章 - 拾遺

September 3, 2023 · 1 分鐘 · Rain Hu

[CS] Sample cost for performance test

Sample code for stop watch using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Runtime.CompilerServices; using System.Data.Common; using System.Diagnostics; using System.Drawing; using System.Text; using System.Threading.Tasks; namespace Rainspace.PlayGround { public class Program { public static void Main(string[] args) { Stopwatch sw = new Stopwatch(); sw.Start(); System.Console.WriteLine("==============Accumulate1=============="); System.Console.WriteLine("Result: " + Accumulate(0, 100, 0)); sw.Stop(); System.Console.WriteLine("Time cost: " + (sw.ElapsedTicks/1.0e6).ToString() + "ms"); sw.Reset(); sw.Start(); System.Console.WriteLine("==============Accumulate2=============="); System.Console.WriteLine("Result: " + Accumulate(0, 100, 0)); sw.Stop(); System.Console.WriteLine("Time cost: " + (sw.ElapsedTicks/1.0e6).ToString() + "ms"); } public static int Accumulate(int begin, int end, int sum = 0) { int res = sum; if (end < begin) return Accumulate(end, begin, sum); for (int i = begin; i < end; i++) { res += i; } return res; } public static int Accumulate2(int begin, int end, int sum = 0) { int res = (begin + end) * (end - begin) / 2; return res + sum; } } }

May 16, 2023 · 1 分鐘 · Rain Hu

[IT] 關聯模式的五大鍵 Super key、Candidate Key、Primary Key、Alternate Key、Foreign Key

關聯模式的條件 關聯模式可以比實體關係模式(ERM)更精準的描述資料,他有幾個條件必須滿足: 定義域限制: 指資料庫的關聯中的每個屬性質,必須符合該屬性的定義,例如產品名稱必須是字串,薪水必須是整數數字等。 關聯鍵限制: 指資料庫的關聯中必須有關聯鍵的定義,也就是Super key、Candidate Key、Primary Key、Alternate Key、Foreign Key。這些定義我們稍後再來解釋。 實體完整限制: 如果關聯存在主鍵(Primary Key),則不能為空。因為如果為空值,無法得知其相關的屬性值到底是描述哪一個實體。 參考完整限制: 如果關聯存在外鍵(Foreign Key)為非空值,必須有可以參考的主鍵(Primary Key)。因為如果外鍵存在,而無法關連到其他表格的主鍵,這個關聯存在就沒有意義。 語意完整限制: 這個限制不是必須的,但是可以更完備的描述實體世界的資料。例如交易金額高於100元才可以使用信用卡付款等。 關聯模式的五大鍵 Super key 超鍵: 符合唯一性的關聯鍵。 Candidate Key 候選鍵: 符合唯一性以及最小性的關聯鍵。 Primary Key 主鍵: 從候選鍵中,挑選出其中一個關聯鍵,也就是最具識別意義的關聯鍵。 Alternate Key 次要鍵: 沒有被選為主鍵的其他候選鍵。 Foreign Key 外鍵/外部鍵: 關聯中被用來參考到其他表格主鍵的關聯鍵,就是外鍵。 例如學生資料表(student_id, student_no, student_name, student_depid) student_id student_no student_name student_depid A123454321 00001 Rain Hu MSE A123123123 00002 Mike Hu IM A221232134 00003 Eva Hsu ECE A223124125 00004 Dudu Liu ECE A124124512 00005 Gober Wei IT student_id表示學生身分證字號 student_no表示學生學號 student_name表示學生姓名 student_depid表示學生的科系代號 Super key 就可以是 {student_id}、{student_no}、 {student_id, student_no}、{student_id, student_name}、{student_id, student_depid} … 等等,都符合唯一性的條件。 Candidate Key 就可以是 {student_id}、{student_no},都符合唯一性及最小性的條件。 Primary Key 就可以從Candidate Key挑選一個,至於挑選哪一個,就看你的系統特性。如果你的學校是多學制的話,就可能不適合挑選學生身分證字號當主鍵,因為可能某個學生原本是國中部,畢業後再進入高中部,如果系統沒有考慮清楚,這個畢業後再變新生的個體,就可能出錯。 Alternate Key 就是沒被挑中當成Primary Key的其他Candidate Key,例如,如果挑選 {student_id}當成主鍵,Alternate Key 就是{student_no}。 如果存在科系資料表 (depid, dep_name),而且depid當成科系資料表的主鍵,學生資料表的 student_depid就是Foreign Key。 資料來源:https://www.mysql.tw/2015/04/super-keycandidate-keyprimary.html ...

May 11, 2023 · 1 分鐘 · Rain Hu

[IT] Design Patterns

設計模式 Design Pattern 什麼是設計模式? 設計模式是指在軟體設計中通常出現的問題的典型解決方案。它們就像是預先製作好的藍圖,您可以根據自己程式碼中出現的重複設計問題來進行自定義。 設計模式不是一個特定的程式碼,而是一個解決特定問題的一般概念。您可以按照模式的細節來實現適合自己程式的解決方案。值得注意的是,設計模式常與演算法混淆,因為這兩個概念都描述了解決某些已知問題的典型解決方案。模式是一個更高層次的解決方案描述。 模式通常包括模式意圖、動機、結構、程式碼示例等幾個方面,以便人們在多種情況下可以複製它們。模式目錄還列出了其他有用的細節,例如模式的適用性、實施步驟和與其他模式的關係。 誰發明了設計模式? 設計模式不是晦澀難懂、高深複雜的概念,相反地,它們是物件導向設計中解決常見問題的典型解決方案。當一個解決方案在不同的項目中反復出現,某人最終會給它命名並詳細描述解決方案。這基本上是模式的發現方式。 模式的概念最初是由Christopher Alexander在《模式語言:城鎮、建築、建設》中描述的。這本書描述了一種用於設計城市環境的“語言”。這種語言的單位是模式。它們可以描述窗戶應該有多高,建築物應該有多少層,社區中綠地的大小應該是多少等等。+ 這個想法被四位作者Erch Gamma、John Vlissides、Ralph Johnson和Richard Helm接受。在1994年,他們出版了《Design Patterns: Elements of + Reusable Object-Oriented Software》一書,將設計模式的概念應用於編程中。該書介紹了23個解決物件導向設計中各種問題的模式,並迅速成為暢銷書。由於書名過長,人們開始稱之為“四人幫的書(Gang of Four, GoF)”。 此後,發現了許多其他物件導向模式。模式方法在其他編程領域也變得非常流行,因此現在還存在許多與物件導向設計無關的模式。 為什麼要學習設計模式? 設計模式是解決軟體設計中常見問題的一套經過驗證的解決方案工具包。即使從未遇到這些問題,了解模式仍然有用,因為它可以使用物件導向設計原則解決各種問題。 設計模式定義了一個共通的語言,使團隊之間可以使用它更有效地進行溝通。 設計模式的分類 設計模式可以根據其複雜性、細節程度和應用於整個系統的規模進行分類。它們有點像道路建設的類比:通過安裝交通信號燈或建造整個多層立交橋和地下通道來使十字路口更安全。 最基本和低層次的模式通常被稱為 “idioms”。它們通常僅適用於單一程式語言。 最通用和高層次的模式是架構模式(architectural patterns)。開發人員可以在幾乎任何語言中實現這些模式。與其他模式不同,它們可用於設計整個應用程序的架構。 此外,所有模式都可以通過其意圖或目的進行分類。本文將涵蓋三個主要模式: 創建型模式(creational):提供了增加彈性和重複使用現有代碼的物件創建機制。 結構型模式(structural):解釋如何將物件和類組合成更大的結構,同時保持這些結構的靈活性和效率。 行為型模式(behavioral):負責處理物件之間的有效溝通和職責分配。 SOLID 原則 在進入本文之前,來認識一下 SOLID 原則:(詳細的內容可以參考YC的部落格) S = Single-responsibility principle (SRP) = 單一職責原則 O = Open–closed principle (OCP) = 開放封閉原則 L = Liskov substitution principle (LSP) = 里氏替換原則 補充:jyt0532 I = Interface segregation principle (ISP) = 介面隔離原則 D = Dependency inversion principle (DIP) = 依賴反向原則 正文 Factory 簡介 ...

May 1, 2023 · 1 分鐘 · Rain Hu
Oh! You closed up the window, so you cannot see raining

[IT] C# Depth Ch.2 C# 2

C# 2 一、泛型 使用泛型(generic type)可以在編寫在編譯時類型安全的通用程式碼,無須事先知道要使用的具體類型。 示例1: array類型: 大小需預先設定,若要添加需要重新分配 public static void Main(string[] args) { PrintNames(GenerateNames()); } public static void PrintNames(string[] names) { foreach (string name in names) { Console.WriteLine(name); } } public static string[] GenerateNames() { string[] names = new string[4]; names[0] = "Mike"; names[1] = "Rain"; names[2] = "Jessica"; names[3] = "Billy"; return names; } 示例2: ArrayList類型: ArrayList.Add是Object的方法,但如果塞入不適合的參數類型,可能會引發InvalidCastException public static void Main(string[] args) { PrintNames(GenerateNames()); } public static void PrintNames(ArrayList names) { foreach (object name in names) { Console.WriteLine(name); } } public static ArrayList GenerateNames() { ArrayList names = new ArrayList(); names.Add("Mike"); names.Add("Rain"); names.Add("Jessica"); names.Add("Billy"); return names; } 示例3: StringCollection專用類型: 解決前述兩個問題,但也限制了返回值。 ...

January 20, 2023 · 2 分鐘 · Rain Hu
Oh! You closed up the window, so you cannot see raining

[IT] C# Depth Ch.1 與時俱進的語言

與時俱進的語言 一、System Class 1. 泛型(genric) 可更清楚的描述序列中每個元素的類型。 C#1 示例 public class Bookshelf { public IEnumerable Books { get { ... } } } C#2 示例:泛型 public class Bookshelf { public IEnumerable<Book> Books { get { ... } } } 2. 可空值類型(nullable value type) 可有效的表示未定的變量值,以擺脫魔數(用-1當集合索引,用 MinValue 或 MaxValue 做為初始值)。 示例 string? a = null; Console.WriteLine(a ?? "null"); // null a = "abc"; Console.WriteLine(a ?? "null"); // abc 3. 匿名類型(anonymous type)、隱式局部變數(var) 兩者皆可解決靜態類型語言的缺陷:程式碼冗長。 示例1: 匿名類型(anonymous type) var book = new { Title = "Harry Potter", Author = "J.K. Rowling" } string title = book.Title; string author = book.Author; 若已經調用了建構式的話,就無需顯式的宣該告變數的類型了。 示例2: 隱式類型(implicit typing) ...

January 17, 2023 · 2 分鐘 · Rain Hu

[IT] Shell 筆記

Reference https://blog.csdn.net/w918589859/article/details/108752592 https://www.w3cschool.cn/linux/linux-Shell.html 一、Shell 簡介 什麼是 Shell? Shell 是一個用 C 語言編寫的程式,它是使用者使用 Linux 的橋樑。Shell 既是一種命令語言,又是一種程式設計語言。 Shell 是指一種應用程式,這個應用程式提供了一個界面,使用者通過這個界面訪問作業系統核心(kernel)的服務。 為什麼要學習和使用 Shell? Shell 屬於內建的腳本,程序開發的效率非常高,依賴於功能強大的命令可以迅速的完成開發任務(批次處理)。 Shell 腳本(Shell script) 是一種為 Shell 編寫的腳本程式。業界所說的 Shell 通常都是指 Shell 腳本。 二、 Shell 入門 1. Shell 環境 Shell 編程需要能編寫程式碼的文本編輯器和一個能解釋執行的腳本解釋器。 在 linux 中有很多類型的 Shell,不同的 Shell 具備不同的功能,Shell 還決定了腳本中函數的語法。 Bash 是 Linux 中默認的 Shell。一般情況下,人們不區分 Bourne Shell 和 Bourne Again Shell,所以 #!/bin/sh 也可以被替換成 #!/bin/bash Linux 的 Shell 種類眾多,不同的 Shell 都有自己的特點以及用途,常見的有: Bourne Shell (/usr/bin/sh 或 /bin/sh) Bourne Again Shell (/bin/bash) C Shell (/usr/bin/csh) K Shell (/usr/bin/ksh) Shell for Root(sbin/sh) …… 2. Bash 常用快捷鏈 快捷鏈 功能 Ctrl+A 把游標移動到命令行開頭。 Ctrl+E 把游標移動到命令行結尾。 Ctrl+C 強制終止當前的命令。 Ctrl+L 清除螢幕,等於 clear 指令。 Ctrl+U 清除並剪下當前命令。 Ctrl+K 刪除並剪下游標以後的命令。 Ctrl+Y 貼上。 Ctrl+R 在歷史命令中搜索,按下 Ctrl+R 之後,就會出現搜索界面,只要輸入搜索內容,就會從歷史命令中搜索。 Ctrl+D 退出當前終端機。 Ctrl+Z 暫停,並放入後台。 Ctrl+S 暫停螢幕輸出。 Ctrl+Q 恢復螢幕輸出。 3. 輸入與輸出 I/O linux 的標準輸入與輸出 ...

January 12, 2023 · 3 分鐘 · Rain Hu