分布式场景实战第七节 微服务场景实战
18 如何處理好微服務之間千絲萬縷的關系?
17 講講解了服務間數據依賴的場景,除了這種場景之外,其實我們還會碰到服務間依賴太雜亂的場景,這一講我們將圍繞這個場景進行討論,還是先把整個場景描述一下。
業務場景(架構經歷十四)
在我們之前設計的一個供應鏈系統中,它包含了商品、銷售訂單、加盟商、門店運營、門店工單等服務,涉及了各種用戶角色,比如總部商品管理、總部門店管理、加盟商員工、門店人員等,而且每個部門的角色還會進行細分。而且這個系統中還包含了兩個客戶端 App:一個面向客戶,另一個面向公司員工和加盟商。
此時,整個供應鏈系統的架構如下圖所示:
圖 1
上圖中的網關層主要負責路由、認證、監控、限流熔斷等工作。
-  
路由: 所有的請求都需要通過網關層進行處理,網關層再根據 URI 將請求指向對應的后臺服務,如果同一個服務存在多個服務器節點,網關層還將承擔負載均衡的工作。
 -  
認證: 對所有的請求進行集中認證鑒權。
 -  
監控: 記錄所有的 API 請求數據,API 管理系統能對 API 調用實現管理和性能監控。
 -  
限流熔斷: 流量過大時,我們可以在網關層實現限流。如果后臺服務響應延時或故障,我們可以主動在調用端的上游服務做熔斷,以此保護后端服務資源,同時不影響用戶體驗。
 
此時,我們的架構看起來是不是挺完美?且市面上標準的 Spring Cloud 架構都是這樣做的。不過,這個架構會出現一些問題,下面我們先通過幾個例子來看看。
案例一:
在這個供應鏈系統中,很多界面都需要顯示多個服務數據,比如在一個 App 首頁中,針對門店運營人員,需要顯示工單數量、最近的工單、銷售訂單數據、最近待處理的訂單、低于庫存安全值的商品等信息。
此時第一個問題來了,在接口設計過程中,我們經常糾結將兩個客戶端 App 調用的接口存放在哪個服務中?以至于決策效率低下,而且還會出現職責劃分不統一的情況。
最終我們決定將第一個接口存放在門店服務中,此時調用關系如下圖所示:
圖 2
并將第二個接口存放在工單服務中,此時調用關系如下圖所示:
圖 3
案例二:
一個用戶的提交操作常常需要修改多個服務數據,比如一個提交工單的操作,我們需要修改庫存、銷售訂單狀態、工單等數據。
此時第二個問題出現了,因為這樣的需求非常多,所以服務經常被其他多個服務調來調去,導致服務之間的依賴非?;靵y,最終服務調用關系如下圖所示:
圖 4
通過上圖,我們發現服務間的依賴問題給技術迭代帶來了地獄般的體驗,關于這點我們已經在 15 講中進行了細致講解,這里就不過多贅述。
為了解決這 2 個問題,最終我們決定抽象一個 API 層。
API 層
一般來說,客戶端的接口需要滿足聚合、分布式調用、裝飾這三種需求。
-  
聚合:一個接口需要聚合多個后臺服務返回的數據,并將數據返回給客戶端。
 -  
分布式調用:一個接口可能需要依次調用多個后臺服務,才能實現多個后臺服務的數據修改。
 -  
裝飾:一個接口需要重新裝飾后臺返回的數據,比如刪除一些字段或者對某些字段進行封裝,然后組成客戶端需要的數據。
 
因此,我們決定在客戶端與后臺服務之間增加一個新的 API 層,專門用來滿足上面的三點需求,此時整個架構如下圖所示。
圖 5
從圖中我們發現,所有請求經過網關后,全部交由一個共用的 API 層進行處理,而該 API 層沒有自己的數據庫,它的主要職責是調用其他后臺服務。
通過這樣的設計方案后,以上兩個問題就得到了很多地解決。
-  
應該將某個接口放在哪個服務的糾結次數減少了: 如果是聚合、裝飾、分布式的調用邏輯,我們直接把它們放在 API 層。如果是要落庫或者查詢數據庫的邏輯,目標數據在哪個服務中,我們就把數據和邏輯放在哪個服務中。
 -  
后臺服務之間的依賴也大幅減少了: 目前的依賴關系只有 API 層調用各個后臺服務。
 
此時,我們的設計方案完美了吧?別高興得太早,還會出現新的問題。
客戶端適配問題
在這個供應鏈系統中,一系列的接口主要供各種客戶端(比如 App、H5、PC 網頁、小程序等)進行調用,此時的調用關系如下圖所示:
圖 6
不過,這種設計方案會存在 3 個問題:
-  
不同客戶端的頁面細節的需求可能不一樣,比如 App 的功能比重大,就會要求頁面中多放一些信息,而小程序的功能比重小,同樣的頁面就會要求少放一些信息,以至于后臺服務中同一個 API 需要針對不同客戶端實現不同適配;
 -  
客戶端經常需要進行一些輕微的改動,比如增加一個字段/刪除一個字段,此時我們必須采取數據最小化原則來縮減客戶端接口的響應速度。而且,為了客戶端這種細微而頻繁的改動,后臺服務經常需要同步發版;
 -  
結合 #1 和 #2 我們發現,在后臺服務的發版過程中,常常需要綜合考慮不同客戶端的兼容問題,這無形中增加了 API 層為不同客戶端做兼容的復雜度。
 
這時該如何解決呢?我們就可以考慮使用 BFF 了。
BFF(Backend for Front)
BFF 不是一個架構,而是一個設計模式,它的主要職責是為前端設計出優雅的后臺服務,即一個 API。一般而言,每個客戶端都有自己的 API 服務,此時整個架構如下圖所示:
圖 7
從上圖可以看到:不同的客戶端請求經過同一個網關后,它們都將分別重定向到為對應客戶端設計的 API 服務中。因為每個 API 服務只能針對一種客戶端,所以它們可以對特定的客戶端進行專門優化。而去除了兼容邏輯的 API 顯得更輕便,響應速度還比通用的 API 服務更快(因為它不需要判斷不同客戶端的邏輯)。
除此之外,每種客戶端還可以實現自己發布,不需要再跟著其他客戶端一起排期。
此時的方案挺完美了吧?還不完美,因為上面的方案屬于一個通用架構。在實際業務中,我們還需要結合實際業務來定,下面我們深入說明一下實際業務需求。
前面我們列出了 5 種服務,實際上,整個供應鏈系統將近有 100 種服務。因為它是一個非常龐大的系統,且整個業務鏈條的所有工作都包含在這個系統中,比如新零售、供應鏈、財務、加盟商、售后、客服等,,這就需要幾百號研發人員同時進行維護。
因為我們共同維護一個 App、PC 界面、新零售、售后、加盟商,還有各自的小程序和 H5,所以為了實現業務解耦和分開排期,每個部門需要各自維護自己的 API 服務,而且 App 與 PC 前端也需要根據部門實現組件化,此時的架構如下圖所示。
圖 8
針對以上需求,我們如何在技術架構上進行實現呢?下面具體來看看。
技術架構上如何實現?
我們的整套架構還是基于 Spring Cloud 設計的,如下圖所示:
圖 9
下面我們簡單介紹下圖中網關、API服務、后臺服務的作用。
-  
網關: 網關使用的是 Spring Cloud Zuul,Zuul 將拉取的注冊存放在 ZooKeeper 的 API 服務中,然后通過 Feign 調用 API 服務。
 -  
API 服務: API 服務其實就是一個 Spring Web 服務,它沒有自己的數據庫,主要職責是聚合、分布式調用及裝飾數據,并通過 Feign 調用后臺服務。
 -  
后臺服務: 后臺服務其實也是一個 Spring Web 服務,它有自己的數據庫和緩存。
 
此時的方案看著很完美了,不過它會出現 API 之間代碼重復問題。此時我們該如何解決?且往下看。
如何解決 API 之間代碼重復問題?
雖然 H5 與小程序的布局不同,但是頁面中很多功能一致,也就是說重復的代碼邏輯主要存在 PC API 和 App API 中。
然而,針對重復代碼的問題,不同部門在設計時會呈現 3 種不同的邏輯:
-  
某些部門將這些重復的代碼存放在一個 JAR 中,讓幾個 API 服務實現共用;
 -  
某些部門將這些重復的代碼抽取出來,然后存放在一個叫 CommonAPI 的獨立 API 服務中,其他 API 服務直接調用這個 Common API 就行;
 -  
某些部門因為重復邏輯少,通過評估后,他們發現維護這些重復代碼的成本小于維護 #1 中的 JAR 或者 #2 中的 CommonAPI 服務,所以會繼續讓這些重復代碼存在。
 
假如某些 API 服務提供接口的出入參與后臺服務的一致,此時該怎么辦? 此時 API 服務的接口無須做任何事情,因為它只是一個簡單的代理層。
于是,有同事提出:“每次一看到這些純代理的 API 接口就不爽,我們能不能想辦法把它們去掉。”辦法倒是有幾個,我們一起來看看。
-  
網關直接繞過 API 服務調用后臺服務,不過這樣就會破壞分層,所以很快被否掉了。
 -  
在 API 服務層做一個攔截器,如果 URI 找不到對應 API 服務中的 controller mapping,就會直接通過 URI 找后臺服務并進行調用。不過這種方式將大大增加系統的復雜度,出問題時調查起來更麻煩且收益不大。而寫這些無腦代碼不僅成本低,整體的接口列表還更可控。
 
綜合考慮后,最終我們決定保留無腦的代碼。
后臺服務與 API 服務的開發團隊如何進行分工?
最后我們是這樣分工的:專門的 API 開發團隊負責 API 服務,而后臺服務需要根據領域再劃分小組的職責。
這種劃分方式的好處在于 API 團隊能對所有服務有個整體認識,且不會出現后臺服務劃分不清晰、工作重復的情況。而壞處在于 API 團隊整體業務邏輯偏簡單,長久留不住人。
總結與預告
這里我得坦誠說明一下:其實 18 講中關于 BFF 的內容只占了一小部分,我們主要講解了后臺服務的分層設計。如果你有更好的后臺服務分層設計的方案,歡迎在留言區進行互動、交流。
19 講、20 講我們將進入開發運維的模塊,一起討論如何讓開發效率更高效。
另外,喜歡本專欄的同學,歡迎分享給更多的好友看到哦。
20 一人一套測試環境:測試環境何時能釋放出來使用?
這一講我們開始講第十六次架構經歷:一人一套測試環境。這個經歷還蠻特別的,因為網上很少有人講解這樣的方案。
業務場景(架構經歷十六)
當時,我們公司的基礎設施使用的是虛擬機,且還未遷移到容器。
我們一共搭建了 3 套測試環境。之所以搭建了 3 套之多而不是只有 1 套,主要是考慮到多個并行項目同時進行時,需要實現分開測試和分開上線。而 3 套測試環境在一定程度上可以避免這些并行項目因為排隊導致延期的情況。
一般來說,研發流程是這樣的:需求宣講 ——> 接口/方案設計 ——> 功能開發 ——> 聯調 ——> 測試 ——> 預生產 ——> 上線。
在這 3 套測試環境中,有 1 套專門用于聯調,另外 2 套專門用于測試。
那么,1 套聯調測試環境夠用嗎? 答案是不太夠,因為我們經常需要排期使用。那么 2 套測試環境夠用嗎?還是不夠。這里,我講一個具體的例子你就明白了。
之前我們有一個項目已經上了測試環境,功能測試反饋沒問題后就等第三方驗收了,可是第三方的驗收拖了很久,以至于我們不得不繼續占有這套測試環境。
之后,又有一個小的迭代項目要求下周四上線,并且還有一個上百人做的超大項目剛進入測試階段,這就需要 2 套測試環境。此時測試環境立馬不夠用了,而且聯調環境都被征用了。
然后,業務方還提了一個加急需求要求本周四上線,于是出現了下面這段對話。
“我們有個緊急需求這周四要求上線,你們能不能把測試 1 讓一下?”
 “不行啊,我們這個功能需要測試一周,下周四就要上線了。如果讓給你們一天,我們就要延期一天上線了。”
 “其實是 2 天……”
 “那更不行。要不你問問 XX,他們正在做的項目周期長,應該能勻給你們兩天?!?br /> “不行吧,那個項目號稱公司第一優先級,我開不了口啊?!?br /> “不然你們就用測試 3?”
 “我哪敢啊,那個驗收項目是領導親自跟的?!?br /> “可是我們也不能延期啊,業務方都確認過很多次了,我們也跟合作伙伴談好了?!?br /> “……”
后面就是因為搶測試環境的問題,導致我們的緊急需求上不了線,有苦也沒地方說。
在實際工作中,一個組同時開展好幾個項目的情況經常發生,尤其是業務對接方比較多的小組。為此,我們決定好好解決這個問題。
解決思路
我們希望達成的目標是可以快速搭建一套新的測試環境,使用完立馬銷毀。
針對這個目標,我們的解決思路是這樣的:
-  
利用容器的特性,在幾秒內快速啟動了服務實例;
 -  
將測試環境需要搭建的服務通過容器實例部署起來;
 -  
將這些容器通過 Kubernetes 管理(編排)起來。
 
那么,這一整套測試環境都需要包含哪些服務器呢?請看下圖所示內容。
圖 1
以上就是每套測試環境中需要部署的組件。
決定使用容器靈活創建測試環境后,我們曾經對每一套容器環境是包含全部組件還是部分特定組件調研了很久。
使用過容器的開發人員都知道,在容器中部署 MQ、ZooKeeper、Redis 或配置中心是一件很簡單的事情。比如使用容器部署 Redis,我們只需要輸入如下 2 行命令就可以搞定。
$ docker pull redis
 $ docker run --name a-redis-name -d redis
而使用容器部署 ZooKeeper、MQ 的方法也是類似。不過,這里有點不一樣的是我們公司所有的中間件基本不是純潔的開源版本。比如配置中心,我們并沒有使用 Spring Cloud Config,也沒有使用 Nacos,而是使用了一個完全自研的產品(包括 MQ 和網關都是自研),它既不支持容器,也不支持單機版。而 ZooKeeper、Redis 是基于開源版本,并在服務端加了一些封裝。
此時,客戶端強制我們使用一個自定義的客戶端 SDK,且使用的中間件必須強綁定配置中心。
之前我們評估過,如果把這些中間件部署到容器中,將會出現如下 3 種情況。
-  
中間件服務端改造成本大;
 -  
客戶端的 SDK 需要進行大量的改造;
 -  
最重要的一點是會導致容器環境與其他普通環境存在很大的代碼差異。因此,就算我們在容器中測試沒問題,還需要在其他環境進行大量測試,此時容器測試環境就沒有什么意義了。
 
為此,最終我們決定在容器測試環境中只部署獨立的 API 服務或后端服務,其他組件直接重用測試環境的中間件,如下圖所示:
圖 2
基于以上設計方案,如果我們想快速部署一套獨立的測試環境,一般需要解決哪些問題?因為我們的容器測試環境復用了測試環境的一些組件,所以需要解決如下 5 個問題。
1. API 服務間的隔離
如何確保容器環境的客戶端請求到達容器的 API 服務?而非容器環境的客戶端還是正常到達測試環境的 API 服務?
原來系統是這么設計的:每一個 API 服務中都會帶一個配置項 channelID,然后客戶端每次訪問 API 時都需要帶上一個 channelID 參數。網關層接收到這個請求后,會根據 channelID 將請求匹配到對應 channelID 的 API 服務中(當然 URI 也需要匹配),此時整個隔離過程就比較簡單了。
先介紹一下具體的研發流程:每個項目都有一個 JIRA Issue,而 XXXX123 這個項目就是一個 JIRA Issue ID,我們會為每個項目單獨起一套容器測試環境,于是這個 Issue ID 自然而然地被當作了環境標識。
再回到 API 的隔離,一般來說,客戶端會把上面 channelID 放在配置文件中,等到容器測試時再打一個包,此包中 channelID 的配置值為 JIRA Issue ID 就是容器測試環境的標識。最后,我們會在容器環境打包 API 服務時,自動將 channelID 的配置值改為 JIRA Issue ID。
具體的調用請求處理過程如下圖所示:
圖 3
在圖中,我們發現網關層接收到所有請求后,會根據不同的 channelID 將請求分發到不同的 API 服務中。這樣,API 服務的隔離問題就解決了。
2. 后臺服務間的隔離
如何確保容器環境部署的服務只調用容器服務?而測試環境虛擬機的服務只調用虛擬機服務?
原本系統是這樣設計的:在打包 RPC 服務時,我們將一個環境變量 env 的值設置為容器測試環境的標識,也就是 JIRA Issue ID,比如 XXXX123。然后每個 RPC 服務注冊 ZooKeeper 時,我們將在 service 的 meta data 中加一個 tag,并設置 tag 的值為 XXXX123。之后,RPC 服務只會調用同樣 tag 的服務,什么意思呢?
比如測試環境中有 3 個 UserService,其中 1 個是測試環境的虛擬機,2 個是容器測試環境部署的 UserService,前者的 tag 為空,后兩個容器 UserService 注冊 ZooKeeper 后,它們的 tag 值分別為 XXXX123 和 XXXX245。另一個 OrderService 調用 UserService 時,如果 Order Service 也是 XXXX123 這個容器環境的服務,則它只會調用帶 XXXX123 這個 tag 值的 UserService;如果它是正常虛擬機的服務,則只會調用不帶 tag 值的 UserService。
這樣,后臺 RPC 服務間的隔離問題就搞定了。
這里,你會發現以上要點中我們并沒有提及 ZooKeeper,因為 API 和 RPC 服務的隔離問題解決后,ZooKeeper 的數據隔離問題基本也解決了。其實,ZooKeeper 在每套測試環境中起的作用只是 API 服務和 RPC 服務的注冊發現。
3. MQ 和 Redis 隔離
如何確保容器環境和虛擬機之間的 MQ 消息不互串、Redis 數據不互相影響。
本來我們想使用類似 tag 的概念解決這個問題,通過封裝 MQ 與 Redis 的客戶端代碼,讓他們只消費同樣 env 環境變量值的服務生產的內容。
但是,我們還需要遵循這么一個原則:盡量減少容器測試環境與正式環境的代碼差異。針對這個問題,我們討論了很久,覺得沒必要專門定制,只需保證走測試流程時使用不同的測試數據就可以了(本來不同的項目就會使用不同的測試數據,包括不同的用戶、不同的訂單等),這樣基本不會再出現不同容器測試環境流轉同樣的 MQ 消息、緩存數據的情況了。
當然,Redis 中的一些通用數據還是會共同使用,比如城市之類的基礎數據。不過,這些數據就算不同容器測試環境之間互相串聯也不要緊。
4.配置中心數據的隔離
對于配置是這樣設計的,如果容器測試環境的值與虛擬機測試環境的值不一樣,我們不會修改配置中心的值,而是在容器環境的啟動腳本中動態加上針對各自容器測試環境的環境變量,然后在業務代碼中啟動環境變量優先級高于配置中心的參數,這樣就確保了容器測試環境的特殊配置,從而不影響配置中心的值。
5.數據庫間的數據隔離
數據庫互相影響的情況一般分為如下兩種:
(1)測試數據互相影響
這點其實跟 MQ/Redis 的情況一樣,我們只需要保證測試數據各自獨立就可以了。
(2)數據庫結構兼容問題
這個問題是這樣的,比如同時進行 2 個項目,XXXX123 這個項目刪除了 user 這張表的 updateFlag 字段,而 XXXX100 這個項目還需要使用這個字段。此時如果 2 個項目共用 1 個數據庫就會互相影響。
其實,這點我們在 03 講 中有談過,每次版本迭代時,我們都需要保證數據庫可以兼容前一個版本的代碼。比如剛剛那個例子,我們不會直接在 XXXX123 中刪掉 updateFlag 字段,而是等 XXXX123 上線了后再刪掉。
關于數據庫兼容前一個版本,我再舉一個例子,比如我們在 XXXX123 這個項目中增加了 1 個字段,且 updateUserId 字段的值為必填,不然數據就會報錯。而 XXXX100 這個項目并不會更新 updateUserId,這樣如果 XXXX123 讀到了 XXXX100 寫入的數據就會報錯。
這種情況該如何處理呢?此時我們可以在項目 XXXX123 中增加一些代碼讓它可以容錯,即允許 updateUserId 為空。我們也可以將項目 XXXX123 與 項目 XXXX100 部署到不同測試環境的數據庫中。
解決完上面這些問題后,基于現有測試環境快速部署多套容器環境的思路就沒啥大問題了,接下來我們再簡單介紹一下使用流程。
使用流程
我們的使用流程是這樣的,每次新建一個工程時(新的 API 或者后臺服務),我們都會在 Jenkins 上配置一個 Job,而這個 Job 需要接受如下 3 個參數。
-  
Branch:需要部署的代碼分支;
 -  
測試環境: test1/test2/test3(已經有 3 個測試環境,它決定了部署需要使用哪個測試環境的中間件);
 -  
容器測試環境標識: 也就是 JIRA Issue ID。
 
這個 Job 啟動時,我們需要調用一個小工具,而這個小工具需要連接 Kubernetes 創建namespace(=JIRA Issue ID ),然后在 namespace 中增加一個 pod(pod 中運行的是專門為 JIRA Issue ID 打包的代碼)。
在做某個項目時,比如 XXXX123 需要使用 UserAPI、UserService、OrderService、ProductService,我們會配置一個新的 Jenkins Job 聯動 UserAPI、UserService、OrderService、ProductService 的 Job,并且將各個服務對應的 Branch、測試環境和 JIRA Issue ID 傳入 Jenkins Job 中(這些值都通過 hard code 配置在新的 Jenkins Job 中)。之后,每次點擊這個項目的 Jenkins Job,我們就可以對這個項目的容器測試環境進行部署了。
當然,如果項目成員想自己部署一套環境,此時只需單獨配置一個新的 Jenkins Job,并找一個不一樣的(比如開發任務的 Issue ID)容器測試環境標識就行了。
通過這套方案,我們就可以實現如下所示的效果了。
圖 4
從此以后,我們再也不用在聯調測試時求人了。
一人一套測試環境的方案成本其實非常小,因為代碼改動很少,且 1 周半就可以把整個方案實施完成(時間主要花在申請服務器和部署 Kubernetes)。
此方案上線后,得到了使用者的一致好評,尤其是測試同學,這里我總結了三點原因:
-  
再也不需要因為協調測試環境花很多時間溝通了;
 -  
一鍵就可以將相關服務部署起來,不像以前需要一個服務一個服務部署;
 -  
因為容器測試環境的搭建很簡單,開發人員每完成一個功能,測試人員即可介入測試,而不需要等整個項目提測后再介入,大大縮短了提測后的測試周期。
 
總體來說,這個項目的效果非常棒,而且后面容器測試環境基本上保持人均一套的使用頻率。
總結與預告
到這里,我的 16 次架構經歷也就講完了。接下來的結束語,我們不講架構經歷了,將通過 3 次真實的經歷分享老板到底想要一個什么樣的架構師。
如果你有更好的方案或者本文有什么疏漏的地方,歡迎在留言區進行互動、交流。
另外,如果你喜歡本專欄,歡迎分享給更多的好友哦。
為了不斷提升課程服務質量,這里有一份課程改進的問卷,請你抽出幾分鐘的時間填寫一下。同時,我們會根據內容反饋,挑選 5 名用戶各贈送專欄 1 個。
問卷鏈接:https://wj.qq.com/s2/7871076/3f7f
結束語 如何成為老板不可或缺的人?
本專欄的所有課程到這里就全部更新完了,感謝你看完了我的 16 次架構經歷。
此時,我想很多人還存在這么一個疑問:如何成為一個優秀的架構師?在這個問題上,我覺得應該分為兩種情況:第一種是成為面霸型架構師,第二種是成為老板眼中不可或缺的人。
如果你想成為一個面霸型架構師,我認為你只需做到以下 2 點就行:
-  
把我的 16 次架構經歷讀透,并深入理解背后能解決哪些場景問題;
 -  
將 16 次架構經歷背后涉及的技術原理搞清楚。
 
我相信等你把這兩點搞清楚后,在面試過程中一定能成功秒殺面試官。接下來,我們主要討論一下如何成為一個老板眼中不可或缺的人。
這里我之所以將這兩種情況分開來講,是因為面霸型的架構師真不一定是老板眼中不可或缺的人,我先分享幾段個人真實的經歷你就能明白了。
經歷一
在工作第三年的時候,我認識了一個老板,他當時開了一家國外外包公司。因為覺得我技術不錯,所以他一直希望我能去他們公司就職,不過我沒答應,只是提議可以當兼職顧問。
某天周六,這個老板打電話跟我說:“我們的系統出現了一個問題,做了某個操作后,整個頁面凍結住了,怎么點都沒有用,目前技術人員還沒有頭緒,但是客戶一直在催,想請你幫忙看看什么問題?!?/p>
我打開系統看了一下,整個界面的確是無法點擊、輸入了。后來,我重現了好幾次這個問題,發現整個界面沒法點擊時顏色好像有點不一樣,是不是將一個透明浮層置頂了?
最終答案也出來了,的確是由于一個 bug 導致浮層沒退出。那為什么他們的技術人員都沒有頭緒呢?因為他們都是后端開發,JS 經驗比較少??戳宋业膫€人經歷,你應該猜得出來我也是偏后端。此時我可以跟老板說:“我是后端,所以這個問題不屬于我的領域范圍嗎?”
對于老板而言,他們并不在乎我們的職責是什么?老板最在乎的是我們是不是可以幫他解決技術問題。
經歷二
這個經歷是我在外企碰到的一個問題,我們先看看下面這段對話。
有一天,公司 SVP 跑過來問我:“XXX,你有沒有覺得我們的開發速度慢?是不是我們的技術不行?”
“你能跟我詳細說說哪些地方開發速度慢嗎?”
“產品的人跟我說,他們現在提的需求經常需要好幾個月才能上線,有時候一個簡單改文字的需求都是如此。”
關于這個問題,一時半會兒我也解釋不清楚,因為一開始溝通就不在一個維度上。因為開發者認為的開發速度慢指從開始開發到最終上線的時間久,而領導們認為的開發速度慢指一個需求從提出來到最終上線的時間久。
在這里我想問一下:你覺得開發速度慢算一個技術問題嗎?要我說可算也可不算。
針對上面這個問題,最終我們坐一起討論了下,并列出了所有影響開發效率的因素,如下表所示:
注意:表中我們只是列舉了部分問題進行說明。
針對這些影響因素,最終我們決定能通過技術解決的就通過技術解決。因此,有時領導提的問題并不是一個單純的技術問題,我們需要將其轉化為具體的技術解決方案。
此時,你可能想說:開發效率低這種事情不是應該找架構師嗎?這個不是管理的問題嗎?下面我們接著看一段經歷。
經歷三
曾經,我們有一個新的項目,它的需求影響面比較大,功能點比較多。在架構設計時,如果還是基于原來的系統將會出現一系列問題,因為原來的系統做了 4年了,架構時間相對比較久。
此時,一個架構師趁機提議道:“我們能不能趁著這次需求將架構進行更新?!?/p>
之后,這位架構師就著這個問題與另一位負責這個項目的技術總監進行了討論,并提交了相應的提案,提案中陳述了新架構的代價和好處。代價是需要多花 3 周時間進行研發,好處是系統會更穩定、問題會更少、迭代速度會更快。
因為 CTO 是產品出身,聽這位架構師的陳述后不明覺厲,于是爽快地同意了,接下來項目直接進入如火如荼的開發階段。
當然,在實際業務中,任何一個項目都會出現各種各樣的變數,比如業務方說這個需求之前沒考慮清楚,還有一部分流程遺漏,我們必須先把它解決了,不然系統用不了。于是,業務人員臨時變更了需求。再比如更新新架構時,有些系統需要進行遷移,而有些系統不需要遷移,但是在實際做的過程中我們發現,原來決定不遷移的一個系統由于數據庫耦合的問題,此時也必須遷移了。再比如,一些同學對新架構不熟悉,需要多花點兒時間上手。
面對這些突發事件,項目就很容易延期。于是,出現了下面這段對話。
某一個會上,CTO 說:“咱們的架構師不行啊,這次系統上線后,如果性能不穩定,就把他開了?!?/p>
我們詫異地問道:“為什么?還有其他原因嗎?”
CTO 說:“你看我們這個項目,本來 1 個半月就可以完成,加了新架構的遷移后變成了 2 個多月完成,現在都快拖成 3 個月了,這明顯是架構師的問題啊。早知道是這樣的話,我們還不如不遷移新架構呢?!?/p>
我們就幫他開脫:“這其實也不全是架構師的問題,不是還有一些需求變更嗎?”
CTO 說:“我知道啊,那些需求我看了,改動并不大,不至于拖上 1-2 個月?!?/p>
我們都沉默了,心里面 OS:“當初討論遷移新架構,你也是同意了啊?!?/p>
CTO 離開后,我們兩個總監私底下商量:“一定要保住這個架構師,不能讓他一個人背鍋?!?/p>
后來,有一次與 CTO 吃飯,他跟我們解釋道:“我的壓力也很大,本來跟老板說好了多久就可以上線,結果拖了兩個月。當時我也跟老板解釋了架構遷移的事,老板本來是同意的,可是第二個月就把架構遷移的事忘到九霄云外了,因為他壓根兒對軟件研發沒概念。”
在整件事情中架構師有錯嗎?好像沒錯啊。
事后,我們也回顧了一下整件事情,之所以是架構師背鍋,關鍵原因在于我們對架構師的期望不一致,比如我們期望開發效率高還是系統穩定性好?抑或是復雜問題的突破?因此,在真正解決問題之前,我們必須搞清楚領導對我們的期望值。
這里,我把關于如何成為老板不可或缺的架構師的要點總結為以下三點:
-  
別在乎個人職責和邊界是什么?我們需要在乎是否能夠幫助老板解決實際技術問題;
 -  
有時候領導談的問題并不是單純的一個技術問題,我們需要把領導的問題轉化成技術可以解決的問題;
 -  
我們需要搞清楚同事和領導的期望值,也是最重要的一點。
 
以上就是我的三段個人經歷,它們并不能作為所有公司的評判標準。因為一名優秀的架構師的定義可以從很多維度上進行闡述。
不過,我也不期待一篇文章就能讓你懂得如何成為老板不可或缺的人,我只希望這篇文章能給你一點啟發。如果你能從中感同身受,那將是我莫大的榮幸了。
最后,感謝你花時間看完了我所有的課程,希望它對你有幫助。如果你覺得此專欄有價值,歡迎轉發給更多的朋友。
我是韋木,有興趣的同學,也可以關注我的公眾號,“大木韋”。
好了,我們的《軟件架構場景實戰 22講》今天已經全部更新完了,為了不斷提升課程服務質量,這里有一份課程改進的問卷,請你抽出幾分鐘的時間填寫一下。同時,我們會根據內容反饋,挑選 5 名用戶各贈送專欄 1 個。
總結
以上是生活随笔為你收集整理的分布式场景实战第七节 微服务场景实战的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: js 计算时间差(去除法定节假日,休息日
 - 下一篇: XMind使用技巧1