Sunday, November 22, 2020

研究 Monad 的心得

學了 Clojure 再來學 monad ,彷彿像是學了英文之後,再來學日文。表達同樣的語意,但是,用不同的方式表達。

一 monad 用來幹嘛?

monad 用來夾帶 context 。什麼是 context ?基本的概念有點像是,本來是「值」語意,加上了 context 就變成了「向量」語意。


二 如何定義 monad

定義一個 monad 就是要定義兩個 operations
(1) unit 或是稱之為 return 。
     這個 op 接受一個 value ,傳回被 monad 修飾過的 value (monadic value)

(2) combine 或是稱之為 bind。
     這個 op 接受一個 monadic value 和一個可以接受 ordinary value 的函數。這個 op 的作用就是組合上述兩者,於是就可以得到一個可以處理 monadic value 的新函數。

三 常見的 monad 所處理的問題集合

(1) Maybe monad 
     在 Clojure 的世界裡,比較好的 modeling 沒有值的方式,並不是使用 nil 。 而是使用 vector 或是 hashmap 來 modeling 真實世界的 entity 。如果用 vector 或是 hashmap 來做 modeling 的話,有時候根本不用判定 nil ,也就是 Maybe monad 完全不需要。

(2) List monad
     處理 mapcat 可以處理的問題。

(3) Reader monad
      處理 dependency injection 可以處理的問題。 

Sunday, November 15, 2020

Some database-related quotes

* SQLite is not a replacement for PostgreSQL. SQLite is a replacement for fopen()


* We should call NoSQL databases as Postmodern Databases because they are:

  1. Absence of objective truth

  2. Queries return opinions rather than facts


* NoSQL databases that only have weak consistency are enforcing a broadly applied premature optimization on the entire system.

Tuesday, September 8, 2020

npm lockfile

話說,長久以來,我在開發 nodejs/javascript 的 project ,都有一個問題。到底需不需要把 package-lock.json 放進 source control 裡?

總是感覺需要,但是常常 npm install 的時候,這個  package-lock.json  就會大改。讓我覺得也滿困擾的。總覺得好像並沒有真的 lock 下來?

原來我少學了一個指令 npm ci

npm ci 的功能,就是可以嚴格地依賴 package-lock.json 來安裝套件。如果真的需要昇級才能裝的話,它就會丟出 error 。

Tuesday, August 11, 2020

讀書心得 --- 什麼才是經營最難的事

作者是安霍創投的經營者, Ben Horowitz 。書裡的內容,看起來,雖然也有引述許多經營管理書的論點,但是,最精采的部分,則是作者獨到的心得。對我來說,書中有一些點,是我不曾在其它書看到過的。以下列出幾點:

1. 人資的功能

長久以來,我也想不清楚,人資是用來幹嘛的?好像重要、又好像不重要。書裡給了一個簡單、清楚的概念:產品品質靠品保、管理品質靠人資。人資就是用來確保管理的品質的,是用來防止人事管理的環節,有任何一環嚴重出錯的功能。

2. 先管人、再管產品、最後才管利潤

作者主張要「必須」打造優良的工作環境。當公司的營運順利時,公司是否是依靠快樂的員工、優良的工作環境來達成利潤,也許沒有很明顯的差別。然而,當公司營運不順時,如果沒有優良的工作環境,優秀的員工就會快速離職,公司的營運會雪上加霜。而經營公司,一定會有營運不順的時刻。也因此,打造優良的工作環境,是目的而不是手段。

3. 員工訓練

Why?
有至少四個理由,應該實施「員工訓練」:生產力、產品品質、績效管理、員工留任。

績效管理是一般公司很容易欠下管理債的地方。在員工訓練時,就應該清楚設定好績效目標。等到真的需要開除員工時,就容易說清楚,為何沒有達成績效目標。

一般員工最常見的離職理由,除了經濟因素之外,往往不外乎兩個原因:
1. 討厭主管 - 主管不懂得帶人、不管屬下的職涯發展、不知道應該給予回饋。
2. 學不到東西
而員工訓練可以同時解決上述兩大問題。

How?
員工訓練應該要分成兩大主軸:職能訓練 (functional training) 與管理訓練。做得好的話,對於員工的士氣也極有幫助。

如何讓主管一定會落實員工訓練呢?最大的障礙往往是觀念問題,很多人覺得員工訓練太浪費時間。最有效的作法:要主管先訂出一套待聘人員的培訓計畫,否則遇缺不補。


Wednesday, July 8, 2020

Neovim + Conjure

友人推荐我試用看看 Neovim + Conjure 來取代 vim + fireplace 。我試了之後,覺得整體而言,算是又改進了一些些,這邊簡單記錄一下 Conjure 的用法。

主要會使用到的 Conjure 指令:
:ConjureEval [code]                類似 fireplace 的 cqp
<localleader> ee    // evaluate the form under the cursor.  (e 是 inner 的諧音)
<localleader> ece  // Evaluates the form under the cursor and displays the
                         result as a comment at the end of the line or below
                         the current line if you already have a comment there.
<localleader> er    //  evaluate the root form under the cursor. (r 是 outer 的諧音)
<localleader> e!     // evaluate the form under the cursor and replace it.  (! 意指 side effect)

類似 fireplace     :Require 的功能,重新載入整個檔案。
<localleader> eb   // evaluate the current buffer
<localleader> ef    // evaluate the current file from disk

快速檢查特定變數的『值』
<localleader> ew   // evaluate the current word
<localleader> ecw  // Evaluates the word under the cursor and displays the
                         result as a comment at the end of the line or below
                         the current line if you already have a comment there.

開啟 log buffer  的指令
<localleader> ls            // 水平開啟
<localleader> lv           //  垂直開啟
<localleader> lq           //  關閉


看文章、切換到定義
K                               //  Look up documentation for the word under the cursor.
<localleader> gd          //  跳轉到定義

貼上最後一次 evaluation 的結果。 ( 與 nvim register 的『組合功能』)
"cp                            // 上一次 evaluation 的結果會自動存放在 "c 這個 register 裡。
:reg                           // 可以顯示所有的 registers 的內容

對某一特定的 expression 遠端求值。 (與 nvim mark 的『組合功能』)
mf                               // 標記「位值」於 mark f 
<localleader> emf          // 對 mark f 的 expression 做求值。

對被反白的區塊 expression 做求值。 (與 nvim 反白選取的『組合功能』)
<localleader>E              // evaluate visual selection 

應用於 ClojureScript + shadow-cljs
:ConjureShadowSelect [build-id]        // 啟動 cljs repl ([build-id] 是 symbol 非 keyword)
:ConjureEval :cljs/quit                       // 關閉 cljs repl

Thursday, June 18, 2020

劃分 software components 的指導原則 -- From Clojure Applied

We separate our code into components for several reasons:

  1. reuse of generic components within an application
  2. dividing development within a team
  3. dividing development within a structure that allows us to think about only part of the problem at a time 

Guidelines to group code together to separate software components:

  1. the functions work on the same kind of data
  2. the data has a common scope or lifetime
  3. the likelihood of change from external requirements is similar
  4. the resources needed are similar

Friday, June 5, 2020

rules of abstraction

在開發軟體的過程中,總是會有幾回,一不小心失手,寫了失敗的 abstraction 。然後,日後再來痛苦地修正。比方說,把這個 abstraction 放棄掉,先變成大量、重複的程式碼,再來觀察規律,重新提鍊。

那有沒有什麼法則,可以用來提醒自己,做簡單的 checklist ,避免自己寫出糟糕的 abstraction 呢? 有的。

rule 1: Wait until the code is repeated three times before you extract it.
rule 2: If you can't think of a good name for your abstraction, it is probably not a thing.
rule 3: Understandable and reusable abstraction is usually less than 10 lines.

法則 1:重複三次才提鍊
法則 2:想出好名字才提鍊
法則 3:一個容易理解、可以重用的抽象,往往少於 10 行。


仔細想想,為什麼寫好 function 是如此的困難呢? 大概是因為我們同時做了三件事吧:

  • invent a new purpose
  • invent a new implementation
  • name it 



Friday, March 20, 2020

Software Consulting Business (Marketing)


  • 營銷 (marketing) 的主要劃分界線是『是什麼,而不是如何做』。幫助潛在客戶了解要實現的目標 (結果),但不要提供有關如何實現目標的詳細說明,否則,你將放棄自己的價值和/或提示客戶認為不需要你 (但感謝你免費給我這一切)!
  • 切勿在諮詢 (consulting) 、專業演講 (professional speaking) 、輔導 (coaching) 甚至隨意交談中告訴別人你所知道的一切。告訴別人他們需要知道什麼即可。這樣一來可以減少工作量,而且可以使你成為『感興趣的對象』,而不是無聊的事情。
  • 你必須傳播你的信息以建立信譽 (credibility)。嘗試顯示在盡可能多的渠道 (channel) 中 。
  • 如果你想成為出名的專家,那麼在小池塘里做大魚會更容易,因此請仔細選擇池塘。
  • 在專案進行到 2/3 的時刻,就主動要求客戶幫忙介紹新客戶。 (ask for referrals) 
  • 詢問你的客戶關於: 
    • 他們閱讀什麼? (Where you publish)
    • 他們參加什麼活動? (Where you speak)
    • 他們做決定時,參考誰的意見? (Whom to network)

Wednesday, March 18, 2020

Software Consulting Business (Negotiation) --- part 3

最近我推掉了一個客戶。和這位客戶談生意以來,一直沒有談成,總覺得自己一直在做他的免費顧問。對方一下子要做 A 案子,一下子又要做 B 案子。最後我決定停損,於是就終止了與這位客戶的往來。

如果應用「一開口就說『不』」一書的談判五步驗來自我檢討的話:
1. 設定使命與目標
2. 找出對手的痛處
3. 設定預算
4. 確定對手是 economic buyer
5. 談判前先設定議程

從第一點,我就失敗了。我的使命與目標應該是讓客戶明白,我致力於做高品質的軟體。我本來一直認為,客戶是欣賞我的軟體能力。結果我婉拒他的那一天,我隨口問他,他最欣賞我的哪方面。他回答我,因為我幫他介紹了一個人認識,這讓他覺得很上道。

設定預算,我一開始也沒有做。到了後來,談了三次還不夠,還要談第四次、第五次。其實第三次談判沒有明確的進展,往後就可以婉拒了。

談判議程方面: 每次與客戶見面,我通常會 demo 新完成的案子,就當做打簡報一樣。然而,這個方式顯然是效果很差,客戶關心的是他自己的問題,而不是我能做什麼。換言之,我也設定了錯誤的議程。比較合理的議程應該是說,第一次見面,我要說明做軟體需要有規格書、並且要求客戶下回如果要找我見面,請設法準備規格書的雛型。之後每一次的見面,都要在委任我做的事情上有明確的進展。



Software Consulting Business (Negotiation) --- part 2

在平時就要多練習談判時的技巧:隱藏需要、提出好問題、表現出不自在、說「不」並要求對方回答「不」、淨空思緒。

做生意時,說「不」,是有技巧的,通常要加上關懷呵護,例句:
『 OOO,我做不到,真的沒有辦法,但是我確實想跟你合作。我們如何可以找到替代方案?』

在覺得可能會有衝突的時候,直接詢問:
『你想要我怎麼辦呢?』

發現自己講話講得太多時,嘗試最簡單的反詰:
『我說夠了,OOO,你覺得要怎樣處理這些事呢?』

與談判對手協商議程:
『OOO,我不確定這個消息對你有沒有價值,如果沒有,可以直說,我就不往下講,好嗎?可以。那麼這就是我們的約定。如果不對,我們就停下來。如果可以,才往下討論。』
// 給對方說『不』的機會,並且再三求証他的意願。

=== 應用技巧的 5 個步驟 ===
1. 確定你有一個強而有力、由對手觀點陳述的使命與目標,可以使對手看到並決定你的產品及服務是他們需要的。
2. 確定你知道對手的真正痛處 --- 他們之所以談判的真正原因。你提出問題,並創造願景。
3. 評估你和對手雙方的所有預算 --- 時間、精力、金錢、情緒投資。絕對不能忘掉這些預算,要隨時監控,觀察雙方決策如何受到影響。
4. 確定你是和真正的決策者打交道。
5. 沒有書面議程,絕不打電話或送出電子郵件。
議程的內容可以分成幾類:問題、心結、要求、下一步 
『要求』要進入議程,才能驅使對方做出決定。

Friday, March 6, 2020

Software Consulting Business (Negotiation) --- part 1

做生意總是不停地要提案,報價,仔細想想,每一次的報價就像是一場談判。以下的內容出自「一開口,就說不」一書。

要做好「以決策為基礎的談判」 (而非「以情緒為基礎的談判」) ,需要做好下列四件事:
  • 專注於使命與目標
  • 控制個人的需要、不輕易表現對成交的渴望
  • 不怕說「不」
  • 不怕別人說「不」
認真遵守上述四個直接了當、可達成且有效的目標,才容易得到理想的最終成果。

重點在於:要專注在可控制之因素,並且就這些『可控制之因素』去訂出合理的目標,而不是把談判的『結果』當成目標,因為談判的結果是一種不可控制的事。



Thursday, February 13, 2020

Software Consulting Business (Progress)

回想從 2019 8/11 至今,也做了整整半年的生意。從完全沒有計畫、只憑感覺做,到把 Million Dollar Consulting 一書看完。大致上可以列出下列幾點的進展,我引用 Million Dollar Consulting 一書的重點來說明:

1. Seeing only economic buyers.
   領悟這點滿重要的。我領悟之後,就明白,我的買家大部分是高階主管或是中小企業主。其它人往往都只是 Gate keeper 而已,見他們只是浪費時間。為什麼 economic buyer 很重要呢?最重要的原因是,如果要 charge value-based fee ,只能找 economic buyer 來談。只有 economic buyer 才真正關心 output 。

2. Writing proposals with options.
   我從這一點想出了兩招可以快速幫自己增加利潤的招式:
   (a) 讓渡著作權               + 10%
   (b) brand mark removal  + 20%
   這些都是 options ,選購項目,但是客戶往往有誘因要購買。

3. Charge value-based fee / Conceptual agreement
   Alan Weiss 透過一再地與客戶交談,找出創造價值的契機。他把 value creation、pricing、proposal 合為一體。

   我的話,也是採取類似的精神。和客戶深入地討論軟體的需求、訂出合適的規格、提案、報價 、實作。我的報價,如果一般人只看我寫多少的 code 的話,會覺得真的是非常貴。但是,在這個討論的過程之中,最大的價值創造階段,其實是在「訂定規格」。我寫的每一個功能,都要是真真切切派得上用場的,這件事在訂規格的時候就已經確立了。

   (續) 我後來重看了這部分的章節,覺得自己其實誤讀了一個很重要的部分。我自己在與客戶談需求時,並沒有詳細地去把 conceptual agreement 這一塊談好。如果要提高成交率、且為客戶創造高價值的話,其實應該要對這個部分,下功夫去詳談。conceptual agreement 包含 objectives, metrics, value 三個元件,它也是連結 trust relationship 與 accepted proposal 中間的重要環節。

4. Populating the Accelerant Curve.
   目前的話,最左端的產品服務,是一些不收錢的免費文章
   左二的部分,需要做 open source project 、提供可客製化的軟體解決方案。(半客製化)
   右二的部分,是幫客戶寫軟體。(全客製化)
   最右邊的部分,則是每年收取軟體維護費。 total development cost 的 25%

5. Create marketing gravity.
   通常只有 referrals, speaking, networking 可以短期且快速地帶來客戶。目前我的經驗來講,referrals 和 networking 有成功的案例, speaking 則還沒有…


如果套用 Business Canvas 的九大區塊來分析上述 5 個重點的話:
1 對應到 Customer segment
3 對應到 Value proposition
2, 4 對應到 Customer relationship management
5 對應到 Channel

Thursday, January 16, 2020

用 Event Modeling 的方式來描述規格

如何描述規格?

我做軟體做好幾年了,寫程式換過幾種語言。而寫規格書,卻沒有下過功夫去研究。最近一次開發一個比較大的系統,我自己後來寫出來的規格書,大概包含了三個部分:

1. 用講故事 (story telling) 的方式,用人類語言敘述的系統行為。 
2. Database 的 schema 
3. API 的 spec 

後來,仔細想想,這樣子其實也是有問題。其實一個系統的開發,應該拆解成三個階段:
A. 用「非開發人員」也可以理解的方式,書寫的高階系統行為、概述。講的是系統的目的 (purpose)
B. 以程式語言實作系統 (implementation)
C. 寫出該系統的實作規格 (description of implementation)

以我自己的最近一回做的東西來講,story telling 算是 A 。Database schema 和 API spec 都是 C。而系統在與非開發人員溝通,主要是依賴 A 的部分。換言之,其實我做 A 的部分,算是做得很不清楚,因為只有 story telling ,算是相對難以把事情說清楚的。

Event Modeling

Event Modeling 該網站提出的方法,我覺得算是 story telling 的加強版,即 story telling with time。它建議,首先畫一條水平軸,描述「時間」的進展,然後在這個由時間構成的水平軸線上,會放上一個又一個的長方形來描述系統的 story 。

每一個長方形由三個要素構成:
1. Trigger              - 通常是「使用者介面」或是「外部 API」
2. Action               - 通常是要讀或是要寫入系統,分成兩種:Command 與 View 。Command 是「想要改變系統狀態的意圖」、而 View 是系統當下的「報表」、「結論」
3. Event        - 寫入硬碟的業務事件 (business fact)

長方形又可以根據 action 與 external states 可以仔細區分成 4 種 patterns
1.  Command   - state change
2.  View          - view
3.  Translation - external state input
4.  Automation - external state output