Sunday, June 16, 2019

Architecture: Cut horizontally v.s. Cut vertically

關於 software architecture ,我最近發現了有一塊,過去我總是沒有想得很清楚的地方: cut horizontally 與 cut vertically 的比較。仔細想想,這個也不是什麼太新的觀念。一般來講,像公司內部的分工,也有類似的兩種概念

cut vertically 近似於公司切分事業部的概念: A 部門負責 a 產品,所以 A 部門就盈虧自負。在 software 就是切分出 Component, bounded context 。也可以稱之為 package by component/ package by feature

cut horizontally 比較近似於公司內統一採購、發包的概念: 公司完成工作,有時會透過與第三方協力廠商共同完成。與第三方的關係,會透過統一的採購、發包專人來做。這在 software 就是切分出 Application, Adapter 的層次。可稱之 package by layer 。 cut horizontally 比較難找到很巧妙的類比,不過,對照 cut vertically 之後,應該比較容易想象。

無論是 cut vertically 或是 cut horizontally ,都要設法讓 components 或是 module 可以解耦(decoupled)

在 cut horizontally 的情況,應用的技巧,主要是 Dependency Injection 。
然而在 cut vertically 的情況,應用的技巧則是 events/shared kernel 等。

Monday, April 15, 2019

tmux session manager --- tmuxp

不知不覺中,我開發 web application 的時候,會需要用 tmux 開啟多個背景視窗。比方說,一個用來啟動 frontend 的 npm run start 。另一個用來啟動 clojure 的 lein repl 。每次都要重複下一些固定的指令,也滿煩人的。所幸,早就有工具來處理我遇到的問題 --- tmux session manager。

我安裝的是 python 版本的,因為我在 ubuntu 上安裝 ruby/gem 並沒有想象中的好裝,我二話不說看看有沒有 python 或是 nodejs 版的。結果實驗的結果是 python 的 tmuxp 最容易安裝。

安裝好 tmuxp 之後,前前後後就是用到二個 tmuxp 的指令 :
1. 先用傳統的老方法,手動把 tmux session 建立起來,並且切割視窗,跑不同的程式。
然後,下一個指令,把現在的 tmux session 寫到檔案裡, 記得把檔案存到 ~/.tmuxp/ 資料夾下,之後會比較簡單。
tmuxp freeze session-name

2. 之後,對 freezing 完的 yaml 檔做一些適當的修改。要再啟動時,下一個指令
tmuxp load session-name

Saturday, March 30, 2019

vim skill & use cases

有幾個我最近才搞懂的 vim 技巧,搭配上使用情境 (use cases) 之後,這些技巧也就不再那麼難以理解了。

< 多重剪貼簿 >
registers 本質上就是 multiple clipboard 。但是,其實平常我也不會特別想要同時使用多個剪貼簿。這個好用的點,通常是當 yank 與 delete 衝突時,就很方便。

常發生的情況是這樣子:

  •  yank 第 15 行,打算 paste 到 28 行。 =>  yy
  • 在 paste 之前,在 27 行做行刪除。 =>  dd
  • 在 28 行按下 p 時,失敗! 因為貼上的並不是原先的第 15 行。


解法是這樣子,最後一個操作要改成  =>  "0p  
"0 這個 register 總是會放入 yank 的資料,如果不指定 register 的話,會使用 default register ,但是在上述的情況, default register 會被 delete 的資料給填充。

輸入 :reg ,就可以看到各個 registers 的內容。

< 重構程式碼、變數重新命名 >
這種時候,用 vimgrep 似乎頗合用。

:vimgrep /PATTERN/  **           =>  在當前目錄與其子目錄下,找出所有的 PATTERN

搭配指令
:cnext, :cn             =>  去下一個找到 PATTERN 的 buffer
:cprevious, :cp      =>  去上一個找到 PATTERN 的 buffer
:copen                   =>  打開 Quickfix 窗口,顯示所有結果
:cclose, :ccl           =>  關閉 Quickfix 窗口



< 不使用 Ctrl - P 的 fuzzy search  >

:e **/*部分檔名
:vsp **/*部分檔名

原理的部分,可以查  :help starstar-wildcard

Tuesday, February 19, 2019

用 Graalvm 製作 clojure native image

在 ubuntu 18 做的實驗:
1.  下載、安裝 Graalvm 

2. 在 ~/.lein/profiles.clj 裡增加
{:user {:plugins [[io.taylorwood/lein-native-image "0.3.0"]]
        :native-image {:graal-bin "/path/to/graalvm-1.0.0-rc1"}}}
如此,就可以使用 lein native-image 這個指令

3. Graalvm 需要下列的套件
sudo apt-get install gcc
sudo apt-get install zlib1g-dev

4.  lein native-image  之後,就可以得到 native image 。

Friday, February 8, 2019

從 SQL 到 Datomic query (datalog)

要理解新的概念,一般而言,用舊的、已經熟悉概念來加以連結新的概念,會是比較容易的方法。另一方面,要讓人們去接受新的解決方案,先確定舊的問題都可以在新的解法中解決,也是有效增加人們信心的作法。

當我使用 SQL 來開發 web application 時,最常用的 SQL query 是什麼呢? 其實未必是複雜的 join operation 。最常用的,反而是樸實無華的查看單一或是多個 rows:
(1) SELECT * FROM A
(2) SELECT * FROM A WHERE A.col = b

那麼,這麼簡單的 SQL query ,如果是在 Datomic 的世界,又是怎麼對應呢?我在 datomic 官方的 mbrainz-sample 找出的一段 query 。用了之後,覺得非常容易可以對應上述的兩種情境。sample code  在下方
舉例來說明:
如果有一個「使用者」的概念,要用資料庫加以建模。使用者有電子郵件、密碼、名字三種屬性。同時,我們需要一個資料庫查詢 (query) ,可以根據電子郵件來查出對應的使用者

1. 用 RDB 來建模的話,這個 sql query 會長成這樣子:
SELECT * FROM user WHERE user.email = "ecoboy@qwerty.com";

2. 用 Datomic 來建模的話,一旦利用上述的 utility functions ,這個 query 就可以用下列的函數產生。
(find-by db :user/email "ecoboy@qwerty.com")

附註:
(a) 在 SQL best practices 裡,因為要考慮效率,往往不建議用 select * 這種 query 直接放在 production code 裡。
(b) 在 Datomic  best practices 裡,因為 datomic 的 query 並不需要往返 client-server ,同時 Entity 有 lazy evaluation 的特性,一般而言,推荐的作法是直接取回 Entity ,相當於 SQL 裡的 row 概念。

Monday, February 4, 2019

From REST to CQRS with Clojure, Kafka, and Datomic

Clojure/conj 2015 年的 conference talk --- From REST to CQRS with Clojure, Kafka, and Datomic 是我 2019 年所看到第一篇深受啟發的 talk ,也有 youtube  影片。

首先作者先探討 Restful API  的一些問題:
1.  modeling - jamming every operation into CRUD on some resources is often unnatural, creating impedance mismatch. 
Restful API 可以視為是模仿 Database 的 CRUD 介面 (post, get, patch, put) ,然而,這個 modeling 在本質上,未必適合對各式各樣的問題做建模。
2. mutability semantics
Restful API 隱含了 mutable 語意
3. the kingdom of nouns for distributed system 
最後就是有太多的 API ,然後需要有類似 swagger 之類的 API document 系統 …
4. integration 
integration by API 比 integration by ETL 好一些,但是,還是有許多缺點

然後,作者 (Bobby Calderwood) 提出了一個應用 CQRS + Event sourcing 來設計系統的架構 (Commander Pattern),如下圖:



















新的架構處理了許多舊有的問題:
1. modeling 
web services 的部分只對 communication semantic 做建模,所以只有三種,而非 resources * CRUD 。communication semantic 是指 /command /update /query 三種語意。
2. immutable semantics
/command API 會寫入 command log 。這個 command log 對使用者的 intention 做完整地記錄,相較於儲存進資料庫裡的資料, command log 有更完整的 command story
3. too many APIs
因為新架構的 http endpoint 只有三種: /command /update /query 。
4. integration
新的架構裡可以 integration by events ,因為有儲存下 command log 。要整合的時候,其它系統去訂閱 command log 就可以完整地拿到系統的 states

心得感想:
(*) end-to-end principle
在這個架構裡, Web services 層只用來處理 communication 。 Restful API 的 resources 名稱,其實算是一種 domain semantics,應該要放到 Business Logic 層來實現。這其實很像網路世界的 end to end principle ,因為 Client 與 Business Logic 就像是溝通的兩個端點 ,針對應用 (application) 設計的種種特性 (features),應該要在這兩端來加以實現,而不是在中間的 Web services 層實現。

(*) We shape our tools and thereafter our tools shape us. 
Restful API 的設計,有點像是使用了 SQL/relational database 之後的思維模型會構思的設計。而這個 Commander Pattern 則是使用了 Datomic 之後的思維模型會構思的設計。

Thursday, January 31, 2019

重拾 Datomic

這些日子接了一個專案,打算用 Luminus 來做 web application 。前端考慮了幾個選項之後,覺得還是 ClojureScript + re-frame 是最先進的選項。資料庫自然還是要用 Datomic 才是最合用的選項。

Datomic 參考資料
1. Leran Datalog Today  --- 互動式的教學網站,可以練習 Datomic 搭配的 DSL: Datalog
2. Missing Link Datomic Tutorial --- 比官網的 Datomic tutorial 易懂,因為省略了太細的細節
3. How to setup Datomic Free with Clojure  ---- 看完了 tutorial 總是要自己實作一下,參考這個來實作最快
4. Using Datomic in your app: a practical guide --- 使用 Datomic 的實務經驗談
5. The ten rules of schema growth --- 使用 OLTP 資料庫常遇到的問題: schema migration ,該怎麼處理呢?

適合什麼情況?
哪些情況適合用 Datomic ? Datomic 適用於 OLTP 的應用、適合於 iterative development ,也就是說,如果一開始對於問題的細節有很多不了解,會有許多難以預測的新 schema 變動, Datomic 是很不錯的選項。

關於 Datomic Schema 的兩個特別的心得
(1) Datomic Schema 不需要有獨立平行的版本控管 migration file 來管理。
Datomic is uniquely suited for iterative development. Change is easy, due to the granular data model and small but powerful schema. And change is always tracked within the database itself, so you do not need a parallel infrastructure of version-controlled migration files as your application evolves.

(2) Schema 安裝是 idempotent ,所以可以放到 server startup code
In Datomic, installing your schema consists of submitting a regular transaction. Attribute installation transactions are idempotent, so you can just write your schema installation transaction in your application code and transact in your server startup code.