拯救你的程式碼
稍微有點標題黨,不過很短,可以看
背景
最近一直在參加開發公司新運營系統的引擎部分,寫了很多很多程式碼,也逐漸產生了一些自己對此類業務的解決方案的簡單想法。運營系統乾的事,其實就是支援運營人員配置活動。所謂活動其實可以簡單定義為:一系列條件都滿足就執行某個 (些) 動作。對應到程式設計師的黑話就是:一坨 if else 之後執行某 (幾) 個函式。
if else
說到寫 if else,大多數程式設計師可能都會會心一笑,畢竟不論寫啥系統,程式碼裡大部分語句還是 if else。業務系統就是對 PM 的需求堆 if else,基礎服務就是對 OS 資源和網路問題堆 if else。越來越多的需求造成了程式碼的膨脹,如何來管理這坨 if else,就衍生出了設計模式:通過各種手段來把 if else 劃分到更小的粒度。當然,還沒有任何一套方法論可以解決 if else 複雜性的問題,因為 if else 反映的其實是真實業務的需求,它其實代表了業務的複雜性。就像魯迅或者馬雲或者巴菲特說的:“不論用什麼方法,if else 不會憑空消失,只會從一個地方轉移到另一個地方”。但是,在面對特定的場景,特定的業務,程式碼的閱讀性、可維護性以及擴充套件性是可以得到提升的。
規則引擎
規則引擎不是一個新東西,而且已經存在了很長時間了,市面上也有各種規則引擎。比如大家常用的 iptables,就是一種規則引擎,crontab 也是一種規則引擎。我們平時寫的業務邏輯,其實也是規則引擎,只是用一種不那麼明顯的方式來體現。比如:“如果重置的密碼沒有包含大小寫和標點符號,就不讓提交”,“如果使用者是抽獎送的 VIP 雖然不播廣告但給他彈窗”……這些業務邏輯,無論怎麼優化,要處理的程式碼分支是一定存在的。規則引擎通過自定義的一套語法(DSL),提供了程式語言所不具備的語法糖,來最大限度減少開發量。同時大部分規則都需要支援使用者隨意配置,因此 DSL 大多是解釋執行。使用者在後臺配置一條規則比如,遊戲中使用者線上 1000 分鐘後扣 20 的點卡:
When
{
?customer: Customer(totalTime >=1000);
}
Then
{
execute {?customer.setAmount(getAmount()-20.00);
}
市面上比較常用的幾款規則引擎都屬於非常重量級的,使用者必須去學習它的 DSL 才能使用,當然基本上都是 JAVA 的包。這有一篇文章是幾款規則引擎的比較。沒有深度用過,我也沒法對此進行評價,但由於其概念實在太多且使用場景受限,我覺得它始終是個臨時方案,畢竟 “大道至簡”。而且 DSL 會越寫越複雜,真正用到語法糖的地方還是少數,到最後變成另一種蹩腳的而且領域受限的程式語言了。雖然如此,但由於其規則可動態增加,老規則便於複用,對於提供通用解決方案的一些軟體公司來說,規則引擎還是很有吸引力的。畢竟程式碼不需要動,加一些規則就能再次銷售。
但是對於進行業務開發的 RD 來說,其實需求很簡單,如果一個東西:
- 正確
- 簡單
- 能減少繁瑣的工作
那麼這便是一個有吸引力的解決方案,如果它能再快點兒,那就是一個絕妙的主意了。對於減少 if else,我覺得 Linq 是一個非常好的方案。
Linq
Linq是 C# 中的一種常見技術,用過的都覺得爽。它就是一種語法糖,編譯器會編譯成真正的程式碼而不是在執行期解釋執行,因此效率也很高。Linq 程式碼大概就是這樣:
// Specify the data source.
int[] scores = new int[] { 97, 92, 81, 60 };
// Define the query expression.
IEnumerable<int> scoreQuery =
from score in scores
where score > 80
select score;
可以看到,在程式碼中一些邏輯如果能這樣表達,那程式碼將會變得非常簡單。linq 基本上就是把 sql 語句搬到了 C# 中,唯一的區別就是它把 select 放在了最後而 sql 是在前面。這其實也是因為 IDE 智慧提示的需求,而不是查詢結構本身要這麼設計。把 select 放在最後,IDE 就知道你前面用過哪些變數,就可以分析出你可以 select 什麼從而進行提示。但是 Linq 是 C# 中的技術,和編譯器是強相關的,想移植到別的語言,還是很不容易的。當然,社群也是有一些嘗試的,比如 go 的移植版linq-go。然而,你懂的,由於 go 本身不支援泛型,編譯器也不支援 linq 語法,因此使用起來當然還是比較蹩腳,而且肯定是 interface{}和型別推斷滿天飛了……
sql
其實我們常用的 sql 中的 where 部分是完備的,Linq 也是把 sql 搬到了 C# 中。換句話說,sql 的 where 部分其實可以組合任意的布林邏輯。所有 RD 都會使 sql,而且是經常使 sql,既然想從編譯器的方向搞事情太麻煩(尤其是 go 是一門以簡單著稱的語言,官方對於加關鍵字是深惡痛絕的,更別說語法糖了),那麼把 mysql 查詢功能幹掉,解釋執行 where 比較的那部分功能做成一個函式提供出來呢,比如查詢一個人是不是頂級程式設計師可以這麼查:
sql := `sex='male'
and (
dislike in ('girl', 'woman', 'female')
or
hobby in ('dress up', 'makeup')
)`
但是由於沒有表資料,那麼真正用於比較的資料就需要業務方自己來提供了,以上功能可以寫為:
func isTopProgrammer(userInfo User) bool {
sql := `sex='male'
and (
dislike in ('girl', 'woman', 'female')
or
hobby in ('dress up', 'makeup')
)`
ok,_ := yql.Match(sql, map[string]interface{}{
"sex": userInfo.Sex,
"dislike": userInfo.Dislike,
"hobby": userInfo.Hobbies,
})
return ok
}
yql 其實就是我最近搞的一個 lib(求 star,求 pr,求指導),幫你執行 sql 的比較。
如果這麼搞,其實業務邏輯中經常變動的部分可以抽象到配置檔案裡,比如:
// 先定義好不同case的處理函式
type handleFunc func(map[string]interface{}) error
var handlers = map[int]handleFunc {
1: sendEmail,
2: sendCoupon,
3: sendSms,
4: sendAlert2Boss,
5: runAway,
}
// 從當前請求中解析資料
data := resolveDataFromPostParams(request.Body)
// 從配置檔案載入規則
rules := loadRuleFromConf()
//列舉每條規則進行匹配,如果匹配成功則執行對應handler
for _,rule := range rules {
success,err := yql.Match(rule.SQL, data)
if nil != err || !success {
continue
}
handler := handlers[rule.ID]
handler(data)
break
}
當然這種方式也有利有弊,比如說,把規則分離到配置檔案中,在 debug 時得幾個檔案之間跳來跳去地看程式碼,比較蛋疼(少寫點 bug 就行了,哈哈)。優點之一比如說可以利用推送平臺實時更新配置檔案,從而達到程式碼熱更新的目的。
最後
其實 yql 還有很多應用場景(我感覺),當然也有一些不足,比如功能還比較單一,解釋執行,快不快其實也沒和誰對比過……不過希望大家能夠嘗試嘗試,如果能夠提升工作效率,還是不錯的。求關注,求 star
- 加微信實戰群請加微信(註明:實戰群):gocnio
相關文章
- 拯救你的Go程式碼Go
- 一鍵fxxk,程式碼修復神器拯救你
- 低程式碼如何“拯救”企業?
- 別讓程式碼愁白頭髮!15 個 Python 函式拯救你的開發生活Python函式
- 敏捷史話(六):也許這個人能拯救你的程式碼 —— Robert C. Martin敏捷
- 拿什麼拯救你,我的QC充電頭?
- Guava - 拯救垃圾程式碼,寫出優雅高效,效率提升N倍Guava
- 拯救祭天的程式設計師——事件溯源模式程式設計師事件模式
- 重構你的javascript程式碼JavaScript
- (譯)保持你的程式碼整潔
- 如何改進你的指令碼程式指令碼
- “慶俞年”後傳:拿區塊鏈拯救你,我的公章區塊鏈
- Kotlin進階:動畫程式碼太醜,用DSL動畫庫拯救,像說話一樣寫程式碼喲!Kotlin動畫
- 如何快速讓你的程式碼支援Cocoapods!
- 你是如何組織html程式碼的?HTML
- 如何讓你的程式碼整潔漂亮
- 優化你的程式碼結構 --- MVP優化MVP
- “拯救者”拯救不了聯想手機
- 拖延症晚期?你需要這個待辦事項清單來拯救你
- 掌握這些程式碼安全檢視方法,提升你的程式碼質量
- 《Narita Boy》GI 評測 7.75 分:消滅邪惡程式碼,拯救數字王國
- 好程式設計師寫出來的程式碼,就叫好程式碼嗎?你錯了!程式設計師
- 你的 JS 程式碼本可以更加優雅JS
- 前端程式碼你是如何做抽象的?前端抽象
- 你見過背誦程式碼的程式設計師嗎?程式設計師
- 忘了Python關鍵語句?這份備忘錄拯救你的記憶Python
- 如果 SSH 被中斷,Linux screen 工具如何拯救你的任務以及理智Linux
- 你寫註釋她幫你寫程式碼
- 拿什麼拯救你,我的offer!(從零打卡刷leetcode,No.004)LeetCode
- 求求你規範下你的程式碼風格
- 為什麼你寫的程式碼糟透了?
- 你的JavaScript程式碼都經歷了什麼JavaScript
- 程式碼管理流程你們是怎麼做的
- [譯] 用依賴注入解耦你的程式碼依賴注入解耦
- 【譯】使用Set使你的程式碼執行更快
- DSL-讓你的 Ruby 程式碼更加優雅
- 使用 TypeScript 裝飾器裝飾你的程式碼TypeScript
- 如何移除你專案中99%的JS程式碼JS
- 那些坑你沒商量的程式碼死迴圈