薄薄一本、每頁短短的還有可愛插圖(?),觀念不難但做到很難

軟體開發環繞著「value」,翻成中文我想是「價值」。

value is “what you want”.

重要概念:

  • 決定 value 是什麼或者說要什麼,feature 會為軟體帶來 value
  • 以重要性決定做 feature 的順序
  • 以 feature 組織 team
  • feature by feature 開發,以 feature 了解目前進度
  • 頻繁 deliver 得到回饋以知道是否需要調整 feature、方向甚至可以結束開發

每個概念都有更細的觀念跟具體作法,不過本書不太提具體作法。

Agile

整本書概念算是環繞著 Agile 的精神吧,看完最大感想:

Agile is simple, but not easy.

Agile 應該不只是開發人員的事,也包含業務甚至客人,而光開發要能做到就已經很困難了。

我沒有長時間跑 Agile style 開發的經驗,不知道長時間運作的結果,也不知道跑起來順的 Agile 是什麼樣子。只有拿相關東西做些實驗,例如 unit test 跟自動化測試,但連 CI 都還稱不上。

對開發而言光是「隨時保持軟體可正常運作、可以 deploy」,也就是完整 CI/CD 就已經很不容易了。

Read more »

提升系統某部份效能(減少執行時間)時,對系統整體的影響取決於該部份佔系統的比重以及其效能提升的程度。

某個程式原本的執行時間是 T,效能提升後執行時間為 T'。其中某部份程式的執行時間為 t、其佔全部執行時間的比例為 a = t / T。假設此部份提升效能後的執行時間為 t',即該部份效能提升為 k = t / t',則整個程式的效能提升為:

S = T / T' = 1 / ((1 - a) + a / k)

是個蠻直覺的定理。在 Performance of Concurrency 有寫過,這篇是比較 general 的版本。

忙了半年左右,我回來了(?),來寫點早該看完的《Clean Code》小心得。

整本書講 clean code 的原則,最後以一個大例子運用原則跟示範 refactor。寫那些原則像在抄書,只針對比較有感的原則跟 code smell 寫點心得。

最少驚奇(嚇)原則

讓看你的 code 的人(很可能就是你自己)對那段 code 的預期符合實際結果,儘量符合 common sense 以減少驚奇、驚嚇與驚恐。code 愈能符合預期,愈能減少進去實作看細節的時間。反之,如果常常不符預期,不用多久大家就會戒慎恐懼的每次都進去看實作,不然天知道它會發生什麼事,對吧?

不過我承認,似乎不是所有人的 commen sense 都一樣。

Read more »

原本電腦有用 UEFI 裝的 win7 跟 debian,用 grub2 開機。

多灌 win10

其實從來沒搞懂 UEFI 在幹嘛,只知道比古早時代的 BIOS 新,然後常常造成我灌系統的困擾(喂)。

這次用新硬碟裝 win10,原本用 legacy mode 裝起來,但 update-grub 抓不到,在 /etc/grub.d/40_custom 寫 google 來的各種 menuentry 也不行。改用 UEFI mode 裝 win10,它一下說找不到磁碟分割表(明明看起來就有),一下又說無法設定重開機所以不能裝,但明明我 BIOS 裡的 boot priority 已經選那顆新硬碟了(不過事後懷疑說不定應該要選 win7 的那顆才對)。在 BIOS 裡東調西調,從相容 legacy mode 換成 windows 8/10 又換成 windows 8/10 的另一種模式總算裝起來(裝完還把我 linux 那顆硬碟的 SATA port 關掉不知道是怎樣= =)。

看起來 win10 把自己的開機區裝到原本 win7 的 UEFI 系統,所以不動原本 grub 設定的情況下,從原本開 win7 的 partition 進去,就可以再選 win10 或 win7 開機。只是如果要開 win7,它會再重開一次……= =a…..(後來懷疑說不定是因為 win10 預設不會「真關機」,所以某些情況下開 win7 會需要重開,不過只是猜測,沒試過)

grub2 要加開機選項一般只要 update-grub。如果有自訂需求,到 /etc/grub.d/ 底下手動加再 update-grub

在 Linux mount 成 read-only 的 NTFS

裝 win10 後的某天,我在 linux 裡要存檔案到原本 windows 下放資料的硬碟(理所當然的是 NTFS)。

嗯?為什麼寫不進去?ro?為什麼變 ro 了?之前都可以 rw 啊。

umountmount 了一陣,ro 就是 ro,錯誤訊息看起來是說 windows 休眠中,所以不給 mount rw 免得壞掉。

蛤???windows 休眠中???可是我現在是開機成 linux 啊???哪來的 windows???感覺就是 win10 的錯(喂)。重開機進 win10,再重開進 linux,嗯?又好了?從 win10 關機,開機進 linux,又 ro。

這篇 給了我答案。簡單來說,win10 的 shut down 不是真的 shut down,reboot 才會真的 shut down(講人話)。好吧,把那個快速啟動關掉,我也不差那幾秒。win10 關機,開機進 linux,耶,世界一片美好。

前陣子寫 code 遇到 exception 或程式執行錯誤該丟出 exception 的情況,雖然知道 try catch 跟 throw exception,但「什麼時候」要「如何使用」exception 卻沒個概念然後搞得一團亂。只好來念念《例外處理設計的逆襲》,順便整理下嗑完書的簡略筆記。

區分 Fault、Error、Failure、Exception

首先區分幾個名詞的概念,不然這些東西都很像,不分清楚講到後來都不知道在講些什麼了。

  • (從外部看)一個 component 沒有提供正確服務稱為 service failure,簡稱 failure。
  • error 是種「狀態」,表示 component 內部處於錯誤狀態。這種狀態可能導致 component 執行失敗,造成 failure。
  • fault 則是導致 error 發生的「原因」
  • 程式語言以 exception 表達 error 與 failure 的概念。
    • 從不同角度來看(如 caller 跟 callee),exception 可以代表 error 也可以代表 failure。
    • 遇到某種情況要不要丟出 exception,決定方式之一是看在該 function 的語意及功能下,該狀況是不是屬於「目前可能處在不正確的狀態」或「被 call 的 function 沒做好該做的事」。如果是,當然就丟出 exception。
Read more »

prefix scan 是計算一個數值 vector 所有的部份和,每個結果 element 是原始 vector 對應位置之前數值的和,包含自己的稱為 inclusive prefix scan,不包含稱為 exclusive prefix scan。例如 [3, 5, 4, 10, 8] 的 inclusive prefix scan 是 [3, 8, 12, 22, 30],exclusive 是 [0, 3, 8, 12, 22]

Read more »

Bob 大叔的書之一《The Clean Coder》,算是《Clean Code》的續集吧。

《Clean Code》講怎麼寫 code,《The Clean Coder》講怎麼當 clean coder。記錄些心有戚戚焉的片段跟感想。

測試

設計「易於測試的程式碼」(p.48)

我想設計良好的程式應該也會好測試?從設計還是從測試出發,最後目標是一樣的,偏好哪種我覺得沒什麼差。

到目前為止,我大多從設計出發。先想概略設計、class 的責任、class 之間的關係等等,接著實作會邊寫功能邊寫測試,但不是 TDD。通常是實作一小塊、寫那一小塊的測試,而不是先寫測試才實作。即使從設計出發還是需要測試的,因為可以確保程式是對的,之後也不怕修改。

沒有實際用 TDD 寫 code,只在 dojo 小小玩過,所以說不上從測試出發是不是會導向好設計,能想像的只有因為要測試所以功能切分上應該不會太糟。

Read more »

用 concurrency 就是為了更快,為了比 sequential 程式快,不然搞得那麼複雜幹嘛呢。

如何評估 concurrent 程式的效能提升?

speedup = sequential 程式執行時間 / concurrent 程式執行時間

speedup 可能隨著使用的 core 數改變,標示程式在不同 core 數上的 speedup,可以由不同 core 數的 speedup 變化知道程式的 scalability。speedup 的提升隨著使用 core 數增加而增加甚至比例接近 core 增加的數量,表示有好的 scalability。理想狀況是 core 數加倍 speedup 也加倍。

有時會發生 speedup 的提升超過 core 的增加數量,稱為 superlinear speedup。這通常是有問題,要再確認 concurrent 程式執行結果是否正確、是否使用一般情境下的 dataset 而非只是測試資料。superlinear speedup 常見的原因是資料量太小,sequential 程式因為不斷需要新資料而被清掉的 cache 反而在 concurrent 程式中因為各 core 處理的資料量太小而 cache 住,自然 concurrent 程式在資料讀取上會比較快,造成效能變超好的錯覺。(假的!)

如果已有 sequential 程式、要決定是否 concurrent 化,能事先估算效能提升比較好,畢竟 concurrent 程式複雜也需要投入成本開發,如果效能提升不好就白費工夫了。

接下來兩個定理皆假設一個 core 上只執行一個 thread,如果一個 core 上執行多個 thread,就要把下面公式中的 core 數換成 thread 的數量。

Read more »

設計 concurrent algorithm 後當然要確認正確性。在《Principles of Concurrent and Distributed Programming》中 Ben-Ari 定義了為驗證 concurrent algorithm 各種特性的抽象結構(concurrency abstraction),可分為以下四個部份:

  • Programs are the execution of atomic statements.
  • Concurrent programs are the interleavings of atomic statements from two or more threads.
  • All possible interleavings of atomic statements must be shown to retain whatever property we are hoping to verify within a concurrent algorithm.
  • No thread’s statement may be (unfairly) excluded from any arbitrary interleavings.
Read more »

Concurrency vs Parallelism

concurrency 是如何拆分程式成多個獨立的工作,讓這些工作可以一起「正在進行(in progress)」但不一定要「同時執行」。「正在進行」是多個工作可以輪流到 CPU(或者 core)上執行,雖然不是同時執行但這些工作都是正在進行中的。而 parallelism 則是多個工作「同時執行」,也就是實際上必須要有多個 core 能同時執行工作。

打個比方,有一個廚師要煮一頓飯,他「同時」(實際上是輪流,廚師不會分身術)洗菜、切菜、炒菜跟煮湯,這是 concurrency,把煮一頓飯分成四個工作。現在廚師會分身術喔不是,是有四個廚師,一個洗菜、一個切菜、一個煮湯、一個炒菜,所有人一起動作就是 parallelism(如果同時間只有一個廚師能動作,不算 parallelism)。煮一頓飯也可以拆成炒青菜、煮飯、煮湯三件事,每件事各自從洗到切到煮或炒,這樣也是一個 concurrency solution,而如果有多個廚師一起做,便成了 parallelism。

concurrency 關乎程式結構,parallelism 關乎程式執行。concurrency 是程式或系統怎麼切分成多個工作,而 parallelism 則得要同時「執行」。

關於中文翻譯

concurrency 的中文翻譯是「並行」,parallelism 是「平行」。但「平行」很容易出現在描述裡,常常搞不清楚到底「平行」是指 parallelism 還是只是一個形容?我比較喜歡在需要精準指出是 concurrency 或 parallelism 的時候用原文,單純的形容或者描述用「平行」,除非英文用在中文句子有點怪才會用中文「並行」跟「平行」並且加註英文。

Ref