秋分
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    --- tags: lsa --- # 自動測試 - Book mode https://hackmd.io/@ncnu-opensource/book [TOC] ## 敏捷開發 (Agile software development) ### 何為敏捷開發? > 打程式打超快? ![](https://media.giphy.com/media/unQ3IJU2RG7DO/giphy.gif) #### 敏捷宣言 - **個人與互動** 重於 **流程與工具** - **可用的軟體** 重於 **詳盡的文件** - **與客戶合作** 重於 **合約協商** - **回應變化** 重於 **遵循計劃** > 重視後者,但是更重視前者 #### 要達成甚麼? - 軟體適應性 - 程式設計師團隊與業務專家之間的緊密協同運作 - 能夠很好地適應需求變化的程式編寫和團隊組織方法 - 頻繁交付新的軟體版本以達成較短的開發循環 ## DevOps ### 為什麼出現?要解決什麼問題? > 開發團隊與維運團隊溝通不良,會讓雙方容易產生衝突,而讓整個專案進行的效率低下,DevOps 就是為了讓兩個團隊可以夠順利的溝通合作而出現的一種文化。 故事: [為什麼會出現DevOps?](https://www.ithome.com.tw/news/96861) <!-- > - GOODBOOK: > - [鳳凰計劃](https://www.tenlong.com.tw/products/9789864765867?list_name=srh) > - [clean code](https://www.tenlong.com.tw/products/9789862017050?list_name=srh) > - [學徒模式](https://www.tenlong.com.tw/products/9789862762561) --> ### 如何達成 - 增加各單位間的溝通,確保所有相關人員理解變更的內容並全力合作 - 透過自動化,加速並簡化軟體建構、測試、發布的過程,同時也可以減少人為錯誤發生 - 幅度小而頻繁的變更,可以降低出錯的風險 :::info **SRE (Site Reliability Engineering) 網站可靠性工程** > 基本上就是準備背鍋跟避免背鍋 [name=BT] > 它實作了 DevOps 的所定義的抽象方法,而且規範了更多關於如何用軟體工程的方法與從維運的角度出發,以達成讓系統穩定的目的。 ::: > FIXME: add link ( SRE ) ## CI/CD - 為了解決 - 花費多餘成本在做人工測試 - 人工作業比較容易出錯 - 需要快速得到市場的回應 <!-- > FIXME: 少數(幅度較小)頻繁的更動 FAST iteration --> <!--![](https://i.imgur.com/eQdTS3j.png)--> ![](https://i.imgur.com/GnkAedU.png) ### 流程圖 ![](https://i.imgur.com/qXZeTrC.png) <!-- ![](https://i.imgur.com/Incg4in.png) --> [imgRef](https://www.lucidchart.com/blog/continuous-deployment-best-practices) ![](https://i.imgur.com/E7lFCaK.png) [imgRef](https://www.designnews.com/electronics-test/developing-embedded-software-build-pipeline) <!-- > FIXME: UAT、automated acceptance 的測試細節 --> <!-- > FIXME: developer vs development --> <!-- > FIXME: 注意開發周期的圖 ( 強調週期 ) --> ### CI (Continuous Integration) 持續整合 :::success 自動化的將程式建構起來並進行測試 ::: :::info ![](https://i.imgur.com/63BPDdF.png) ::: 1. build source code 2. 執行測試 3. 執行程式碼分析 5. 自動部署 6. 資料庫整合(初始化資料、還原資料、更新資料庫 Schema 等等...) <!-- > FIXME > 為什麼呢 --> <!--[ref](https://ithelp.ithome.com.tw/articles/10081751) --> <!--selenium--> ### CD (Continuous Delivery / Deployment) 持續交付 / 持續部署 :::success 將 CI 階段 build & test 完畢的程式部屬到測試環境和生產環境 ::: :::info **Delivery & Deployment 的差異** #### 兩者的差異在於是否自動部屬到生產環境 ![](https://i.imgur.com/BioLlEk.png) ::: #### 優點 - 能快速做好測試、分析、部屬 - 防止有問題的程式被提交上去 - 開發人員可以專注於專案 - 快速地將功能丟到市場上驗證,降低團隊開發與市場需求不一致時的反應時間 #### 缺點 - 一些老舊系統可能不支援 - 需要事先的學習或投資 ### 測試 ![](https://i.imgur.com/vbTjHFj.png) [img source](https://automationpanda.com/2018/08/01/the-testing-pyramid/) <!-- ![](https://i.imgur.com/20q0Cam.png) --> #### 單元測試 (Unit testing) > 是針對程式模組來進行正確性檢驗的測試工作 > 正規來說,每修改一次程式就會進行最少一次單元測試 > 良好設計的單元測試案例會覆蓋程式單元分支和迴圈條件的所有路徑 ##### 用意 隔離程式部件並證明這些單個部件是正確、符合預期的,讓我們在開發過程的早期就能發現問題 - **適應變更** - 為所有函式和方法編寫單元測試,一旦變更導致錯誤發生,藉助於單元測試可以快速定位並修復錯誤 - **簡化整合** - 通過先測試程式部件再測試部件組裝,消除程式單元的不可靠,使整合測試變得更加簡單 - **文件記錄** - 藉由檢視單元測試提供的功能和單元測試中如何使用程式單元,開發人員可以直觀的理解程式單元 - **表達設計** - 在 TDD 中,會先寫測試而後再做開發,這樣有助於在開發初期釐清程式介面如何設計 > TDD(Test-Driven Development)測試驅動開發,簡單說就是「先寫測試再開發」 <!-- --> ##### 整合測試 (Integration testing) > 針對各模組之間的互動進行測試 ###### 用意 單元測試通過不表示程式可正常運行,整合測試可確保程式裡各個單元互動正常 <!--###### 種類 - Big Bang - 將所有元件合併在一起一次測試 - Top Down - 從最上層的模組開始往下測試 - Bottom Up - 從最下層的模組開始往上測試 - Sandwich - 同時從最上跟最下層往中間測試 --> ##### 端對端測試 (End-to-end testing / E2E testing) > 模擬使用者操作應用程式的行為 ###### 用意 測試會與真實使用狀況一致,可模擬應用程式的實際表現 :::warning E2E 測試耗時且較難找出問題確切位置,所以前面單元及整合測試要確實,E2E 測試才能體現出效益 ::: :::info ### UAT (User Acceptance Testing)用戶接受度測試 > 部署軟體之前的最後一個測試操作,確保軟體準備就緒,並且可以讓使用者執行軟體預期的功能 #### 步驟 1. **軟體需求分析**:瞭解軟體功能和性能要求、軟硬體環境要求等,並特別要瞭解軟體的品質要求和驗收要求。 2. **編製「用戶接受度測試計劃」和「專案驗收準則」**:根據軟體需求和驗收要求編製測試計劃,制定需測試的測試項,制定測試策略及驗收通過準則,並經過客戶參與的計劃評審。 3. **測試設計和測試用例設計**:根據「用戶接受度測試計劃」和「專案驗收準則」編製測試用例,並經過評審。 4. **測試環境搭建**:建立測試的硬體環境、軟體環境等。 5. **測試實施**:測試並記錄測試結果。 6. **測試結果分析**:根據驗收通過準則分析測試結果,作出驗收是否通過及測試評價。 7. **測試報告**:根據測試結果編製缺陷報告和用戶接受度測試報告,並提交給客戶。 ::: <!--> 並不是所有網站都值得撰寫測試,對於一個需求不確定、價值性不高的網站來說,撰寫測試就是浪費時間--> <!-- ### github / gitlab flow > 待補 --> ### TDD (Test-Driven Development) 測試驅動開發 > 先寫測試再做開發 #### 優點 - 在開發初期釐清程式介面如何設計 - 使介面易於測試,可以讓介面寫好的當下馬上進行測試,確認是否符合預期 #### 步驟 ![](https://i.imgur.com/8in3yyw.png) 1. 開始寫測試 - 寫測試同時思考希望怎麼去使用目標程式 2. 執行測試,得到 Failed(紅燈) - 因為還沒開始寫程式本體,所以應該要出錯 - 確認測試可以跑 3. 實作「夠用」的程式 - 實做出最低限度可以正確執行的程式 - 不要求將程式優化 4. 再次執行測試,得到 Passed(綠燈) - 因為程式本體已經完成,所以應該得到 passed 5. 重構程式 - 改善程式碼,提升可讀性、可維護性、擴充性 - 同時需確保每次修改後,執行測試皆能通過,確保程式有符合預期的執行 #### 缺點 - 可能會被測試綁住,太著重於通過測試而忽略程式應有功能 - 讓簡單的專案複雜度增加 - 整個開發時間延長 - 測試內容只由開發人員設計,可能無法完整呈現程式需求 <!-- > = unit-test der test-case: > - 後面發現之後的模組重新組合會比較好 > - 太要求彈性也不大好 > - 增加哪裡來,哪裡去、解救誰、優缺點 --> ### BDD (Behavior-driven development) 行為驅動開發 > 比 TDD 更進一步,在寫測試前先寫測試規格書 #### 用途 - 為了讓非開發人員可以參與程式的設計 #### 規格書格式 ``` Feature: 一句話簡介這份規格書所涵蓋的軟體功能 對這份規格書更多的介紹 (非必要,不影響自動測試) 介紹.... 介紹.... Scenario: 要測試的測試案例 1 Given 前提條件是.... When 我做了某件事.... Then 結果應該得到... Scenario: 要測試的測試案例 2 Given 前提條件是.... When 我做了某件事.... Then 結果應該得到... ``` :::info #### user story 一種規格文件,從客戶或使用者的觀點,用日常語言或商務用語來撰寫句子以描述功能,在敏捷開發中拿來定義系統需要提供的功能和實現需求管理。 - one common template >As <who> <when> <where>, I <want> because <why> ::: #### cucumber > 輔助執行 BDD 的一個軟體 - 以 node.js 作為範例 - 創個新專案 ``` mkdir hellocucumber cd hellocucumber npm init --yes ``` - 安裝 cucumber `npm install --save-dev @cucumber/cucumber` - 在 `package.json` 修改 test ```json= "scripts": { "test": "cucumber-js" } ``` - 準備待會檔案要放置的資料夾 ``` mkdir features mkdir features/step_definitions ``` - 在專案根目錄創一個 `cucumber.js` ```javascript= module.exports = { default: `--format-options '{"snippetInterface": "synchronous"}'` } ``` - `features/step_definitions/stepdefs.js` ```javascript= const assert = require('assert'); const { Given, When, Then } = require('@cucumber/cucumber'); ``` - 這時如果跑 `npm test` cucumber 會跟你說他沒找到東西可跑 - 要有東西跑,我們要創個 Scenario,Scenario 將會被定義在 `.feature` 檔裡 - `features/is_it_friday_yet.feature` ``` Feature: Is it Friday yet? Everybody wants to know when it's Friday Scenario: Sunday isn't Friday Given today is Sunday When I ask whether it's Friday yet Then I should be told "Nope" ``` - 上面這個 Scenario 的意思是說 - `Feature: Is it Friday yet?` 標題,我們要測試的內容是今天是不是星期五 - `Everybody wants to know when it's Friday` 描述,非必要 - `Scenario: Sunday isn't Friday` 這個案例是說今天星期日,不是星期五 - `Given today is Sunday` 前提: 今天是星期日 - `When I ask whether it's Friday yet` 當我問今天是不是星期五 - `Then I should be told "Nope"` 那我應該得到的回答是 Nope - 這時如果執行 `npm test`,他會找到東西跑,但他會告訴我們那些情境與步驟都尚未被定義 - 在他的警告訊息裡會給你他建議的模板程式,可以直接將那些加到我們的 `features/step_definitions/stepdefs.js` 裡 ```javascript= Given('today is Sunday', function () { // Write code here that turns the phrase above into concrete actions return 'pending'; }); When('I ask whether it\'s Friday yet', function () { // Write code here that turns the phrase above into concrete actions return 'pending'; }); Then('I should be told {string}', function (string) { // Write code here that turns the phrase above into concrete actions return 'pending'; }); ``` - 這時再跑 `npm test` 會發現他能抓到我們寫的程式,並顯示說他們回傳狀態為 pending - 將程式修改 ``` const assert = require('assert'); const { Given, When, Then } = require('@cucumber/cucumber'); function isItFriday(today) { // We'll leave the implementation blank for now } Given('today is Sunday', function () { this.today = 'Sunday'; }); When('I ask whether it\'s Friday yet', function () { this.actualAnswer = isItFriday(this.today); }); Then('I should be told {string}', function (expectedAnswer) { assert.strictEqual(this.actualAnswer, expectedAnswer); }); ``` - 注意 `function isItFriday` 裡面並沒有寫東西,因為按照 BDD 流程我們應該先寫測試 - 跑 `npm test` 我們應該會得到 fail - 最後我們實作程式本體 ```javascript= function isItFriday(today) { if(today === 'Friday'){ return 'Yes Yes Yes'; } else{ return 'Nope'; } } ``` - 這時再跑 `npm test` 就應該會通過測試 ## 故事時間 ### VM - 安全性高,在 VM 中做的動作不會影響到 Host OS - 使用較容易 - <span class="aka">耗時耗資源</span> - 每次都要先在 VM 裡面裝好一套作業系統才能執行應用程式 - 建好作業系統也要等開機 - 就算應用程式本身只有幾 KB,還是必須要耗費一整個作業系統的資源 - 伺服器不只要分配資源給應用程式本身,也會需要將一部份運算資源分給作業系統的執行 ### Container - 執行速度快 - VM 以分鐘為單位 - Container 可以秒為單位 - 儲存空間小 - VM 以 GB 為單位 - Container 以 MB 為單位 - 資源更有效運用 - 免去了執行 Guest OS 的義務,同一台主機上可以裝載的 Container 數量可以是 VM 的好幾倍。 > VM 與 Container 的比較並非說孰優孰劣,只是特性不同,在不同情況下會有比較適合的選擇 ### 微服務 microservices **vs** 單體架構 Monolithic Architecture ![](https://i.imgur.com/wY21YiS.png) #### 單體架構 - 開發一個新專案時會比較簡單 - 測試操作起來會比較容易 - 結構規劃簡潔 :::danger **但是** - 服務之間的緊密度、相依性高,導致升級困難,測試容易出問題 - 程式太大容易讓人難以理解 ::: #### 微服務 - 將龐大的專案拆成幾個不同面向的小專案,當程式夠小、容易理解、開發效率能被提高 - 各個服務互相獨立,相依性較小,不易因一個服務癱瘓而癱瘓整個系統 - 各團隊可以依照自己的需求使用適合自己的語言、資料庫開發 - 每個服務可以依照自己的需求,選擇在不同機器上部署 - 服務可以獨立部署,小組可以直接更新現有服務,而不需要重建和重新部署整個應用程式 - 可針對單一服務做擴展,而不用將整個專案重新 run & deploy | 單體架構| 微服務 | | --------| -------- | | 較容易測試 | 較麻煩測試 | | 相依度較高 | 相依度較低 | | 適合小型專案 | 適合大型專案 | | 開發時比較侷限 | 開發時比較自由 | | 較容易開始開發 | 較麻煩開始開發 | ## Kubernetes :::success Kubernetes 是一個可以幫助我們管理容器的系統,他可以自動化部署及管理多台機器上的多個 container,對微服務架構有很好的支援 <!-- > FIXME: 大量部屬可以用 docker swarm , 用 k8s 的理由? --> #### 功能包含 - 同時部署多個容器到多台機器上 - 對容器做自動擴展 - 自動偵測並重啟故障的容器 [ref](https://hackmd.io/kO6-flQpSsmR5jk-dytgkA) ::: ### 跟 docker swarm 的比較 - docker swarm 比較簡單開始使用 - k8s 有著超過 1200 名貢獻者的龐大開源社群 - k8s 在較大型的專案上可以跑得比較順 ### 優點 - 可以跑在任何地方 - 可以在私有雲、公有雲或是混合雲上執行 - 高度模組化 - 每個服務都被切成一個 pod - 活躍的社群 ### 缺點 - 安裝及設定上比較複雜 ### 在 k8s 上裝 gitlab runner > 我們選擇使用 microk8s,它是個由 ubuntu 維護的軟體,輕量化的 k8s。 #### gitlab runner 我們需要有 gitlab runner 才可以在 gitlab 上面執行 CI/CD,雖然有公用的 runner (shared runner),但需要註冊信用卡而且也有使用時數限制,我們也可以選擇自己架設 runner,架設的環境有很多種選擇,[官網](https://docs.gitlab.com/runner/install/)上有各種安裝方法的教學。 #### 安裝過程 1. 安裝snap (一個軟體部署和軟體套件管理系統) `sudo apt update` `sudo apt install snapd` `sudo apt install snapcraft` 1. 安裝 microk8s `sudo snap install microk8s --classic` 2. 要先把使用者加入群組才可以使用 microK8s (記得重開機) `sudo usermod -a -G microk8s $USER` `sudo chown -f -R $USER ~/.kube` `sudo reboot` 2. 啟用 helm3 (管理 k8s 裡設定檔的一個工具) `microk8s.enable helm3` 3. 設定簡寫 `alias helm=microk8s.helm3` 4. 創建一個 namespace "gitlab" `microk8s.kubectl create ns gitlab` 5. add chart repo `helm repo add gitlab https://charts.gitlab.io` 6. 創建一個設定檔 [default yaml](https://gitlab.com/gitlab-org/charts/gitlab-runner/blob/main/values.yaml) `vim values.yaml` - config values file - 以下兩項必填,可以在 gitlab repo 的 setting -> CICD -> runner 找到 - `gitlabUrl` - `runnerRegistrationToken` 7. 安裝 runner `helm install --namespace gitlab gitlab-runner -f ./values.yaml gitlab/gitlab-runner` - `# helm install --namespace [namespace] [release name] -f [config values file] gitlab/gitlab-runner` 8. 列出所有 namespace 底下的 pods, services 等 `microk8s.kubectl get all --all-namespaces` :::success 要記得把 "Gitlab / Setting / CICD / Runner / Enable shared runners for this project" 的選項關閉,否則就算你有自己架 runner,gitlab 似乎會優先認為你要用 shared runner。 ::: :::warning ##### 若要刪除 runner - `helm delete --namespace gitlab gitlab-runner` - `# helm delete --namespace [namespace] [release name]` ::: :::info #### Helm 一個運行在 k8s 上的服務可能包含很多設定檔 (yaml 檔),為了方便管理或是快速部屬一個服務,我們可以使用 Helm 來幫助我們,他會把 k8s 一個服務中各種元件裡的 `yaml` 檔統一打包成一個叫做 `chart` 的集合,然後透過給參數的方式,去同時管理與設定這些 `yaml` 檔案。 ::: #### .gitlab-ci.yaml 範例 > 定義程式被 commit 之後應該自動執行哪些動作 ```yaml= stages: # 各個步驟的名稱 - build - test install_dependencies: # 名稱 stage: build # 表示屬於哪個 stage,可以重複,同樣 stage 的會同時執行 script: # 將執行的指令 - npm install express --save - npm install mocha --save-dev artifacts: # 讓此 stage 產生的指定檔案目錄可以被其他 stage 使用 paths: - node_modules/ unit test: image: node:latest # 在此 stage 要使用的 image stage: test script: - npm test ``` ### pipeline 執行例圖 ![](https://i.imgur.com/ogW0wBS.png) ## ref https://reurl.cc/7yGoL1 https://www.itread01.com/content/1546753336.html https://sensu.io/blog/kubernetes-vs-docker-swarm https://cwhu.medium.com/kubernetes-basic-concept-tutorial-e033e3504ec0 <style> .aka { background-color: #CD5C5C; color: white; font-size: 16px; font-weight: bolder; border-radius: 50% 20% / 10% 40%; } </style>

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully