當技術重構遇上 DDD
- 困境:項目背景
愛番番溝通基於百度商橋快速完成了產品功能和技術架構的從無到有,但同時也繼承了百度商橋歷史功能繁雜、技術架構陳舊的缺點。爲了能更好地服務於愛番番溝通將來的產品演進,提高產研能效,需要從實際問題出發,聚焦主要矛盾,對產品架構和業務架構進行重構。
爲了更好的理解本文內容,以下是必要的名詞解釋:
1.1 愛番番溝通是什麼?
愛番番溝通是連接訪客和商家的在線諮詢工具。一方面訪客可以隨時隨地諮詢,縮短訪客獲取服務的途徑,另一方面商家也可以快速響應並提供服務。同時在推廣場景中,商家還可以根據訪客的諮詢內容反哺回上游廣告通路,優化投放模型,提升營銷轉化效果。
1.2 爲什麼要重構?
百度商橋經歷了幾次不同的產品定位和多年版本迭代,產研團隊也換了幾波人。客戶問題較多,架構長期缺乏系統性治理。給產研團隊帶來多個層面的掣肘:
-
團隊內對產品的主要業務邏輯沒有知識儲備。經常需要研發去翻閱項目代碼東拼西湊出現有邏輯的大致模樣。
-
客戶反饋問題數量居高不下,典型問題如:
-
訪客進站識別不及時,客服感知不到訪客已進站。訪客離站識別不及時,容易誤導客服向離站的訪客繼續發起溝通,引發溝通不暢的表象;
-
訪客的廣告相關信息(來源、搜索詞、關鍵詞)獲取不及時、不完整;
-
訪客全生命週期內的行爲數據有概率性延遲和缺失;
-
商家歡迎語、自動回覆發送順序錯亂,不觸發發送等;
-
服務穩定性引起的登錄失敗,消費發送失敗、移動端消息提醒不及時等;
-
還有一部分客戶問題屬於新需求範疇,比如諮詢組件樣式靈活定製、支持離線溝通。
-
團隊士氣低落,生產力不高。疲於應對救火問題,難以承接較大功能需求開發。
-
現有架構陳舊,模塊繁雜,長期缺乏治理。模塊數量和人員規模失配,小需求可能涉及多個模塊改動。存在大量陳舊代碼,只能不停地進行『打補丁』方式修復問題。
-
反思:定義問題和挑戰
面對當前困境,整個產研團隊都意識到了需要儘快做出改變。透過現象找本質,上述現象背後的關鍵問題是什麼呢?又會面臨哪些挑戰呢?
2.1 定義問題
通過進一步分析問題的根本原因,可以把問題分爲以下幾類:
【產品層面】產品方向及定位不明確,功能層級及分類不清晰
-
產品演進方向不清晰,業務領域主次不清,各模塊的業務主路徑不清晰。平時開發都是堆砌功能,導致不少業務場景存在使用體驗的卡點;
-
由於歷史原因系統支持的角色冗餘且複雜,既有平臺型角色比如支持百度顧問和商家直接溝通。又有 B 端其他角色比如支持銷售直接查看線索;
-
從 PC 時代到移動時代,但是產品還保留着一些歷史兼容的痕跡。比如常用語是按照 PC 和移動進行一級分類,站點樣式類型只能設置一個端。
舊版客戶端界面示例
【架構層面】客戶端架構多年未演進,功能迭代難以爲繼
-
客戶端僅支持 Windows 系統且架構一直未演進,技術棧基於 C++,和團隊主要技術棧偏離,只能艱難維護,無力承接新功能需求。迫切需要演進爲能跨平臺、主流的、前端技術棧;
-
訪客側前端還未做到前後端分離架構,體驗和開發效率大打折扣。
【架構層面】服務端架構的基礎溝通層待演進
溝通協議層作爲溝通產品非常重要的一環,還存在架構方面的不足:
-
多種網絡連接協議下的穩定性需提高;
-
和不同端的消息發送性能需提高。
【架構層面】服務端架構的業務層待演進
業務層包含 20+ 服務模塊,主要的業務邏輯採用共享庫的方式維護,導致模塊邊界不清,數據鏈路混亂,功能重疊耦合嚴重,迫切需要演進爲主流微服務架構。
-
模塊內職責不夠內聚,模塊間調用關係耦合高;
-
同樣的數據存在多份存儲,數據一致性存在問題;
-
數據流的同步異步傳輸鏈路混亂。
【架構層面】整體服務端架構自運維成本高,可維護性很低
歷史遺留系統中需要運維多種自運維中間件,導致團隊不能聚焦業務功能開發。既降低了研發生產力,也給系統穩定性帶來巨大挑戰。
-
自運維了反向代理 Nginx 集羣、Zookeeper 集羣、Storm 集羣、Kafka 集羣、Solr 集羣、Prometheus 集羣;
-
離部門的主服務端集羣面向雲原生的服務治理架構還有不小差距。
【組織層面】產研團隊整體對業務的理解不夠且未拉齊
-
業務架構和研發架構長期脫鉤,導致團隊對大到溝通行業小到具體某個模塊的領域知識沉澱缺乏,迫切需要在產研層面拉齊現有認知;
-
在團隊達成共識的基礎上將來才能形成隨產品快速演進從而快速迭代領域認知的正向循環。
2.2 認清挑戰
歸因清楚問題後,重構的方向逐漸清晰起來。但執行落地階段也會面臨着業務演進壓力,原架構基礎薄弱,資源短缺等挑戰。
架構陳舊,代碼裏有不少隱蔽的『坑』
從以往經歷看,有時候一個很小的改動,看起來很有把握的一次上線也可能造成客戶問題。一方面代碼中缺乏設計的地方多,另一方面整體迴歸測試覆蓋不全。組內自嘲這種狀態爲『每一行代碼都剛剛好』,不能多也不能少。
重構和業務演進既要又要
這個挑戰是大部分團隊都會遇到的,業務不可能停止演進等待技術重構。如何能在不影響已有業務且保證部分高優業務需求正常迭代的情況下進行重構是必須要回答的問題。
不能僅僅是重構,客戶可感知的體驗要更好
涉及客戶端架構升級,必然會帶來一些新的用戶體驗,需要管理好存量用戶的預期。本次重構範圍大,產品質量不下降既是要求也是挑戰。
產研團隊較新,對原有業務功能缺乏足夠了解
業務研發團隊很依賴領域專家的業務知識指導,子領域間和模塊間的職責和邊界劃分,數據歸屬等理解需要建立在業務理解的基礎上。這些對現有團隊是個不小的挑戰。
因此,抓主要矛盾,分階段小步快跑是本次重構的基調。
- 紓困:解決問題
僅僅從技術層面做重構只能解決眼前的技術問題,隨着業務快速迭代,純技術重構的成果很容易消失殆盡。考慮到需要對業務和技術層面雙管齊下做出改變,在現有複雜業務基礎上仍能保持高效的產研交付效率,加上隔壁兄弟團隊之前在線索管家產品已經收穫了 DDD 改造的收益,因此本次技術重構決定結合 DDD 來做,從產品到技術來一次認知升級、架構升級。
3.1 定位:確定產品方向及核心痛點
產品定位及差異價值
產品定位:選擇『不做什麼』更加重要
-
聚焦在售前接待場景,幫助商家獲取聯繫方式,不做售後服務場景;
-
聚焦在廣告營銷場景,幫助廣告主接待推廣流量並優化效果;
-
由於是 ToB SaaS 模式,所以暫時聚焦企業客戶需求,不做平臺型針對企業的上層需求。
產品使用角色:誰是我們的用戶?
- 聚焦在 B 端客服角色。剝離其他角色相關功能,比如跟進線索的名片功能歸到線索管家模塊(銷售角色),反哺功能歸到 oCPC 反哺模塊(SEM 角色)。
差異化價值:客戶爲什麼會選擇我們?
-
全鏈路閉環:從推廣開始到訪客進站、對話、留資,直至標記會話反饋 oCPC 目標,全程無縫銜接;
-
與線索管家結合:智能識別會話和留言板中的線索信息,自動沉澱至線索管家,有效節省線索梳理工作;
-
智能營銷:訪客意圖智能分析識別,千人千話引導訪客開口留資;
-
多端共用:支持 Web、App、PC 端同時使用,隨時隨地實現溝通。
3.2 分析:識別核心領域和模塊,拆解業務邏輯
3.2.1 事件風暴:剖析流程和對齊認知的好幫手
針對主要業務流程,產研團隊通過事件風暴的方式梳理了事件流,定義了每個事件相關的角色、動作、規則條件和事件結果。最重要的是對齊了團隊的業務認知,靠集體智慧剖析了整體業務細節。
3.2.2 邊界是合作的基礎:劃分領域和模塊,形成統一語言
根據產品定位及產品價值分析,結合梳理好的業務流程,需要劃分子領域,相應配比合適的資源投入。
【核心域】
-
訪客域和客服域屬於核心域比較自然,同時作爲底層的基礎能力,協議連接域包括 tcp、websocket、http、long polling 協議,協議報文格式,連接狀態維護等也應該是核心域。其次會話域也是核心域,互發消息纔算進入真正溝通,會話內容裏的意圖表達和留資纔是溝通的主要目的;
-
核心域的策略是圍繞產品價值,重點投入資源。儘可能把非核心功能從核心域剝離,警惕容易引起團隊失焦的投入。
【支撐域】
-
數據分析域是必要的功能但目前還不是重點,線索域對溝通來說是後鏈路必經環節,但應該更多利用愛番番線索管家的能力。廣告域包含訪客推廣信息解析,會話效果反哺,照理是核心能力。但這裏劃爲支持域是因爲關鍵的能力在搜索團隊已提供,溝通團隊做好數據接入和數據供給工作;
-
支撐域的策略是儘可能以較少資源建設必要能力。當然,隨着業務的發展支撐域也可能在未來變成核心域。
【通用域】
-
賬號權限功能是大多數系統的通用能力。訪客場景屬於 ToC 場景,會遇到黑產流量攻擊,包括訪客進站和訪客發送消息需要引入風控反作弊能力。愛番番溝通主要藉助了愛番番策略團隊和廠內安全部的能力;
-
通用域的策略是儘可能不親自建設系統,藉助外部能力快速完成能力建設。
3.3 架構:搭建整體技術架構
架構目標及設計要點
-
根據流量南北向把各種服務按照職責類別分爲多個層次,用戶界面、接入網關、業務前後臺、溝通協議連接等 5 層由溝通團隊建設維護,底下基礎服務和存儲層主要藉助基礎技術能力。分層建設能夠定義服務不同等級、高效使用團隊研發資源、承接不同流量類型(實際用戶流量、後臺用戶流量、異步調用流量、定時任務流量等)、簡化請求涉及的數據鏈路、根據層次不同建設非功能性需求(技術棧選擇、熔斷限流、彈性伸縮等)。
-
技術架構匹配業務架構。服務模塊邊界符合業務邊界。核心服務內需設計領域模型,圍繞領域層和應用層構建業務邏輯,搭建 DDD 四層分層架構,做到領域模型和技術細節分離,不穩定實現依賴穩定實現。
-
符合典型微服務架構。服務職責內聚,服務和數據一體。數據歸服務私有,服務間不共享業務邏輯,服務間通過 API 或領域事件進行協作。
-
數據架構合理。儘可能採用數據最終一致性策略。每種數據非必要不多處存儲,多處存儲須有最終一致性方案保證。涉及 nosql 類存儲如 Redis、HBase、ES(Elastic Search) 時,防止大 key 造成分片不均,業務數據按需進行分庫分表存儲。
3.4 突破:架構設計的關鍵技術
3.4.1 落地真正的微服務架構
隨着子領域和模塊的劃分確定後,需要調整對應的模塊職責及模塊間協作關係進行改造,重點改造點包括:
合併老模塊
改造前服務端有 45 + 服務模塊,服務職責劃分不當,服務粒度不合適。具體表現爲:
-
有些功能粒度太細,徒增維護成本,可以合併。
-
某些類似功能散落在多個服務,比如 5 個模塊都有提供訪客相關信息查詢,可以合併。
-
有些服務隨着老客戶端的升級,功能改造後更合適合併到其他服務,原服務可以下線。
-
反向代理層職責劃分不合理導致服務集羣太多,絕大部分可以遷移至公司級的 BFE 進羣,少數包含很多 lua 邏輯 Nginx 集羣暫時保留,但可以合併。
經過合併下線改造後,服務數量減少了 15+。
拆分新模塊
有些功能很重要,需要形成獨立的模塊重點建設。比如:
-
訪客廣告信息解析服務。廣告信息對於客服刻畫訪客畫像,理解訪客非常重要。但之前的解析邏輯散落在多個模塊且實現不統一,解析準確率不高,沒有足夠的補償策略保證必要的解析成功率。
-
機器人智能回覆服務。這也是產品定位的一個差異化價值。爲了讓客服更高效接待訪客,引導訪客多留資,這塊的產品演進越來越多,複雜度也隨着加大。
-
線索服務。這裏的線索服務是愛番番溝通和線索管家產品的邊界,主要是針對會話內容或者留言內容提取聯繫方式,然後通過接口或事件的方式流轉到線索管家,同時也要形成諮詢到線索的閉環數據。
模塊間不共享業務邏輯
改造前的後端業務服務不是真正的微服務,雖然都是獨立部署,各自暴露接口,但服務實現層耦合嚴重:
-
通過公共庫( 即 java 的 jar 包 )共享業務邏輯。同一段業務代碼被多個業務服務依賴,既降低了代碼可維護性,也降低了服務的可測試性。
-
通過緩存( Redis )傳遞數據。一個 redis key 經常既有多個服務在寫入,也有多個服務在讀取。
-
通過 DB 共享數據,直接讀取屬於其他服務職責的數據表。
改造原則:不共享包括業務邏輯的公共庫,讓微服務垂直劃分,相關業務數據(包括緩存數據)歸服務私有,通過 API 接口提供能力,或者通過領域事件推動下游流程。
最終一致性前提下的高可用性
可用性的關鍵手段是數據複製。可以藉助不同的數據同步方法,結合不同特點的存儲類型完成多樣化業務場景的高可用性。常用的數據複製 / 同步手段有:
-
發佈 / 訂閱模式:上游服務利用消息隊列把相關數據以消息爲載體發,下游服務訂閱該消息並做相應的持久化。整個溝通服務端在大量使用這種方法,也是服務解耦的一大利器。
-
CDC 模式( Change Data Capture ):簡單說就是通過監聽 MySQL 的 binlog 感知到上游服務的數據變化(包括新增、更新、刪除),解析日誌並做一些處理(比如關聯表查詢等)後發送到消息隊列,下游按需訂閱處理。
CDC 模式和發佈訂閱模式配合使用能滿足很多場景,分離讀寫服務和選取異構存儲介質。比如訪客進站記錄寫入 MySQL 和訪客歷史記錄查詢 ES,會話寫入 Table 和會話分析服務查詢 Doris 。即能有效滿足各自場景的數據存取需求也能提高場景的可用性。
當然,這種可用性往往會犧牲一定時效性內的數據一致性,需要根據實際業務場景做出權衡。根據經驗判斷在馬上得到答案和得到正確答案之間,大多數人更想要的其實是馬上得到答案。
3.4.2 數據鏈路治理
改造前主要場景包括進站、離站、自動回覆、會話內容校驗、線索識別、結束會話等的數據流的必經節點是實時計算服務,其核心實現是 storm,但因爲多種原因該集羣很不穩定,會引發出上述提到的大量客戶問題。深層分析現狀主要有以下弊端:
-
storm 拓撲設計不合理,拓撲節點職責不清;
-
拓撲節點中存在大量的業務邏輯,普遍利用 redis 傳遞數據,redis 鍵設計混亂,可維護性很差;
-
storm 集羣是幾年前引入的,版本低,一直沒升級。
經過分析業務需求,只升級 storm 集羣版本不會解決實際問題,另外實時計算框架在現階段不是必須項,因此得出了以下改造思路:
-
去除這個集中式的計算集羣,按業務場景梳理各自數據流,避免互相干擾。讓對應業務服務模塊承接業務邏輯,如需提高業務響應可通過緩存集羣加速;
-
服務模塊間儘可能通過異步方式( kafka 消息隊列 )傳遞數據,目前消息隊列也能達到近實時效果,同時增強消息隊列的災備功能和訂閱情況監控;
-
訪客一段時間不說話需要自動回覆等延時場景通過延時任務的方案解決;
-
redis key 重新梳理,優化大 key( 一個 key 承載的內容特別大,比如一個 key 就包含全系統訪客的部分信息,這樣的 key 設計顯然太大 ),儘量不跨服務模塊直接操作 redis。
業務程序的靈魂是數據,技術架構時要多花時間考慮數據存儲和讀取的方方面面。比如用什麼存儲系統( 存儲系統不可能讀也最快,寫也最快,需要權衡 )、什麼時候用緩存,整個業務流程的數據傳輸鏈路應該怎麼樣,溝通系統涉及到很多寫放大還是讀放大的權衡等等。本次重構也涉及到了這些方面的梳理和改造,在此不一一介紹。
3.4.3 溝通協議優化
爲什麼要做協議優化?
針對 1.2 章節中提到的客戶端上經常出現丟訪客,消息不上屏等問題,簡單的打補丁方式已經難以將問題徹底解決,因此必須從協議層進行徹底的改造優化。詳細痛點如下:
-
現有協議缺乏魯棒性,從協議層面埋藏着隱患。一個事件(如進站、建立溝通、離站)需要多個包來完成交互,如果一個訪客操作頻繁,訪客狀態也會頻繁做變更,很容易出錯。
-
富客戶端模式,端上維護了過多的狀態信息,過度依賴推送包的順序,而且缺乏容錯、自恢復恢復機制,容易出現訪客不展示,消息不上屏等問題。
如何優化?
-
通知模塊採用分佈式鎖控制併發,併爲報文增加 SeqId 來確認早晚順序,爲客戶端提供判斷依據。
-
優化狀態協議,簡化掉動作通知類報文,採用以訪客狀態爲主的報文,如下圖所示,將動作報文簡化掉,只保留狀態報文,報文數量減少約 60%,降低客戶端處理複雜度,減小出錯概率。
-
客戶端側,由 socket 長連接改爲爲 http + socket 推拉結合的方式,當斷網重連、或者報文丟失、錯亂時,則客戶端主動拉取最新狀態,徹底接解決訪客狀態不對,消息不上屏等問題。
猜你想問:
1、上面提到分佈式鎖控制併發,會因鎖競爭而增加請求處理時間嗎?
答:鎖粒度爲單個訪客粒度,粒度足夠小,而且同一個訪客在快速操作( 如頻繁快速打開頁面、發起溝通 )時,纔會出現鎖競爭的情況,對單訪客來說,常規的操作併發不大。
2、既然協議優化收益這麼搞,爲什麼不早點做協議優化呢?
答:之前受限於業務邊界劃分不清晰,訪客狀態變更散落在業務前臺、業務後臺、原 storm 集羣多個地方,無法做統一管控。只有在完成了前期建構優化、數據鏈路治理完成之後,站在原有的工作成果至上,才能做協議優化。
3、客戶端的推拉結合爲什麼不早點做呢?
答:如前文 2.1 中第 2 條所說,客戶端技術棧基於 C++,只能艱難維護,無力承接新功能需求。因此想改動客戶端的協議,可謂異常艱難,這也是下文 3.5 章節客戶端架構升級的一大原因。
小結
-
訪客、客服、會話管理模塊的 DDD 改造。
-
由貧血模型改爲富血模型,通過狀態機控制狀態變更。
-
客戶端請求以 http 爲主,同步得到返回值,降低出錯概率。socket 主要用於給端上的通知。
-
協議包簡化, 以訪客狀態維度進行交互,極大減少包的數量。
3.4.4 去除自運維中間件
如前面所述由於歷史技術棧原因愛番番溝通團隊內部運維了好幾種中間件,先不說引入這些中間件的正確與否,現狀是沒有足夠知識儲備,既給系統帶來了很多不穩定因素,也降低了團隊的研發效率。因此本次重構在這個方面的改造原則是優先考慮下線架構中不必要的中間件,必要的中間件也不另行維護,遷移到部門基礎技術團隊運維。
集羣改造下線
-
Zookeeper 集羣:改造前主要用來做業務配置中心,遷移到 k8s 更友好的 ConfigMap( 由基礎技術團隊運維 );
-
Nginx 集羣:改造前有好幾套反向代理集羣,其中既有路由轉發邏輯,也有業務邏輯。業務邏輯下沉至對應的 gateway 服務,由團隊維護。路由轉發邏輯遷移至 bfe 集羣,由基礎技術團隊統一運維;
-
Storm 集羣:邏輯改造,下線。細節上面已交代;
-
Solr 集羣:下線,相應查詢邏輯改造遷移至 ES 集羣。
集羣遷移
此部分集羣雖然不能下線,但團隊內不另行維護,轉而遷移至部門集羣。包括 Kafka 和 Prometheus 集羣。
3.5 擴展:客戶端架構實踐
3.5.1 客戶端跨平臺架構
隨着原客戶端維護代價越來越大,結合客戶對 mac 端的訴求,因此選擇了跨平臺的 Electron 框架。
爲什麼選擇 Electron ?
-
開源的核心擴展比較容易。
-
界面定製性強,原則上只要是 Web 能做的它都能做。
-
是目前最廉價的跨平臺技術方案,HTML + JS 的技術儲備,而且有海量的現存 UI 庫。
-
相對其他跨平臺方案( 如 QT GTK+ 等 ),更穩定,bug 少, 只要瀏覽器跑起來了,問題不會太多 。
-
方便拓展,可以直接嵌入現有 web 頁面。
Electron 系統架構
愛番番前端團隊的技術棧是 Vue,所以我們選擇使用 Electron-Vue 來搭建項目。Electron 有兩個進程,分別爲主進程( main )和渲染進程( renderer )。主進程中包含了客戶端自動更新、插件核心、系統 API 等。渲染進程是 vue + webpack 的架構,兩個進程間通過 ipc 進行通信。
愛番番客戶端主要是 IM 業務,所以通信方面使用 websocket 來進行消息通知,由於客服發送消息包含樣式設置,所以傳輸內容包含富文本,這樣就很容易引起一些 xss 問題。我們使用 xss 白名單的方式來過濾 xss 攻擊,並且所有內容都會通過策略過濾,攔截黃反等不良文本。
愛番番溝通考慮到今後能更靈活地接入更多業務垂類並且支持第三方自主開發個性化功能。同時需要兼顧平臺代碼的穩定性和易用性,我們採用了插件化架構的方式來實現客戶端。
開發中遇到的問題
Electron 帶來很大便利的同時,其本身也有很多硬傷。如常被人吐槽的內存佔用高、和原生客戶端性能差異、API 系統兼容性問題等。這些問題在開發過程中需要提前考慮到。下面是開發過程中必然會遇到的幾個問題。
1、性能優化
性能優化是在開發完需求功能後經常需要考慮的。在 Electron 中,最好的分析工具就是 Chrome 開發者工具的 Performance ,通過火焰圖,JS 執行過程的任何問題都可以直觀的看到。
2、Window7 系統下白屏問題
因爲在測試過程中 QA 同學使用的一直都是 Win10 的系統,所以白屏問題一直沒有被發現。直到客戶端正式上線,白屏問題被集中反饋,至此我們開始重視白屏問題並積極解決。
由於我們使用的 electron 版本是 9.x 的版本,該版本下默認開啓 GPU 加速,但是 Win7 下啓用 GPU 加速需要管理員權限,如果沒有管理員權限去執行的話進程就會卡住,導致首頁白屏。所以解決此問題方法就可以從兩方面解決,第一是開啓管理員權限,第二是關閉 GPU 加速。考慮到客戶端使用的人羣大部分是客服,公司電腦配置較低且一般沒有管理員賬號權限,所以我們選擇通過關閉 GPU 加速( app.disableHardwareAcceleration() )來解決次問題。
3、其他問題
在 Electron 開發過程中還要注意一些常見問題。如讀寫文件的編碼問題,客戶端安全問題存在 rce,可被任意執行命令,內存使用率過高問題等。
3.5.2 微內核 / 插件化架構
什麼是插件化架構
插件化架構就是軟件本身只提供插件運行時的核心( pluginCore ),併爲插件運行時提供訪問的接口( pluginAPI ),通過插件平臺下載插件( plugin )後可以在軟件上完美運行。
最基本的例子就是 webpack,作爲主流的構建工具,webpack 只抽象了一個軟件運行時的環境,在不關心和改動這個系統已有的代碼前提下,卻能獨立開發新的插件來充實整個系統的能力。
pluginCore: 插件運行時核心;pluginAPI:爲插件運行提供訪問接口;plugin:實現具體功能的插件。
插件化架構優勢
插件化架構是開閉原則在跨系統級別的最佳實踐。在插件核心和接口不變情況下,系統可以持續接入新插件,來豐富系統的功能。在一個非插件化的系統中,隨着功能模塊的增多,代碼量激增,在引入新功能和修復 BUG 都會越來越困難和低效。但插件化架構不管已有系統功能多複雜,開發新的功能的複雜度始終一樣。而且隨着系統的平臺化,第三方接入差異化功能也不會影響系統的穩定性。
愛番番插件化現狀
爲了滿足其他第三方平臺的定製化需求,如電商平臺的商品及訂單模塊,CRM 平臺的客戶模塊,售後場景中的評價模塊,愛番番客戶端的插件化架構的設計要點:
-
插件化架構方案
-
提供兩種接入方式:JS-SDK 接入、Webview 方式嵌入。
-
第三方插件與愛番番客戶端存在兩種通信機制:事件廣播、實例注入。
-
番番客戶端插件分類:左側菜單插件、會話工具欄插件、會話側邊欄插件。
-
插件配置文件說明:
{
"version":"0.0.1", // 版本號
"id":"demo-name", // 綁定事件ID
"name":"組件名稱", // 插件名稱
"viewUrl":"", // 如果是菜單插件需要提供webview地址
"target":"toolbar", // menuList——菜單插件、toolbarList——溝通區插件、infoList——右側工具欄插件
"dependent": {
"method": [],
"version":"1.0.6" // 依賴客戶端版本
}
}
- 歡喜:解決效果
4.1 產品架構升級
新客戶端設計原則:
-
按照 DDD 原則,來定義菜單模塊並抽象功能層級;
-
結構對比老版層級更加清晰,功能擴展性更強;
-
容器變更並重新定義,釋放核心會話功能的區域;
-
三端( Mac + Win + Web )合一,共用一套產品設計,操作靈活便捷。
4.2 客戶體驗提升
遷移後,我們對新客戶端的使用客戶進行了回訪,除了需求的反饋,也收到了一些肯定:
4.3 產研效能大幅提升
技術爲產品服務,產研共同創造業務價值。產研效能是技術重構的首要目標。可以通過兩方面衡量效果。
需求的整體交付速度
- 就像敏捷迭代的精髓不是看交付過程的單點效率,而是看發現需求到需求上線的整體效率。這也是通過 DDD 帶給這次技術重構的最大價值。經過需求和業務的分析、設計、實現等環節,讓產品、設計、研發整個團隊的磨合和對業務的理解提升到新的高度,輔助以合理的技術架構,能整體提升需求交付效率。
技術研發效率
-
直接體現是更少的人支撐更大的產品範圍。以前技術研發 12 人,現在 7 人;
-
間接體現是代碼維護成本大大降低,服務模塊數量和團隊人數比例協調,模塊職責和協作關係明確,接口設計質量高,代碼規範度高,新人上手速度快。
4.4 產研效能大幅提升
4.4.1 系統穩定性
直接體現是前面交代的高頻技術穩定性問題如訪客進站識別不及時、自動回覆不觸發等已得到全面的治理,各系統模塊穩定性指標長期維持在 99.99%。
4.4.2 可維護性
代碼維護成本大大降低,架構在不同層面更具維護性:
-
服務模塊數量和團隊人數比例協調;
-
模塊職責和協作關係明確;
-
業務數據流流轉鏈路清晰;
-
項目代碼結構規範、易懂。新人上手速度快;
-
接口文檔在線化。
4.4.3 可演進性
愛番番溝通系統的潛在可演進方向很多,有些方面已做好設計預留,比如:
-
更多溝通格式:已和業務系統解耦,很容易增加溝通內容格式如視頻、語音等;
-
更多連接形式:目前已支持包括 http、tcp、websocket、long polling 等推拉形式協議,幾乎滿足了絕大部分場景;
-
;更多業務類型接入:基礎溝通能力已有開放能力,可利用 api 方式低成本接入
-
溝通功能的持續演進:比如更智能化、和線索管家更無縫集成、更強的風控能力,這些需求可按需建設相應業務模塊,獨立演進。
- 成長:經驗總結
通過這次重構團隊經歷了從困境到反思的痛苦過程,相應地也獲得了組織、技術、人等層面的成長。
組織
-
產研團隊聚焦到創造業務價值,從能解決客戶問題視角開展日常工作;
-
產研協作效率更順暢,基於統一語言溝通需求和設計;
-
在業務迭代過程中沉澱了領域知識。
技術
-
技術問題的答案往往要從業務中尋找答案,理解業務是開展技術的前提。不同業務帶來不同的技術訴求,適配的技術纔是最好的,也是先進的;
-
經過重構的架構能適配當前業務發展,研發能把絕大部分精力放在業務實現上,屏蔽了日常開發的很多噪音。
人
-
通過本次重構提高了每個成員對溝通業務的全方位熟悉。既有自身業務的全貌,也有行業友商的演進現狀,對未來演進方向有了對齊;
-
在瞭解技術架構的來龍去脈和全貌基礎上,讓每個業務研發能聚焦建設自己負責的模塊。通過 DDD 實踐提升自己的應用架構水平,提供了技術進階的新方向,發揮出模塊負責人的主觀能動性。
- 星辰:未來展望
目前的愛番番溝通由於進行了重新定位,方向更加聚焦,但同時也面臨着很多方向性的選擇。如:面對不同的上游場景以及不同的推廣平臺,後續的接入能力是否需要更加強大。智能機器人有些場景下的策略模型沒有保持持續迭代更新,是否需要往智能化方面更進一步。
技術架構的規劃首先應該圍繞業務訴求展開,除此之外會繼續向雲原生演進,增加容量評估、全鏈路壓測、流量治理等能力。比如近期計劃把底層基座從 K8s 式微服務治理升級成服務網格,對齊愛番番主集羣能力,便於以後能更好地複用基礎技術平臺的能力。同時進一步降低多開發語言下的統一服務治理成本( 接入層和協議連接層的服務是 golang,業務服務是 java )。
在未來,如何做到「既要好,又要不同」愛番番溝通產研團隊依然還有很長的路要走。
7. 作者介紹
本篇系愛番番溝通產研團隊多位同學共同編寫。
-
飛邪:架構師,擅長通過微服務架構和 DDD 落地複雜系統;
-
堅果:產品經理,擅長 ToB SaaS 及廣告產品;
-
甯甯:一個和商橋、在線溝通有不解之緣的產品經理;
-
小麥:資深前端工程師,在光速演進的前端領域內苦苦掙扎的 FE;
-
flyme: 資深研發工程師,擅長通過改進技術方案來應對複雜多變的業務場景。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/_ggIPOvB-ptBanbqqKULxQ