前面兩篇聊了不少 CLI / PIPELINE 開發的技巧跟基本功夫,這篇換個方式,來聊聊後端工程師該如何自己練習基本功夫吧。這次談的是 “精準” 控制的練習。
我在公司負責架構的團隊,兩個月前,我出了個練習題讓團隊的人練習,目的是測驗大家對於處理大量複雜的任務的精準程度。所謂的 “精準”,是指你腦袋裡面能很清楚的掌握你 “期望” 程式該怎麼跑,以及實際上你的程式是否真的如你預期的執行。這篇文章,我想換個方式,把這練習題的 source code 公開出來,用實際的 Hands-On Labs 練習的方式來進行。有興趣的朋友可以親自練習看看。練習的目的,是讓你思考如何精準的處理任務,而不是學習一堆大部頭的框架,因此我設計的這練習題,你只要熟悉基本的 C# 語法與 BCL (Basic Class Library) 就足以應付了,困難的地方在於你如何解決問題。
練習可以很簡單,也可以很複雜;我還蠻想試看看收集大家的解法,在這篇文章的後半段統一做個評論的;如果你願意將你的 solution PR 放上來,我會在後半段用我的角度幫你 code review 當作回報。之前會想在內部讓 team member 做這練習,目的很簡單,現在的工程師越來越容易忽略掉一些開發的基礎能力,面臨問題就越來越依賴外部的工具或服務來解決。使用不得當,往往就會在執行效率,程式碼維護,或是系統維運的階段付出代價。我們都用 public cloud, 光是 VM 的 instance 數量就超過百台,工程師們你知道你寫的 code 會直接反映在成本上嗎? 只要改善 1% 的效能,每個月的費用成本就可以降低 1% …, 這情況在你的流量很大的時候,加上背後的運算資源都來自雲端服務時會更明顯…。
因此,在公司我都會跟工程師在一對一面談的時候,問問 developer 自己是否想過這些問題:
延續前一篇,在寫 demo code 的時候想到的小技巧,但是文章內容時在塞不下了,所以另外補了個番外篇,就當作日常開發的小技巧分享吧 (搞不好這種短篇的還比較受歡迎 T_T)。前一篇介紹的是 CLI + PIPELINE 的開發技巧。我就以這為主軸,分享一下幾個相關的開發技巧吧。其中一個就是如何透過 pipeline 傳遞物件,另一個就是善用 LINQ 來處理 pipeline 傳來的物件。
最近工作上碰到個案子,其中一個環節需要開發 CLI (Command Line Interface) 的工具,用來處理上百萬筆的資料,處理的步驟有好幾步,希望能按照步驟獨立成數個 CLI ..。資料筆數跟處理步驟是兩個不同的維度,以開發角度當然是按照步驟來區隔 CLI,但是以執行的效能考量則是希望處理好一筆資料的所有步驟,然後再處理下一筆。我跟同事提了 PIPELINE 的作法,也簡單做了些 POC 來說明可行性,所以才起了寫這篇文章的念頭。
如果你熟悉 linux 的 shell script, 你會發現很多內建的指令都能做到這些需求,大量資料的 input / output 都透過 stdio 來進行,shell 也提供 pipe(line) 的指令,讓前一個 CLI 的 stdout, 能夠直接接上下一個 CLI 的 stdin, 就能做到像接火車這樣的串接機制。不過使用的時候很簡單,這彈性的背後,有很多平時不會留意的基礎知識,所以寫了這篇打算來介紹一下 CLI 如何透過 PIPELINE 串流(平行)處理大量資料的開發技巧 (C#)。
圖片來源: https://pixabay.com/photos/tree-landscape-field-branch-696839/
架構面試題,這系列好久沒寫了。這次來探討一下,怎麼妥善的用 RDBMS 來處理樹狀結構的做法吧。
即使 NOSQL 風行了這麼多年,現在還是有不少服務背後是用 RDBMS 在處理資料的。RDBMS + SQL 是個絕配,將資料轉成表格,加上結構化的查詢就能解決過去 80% 的問題了。不過 Tree 這種資料結構,在 RDBMS 裡面就是格格不入。幾種 Tree 的基本操作,在 RDBMS 裡面都要花些心思轉換才能夠妥善處理。例如不限定階層的儲存、查詢某個節點以下 (不限定階層) 的所有子節點,或是 Tree 的搬移、刪除等等操作都是。如果用 RDBMS 的關聯性來處理 Tree Node 跟 Node 之間的關聯,就會衍生幾個階層就需要 Join 幾次的困境 (我不可能無限制的一直 Join 下去啊)。如果搭配特殊語法 (如 T-SQL CTE), 或是用 programming language 搭配或許能夠解決, 不過你就必須在複雜度與效能間做取捨了。
我覺得這是個不錯的題目,能鑑別出你的基礎知識夠不夠札實,能否靈活運用;也能看出你是否容易被既有的工具或是框架限制住做法的測驗。這邊先不討論 tree 到底該不該擺在 RDBMS 上面處理這種議題,那是另一個層次的討論。如果背後的 storage 就限定在 RDBMS 的話,我想探討的是我們有哪些方法能夠妥善的處理他?
在今年 .NET Conf 2018, 我講了一個場次: Message Queue Based RPC, 內容就是這篇文章的前半段… Message Queue 本身的架構就容許部分服務掛掉也還能正常運作,是高可靠度 / 非同步通訊不可或缺的一環啊! 這個場次我說明了如何用 C# 把 Message Queue 封裝成 RPC, 同時支援 C# async / await 的整個過程跟細節。不過時間只有短短的 50 分鐘,要交代完整的來龍去脈實在有點困難啊,剩下的部分我就在這篇文章補完。
這類主題,拉得更高一點來看,目的其實是整合啊! “架構師” 在這幾年變成技術職的終極目標,不過軟體業的市場還很年輕,市場上有經驗的架構師也不多啊,很多文章都在談論架構師到底該做些什麼事? 其中有一點很多文章都有提到,就是 “技術選型”。架構師應該用他的專業及經驗,替團隊挑選一個符合現況及將來發展的技術。這句話並沒有錯,不過我看過幾個例子,都沒有做到位;因為選完之後,下一步就是要應用啊! 成熟的服務或是框架,在現在的時空背景下其實不是個大問題,但是每個團隊面臨的商業需求,歷史包袱,團隊組成狀況等等都不同,很難有哪一套服務或是框架可以適應所有情況的。因此你做完技術選型後,下一個難題是將這些技術 “整合” 起來給團隊使用。
這就是我這篇文章想要表達的;我們挑選了 RabbitMQ 當作我們服務背後的 Message Queue, Message Queue 掌控了可靠的通訊核心, 非同步的通訊,到 CQRS, 到 Event Driven 事件驅動, 訂閱 / 通知 等類型的通訊都需要靠他,我期望內部團隊能發展出一套體系,能將這些機制串在一起。這些機制整合的好,團隊的能力就能往上提升一個檔次。既然整個體系,是架構師規劃出來的,該如何 “整合”,自然是架構師最清楚其中的關鍵了。我一直期望我對團隊的貢獻不只是紙上的規劃而已,而是能真正融入開發,從 code 層面就能幫助團隊提升。因此這篇我就打算從 Message Queue 幾個應用場景切入,示範一下從架構的角度,該如何看待 Message Queue 的整合這件事?