2018年3月11日 星期日

<令人難以理解的軟體工程師生涯>心得

先前在 Facebook 上面看到這篇文章(因為怕有人沒 Facebook 權限,所以貼關鍵評論網的轉載),看了看有些心得,就打在這裡:
https://www.thenewslens.com/article/91122
話說回來,我看了關鍵評論網的引言<我們想讓你知道的是>,還是不知道它想讓我知道什麼……。
其實這篇文有點跟原文對幹的意思,身為資淺軟體工程師這麼做好像有點不識大體,不過…反正我這個小咖 blog 也沒人看,大概也沒差,而且大部分的內容,多半去看<人月神話>就有了XDD。

十倍軟體生產力是否存在?我的答案是:Yes,肯定的 Yes
這件事情不單純在軟體,各行各業都是如此,熟練的高手能得到比一般平庸的操作員數倍的生產力,軟體奇特之處在於,生產力可以高到十倍甚至更高之譜,遠超過其他行業頂尖高手和一般人之間的差距。
箇中原因,在人月神話裡面已經有解釋:軟體是人類有史以來發明過最複雜的東西,是邏輯和數學的直接表達,寫好軟體就是一次次表達腦中的虛擬結構,而頂尖的腦袋的虛擬能力,遠在一般腦袋之上;之前就有個<學長告誡>:不要去問數學高手(aka 拿了兩次數奧金牌)數學問題,他講的話你聽不懂--他們虛疑化的層次遠超過你,你要想三步的東西他一步就講完了。
學會寫程式之後(差不多就大學吧),認識的很多很強的高手,真的是活生生體會到所謂的十倍-百倍生產力這件事,這些人現在要不是在 Google 大殺四方就是創業去了。
自己有時多少也會懷疑自己到底能不能做到那個程度,而且我相信,諸位軟體工程師的生涯中,一定也遇到過非常多10倍生產力的高手,也因此原本這篇貼文,才會獲得了如此大的迴響。

於是我們回到文中的大哉問:如果已經有了頂尖、十倍生產力的軟體工程師,那為何需要平庸工程師(就像我這種)?
軟體世界不是人多好辦事,但人少不成事。
原作者用了三個月的時間,改寫數萬行的程式為數千行漂亮的程式碼,非常厲害。
但一個 LInux 核心到現在有兩千萬行程式碼,如果像他這樣三個月估且算一萬行好了,要花 6000 個月,也就是 500 年才能寫完,這是可以接受的嗎?chrome 瀏覽器 500 萬行,firefox 一千萬行,每個都要十倍工程師孜孜不倦花好幾年手工打造嗎?還不要提現下消費者是每半年到一年要看到一次改版噢。
https://www.quora.com/What-is-the-biggest-program-lines-of-code-ever-made
這還不算上自己腦袋打結的時間,更不用提即便是天才也會有他的盲點,學的知識的它的上限,懂CPU的不一定懂網路,會演算法的可能不善於實作,懂資訊安全的可能不會硬碟……,系統長大之後會出現許多測試整合的工作,單打獨鬥鐵定有一個上限存在。
大型軟體本來就要綜合眾人之力,這又回到本來的問題:集合眾人就要溝通問題本質的數學邏輯,然後發生誤解跟整合問題,就算團隊全部都是10倍生產力工程師也無可倖免,以前總以為一流的軟體公司,像什麼 Google, Amazon 什麼的,裡面的程式一定都是藝術品等級,後來問問任職的同學,才發現根本不是這回事,有點年紀的大公司,軟體總是變成一團屎,還聽說過有幾個檔案變成 magic code ,根本沒人敢動的。
在跟強者我同學一哥聊天時,就有說到:「公司花錢請你來是要解決問題,不是把公司的東西變藝術品」、「每家公司都有鳥事,所以沒方向的話就選薪水高的」聽起來很世儈,但現實如此。

其實這幾年來,一直覺得台灣軟體最大的問題,並不是我們沒有夠多的10倍生產力軟體工程師,10倍軟體工程師本身就是一個異數,也許培養一群人裡,比例也就這麼多;更何況,過度看重十倍軟體工程師,顯然把世界想得太簡單,以為不管什麼問題,只要派出一位10倍軟體工程師都能迎刃而解,但很多問題卻不是如此。
我覺得我們最缺的,是培育出許多平庸的軟體工程師之後,如何拉一位 10倍軟體工程師,把大家組織成部隊來打群架(順帶一提,所謂的平庸工程師, 是指:給定一個嚴謹的規格,可以四平八穩完成開發,不要寫出會 buffer overflow 之類的低級錯誤,足矣。),我們很喜歡強調個人能力不足,但現在這個時代,就是要靠打群架才能打勝仗,如何把 10 位平庸的工程師組織起來,搭配一位 10 倍生產力的工程師,變成 50 倍生產力的團隊?只靠單打獨鬥,我們要如何挑戰百萬行甚至千萬行的系統?
也許哪天我們會看到:原本千萬行的程式,大家一起重寫的只剩下百萬行,功能不變,效能更好,而且架構儼然。前幾天完成 Alpha 版之後,大家不禁開瓶慶祝,笑聲充斥整個辦公室。

這大概才是台灣要追求的方向。

話又說回來,其實寫程式就只是寫程式,就算不寫程式跑去教書,腦袋還是可以想程式邏輯;上班寫無聊的程式,下班還是可以繼續學有趣的東西;就算當管理職不寫程式,把軟體架構切好,交給下面的團隊幫忙開發,對專案就沒有任何助益?誰說只有寫程式,還要寫得快又寫得漂亮才能貢獻社會?
理論上我們可以用寫程式數倍的時間,一行一行驗證我們的程式碼有沒有問題,把程式改到完全不會出錯,但世界不鳥這些,<不吃飯不睡覺,打起精神數鈔票>比較重要,程式當掉資料飛了,跟客戶土下座就好,反正沒有一次土下座解決不了的問題,如果有,就兩次。
寫程式其實沒有這麼偉大。

我們持續寫下去,只是因為寫程式很快樂,解決問題很快樂,重新打造輪子很快樂(等等…),覺得自己又變厲害了很快樂,完成大系統裡的小螺絲,很快樂
每位程式設計師,其實都是無可救藥的樂觀主義者。

2018年3月4日 星期日

Coursera Introduction to Logic

前些日子開始修了 coursera 上 stanford 大學開的 Introduction to Logic,修完而且有學到東西,其實個人習慣上滿常亂加一些 coursera 上的課程,有些聽一聽覺得無聊就沒聽完,沒聽完的就不會在這裡推薦就是。

下面是基本資訊:
課程名稱:Introduction to Logic
開課學校:Stanford University
授課教授:Michael Genesereth
開課時間:10 周
教學方式:靜態講義
通過方式:每週完成指定的作業,下面會詳述作業內容。

課程內容涵蓋基礎邏輯的概念,符號介紹,邏輯證明跟歸納證明,沒有到太複雜的內容,如果在台灣的大學有修邏輯的話,應該也是差不多的內容,例如通識很熱門的<邏輯丙>,應該內容也差不多。
不像其他課程是教授親自上陣講課,這門課上課的方式是看靜態文字講義(似乎有簡體中文不過我是看英文的),講義看過之後會自動記錄看過,相對來說看靜態文字比看教授講解還要無聊一些,而且有點吃英文能力。
課程內容很大一塊是放在 fitch system,並且證明也都是用 fitch system 來證明,每周作業會出約莫 5 到 10 題的題目,有些是選擇題,選到正確的選項即可;有些則是證明題,要證出所要的結果;有幾週會加一些邏輯遊戲跟參考影片,例如邏輯踩地雷,或者看教授演示一個邏輯表達系統。
證明題使用的是一個 javascript 寫的證明系統,可以用滑鼠選擇敘述,還有要使用的運算來完成證明,一開始有一點難上手,不過熟練之後就會覺得設計真的非常厲害,For all 跟 Exist 的符號代換都會自動完成,點一點就發證明完成了。唯一卡比較大的是在第八週的歸納法,久違地動用紙筆在紙上釐清議義範例證明的思路,想通之後在系統上重現就清楚多了。

學完之後真心覺得有學到東西,我從來沒想過原來連 (p => q) => (~q => ~p), (p => q) => (~p | q) , (p | ~p) 這樣基礎的邏輯也可以證明,但是千真萬確,證過一次才知道這真的可以用邏輯推出來,所以以前說的那些:前題錯就可以推出任何東西,「如果月亮是起司做的,那麼月亮可以吃」都是真的。
其他要注意的事情:寫作業的系統不知道為什麼,用 chrome 開的話會有些問題,用 firefox 來操作就沒問題。
另外,我誠心建議大家睡前不要讀邏輯,讀邏輯當然要沐浴更衣正襟危坐有一次念完之後睡覺,結果在夢裡想歸納證明………,醒來累得半死。

2018年1月25日 星期四

使用 git submodule 管理 project 所需的其他模組

故事是這樣子的,最近在寫一些分析資料的程式,用的是 python 跟 numpy。
一開始改寫的時候,發現一開始 load 資料的地方,Python 實在太慢了,載入 20000 筆資料耗時超過 150 秒,後來決定用 C++ 改寫載入數據的部分,同時利用別人寫好的 cnpy 這個 project,寫出 numpy 檔案作分析,結果載入速度竟然一口氣降到 4.5s,加速 15 dB,太可怕了(yay。
為了要使用 cnpy 這個 project,順手研究了一下要如何給使用 git submodule,這篇文章就做個介紹:

基本上submodule 利用的場合,就如我上面說,我的 project 要用到其他 project 的程式碼,我希望讓我的使用者能直接拿到其他 project 的程式碼,這樣他們不用自己再去載,麻煩之外可能還會載到錯誤的版本。
另一方面,我們又不想把對方的程式全部加到我的 repository 裡面,這樣會帶來不好的後果,上游的程式碼修改,要自己手動更新,沒辦法用 git 的方式更新,增加錯誤的機會。
git 針對這個使用情景的解決方式就是 submodule:

遇到 submodule 的時候通常有兩種狀況,第一種比較常見的,是載了一個別人的project,發現裡面有用到 submodule,例如知名的補齊工具 YouCompleteMe ,裡面針對各種語言的剖析工具都是 submodule,這些專案載下來的時候, submodule 裡面都還是空的,要先用下列指令把 submodule 載下來:
git submodule init
git submodule update
或者可以用一行指令解決:
git submodule update --init --recursive
--recursive 會在 submodule 裡面還有 submodule 的時候,一口氣都設定好。
又或者可以在 clone 專案的時候就指定要一齊複製 submodule(不過通常在 clone project 的時候還不知道裡面有 submodule,所以…通常不會這樣下):
git clone --recurse-submodules url

第二種狀況如我上面所述,我們自己新增一個 submodule,我要做的就是新增 cnpy 為我的 submodule:
git submodule add git@github.com:rogersce/cnpy.git cnpy
後面的 cnpy 是指定 submodule 要放在哪個資料夾裡面,通常名稱都跟 project 本來的名稱相同,才不會搞混;這時候記得會開始把這個 project 下載下來,接著檢視 status 的話會看到下面的內容:
new file: .gitmodules
new file: cnpy
.gitmodules 檔案裡面記錄了 submodule 的名字,現在的路徑以及遠端 url,這是可以用 add 及 commit 將這個 submodule 保存下來。

在一個有 submodule 的專案裡面工作,會和一般的工作內容稍有不同,當進到 submodule 內部的時候;submodule 從外面來看只是一個參照,如果真的進到這個資料夾,用起來就會像另外一個 git repository 一樣,一樣會有 master 等等 branch,可以用 remote 拉別人的修改下來,或者自己送 commit 出去。
比較讓人疑惑的通常是在外面的 project,當內部的內容有修改的時候,外面會出現一些讓人很疑惑的訊息,例如當我們對 cnpy 這個 project 新增一個 commit,從外面會看到這樣的訊息:
git status
modified: cnpy (new commits)
這則訊息的意思是,cnpy 這個 submodule 有了修改,修改的內容是新增了 commits;可以把git submodule 想成一個快照,現在 submodule 的狀態已經脫離這個快照,從 git diff 就會看出差別,最下面是 commit 的修改訊息:
git diff
diff --git a/cnpy b/cnpy
index f19917f..8f997be 160000
--- a/cnpy
+++ b/cnpy
@@ -1 +1 @@
-Subproject commit f19917f6c442885dcf171de485ba8b17bd178da6
+Subproject commit 8f997be1f87279f09054acbdb896162b1e9d3963

這時對這個 submodule 做 add, commit,就會更新這個 submodule 的快照值;另外如果我們想要 submodule 維持在之前的快照上,用 git submodule update ,git 即會將 submodule 簽回到當初記錄的版本:
git submodule update
Submodule path 'cnpy': checked out 'f19917f6c442885dcf171de485ba8b17bd178da6'

不過 update 之後會有一些不好的效果,因為這時 submodule 被強制簽出 f19917 這個 commit ,裡面就出現了一些沒有 commit 的修改,在這裡有內容未被 commit,所以它會顯示:
git status modified: cnpy (untracked content)
從外面會看到 submodule 有修改,但要消掉這個 untracked content 的訊息,就要進到 submodule 資料夾裡面,用 checkout 或 clean 的方式,讓 submodule 的狀態回到 clean 才行。
但同時也要注意的,這時候 submodule 就處在 detach HEAD 的狀態(在上面的例子,submodule 落後 master 一個 commit ),這時進到 submodule 做些 commit,這些 commit 並沒有 branch 參照,下一次再下 submodule update 的時候,所做的修改就會消失,如果有要修改的話,建議要先在 submodule 裡面生成一個 branch 來保留修改。

另外一個比較需要注意的,大概就是在移動 submodule 的參照的時候,儘量可以用 git mv 的方式來移動,用 os 本身的 mv 似乎比較容易出問題。

我想 submodule 我們就講到這裡,下面這篇官方的參考資料:
https://git-scm.com/book/en/v2/Git-Tools-Submodules
裡面還有很多 git submodule 神奇的用法,例如從外面用 git submodule 指令一口氣更新所有 submodule 的狀態到最新,把所有 submodule 現下的狀態推送到遠端,等等。
但我個人認為 submodule 相對來說是比較偏門的指令,自己也是用了這麼久,最近才第一次用到 submodule,大家還是用到再來查文件比較實在;另外話又說回來, git submodule 能管理的相關 project 數量也是有個限度,數量多到一定程度,submodule 也會顯得捉襟見肘,因而 google android 才會另外推 repo 這樣大量 git repository 的管理工具吧。

2017年12月31日 星期日

Git 教學影片系列

故事是這樣子的,自己大概三四年前開始使用git,一路用到現在,對 git 相關的功能算是相當熟悉,有時也會負責教其他人使用 git,自己的 blog 上其實也留了不少 git 相關的文章:
https://yodalee.blogspot.tw/search/label/git
大約兩個禮拜前突發奇想,反正都要教,乾脆就錄個影片,以後只要貼影片給別人看,不只教認識的,還能教虛擬世界中「沉默的多數」(誤),想著想著稍微規劃了一下,好像還真的有點模樣,於是就開始了我變身網(ㄈㄟˊ)紅(ㄓㄞˊ)的第一步。

最後確定的版本有以下幾集的影片,一部是相關的功能,順便還會介紹一些社群習慣或是我自己的習慣,講得滿雜的,也有些出錯的地方:

Ep. 1 安裝與設定
Ep. 2 Add, commit:50/72 rule, gitignore, commit hash, DAG
Ep. 3 如何指定一個 commit:hash, HEAD, ^ ~, reference, show, log, diff, diff --staged
Ep. 4 patch add and amend
Ep. 5 branch, checkout, merge:解衝突
Ep. 6 Rebase:rebase -i,解衝突
Ep. 7 遠端開發,使用 github:用 gitgraph.js 的開發經驗,來說明如何使用 github
Ep. 8 stash
Ep. 9 format-patch, apply, am, cherry-pick 各種搬移工作的方法
Ep. 10 bisect, blame
Ep. End ending:講一下一些沒提的東西

自己做起來就發現,想當 youtuber 要費的功夫真的超級大,除了初期收集資料跟準備材料,投影片跟 demo 用的 project,還要確認要講的內容沒有錯誤;真正錄的時候可能還要多錄幾遍,確定哪裡說不好要改進,如果不小心說錯了,要重頭再錄一次,事後還要上傳 Youtube 修改影片資訊等等。
像後來,就發現我在安裝的那章其實有個錯誤,Windows系統不能只安裝 Tortoise git,還要安裝 git 才行…不過暫時還沒想到怎麼去修正它(yay;如果像那些網紅一樣還要加後製,那成本真的超級大,我猜不組個小團隊其實是很難撐起來的

總之這些是最後的成品,收到一個 youtube 播放清單中:
https://www.youtube.com/playlist?list=PLlyOkSAh6TwcvJQ1UtvkSwhZWCaM_S07d
或者下面是嵌入式的影片:

自己回想起來其實花了非常多時間在錄這些教學影片,還去買了新的麥克風,錄製跟剪輯影片分別使用 obs 跟 ffmpeg 剪輯指令,因為加特效太麻煩,所以就沒加特效 =w=,希望這些影片能對大家有所幫助。
雖然本人比較喜歡低調路線,不過想想,既然都花了這麼多時間,這些影片要是沒有人看就太可惜了,因此來學一下農場的做法,希望大家覺得影片有你幫助的話,就幫小弟分享一下,無論是這篇文章或是上面 youtube 播放清單的連結都可以。

ps. 也能透過blog 旁邊的連結,用 Paypal 給點賞,鼓勵一下小弟,不過這不強求啦,畢竟 Paypal 手續費抽滿貴的。

2017年12月5日 星期二

不當行為

本書的全名是:<不當行為:行為經濟學之父教你更聰明的思考、理財、看世界>
本書的內容,是在說明作者從他研究所的研究開始,從開始單純收集資料,其後開始設計實驗發表研究,挑戰主流經濟學的觀點,最後創立行為經濟學這一個經濟學的分枝的整體回顧。

所謂的不當行為,其實是從當時主流的經濟學標準模型來看,標準模型將人類行為理想化之後,藉由簡化後的<人類>來對經濟做出預測,並在數十年間越發展越強勢,變成所有經濟學的現象都要依靠標準模型化的<人類>來解釋,任何偏離標準模型的研究,或者宣稱人類不符合標準模型的行為,在當時都會被視為異端邪說。
作者一路以來,就是不斷從人類的行為中尋找與標準模型不同的行為(也就是所謂的<不當行為>),試圖去推翻標準模型。

這裡可以舉一些很簡單的例子,例如標準模型可能假設,無論任何情境下,人對金錢是一視同仁的。
但有研究指出,我們對待同樣的 100 元,獲得 100 元跟損失 100元的快樂跟難過卻不是等價的,人們對損失會比獲得敏感,傾向規避損失。
又或者去便利超商買東西,如果店員告訴你,現在買的50元的商品在一個街口之外有5折的活動,你可能會為了這25元走一個街口;但如果你今天是買一台10000元的電視,一個街口外的賣場有 9950 的商品,你卻不會為了省這50元跑過去。對同樣的 50 元,我們在不同的情境下會有不同的價值,有時會想省有時不會--又是一個違反標準模型假設的行為。

當然如果只是把行為列出來是不會有什麼效果,畢竟人類如此複雜,標準模型也會推出它們對此類行為的解釋。為了推翻標準模型的假設,作者必須設計實驗,把實驗變數壓到最低,證實很難找到其他理由,讓標準模型能夠合理解釋這樣的行為,從而慢慢推翻標準模型中<人類的行為是完全理性、完全數字>的假設,書中對這些實驗的設計都有粗略的介紹。

要澄清的是,其實標準模型並沒有不好,人類行為跟思考太過複雜,沒經過適當的簡化,如果一開始就栽進複雜的世界,從一開始就會卡住完全做不出成果。
如果要我比喻,用我熟悉的電路來說,半導體的行為十分複雜,如果我們一開始就用完全真實的電晶體去做設計,光是最簡單的電路都做不出來,所以研究上會弄出截止區、飽和區的平方模型,幫助我們在大方向上可以近似電晶體的行為,才能有效的去設計複雜的電路。
但當模型被用過頭,假設所有電晶體都是理想的元件,許多真實電晶體的行為反而被忽略,而在設計上無法精準預測電路行為,這時就要打破舊有模型的框架,去創造新的模型才能更好的預測電路。
把平方模型/電晶體/電路代換成標準模型/人的行為/經濟活動,差不多就是這本書在談的事情。

在書中最後幾章,也有舉些例子說明,如何把行為經濟學的研究成果放在政府的政策下, 配合上面所說的,人類對損失比獲得更為敏感,讓我想到最近高雄市為了因應空汙推動大眾運輸,推出冬季搭乘大眾運輸免費的政策,這是一種獎賞或是<蘿蔔>的策略;如果要推大眾運輸,還有一種方式就是提高私人運具的成本,例如加強違停的拖吊,提高路邊停車的收費,這則是懲罰或是<棒子>的策略。
對照上面的人的行為,會知道用<棒子>政策可能會比<蘿蔔>有效很多,要把同樣人次趕向大眾運輸,騎機車被開單20元,可能在要大眾運輸上補貼40 元才有同樣效果,當然也是因為這樣,<棒子>的政策通常比較被大家討厭,造成政府常常在補貼政策上花大錢,成效卻不是很好,也許這是政策制定者值得參考人類行為研究的部分了。

若要說這本書有什麼缺點,我覺得這本書有點草率,全書的翻譯不是很好,漏字錯字有點多(我至少看到三個,沒看到應該會更多),注譯選擇在每章節結尾而不是出現的當下,書末也沒有附翻譯表跟專有名詞索引,讓人看得有點痛苦,原作有可能比譯作更完善一些。
我覺得以行為經驗學來說,這本書不算深入,但要說是導讀,說得有不夠全面能夠真正了解行為經濟學,如果沒有要完全看懂背後的經濟學原理,當小故事書看過去還算可以接受。整理來說不推,相關的議題,市面上應該會有更好的書才是。

最後是書名,其實後面那個「行為經濟學之父教你更聰明的思考、理財、看世界」根本是亂加的,真正的書名就是「不當行為:行為經濟學的形成史」而已,至於幹嘛加上思考、理財,我猜純粹為了吸引眼球吧,實際內容一點和理財一點關係也沒有。