从MVC到云原生:CBU研发体系演进之路
作者:遠巖,高級開發工程師。2019年畢業加入阿里巴巴,主要負責 CBU APP 端前臺場景工程體系及服務端 Serverless 化建設。
前言
?
CBU作為集團內最早成立的幾個BU之一,有著多年豐富的業務沉淀,而CBU的技術也伴隨著業務一起不斷地演進和成長著。從PC時代的WebX到如今的Serverless,CBU的研發體系經歷了多次變革,在不同的階段中有著不同的特點。筆者所在的團隊近年來一直在負責前臺場景研發體系升級相關的工作,在這期間也對過往模式的演變進行了大量的回顧和分析,希望能夠通過本文對過去十年中CBU在研發方式和技術架構上的嘗試和探索做一個簡要的回顧和總結,重新審視我們所走過的路,同時也對未來的方向做一些探討和展望。
?
青銅時代(2010~2013)
?
10年前的互聯網,移動終端還沒有興起,絕大多數的產品都是為PC用戶所服務的。在這種背景下,采用B/S結構是一種毋庸置疑的選擇,因此當我們回顧這個時代的技術時,最先能想到的自然是那些和WEB、瀏覽器關系最密切的關鍵詞:比如WebX、jQuery、Velocity等等。
?
在這個階段,業務流量并不巨大,系統的性能瓶頸基本集中在數據庫的讀寫上,大部分的應用仍然采用單體式的架構,從前臺頁面到后臺邏輯都封裝在同一個應用中,而在應用內部,往往是采用MVC的分層思想對不同功能的模塊進行劃分。彼時CBU的前臺應用架構也基本是這個思路,頁面通過Velocity模板進行開發,后臺業務邏輯則封裝成應用中單例的Service實現,中間通過一個類似Controller的粘合層進行連接,將后端的數據字段轉換成前端模版中所使用的變量:
?
?
這種模式的優點是,由于所有的模塊都在同一個應用中,非常便于集中管理,當一個開發同學非常熟悉整個應用結構時,他便可以非常快速地完成一整個需求的開發。但缺點也同樣明顯:隨著業務的發展,前臺邏輯變得越來越復雜,需求必須要拆解成前后端分離的方式,讓專人做專事,而前臺代碼被耦合在應用中,使得前后端分離開發變得異常困難;除此之外,前臺邏輯的變化往往是非常頻繁的,如果每次修改一個頁面元素都要發布整個應用,不僅研發效率會十分低下,還會影響線上業務的穩定性。
?
為了解決上述問題,當時CBU的同學們充分利用了Java的動態類加載機制以及Groovy腳本語言,以一種特殊的方式實現了前后端分離開發和快速迭代,這里我們以商品詳情場景為例解釋一下其機制和原理。
?
首先,一張頁面被拆分成若干個組件,每個組件都會對應一個bundle,這個bundle中包含了前臺的vm模板,js代碼,以及一個Groovy腳本。在實際研發時,需要先通過一個映射表達式聲明該組件所需要消費的后臺模型或字段,然后通過Groovy腳本(相當于Controller層)將其轉換為vm模板中的變量,接著便可以開發前臺的vm模板和js邏輯。開發完畢后,通過一個定制的發布系統,便可以把對應的bundle發布到前臺應用中,由應用內部的JVM動態加載Groovy腳本以及vm模板,完成需求功能的上線。下圖便是一個使用這套研發體系開發需求的實際例子:
?
?
這套研發體系通過JVM動態加載的能力,將面向前臺的View層和Controller層邏輯抽離出來,使其能夠進行獨立開發和動態發布,從而實現了前后臺邏輯之間的解耦,提升研發效率。只要后臺邏輯沒有大的變更,很多需求都可以通過bundle快速開發上線。不過在實際運行時,所有的邏輯仍然是在同一個應用中執行的,這在一定程度上會帶來一些安全隱患。除此之外,這套研發體系也是非常定制化的,bundle的發布系統實現非常沉重,并且對應的前臺應用有強綁定關系,這就意味著很難將它快速地復制到另一個業務場景中復用(CBU最終只有商品和店鋪兩個業務落地了類似的模式)。
?
盡管存在著一定的問題,但即便以現在的眼光來審視,也不得不承認這套研發體系有著非常超前的設計思路。尤其是通過引入bundle這一概念,使業務迭代開發變得十分聚焦。在本文的后續章節中我們會看到這一思路最終將伴隨著云原生技術革命,再一次回到我們的視野當中。
?
蒸汽時代(2014~2018)
?
這一階段,互聯網行業的形態發生了非常巨大的變化。隨著智能手機的流行和普及,移動互聯網迅速崛起,各種各樣的業務都開始向移動端發力。集團發動ALL IN無線的戰役,大量的業務和產品需要快速向移動端遷移。同時,隨著智能手機市場的不斷下沉,加上其“隨時隨地”都能使用的特性,互聯網業務此時所需要應對的流量挑戰和PC時代將不再是同一個數量級。
?
在技術側我們也能看到與上述現象所匹配的變革。一方面,由于流量的激增和系統復雜度的增加,傳統的單體式應用無法再支撐業務的發展,隨著Docker這一關鍵技術的出現,服務端應用的分布式拆分和微服務化成為不可阻擋的趨勢。另一方面,由于移動端崛起,前臺展示突破了PC鍵鼠交互以及瀏覽器能力的限制,用戶對于產品體驗和交互的要求勢必會變得更高,這促使研發人員進一步細分化為負責底層業務邏輯的服務端研發和負責前臺展現交互的前端、客戶端研發:React的出現敲響了傳統WEB技術的喪鐘,開發獨立APP成為拓展業務的不二選擇,前端技術和客戶端技術在這一階段開始飛速發展。
?
這樣的背景下,單體式應用和MVC架構逐漸死去,前后端分離的架構模式和Restful API登上歷史舞臺,每個細分領域的技術棧都在飛速成長,大型軟件的開發流程從此將會面對更加復雜的協作和研發模式。
?
回到CBU本身,這一階段技術上最重要的任務就是將原本PC上的業務快速地遷移到無線終端上去,因此成立了專門的無線團隊,開始重點打造手機阿里APP。整體思路非常簡單明了,原有的業務體系和邏輯保持不變,進行微服務化改造,以RPC形式對外提供核心業務能力;架構上增設無線服務層,面向APP進行業務邏輯的適配和封裝,通過集團統一對外網關提供Restful API給客戶端及前端開發人員使用。這樣就可以在基本不影響已有業務體系的條件下,讓APP上的業務快速跑起來。無線服務端在這里所扮演的角色非常類似MVC架構模式中的Controller層:通過RPC與底層基礎業務交互,然后疊加面向無線側的特殊業務邏輯,最終對數據結構進行一定的處理和封裝,通過集團對外的無線網關透出給前臺客戶端使用:
?
?
在此模式下,無線服務端和客戶端研發人員扮演著十分重要的角色,他們的研發和協作模式將最終決定APP的迭代速度以及質量。接踵而至的新挑戰催促著CBU的工程師們對已有的研發體系進行全面的升級,而最終他們給出了十分精彩的答案:輕服務和場景搭建兩大技術應運而生,接下來我們會看到,這兩者結合所產生的奇妙化學反應,將會給前臺場景的研發模式帶來一次重大的突破。
?
輕服務平臺
?
如上文所述,在ALL IN 無線的時代,無線服務端的研發同學們需要在已有的基礎業務接口上進行大量的改造和封裝,為無線APP端提供服務接口。而在微服務架構下,服務端要對外透出接口,一般需要在應用內編寫RPC服務,然后通過集團的無線網關將對應的RPC服務暴露成集團APP可以調用的HTTP接口:這種方式下一個服務從開發到上線往往需要數天時間。而為了保證客戶端功能的快速迭代,避免業務受到發版節奏的影響,很多簡單邏輯往往會被上行至服務端處理,這就對無線服務端的迭代速度和靈活性提出了一個非常高的要求。既有的技術生產力不能滿足業務訴求,那就勢必要進行創新,于是便誕生了能夠支撐快速敏捷開發的輕服務平臺,代號為MBOX。以今天的視角來看,這一平臺踐行的便是當下非常火熱的Serverless理念,并為服務端同學提供了FaaS(Function as a Service,函數即服務)的能力。
?
MBOX平臺依然采用了動態類加載機制來實現代碼的熱更新,并結合字節碼技術提供了一個JVM內的“安全容器”,把Java語言的動態化特性運用到了極致,其架構理念和實現原理如下圖所示:
?
?
通過配套的研發平臺和發布系統,開發者可以將自己編寫的一個類動態加載進線上應用的MBOX容器中,并創建一個單例對象;各種常見中間件如RPC和緩存能力,都可以通過注解進行聲明注入并使用;而服務一經發布,便可以通過指定的Gateway訪問到。這種無需配置、開箱即用、快速上線的輕服務迭代方式,非常適用于當時無線服務端所面對的開發場景:對現有的業務RPC服務進行組合編排,再加上一些面向APP端的簡單處理邏輯,使用MBOX便可以在幾小時內完成從開發到上線的整個流程,生產力得到了極大的提升。
?
場景搭建
?
早在PC時代CBU就已經建設了頁面搭建相關的技術產品,而在無線端,這一命題實現起來卻要復雜許多。首先,客戶端的頁面并非像前端一樣,由標準的瀏覽器所承載,iOS和Andorid雙端從底層的系統機制到上層的組件實現都完全不同,要想實現統一的頁面搭建,勢必需要抹平這層差異。其次,場景搭建并不是簡單的堆砌組件,還需要考慮每個組件背后的數據源:來自各種應用的服務接口必須和組件解耦,而不能在組件內部通過Native邏輯實現,否則將會導致組件完全喪失復用性,并且使業務迭代更加依賴發版。
?
為解決上述問題,各端的工程師付出了諸多努力。首先是制定多端差異的抹平和融合方案,該方案從各端組件化渲染方案進行抽象,統一了一套相對抽象、可擴展的協議,包含頁面協議、布局協議和組件協議三大部分。頁面協議指定了當前頁面的基本信息、頁面主體結構、埋點信息、渲染方式;布局協議指定了該布局下所有組件的布局方式,同時以布局容器可支持組件abtest、組件分流、組件個性化等投放方式;組件協議細化到組件的基礎屬性、渲染方式,除此之外,還會定義組件的數據綁定行為、數據請求方式、數據取數方式,從而將組件UI和數據解耦,提升組件復用性和可維護性。
?
Android、iOS雙端分別面向這套標準協議,對端上的多種渲染方案和Native能力進行封裝,提供了統一的搭建容器實現,抹平了多端渲染的差異。
?
在此基礎上,前臺的開發/運營就可以通過搭建和配置化的方式,構建出前臺頁面的渲染協議(頁面協議+布局協議+組件協議),該協議最終被上行至服務端的“渲染網關”節點,由其來收口所有搭建場景中協議的下發。除了協議下發之外,渲染網關還收口了所有組件的取數邏輯,通過一個通用的數據網關接口來統一前臺組件的取數方式,讓整個搭建體系變得更加簡潔和標準。
?
?
構建完整的場景搭建體系是一項浩大的工程,其中包含著無數研發人員的智慧結晶,受限于篇幅本文不再過多展開,想要了解更多的朋友可以參考我們之前的系列文章:
?
- 《CBU場景運營建設實踐與探索》
- 《CBU端容器標準化方案》
?
敏捷研發體系
?
在場景搭建體系中,渲染網關對外封裝了統一的取數接口,前臺的組件將會通過這個接口直接消費后臺的服務端數據源,也就是一套重后端的方案(主要邏輯在服務端實現),因此在實際落地當中,往往需要為每個組件獨立開發一個專屬的數據源,這些數據源基本是對已有的RPC服務進行簡單調用,然后封裝一些前臺相關的邏輯,因此使用輕服務來解決再合適不過了。于是兩者相互結合形成了一套非常敏捷的研發體系:前端開發者開發UI組件,后臺開發者通過MBOX編寫一個輕服務,快速適配生成數據源,兩者通過搭建進行簡單的配置化綁定,一個頁面就完成了,十分高效。正是這樣敏捷的研發體系,幫助CBU快速地開拓了無線戰場。
?
營銷會場類頁面是應用這一研發體系的典型場景,我們以某行業導購會場為例來體驗其研發流程:
?
?
在這種研發體系下,前端和客戶端研發人員可以專注于開發自己的組件,而服務端研發人員則可以使用輕服務的方式快速為對應組件適配封裝對應的數據源接口(或者是編寫傳統的RPC服務),得益于搭建平臺對組件和數據源的標準抽象,雙方的研發流程可以互相解耦,讓整個研發體驗變得更加專注和高效。而采用這種前后端分離的模式之后,各端的技術能力和架構將得到更加聚焦的打磨,因此我們在之后將看到前臺組件和后臺數據源的研發模式都會出現新的突破。
?
總之,新的研發體系大大提升了前臺場景的研發效能,這離不開背后的兩大關鍵技術突破 —— 場景搭建體系和輕服務平臺。而在此之中,又蘊含著無數工程師智慧和汗水的結晶,是他們面對未知時的勇氣和堅持探索的熱情成就了這些偉大的技術產品,并為CBU研發體系的演進之路立起了一座新的里程碑。
?
向開拓道路的先驅者們致敬。
?
摩登時代(2019~2020)
?
故事還在繼續。最近兩年,移動互聯網已經進入下半場,隨著時間的推移,既有業務模式演變的越來越復雜,同時也越來越成熟,而在此基礎上,又有著諸多新的賽道被開拓,越來越多的競爭對手走上了跑道。我們看到了航母級APP在一次次的打磨和歷練中竣工并啟航遠征,各種新的業務場景像停靠在甲板上的一架架艦載機,隨時準備以極快的速度起飛。總的來說,已有業務完成了野蠻生長,逐漸步入需要更多精細化打磨的階段,而更多新興的業務場景則需要通過借助既有的沉淀,用比以前更快的速度跑起來。
?
而在技術側,職能細分化使得各端的技術棧在過去幾年里都得到了相當大的突破:在前臺展示方面,無論是前端還是客戶端,組件化研發都已經成為基本共識,并且技術方案也高度成熟,甚至出現一些能夠根據UI智能還原生成組件的技術。而在后端和運維方面,隨著Kubernetes一統容器編排,云原生理念被迅速引爆,大量的底層運維和中間件能力被再一次下沉,以FaaS為代表的Serverless技術手段帶來了生產力的極大提升,讓上層人員能夠更加關注業務邏輯。對于大部分的普通業務場景,前后端技術都已經實現了一定程度的開放化:前端可以通過Serverless能力來快速編寫服務端接口,后端也可以通過低代碼和可視化方案開發前端組件,這都象征著對應技術棧的高度成熟化。
?
在上一個階段中,我們通過搭建體系+輕服務的方式,打造出了一套能夠敏捷迭代的高效研發體系,幫助CBU快速完成了無線業務的布局,但在“野蠻生長”過后,也開始逐漸暴露出一些問題,其中最為重要的是以下幾點:
?
?
針對于以上問題,我們進行了大量的討論和分析(詳細可見前文《CBU Serverless 研發體系 FY20 S2 建設總結》),并貼合實際業務訴求和業界技術的發展情況,制定出了以下的策略:
?
?
下面筆者將分別為大家介紹每一個策略的具體實現方案。
?
MBOX + FunctionCompute:打造真正的云原生FaaS解決方案
?
前文提到過,CBU在很早的時候就開始大規模應用落地輕服務平臺MBOX,經過幾年的沉淀,這種FaaS形式的服務已經幾乎滲透進我們的每一條業務線,帶來了顯著的研發提效,MBOX這一技術產品也在經過多次打磨后變得越來越成熟。
?
與此同時,我們也一直在關注著業界和集團內對于Serverless架構的最新落地方案,期望能夠將Runtime層的實現從JVM容器升級為真正的Serverless容器,實現更安全的資源隔離和彈性伸縮能力。這個財年,我們和阿里云函數計算(Function Compute,下文簡稱FC)團隊的同學并展開了合作,經過近一個季度的打磨和試錯,完成了MBOX平臺與FC函數運行時的整合,為服務端的研發同學打造出了一套將大量歷史經驗和最新技術方案相結合的標準FaaS解決方案。
?
在這套方案中,最大的變革來自中間件能力的下沉,得益于各種中間件能力的sidecar化,上層的業務應用可以變得十分輕量,從而具備了快速部署和彈性伸縮的條件。在此基礎之上,FC團隊結合集團的基建,提供了成熟的函數運行時容器,支持函數級別的資源隔離和彈性伸縮,實現真正的Serverless能力。最終,我們將經過多年沉淀的MBOX編碼方式和新的中間件調用方式進行了高度整合和優化,面向研發人員提供一套非常高效的業務FaaS編程框架和配套的預覽調試插件,真正做到開箱即用的研發體驗。整體方案架構如下圖所示:
?
?
和傳統的應用相比,這套函數應用方案十分輕量,可以實現快速迭代,同時還可以享受Serverless的紅利,無需關心資源運維。而相比于原有的MBOX輕服務方案,又有著更高的擴展性和安全性。
?
建設規范化的數據源體系
?
在前后端分離的研發模式下,通常將為前臺組件提供數據的服務接口統稱為“數據源”,在之前的研發體系中,任何形式的服務接口都可以注冊成為組件的數據源,并沒有任何的規范或者標準,最終隨著時間的流逝,體系中的數據源數量飛速增長,難以維護。經過分析后,我們認為出現這種現象的主要原因有以下幾點:
?
?
為了解決上述問題,我們在現有的混沌局面之上建立了一套新的分層標準和規范,并提供了一系列新的工具和能力切面,逐漸形成了一套全新的數據源體系,并命名為“奇點”,下面我們來看一下奇點是如何解決以上問題,又帶來了那些新的能力:
?
第一步,對數據源進行分層和標準化。
?
通過對歷史經驗的歸納總結,我們將各類數據源進行了分層,并對每一層的數據源進行了標準化的抽象:
?
?
值得一提的是,我們將原來很多專門為前臺組件適配數據邏輯的輕服務腳本從數據源中剔除了出去,單獨抽象了“字段映射”的腳本層,避免這些一次性的服務污染整個數據源體系。
?
我們為開發者提供了一系列的插件,可以從服務端的代碼定義中抽取出這些數據源的定義并進行標準化封裝,然后注冊至奇點的后臺數據庫。隨著底層開發同學的逐步接入,我們便可以慢慢建立起一個更加清晰和標準的數據源體系。
?
第二步,增加能力切面,讓所有數據源變得可理解、可編碼。
?
在第一步的基礎上,我們還要徹底解決數據源的使用問題,首先要讓數據源變得可理解,目前奇點通過javadoc掃描源代碼注釋的方式抽取所有服務的出入參定義及說明,并適配成標準的swagger開源協議,導入到RAP平臺(由阿里開源的API文檔平臺)形成文檔,在此基礎上我們還會通過特定方式采集服務的一些真實樣例,這樣任何人都可以快速理解一個數據源的具體含義和使用方式,徹底改變之前口口相傳的低效協作方式。
?
接著還要進一步簡化和規范數據源的使用方式,這里先說說面向服務端側,奇點提供了一套通用的調用樁SDK,通過引入該SDK,只要知道數據源在奇點平臺中的簽名(即唯一標識符)就可以快速創建一個調用樁,并可以通過該調用樁進行泛化調用,完全不需要感知底層服務的類型,也無需引入任何其他依賴。考慮到泛化調用方式在開發時無法實現代碼提示,體驗比較糟糕,我們還制作了一套IDE中的輔助插件,這個插件通過掃描源碼時所記錄的出入參字段結構,可以在指定的工程中生成對應的DTO類定義,再加上一些序列化轉換邏輯,實際開發人員便可以實現非泛化的調用,就像使用本地定義好的服務一樣順暢,而這種方式由于沒有引入任何二方包,所以不會產生任何項目依賴沖突問題,因此研發效率不會受到任何影響。
?
?
總之,通過為所有接入的數據源提供文檔、樣例、調用樁和字段結構這四個通用的能力切面,奇點做到了讓所有的數據源變得可理解、可編碼、可觀測。隨著不斷推廣和業務場景的覆蓋,這將有助于在研發人員內形成一個良性循環,從而長期維持新的體系秩序。
?
第三步,改變前臺組件消費數據源的方式。
?
一直以來我們都通過封裝服務接口的方式為前臺組件提供數據源,這樣會不知不覺中產生大量的一次性服務。這些服務通常都沒有什么復雜邏輯,只是消費一些現有的數據源然后做簡單的字段映射。經過思考我們最終將這類服務從奇點的數據源體系中剔除出來,單獨抽象為字段映射的腳本(使用FaaS實現)。前臺組件最終將不再直接消費數據源,而是通過一份標準協議,聲明其所需要的數據源和用于處理這些數據源的映射腳本,通過映射腳本來消費數據源。
?
?
這份標準協議可以通過搭建平臺自動生成,通過這種方式我們將大量的一次性邏輯單獨抽離了出來,避免它們對數據源體系產生干擾,起到架構中防腐層的作用。
?
總之,在建設完奇點這一套新的架構體系后,我們終于“守得云開見月明”,打造出了一套清晰可用的數據源體系,至此我們已經基本解決了之前研發體系中的絕大多數問題,是時候對它們進行一定的整合,來產出面向前臺場景的標準研發解決方案了。
?
前臺場景研發標準解決方案
?
可以看到,經過多年的積累和打磨,CBU的前臺場景研發體系已經非常成熟了,整體看來,它是由幾個關聯性很高的子平臺所構成:組件平臺(前端、客戶端用于開發和注冊組件的平臺)、搭建平臺、FaaS平臺、和數據源平臺(奇點)。在過往的研發流程中,這些平臺之間是通過一系列的約定進行聯動的,而這些約定往往是“經驗”性質的,對于沒有使用經驗的同學而言,理解和上手的門檻還是有一點高的,且各個平臺之間存在著比較強的割裂感,在整個研發流程中開發人員需要在多個平臺之間反復操作和跳轉,帶來了很多不變。
?
在攻克了原有體系中存在的諸多問題之后,我們決定將這套新的前臺場景研發體系進行標準化,以搭建平臺為中心,通過綁定關聯的方式、打通其他各個子平臺的功能,將研發流程集中串聯在一起,把搭建平臺打造成場景研發的核心“工作臺”,沉淀出一套標準的前臺場景研發解決方案。
?
在這套標準的解決方案中,一個前臺場景由一張搭建頁面(包含多個組件)、一個FaaS函數應用(由標準的腳手架生成)和一系列的數據源組成,在初始化階段中,可以將三者進行綁定關聯形成一個完整的場景工程。
?
完成初始化后即可進入實際的研發階段,這個過程中前臺研發專注于組件的實現,后臺則負責在FaaS應用內部引用各種奇點數據源(或新增)實現業務邏輯,再通過字段映射腳本為指定組件進行UI層的封裝適配,雙方都可以做到Only Focus on Business的研發體驗。
?
研發階段完成后,即可在搭建平臺上進行配置和聯調,由于各個子平臺已經完成高度串聯,因此在搭建平臺上可以直接完成組件、數據源和字段映射的綁定及實時預覽,甚至可以通過打印數據鏈路來排查可能存在的問題,節省配置和聯調所用的時間,也降低出錯的成本。最后再進行測試和發布,一個前臺場景便可上線。
?
以我們目前已經落地的無線商品詳情頁場景為例,在此標準解決方案下,研發流程如下圖所示:
?
?
非常有趣的是,仔細觀察這套方案的實際開發階段,其中一個組件模塊所包含的內容:組件UI + 映射腳本 + 業務數據源 ,這一組合正是10年前bundle思想的延續。但相比于當時,新的這套方案更加標準化、更加易于使用,能夠快速地被應用于各種前臺場景。另外我們也可以看到,隨著各端技術棧的成熟,單一業務模塊的研發流程又再次被高度集中化,這其中大部分的研發工作都已經十分簡化,例如組件的低代碼開發、無需關心運維的函數即服務,或許這些工作以后又將脫離具體的崗位劃分,整合成一個新的“全棧”工程師角色,如此一來,單個需求研發的溝通成本將會進一步降低,研發效能或許會再次邁上一個新的臺階(當然,這只是一個YY性質的推測,歡迎大家拍磚交流)。
?
結語
?
至此,我們已經一路走過整整十年的歷程,感慨過往崢嶸歲月的同時,我們也在努力創造新的輝煌。研發體系的演進之路不會有終點,未來我們仍將繼續探索。感謝一起前行的同路人們,也歡迎更多有識之士加入我們,一起鑄就下一個新的時代!
原文鏈接:https://developer.aliyun.com/article/782513?
版權聲明:本文內容由阿里云實名注冊用戶自發貢獻,版權歸原作者所有,阿里云開發者社區不擁有其著作權,亦不承擔相應法律責任。具體規則請查看《阿里云開發者社區用戶服務協議》和《阿里云開發者社區知識產權保護指引》。如果您發現本社區中有涉嫌抄襲的內容,填寫侵權投訴表單進行舉報,一經查實,本社區將立刻刪除涉嫌侵權內容。 與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的从MVC到云原生:CBU研发体系演进之路的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 尼日利亚学生开发者,用阿里云PAI打造了
- 下一篇: 《口袋奇兵》开发商引入阿里云PolarD