Kai Chen
    • 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 New
    • 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 Note Insights Versions and GitHub Sync 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
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # 虎年行大運 ~ Clean Code 系列 - 編排 ## 【前言】 最近開始看 Clean Code 了,接下來會做關於書中內容的心得與個人經驗整理的分享文。 ## 【主文】 藝術這種東西、或稱概念,真的是見仁見智。 會用藝術來表達編排,也就表明了這是一種不被硬性規定的行為,如果你願意遵循,那或多或少可以幫助你在程式碼的設計架構上更清楚鮮明。當然這也不代表只有一種模式可以遵循,因應不同團隊、環境,有不同的方式需要遵循。 至於沒有這種規範的團隊或環境,則很適合去起個頭著手整頓一下大家的風格與意見,從而擬定建構出屬於你們的一套 Coding Style 靈活的運用可以清晰整體程式結構,幫助開發者在閱讀程式碼的速度與細節上的理解更快更準確,Kai 下面會整理一些書中的道理與自身碰到的例子做說明~ ## 【書中的大道至簡】 - **垂直** - **概念間的換行區隔** 現行的 IDE 幾乎都是從左至右,從上至下的書寫方式,這也是最貼近**自然視覺 - F 型瀏覽模式**的方式,至於什麼是 **F 型瀏覽模式**,可參考該篇文章 - [F型瀏覽模式:設計一個良好的視覺層級結構](https://kknews.cc/zh-tw/design/mmlln4g.html)。 如果讓程式碼的上下全部緊貼,那麼將會很難在短時間內辨識說諸如: 套件管理、建構子、屬性、方法等區塊內容,甚至也會不好理解程式全貌。 ```java= // 這是一段 Kai 在寫 LeetCode 的範例,壓成無垂直分段的樣子 import java.util.ArrayList; import java.util.List; public class MedianOfTwoSortedArray { public static void main(String [] args){ Solutions solutions = new Solutions(); int [] nums1 = new int[]{1,2,3}; int [] nums2 = new int[]{4,5,6}; System.out.println(solutions.findMedianSortedArrays(nums1, nums2)); } } class Solution { ... } ``` ```java= // 再看一段,有垂直分段的樣子 import java.util.ArrayList; import java.util.List; public class MedianOfTwoSortedArray { public static void main(String [] args){ Solutions solutions = new Solutions(); int [] nums1 = new int[]{1,2,3}; int [] nums2 = new int[]{4,5,6}; System.out.println(solutions.findMedianSortedArrays(nums1, nums2)); } } class Solution { ... } ``` 上述兩段程式碼是不是讓你有感閱讀所花費的時間不一樣呢? Kai 希望有^^ - **密度與距離** 相同的概念,盡量放置的靠近。 相依的概念,盡量放置在上下,對應使用關係上。 這是為了讓彼此閱讀起來更有連貫性、關係性,不要讓開發者花太多的時間追尋那些不應該需要重複閱讀的過程。 ```java= // 看一段被區隔開來的參數 public class Config{ public Config(){} /** * the class name of the config */ private String name; /** * the value of the config */ private String value; public Config(String name, Stirng value){ this.name = name; this.value = value; } } ``` ```java= // 再看一段整理過的 public class Config{ private String name; // class name of the config private String value; // value of the config public Config(){} public Config(String name, Stirng value){ this.name = name; this.value = value; } } ``` 上述並不是個太好的例子,因為這種註解基本上不該存在,但應該能夠董相同的概念需要放置一起這句話。至於相依的概念部分則是可以用以下舉例 ```java= // 看起來還不難看對吧? 但應該還可以再梳理一下~ public class Configs{ public Configs(List<String> names, List<Stirng> values){ this.setConfig(names, values); checkConfigValid(); sendFailureResponse(); } checkEachConfigValid(){...} sendFailureResponse(){...} setConfig(List<String> names, List<Stirng> values){...} checkConfigValid(){ for(...){ checkEachConfigValid() } } } ``` ```java= // 看起來"有序"多了對吧? public class Configs{ public Configs(List<String> names, List<Stirng> values){ this.setConfig(names, valus); checkConfigValid(); sendFailureResponse(); } setConfig(List<String> names, List<Stirng> values){...} checkConfigValid(){ for(...){ checkEachConfigValid() } } checkEachConfigValid(){...} sendFailureResponse(){...} } ``` 因 **checkConfigValid()** 呼叫了 **checkEachConfigValid()** 做使用,因此在編排上兩者應該盡可能靠攏,且應為 **checkConfigValid()** 放在上方;**checkEachConfigValid()** 在下方的方式。其他方法就依照在建構子中被呼叫的順序而定,這樣讓開發者逐一順下來的時候會更能從方法的次序去了解整體被呼叫時候的位置。 - **變數的宣告** 通常會將變數放置於最靠近使用的地方,若是實體變數(Instance Variables)則會放置在類別靠近上方的位置,因為他可能會被大多數的方法使用到。 若方法本身行數不多的時候,會建議將變數放在整體接近上方的部分,這是因為若方法有輸入的參數,讓開發者第一時間認知到有哪些輸入參數?內部有哪些變數?可以直接加深印象,繼續研讀的時候也不需要再去記得其他參數。 而程式碼本身很長的時候,變數的宣告則盡量靠近被使用到的部分,開發者在分段閱讀的時候可以容易追溯到變數在哪裡這件事情。 - **水平** - **總寬** 從以往的窄螢幕發展到現在的寬螢幕,一個螢幕可以容納的字元變得更多,開發者在編寫程式碼的時候更無須注意換行的需求。但事實上真是這樣嗎? 據統計來說,單行寬度字元達到 80 ~ 90 時,使用者習慣人數便會呈現雪崩式下滑,許多工程師反映無邊際的水平擴展程式碼完全不是朝著高可維護性的方向前進。 對大多數工程師而言,習慣的是介於 20 ~ 60 個字元之間,當然這完全都沒有任何硬性規定存在,如果能夠有建議,不妨測量一下公司提供的螢幕寬度,然後以螢幕寬度來制定最適當。畢竟你跟你的團隊都在同一間公司,使用的應當是同一類型的螢幕才對。 - **空白** 這邊提的不是為了縮排的空白,而是字裡行間的空白處理。這是為了凸顯出行段間的個別重要部分而做的事情,甚至在另一種用途上,空白還代表了強調運算子的優先權 (只是這部分通常會被自動化編排工具當成一般空白給忽略掉...),而這種運用手法尤其適合用在數學運算上。 ```java= // 舉個例子: 計算一個梯形面積並且減掉一個已知面積的內部圖形 // 未整理的 public double countArea(int topWidth, int downWidth, int height, double area2){ return (topWidth+downWidth)*height/2-area2; } // 整理後的 public double countArea(int topWidth, int downWidth, int height) { return (topWidth + downWidth) *height/2 - area2; } ``` 你完全可以明顯感受到整個公式變得更有訴說力,他們在強調著先後的邏輯順序,告知你整體的運算流程。眼尖的人甚至可以發現以下的不同。 ```java= countArea(int topWidth, int downWidth, int height, double area2){} countArea(int topWidth, int downWidth, int height, double area2) {} ``` 這是為了強調方法與參數的關係,使其不與實作區搞混。但這種作法實際上也沒有太要求就是了。 - **對齊** 有不少工程師喜歡做以下事情,去對齊他們的參數或是方法等等。 書中的作者原先也是喜歡採用這種方式撰寫程式碼,但久而久之發現,這反而強調了更多不應該去注意的部分,好比你看著 **getValue1**,同時也注意到了下面兩個參數,朦朧間你就認定了下面也是 private String 的宣告與型態,但這明顯是不對的。 你的視覺在不經意的時候已經注意到了不須要注意的部分,也容易因連續而造成錯誤的認知,更重要的是自動編排工具會完全否定這種格式,因此這樣的寫法不一定好用,有時壞處可能更大一些。 而且當你的參數或是方法列表很長的時候,通常就意味著設計架構需要被好好的檢討了。 ```java= private String getValue1; private int getValue2; protected boolean getValue3; ``` - **縮排** 為了更有力的將區塊之間的不同表達出來,除了透過垂直的分隔以外,還可以再透過水平的縮排進行處理。 Kai 就直接拿第一段的舉例繼續處理。 ```java= // 這是一段 Kai 在寫 LeetCode 的範例,壓成無垂直分段、無水平縮排的樣子 import java.util.ArrayList; import java.util.List; public class MedianOfTwoSortedArray { public MedianOfTwoSortedArray(){System.out.println("Hello!");} public static void main(String [] args){ Solutions solutions = new Solutions(); int [] nums1 = new int[]{1,2,3}; int [] nums2 = new int[]{4,5,6}; System.out.println(solutions.findMedianSortedArrays(nums1, nums2)); } } class Solution { ... } ``` ```java= // 再看一段,有垂直分段、無水平縮排的樣子 import java.util.ArrayList; import java.util.List; public class MedianOfTwoSortedArray { public MedianOfTwoSortedArray(){System.out.println("Hello!");} public static void main(String [] args){ Solutions solutions = new Solutions(); int [] nums1 = new int[]{1,2,3}; int [] nums2 = new int[]{4,5,6}; System.out.println(solutions.findMedianSortedArrays(nums1, nums2)); } } class Solution { ... } ``` ```java= // 最後,有垂直分段、有水平縮排的樣子 import java.util.ArrayList; import java.util.List; public class MedianOfTwoSortedArray { public MedianOfTwoSortedArray(){ System.out.println("Hello!"); } public static void main(String [] args){ Solutions solutions = new Solutions(); int [] nums1 = new int[]{1,2,3}; int [] nums2 = new int[]{4,5,6}; System.out.println(solutions.findMedianSortedArrays(nums1, nums2)); } } class Solution { ... } ``` 相信你完全可以透過第三段的程式碼更容易理解區塊的範圍,縮排不僅是為了給大區塊提供明確的範圍,諸如像是 if/else、while()、甚至是只有一行陳述句的方法,都應該做到垂直加水平整頓,甚至是雖然 if 允許陳述句只有一句便可不加括號,但還是請乖乖的換一行、縮一排、加上括號處理,你不會想要哪一天這個結構被誰在下面加了一句新的陳述句卻因永遠啟動而炸鍋的。 - **空視野** 類似 if,while 也有不使用陳述句的狀況,這種時候會很容易混淆開發者的閱讀,畢竟那不算是能直覺得理解的部分。因此最好能避免這種寫法就避免,不能避免的話,也請加個分號加以提示。 你總是會想針對只有一行的處理偷個懶,但其實寫的正規一點並不會花你多少時間,甚至可以避免未來發生錯誤的可能。 ```java= // 你不會想遇到哪一天誰在下面加了一段新 CODE if(true) System.out.println("Hello!"); System.out.println("world"); // While 在 readBuffer 的處理很常被這樣用於隨時監聽回應 while(dis.read(buf, 0, readBufferSize) != -1) ``` ```java= if(true) { System.out.println("Hello!"); } System.out.println("world"); while(dis.read(buf, 0, readBufferSize) != -1){} // or while(dis.read(buf, 0, readBufferSize) != -1) ; ``` ## 【結語】 編排算是針對 Coding Style 講述非常多的部分,而這些從來不是硬性規定,書中的最後提到了需要與你的開發團隊協商,共同討論出一個大家都願意接受的風格並進行推動。 能夠逐步一致化產品間的程式碼設計結構,彼此在往後互相支援時也不會有太多的詫異感。 首頁 [Kai 個人技術 Hackmd](/2G-RoB0QTrKzkftH2uLueA) ###### tags: `Clean Code 無瑕的程式碼`

    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