顯示具有 Thinking 標籤的文章。 顯示所有文章
顯示具有 Thinking 標籤的文章。 顯示所有文章

2014年5月10日 星期六

從不同程式語言的異同思考問題的本質

《學程式語言的樂趣》描述我早期學程式語言的事,後來幾年多了一些心得 ( Python, Haskell, C++, Objective-C ),之後有機會再補上。這裡想寫的是藉由學習不同程式語言後明白的事。

學特別的程式語言有助於掌握不同的概念。我最初慣用的語言是 C (高中三年),再來是 Java (大學四年)。藉由 Java 開始接觸 OOP 的思維,除了程式語法之外,學到更多的是寫程式的思考方式。其實回頭再去看 C,也可以使用一樣的思維,只是當語言直接綁入思維時,會被迫這麼做。就像用 Haskell 必須寫出 stateless 的程式,就會更明確地留意 state。不過學 Java 的時候還沒察覺到這點。

後來長時間地陸續用了 Ruby、Python、C++,還有加減寫 JavaScript。開始掌握到一些程式語言背後共同的特性:組合邏輯控制,以及管理資料的狀態。回歸到最原始的電路來看,程式的運作就是邏輯控制 (and/or) 和狀態 (on/off)。當要做的事變複雜時,必須結構性地管理它們。

舉例來說:

  • Java 定了 class 和 interface 表示「資料+實作邏輯」和「操作介面」,class 內又有 public/(default)/protected/private 限制資料的存取範圍。還有 package 封裝同一群 class。
  • Python 表現的比較直接,容易連結回 C 該如何表現這些思維。每個 method 第一個參數一定是物件本身,慣例命名為 self。'_' 開頭的 function 和 method 表示只限於內部使用。用 module 封裝同一群 class。
  • C++ 藉由不同的方式使用 virtual,class 可當作 "class" 或當作 "interface",或帶有實作的 "interface"。class 有 public/protected/private 限制資料的存取範圍,但又有 friend 可讓指定的 class 存取無視這些限制。有 namespace 封裝同一群 class,還有 anonymous namespace 可以嚴格的封裝實作細節。

不同的語言有各自擅長的地方,學習別的語言的時候,會想要借鏡別的語言的特色,運用到原本常用的語言裡。但是接觸過 Scheme 和 Haskell 再回頭嘗試用在 Python 和 Java 的時候,遇到很大的問題:

  • 無法直覺地使用天生不支援的功能。比方說 Java 的 function 不是 first-class function,得用物件包一層,再自成一套體系。例如用 functionaljava
  • 和原本語言本身的風格不合,增加其他人的維護成本。

第二點是比較大的問題。自己用了一套「functional Java」的寫法,其他人也得學習如何解讀。以 Python 舉例,下面是同一件事用三種不同寫法:

for-loop

numbers = []
for i in range(0, 10):
    numbers.append(i * 2)

list comprehension

numbers = [i * 2 for i in range(0, 10)]

map

numbers = map(lambda i: i * 2, range(0, 10))

對沒學過 Python 的人來說,for-loop 比較直覺,沒學過 Python 也可推敲出意思;初看 list comprehension 不明白這是什麼,不過花點時間看幾個例子就懂了。map 比較困難,得有 functional programming (FP) 的概念才能明白。

Python 本來就有這些語法,我們不會責怪這樣寫的人。但用在 Java 裡就有爭議了,為什麼要另外包一套框架,寫出要別人花額外工夫才能讀懂的程式?

後來我察覺到更深層的思維:OOP 也好、FP 也好,目的都是結構性地管理資料和邏輯,只是表達的方式不同。掌握到這點後,我將時間花在有助於真正目的事上,而不是寫得更 OOP 或 FP。原本遇到的困擾 (如何在 B 語言裡善用 A 語言的特性) 自然就不存在了。

舉例來說:

  • 為什麼 FP 要強調 immutable,還有習慣用 map? 因為 immutable 的資料沒有 state,自然沒有被誤改的風險。有沒有用 FP 的 map 到不是重點,map 只是方便套用一套控制邏輯產生另一批 immutable 資料。是實作層級的小幫手,不是設計準則。
  • 為什麼 OOP 強調 Tell, Don't Ask? 也是為了減少外漏 state。即使用沒有 OOP 的語言,也可這麼做。像 iOS 的 Quartz 2D,API 需要用的 CGContextRef 是 struct CGContext* 的 typedef,但是使用者不知道 struct CGContext 是什麼,只知道呼叫函式時要傳入 CGContextRefQuartz 2D 封裝需要的 state 在 struct CGContext 內,隨時可改變它的結構。
  • 為了方便模組之間獨立開發,不用擔心日後改寫模組內部的實作造成外部程式出錯,最重要的是定出乾淨的介面,讓別人不會誤用。再來才是善用語言的特性讓別人想誤用也不行。例如 C++ 的 anonymous namespace 是隱藏實作的好方法;Java 的 package + (default) class 也是好方法;Python ... 只能用底線命名然後祈禱不要有人亂搞。

從問題的本質 (管理資料和邏輯) 來看,自然會明白這些設計準則,還有區分出設計和實作 (準則和表現方式)。剩下的是衍生想法,像是管理 state 方法的優先順序:

  • 沒有 member field (沒 state 最好!)
  • 有 immutable member field (非得有 state 不可的話,至少讓它不可修改)
  • private mutable member field (非改不可的話,盡可能減少能改它的程式碼)
  • ...

重點還是掌握問題的本質,避免迷失在解決的方案之中。

結語

總結來說,一套程式語言有一套思維,試過多套不同特性的語言後,藉由它們之間的同異處,可以察覺這些語言想解決的問題是什麼。繼而明白真正的問題是什麼,再回饋到解決問題的思維中,避免落入特定解決模式裡 (如道地的 OOP 或 FP)。起初學不同語言只是覺得好玩,誤打誤撞得到這樣的體會,滿有意思的。

相關文章

2014年3月2日 星期日

事情的另一面: 測試與除錯技巧

回顧過去數年的經驗,最大的體悟除《從需求出發理解背後技術的思考脈胳》以及《專注於滿足需求而非工具或方法》之外,大概就是沒有所謂的鐵則,許多事情都有另一面,端看你處於什麼情境、從什麼角度看它。

上份工作以 machine learning 為主 (2008 ~ 2011),針對一個特定的應用問題,實驗不同的演算法,看看能否實際運用在產品上。結果不如預期時,會陷入不知該懷疑演算法、演算法參數、還是程式寫錯的窘境。因此,對於程式正確的要求,遠高於其它產品。這樣才能專注地藉由實驗修正理論模型。在這個需求之下,Test Driven Development 就成了相當有用的開發方式。經過數次用 TDD 開發的經驗後,總算能夠達到和不用 TDD 差不多的開發效率。這意味著用了 TDD 也不會拖慢完成第一版的時間,並且程式更易於理解和維護。儼然是 TDD 的完全勝利!

但這個經驗有個代價。代價不是學習 TDD 的時間,畢竟學什麼工具或方法 (如OOP) 都要時間。學習 TDD 對立的結果是: 學不到除錯的技巧。

起初我以為除錯是果,治本的方式自然是避免有因。那麼,TDD 貌似完美的解法,學 TDD 即可。但是開發專案免不了團隊合作,也免不了使用第三方程式。換句話說,錯誤遍地都是,有時甚至是作業系統或編譯器的錯。拙劣的除錯技巧無法適應這個時代。我在和別人一起除錯時才發覺這事。對方能力很好,不過開發習慣不太好,常犯一些「我無法想像的錯誤」。但也因為他的習慣,讓他可以比較快看懂別人寫的亂糟糟的程式,可以比較快想到問題可能出錯的地方。我費了不少力氣才補足這塊,實在是始料未及的事。只能說,該走過的路還是得走,無法省去。

目前的工作以 C++ 為主,為了在大量的原始碼裡除錯,偶而會視需求加強一下 gdb 的使用技巧,還有練習寫 python script 簡化 gdb 操作程序。相對於兩年前,gdb 的操作技巧進步不少。另外也寫了 gj 幫助閱讀程式碼。但是在觀察同事的開發方式後,發覺我有時過於依賴工具的便利性,反而減少全面性的思考。最後還是得有系統地一步步思考、推論,才能有效率地解決問題 (關於這點,之後有適當材料再另寫文章說明「系統化的解決問題」)。換句話說,熟練除錯工具反而無意識地減少我系統性思考的時間,也滅少我系統性思考的經驗。我的意思並非捨棄除錯工具,像 Sherlock 那樣全部都在自己的思維宮殿裡解決 (雖說那樣實在是相當地帥啊!)。凡人如我等,還是需要工具輔助搜集情報和記錄訊息。只是這兩件事是相斥的,愈是熟練除錯工具,愈少思考;愈長思考,自然也愈不依賴除錯工具。

再回頭看 TDD,目前的工作絕大多數情況不適用 TDD。一來不像開發 machine learning 工具那樣,要求近乎100%正確。二來大部份的程式和 GUI 相關,本來就不容易測試。若要達到像以前一樣的開發效率,我得先熟悉 C++,再熟悉 C++ 基本的 unit test 工具,再熟悉和 GUI 相關的測試工具和知識。對照達到後帶來的好處,相當地不划算。不過其中一個和 GUI 無關但和網路高度相關的子專案,我很自然地用 Python + TDD 的方式開發核心部份。日後上線時,也從中獲得明確的回報: (1) 極少的錯誤。以及 (2) 透過單元測試輕鬆地重制線上偶而才會發生的網路錯誤,只更新一次程式碼就修正了問題。可參考《寫出容易測試的程式》了解類似的處境和用到的技巧。當然,我也因此「失去」一些線上除錯的經驗。

除了測試與除錯的心得外,軟體設計模式和軟體開發準則,也讓我經歷了幾次「打破鐵則」的心路歷程。之後再另寫文章補充。

回顧這些事,讓我明白個人經驗的侷限,而減少過度歸納和推衍的習慣。看別人的論述時,會多想想自己和對方的情境,從中得出目前我能用到的部份。不會過於尋找或遵從「聖杯」。白話來講,就是比較務實吧。

2012年8月5日 星期日

從需求出發理解背後技術的思考脈胳

最近在技術上多了不少體悟,關鍵是要掌握住問題的需求,接著不斷思考和嘗試,避免卡在特定的規則或工具裡,將重心放在隱藏在這些東西背後的核心思想。

直接看現有的工具或別人的作法很難有所體會,但自己從頭邊做邊想,會得出自己一套理論, 接著會出乎意料地更快理解這些工具和作法。畢竟在足夠嚴苛的需求下,方法可能有些差異,背後的精神卻是類似的。

比方說,若程式反應速度要求在 1ms 以內,全部資料來源都得在記憶體或網路,不能使用硬碟。那麼,針對這種應用,單機程式能做的事只有將東西塞在記憶體裡取用

然而記憶體有限,資料總有放不進去的時候。在這種速度要求且資料過大的前提下,可能的作法大概是:

  • 像 cache 那般有套機制留住最常用的資料。
  • 在記憶體裡存 index,index 內存必要的資料,若需要更多資料再從硬碟讀。
  • 先做前處理「壓縮」資料成摘要,摘要必須小到可以放入記憶體內。資料的品質(正確性)也許會有一些損失,但是是必要的取捨。之前在讀 YouTube 關聯影片和 IBM 的 Watson 論文時,有看到類似的思路,工作上也做過類似的事。和前述方法不同的地方是,資料的筆數變少,轉為另一種高質量的資料。

再以 Test Driven Development 為例,最重要的不是 TDD 的三步規則,也不是相關工具要怎麼用,而是導入「在設計的開頭, 就將測試視為主要考慮項目」,其它東西都是這個想法的衍生。

從這個角度出發,實作久了自然會理解為什麼介面要開洞放入物件,為什麼需要 factory 隔離生成和操作邏輯。至於是否真的有先寫測試,現在我覺得不是鐵則,在有為測試而考慮的設計下,在必要時補測試可能更划算,將時間花在刀口上。但若一開始沒為測試考慮,事後要補就很辛苦,加測試的價值又更低了

再往上拉一個層次來看,解決問題的前提,本來就是如何確認問題有被解決,若無法確認問題有無被解決,用什麼方法也是白搭,不知成效如何。從這個角度來看,在設計之初就考慮測試,並不是什麼新穎或強人所難的事。但要走到這步,如同學其它東西一般,需要累積不少經驗

總結來說,要學習一個技術最好的方法,就是在有適當的需求時再學。平時看到和自己需求無關的知識,加減有個印象在腦裡即可。待要用到時可利用腦裡的索引找出相關資訊,先有個廣泛認知。接著根據自己的需求可以明白那些是比較相關的知識,邊看邊動手做些雛型試試。有了這些操作經驗和背景知識後,再從頭確認一次自己真正的需求為何、有那些限制和對應解法,就能理解要如何應用這些技術和工具到自己的情況裡。

2012年2月19日 星期日

專注於滿足需求而非工具或方法

看到 command 提到《Don't Fall in Love With Your Technology》,而有一些感觸。

從高中開始,我一直想弄明白 Perl、Python 到底那一個比較好用,這樣我學其中一個就可以了。後來又多了 Ruby 這個選項,讓這問題變得更複雜。大概到大學後期或研究所的時候,我才肯定這是一種信仰上的爭辯,而將這個問題拋之於腦後。

同一時期,我也花了滿長一段時間才明白許多問題沒有標準答案得視情況而定。每當對此有所體會時,就會想起大學電子學老師整年重覆強調的一句話:「沒有前提,就沒有答案」。雖然兩學期的電子學都是低空飛過,這句話深深印在心裡,只是那時我對這句話的理解仍不深,還需時時重新琢磨它的含意。

我花了更長的時間才將前面兩個心得連結在一起,從而明白任何工具或方法的爭辯很可能都是偽命題,重點在於需求是什麼?要如何滿足需求?如今回想起來,《不要自称为程序员》將這個觀念解析得相當清楚,相當值得一看。

舉例來說,「vim vs. emacs」是個偽命題,這取決於自己當下的環境為何。若團隊內多數人使用 emacs 且自己兩者都不熟,那麼 emacs 是較為合理的選擇。反之,若自己相當熟 vim 而團隊內多數人兩者都不熟,那繼續使用 vim 較為合理。重點在於「如何有效率地在自己的環境下解決問題」,而非「一般而言,那一個編輯器比較強?」

再以軟體開發的方法來看,「agile vs. 某個軟體開發方法」也是偽命題,不論 agile 公認的定義為何,重點在於滿足需求,而滿足需求不見得需要一套完備的軟體開發方法;有完備的軟體開發方法不見得能滿足需求。要滿足需求有太多事要做,研讀相關技術、軟體開發、市場行銷等,軟體開發可能是滿足需求的其中一項基石,但不是全部。若滿足需求的前提需要改善軟體需求,自然需要改善它;反之則否。《Joel on Software - 別讓架構太空人嚇到你》對「開發軟體的方法 vs. 滿足需求」提了生動的描述。

舉另一個具體例子,「是否需要重構?」往往帶來許多爭議性的討論,各方人馬(PM、RD、QA、...) 對此有不同看法。若這段程式一直都不需要加新功能,那的確不需要重構。重構只會花費時間讓程式碼變漂亮,對於滿足需求沒有任何影響。反之,之後需要繼續大幅加功能,逐步重構部份功能,則對完成產品(滿足需求)大有幫助。

最近幾年有一個很紅的議題,開發網站是用 Ruby on Rails 好,還是用 ... 好。最近一年可能還會多一些人問是否要改用基於 node.js 的新 framework。要回答這問題得先看需求為何,若只是做幾頁的小網站,用什麼方法差異都不大;若是做長期維護的大網站,要看目前團隊成員熟悉的工具和程式語言為何,再來評估使用 Rails 的相對成本。若再涉及和後端整合,又和既有的 code base 有大幅關聯。而要回答這一切一切衍生的議題,還是得先看:究竟需求為何,基於什麼原因而採用 X 會更好?以 Justin.tv 為例,《Django: Why is Justin.tv porting their codebase to Django from RoR?》說明 Justin.tv 轉換的主因是全部程式都是用 Python 寫的,此外,他們也想藉機重新設計一遍架構,去除 legacy codes,以符合現今的使用需求。

舉這些例子的用意不是無限上綱地說工具和方法都不重要,而是強調將焦點放在如何滿足需求,若有需要選用好工具,才有必要討論它。問錯問題的話,永遠不會得到有用的答案。

2011年9月18日 星期日

Problem Solving 的技巧 (3):因事制宜

不知不覺,這類文章可以寫到第三篇,感到頗意外的。前兩篇是:

昨天看到 TonyQ 在 Soft_Job 寫的文章:《Re: [閒聊] 你在開發程式時,是重視績效還是品質。覺得深有同感,摘錄幾段如下:

對我們來講很多其實可以是 nice to have 的東西, 都會被我們當成 must have。

這個判斷是經驗跟 domain 累積下來的,沒有公式,沒有法則, 做久了你就是會知道什麼架構之後會一直噴 exception ,

而且你還會知道等他出事時你一定沒辦法好好處理, 所以你要在這個當下把它處理掉。

...

觀察他們影響到哪些地方,你有沒有能力測試他們, 還有你的環境允不允許這件事情帶來的不穩定性。

一般來講,如果是我個人自己的專案,我非常不介意大改, 只要我後續還有時間可以處理這些出來的問題。

對公司或者客戶的專案,我會採取相對保守的態度。

這是對風險管理的策略問題。

在 Plurk 上貼了這篇文章後,Thinkerqrtt1 提出另一面看法,強調「早期發現,早期治療」的好處。於是決定借題寫一下自己的看法。

在討論這個議題前,我想先強調,為了方便聚焦討論,我們往往會先偋除一些條件,或是先依自己的假設開始論述。而有爭論的地方,往往卻是這些隱藏的前提。好比說「寫測試碼重不重要?」單單這樣一個命題,只能討論出很模糊的概念,不論支持與否,看起來都有些道理。但加入一些條件後,像是「這是長期開發並有多人參與的專案」或是「後天要交的雛型」,相信大家對此會有不同的答案,也會少一些分歧。相關的想法,可以參考《黑天鵝效應》這篇有摘要讀書心得,其中敘事謬誤和戲局謬誤啟發我這個觀點。

我的想法是,在達到必要需求的前提下,依個人以及團隊的能力,看看能提昇多少品質。問題在於,何謂 must have、何謂 nice to have,每個人的見解不同。爭議點在於,每個人的能力不同,導致評估的實作成本不同。一樣是 nice to have,有些被認同可以做,有些則否。

( ps. 這篇文章不討論規格不明確的問題,這是另一個大議題。 )

舉例來說,A 認為現在重構只能提升一點品質,卻要花兩天;B 認同 A 評估的品質,但 B 覺得只要花半天。所以 A 覺得不划算,而 B 持相反意見。從這樣的評估結果很難說 A 或 B 誰對誰錯,也許 A 沒重構經驗不信任重構,也可能 A 有豐富的經驗,估得比 B 準。

在體認到個人能力不同、習慣不同的前提下,對自己的要求是盡量提高自己的能力,多付出時間提高品質,減少日後維護成本並能練功,形成正向循環對其他人來說,看對方是那種人,是「過」或「不及」,再從另一個角度和對方討論。

舉例來說,若團隊成員不熟或不認同 unit test。當下就要出貨了,這時硬要大家學習並實作測試,並不適合 (不如當「負面教材」,待下次專案的開頭提出討論)。但若成員有過相關經驗,同樣時程下,就能針對核心程式補些測試,花最小成本減少最多風險。當成員嘗到測試甜頭,不小心寫過多測試碼時,和對方討論優先順序,減少寫 C/P 值低的測試碼。

回頭看品質的問題,能力愈強、經驗愈豐富,增加 nice to have 的成本愈低,自然能前期處理,減少技術債。反之,在時程的考量下 (ship or die),能力和經驗不夠時,得選擇先放過一些潛在問題,日後仍有需求時,再花更多成本補救。先活下去,才有更多的本錢來還債。

因事制宜說來簡單,只有四個字而已。實務上卻需經年累月的經驗,不止要考量時程、未來需求變化等項目,也要留意每個人的能力和習性,才能在當下找到較為適當的平衡點。而增加經驗的方法,如同杜書伍在《打造將才基因》裡所言,除了比別人投入更多時間外,沒有其它的捷徑。

2011-09-25 更新

看到 Thinker 提了他的相關看法:《程式碼要清的多乾淨?》,裡面提了不錯的建議:

除了能力不同之外,個人的膽量、積極態度和價值觀也同樣影嚮著評估的差異。 我強調的是,積極態度和個人的能力呈正相關。
...
要評估自己的能力,並適度的承受犯錯的風險。
勇於嘗試、有控制性地犯錯,對於學習很有幫助。我覺得在我學習的前一大段生涯裡,過於謹慎而不敢犯錯,以致於學習速度較為緩慢。而我認識一些晚起步、卻成長相當快的朋友,都具有大膽嘗試、不斷犯錯的特質。他們快速地累積經驗,並培養出更多的膽識和更大的企圖心。

2011年4月2日 星期六

Problem Solving 的技巧 (2):別把解法當作問題定義

《真正的問題是什麼?你想通了嗎?》裡提到一點重要的觀念,別把別人的解法當作問題。最近累積了不少實例,比較能清楚地表達這個想法。

「把解法當作問題」的意思以及它帶來的負面影響

在分配工作時,為了減少溝通成本,常會隱藏一些訊息,只告訴合作同伴他「應該」知道的事,而省略了原始的動機和考量。問題在於,實際執行的人通常比對方清楚細節,很多問題在執行後才會浮現。但分配到工作的人不清楚前因後果,即使查覺不對勁,也無法 (或不願) 做出進一步修正。

好一點的情況,在分工前會先進行討論。然而,討論常會陷入各執一詞的局面,討論雙方作法優缺點後,會發覺找不到共識。實際上這只是眾多解法的兩個提案而已,若深入討論雙方作法背後的動機,各自預先假定的前提,會發覺尋找共識並不困難,畢竟,雙方是在解同一個問題。

在需求一樣,假設一致的情況下,兩個頭腦清楚願意討論的人,沒道理找不到共識,只是我們習慣省略前提,也沒先釐清需求,直接討論解法,才會覺得有個看不見的牆擋在中間,對話難以有交集,我不認同你認同的點,你也不認同我認同的點。

當我開始不預設立場後,看清楚很多事,我第一件事不是評斷大家作法的好壞,而是先問這樣做的考量為何?從考量的點會問出需求,從需求和考量的點會發覺矛盾,從而發現隱藏的假設。接著就能討論假設是否成立,或是不成立又會如何?很可能所有的點會重新洗牌,然後聚焦出更清楚的需求。

按部就班從需求討論各種作法,尋找大家認同的假設,接著在假設下收斂可能的作法,或是列出有影響但還不確定的點,然後評估何時由誰來釐清不確定的點,再來做更細的決定。這樣做下來,通常會有大家都滿意的成果,互動的過程中也會相處愉快。

以開發網站為例

舉例來說,A、B 要合寫一個網站,A 想用 PHP 直接寫,因為他覺得大家都會寫 PHP,寫起來也快;B 想用 Python + Django,因為他覺得日後比較好維護。

A 和 B 的想法都沒錯,但是一討論就陷入死結,這是很吊詭的事,兩個人想法都對,也在做同一件事,為什麼不會有共識?

這表示上述的論點一定有其中一點是錯的,仔細思考會發覺,其實 A 和 B 「沒有在討論同一個問題」,也沒有在同樣的立足點 (假設) 上討論。

  • A 可能假設時程很趕,沒有時間慢慢從頭學 Django,若他不會 Python,還得多學 Python,而且他可能不想學新東西,覺得 PHP 用起來沒什麼問題,為什麼要自找麻煩用別的作法?
  • B 可能假設學習 Python + Django 很簡單,即使時程很趕也還好,或是時程可以再談,沒有人說一定要什麼時候出來,在 B 認為可以來得及做完的前提下,B 認為要認真考量維護的事。

從 A 和 B 隱藏的假設可看出一些衝突:學習新東西花的時間成本、對於時程的認知、是否需要重視維護。而這些假設大概和 A、B 各自過去的經驗有關,比方說 B 收拾過用 PHP 開發的爛攤子,A 沒有和多人共同開發過稍具規模的專案。若 A、B 能和對方說明自己的前提,就有機會順著前提再討論為何有這樣的前提,彼此較能接受對方的看法。

然後再對照目前的需求,會發覺有些前提不再成立,或是更為重要。像是 A 當初收拾的爛攤子是別的因素造成的,可能是時程太趕或開發者習慣不好,主因不是 PHP。

將這些事都攤出來討論後,會發覺幾個立基不牢靠的推論:

  • 為了方便維護,要用 Python + Django。
  • 為了快速開發,要用 PHP。

這是將需求和解法綁在一起討論,但是實際的情況是,方便維護的作法不只有 Python + Django,快速開發的作法也不只有 PHP。視開發人員的經驗,將兩者反過來陳述也可能成立。

所以,真正考量的點應該是:

  • 先確定時程和功能需求,才能判斷開發速度要多快。
  • 確定日後是否需要擴充,擴充的程度和時程,從而判斷維護的成本。

然後列出相關選項,需注意的是,要依現有人員的能力列,而不是「一般」的認知。若時程不是太緊,可以先排時間評估各種方案,像是 Python 不只有 Django 一家 framework,也許可以考慮 Flasky 或 Pyramid;PHP 也不是沒 framework,若願意犠牲多一點執行速度,可以研究 PHP 的 framework;或是另找別的路,用 Ruby on Rails 或用 Java 體系的解法。

要注意的是,過猶不及,當考量的點過於發散時,不確定的點太多,沒有心力一一確認,討論會流於空泛。這時要列好需求,依現有人員的能力做些假設,先達成局部共識再繼續討論,比較容易聚焦。像是因為內部人員最熟 PHP 和 Python,用這兩者風險較低,所以只考慮這兩個體系的解法。

結語

類似的例子很常發生在日常生活的討論裡,不限於技術方面。隱藏的前提不見得都是技術議題,人性是很複雜的。關鍵在於別把別人提的解法當問題,自己也別預設立場著重在說明解法,而沒說明問題需求和自己的假設 (前提)。

在討論過於發散時,要先取得共識排除一些考量。即使共識的原因只是「不為什麼,我們都覺得不重要」,也是不錯的作法。可以先聚焦往後討論,待討論到後面有更明確的想法,或是再和第三個人討論時,可能會查覺原本的前提有問題,這時再回頭修正它們,重新沙盤推演一遍,得到更確實的解法。有了紮實的共識,清楚各項決策的前因後果後,之後遇到各種變動,都能迅速明確地處理。

2010年11月21日 星期日

Problem Solving 的技巧 (1):系統設計是一連串的取捨

費曼和杜書伍可說是影響我思考方式最深的人,即使重覆閱讀、重新思考他們話,仍能獲得不少新體悟。今天偶然發現《真正的問題是什麼?你想通了嗎?》的推薦序是杜書伍寫的,看了以後收獲良多,看了這麼多書,這還是頭一回看了推薦序而覺得有用。

文中提到:

釐清問題的真實性後,面對真正的問題時,須有一個認知:甚少問題能以單一方案解決,而須由不同面向,分頭淡化問題。...這些不同面向的解法,單獨用都只能解決局部問題,但配套提出後,卻能大幅降低問題的嚴重性,到一可接受的範圍內。

企業經營無時不刻面臨問題的發生與解決,在問題決的過程中會發現,現實生活中並沒有可「百分之百」被解決的問題。誠如書中所言:「每一個解決方案都是下一個問題的根源」,一個有利於某面向的方案,代價往往是犠牲另一面向的利益。因此,如何透過溝通、妥協的過程,尋求最適的解法而非完美的解法,將問題的衝擊降到多數人可接受的範圍內,即為好的解決方式,否則反而可能適得其反,滋生新的問題。

看了這段話,更明白杜書伍花了多少歲月與心力實踐他在《打造將才基因》裡說的方法,完全是實實在在的真工夫。用精簡的文字描述出極為深刻的道理,實在是太厲害啦!

舉例來說,使用資料庫時,需同時擔心寫入速度和確保不會損失資料。若每次寫入時都寫入硬碟,可以確保資料正確,但卻會很慢;若先寫入記憶體,集合成一批再一起寫入硬碟,可以大幅提昇速度,但若資料庫伺服器當掉,卻會喪失大批資料。

一個配套解法是每次都寫入硬碟確保資料正確,接著使用 RAID 提昇寫入速度。但是用上 RAID 仍是操作硬碟,提昇有限,於是再加上帶有 write cache 的 RAID,這樣就能大幅提昇速度。但這又造成新的問題:雖然資料庫伺服器掛了不會影響資料,但若機房停電,仍會喪失 RAID cache 內的資料。於是在 RAID 裡加上電池,就能克服這問題 (附帶一提,我很喜歡這句話:「系統設計是一連串的取捨」)。

整個串起來就是「資料庫伺服器每次都寫入硬碟,並使用帶有 write cache + 電池的 RAID 機器」,這樣能同時兼顧寫入速度並確保不會損失資料,不過就變成大幅提昇開銷了。若將支出也列入考量點的話,配套解法可能又不同,也許是降低寫入速度的要求,也許是容許損失多少時間內的資料。

以這麼技術的問題做為例子,其實有損杜書伍提的解題思維、以及《真正的問題是什麼?你想通了嗎?》的價值。真正在解決問題時,需要思考多個面向,而不能只局限在定死的框架裡以技術本位思考。以資工的術語類比的話,用 BFS 的方式思考會比 DFS 容易找出好方案。比方說可以考慮修改規格或換方式滿足需求,或是重新定義問題,找出真正的需求和剛好到位的解法。問題往往來自於期望和感受之間出現落差,有時換個角度看問題,就能剛好繞開原本的技術難題,並且沒有犠牲任何事情。

以我最近在做的事為例,我在找網站壓力測試的工具,雖然能找到一些好用的工具,但它們卻沒提供良好的登入機制,讓我無法開始測試。若硬往技術方向思考,解決問題的選項不外乎再找下一個工具,或是改工具的程式碼,加入一個前置登入的機制。但其實退一步思考,我真正的需求是產生大量連線,以「如同使用者登入」的方式進行壓力測試,我並不需要用正規的方式登入自家網站,大可另寫一個網址,開後門避開繁瑣的登入流程,直接登入測試帳號。於是,我只需要評估壓力測試工具,不用在意它是否有完備的登入機制。

但思考面向變廣後,比起定好其它因素、單純考量技術來說,問題也變得更複雜。要有效地在不同面向間穿梭,需要更多的經驗和練習,就像以往專精學一件事一樣,只是變得更困難。杜書伍在《打造將才基因》裡有不少這方面的說明,強烈推薦閱讀。概念是先專精一個技能,接著專精第二個技能,並找出和先前學習經驗的異同點,融會兩者成為自己的思考系統。接著專精第三個、第四個技能,找異同點,漸漸拼出多元且深入的思考方式。

最近這一年有點開竅,開始會朝多元化思考,先記錄目前的體悟。待有更多經驗後,再來寫心得吧。

2010年9月11日 星期六

每件事都有它的價值

過去我一直在尋找捷徑,希望能找到經驗以外的價值,不然只是比年資,感覺很無趣。老手比新手強,只是因為他做得久、比較熟悉公司內的程式。待新手變強後,也只是因為他經驗變多。似乎人與人之間沒什麼差異性。改善自己學習的方式是個好主意,但有智慧的人都會不斷改善自己學習的方式,以能夠更有效率地學習。我不斷地思考自己的定位,以及如何學得更有效率。期望在天份、經驗外找到其它的聖杯。

Steve Jobs 在對 Stanford 大學的畢業演講裡提到:

Again, you can’t connect the dots looking forward; you can only connect them looking backwards.

抱著半信半疑的心態,我只能先相信這個看法,繼續邊做邊想。

後來在杜書伍的《打造將才基因》裡看到:

我並末想出什麼令人拍案叫絕的答案來,但當時得到的結論卻一直到現在我都認為是正確的,...,經驗要累積得快,除了比別人更努力工作外,似乎找不到其他的方法。

看第一次時仍是半信半疑。然而,最近重讀這本書,對照近來的體悟,忽然間想通了這點。

在經歷 TDD 的洗禮後,我覺得我好像找到一個不錯的答案,至少它是我在軟體開發領域裡找到最好的答案。似乎只要練 TDD,就能在同樣時間內爆增功力。相較於過去看的 Design Pattern、程式語言實作技巧等,TDD 似乎更宏觀實用。

就在實踐 TDD 一年後,偶然看到別人的討論,而有不同想法。練習 TDD 後確實能寫出較好維護的軟體,不過除錯的經驗也變少了。寫了快一年半的程式下來,我一直沒有用 debugger 的需求,只開過兩三次 python debugger,碰一下就放棄它,改成補寫 unit test 偵錯。這才發覺,每段時間都有它的意義,只是練得目標不同。我明白照目前的方式走下去,再過個三年五年,我用 TDD 的功力會愈來愈深,不過用 debugger 功力仍然會是零。這沒好壞之分,端看目標為何,以及自己的定位。

在其它學習的經驗裡,發覺看過的知識,還是要實際操作過數次才能內化到自己的思考體系裡。操作次數愈頻繁,體悟愈深。像許多系統設計或軟體開發流程的最佳實踐 (best practice),還是要走過不同的路,回頭才會明白最佳實踐背後的考量,才知道如何融會這些點到自己的情境裡。很多東西光用看的,或光用做的,無法體會背後的精神,遇到狀況時仍然使不出來。所以,減少嘗試多讀最佳實踐,效果有限;老是硬幹不讀別人的體悟,也是效果有限。

剛才在聊看 Python 源始碼的事Scott Thinker 不約而同建議直接看原始碼,而不用看書 (即使 Scott 認為書本的大綱看來不錯)。但我覺得先看書有個概念再來看原始碼應該比較有「效率」。經 Thinker 說明,才發覺這是練得目標不同。直接硬啃 code 看來較費工,但在費工之中才會有更多練習讀碼的機會,會更熟練相關工具和技巧。而我的目的是增加系統設計經驗為主,讀原始碼為輔,自然會覺得先讀書較好。

每件事都有它的價值,每個技術都需要時間才能挖深。然而,要將走過的路合起來發揮最大功效,要將所學收斂在相關領域裡。這讓我不經花更多時間思考,往後自己的定位為何,我想發展什麼樣的知識網。總之,相信 Steve Jobs 和杜書伍的話,「Stay hungry. Stay foolish.」繼續邊做邊想吧。

2010年7月18日 星期日

學習的自我要求

學生時代我一直在想一個問題,究竟是問題導向的學習方式較佳,還是技術導向較佳?舉例來說,我想寫個留言版,我發現要完成最基本的需求,我得學 HTML、PHP 和 MySQL,於是我針對我要做的功能學相關的語法,最後完成留言版。可能資料庫設計沒用到正規化,網站外觀沒用到 CSS,一些動態功能用 PHP 實現而非 JavaScript。相較於從頭學寫網站所需的各項技術,這個作法比較務實,我用較少的時間完成目標。極端地看,用問題導向的解法時,我可能找到相關的程式碼,用它們拼貼出結果,但不確定各塊在做什麼。技術導向的解法,可能要先花一段時間弄清楚寫網站需要的技術,再各別學個基本能力,接著開始實作。當然,世界上不是只有 0 和 1,我們常混著用問題導向和技術導向的方式解問題。這裡我說用問題導向的意思,是指偏向用問題導向。

不只做產品,做研究時也是類似的情況。問題導向就是從問題開始往下挖,看前人做那些方法,將自己不熟的部份補起來,有了必要的知識後,就能回頭解決問題。而技術導向的做法,我可能會加強基礎學科知識,視類別而定可能是機率和線代,或是計算機組織和編譯器,接著才開始思考如何解問題(或重新定義問題)。

以前我沒什麼時間觀念,通常是技術導向的作法,覺得有趣就看我能從多底層開始往上學。比方說使用 Java Collections Framework 時,我會弄清楚我要用的資料結構怎麼運作的的,時間複雜度是多少。實際上大部份的使用情境不需要這些知識,稍微讀一下文件的注意事項即可。要用 machine learning 的工具,就找適合的 machine learning 課程講義來讀,弄清楚要用到的 model 怎麼運作。直到現在,我無法確認這些對於使用工具究竟幫了多少忙,當初花的時間對應到目前的幫助,真的划算嗎?

最近我試著用問題導向的方式解問題,初期進展確實比較快,不過後來遇到一些狀況,才發覺技術導向的好處。有些情況,我們根本不明白問題出在那裡,有太多可能。舉例來說,前幾天我和同事發覺不同使用者登入同一頁面,操作速度卻差了一大截。有許多可能原因:網路連線 、網頁框架、資料庫等。做了一些初步測試,我懷疑是 MySQL 根據歷史記錄做錯 query optimization。於是用 EXPLAIN  看相同的 SQL 配合不同使用者 ID,結果發現 MySQL 執行 query 的方式有細微差異,造成取出某些使用者的資料時,用較慢方式執行 SQL。於是讓 MySQL 重分析表內的資料後,問題就解決了。若不是之前稍微看過 MySQL 執行 query 的相關知識,不會這麼快就直指問題核心。也許就會用別的方式繞開這問題,一輩子都不知道怎麼解它。待發生類似問題時,又用別的方式繞開它,長遠來看浪費開發時間又增加維護成本。

另一個反面的例子是,我一直沒用 lock 的習慣,教科書告訴我們 deadlock 很可怕,所以我會想辦法避開用 lock。結果最近有個小專案因為沒用 lock,真的發生 race condition 造成有一點點資料不正確。實作前我明白會有這樣的狀況,但這個問題對我們的目的沒什麼影響,衡量開發時間後我決定寫下註解強調會有 race condition,而選擇不處理它。對照最近的體悟,我明白這樣下去我不可能學會用 lock,這不是個好現象,所以又找時間回頭看 MySQL 怎麼 lock table,結果比想像中來得簡單,之前多慮了。

有很多類似這種的逃避例子,像多人一起寫程式容易有問題,於是大家傾向將功能切乾淨,每人寫沒有交集的功能,最後再來整合。但是,對照近年來的軟體開發的趨勢,愈早整合愈容易解決問題。一個人開發容易有盲點,互相協助可以降低初期錯誤,以利後期整合。問題是,要能順利地多人共同開發,得做對不少事才行。像是版本管理系統、coding style、天天合併程式等。每一項都需要時間練習。若一個人開發時有好好練習,和別人合作時會減少許多問題,比較容易推動密集的團隊合作。

在面試別人時,我發覺一個問題:有些人學到的技能剛好只能應付他負責的專案。問題在於,若平時我們都處理簡單的專案,要怎麼轉去負責困難的專案?兩者之間有個斷層。像這類的例子不勝杖舉。比方說要從資料庫表 A 取出部份資料塞入表 B,最「簡單」的作法是寫個程式用 SQL 取出資料,用程式做些處理再用 SQL 一筆筆寫入表 B。另一個作法是直接用一個較複雜的 SQL 直接搞定。當資料量大時,後者執行速度會快上不少。並且,學會後者的寫法後,之後只要花一點時間就能處理類似的情況,不用再寫一個小程式。其它像寫程式的習慣、用程式工具的習慣,都是一樣的。多數情況我們可以用最「不費力」的作法滿足需求,但長遠來看卻是毫無長進。實際上有更有效率的作法,這裡的效率包含開發時間和軟體品質。

對照大學的程式來看,這一年來我以為自己程式已寫得頗有品質了,雖然知道一些小問題,但覺得並不迫切,也不知怎麼查相關的解法,就放著它們。最近翻了一下 Effective Java 第二版Growing Object-Oriented Software Guided by Tests,才發覺還有太多的東西要學,自己和資深的軟體工程師差了一大截,照我目前的學習方式,和他們的差距只會拉大不會縮短。若只專注完成眼前的工作,我永遠無法補足和更難工作之間的差距,這才驚覺問題導向的盲點。

走過天平的兩端後,我現在的體悟是,得雙向夾擊來解決問題。一方面用問題導向解問題以符合時程,確保時間有花在刀口上。另一方面再抽時間用技術導向的方式強化自己的實力。如此一來,在完成當下的專案的同時,也有一點一滴地補足技術斷層,取得挑戰更難專案的機會。題外話,英文也是很重要的「技術」,這一年來我半強迫地讓自己盡量搜英文文件,思考關鍵字比以前敏銳不少,閱讀速度也變快,獲得答案的速度比以前快、品質也較佳。

2010年4月24日 星期六

百人百觀 (3)

原本我以為大部份問題有「標準答案」,而不斷地尋找每個問題的「標準解」。兩個人見解不同,必然有人有誤,也可能都不對。在《百人百觀》裡,我才明白不是這麼一回事:

最後我發覺沒什麼最正確、最有道理的事,百人百觀,於是我不會硬把自己的想法套到別人身上,當別人和我抱怨誰的想法不合理,大家都如何,他偏偏不合群,即使我贊同大部份人的看法,卻不會像以前一樣,認為那個特立獨行的人有問題,想說服他。

《百人百觀 (2)》裡,我才明白不該強加自己的觀念在別人身上,即使我認為自己沒錯,也要尊重別人的見解:

於是我不在意我是否能影響聽者的觀點,有的話,當然很高興;沒有的話,對方可能需要不同的契機來改變,那個契機不是我。也可能這個想法適用於我,不適用於對方。另一方面,我仍然熱於與人討論,百人百觀不意味交流沒有意義,只是不用過於執著自己的想法。

但是直到最近,我才明白自己的想法常常有誤,要能接受不同的看法,從中學習。這個轉變花了我不少時間。先是看了費曼的言論而開始懷疑一切、懷疑自己。我很喜歡他在《這個不科學的年代! 》第一篇裡說的話:

有些人說:「你怎麼能夠活著而無知?」我不知道他們是什麼意思。我從來都活著,也從來都很無知。那容易得很。我想知道的是你如何能什麼都知道。

後來又看了 TED Talk 《Weird, or just different?》,裡面有段話很棒:

Whatever brilliant ideas you have or hear, the opposite may also be true.

我原本對此半信半疑,經過幾次實例驗證,發覺我堅信「絕對沒錯」的作法,仍有一些情境不適用。若能從自己習慣的作法中找出反面的價值,或許會大有幫助。一但認定「肯定如此」後,就失去改進的機會了。

至於前兩篇文章對於溝通的焦慮,現在的心得是,要能開放心胸,站在對方的角度思考。嘗試幾次後,會發覺以前沒想到的事。再來就是去除情緒,就事論事。說來容易做來難,還在持續練習中。附帶一提,站在對方的角度思考並不容易,不只是情緒上的問題,有時沒類似的經驗,無法明白對方看重的點。

2008年5月6日 星期二

學習的方式不斷地在改變

記得小學時得到圖書館找資料,順便看看劉欽興漫畫。高中時開始學著用網路找資料,但仍維持國中時自己手寫筆記整理的習慣。大學後會交錯使用電子書、實體書、網路找資料,上過的課,會把投影片整理好,待要查時再拿出來用,有了投影片,似乎已可很快地溫故知新,再適當地用 BBS 整理零亂資料,一切似乎很順暢。

研究所開始,漸漸發現看 WikiPedia 的比例愈來愈高,有時乾脆直接上 WikiPedia 找,結果剛才要找 fragmentation 的定義,回頭看 OS投影片,看不到什麼有用的知訊,WikiPedia 一查,完整又詳細的說明馬上出來,文字組織明確,定義和例子兼具,實在想不到比這更方便的查法了。

小學時當興趣閱讀的兒童大百科,曾幾何時,已變為占空間難以使用,又容易過時的存在呢?

隨著獲取的資訊愈來愈雜,深度廣度都在急遽變化,開始架 Wiki 整理零散的知識,偶而用 Blog 較有系統地寫下心得,開始覺得,永遠不會有完美的方法。資訊不斷成長,學習的方式也跟著在改變,不只要學新東西,也要適時學習新的學習方式,拘泥於過去學習方式的人,相對來說是愈學愈慢,終會跟不上前進的腳步。對於這樣的變化,我感到的不是恐懼,而是有趣!

五年前有誰想得到,WikiPedia 或 QA 系統 (e.g. Yahoo!知識家),有可能如此發達?社群書籤 (Social Bookmarking) 也帶來新的使用方式,在許多層面上來看,它們是搜尋引擎無法取代的。找資料和管理資料的方式將會漸漸地多元化,只懂得 google 終會跟不上時代的。若對此有所疑問,不妨用同樣的關鍵字到 GoogleWikipediaYahoo! Answersdel.icio.us搜尋,看看出來的結果,略加分析,就會發現這四者有很大不同的特色,視要找的資料而定,各自有擅長的領域。

也許未來仍會有更快的找資料方法,比方說根本不用找,資料全都被記錄下來,看過的東西永遠不會忘,只要索引一下立即取回。以現今硬碟空間的成長速度和個人化工具發展來看,這樣的遠景似乎不用五年就有可能達成吧。

2008年1月22日 星期二

能者多勞?

以前曾寫過類似的心得,當時看了「別給優秀人才過多的工作」這句話,深有同感,過去一年剛好有不少管理的經驗,配合自己和別人的情況來看,卻發現這個觀念難以實現。

可能任何地方都有一樣的問題,緊急重要的事不得不交給信任的人,而且這類事永遠不會少,於是有能力的人手邊工作只會愈做愈多,主管在必須達成上級要求的前提下,很難做到工作量平衡,大家都忙著為眼前的情況解套,自顧不暇,那來的時間培育人才?

唯一的解套方式就是讓組內有一群優秀人才,自然不會發生能者多勞的慘狀。於是,人才多的組織愈來愈強;人才少的組織,人才沒時間充實自己,失去前瞻競爭力,漸漸被操到不是人才。像是「多做多學」、「態度決定高度」之類的話,在這種場合只是不得已的精神慰藉罷了。

2007年12月25日 星期二

先破後立

前幾天konya問我,這一個月半來想法轉變的原因,說實在的,這還挺難回答的。

我一直很喜歡這段話:

看山是山,看水是水;
看山不是山,看水不是水;
看山還是山,看水還是水。

我走過的路,常常如此,在記下過去的想法後,這個軌跡更是明顯。我愈來愈明白,為什麼成功人士都說些像屁話般的大道理,像是「態度決定高度」、「你的心胸有多大,舞台就有多大」,可惜我無法清楚地描述出這個轉變,硬要說明,也只是用更長的篇幅說屁話。但和我聊天的人,我可以依他們所處的位置,給相對應的回答。如果對方看到的還是山,我必須說明其實那不是山;而當對方明白那不是山時,我卻要更直接地點出,其實那是山。

舉個例子,《通往成功的方法》裡提到,當不知如何是好時,選困難的路。當對方接受這個想法,並落實時,必須改告訴對方,如果你努力錯了方向,再怎麼跑也到不了終點。用商管的角度思考會更直覺,我們要為客戶創造價值,產品做得再好、價格再便宜,客戶不想用,還是白費力氣。比方說現在大家普遍使用19″ LCD電腦螢幕,若製程有所突破,38″ LCD電腦螢幕的價格和19″的差不多,38″的會大賣嗎?其實不見得,考量到使用電腦的習慣和一般住家的大小,38″ LCD適合當電視,卻不適合當電腦螢幕。那麼38″ LCD沒有價值嗎?也不見得,要看針對什麼樣的客戶(市場區隔),年輕人只用一台電腦沒有家用DVD播放器或電視,平時工作用NB,多一個38″ LCD,可以做為娛樂用。

重點是,要先確立客戶需求,再行研發;先確立自己的目標,再開始努力。那麼,為何一開始要說選困難的路?因為那總比不努力來得好。我也很喜歡這句話:

沒有前提,沒有答案。

在「看山」的議題上,有類似的意境在。要破還是要立,端看我們處在什麼位置。

附帶一提,當我們回頭看山是山時,內心的想法已有所不同,這個想法轉變,將帶動其它方面的提昇,比方眼界更廣,立足點更高,連帶反映在日後的行動上。我愈來愈常聽到人生歷程的前輩和我說最重要的還是「人」,或是最重要的能力是「態度」,不管在什麼情境,在什麼考量下又聽到這老掉牙的詞時,我漸漸明白他們的意思。

在不斷地自我提昇後,我們無法簡單地和他人解釋這一串成功背後的原因,因為在每一階段,內在和外在都在轉變,沒有一個方法能含蓋這個過程。當我們在 A 情況時,我們該這麼想,進入 B 情況後,應該改成這麼想,...。面對一個素昧平生的人,想分享這一系列的想法,太費時也無助益,於是只能用最後的體悟來回答對方,而形成另一個屁話。

2007年12月19日 星期三

自信和積極

剛才看到李開復寫的文章:《給中國學生的信:做個積極主動的你》,有些啟示。

先談「自信」,高中時我寫下這樣的疑問:

人為什麼會有自信心呢? 是出於本能嗎?
還是別人給他的? 是因為有了別人的表示,
所以才會有自信心? 還是因為天生如此?
為什麼有些人會覺得自己一無是處, 很失敗,
沒優點? 是真得嗎? 還是因為他缺乏自信心?
又有自信心是來自於有能力嗎? 一個平凡過日子的人
也可以擁有自信心啊

我覺得自信心或許也可以由”看到別人沒有自信”
而導至自己產生了微妙的自信, 看到別人的失敗,
覺得自己成功. 也或許是因為自己有份優於別人的能力.
是種比較後得到的感覺

當時正在轉型的階段,經過後來六年多的嘗試,我漸漸建立出自信,有些誤打誤撞。記得李開復寫過一些文章,提及自信是需要培養的,藉由自己的經驗,我印證了這點,並了解往後自己仍有培養不同方向自信的可能性。這裡必須補充的是,當時的體悟不夠完善,真正的自信應該來自於本身,從比較而來的自信,終究會由比較而失去。唯有達到超越自己,才能自強不息啊!對此觀點有興趣的人不妨看看電影《霍元甲》。

不只自信如此,認識會長、skylight這類人,給我最大的啟發在於積極的程度。常會發現「原來也可以這麼做哦?」,接著反問自己:「我為什麼不這麼做?」,而在和家人或朋友聊天時,在他們身上看到我過去的疑惑,從而明白我的確有在前進。對於那些未能踏出的朋友,也只能簡單地分享觀念,待他們自己踏出來。

這裡引用李開復該篇文章裡的一些反面例子,深有同感:

他們總是抱怨:「我沒時間。」——這表明:又是外力控制了我,讓我沒有選擇的機會。
他們還喜歡說:「我不得不如此。」——這其實意味著:迫於環境或他人的壓力,我只好選擇服從。
他們在自我表白的時候說:「我就是這樣的人。」——這其實是在宣稱:我已經無法改進或提高自己了。

對於沒時間的觀點,李開復給了一段說明:

遇到困難時,不要找藉口,應該多想一想,有沒有別的解決方案?能不能將問題分解開來,一步一步地加以解決?或者,是否需要先提高自己在某方面的能力,然後再回頭來處理這個難題?不要因為逃避而說自己沒有選擇或沒有時間——沒有人缺少時間,只不過,每個人分配時間的方式有所不同而已。

漸漸地,我發現自己在挑合作伙伴時,不像以前那樣極力看重個人能力,而轉為看重態度,或著更明確的說,是積極的程度。

然而,在沒有明確目標時,人很難有熱血地衝衝衝,像我自己,時常覺得我憧憬的生活,是悠閒自在,到不用成就一番大事業,只是偶而又不甘於平凡,想做點什麼。李開復是這麼回答的:

美國人很喜歡嘗試不同的工作,他們一生中平均要換四次工作。在長期計劃經濟的思想影響 下,更多的中國人不願意換工作,而更傾向于終生做一件事。其實,換工作崗位的意義在於,你一開始作的決定並不一定是你的終生決定,你仍然有機會去嘗試更多 的東西,只有這樣才能真正找到自己的興趣所在,才能最大限度地發揮自己的潛力。

所以,不要因為暫時不瞭解自己的長處而猶疑不決。大家要珍惜每一次嘗試,因為機遇往往不可複製。要隨時作好準備,以免機遇到來時錯失良機,同時也應學會從每一個失去的機遇中吸取教訓。此外,只有敢於挑戰自我,你才能充分地開發自身的潛力。

這和Paul Graham的格言一樣,有兩條路可選時,走難的那條。當選擇差不多時,有時這意外地受用。

ps

李開復果然是大道理天王啊!之前略讀「最做好的自己」時,就覺得那是本佳言錄大全,偶而讀很有感受,但讀太多時會感到很空虛。學而不思則罔,思而不學則殆。

2007年12月15日 星期六

讀iWoz初感:耐心

最近和一些朋友聊天時,加上自己做研究的體悟,耐性真的很重要,比快速的反應力還重要。從網路上大師的文章讀到,從學長那聽到,自己體會到,還有發現學弟又遇到一樣的問題。看到Woz提到「一次跨一步」的重要,再次從不同背景的人身上獲得印證。

p75,培養一次跨一步的耐性:

多虧了這些科學計畫,我得到了在工作上終生受益的核心能力:耐心。我是說真的。大家往往低估了耐心的重要。我是,說從小學三年級到初中二年級,我所進行的科展計畫讓我逐漸學到多事情,學會如何把電子元件組合起來,而不是只懂得翻書。多時候我想,天啊,我真是太幸運了,看來我似乎從一開始就幸運走對方向,從小就學會一次跨一小步的做事方法。我學會不要太擔心結果,而是專注在做事的過程上,並且要盡可能把事情做到最完美。

今天在工程界做事的人並非每個人都有同樣的領悟。我在蘋果電腦和其他公司工作的時候,看到很多怪才想一步登天,卻不肯先一步步完成中間的步驟,出來的結果當然不對,絕不可能行得通,那只是一種認知層次上的發展結果,如此而已。如果沒有經過實做,你無法單單在認知的層次教會別人下兩步該怎麼走。

話說回來,也如同Woz在書裡提到的,不要隨便相信任何事,科學家的精神就是要自己動手實驗。不少大道理大家都聽過,實際走一遭後才會確實了解,而不是單單知道而已。令人為難的是,當自己走到一個程度後,難以和別人分享自己的經驗,以減少別人的冤枉路。我們只能剛巧碰到差自己一步的人,向他們請教,或協助他們,讓自己跨向他們的所在,或讓他們跨向自己的所在。所以我喜歡像這樣一路記下自己的心得,減少自己忘記成長歷程的遺憾。

2007年5月21日 星期一

包裝是門學問

當我還是技術狂時,覺得嘴炮是次要工作,東西好別人自然會用,所以把基本能力學札實點才對。然而報告也是門學問,不如我原本想像那麼簡單,這年頭選擇太多,如何快速吸引觀眾注意力,讓他們了解自己的東西為何,好在那裡,變得相當困難。所以做報告,做簡報檔,上台報告都變成值得深入學習的能力,看來很淺顯的道理,但還是很多人不願意做,或是認為那是膚淺的事,仍然認為重要的是技術吧。

但剖析社會結構就會發現,即使現今結構看似「扭曲」,做品牌,做包裝的部份獲得最高比率收入,上台報告的人看似做最輕鬆的事,卻最風光,收入也高。以前我覺得這是歪道,只想弄好技術,但現在漸漸覺得走上這歪道比較適合我 XD 。或著說,一半技術,一半包裝才是最適合我的工作,真要說包裝能力,見識過商管人才的作品,我了解自己再怎麼學,也只是個半調子。

技術人才會覺得過度包裝的報告很浮誇,不足取信又找不到重點;擅於行銷的人會覺得技術人才的報告令人想睡,什麼也聽不進去。我應該頗適合當中間份子,我本來就一直走中間路線啊。

2007年4月1日 星期日

學習決策模式

人生充滿許多決策,不僅是商業上要做決策,個人行為隨時也得做決策,學習決策模式有其必要性。

一個多月前和台大國貿系的朋友去逛國際書展,他推薦看《決策聖經》,號稱商學院必看的經典書,全書收錄14篇論文。從浩然借回來後,我耐著性子看完第一篇,完全不懂。接著我想到我不該試著思考商學院的學生怎麼思考,以我的條件來說,應該要用理工人的角度思考商學,這樣才有我的思考價值,不然只是從頭花大量的時間培養出商學院學生的能力,我不是專讀商學的,再怎麼花時間也達不到他們的水準。

抱著這樣的心態又讀了第二、三篇,還是看不懂,於是我把書還回圖書館。打電話問我朋友,這本書是什麼回事啊,對方回答:「你不覺得條列分明,分析得很清楚嗎?好吧,其實我讀起來也滿吃力的。」我只能說,從理工人的標準來看,我不能接受這算條列分明,雖然有分項,但難以理解。似乎每次讀到理科外的科學都有這種感覺,一來也是非理科的本質較為複雜,資訊混亂不清。

剛才看到這篇《有效的決策》,容易懂多了,大師不愧為大師,可以用很實務的方式描述理論。不過我想等遇到實例時,再回頭依這篇說的方式走一遍,成效會比現在細讀更多。

摘要心得:

  • 區分一般性和特殊性:用三維座標容易理解,X軸為人、Y軸為問題出現次數、Z軸為時間,XY平面上的水平線和垂直線都表示一般化;孤立的點為特殊化,但要區分是否在時間軸上仍是孤立點(預測未來)。一般性問題要參考舊例,特殊性問題要拋棄包袱。
  • 定義問題。
  • 定出邊界條件,決定正確決策的範圍,不要先以可接受的角度選擇,這樣失去界定邊界的意義。
  • 沒有行動的決策只是構想,要考慮具體實現方式:人、時、事、地等。
  • 循序漸進改善決策(iterative evolution)。
  • 要踏入第一線了解實況,和現實脫節做不出有效的決策。

ps

備忘原文出處,萬一link失效了還可以去出處找。

《有效的決策》:作者:彼得 杜拉克,原刊载于《Harvard Business Review》1967 年 1-2月。

加深還是加廣

過去我一直覺得只有半調子的思考沒有意義,全世界的人都在看、在想,若自己沒有深入思考到一個程度,不如別思考。但近來能思考的事太多了,類型不同、層面不同,趕不上資料浮現的速度,常造成思緒混亂,開始想著是否要換個方式思考,拼量而非拼質,看看會有什麼變化。

但改變自己思考習慣的代價,是會遺忘自己原本的優勢,所以在這記下目前的觀點,那天轉不回來時,至少還有個「還原點」可以補救 XD 。另外,隨著分類「Life」的快速成長,看來這個Blog還是需要分類「Thinking」,以區分「Life」、「Thinking」和「Life + Thinking」。

2006年11月16日 星期四

思考和語言的本質 - 2

沒想到這類想法還會有續集,第一篇是”思考和語言的本質”

我認為人只能從自己的方向理解萬物,只能理解本來就理解的事,沒有人能傳授知識給自己,唯一能做的是,透過對方的描述,用自己的方式分析,再擴充至已知的分類裡。這段話用極端的方式描述,是想強調”理解”的含意,做些平衡的修飾會使我的想法失真更多,字面上不代表我的全意。

知道和理解的含意不同,退一步來說,知道只是記下文字,沒有理解沒有意義。

數學、英文、中文都是語言,特性是愈習慣用得愈熟練,思考也能更快,視情況用不同的語言才能最佳地表達出來。另有圖像式的思考,圖像式思考比任何一種語言都快,或許和人類視覺特性發達(相較於電腦極弱來說)有關,雖然無法證明,這應該是普遍默認的特性吧。

談話的過程就像腦內有個knowledge base,將裡面的元素組合對應到interface text,對方接受到interface text後再想辦法對應到腦內的knowledge base,口說談話來往很快,能及時修正方才的誤解,讀書卻是不同的情況。XXC知識的誤讀與發展提到誤讀造就創新發展,同樣的,孔子說:「溫故而知新,可以為師矣。」,這些是相似的概念,同樣一份文字,一份經作者千錘百鍊的結晶,在不同時空下解讀出多樣化的結果,如同小說要預留想像空間給讀者,冰山一角,學問亦是如此。

選擇性認知常造成誤讀,比方我認為思考就是無法傳遞,我看什麼文章都在找相關的概念,再放大片段來佐證我的想法(台灣媒體是這方面的高手)。但這些偏執放大的成果,有時卻形成創意。”沒有前提,沒有答案”則是反向運用,傳達知識者不先確認對方的情況,無法傳達出有用的知識。

思考無法傳遞,但可以經由自己的思考猜測別人的想法,個人經驗裡,猜對方想說什麼,不管是討論還是讀書都比嘗試理解對方所言快甚多。sltsao老師”研究生的學習與訓練”提到想比讀重要,以及Blake”懷疑與類比”提到:

「大概是已經對某個領域比較了解,而且相信那個就是世界運作的法則。所以到不同領域的時候,只是做一個mapping。」

”你始終得先了解一個道理,才有辦法和其他的道理相通。”

從我的”誤讀”來看,背後的道理和我說的一致,先有自己的系統,再將其他人的想法透過自己的系統吸收,觸類旁通則是進一步的推衍。

將談話的內容拆解成定理、描述、舉例三者來看,不管是一般性談話還是讀paper,都可看成這三者的構成,只是paper區分的更為明顯。這裡將定理的標準放鬆,泛指規則,一般性原則,能從中衍生出全貌。我們都偏好舉例說明,透過例子,自己建立規則比看懂定理快,先建起自己的規則,再和定理比對修正,比直接看定理並思考各種可能容易接受它。定理、描述、舉例用三種不同層面說明同一件事的含意,是讓接收者能從其一二推出自己的認知,再用剩下的做驗證,確定自己的認知和對方無誤。

就像學習文法(在數學來說是公設和推衍規則),文法是從大量例子(日常對話)歸納出的,外國人問我們這樣的中文通嗎?我們會用習慣來判斷,而不懂什麼是中文文法,這個”習慣”就是自己的認知系統(前文的knowledge base的子集合),剛好在中文環境的人都有極高相似度的認知,即使沒有公設也不成問題。我們的中文系統是從大量的語言例子裡無意識地分析形成的,從這來看,Neural networkEvolutionary computation就很有道理了,人類自己都是用大量的輸入訓練出思考系統,沒人知道裡面的規則,處理複雜的事,或許就要用類似的做法吧。

我只能說,我又做了次”看山是山,看山不是山,看山是山”的事,我總要經過個轉折再回頭,才能醒悟這些看似廢話的結論有多偉大,差別在於,思考的過程多擴充了些有的沒的。

2005年12月11日 星期日

思考和語言的本質

 作者   fcamel (飛啊!演化的小駱駝)  看板    P_fcamel
 標題   [thought]   思考和語言的本質
 時間   Sun Dec 11 18:24:14 2005
 
抽象是無法傳達的, 必須以事實, 例子或是經驗來傳達

抽象的重要性在於, 抽象能描述一統的概念, 而不用窮舉所有可能;
實例的重要性在於, 它能幫助了解背後的抽象概念

什麼是語言? 什麼是想法?

先有了想法, 我們接觸到事物, 於是給予這之間一個對應的媒介,
這個媒介可能是語言, 文字, 圖像(以下以符號統稱)

比方說, 我們稱"X"為拖鞋, 於是大家看到"X"都知道它叫拖鞋,
接著大家就能交替用拖鞋代替"X"

"X"可能是一串描述, 或一件事, 一個物品,
但一定是先有認知才有代表的符號

ex1: Eskimo的語言裡有許多冰的相關詞彙, 這是因為他們在這方面需求很大,
     如果將這些詞彙換成中文, 我們看了也無法體會細節的差異

ex2: "青春", "失戀"這類詞, 大家都懂大概的意思, 但沒有經歷過是無法明白的,
     而經歷過的人, 感受也各自不同, 這些詞只是反映出一種模糊的概念,
     端看接受者如何看待它, 所以, 青春是苦澀的, 青春是酸甜的, ...

想法必須透過媒介轉換才能交流, 好比著作,

    作者的想法 --(文字)--> 書
    讀者       --(文字)--> 讀者本身的想法(解讀)

作者的想法是否能傳達給讀者, 端看讀者和作者對文字的解讀是否相似[*1],
所以作者必須以一般人能理解的方式傳達出來

反向驗證, 如果不懂文字, 能否思考?
以下棋為例, 只要有圖像理解能力, 就有能力理解規則, 有辦法下棋

感覺上圖像思考比較直接, 但有些"X"無法以圖像表示,

ex: "8:00起床", "待會要上課"

語言(說話)和文字是同樣的概念, 只是文字比語言又多轉換了一層, 也失去更多資訊,
而我們極為熟悉這之中的轉換, 有時不會特意去分別它們

用學英文的的觀點來看

    [ 英文 ] <--(翻譯)--> [ 中文 ]
        \                    /
         \                  /
          \                /
             [   想法   ]

只有當我們能用英文解讀英文的生字時, 才稱得上理解英文,
閱讀英文先翻譯成中文再思考, 已是二次轉化的產品了, 速度慢又失真

英文和中文之間的翻譯, 是大部份人對於兩邊詞彙的認知,
用來幫助我們了解不熟悉的部份, 但符號畢竟是符號, 重點在想法本身,
"X"是用在什麼時候, 大概代表什麼含意, 比"X"對應到中文裡是什麼來得重要

ex: 即使明白"therefore", "because", "so"這類詞的中文意思,
    不見得明白什麼情況會用到什麼詞
    ( 英文不好, 麻煩英文好的人幫忙提供更有力的例子 )

雖然思考是透過媒介來交流, 但媒介也左右了思考

什麼是記憶? 記憶是想法透過符號(媒介)暫存的結果

為了幫助建構更深更廣的思考,
我們必須有符號輔助記憶, 才能將一個階段的結果儲存起來,
以簡單的方式表示它, 再組合眾多結果得到更深的結果

ex1: y = x 是條線, y= 3x - 5 也是條線, "線"的概念包含了無窮個"點"
     要討論兩線的共同點時, 我得用線的概念來找到這個點

ex2: 快樂是"正面"的感覺, 在描述快樂時我用了"正面"的概念,
     人生要活得快樂才有意思, 描述人生時我用了"快樂"而帶有"正面"的意思

必須透過媒介才能自我思考的結果, 是思考被媒介給限制住了,
要如何在現有符號的框架裡, 挖出更深層的想法?
到這步時我的思想斷掉了, 我找不出編織想法的方法,
想法像散掉的線, 聚不出方向

用例子來看可能可以傳達我的意思,
如果用的材料都是石頭, 再怎麼處理也不可能點石成金


PS

*1 靈感來自於前幾天寫的程式, 相關文章可以往前翻
   http://www.csie.nctu.edu.tw/~chlo/web/codes/sbc/sbc.html