over 1 year ago

書摘

把生命當成目的本身,而不是達成目的的手段。當你為了追求財富、名氣或權勢的時候,你的生命就變成了為了這個目的的手段,


侯文詠在大二時,因為喜歡看電影,功課就應付過去,結果竟然導致醫學院好幾科成績在及格邊緣擺蕩。當時他面臨一個抉擇,到底要不要繼續看電影?如果繼續看下去,又不顧好課業,那麼萬一被當掉,接下來幾年就會非常辛苦。但是如果不看電影,回首看看自己的人生,那就只剩下上課、考試、吃飯、睡覺一樣乏善可陳。

後來,侯文詠決定瘋狂地看電影,但是同時努力把握時間兼顧課業,讓作息穩定、按時讀書,為的是能看更多的電影。當時他根本沒想過,有一天會變成一個作家,更不知道這樣的興趣會帶來怎樣的前途。後來那一年,侯文詠看了超過三百部電影。

停止看電影或繼續看電影,當年那個看似無關緊要的選擇,在很久之後重新回顧的時候,他所代表的,其實是兩條截然不同的遭遇或命運。但是在當下,你不可能知道。對許多人來說,因為看不到,所以會恐懼、會猶豫、會懷疑、會害怕,所以關於前途、能不能賺錢,這些聲音會變得巨大,因為這樣,你會越來越不容易聽到自己內心的召喚。


JK羅琳在2008年哈佛的畢業典禮致詞曾說過,父母希望他讀個實用的學位,結果後來她自己把主修科目改成古典文學。在這個星球上的所有科目裡,大概很難找到一個比希臘神話更沒有用的科目了。


就算聽從你內心的聲音,呼應內在的召喚,也不保證你一定就能功成名就。請把追尋自己的興趣當成像是跑馬拉松的過程,想像他是一個需要5年, 10年, 甚至更久才能達成的事情。你當然需要全力以赴,但是不要過於在意外成敗,請讓自己歡喜的去做,重點是要保持最初內心的渴望。

 
over 1 year ago

最近在思考,如果創業該挑自己擅長的領域。那麼我該如何決定自己該深入鑽研哪個領域?

這個問題可以用很功利的方法來思考,你可能會想,哪些領域比較有潛力,比較被社會大眾看好,哪些領域比較有可能會賺大錢,於是就決定投注心力去學習。

這樣的心態聽起來很像媽媽幫小孩填志願,聽說未來電機系比較好找工作,於是就幫小孩填電機系。聽說當牙醫比當醫生輕鬆,就幫小孩把牙醫系填的比醫學系前面。

我以前常常會陷入一種思考模式,我把他取名為賈伯斯症症候群。我高中時正是賈伯斯璀璨的最後時光,那時iphone 3G剛出,App還是一片藍海,寫個假裝喝啤酒的App都會有人付錢買。賈伯斯的現實扭曲力場感染了全世界,一項項蘋果產品像是宗教的佈道大會一一發表。賈伯斯在史丹佛大學的畢業演講中,告訴大家,只要你追尋他內心的直覺,相信所有點最後都會連在一起,最後就改變了世界。

這在我心中種下一顆種子,任何有志之士都應該像賈伯斯一樣追尋內心的直覺,以改變世界為己任。

之後很長一段時間,我在挑選題目或研究的領域的時候,都會用這東西能不能改變世界,當成衡量一個專案值不值得做相當重要的指標。如果有的題目聽起來很普通,不酷,聽起來對世界沒什麼影響,那麼就不要做。如果自己能力還不足以改變世界,那就會轉而追求改變自己的生活圈附近的人,可能是你的師長、你的朋友、你的家人、你朋友的狗。

簡單說,這個症候群會讓你盡可能的讓你做的事情很酷,某種意義上來說這是好事,因為他讓你放棄掉很多不值得做的事情,並起避免你把事情做得平庸。但是後來我漸漸發現,這樣的心態是anti-pattern,乍聽之下好像有道理,但是實際上目標這樣設會導致你一直繞遠路。

如果你用這東西能不能改變世界來決定要不要做某項專案、或是要不要學習某個領域,可能會因為自身眼界的不足,而導致放棄掉許許多多的可能性。

你會覺得某些東西不酷,很可能是因為你自身的實力和眼界還沒辦法知道這東西能發揮多大的影響力。某些東西可能其實是個很重要的敲門磚,但因為你的實力還不足,所以就過早把這段可能剪枝掉了,就像國中的時候覺得一元二次方程式沒什麼用,只要會加減乘除就可以在社會上生存,就決定放棄不學了一樣。

前幾天,我跟朋友在討論該如何挑選自己想要鑽研,擅長的領域這個話題,朋友直接借給我請問侯文詠這本書,說你現在討論的某些話題,跟侯文詠討論的有點像,可以找時間看看。我看完之後有種豁然開朗的感覺。

總結一句話:你應該要追尋你發自內心喜歡的事物,而不是為了其他目標去選擇你該追尋什麼事物

如果你把目標定在改變世界,那麼你一定會努力想,我到底該怎麼做才能改變世界,於是你就會挑捷徑走,挑看起來認為能改變世界的題目做。

通常的情況是,你還太淺,尚未累積出足夠改變世界的能力與視野,於是你會一直撞牆,覺得充滿挫折,為什麼我這麼努力,世界還是不會改變,為什麼我總是找不到對的人幫我,為什麼我要做的事情如此困難。剛開始你會硬撐,相信堅持能夠克服一切難關,但是當你遇到異常麻煩的困難擋在你面前的時候,光靠我想要改變世界的決心其實很難堅持到最後。因為多數人並不是那麼想要改變世界,他可能有50%的心覺得改變世界還算不錯,另外50%覺得如果我真的改變世界會聲名遠播,大家會尊敬我,敬佩我。你想要的其實是受人尊敬

而受人尊敬最正確,最快的方式是對世界做出貢獻

做出貢獻的方法在於解決大家困擾的問題,而想要解決這些問題你需要擅長某些領域,而精通領域的方法在於找出自己的天賦與熱情。

賈伯斯的話中,真正重要的並不是改變世界,而是在於傾聽你內心真正的聲音,因為你的內心很容易被外在的雜訊淹沒,你很容易受到其他人的影響,跑去追尋聽起來有前途、比較有可能成功、比較可能賺錢、比較安穩、比較容易受人尊敬的路。

只有你認真的問自己喜歡什麼,才有辦法在過程中得到樂趣,並且樂此不疲,你不會因為外在環境而患得患失,只會關注自己是否每天都真正進步。當你努力的做你喜歡的事情時,你會慢慢累積出1萬個小時的努力,遇到各種有趣的人與機會,最後那些點才會在未來清晰地連在一起。

 
over 1 year ago

最近一直在思考,到底軟體人跳下去做硬體,為什麼會很容易踩到雷被炸死,以及更進一層的問題:要怎樣做硬體專案(或是更廣義的推廣到所有創業題目),才不會掛點。在思考幾天、並且和紘銘大大聊天後獲得啟發,覺得愉悅,決定寫文章記錄下來。

創業的Golden Rule:挑對題目,找對人,做對事,水到渠成。

這句話聽起來很簡單,很直覺,聽起來沒什麼大問題,但實際上大家常常說一套做另外一套。

挑對題目

創業首先最重要的,是挑對題目。

但大家可能不太明白挑對題目的意思。我們用XDite的話給個操作型定義吧,所謂對的題目,意思是解決你本來就很擅長的問題。你必須要夠在3~6個月生出第一版prototype產品並且收到錢。

你說做不到?很抱歉,那就代表這題目不適合你。

那些看起來很紅、如果做出來的話一定能賺錢、我好像可以做做看的題目,如果無法pass操作型定義,那麼基本上有9成以上的機率會失敗。

通常是怎麼死的?因為你不擅長解決這問題,那麼你就不知道解決這問題需要多少錢、需要花多少時間。你會很容易低估預算、低估工時,原本以為3個月可以做完結果做了6個月還弄不完。原本以為花100萬塊可以搞定結果花了200萬。

再來是你根本看不出隱藏的風險。如果你本來就很擅長,那麼你通常會知道哪些地方可能出問題,可以事先防範。但如果你不擅長,基本上就是在玩踩地雷,炸到你死。

你說你可以邊做邊學?馬的你是來上課的還是來創業的?創業的學費很貴的,錢燒完就沒了,痛了就知道刻骨銘心啊。

創業應該是解決你本來就擅長的問題,因此挑題目比挑夥伴還重要。

一個會成功的創業團隊應該是,每個人都做自己擅長的事情,這樣子速度就會跟用飛的一樣,速度快,燒的錢就少。能很快解決問題,就算走錯路,也能很快修正方向。最後客戶滿意心甘情願付錢,你說這樣還能失敗嗎?

但問題是,你不可能擅長每件事,你的團隊能獨自把問題cover掉那當然最好,但要是不行,需要找外部的合作夥伴,那該怎麼辦?

答案是,一個人打不過,把大家都拖進來一起打啊!

你不會寫code,那就找其他會寫code人來幫忙啊!你不會製造,那就找OEM廠的PM幫你評估啊!不要妄想自己能夠解決那些問題,這世界上的問題夠多了,讓專業的人來做專業的事,他們做比你做更快、更好、更省錢。

這時候問題就來了,你有沒有辦法說服他們加入你?

找對的人

這裡不談找創業夥伴,創業夥伴應該本來就在你的核心團隊裡,這裡談找合作夥伴。

如果你本身夠厲害,是做這個案子不可或缺的人物,那麼你就具有更高的籌碼可以跟別人談合作。你可以跟他說,這東西我超強,我來做基本上一定可以完成,但是有些部份沒有你我做不來,你要不要一起合作,最後事成了,大家一起喝酒吃肉?

如果你不夠強,或是你本來就不是解決這個問題的核心人才,那麼大家看你跳下去做一定覺得超不可靠的,合作下去失敗錢就拿不回來了。就不敢跟你合作,不敢背負風險,頂多只敢把你當作案子在接,要你出錢他們才肯出力。

如果其他人把你當作案子在做,自然就不會鞠躬盡瘁,有做就好,遇到問題慢慢回報、慢慢處理,如果這是你產品或服務的核心,那麼你修正回饋的速度會很慢。基本上就是有一個idea但找別人開發的經典陷阱。

你不需要學會所有的技能,但你需要有能說服人家和你一起打仗,勝券在握十之八九,到時候榮華富貴一同共享的能力和氣度。

做對事

當你挑對題目、找到對的人,那事情就成一半了。你可以預料大多數的風險,有突發狀況也有餘裕可以應付。不至於疲於奔命或錯估情勢。接下來你只要正確的處理問題、專注於解決問題、帶給顧客價值,公司就會開始慢慢成長,運氣好的話,就可以穩定上軌道了。

 
over 1 year ago

這本書已經絕版了,博客來和和Tazze都找不到,我是在圖書館找到這本書的。

這是一本很棒的書,他談的是做生意的基本常識,也就是一位成功的商人的心智習慣。這些常識課本裡不會講,父母不會教,多半只能靠親身經歷才能體會。

這本書提到幾個很重要的觀念,在這裡記錄下來。

寫一份給你自己看的企劃書

你只要誠實的回答自己四個問題就好:

  1. 你的想法是什麼
  2. 你打算如何行銷
  3. 你認為生產或是提供你所銷售的東西,成本是多少?
  4. 當你實際開始賣的時候,你預期會發生哪些事情?

你必須誠實面對自己,擬定銷售計畫,估計養活公司鎖需要的營業額和毛利合不合理。你必須自己拿紙筆開始估算每個月要賣多出多少產品,要花費多少錢在員工的薪資、行銷費用上,訂出產品的毛利,有多少現金流量的需求。如果你發現預計的現金流量一直無法改善,那麼這個事業就不可行。反之,你所需要的資本就是財務報表上的最大現金赤字,這就是你需要的創業準備金,但是建議你多準備個50%,因為頭洗下去後你會發現,成本總是比你預期的還高,利潤總是比你預期的還少

永遠記得,毛利率很重要

整個事業剛起步的時候,最重要的就是毛利。因為毛利不僅決定了你賺了多少錢,更重要的是,你必須拿那些錢去支付公司的其他費用,才有辦法維持公司的營運。

記得一件事情,如果你的毛利為10%,那麼每1塊錢的費用(員工薪水、店租、水電、行銷),你都必須要賣10元的營業額才有辦法打平。但如果你的毛利是40%,那麼你就只要賣2.5元的營業額就可以打平。毛利率越高,你支應費用的營業額就可以越小,你的資本就可以撐得夠久,對大多數新創事業而言,時間是活下去的關鍵。

作者提到一個新手創業的可怕陷阱,叫做業務員心態,也就是為了要讓營業額達到目標,而不惜犧牲毛利率。很多人會把目光放在我們公司有多少營業額,卻忽視了營業額不等於現金,但現金才是真正你的事業生存所需要的食糧。這件事情很重要的原因來自於一個基本的事實:你的資本有限。如果你的毛利並不足以支應你費用的缺口,最後就會把你的資本花光。因此你必須確保把資本花在短期內會產生現金流量的地方。再來是,盡可能努力維持最高的每月毛利率,不要追逐任何低毛利率的銷售。

舉個案例,假設你開了一間飲料店,你這個月的目標是賣30萬元的營業額,因為賣出30萬元才有辦法損益兩平,現在是這個月的最後一週,但你只賣了15萬的營業額,那你會怎麼辦?你可能會選擇降價促銷,務必求營業額達到目標。但這是很危險的作法。因為你一旦降價促銷,就是在損害你的毛利率,就算營業額達標,總體毛利率還是不足以支應所有的費用。要讓營業額上升很簡單,降價促銷就可以了,但如果你一直沒辦法提升到能養活公司的毛利率,很可能就代表這門事業不可行。

避免土撥鼠節症候群

我是在XDite的網誌中看到他提到這本書和土播鼠節症候群,所以也去找這本書來看。土播鼠節症候群是一種「自我重蹈覆轍的毀滅傾向」。我們總是有些心智思維模式,會一再的害我們陷入困境,是我們卻很難改變。例如,我們都不喜歡承認自己錯誤、總認為問題是大環境或別人造成的。沒有人不會犯錯,我們一定都會犯下一些錯誤,但重要的是如何反省,並且避免下次再犯下同樣的錯誤。

再來是,很多人要創業的時候,腦袋會想十個點子,然後問別人說「你覺得哪個點子最棒,哪個點子最容易成功?」,但實際上,你真正該問的問題是「我想要投入哪一個事業,哪個最適合我想要過的生活。」你需要專注,太多的機會會造成分心甚至失敗,如果你很認真的真的想要擁有自己的事業,你必須要從你的所有點子中挑出一個,這個點子必須是最吸引你的。你必須要對這個產業徹底研究,了解實際這個產業是如何運行的、你要有長期投入的準備,你應該計畫你會有五年以上的時間會投入到你的新事業上,本來要養活一個新事業,就要花費很長的時間。

雖然你需要專注,但你不能故步自封,市場的機會一定會和你原本的假設不同,很多事情不會照你原本想的計畫發展,你必須想辦法let them works,去觀察、傾聽、做實驗、提問題、改變、修正觀念,直到你的事業夠強壯,不再需要你為止。

挑選創業方向的原則

這裡作者提到一個務實的觀念,和Peter Thiel的從0到1相反。Peter Thiel喜歡的是那種壟斷某個產業的公司,他討厭競爭的事業,因為過度競爭代表沒有人能賺到超額利潤。而作者喜歡的是那種有人已經在裡頭賺錢的事業,而且有許多競爭者,理由是有很多競爭者代表這個產業進入門檻不高,而且有人賺到錢。比起那些全新的點子,作者更喜歡那種存在百年以上的生意概念,不需要革命性的創新,但是要每個人都能夠輕易了解,因為再也沒有比教育市場更昂貴的事情

但正式因為如此,所以作者更強調因為你會有很多競爭者,所以你必須要和別人有所區別。作者喜歡的是那種老舊的產業,也就是客戶的需求已經改變,但是沒有人注意到。變化已經發生,但是業界還沒跟上

最後的重點是找到利基,也就是這門事業能做起來的根本原因,和你的競爭對手區隔的有利武器。你有什麼和原本的競爭對手作法不同的地方?或是你擁有什麼他們沒有的優勢?利基最後一定會隨著時間消退,但是在企業成長的前期,他是能抵抗競爭對手的重要武器。

養成漲價習慣

漲價一向不是容易的事情,他會引起客戶反彈,你如果突然大漲價,客戶一定會抱怨並流失,但如果你一段很長的時間沒有漲價,有一天你會發現你自己別無選擇。

因為總是有成本會上升,你的毛利率會慢慢變少。舉例來說,薪資費用會一直增加、勞健保也會增加、設備用品的成本也會日漸增加。除非你定期漲價,否則你的利潤會被吃光光。

另外別忘了,你不能把公司當成所得的來源,你要把公司當成資產。資產是需要維護的,如果你希望你公司有穩健的毛利率,你不能讓公司毛利低於業界水平,否則你將來可能根本賣不掉公司。

漲價不用高,但是你必須定期漲價,每次漲一點點,避免顧客抱怨,但同時維持自己的競爭力。

找到利基

通常在你開始一個事業的時候,你不會立刻找到利基。通常你會在公司成立後一段時間才找到,你要做的事情是捲起袖子、開始銷售,看看市場如何回饋你。你會碰到意外、碰到障礙、碰到好事、碰到機會,發現事情跟你想的不一樣。

利基會在你想清楚你的生意是什麼的時候出現。

避開產能陷阱

盡量不要用打折出售閒置的產能,除非你有合理能向舊客戶解釋說明的理由。

你以為你增加了營業額,但其實你損傷的是自己。你在砍自己價格的同時,就等於在市場上引入了一個競爭者,那就是你自己。另外,當你用低毛利率業務把你的產能填滿,你就喪失了為高毛利生意服務的機會,而且你會懶惰,懶得去尋找更高毛利的客戶。最後是你忘記資金是有成本的,你做一筆買賣像當於投資,你把資本浪費在低毛利的客戶上絕對是個錯誤。

 
over 1 year ago

關於講座

這篇只是心得,同時為了尊重講者,所以我不會提關於實際的技巧。想深入了解的約我吃飯聊。

因為在FB上follow XDite, 看到這個講座很多人推薦,明明還是學生手頭不是很寬裕,但還是狠心把報名費刷下去了(反正我也不懂如何投資股票,那就把錢拿來投資自己吧)。與其說這場講座講的是GH, 不如說講的是行銷的基礎與本分

這場講座講了8, 9個可以立即使用的Growth Hack技巧,但是我認為那些都不是本質。Growth Hack的本質其實很簡單,就是

  • 關心你的顧客、為你的顧客著想
  • 替顧客帶來價值

只要你對這兩件事情用心,其他的一切就會自然發生。

因為要關心你的顧客,所以你要想辦法觀察顧客的行為,顧客為什麼不上門?為什麼在門口看看招牌就離開了?為什麼不肯點更貴的餐點?顧客離開之後,下次還會再來嗎?甚至他們會願意推薦朋友來嗎?

觀察完行為之後,你要如何改善?要如何設計招牌?如何設計菜單?你要如何影響顧客的行為,為顧客帶來更多價值(你也可以收到更多錢)。顧客離開之後,會再來嗎?會願意推薦朋友嗎?

因此一切的一切都圍繞在你有沒有替顧客解決問題、帶來價值?
如果你沒有真正為顧客帶來價值,那麼顧客不會願意上門,也不會願意推薦其他朋友,那麼你的服務就很難成長上去。

所以一開始XDite就講了,Growth Hack的重點在於把產品做好,不把產品做好,用再多GH技巧都是奇計淫巧,最後會弄巧成拙。但是問題來了,通常的情況是你以為你把產品做好了,但是顧客根本不甩你。

所以本質上這是一個相輔相成的問題,你要去關心顧客、為顧客著想、聆聽顧客聲音,才有可能把產品做好。把產品做好之後你的用戶數量才會跟著成長。

值不值得?

老實說,非常值得。

這是一場行銷講座,所以主辦方自己在行銷的時候完全就是照著講座的內容在做。我自己最大的收穫是,我填了課前問卷,課前問卷要你寫一些你的需求和想學習的方向,結果XDite特別寫了一篇部落格文章回答我一直撞牆的問題。光是這樣就回本了。

講座的內容大概一半左右都可以在XDite的部落格或FB上找到,但實際去聽會有更全盤且有系統的了解,還可以聽到一些實際的案例,讓你知道這套方法是真的work的。像是演講中的A/B測試範例,老實說我真的沒預期改了幾個字會造成3倍以上點擊率的改變。

演講結束之後跑去找XDite問問題,同時檢視自己過去犯下的錯誤,想想之後該如何改進。我覺得很有趣的一點是,XDite的學習路程和想法都很簡單、很直觀,那是一種直接面對問題並解決的個性。因為覺得Rails寫網站很快,所以卯起來學Rails。因為想要解決問題,所以去學習更多tool,獲得更多成就感。最後藉由把學習到的東西分享出去,做出口碑,自然而然形成Content Marketing,大家願意買他的帳。

以前一段時間覺得,純軟好難賺到錢,所以決定跑去做機械設備,結果把自己搞得超級崩潰、另外看了很多Angel Club的Case之後,漸漸發現,賺不賺得到錢和軟硬無關,而在於你有沒有解決真正的問題。台灣不乏純軟體,但是解決真實世界問題的好公司。貿然投入自己不熟悉的領域往往會把自己搞得灰頭土臉。

重點從來都不在技術,而在於有沒有解決問題,有沒有替顧客著想。

 
over 1 year ago

因為交大VPN(或是說juniper協定)實在是對Linux超級不友善,搞好久才終於連上, 簡單在這裡紀錄一下步驟:

我使用的OS是Ubuntu 14.04

  1. 關鍵字不要再查Juniper了,沒有debian版本的。請直接去github下載openconnect,不要用apt-get,因為不夠新,不支援juniper。到你喜歡的地方 git clone https://github.com/cernekee/openconnect

  2. 執行./autogen.sh,讓他幫你生成./configure

  3. ./configure, 然後他會跟你說你沒有vpn-script,噴錯就停了,請直接照著錯誤說明重新下一次./configure --with-vpnc-script=/etc/vpnc/vpnc-script

  4. 好了,接下來下make

  5. make成功後會產生執行檔,請先上sslvpn.nctu.edu.tw。自己輸入交大學生的帳號密碼登入,然後把你瀏覽器的DevTool打開,去查看cookie,把DSID這串數字複製出來。

./openconnect --juniper -C "DSID=foobar12345" sslvpn.nctu.edu.tw

-C意思是cookie的意思,foobar12345換成你剛才的DSID值。

接下來yes/yes/yes,好了,你連上VPN了,希望這篇文章造福後人。

參考資料:openconnect for juniper

 
almost 2 years ago

忘記在哪裡被推坑了,跑去找了革命前夕的摩托車日記這部電影來看。

這部片不新了,是2004年的片子,但是拍的很有味道,把格瓦拉和死黨旅行的風霜感都拍出來了。我在看完這部片後覺得有些情節感覺很白爛,不知道是編劇改編的還是格瓦拉自己的日記就這樣寫,我立刻跑去找革命前夕的摩托車之旅來看。

讀完原著後,我發現,他媽的日記真的這樣寫,這部片拍的還挺寫實的。

----以下有雷----

電影裡面看到那部摩托車一直摔、一直摔、一直摔,那部車是真的很破爛沒錯,但我真的不知道為什麼要摔車這麼多次,一開始摔到池塘裡、摔到沙地裡、後來又摔到雪地裡,最後摔到齒輪箱壞掉、煞車壞掉、整部車解體才被蓋上裹尸布送走。看到那部車被折磨的不成人形了,原本想說這會不會是電影效果,讀了日記後發現,是真的。

格瓦拉有先去找女友告別,是真的。電影裡他女友的眉毛非常濃密,這我不知道真假,但看起來不太舒服。女友給他15美元請他去邁阿密回來時要買禮物,是假的,根本沒有這15美元,至於女友後來跟他分手這一段,老實說我沒看到日記裡有寫。

路過某個湖,格瓦拉的朋友直接拿槍把野鴨射下來,雙方嘴砲誰要去跳進冰冷的湖水把野鴨撿回來,最後格瓦拉跑去撿,是真的。

到某個小鎮時,剛好看到一間報社,格瓦拉跑進去宣稱自己和死黨是痲瘋病專家,然後獲得報紙一個欄位的介紹,去修車時還騙老闆說我們是痲瘋病專家,還拿報紙給老闆看,苦苦哀求老闆幫忙修車。之後老闆修好後帶他們去參加舞會,結果格瓦拉喝醉後勾搭老闆太太,差點被老闆殺了,倉皇逃出舞會。本來以為這一段是電影情節需要,拍成這樣子,沒想到日記一讀,全都是真的!

向新認識的朋友謊稱旅行一週年了,想要喝酒慶祝但是卻又沒錢買酒,等到朋友叫酒過來時又說阿根廷的習俗裡面必須先吃飽,才能喝酒,最後騙到酒和東西吃,是真的。

在智利的沙漠裡遇到一對失業、貧困的共產黨夫婦,身無分文,連一條毯子都沒有,那晚非常冷,格瓦拉和他朋友阿爾貝托分他們一條毯子,兩個人一起擠另一條。隔天陪那對夫婦到附近的礦坑找臨時工,真的。被臨時工的工頭罵,叫格瓦拉趕快閃人,真的,但電影拍的有些過於無理,但是有些小誇飾但無傷大雅。

在痲瘋病人村直接握病人的手,因為沒做彌撒所以不能吃午餐,但病人偷偷端給他們吃,離開艘木筏取名叫曼波探戈號,都是真的。

格瓦拉24歲生日還待在痲瘋病人村,大家祝詞慶祝,是真的,慶祝完畢後晚上,格瓦拉跳下水游泳,想要游到對岸的痲瘋病人村。很抱歉,跳下水想要游到對岸是假的,沒有人會想要晚上游過亞馬遜河,絕對沒有。

基本上格瓦拉在進行這趟旅程時,大概是23~24歲的年紀,他的夥伴阿爾貝托29歲,他們旅行了九個月,前半段靠摩托車死撐,後半段搭便車、便船、換了各種交通工具,把整個南美洲繞了半圈。

你可以透過這部電影、這本書感受到南美洲的風光,他們無時無刻喝著阿根廷的國茶馬黛茶、旅途上有沙漠、有冰雪、有草原、有湖泊,南美洲的美景映入眼底。我建議的順序是先看電影,再看書。因為電影拍的寫實、精彩,而書可以用敘述彌補電影旅程的不足。

這不是一部心靈成長電影,他不是那種深夜遇到切格瓦拉(X)蘇格拉底(O)的心靈勵志片。

你可以在這部片裡面看到格瓦拉年輕時的影子,那時他才23, 24歲,是年輕人對世界充滿好奇心的年紀,他還沒開始工作,還沒被現實擊倒,迫不及待想要走出去探索這片土地。他有女友,但這並不會拘束他追尋自由的性格。

什麼樣的人會在身患氣喘後,仍要加入美式足球隊踢球?明明時醫生的小孩,差一個學期就能從醫學院畢業,卻要跑去南美洲半圈,到處搭便車蹭飯把自己搞得灰頭土臉。遇到痲瘋病人時勇敢的握住他的雙手。在古巴革命成功後,不願好好當個首長退休,反而選擇把革命推廣到整個南美洲。又跑去非洲練游擊,最後死在玻利維亞。

我相信這趟旅行徹底改變這個年輕人的想法。他看了太多底層的人民為了一粥一飯掙扎、看到無情的資本主義建立的礦場如何迫使窮人犧牲健康換取溫飽、看到被殖民統治後的原住民是如何喪失了自己的民族性、他受的高等教育迫使他去思考為什麼世界會變成這樣子,這趟旅行在他生命中種下了無法回頭的種子,加上他性格上的執著與不屈不撓,最後造成他這一生悲劇的必然。

看完之後,我發現很難歸納出一個心得,或是說自己獲得什麼啟發。因為這趟旅行是如此的平鋪直敘,卻又造成了如此深遠的影響。前些日子閱讀完易中天的品人錄後,我會說,生命是性格和環境造就的必然。從終點回過頭來看,一切都看似命中註定,可是從起點往終點望,卻又看不見盡頭似的。

總之,推薦這部電影。

 
almost 2 years ago

如何實作JavaScript Promise?

本篇文章是我閱讀了A+ Promise implementing的筆記與心得。因為官方講解其實用語很精煉,所以我決定用我自己的話寫一篇容易看得懂的筆記。有任何錯誤歡迎留言指正。

PS: 我在本篇文章中交替使用resolve與議決這兩個詞彙。

建立物件內部變數

//Promise內部有三種狀態

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise() {
  // 一開始的狀態是Pending

  var state = PENDING;

  // 一旦Promise被resolve,把成功的value或是失敗的error快取起來

  var value = null;

  // handlers用於儲存 呼叫then或done的後success, failure的handler

  var handlers = [];
}

建立轉換狀態的內部方法fullfill和reject

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise() {
  var state = PENDING;
  var value = null;
  var handlers = [];

  function fulfill(result) {
    state = FULFILLED;   //讓狀態改成成功

    value = result;      //快取結果

  }

  function reject(error) {
    state = REJECTED;    //讓狀態改成失敗

    value = error;       //快取錯誤

  }
}

建立更高階轉換狀態的方法resolve

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise() {
  var state = PENDING;
  var value = null;
  var handlers = [];

  function fulfill(result) {
    state = FULFILLED;
    value = result;
  }

  function reject(error) {
    state = REJECTED;
    value = error;
  }

  // resolve接受一個單純的值或是一個Promise當作參數。

  // 如果是個一般值,那就轉換狀態

  // 如果是個promise,那就對該promise進行議決,等到議決結果出爐再透過callback轉換狀態。

  function resolve(result) {
    try {
      //試圖取得該物件是否包含then方法,若有,則代表這是一個promise

      var then = getThen(result);   
      if (then) {
        //如果傳入的值是個promise,那麼就透過doResolve先去議決該promise,

        //再根據議決的成功與否callback resolve or reject

        doResolve(then.bind(result), resolve, reject)
        return
      }
      fulfill(result);
    } catch (e) { //在resolve的過程中,如果catch到錯誤會讓該promise reject

      reject(e);
    }
  }
}

getThen

判斷傳入的值是不是promise,如果是的話回傳該promise的then方法,可以注意到檢查方式很鬆散,只是檢查有沒有then方法而已,這種方式可以讓多個不同的promise library彼此相容。

function getThen(value) {
  var t = typeof value;
  if (value && (t === 'object' || t === 'function')) {
    var then = value.then;
    if (typeof then === 'function') {
      return then;
    }
  }
  return null;
}

doResolve

實際進行議決,doResolve 有責任確保傳入的resolve和reject這兩個參數只有其中一個會被呼叫一次

注意doResolve的工作,他會以傳入的fn進行議決,然後再根據議決結果呼叫傳入的onFulfilled或onRejected。並且使用了一個內部變數done來確保onFulfilled或onRejected只會被呼叫一次。

function doResolve(fn, onFulfilled, onRejected) {
  var done = false;
  try {
    fn(function (value) {
      if (done) return
      done = true
      onFulfilled(value)
    }, function (reason) {
      if (done) return
      done = true
      onRejected(reason)
    })
  } catch (ex) {
    if (done) return
    done = true
    onRejected(ex)
  }
}

仔細觀察可以注意到,fn吃兩個參數,一個是成功時的callback,另一個是失敗時的callback,正好對應到Promise建立時的syntax

new Promise(function(resolve, reject) { ... });

建立Promise建構式

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise(fn) {  //傳入fn作為參數

  var state = PENDING;
  var value = null;
  var handlers = [];

  function fulfill(result) {
    state = FULFILLED;
    value = result;
  }

  function reject(error) {
    state = REJECTED;
    value = error;
  }

  function resolve(result) {
    try {
      var then = getThen(result);
      if (then) {
        doResolve(then.bind(result), resolve, reject)
        return
      }
      fulfill(result);
    } catch (e) {
      reject(e);
    }
  }

  doResolve(fn, resolve, reject);  //對fn進行議決

}

整個promise基本設定完成後,執行最後一行doResolve,直接對new Promise(xxx)的xxx進行議決,要是議決成功就執行resolve,議決失敗就執行reject。

解釋

為什麼resolve要搞這麼複雜,還要透過doResolve來解決?因為一個promise被議決時有下列兩種情況:

//有一個非同步的promise, 會在一秒鐘之後議決成yeeeee

var yeePromise = new Promise(function(resolve, reject) {
    setTimeout(function() {
    resolve("yeeeee");    //resolve一個value

  }, 1000)
})

//在三秒鐘之後議決yeePromise

var p1 = new Promise(function(resolve, reject) {
  setTimeout(function(){
    resolve(yeePromise);   //resolve一個promise

  }, 3000)
});

如果該promise發現他必須再resolve另一個promise(他具有then方法),那麼就必須繼續取得該promise議決的結果。取得結果的方法是呼叫該promise的then,一旦呼叫then後會有三種情況,沒事、呼叫onFulfilled callback,或是呼叫onRejected callback。

doResolve吃三個參數,fn(要議決的內容), onFulfilled(成功時的callback), onRejected(失敗時的callback),因此我們可以把要fn訂成該promise的then,也就是doResolve(then.bind(result), resolve, reject)。
bind會把執行then時的this綁定到該promise上,因此看起來就像呼叫了該promise的then,如果成功的話就繼續議決(resolve),如果失敗的話就否決(reject)

觀察Promise狀態

我們已經完成所有基本的工作了,現在唯一的問題是,我們沒辦法知道該promise到底有沒有乖乖把任務完成,因此我們需要.then來回報狀態。

但我們先來實作.done吧,因為.done比.then簡單一點

promise.done(onFulfilled, onRejected)

首先我們有幾個需求

  1. 只有onFulfilled或onRejected其中之一會被呼叫
  2. 只會被呼叫一次
  3. 他不會立刻被呼叫,而是會在done return之後之後才會被呼叫(非同步)。
  4. 不管我們的promise在call .done之前被議決或是.done之後,他就是會被呼叫
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise(fn) {
  var state = PENDING;
  var value = null;
  var handlers = [];

  function fulfill(result) {
    state = FULFILLED;
    value = result;
    handlers.forEach(handle);   //fulfill時,要執行每一個待執行的handler

    handlers = null;
  }

  function reject(error) {
    state = REJECTED;
    value = error;
    handlers.forEach(handle);  //reject時,要執行每一個待執行的handler

    handlers = null;
  }

  function resolve(result) {
    try {
      var then = getThen(result);
      if (then) {
        doResolve(then.bind(result), resolve, reject)
        return
      }
      fulfill(result);
    } catch (e) {
      reject(e);
    }
  }

  function handle(handler) { 
    if (state === PENDING) {
      handlers.push(handler);
    } else {
      if (state === FULFILLED &&
        typeof handler.onFulfilled === 'function') {
        handler.onFulfilled(value);
      }
      if (state === REJECTED &&
        typeof handler.onRejected === 'function') {
        handler.onRejected(value);
      }
    }
  }

  this.done = function (onFulfilled, onRejected) {
    // ensure we are always asynchronous

    setTimeout(function () {
      handle({
        onFulfilled: onFulfilled,
        onRejected: onRejected
      });
    }, 0);
  }

  doResolve(fn, resolve, reject);
}

.done透過setTimeout來達成非同步的效果,在next Tick之後才根據狀態執行handle看看(晚點再講為什麼要這麼做),然後根據狀態決定要先等待還是進行處理。如此一來,就可以透過傳入.done的callback來讓promise根據狀態決定是否執行任務了。

搞懂.done後再來就是大魔王.then了

Promise.then(onFulfilled, onRejected)

this.then = function (onFulfilled, onRejected) {
  var self = this;
  return new Promise(function (resolve, reject) {
    return self.done(function (result) {
      if (typeof onFulfilled === 'function') {
        try {
          return resolve(onFulfilled(result));
        } catch (ex) {
          return reject(ex);
        }
      } else {
        return resolve(result);
      }
    }, function (error) {
      if (typeof onRejected === 'function') {
        try {
          return resolve(onRejected(error));
        } catch (ex) {
          return reject(ex);
        }
      } else {
        return reject(error);
      }
    });
  });
}

可以看到我們用了一個很漂亮的作法來實作.then,那就.then會回傳一個新的Promise。如此一來你就可以使用Promise Chain來串接).then(cb).then(cb).then(cb)

這裡超級精彩的:.then回傳了一個新的Promise,而這個Promise所答應的事情是「原本Promise的完成(done)」

光講不清楚,我們寫一段簡單的code就知道什麼意思了

//這是一個會在10秒後議決成'yeeeee'的Promise

var yeePromise = new Promise(function(resolve, reject) {
    setTimeout(function() {
    resolve('yeeeee');
  }, 10000)
})
//我們呼叫了.then()

yeePromise.then(function(result) {
    console.log(result);
})

呼叫.then()後, .then()會回傳一個新的Promise,這個Promise會去呼叫yeePromise內部的.done(),而.done會先檢查yeePromise的狀態,發現是Pending,就先把handler放在handlers裡頭,直到5秒後yeePromise被resolve了,他才會執行剛剛保存的handler,最後印出'yeeeee'

為什麼.done內要setTimeout(fn, 0)

這是很重要的問題。請看下列程式碼

var promise = query();  
A();  
promise.then(query);  
B(); 

你預期會發生什麼事?
如果Promise是非同步的話,答案會是A() -> B() -> query()
如果Promise是同步的話,答案會是A()->query()->B()

為了避免讓程式設計師混淆,因此Promise的實作規格規定一定要是非同步的。

注意

另外請注意,.done並不是Promise/A+的實作標準規格,但大多數的標準Library會實作他。

以上就是我的筆記,希望這份筆記能夠讓你簡單的理解Promise是如何實作的。

reference
 
almost 2 years ago

談Vim

如果你是一位程式設計師,那麼你多半聽過、或碰過Vim。

這裡替沒聽過Vim的朋友解釋一下。Vim是一個編輯器程式,就跟你Windows電腦裡的記事本、Notepad++一樣,你可以用他來編輯一些文字檔案。但Vim不是設計給一般使用者使用的,他只有簡明的編輯畫面,不能用滑鼠控制,就連移動游標都是靠鍵盤來完成。Vim在程式設計師的世界裡有著編輯器之神的美譽(請不要跟我拿神之編輯器來戰,這不是重點),因為程式設計師工作一整天,幾乎每個小時都黏在編輯器上面,有一個順手的工具是很重要的。

但Vim有一個惡名昭彰(?)的學習曲線。對初學者來說不好上手,因為不能使用滑鼠,所以每件事情都要透過敲鍵盤下指令完成。存檔敲鍵盤、搜尋取代敲鍵盤、移動游標敲鍵盤、打字刪除敲鍵盤。Vim就像一匹野馬,他必須要被程式設計師馴服,基於使用習慣,建立自訂的快捷鍵後,才會變得好用,但這也代表著必須花費很長的一段時間。

從初次接觸Vim、學習並適應Vim、到現在堪用但不擅用Vim,我對於那些常常在使用Vim的高手會有一種莫名的憧憬,我想大多數的程式設計師或是外行人都是這樣吧,看到終端機的黑畫面先敬畏三分。周遭大神的電腦多半是白Mac配終端機的黑畫面(大神的Mac一定要是Air),因為那隱約代表著我知道我他媽的在幹嘛,用純文字來操作效率更好

Learn Vim Like a Boss

這幾天,剛好工作告一段落,稍微有些空閒,我決定研究看看如何像大神般使用Vim。我想要體會那種敲敲幾個鍵,檔案就照著我的意思修改,那種效率大增、感覺自己像個大師的感覺。或許也是潛意識吧,我隱約覺得高手們多半善用Vim,因次想變強一定要學好Vim(很經典的邏輯推論錯誤XD)。

原本的目標是我希望我的Vim 能和IDE一樣方便,於是我上網搜尋後,找到一篇談論「像IDE一樣使用Vim」的文章,但我很快就發現這篇文章對我來說太深,他使用了各種套件,致力於讓Vim達成像IDE一樣的功能。但我覺得我應該要先把Vim的基本功能學好,讓Vim所思及所得,想到什麼手指就自動修改好,再來談讓Vim像IDE一樣工作。

於是我找到一本電子書,叫做Practical Vim: Edit Text at the Speed of Thought,我花了幾天的時間,挑選幾個章節做練習。這是一本很適合Vim初學到進階的書,每個章節都可以單獨閱讀,你可以學習到很多基本但常用的功能,例如根據需求移動游標、管理多個檔案、搜尋取代、還有很多有用的command,我相信只要把這些學好,你使用Vim的效率會大幅增加。

但學了幾個章節後我又厭倦了,因為要學的東西實在是太多,常常讀沒幾章就會想睡覺。我明白這些都是基本功,但是令人傻眼的是「怎麼那麼多基本功啊啊啊啊~~」。

剛好在搜尋問題解答的途中,我發現了一篇很棒的教學,叫做Learn Vimscript the Hard Way,這是一本免費的電子書。要知道Vim所有的外掛都是透過Vim Script寫成的,想要擅長Vim,搞懂VimScript是必須的。作者在本書的開頭開宗明義:「請一定要照著本書的範例練習一次,並且完成所有的Exercise,我保證你練習完後一定會發現自己的進步。」

天啊~一定會發現自己的進步,太帥了~於是我就很乖的把前十五個章節都看完並練習一遍。但老實說,練習的過程蠻乏味的,雖然作者盡可能的讓練習題貼近日常使用所需(例如:建立一個可以讓你迅速編輯.vimrc的快捷鍵),但是總覺得這實在是太慢了。我有感覺到自己的進步,我能夠使用並建立簡單的快捷鍵,但總覺得還少了某些東西,距離目標「讓Vim和IDE一樣方邊」還好遠。

嘗試打造自己開發環境

於是我決定先暫停下來,我想先試著打造看看自己的開發環境。因為最近我很常寫JavaScript,我就先試著打造能夠讓我日常開發JavaScript方便的環境吧。我搜尋了幾個常用的套件,嘗試裝上去看看。但是依舊充滿挫折。

挫折1: 自動換行功能

1. 我希望能夠讓我打{的時候
{

2.會自動補齊右括號,且游標停留到中間
{|}

3. 且按下Enter時會自動換行
{
    |
}

4. 再度換行後,按下backspace時,會回到上一行的縮牌位置,而不是退到該行的起頭
//after <Enter> gain
{
    
    |
}
//and Press <backspace>
//good
{   
  |
}
//bad
{
    
|
}

1,2,3都做到了,但是4不知道要怎麼做,但是IntelliJ IDE會會幫我做到第四點,可惡討厭啊啊啊(信心--

挫折2: 自動補齊功能

IDE最潮的就是要有自動補齊,既然Vim自訂性這麼高,加上自動補齊也沒什麼難度吧(?)。於是我找了個叫做YouCompleteMe的套件,才發現原來自動補齊是個背後技術涵養超級高的功能,這個套件背後竟然有一個Server/Client的架構,他還有不同的complete Engine,還會自動智能挑選Engine(實在是太潮了啊~),還會幫每個關鍵字做ranking。幸好安裝過程並不困難,但是裝完後很快就發現問題了。竟然沒有內建支援JavaScript啊啊啊啊。(信心--

沒關係,官網說你可去找另一個叫做tern的project,他是專門為了javascript所設計的語法分析引擎,可以和YouCompleteMe順利工作。於是我把tern安裝起來,發現怎麼沒有順利工作?仔細觀察文件後才發現,tern如果要順利運作,必須要在每個project的file上建立一個config檔.tern_project,在這個config的內必須要敘述使用的library。tern才會提供適當的補齊功能。內心OS瞬間浮現:所以我每次開一個新專案~想要自動補齊都要再另外再寫一個設定檔?!為什麼要搞這麼麻煩啊啊啊啊啊啊。

後來我還是乖乖寫了.tern_project設定檔,好不容易讓自動補齊work了,但立刻發現tern的自動補齊會額外在你的編輯視窗上頭再開一個顯示資訊的split window,這個小視窗實在煩人,所以我最後把tern和YouCompleteMe都刪掉了。(信心-=5

挫折3: 語法highlight

好吧,我決定要從最基本的下手,就算不能自動補齊,至少我的畫面是漂亮的,賞心悅目至少每天開發時心情會好一點。於是我上網挑了幾種colorscheme。嗯……看起來最流行的Solarized? 跑在終端機的感覺沒有很好看。Molokai看起來配色很漂亮,下載下來裝裝看好了

Molokai在Ruby上的colorscheme

為什麼在JavaScript上感覺就是有點怪怪的~

啊~再搭配vim-javascript-syntax好了,官網推薦說這個可以增強javascript的syntax功能,看看會不會好一點

QAQ到底發生什麼事了,那個function name不要兩個都是綠色啊啊啊(信心-=10)

我喜歡IntelliJ裡面預設的配色,優雅,簡潔,但是我網路上找到的IntelliJ ColorScheme套上去就是很怪。

IntelliJ的JavaScript檔案配色

就這樣,短短三個功能就讓我的信心碎了。Vim對我來說就像一部拼裝車,你可以把他改得很拉風、很潮,你可以找到很多前人留下來的裝備,但是想要讓他易於使用,你需要更多時間去慢慢調校(O)調教(X)他。

出現轉機

後來,我在查資料的途中,閱讀到一篇部落格文章,一瞬間有種大徹大悟的感覺。

那篇文章是由Antonin Januska寫的,標題叫做「Don’t tell people to use VIM (because) You’re Using It Wrong」。讓我簡單的把重點翻譯出來。


不要再叫別人學Vim,因為你根本用搞錯了

很抱歉,Vim不會讓你成為厲害的開發者。你不會只是因為用Vim後按下幾個少少的按鍵,然後程式碼就自動生出來了。Vim不會是一個程式設計師好或不好的關鍵要素,甚至,Vim也不是最棒的編輯器。

如果你還願意聽下去,讓我娓娓道來

我剛開始學習coding時用的是Notepad,就像其他的web開發者一樣,接著我很快就改用Dreamweaver。Dreamweaver對我們這種初學者來說就像上帝一樣,自動補齊、即時預覽、各種檔案的語法highlight,還有程式碼折疊。錯誤和bug還會自動跳出來,還有FTP、Project Filetree、那就是個你心目中理想、萬能的IDE。

使用Dreamweaver之後,我的生產力提昇了一千倍,再也回不去了。直到有一天我開始寫C#,跳槽到Visual Studio,他完全顛覆了我對程式碼編輯器的想像,我再一次回不去了。多重視窗、重構、跨檔案自動補齊、套件管理,多麼完美的工具,我的生產力再度提昇了一百倍。

當我換工作之後,我擔任某專案的首席開發者,我擅長的是PHP,因此不能再繼續使用C#/VisualStudio了,於是我挑選了WebStorm作為我開發PHP的利器。剛開始,他看起來和可以和VisualStudio相提並論,但是很快我就發現,對於開發PHP來說,WebStorm是個大災難,他有太多視窗、包含太多太多套件了,剛好當時同事都在用Sublime Text 2,於是我決定改用Sublime開發,而WebStorm就拿來上傳FTP和debug。

Sublime Text 2是個低調但很棒的工具,他開啟檔案很快、外掛很多,然後畫面很簡單,我無法再回去使用那些笨重的IDE。於是我就用Sublime用了幾年,直到有天,有位開發者告訴我他超愛Vim。

我當時其實有點想從Sublime跳槽,我嘗試了一下,就改用Vim了。為什麼我要改用Vim呢?和生產力一點關係都沒有。而是因為我爽(Comfort),我喜歡使用shell來完成我大多數的工作,Vim可以跨OS X和Ubuntu上運作,不需要安裝其他套件。我並沒有成為更厲害的程式設計師,但我更享受coding這件事。我並沒有成為快捷鍵的高手,敲敲:djsdfakjs之類的然後就瞬間把我的code重構了,但我享受不使用滑鼠工作的爽感。

很多我的同事、朋友他們都試著使用Vim,但他們後來都說沒有FU。我覺得那沒什麼關係,Vim本來就不見得適合每個人。在我看來,Vim根本不適合大多數人。

當有人告訴我他們嘗試過Vim,但是很難上手的時候,我會問他們三個問題

  1. 你有自訂你的Vim過嗎?
  2. 你是那種Vim的一日球迷嗎?
  3. 你對用Vim之後的期待是什麼?

第一個問題是針對那些sudo apt-get install vimbrew install vim,然後學了一些shortcut cheatsheet,然後就沒戲唱了的人。光是這樣並不會讓你飛起來,我強烈建議你閱讀Coming Home to Vim並且從那裡開始,如果你沒有自訂你的Vim,那麼對大多數人來說,用Vim當開發環境一點用都沒有。

第二個問題是針對那些嘴巴講喜歡Vim但甚至根本不用Vim開發的人,他們會告訴你

  • 不要用上下左右
  • 不要用滑鼠
  • 全部使用快捷鍵
  • 使用d, c等快捷鍵而不要用delete來刪除
  • 盡可能少用insert mode
  • (然後默默安裝其他人的設定檔)

要熱愛Vim是相當沈重的一件事。讓我告訴你吧,我還是用我的方向鍵、但不使用滑鼠,我並沒有瘋狂的使用快捷鍵,甚至一開始幾乎沒有,我依然不習慣使用c,但是我會用o換行。

從正常人到Vim的極端基本教義派會把你搞到瘋掉,慢慢來,甚至如果你一開始需要滑鼠,那就用沒關係。

第三個問題,所以你到底在期待什麼?你是期待某種開發者之道嗎?或是某種寫code的加持之類的,或許你曾預期使用Vim之後,你的程式碼就會比以前好十倍?或是你的工作會更輕鬆十倍?告訴你,這些統統不會發生,至少前幾個月不會發生。你的生產力會跳回你一開始的程度,然後慢慢隨著時間滾雪球變強。問題是,這些事情不會立刻發生,可能要幾個月,甚至更久。


結語

讀完這篇文章後,我想起了我學Vim的初衷,然後狠狠的嘲笑自己一番XD

我犯過這篇文章講的所有錯誤,我以前就是那個拿別人的.dot file安裝,然後根本不會修改的那種人(感謝vgod的vim的設定檔,那真的不錯用,特別是我剛開始學vim的時候),過了一陣子之後我才開始慢慢客製化我的Vim,我自己改掉我的Vim狀態列、加了簡單的設定。但是我從來沒有好好的學習與研究他,直到這幾天。

當我開始練習Learn VimScript the hardway的時候,我還感受不太到到底這些教學有什麼用,但後來我才大致了解,那些「教你如何自訂快捷鍵」其實是個相當重要的基本功,因為每個人的工作流程都不同,他要你學習的是建立你自己的Vim,因為只有你知道你自己的需求、習慣的工作方式,這樣的練習對你才有意義。

Vim代表的是一種工作哲學,他就是一張幾乎具備無限可能、可以讓你自訂功能的工作台。你可以把這張工作台調整的更符合自己的需求,加上一些你想要的套件,讓你更快速的完成你的工作。但是這些都要花時間,如果你沒空,用別人幫你準備好的工作台(IDE)也很好,重點是你開心,以及能不能有效率的完成工作。

另外在閱讀文件與學習Vim的途中,我能夠逐漸感受到Vim的設計哲學,那是一種program your file的感覺。雖然如此,但Vim的學習曲線還是很陡,很多問題還是很麻煩,像我在這篇文章提到的幾個問題,如果有人可以解答的話我會相當感激。

至於要不要用Vim來當你日常的工作環境?我覺得就看個人需求吧。看你在哪個環境下開發最有效率,好好把他熟悉,畢竟我覺得,把code寫乾淨、架構弄清晰,應該比學好Vim更重要一點。以上就是我的心路歷程,希望這篇文章能讓你好好想清楚「為什麼要學Vim?」。

 
almost 2 years ago

最近花了一些時間,做了一個匿名版本的Facebook動態牆網站Nimi。

點我開啟網站,還是測試版,炸開就算了

簡單說,他是一個「Facebook個人頁面的匿名版本」,你可以讓你的朋友在牆上留言,牆面上會顯示留言者是你朋友,但是無法得知對方哪位。

緣起

這個專案最早的起源來自今天寒假時發想的idea,當時幾位朋友聚在網路福利社,說要辦場hackathon。大家最後決定要一起自幹出一個「匿名版本的社群網站」。

有些話,你是不敢再FB上面用自己的名義對大家說的。一般人在FB上總是會試圖維持一個良好的形象,也就是我希望大家認為我是怎麼樣的一個人。多半時候,你會在FB上寫一些中性的、正面的動態,例如最近去哪裡玩、最近工作上遇到什麼糗事、分享一些消息,但你很少會看到朋友在FB上抱怨和另一半分手了、失業了、某門課被當掉了,只有一些無關痛癢的小糗事才會被放上來。

另外,在FB上你會習慣對所有朋友保持表面上的良好關係,你不一定會喜歡你FB的所有朋友,甚至,你會看不起某些朋友的所作所為,但你不會公開的宣揚與批判,這些心情上的抒發只會在幾位好朋友的小圈圈發生。

為了抒發工作上、生活上、情感上的不爽、Facebook開始出現了大量的靠北粉絲專頁,例如靠北x大、靠北工程師、靠北男友、靠北女友……。大家在這裡盡情的匿名大罵,把自己內心的鬱悶抒發出來。這些粉絲專頁的人數往往都破萬,更甚者,靠北男友高達65萬個讚,靠北女友友54萬個讚。這些專頁往往都提供很特定的共同話題作為討論主題,讓有共鳴的人可以按讚follow。

開啟專案

當時的想法很單純,既然每個人都有抒發內心黑暗面(?)的需求,而Facebook只是一個報喜不報憂的平台,那我們就乾脆做一個匿名的動態牆,牆上會出現你Facebook朋友的貼文。但是全部都是以匿名的方式呈現。

我沒有按任何一個靠北XX的粉絲專頁讚過,因為我只要一按,接下來我的FB就會被一些和我沒什麼關係的匿名靠北文洗板。當時我想,我會不想看到這些匿名靠北文的原因,恐怕是因為這些文章和我一點關係都沒有。但如果這些匿名貼文是我Facebook的朋友發的,那我可能就會有興趣看了。所以當時的專案就是基於這樣的想法開發的。

於是這個專案就開啟了,但是幾個禮拜後,專案就停掉了。其中一個原因是hackathon時大家只共同寫了一個晚上,程式碼非常亂,各種模組隨性的接在一起,另外當時專案是使用nodejs開發,但我其實不甚熟悉,很難維護。另一個原因是當時幾位朋友越來越忙,大家沒有空繼續開發,而我本身也不是會上去靠北XX貼文的人,說真的,做這個東西如果自己不會用,那麼熱情遲早會消退,於是最後就把這個專案停掉了,程式碼的屍體就這樣留在我的硬碟裡(突然覺得我的硬碟很像太平間……)。

重新啟動

最近暑假,因為時間上比較有空,剛好和幾位朋友重新聊到匿名這件事情,他們聽到這個專案後覺得蠻有趣的。我們就花了一個下午好好討論,把更具體的功能要求訂出來。我回去之後一個人把以前的程式碼打開來驗屍,然後花了幾天的時間,把當時hackathon發想的東西復打造出來了。

那是一個可以任意發表貼文,任意更換自己的暱稱,而且不會被別人發現自己是誰的網站。你的動態牆上只會有你Facebook朋友發的動態(而且全部是匿名的)。

打造出來很開心,於是第一件事情就是拿給朋友玩玩看。大家覺得能在幾天之內就做出來時在是太酷了,我們四個朋友在一個小時之內就貼了二三十則匿名的動態。大家再上面亂講垃圾話,但很快的,問題就浮現出來了。

你媽知道你在這裡發廢文嗎

這樣的網站有個嚴重的問題,那就是因為匿名,所以大家會開始亂發文,反正發出的文不用負責,而且隨時可以更換名字,又不會被發現是誰,於是大家會開始在網站上貼一堆垃圾訊息。於是每個人的牆都被垃圾訊息洗板,

更可怕的是,我們發現一個這個網站本質上的問題,那就就算是朋友的匿名文,我也不會感興趣

我們就是如此殘酷,實際上,我們一點都不care某位朋友分手了、某位朋友最近被上司罵。如果是在FB上你發了一則分手心很痛的動態,那麼你會得到一堆讚,還有一堆好朋友拍拍的留言。但是也僅限於好朋友。在匿名的環境下,你會開始想,我根本不知道你他媽的是誰,就算你是我fb好友,你也有可能是我很久沒聯絡的國小同學,你分手了老實說關我屁事啊。

同樣的,Facebook也遭遇到同樣的問題。如果Facebook把你數百甚至上千的朋友的貼文按照時間順序列給你,你肯定會果斷的離開Facebook。對於資訊爆炸的問題,Facebook的解決方案是神秘的推薦演算法。他根據你平常互動的朋友、有興趣的專頁來分析你這個人喜歡什麼樣的貼文,然後給予適當數量的貼文讓你閱讀。但是身為一個廢廢的工程師,我實在不想在網站上搞出這麼一個複雜的東西。

對象與內容

我認為一篇匿名的貼文如果要受到大家的分享與關注,最重要的事情在於兩點,也就是對象內容

既然不知道是誰發的文,除非這則貼文是和我有關,否則我一點都不care。要和我有關有兩種方式,一種是直接針對我,發給我,也就是指定發文的對象,另一種是內容會引起我的共鳴,例如同樣都交過男女朋友、同樣都是工程師,有共同的經驗,所以就有額外的共鳴。

因此,我又花了幾天的時間,改良原本的匿名機制,建立了新版的匿名網站。新版的機制是這樣的,當你註冊之後,我會給你一面「匿名牆」,這面牆完全是屬於你的,只有你本人在這面牆上的貼文會以真名顯示,其他人在你牆上的留言或貼文全部都會以匿名顯示。

為了避免遭到陌生人在牆上進行垃圾式的瘋狂洗板,我們參考Facebook的個人專頁的留言機制,也就是由匿名牆的主人決定誰可以在他牆上貼文,只有兩種選項,自己和朋友。另外如果是朋友在他的牆面上貼文,那麼顯示的權限也限縮於版主的設定。

原本認為,這兩個機制搭配在一起,就可以成為很棒的匿名平台。這樣的機制的確解決了一些匿名的問題,但當我把這個測試版的網站貼到Facebook上請朋友試用後,很快就發現問題了。

沒有內容就沒有人要看

測試版的網站貼出來後,立刻發現最大的問題在於大家不知道這個要拿來幹嘛。如果我給你一個讓你的朋友可以在你牆上匿名留言的網頁,其實你根本不知道要做什麼。我是要拿來變成匿名批鬥大會,問朋友說我這個人的缺點嗎?

另一個問題是,任何網站的使用者要回頭,唯一的方法就是「提供給他們想要的東西」。但根本沒有任何能夠吸引使用者的內容。沒有內容,就沒有流量。

再來是,你要怎麼搜尋到你有興趣的內容?為了確保匿名性,我是不能夠加上「搜尋你的朋友」這項功能的。如果你能夠搜尋你的朋友,那你就可以過濾出到底可能在你牆上留言,因此不能提供搜尋功能。比較可行的方法是加入follow功能,讓你可以follow特定的匿名牆。

目前的想法大致如上,還沒有很完善,恐怕還有很長的一段路要走,有任何想法或意見歡迎提供。