windows系統的記憶體用量指標

最近看到同事在抓漏,但是觀察Memory的指標是Working Set,這是有些問題的,於是花了點時間整理Windows的記憶體指標。Memory大概是Windows系統上最模糊的用詞之一,整理這篇文章順便釐清自己一些疑惑。

Page files

大家都知道Windows上當實體記憶體不足時,會把一些比較不常用的記憶體內容置換到硬碟上先暫存起來,稱之為虛擬記憶體(virtual memory也是個很多義的詞),這個過程稱之為Pageout,存放的檔案叫做Page files。

注意到我用了複數(page files),Windows系統上的Page files可以有0~16個。Page files的功能是儲存那些因為系統記憶體需求的壓力而需要被放到硬碟上的記憶體分頁。

Page files的所在位置可以通過註冊表查詢,或是透過(Win10) 本機=>內容=>進階系統設定=>進階=>效能=>設定=>進階=>虛擬記憶體,進行設定。

根據系統不同,Page files有不同的大小限制,x86最大可以到4095MB,x64或PAE後的系統可以到16TB,IA64可以到32TB。Page files一旦被打開使用後,就沒辦法刪除。因此在系統啟動的狀態下,Page files是無法進行磁碟重組的。Page file可以在系統關機後繼續以硬碟的形式存在在檔案中,但可能會造成安全性上的問題。

Page files的大小一般來說min~max大概在1~3倍RAM之間,也可能會因為系統設定而不在該範圍內。

Commit Charge

我們知道系統有兩種記憶體資源,一種是RAM,另一種是page files。Commit Charge指的是系統承諾一定會在RAM或page files保留空間的記憶體數量。

這裡有點抽象,我解釋一下我對Commit Charge的理解。

某些記憶體的內容,系統並不需要保證「這些內容一定要留在RAM上或page files上」。像是mapping到dll檔的記憶體區塊。當然實際執行時,還是要把這些dll的內容找一塊實體記憶體load上去供程式載入,但拋棄掉這塊記憶體上的內容,之後需要時再從檔案載入回來也行。我們可以說,這種記憶體區塊的內容,他們有associated files作為backing store。Commit Charge指的是那些一定要留在RAM或paging files上的內容,因為這些東西一定得在系統上找個地方放。

順帶一題,Commit Charge的值和實際的記憶體使用量是兩回事。系統承諾會替你保留這段空間,但是你現在並不見得會用到這空間,Lazy是好事,因此實際記憶體的用量會小於所承諾的空間。

系統能承諾的Commit Charge,其大小限制就是RAM + page files的大小。如果Page files可以調大,那麼該限制也會跟著被放寬。如果process持續無限制的索求記憶體,導致系統沒辦法承諾給予,當然就會fail。

以下情況會導致Commit Charge增加,另外可以注意一個指標叫做page file quota(其實就是Private Bytes),每個process都有這個指標,大部分情況下,process page file quota會和commit charge一同增加。

  • 當Process透過VisualAlloc call with COMMIT option的時候,代表Process要系統承諾記憶體。這個值也會加入process page quota。這是最常見的情況了。
  • 注意Commit和Reserved不一樣,VisualAlloc一塊Reserved的記憶體,只是代表我想預訂這一段範圍的virtual memory,但是系統不用承諾我要保留這些空間。系統只會建立紀錄該virtual memory範圍的page table,而這些page table占用的空間會被加入commit charge。
  • 當系統透過MapViewOfFile建立memory mapping,可是背後沒有對應到實際的檔案時,系統會使用paging files作為該塊記憶體的backing store。這種狀況下也會增加commit charge,但並不會計入process page quota。因為這個記憶體用量和process較無關(non-persistent memory-mapped file,通常用於IPC)
  • Copy On Write時,背後要拉一塊新的RAM或paging files去對應Write的內容,因此也必須要取得Commit Charge,這類也不會計入process page file quota。
  • Nonpaged and paged pool and other allocation in system space not backed by explicitly associated files. 系統上會有些可以被分頁的記憶體,也有一些不能被分頁的記憶體區塊,這些都會造成commit charge. 也都不會計入Process page file quota
  • Kernel stacks.
  • Page Table、Page Table的保留空間也會占用Commit Charge。
  • Allocations of physical memory made via the Address Windowing Extension (AWE) APIs

常見的記憶體指標

理解Commit Charge和Page Files後,我們來解釋Windows系統常見的記憶體指標。
我自己在查資料、查書,理解這些指標的過程中,覺得相當混亂,有些指標是其他指標的別名,有些在書上有提到,但網路上查不太到資料,讓人相當困擾。

MSDN的官方文件是我目前覺得最準確的溝通方式,因為其包含了該指標可以在哪個Windows API上取得。而且還附上了工作管理員的對照表。

官方的指標分為兩大類,System層級和Process層級,我想下列幾個指標是一般開發者比較常看到,比較重要的。

文件網址: https://msdn.microsoft.com/en-us/library/windows/desktop/aa965225(v=vs.85).aspx

System Memory Performance Information

  • Committed Bytes
  • Committed Limit

Process Memory Performance Information

  • Page File Bytes
  • Private Bytes
  • Virtual Bytes
  • Working Set
  • Working Set – Private

官方文件網址有列出如何透過Windows API取得上述指標,因此我在這邊著重在各項指標的解釋。

  • Commit Bytes
    • 這是一個系統層級的指標。
    • number of bytes of virtual(not reserved) memory that has been committed. 整個系統中,保證該virtual memory在實體RAM或paging files中會留有一席之地的記憶體數量。
  • Commit Limit
    • 這是一個系統層級的指標
    • 整個系統上可以保證分配給Virtual Memory的空間,包含了RAM和paging files, 當然如果paging files能夠expanding的話,該限制會放寬(是一個soft limit)。
  • Private Bytes, Page File Bytes
    • 這兩個值是一樣的
    • 這是一個Process層級的指標
    • The current size of memory committed to a worker process, which cannot be shared with other processes.
    • 該process已經要求的記憶體量,你可以想像成是Process中Commit Bytes的數量,該指標之所以稱之為Private,是因為排除了像是dll檔案的memory-mapped files所占用的記憶體,注意你無法分辨private bytes的變動來自該process本身,還是所引用的dll執行所造成的。
    • 這個指標並不等於實際的記憶體使用量,commit的記憶體只是系統會留一塊空間,但程式並不保證會使用到。
    • 這個和Physical Memory無關,所以你無法分辨這個數值中,有多少在disk或ram上。
  • Process: Virtual Bytes
    • 這是一個Process層級的指標
    • 該Process所有Virtual Memory Area的範圍總和。
    • The total virtual memory allocation of the process, including mapped regions, private committed regions, and private reserved regions.
  • Working Set
      • 這是一個Process層級的指標
      • 簡單但有一點小瑕疵的解釋是,access不會產生page fault的記憶體量。更簡略的解釋是該Process存在於實體RAM中的記憶體量,而不是該Process所有的記憶體量。所謂的小瑕疵指的是已經備份到page file但還是RAM中的的standby page list並不會計入Working Set。
    • Working Set有計入memory-mapped files,也就是有計入程式間共用的dll。如果把所有Process的Working Set Memory加總會會重複計算到共用的部分。
  • Working Set Private
    • 這是一個Process層級的指標
    • 同Working Set,但只包含該Process自己使用的部分,不包含共用的memory mapping file(如dll)。
    • 關於Working Set和Working Set Private, 這個stackoverflow有個有趣的蠟筆比喻。

雜項

順帶一提,上述那些Memory相關的指標,對於Memory Leak除錯基本上都沒太大幫助。

Working Set顯示的是在實體記憶體中的數量。和程式所消耗的總記憶體相關性有限。Private Bytes稍微有幫助一點,但是你無法分辨該數值的增加是來自程式本身還是他所引用的dll檔。Virtual Bytes是個不能精確反映程式實際分配記憶體量的指標。

工具

Windows Internals提供許多分析Memory的工具,有些蠻好玩的可以裝,玩一玩會覺得Task Manager很弱XD。都是免費的,google查一查直接裝就好。

  • VMMap 看虛擬記憶體
  • RAMMap 看實體記憶體
  • Process Explorer 比Task Manager更詳細的Process資訊
  • Process Monitor

Reference:

繼學vim的啟示之後,終於解掉心中的困惑

這篇算是上Visual Studio極速開發的課後心得吧。

在三年前,我寫過一篇文章叫「學vim的啟示」。內容大概是記錄自己從不熟悉vim,想mastering vim,想把vim tuning到跟IDE一樣所經歷的崩潰過程。

學Vim的啟示

每個學vim的使用者大概都會有一段崩潰的經歷,從入門到放棄。少數人會堅持下來,並且可以在日常生活中使用vim。我也是過來人,這三年期間,vim的日常操作沒太大問題,但心中一直有個遺憾在:「我還是不知道高手到底是怎麼達到開發如喝水般的境界。」

接下來三年我做機器、我當兵、我出社會開始第一份工作,這個疙瘩就慢慢隨時間淡忘。直到去年的時候,我看到91 Po出了他行雲流水的開發影片,心中整個一震:「這不就是我當時幻想的開發速度嗎,前輩竟然做到了!」

後來換第二份工作,從寫JS轉到寫C++,因為工作的緣故日常開發開始使用Visual Studio,便迫不及待的報名91開的「Visual Studio極速開發」,想一窺背後的秘密。這門課支援三種語言C#/Java/PHP,但多數人是使用C#開發,之前沒有接觸過C#,課前兩週還特地看微軟官網、自己試寫幾個小程式把語法弄熟,深怕上課過程會跟不上進度,浪費了報名費、害我那兩週幾乎沒有在重訓還熬夜,體重掉了兩公斤。

上完課後腦洞大開,從第一天上課台上什麼都程式都寫不出來的挫樣,回家刻意練習了一整個禮拜,到了第七天終於在22分鐘內以TDD的方式完成了Tennis Kata。

不論是技藝還是心態,這門課都給了我很大的啟發

技藝上最大的啟發是,我終於知道自己用vim的瓶頸在哪裡。

我在三年前的文章裡,寫過這麼一段話:

建立你自己的Vim,因為只有你知道你自己的需求、習慣的工作方式,這樣的練習對你才有意義

這段話基本上並沒錯,很政治正確但是沒啥意義,因為真正的問題在:「你不知道自己的需求。」

不知道需求的意思是:「你不知道你現在要做什麼」,舉一些case像是

  • 不知道自己接下來該寫什麼,於是思考會卡住
  • 不知道自己想找的檔案的位置,於是要花時間找檔案
  • 不知道自己想怎麼重構、想怎麼寫,於是花時間在打字刪除打字刪除

如果不知道自己在做什麼,就會按很多多餘的按鍵、就會開始用滑鼠上下瀏覽看code、表面上看起來很認真在寫程式,實際上只是在裝忙,因為那些行為都沒有實際的產出。

如果你很清楚你要做什麼,你就有了目標。目標越明確,就可以進行最佳化(跟深度學習一樣XD),就可以去一步一步改善,進入iteration tuning的cycle。

光是知道想做什麼還不夠,還要有能力做到這件事。也就是對工具的熟悉,知道該如何用最短的方式下vim指令,而這過程有非常多坑,當坑多到一個程度的時候,大多數人就會被困住動彈不得,放棄並回到自己熟悉的方式,就跟三年前的我一樣。

想要破坑的方法在於「看到有人真的做到了」、「了解他是怎麼做的」、「刻意練習並內化成自己的技能」

「看到有人做到了」這件事情最難,因為大多數人會被「不知道自己不知道什麼」這件事情困住!於是自己在爛泥坑打轉,想要破坑的方法在於參加社群、脫離自己日常的小圈圈、知道比自己厲害的人是怎麼做事的。

「了解他是怎麼做到的」,這件事情稍微容易一點,透過培訓或上課是最快速的方式,主動發問也是個不錯的方式,但如果發問者和實力差距太大的話,一樣會陷入「坑太深被卡住」的困境。

「刻意練習並內化成自己的技能」,這大概是最容易的了,只要花時間就可以做到了。方法論在從籃球機看練習的重要性有提到過。但雖然說容易,沒花個數十個小時大概也是做不到的。

上完課後,我花了一週的時間,每天平日晚上練習三個小時、假日練習五個小時。第一天連環境都架設不好,第二天第三天進度崩潰的慢,花了兩三個小時一個鍵一個鍵對照他的效果、試按,連範例影片的前五分鐘都練不完。

到了第四天的時候,突然腦袋某個地方開關像打開一樣,意識到自己的問題是對TDD不熟悉,必須要以TDD的角度去看Tennis Kata為什麼要這樣寫。進步速度開始飆升,我開始能在45分鐘內完成、接下來每次練習都比之前再快一些些,在第七天,終於在22分鐘內完成。而三個禮拜前我還不會C#。

認知到「這個坑是填得起來」這件事讓我非常開心,後續要把這個技能transfter learning到C++上恐怕還要一些時間,一整個禮拜的練習過程頗辛苦,但感受到自己以穩定的速度進步這件事相當愉快。

非常感謝91大大傾囊相授,破除了我的盲點,除了學到很多技術之外,心態上也成長許多,讓我意識到「不知道自己不知道什麼」、及「該如何review自己並持續改善」,最可怕的是前輩每天都持續在進步,要達到可以把這些知識教給他人,背後要付出的努力根本不敢想像,希望有一天能看到前輩的車尾燈。

最近打算買本學徒模式來看,以前大學時看不懂,覺得這樣也可以出一本書,現在大概會非常有感吧。

清燉牛肉麵的經驗價值

華亞科附近有一間小店叫湯本源,賣得是湯和拌麵,店門口看起來乾乾淨淨,擺了一台點餐機器。某次覓食時看到店門口菜單,一碗肉湯、一碗麵上面放一撮醬,小疊子盛了三種小菜、一杯酸梅汁,要價300元上下,眉頭一皺覺得價格和預期落差太大,便打消入內用餐的念頭。

但我心中一直有個疙瘩在,這間店在Google評價上非常高分,身為一個鍵盤美食家,不踩踩雷說不過去。在門口的點餐機猶豫了一會,老闆娘走出來介紹餐點,哪些辣哪些不辣,決定當作被騙吃一次看看,點了一份320元的清燉牛肉湯,配干貝XO醬拌麵。

 

吃完後的感想是,實在是太便宜了。

 

當你吃到「用心製作的好吃食物時」,你會覺得,啊,這食物的味道就應該要這樣!

清燉牛肉湯中,牛肉塊給的毫不吝嗇,比一般牛肉麵店還多,切成適合入口的大小。牛肉燉得透徹,但形狀又完整,輕嚙即化,牛筋軟嫩輕咬即斷開,放入口中咀嚼,滋味雋永,清燉的湯味道不是厚重的路線,不鹹,喝起來神清清爽。

一旁的XO醬拌麵滋味也很棒。單吃麵條本身沒有什麼味道,但把上頭的XO醬拌開後,微辣和干貝的香氣非常下麵,XO醬本身不死鹹、鮮味誘人,單吃一小撮也沒什麼問題。太辣時配上酸梅汁解膩,中和掉辣味後,剛好可以再喝一口清燉牛肉湯。非常的愉快。

三碟份小菜也很用心,切開的溏心蛋蛋黃呈現凝膠狀,涼拌百香果青木瓜上有黑色一粒粒的百香果籽,咬下去清脆微甜。麵筋筍乾滋味簡單,就是他該有的味道。

店家有提供肉臊飯,如果吃不飽可以免費加點。吃完上面這些其實已經八分飽了,但我實在太想吃看看他的肉臊飯是什麼樣子,決定加點他的肉臊飯。

飯端上,看一眼就知道絕對不簡單。米粒光澤飽滿粒粒分明,上面的肉臊肥瘦比大約3:7,給的毫不小氣,整碗吃完非常滿足。最後一口乾掉酸梅湯當作收尾,杯子的底部還陳著碎花瓣。

後來跟老闆娘聊天,稱讚他們食物的用心,老闆娘說他們的飯是選用冠軍越光米。酸梅湯要煮四個小時。老闆有三十年的料理經驗,參加兩岸料理大賽拿到金牌,店內擺著四本老闆出過的書、其中一本還專門講醬汁怎麼調、另一本是最近出版的,講家常菜的食譜。

翻著這些書,我可以感受到主廚對料理的熱愛。料理不外乎是各種變因的集合,食材的選用、烹飪的材料、方式、時間。厲害的廚師之所以厲害,在於他持續保有熱情,花了很多時間去調整變因,為了一道菜的本味,可以反覆的做,直到調整成自己覺得適合的味道,並把這些經驗內化成自己的技能。這些都需要時間積累成經驗,而320元一餐,其實一點都不貴。

 

但一般人能夠理解這樣的價值嗎?

 

很遺憾,不見得。

這間店的生意並不算好,我中午來的時候,店內並沒有其他客人,過一陣子才來了兩三組。大多數人在店門口看到價格晃晃就卻步離開,Google評論上也有1顆星,嫌湯太淡、嫌CP值太低的評論。

不是每個人都能理解經驗與用心的價值,就連我一開始也覺得,320元吃那一碗湯一碗麵,真的好貴。但多數吃過的客人評價都很高,覺得物有所值、變成回頭客不在少數,有些華亞科園區主管也會帶客戶來這裡用餐。

 

食材的價值估算簡單,廚師的經驗價值估算困難。

工程師的薪水價值估算簡單,工程師的經驗價值估算困難。

可是親口吃過、一起工作過,你會知道兩者的差距是一天一地。

不要追求CP值,而是追求物有所值。

Cannot load relative line numbers in Visual Studio 2017 enterprise

After installing extension relative line numbers in Visual Studio 2017 success, I opened a new project and found that the relative line number plugin is not loaded correcly.

Open logs in ActivityLog.xml I saw following error

<description>System.Runtime.InteropServices.COMException (0x80131163): 
Type library exporter encountered an error while processing &apos;
RelativeLineNumbers.OptionPageGrid.SaveSettingsToXml(writer), 
RelativeLineNumbers&apos;.
 Error: Type library exporter encountered an error while processing &apos;
Microsoft.VisualStudio.Shell.Interop.VSSAVETREEITEM.pHier, 
Microsoft.VisualStudio.Shell.Interop.8.0&apos;. 
Error: Type library exporter encountered an error while processing &apos;
Microsoft.VisualStudio.Shell.Interop.SVsSolutionObject, 
Microsoft.VisualStudio.Shell.Interop&apos;. 
Error: Type &apos;SVsSolutionObject&apos; 
and type &apos;SVsSolution&apos; 
both have the same UUID.&#x000D;&#x000A; 
at EnvDTE._DTE.get_Properties(String Category, String Page)&#x000D;&#x000A; 
at RelativeLineNumbers.RelativeLineNumbers..ctor(IWpfTextView textView, IEditorFormatMap formatMap, DTE dte)&#x000D;&#x000A; 
at RelativeLineNumbers.MarginFactory.CreateMargin(IWpfTextViewHost textViewHost, IWpfTextViewMargin containerMargin)&#x000D;&#x000A; 
at Microsoft.VisualStudio.Text.Utilities.ContainerMargin.<AddMargins>b__25_1(IWpfTextViewMarginProvider mp)&#x000D;&#x000A; 
at Microsoft.VisualStudio.Text.Utilities.GuardedOperations.InstantiateExtension[TExtension,TMetadata,TExtensionInstance](Object errorSource, Lazy`2 provider, Func`2 getter)&#x000D;&#x000A;
--- End of stack trace from previous location where exception was thrown ---&#x000D;&#x000A; 
at Microsoft.VisualStudio.Telemetry.WindowsErrorReporting.WatsonReport.GetClrWatsonExceptionInfo(Exception exceptionObject)

 

You can fix this issue by reference this with a little revision

  • Launch “Developer Command Prompt for VS 2017” as Administrator
  • Go to VS 2017 installation folder cd C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise
  • gacutil -if Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.Shell.Interop.dll

 

key point is last line, Microsoft.VisualStudio.Shell.Interop.[8|11|12].0.dll won’t work for me.

Hope this helps, happy coding 🙂

理解tensorflow中convolution和padding的維度變化


類神經網路進行convolution或pooling時,一定會遇到padding計算的問題,在經過不同大小的stride和kernel後,output的維度常常令人一知半解,在此筆記自己的理解。

Tensorflow關於padding有兩種設定,一種是SAME,另一種是VALID

1. VALID

Valid的想法很直觀,我們讓kernel在input上以s步長(strides)滑動,進行計算,同時保持kernel所覆蓋的範圍不能超出input。

因此計算上簡單的想法是,input size先扣掉最尾端的kernel size,剩餘的部份+1就是kernel anchor可以進行滑動的範圍。如果此範圍可以被strides整除,那就皆大歡喜。如果此範圍無法被strides整除,就代表剩餘的部份一定可以再放一個kernel。因此我們用取ceiling表達最後的output size。

VALID狀況下的output size計算公式:
\begin{equation}
\left \lceil{\frac{n_i – k + 1}{s}}\right \rceil = n_o
\end{equation}

2. SAME

Same的output size定義是這樣子的,

SAME狀況下的output size計算公式:
\begin{equation}
n_o = \left \lceil{\frac{n_i}{s}}\right \rceil
\end{equation}
如果設定為same,output size並不受kernel size影響,因為不管kernel size多大,都會自動補滿計算。唯一會影響output size的是步長,步長越大,output size就會按照比例縮小。

通常搞懂上面兩個公式,就可以了解網路架構的size在通過convolution和pooling之後會如何改變,剩下的細節問題會是:那Same怎麼知道要補多少padding,而且padding要怎麼補?
繼續閱讀 理解tensorflow中convolution和padding的維度變化

什麼是成熟,寫在從第一份工作離職之後

什麼是成熟

上個月和一個愛看電影的朋友討論一個有趣的問題:「什麼是成熟?」

朋友最近看了一部電影,內容敘述一名高中女學生喜歡上老師,但這段戀情卻不被他人祝福,大人告訴他你的喜歡會對老師造成困擾,你的思考還不成熟、未來還有許多值得嘗試的東西。而女學生卻覺得,為什麼他不能喜歡一個人?她因為喜歡,唸書都變得很快樂、成績也變好了,為什麼不行呢?

朋友分享他看完電影後的想法:大人們總是告訴我們不該做這個、不該做那個,大人們所謂的成熟,似乎都是要避免困擾,與其追求或爭取想要的東西,避免負面的結果理性上才是對的。但這樣的想法真的能被稱作成熟嗎?

大人們通常阻止學生追求愛情的理由,多半是學生時期的女朋友很有可能未來會分手,既然遲早會分手,與其浪費時間談戀愛幫別人養老婆,不如先努力讀書賺錢還來得實際。但我認為與其阻止學生談戀愛,不如讓學生學習處理兩人相處中會遇到的問題,沒有人一出生就會談戀愛,這需要時間練習、調適,很多人最後沒有跟第一任對象結婚,但之前犯下的錯都會成為滋養感情觀的養分。

朋友聽完後說,成熟似乎總是和圍繞在過錯上,大概是因為成熟的相對詞是幼稚吧,幼稚給人的感受是容易犯錯、做事情不得體。但那些阻止學生談戀愛的大人們似乎覺得,避免犯下錯誤才是成熟,難道成熟是完善的思考與理性行動嗎?

我想想說道,大人們為了避免學生荒廢課業,預先禁止學生談戀愛,可能會讓自己成為經驗主義的受害者。就像心理學實驗中一群被關在籠子內的猴子,籠子頂掛了香蕉,每次有猴子嘗試拿香蕉,實驗人員就會把冷水從上面潑下來,一段時間之後,每當有猴子想拿香蕉,其他猴子就會毆打阻止,避免被冷水波及。後來實驗人員陸續把籠子內的猴子換掉,換成沒有被水潑過的猴子,結果每當有猴子想去拿香蕉,其他人就會去阻止,甚至籠子內已經沒有任何一隻猴子被水潑過了,他們還是重複前人的行為,用自己過去的經驗武斷地下結論,這樣的作法大概也稱不上是完善的思考與理性行動。

「那怎麼樣算是一個成熟的行為?追求愛情,還是乖乖讀書,哪個才算是成熟?」朋友好奇問道。

「更好的問題會是,成熟的行為應該帶來什麼樣的結果。舉個例子吧,一個追尋愛情的女生面臨兩個選擇,一個是喜歡他外表的有錢人,另一個是很愛他的窮書生,他該選擇誰才算是成熟?」我反問。

「那要看他要什麼。」朋友說。

「所以成熟是,知道自己要什麼。」語畢,朋友與我都安靜一陣子。

知道自己要什麼

知道自己要什麼,勇敢地做出決定並負起責任,是多麼困難的事情啊。大人們認為高中談戀愛的學生不夠成熟,因為他們涉世未深,沒有足夠的經驗判斷對象的好壞,而且可能會因此犧牲學業,在不久的將來後悔,於是阻止他們談戀愛。但那些乖乖聽話,白天上學晚上補習的學生們就知道自己要什麼嗎?

從小到大,學校教我們好好讀書,社會要我們找份體面的工作賺錢、找好對象結婚生子,卻從來沒有教我們認識自己,搞清楚自己要什麼、不要什麼,然後好好追尋自己想要的,讓自己每天快樂的過日子。社會只會在三十歲時關心你怎麼還沒有對象,卻不關心你想要過什麼樣的生活,商人透過廣告說服你需要買這個,卻不關心你真正的需求、沒有人在意你每天工作快不快樂,只有過年時親戚會問你領幾個月年終。

在高中畢業選填資工系時,其實我並不知道自己要什麼,經過兩年以上的修課、自主學習課外的知識,才逐漸對資工系在學什麼有比較清晰的掌握。但其實上完四年課,儘管我會寫程式,但我依然不確定自己是否喜歡寫code、是否願意把寫code變成一生的志業,我只知道自己喜歡打造東西的樂趣。

在大四時決定做自動飲料機時,我其實並不知道自己要什麼,只覺得我不想繼續碰純軟了,想要開發硬一點的東西。結果沒想到頭一洗下去就花了14個月,途中遇到各種困難,還因此延畢了一學期。這專案讓我一窺硬體開發的世界,就像是在薩爾達傳說探索了新地圖一樣,我有了其他資工系學生沒有過的經驗。

後來我選擇不念研究所,因為我不想要在自己想要什麼都不清晰的情況下花兩年拿碩士學位。當完兵後我選了一間以分紅不錯聞名、同事都是高手的公司,結果不到一年我就離職了。我發現我對公司的產品沒有足夠的熱情。儘管我繼續待下去,兩三年之後可以有不錯的收入,但金錢對我而言並沒那麼重要。

後來我向一間做機械手臂的公司投了履歷,展開了職涯的第二份工作,現在的我開始新工作第三週,薪水比第一份工作少很多,但我每天上班比以前都快樂。

我在第一份工作的時間是不是浪費了?如果我畢業後直接先做第二份工作,會不會更好?不,不是這樣的。第二份工作有優點,也有缺點。如果沒有第一份工作經驗,我不會看到高手同事用什麼樣的方式看待程式碼,讓我在進行第二份工作時,迅速自信地看出可以改善的部分。如果我沒有做過硬體專案,我可能無法看出軟硬整合的價值。如果我一畢業直接做第二份工作,可能會把第二份工作的做事方法定錨成衡量公司好壞的標準,在不確定自己的喜好的情況下,或許並不喜歡這份工作。

你通常不會在第一次就做出正確的決定,你的第一個伴侶往往不會和你走入禮堂。你不太可能第一份工作就做到65歲退休。你不會一覺醒來就突然知道自己要什麼,也不會在考完學測填志願時就確定自己一生的志業,你20歲想要的東西和30歲可能很不一樣。

認識自己其實和軟體開發很像,顧客往往不知道自己真正要的是什麼。如果你照著傳統的瀑布式規劃走,先寫規格(e.g. 決定自己想讀什麼科系),按表實作(e.g.乖乖讀完四年大學),最後給客戶驗收(e.g.畢業當完兵開始找工作),很可能會發現產品和現實有很大的落差(e.g.學非所用)。唯一的應對方法是保持敏捷,相信需求本來就會一直改變。你本來就該持續和自己溝通。盡早嘗試,不追求完美,早點生出第一版原型並下水測試,犯錯,然後修正。當你修正的速度夠快的時候,早期犯下的錯誤根本無關緊要。多和其他人交流、溝通,看看世界上其他比你厲害的人是怎麼做事、思考。實作、實習、實踐,做中學才會看到更深入的東西。最怕的是在不確定自己要什麼的情況下,做出一個高成本高代價,而且無法修正的決定。

如何儘早用低成本的方式知道自己要什麼,活出無悔人生,早在2001年2月,一群去山中小屋滑雪的軟體開發專家們早已提出了解答。你只要將敏捷軟體開發宣言中的「軟體」代換成「生命經驗」,將「需求」改稱「自我實現的需求」,一切就豁然開朗。

我們遵守這些原則:
我們最優先的任務,
是透過及早並持續地交付有價值的軟體
來滿足客戶需求。
竭誠歡迎改變需求,甚至已處開發後期亦然。
敏捷流程掌控變更,以維護客戶的競爭優勢。
經常交付可用的軟體,
頻率可以從數週到數個月,
以較短時間間隔為佳。
業務人員與開發者
必須在專案全程中天天一起工作。
以積極的個人來建構專案,
給予他們所需的環境與支援,
並信任他們可以完成工作。
面對面的溝通
是傳遞資訊給開發團隊及團隊成員之間
效率最高且效果最佳的方法。
可用的軟體是最主要的進度量測方法。
敏捷程序提倡可持續的開發。
贊助者、開發者及使用者應當能不斷地維持穩定的步調。
持續追求優越的技術與優良的設計,
以強化敏捷性。
精簡──或最大化未完成工作量之技藝──是不可或缺的。
最佳的架構、需求與設計皆來自於
能自我組織的團隊。
團隊定期自省如何更有效率,
並據之適當地調整與修正自己的行為。

認識自己並不是一張職業性向量表就可以解決的事情,你必須要做各種嘗試,取得回饋、遇到困難、遇到挑戰,看到更大的世界、每一步的決定都會讓你更認識自己一點,你會遇到很多人、發生許多有好有壞的事、隨著你的閱歷逐漸豐富,你會知道對你而言什麼是重要的,而生命有限,什麼是可以割捨的,那才是真正形塑你樣子的東西。

成熟,就是知道自己要什麼。

成年人,就是知道自己要什麼,並且能夠替自己的決定負責的人。

因為自動飲料機而延畢的那一年(23)

處理完電路、機構,經過無數次的測試後,終於來到了最後一哩路。

測試時為了方便,都是使用自來水,但工廠加工的元件可能會有一些油漬,為了徹底洗淨,我們準備了一個大鍋子和兩包檸檬酸,將會接觸到食物的不鏽鋼零件酸洗。

繼續閱讀 因為自動飲料機而延畢的那一年(23)

因為自動飲料機而延畢的那一年(20)

後來我放棄整張桌子全部用不鏽鋼做的想法,價格上實在是無法接受,我找了一間角鋼家具行,請他們用角鋼組了兩張桌子,桌面用不鏽鋼包木板,另外挖一個洞留給管線穿過,角鋼本身是鍍鋅的,比起不鏽鋼耐腐蝕性差了點,但兩三年應該還是堪用的,兩張桌子不到五千塊解決。角鋼真的是很台灣style的發明,雖然一個洞一個洞不夠美觀,但支撐力絕對是一等一的。

繼續閱讀 因為自動飲料機而延畢的那一年(20)