淺談重構

前篇 Clean Code 簡單原則 中,談到寫出好的程式碼有兩個方法:一個是一開始就寫出乾淨的程式碼,但在對整個程式架構都不明瞭的情況下,就得寫出完美的程式碼非常困難;另一個則是靠重構程式碼,透過一次次等價交換小塊程式碼,讓其慢慢變得更乾淨。 重構是什麼? 重構就是一種在不改變程式外在表現的前提下,將其程式碼變得更容易閱讀,且更容易修改。 通常聽到重構,可能會聯想到大興土木的變革,其實不然。重構是一種寫程式的小習慣,是每次動手寫新程式前都會做的事情,有點像是打掃房間一樣,每次進房看到有髒亂的地方就順手整理一下,維持房間的乾淨整齊,而不是等到東西都堆滿地,想要放一張新的桌子都沒地方可以擺。 另外,重構可以幫助我們慢慢形塑整個系統,讓軟體一直貼近實際需求。以往瀑布式開發一開始精心規劃的架構,拆成一塊一塊後分批完成,最後統合起來形成整個系統。但需求一直在改變,從規劃到釋出軟體經過了一年以上,到時市場趨勢已經不是當初規劃的那個樣子,會造成極大的風險。 ![1399244627-1379743011](https://jimmylab-images.seisblue.com/uploads/2018/10/1399244627-1379743011.jpg) 隨著敏捷開發的出現,人們開始縮短開發週期,加快取得使用者的回饋,以利調整方向,但這會造成程式碼必須頻繁的修改。 ![1486430757-1509367922_n](https://jimmylab-images.seisblue.com/uploads/2018/10/1486430757-1509367922_n.jpg) 改動就會有風險,在開發的過程中需要利用**兩頂帽子**的設計方式:「重構」與「添加新功能」。重構確保所有功能不被更動的前提下,利用每次的等價交換,重新思考如何將程式碼分拆成小塊容易維護的樣子,並將區塊間的相依性降低,之後再來添加新功能。 講了這麼多,重構到底要怎麼進行呢?先有程式碼好壞的概念後,找到程式碼中不好的地方,用查表的方式替換成新的形式,代換完後測試一下程式,觀察結果是否與更改前一致,若一致就可以再尋找其他地方進行重構或添加新功能。 在 重構─改善既有程式的設計 這本書提到一些程式碼的壞氣味: Duplicated code 重複的程式碼 Long method 過長函式 Large class 過大類別 Long parameter list 過長參數列 Divergent change 發散式變化 Shotgun surgery 散彈式修改 Feature envy 依戀情結 Data clump 資料泥團 Primitive Obsession 基本型別偏執 Switch Statements 可怕的 Switch Parallel inheritance hierarchies 平行繼承體系 Lazy class 冗員類別 Speculative generality 夸夸其談未來性 Temporary field 迷惑的佔時欄位 Message chains 過度耦合訊息鏈 Middle man 中間轉手人 Inappropriate intimacy 狎暱關係 Alternative class with different interfaces 異曲同工的類別 Incomplete library class 不完善的程式庫類別 Refused bequest 被拒絕的遺贈 Comments 過多的註釋 在大話重構這本書中提供了一些較簡單的方向:...

<span title='2018-10-01 03:51:10 +0800 +0800'>October 1, 2018</span>&nbsp;·&nbsp;1 分鐘&nbsp;·&nbsp;Jimmy

Clean Code 簡單原則

在介紹 Clean Code 之前,想想為什麼會寫出糟糕的程式碼呢?可能是趕進度,也有可能只想早點下班,甚至是連好壞程式沒概念。也有人說程式會動就好了,花這麼多時間讓程式碼變整潔,不是很沒效率? 程式會動就好這件事聽起來很美好,但是需求一直在改變,今天寫好了一個程式後,使用者用了一段時間一定會想要加點新的東西進去,這時如果是糟糕的程式碼,得花非常多時間搞懂之前做了什麼,才能下手改程式碼。 有人統計過閱讀程式碼與寫新的功能所佔的時間約為 10 : 1,由此可見,原有的程式碼越難懂,就得花越多時間在理解程式的原意,開發的時間也就拖得越長。另一件頭痛的事是,如果程式碼糾結在一起,很難保證改了一段程式不會影響到其他區域,到時候改了一個錯誤,出現更多的錯誤,就會沒完沒了。 我們了解到寫出雜亂的程式碼,會導致程式越來越難維護,隨著時間的推移,程式碼產出會慢慢趨近於零,到時候不得不放棄這團糾結不清的系統。但事情往往沒這麼簡單,舊系統經過了時間的考驗,修了無數的錯誤,在重起爐灶時不太可能將所有條件考慮進去,導致新系統不堪使用。 要怎麼避免這種兩難事情發生呢?有兩個方法: 一開始就寫出整潔的程式碼,但新手往往不夠熟練能第一次就寫出乾淨的程式碼,可以先了解好程式碼的方向,慢慢培養寫程式的品味。 重構程式碼,利用代換等量的程式碼讓程式解耦,並利用測試驗證重構的正確性。這主題可以獨立成一篇:淺談重構。 這裡列出 Clean Code 書中幾個簡單的原則,剩下較難或繁瑣的觀念,例如物件、類別、錯誤處理、系統架構 … 等,可以等程式功力更熟練時再回去詳讀: 命名 要讓名稱確實表達意圖,絕對不要用 aaa, a1, a2 這種完全不知道意圖的名稱,至少讓人一眼看出變數代表的意義,例如:traceStartTime 或是 traceCount。 名稱避免誤導,像 O 跟 0,I 跟 l 跟 1,或是 dirToTheDataBase 跟 dirToTheDataManager 這種太相似的變數。 不同的變數,意圖應該要有明顯的區別,像是 fileDir 與 dataPath 實際上是指同一件事情,不應該有兩個變數做重複的事,若有這種情況必須重新思考程式架構。 名稱要可以唸得出來,在互相討論程式碼時才比較有效率,不要有 genyyyymmddhrmnss 這種無法發音的名稱,generationTimeStamp 會更好。 盡量使用大家都熟悉的名稱,課本公式上常用的代稱就可以使用,像寫極座標時,用 r, theta, phi 就是可以接受的命名。 函式 函式盡量越短越好, 超過螢幕可以一眼看完的函式,在閱讀上一定會有困難,所以函式大概控制在 20 行以內。 函式只做一件事情,如果裡面非常複雜,通常可以拆成更多的小函式。 函式內只有一層抽象概念,太細節的功能就包給更小的函式,需要統合的功能就交給更大的函式。 函式通常是做一個動作,所以用動詞開頭命名會比較適當,像 getTimeTable 或是 isDataContinuous。 函式輸入的參數越少越好,最好是零個,一個次之,兩個就不太好了,盡量避免三個以上,超過要用類別將變數包起來。但是非常直觀的變數數量,例如 plot3D(x, y, z) 直覺上告訴我們需要輸入三個變數,就可以接受。 註解...

<span title='2018-09-27 23:20:26 +0800 +0800'>September 27, 2018</span>&nbsp;·&nbsp;1 分鐘&nbsp;·&nbsp;Jimmy

Pycharm 好用的 plugin

強大的 Pycharm 有著許多好用的功能,但還是有些功能是官方沒有照顧到的,官方有開放社群開發插件,這邊介紹幾個覺得還不錯的第三方插件 String Manipulation 這個插件可以幫你完成一些煩人的大小寫轉換、變數排序、自動生成序列等神奇的功能,選項在右鍵選單內: ![01](https://jimmylab-images.seisblue.com/uploads/2018/08/01.png) [BashSupport](https://plugins.jetbrains.com/plugin/4230-bashsupport) 就是bash,但系統沒有預裝,所以要自己從網站上下載 ![bash](https://jimmylab-images.seisblue.com/uploads/2018/08/bash.png) [Fortran](https://plugins.jetbrains.com/plugin/9699-fortran) 可以支援 fortran 77 的固定格式跟 fortran 95 之後的格式 ![fortran](https://jimmylab-images.seisblue.com/uploads/2018/08/fortran.png) 如何安裝第三方插件: 到Pycharm 插件庫挑選第三方插件 下載並解壓縮會有一個 .jar 檔 到 Settings 搜尋 plugin 並選取 Install plugin from disk… ![02](https://jimmylab-images.seisblue.com/uploads/2018/08/02.png) 選取解壓縮的 .jar 檔,如果檔案在桌面可以選上方視窗圖示 ![03](https://jimmylab-images.seisblue.com/uploads/2018/08/03.png) 重開 Pycharm 就可以使用新的插件了

<span title='2018-08-01 11:02:25 +0800 +0800'>August 1, 2018</span>&nbsp;·&nbsp;1 分鐘&nbsp;·&nbsp;Jimmy

PyQt5 Signal / Slot 機制入門

利用 Qt Designer 設計好程式的介面以後,要如何讓程式有反應呢?這時候就得寫背後的邏輯了。 Qt 使用 Signal / Slot 機制來達到物件之間的通訊,就有點像是拿電線接起來一樣。例如將開關接上燈泡後,按下開關就會亮,而將連結斷開後,燈泡就不會對按鈕有反應了。 不知道怎麼安裝可以先看這篇 安裝PyQt5 + 連動Pycharm ![012](https://jimmylab-images.seisblue.com/uploads/2018/07/012.png) 現在我們先設計一個簡易的加法器如下,物件名稱需更改以利辨識 ![02_1](https://jimmylab-images.seisblue.com/uploads/2018/07/02_1.png) Qt Designer 右下角有個 Signal/Slot Editor,先按 + 產生一組訊號連結 在 Sender 欄可以選發送訊號的物件,Signal 欄可以選擇觸發條件,Receiver 欄可以選擇接收訊號的物件,Slot 可以選擇執行的動作 ![02_2](https://jimmylab-images.seisblue.com/uploads/2018/07/02_2.png) 我們希望按下 Clear 按鈕後,三個 lineEdit 框可以被清空,所以設定當 pushButton\_clear 被 clicked() 的時候,lineEdit\_A 要 clear() 自己的資料 ![02_3](https://jimmylab-images.seisblue.com/uploads/2018/07/02_3.png) 剩下 lineEdit\_B 與 lineEdit\_ANS 都比照辦理 現在將圖形介面存檔成adder.ui,並利用 PyUIC 將 adder.ui 轉換成 adder.py 另外寫一個 call_adder.py 來啟動程式: <pre class="brush: python; title: ; notranslate" title=""> import sys from PyQt5.QtWidgets import QMainWindow, QApplication from adder import * class AdderMainWindow(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(AdderMainWindow, self)....

<span title='2018-07-12 23:16:43 +0800 +0800'>July 12, 2018</span>&nbsp;·&nbsp;1 分鐘&nbsp;·&nbsp;Jimmy

安裝PyQt5 + 連動Pycharm

如果要在 Python 上面寫 GUI 介面,推薦跨平台跨語言的Qt,它有 App Designer 可以直接排版後自動生成程式碼。用 signal / slot 作為物件之間的溝通,簡化了很多開發上的複雜度。Qt 底層為 C++ ,所以執行速度較快。PyQt5 只支援 Python 3 ,且不向下支援 PyQt4。 Pycharm 算是個人蠻推薦的 Python IDE,有強大的除錯功能,可以自動整理程式碼,並可以與許多工具結合,比用單純的文字編輯器好很多。 以下專注在 Windows 10,Pycharm 灌好的前提下,如何安裝 PyQt5 並連動: 打開 Settings ![011](https://jimmylab-images.seisblue.com/uploads/2018/07/011.png) 2. 找到 Project Interpreter 並按 + (有 Anaconda 的要先按綠色圈圈取消) ![021](https://jimmylab-images.seisblue.com/uploads/2018/07/021.png) 3. 在上方搜尋 PyQt5 並安裝 PyQt5 與 pyqt5-tools ![031](https://jimmylab-images.seisblue.com/uploads/2018/07/031.png) 4. 回到 Settings 找到 External Tools 並按 + ![041](https://jimmylab-images.seisblue.com/uploads/2018/07/041.png) 5. 設定 Qt Designer 如圖,找到 designer.exe (通常在 Python 根目錄下的 Lib/site-package/pyqt5-tools 裡面),Arguments 設定為`$FileName$`,Working directory 設定為`$ProjectFileDir$`,可以用 Insert Macro 裡面找 ProjetFileDir 生成!...

<span title='2018-07-09 15:53:55 +0800 +0800'>July 9, 2018</span>&nbsp;·&nbsp;1 分鐘&nbsp;·&nbsp;Jimmy

Python 新手上路包

最近太多人問怎麼學 Python 了 我覺得為了學 Python 專門去選學校的課太多此一舉了 畢竟選課會有時間上跟聽不聽得懂的問題 個人覺得用線上資源學習是最快最有效的~~~ ![pylogo](https://jimmylab-images.seisblue.com/uploads/2018/01/pylogo.png) 一個一個回答有點麻煩 就在這裡整理一些學習 Python 的資源吧 首先要先安裝 Python 直譯器 3.7 還是 2.7 ? 除非你有舊的程式要跑 不然一律用最新的~ 建議安裝 Python 套件管理程式 Anaconda ![logo-dark](https://jimmylab-images.seisblue.com/uploads/2018/01/logo-dark.png) 灌 Anaconda 的好處是 一開始他會幫你灌大部分會用到的套件包 包括新手最會卡關的 pip 與自家 conda 套件管理程式 也可以作套件包的版本控制 讓你不同專案的套件包不會打架 特別是有舊程式要維護的時候更重要 Anaconda 環境設定可以參考這篇 Win10下用Anaconda安裝TensorFlow ![MATLAB_R2013a_Win8_screenshot.png](https://jimmylab-images.seisblue.com/uploads/2018/01/matlab_r2013a_win8_screenshot.png) 再來可以選用一個[文字編輯器](https://zh.wikipedia.org/zh-tw/%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8) (Text Editor) 或是[整合開發環境](https://zh.wikipedia.org/zh-tw/%E9%9B%86%E6%88%90%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83) (IDE) 如果是 [Vi](https://zh.wikipedia.org/zh-tw/Vi) 派的我也不反對 (有神快拜) 不知道 IDE 是什麼的話,看看 [Matlab](https://www.mathworks.com/products/matlab.html) 的介面 就是一個很標準的 IDE IDE可以幹嘛? 可以參考下面這篇文章 IDE、編輯器的迷思| iThome 你可以用 Anaconda 幫你灌好的 Spyder 這個 IDE 是仿效 MATLAB 介面做成的...

<span title='2018-01-05 00:17:23 +0800 +0800'>January 5, 2018</span>&nbsp;·&nbsp;2 分鐘&nbsp;·&nbsp;Jimmy

使用 Microsoft Azure Notebook 執行 Python

假如要 Demo Python 程式碼 Microsoft 有提供一個好用的雲端服務叫 Microsoft Azure Notebooks ![](https://jimmylab-images.seisblue.com/uploads/2019/03/image-1.png) 要用這個服務之前要先有 [Microsoft 帳號](https://login.live.com/tw) 如果沒有帳號可以先申請 整個 Microsoft Azure Notebooks 是用 Jupyter 建構出來的 Jupyter 是一個互動式的筆記本,可以將程式碼與註記放在一起,方便與讀者互動 Python 初學者可以先複製官方的教學 Python for DS 101 進去以後按 Clone,把教學範例複製到自己的 Library 裡面 ![Python2.png](https://jimmylab-images.seisblue.com/uploads/2017/11/python2.png) 打開 [01.Basics.ipynb](https://notebooks.azure.com/rheartpython/libraries/PythonDS101/html/01.Basics.ipynb) 就可以看到 Jupyter 的主畫面了 ![Basics.png](https://jimmylab-images.seisblue.com/uploads/2017/11/basics.png) 最簡單要記得的就是執行一個區段按 Shift+Enter 照著這個 Basics 走過一遍就會知道怎麼用了 另外常用到的功能是在前面加 ! 就可以執行 Shell 指令: ``` !pip install soundfile # Install pysoundfile package for wav I/O </p>這在需要額外安裝套件很有用的,或是想要執行一些 grep 或 awk 的指令,不過好像只有在 Azure Notebooks 才行,拿到其他 Jupyter Notebook 不一定能用。 剩下的就看這個 [Cheatsheet](https://s3....

<span title='2017-12-07 16:40:34 +0800 +0800'>December 7, 2017</span>&nbsp;·&nbsp;1 分鐘&nbsp;·&nbsp;Jimmy