啥都復(fù)用不了,還談什么中臺?
圖片來自 包圖網(wǎng)
結(jié)果這位研發(fā)負責人講不清楚,或者技術(shù)人員太實在而不知道該如何表達,最后也把我叫過去數(shù)落一番。
我不怪老板,她的想法是可以理解的,站在投入和產(chǎn)品角度,不要重復(fù)制造輪子是沒有錯的;我也不能完全怨我的下屬,有些東西的復(fù)用和集成的確是不像做 PPT 那樣東拼西湊那樣容易的。
雙方都沒錯,那問題出在哪呢?我將這個問題發(fā)到技術(shù)交流群里,大家討論的也挺熱烈,看來這個問題的確也是大家普遍存在的問題。
有人吐槽老板不懂技術(shù),需要上課的;有人建議需要溝通,需要不斷磨他,盤他的;還有人還建議讓老板參與幾個典型項目,讓他多體會體會的;最后我們把問題歸結(jié)到“信任”二字,原來所有的問題都可以通過“信任”來解決的。
的確信任可以解決任何問題,老板如果一點不懂,他可以信任他的 CTO 能很好的解決這個事情;如果老板很懂,他就會親自解決這個問題了。
今天我們不討論老板的問題,他的需求本身沒有問題,如果我是老板我也會要求不做重復(fù)投入。
本文我更多要站在技術(shù)領(lǐng)導(dǎo)者的視角去嘗試解析這個問題,尋求一定的解決方案。
系統(tǒng)復(fù)用為什么難?
還是從事例說起,我們做醫(yī)療行業(yè)的應(yīng)用系統(tǒng),健康檔案的管理是一個非常普遍的功能。
我們在某系統(tǒng)里已經(jīng)開發(fā)了稍微完整點的模塊,于是乎只要其他應(yīng)用要開發(fā)健康檔案的功能,老板就會說這個我們都做過了,拿過來用就好了,為什么要重新開發(fā)?
我來嘗試的回答下這個為什么很難復(fù)用:
- 這個系統(tǒng)由于歷史原因,是 .net 開發(fā),而我們團隊主流的技術(shù)棧是 Java,開發(fā)語言都不一樣,沒法復(fù)用,只能參考。
- 雖然都叫健康管理,但是不同的應(yīng)用系統(tǒng),他們的差異化還是非常大,慢病管理和專病管理有差異,在基層醫(yī)療和等級醫(yī)療有差異,即使同構(gòu)系統(tǒng),其實也無法直接復(fù)用,需要二次改造。
- 如果這個模塊不是以公共組件的方式進行抽象設(shè)計的話,它其實和當前系統(tǒng)是緊密耦合的,數(shù)據(jù)層的耦合,業(yè)務(wù)邏輯層的耦合,視圖層的耦合,特別是代碼級的耦合,如果在其他系統(tǒng)復(fù)用,首先要去除這種耦合然后在做適應(yīng)化改造,復(fù)用的成本有時候不比重新開發(fā)低。
①復(fù)用是有成本的
DRY 原則(Don't Repeat Yourself)相信每一位程序員都應(yīng)該知道。其指代的是我們寫程序時,不要一遍又一遍地編寫相似的代碼。
當出現(xiàn)某些相似功能的代碼時,我們應(yīng)該將通用部分代碼與特異部分代碼分離,以達到復(fù)用通用代碼,降低整體復(fù)雜度的目的。
復(fù)用這個道理我們都懂,我們也在實際的開發(fā)過程中真正去踐行的,但復(fù)用其實是有成本的。
這也是為什么我們知道重復(fù)制造輪子不好,但卻又不停的的在制造輪子,因為很多時候造一個新輪子比改造一個輪子可能更快,成本更低。
那么復(fù)用有哪些成本呢?
發(fā)現(xiàn)可復(fù)用組件的成本:很多時候我們并不是不想復(fù)用,而是不知道是不是存在我們需要的輪子,從哪里可以找到這個輪子。
正如本文最開始的那位研發(fā)負責人,他可能真的不清楚哪個團隊有他可復(fù)用的輪子,而老板看到的范圍更廣,所以她更清楚。這個和組織管理和知識管理有關(guān)。
學習可復(fù)用組件的成本:別人造的輪子有時候很難了解它內(nèi)部的構(gòu)造和邏輯,就要去學習別人造輪子的設(shè)計和邏輯,這個本身是存在學習成本的,如果對方的設(shè)計和實現(xiàn)與自己的思路存在出入的時候,又會非常的別扭。
擴展可復(fù)用組件的成本:前人造的輪子都是用在他當時的那個場景或者業(yè)務(wù)中,當這個輪子切換到新的場景和業(yè)務(wù)中的時候,你會發(fā)現(xiàn) 100% 的可復(fù)用基本上是沒有的。
這時候就牽扯到對于這個輪子的擴展以適用新的業(yè)務(wù),先不說這個擴展改造是所有者執(zhí)行還是使用者執(zhí)行(后面有一個章節(jié)專門討論組織的邏輯),擴展總是有成本。
修改可復(fù)用組件的成本:有時候組件的抽象能力不夠,無法擴展,或者擴展的時間成本太高,或者組件所有者不愿意支持,復(fù)用者可能采用直接拿過來修改的情況。
修改的成本是一個層面,但把時間拉長來看,組件修改后就和原組件分化了,未來雙方的新功能也無法相互復(fù)用了。
②復(fù)用是有級別的
一般情況,復(fù)用的成本會因為復(fù)用的組件的內(nèi)容不同,所在組織的關(guān)系親密,它的成本是不一樣的。
比如只是復(fù)用一段程序,就相當簡單,如果復(fù)用一個系統(tǒng)功能就很困難;如果復(fù)用同一個團隊的組件就相當簡單,如果跨團隊跨組織的復(fù)用就會變得困難。
所以復(fù)用也是有級別的,為了更好的理解我把復(fù)用分成了一下 5 個級別:
級別越低,粒度越小,復(fù)用的范圍越廣,但價值體現(xiàn)較低;級別越高,粒度越大,復(fù)用的價值越高,但復(fù)用范圍也比較局限。
所以站在業(yè)務(wù)和價值角度上,都是先從最高的層次上去復(fù)用。只有上層無法實現(xiàn)復(fù)用,我們才會逐步向下層去尋找。
但是有時候站在技術(shù)角度,我們習慣在低層次上去復(fù)用,因為這里最接近自己的工作,粒度越小,技術(shù)上越可控。
回到本節(jié)開始的問題,B 系統(tǒng)的功能要復(fù)用 A 系統(tǒng)的功能,這個復(fù)用級別是最高的,如果能復(fù)用那會極大減少工作量降低成本,但這個級別的復(fù)用難度也是最大的,特別是異構(gòu)系統(tǒng),就幾乎沒有可能了。
③復(fù)用是有粒度的
影響復(fù)用達成時間的因素很多,這些因素疊加起來可能導(dǎo)致復(fù)用所消耗的時間更多。
因此對于一些時間特別敏感、由其決定生死的業(yè)務(wù),在可復(fù)用組件未成熟,或者可復(fù)用組件支持團隊的支持力度不夠時,可以不考慮復(fù)用。
不復(fù)用的情況就是我們通常講的煙囪系統(tǒng),現(xiàn)在大環(huán)境的論調(diào)是煙囪系統(tǒng)不好,其在一個業(yè)務(wù)成熟的公司里確實不好。
但是煙囪系統(tǒng)在業(yè)務(wù)早期變化大,快速野蠻生長時,由于不需要考慮復(fù)用,沒有太多的條條框框限制,提供了高效的開發(fā)效率支持,為業(yè)務(wù)的存活做了重要貢獻。
Gartner 在研究報告里提出了宏服務(wù)、小服務(wù)和微服務(wù)的粒度劃分:
- 宏服務(wù):一種傳統(tǒng)的 Web 服務(wù),支持將功能封裝于單體應(yīng)用內(nèi)。宏服務(wù)不支持獨立部署或擴展, 它們只能部署為單體應(yīng)用的一部分,而且它們不需要微服務(wù)基礎(chǔ)架構(gòu)。
- 小服務(wù):就服務(wù)粒度范圍而言,小服務(wù)是一種粗粒度、松散耦合、支持獨立部署的應(yīng)用組件。小服務(wù)需要微服務(wù)基礎(chǔ)架構(gòu)。
- 微服務(wù):微服務(wù)處于粒度范圍的遠端,是一種可獨立部署的組件,能夠支持單個應(yīng)用功能的實施。微服務(wù)可直接部署到微服務(wù)運行時環(huán)境中,也往往具備專用數(shù)據(jù)存儲區(qū)。微服務(wù)需要微服務(wù)基礎(chǔ)架構(gòu)。
如果我們想對已存在系統(tǒng)的能力進行復(fù)用,可以采用宏服務(wù)模式進行,宏服務(wù)的模式適合做系統(tǒng)的集成和治理。
我們對于新的業(yè)務(wù)和項目,剛開始建議采用小服務(wù)的方式進行業(yè)務(wù)領(lǐng)域的拆分,不建議拆分的過細,這個小服務(wù)能滿足該需求的基本抽象即可。
從適中的粒度開始,服務(wù)的粒度一定是業(yè)務(wù)推進的過程中不斷演化的,創(chuàng)新業(yè)務(wù)推動服務(wù)的粒度向更細的粒度裂變,而業(yè)務(wù)成熟穩(wěn)定后,又推動服務(wù)向粗粒度方向聚合。
站在復(fù)用的角度,優(yōu)先級是宏服務(wù)>小服務(wù)>微服務(wù),當然難度反之。
所以復(fù)用要根據(jù)自身團隊發(fā)展情況,業(yè)務(wù)實際需要靈活把握,也要根據(jù)公司的發(fā)展階段,逐步的實現(xiàn)復(fù)用。
總體來說復(fù)用的優(yōu)先級技術(shù)層面復(fù)用優(yōu)先于業(yè)務(wù)層面復(fù)用,團隊內(nèi)的復(fù)用優(yōu)先于團隊間的復(fù)用,項目級復(fù)用優(yōu)先于產(chǎn)品級復(fù)用。
如何更好的復(fù)用
老板要求復(fù)用有沒有錯?沒有錯!員工說復(fù)用太難是不是實情?是實情!作為技術(shù)領(lǐng)導(dǎo)者,我們的職責就是解決團隊的困難,實現(xiàn)老板的目標。
具體如何更好的復(fù)用,老譚根據(jù)自己的工作經(jīng)驗和對該問題的深度思考,提供一定的思路僅供參考。
①不要忽視技術(shù)棧的管理
站在復(fù)用的角度,不同的開發(fā)語言之間是很難復(fù)用的,雖然對于互聯(lián)網(wǎng)或者自運營的信息化而言,還可以通過服務(wù)共享的方式實現(xiàn)復(fù)用。
而對于我們更多以本地化交付的軟件產(chǎn)品研發(fā)而言,技術(shù)體系不統(tǒng)一對于復(fù)用和協(xié)同兼職就是噩夢。
我在負責公司研發(fā)之前,整個公司沒有統(tǒng)一的技術(shù)棧,每個部門幾乎都有自己的技術(shù)棧,當時存在 .net,Java,PHP 等多種語言開發(fā)的系統(tǒng),主流的 Java 語言還存在 Jfinal、SpringBoot、Dubbo 等不同的框架。
對于技術(shù)團隊最容易的代碼程序級別的復(fù)用因為技術(shù)體系的不統(tǒng)一而導(dǎo)致無法復(fù)用,團隊資源無法流動平衡的問題,這對于我們中小規(guī)模的研發(fā)團隊來說就是災(zāi)難。
分散的組織必然帶來不統(tǒng)一的技術(shù)架構(gòu),這就是有名的康威定律(后面還會詳細介紹)。
結(jié)合我自己的工作經(jīng)歷,對于技術(shù)棧的管理提供以下思路供參考:
確定團隊主流語言,主流開發(fā)框架,主流數(shù)據(jù)庫等:我們確定了 Java 語言為主流語言;SpringBoot 為主要開發(fā)框架;采用 SpringCloud 的微服務(wù)架構(gòu)體系;數(shù)據(jù)庫第一選擇為 MySQL,新項目全部統(tǒng)一到 MySQL。
減少非主流技術(shù)體系的資源投入,新的業(yè)務(wù)逐步以主流技術(shù)進行:我之前團隊使用比較小眾的 JFinal,同樣向主流框架 SpringBoot 切換;減少 Dubbo 的使用范圍;嚴格控制非 Java 體系的資源投入,新業(yè)務(wù)可以采用 Java 開發(fā)的混合體系。
逐步向前后端分離的開發(fā)方式轉(zhuǎn)變,大后端體系之后實行大前端:我們做技術(shù)的都清楚,后端穩(wěn)定,前端變化多端,前端的復(fù)用的優(yōu)先級是遠弱于后端的。
但是對老板們可就不一樣,后面的數(shù)據(jù)庫,服務(wù)接口啥的他們也看不見,最直觀的就是前端,所以不能忽視。
我們最先確定下前端的開發(fā)框架 VUE,防止前端技術(shù)的分化,傳統(tǒng)的前端開發(fā)根據(jù)實際需要有準備實現(xiàn)架構(gòu)的轉(zhuǎn)變。
其實這個轉(zhuǎn)變在前期是需要增加投入的,畢竟兩套體系前期要并行,老板質(zhì)問為何要切換前后端分離,當然她不知道的是,如果我們不轉(zhuǎn)變,我們現(xiàn)在連人(前后通吃)都招不到。
中間件不能濫用,新技術(shù)引進需要走技術(shù)評審:技術(shù)人員都比較熱衷各種中間件的使用,對新技術(shù)趨之若鶩,追求新技術(shù)沒有錯,創(chuàng)新也需要鼓勵。
但這些都需要管理,因為作為技術(shù)領(lǐng)導(dǎo)人,我們必須站在團隊整體角度平衡成本、效率、效益的關(guān)系,所以通過技術(shù)評審,我們既能引進新技術(shù),又能管理技術(shù)引進帶來的學習成本,大面積推廣的時機和條件。
通過這一系列的措施,我們至少在技術(shù)底層取得了適度的統(tǒng)一,不同團隊之間的技術(shù)交流就消除了障礙,大家就容易共同積累,促進共享。
②統(tǒng)一架構(gòu),構(gòu)建平臺級應(yīng)用
技術(shù)棧的統(tǒng)一,只能讓我們做到 LV1 和 LV2 層級的復(fù)用能力,再往上走就涉及到功能層面和業(yè)務(wù)層面了,而這更接近老板的視角了。
所以實現(xiàn)更高層次的復(fù)用是每個技術(shù)領(lǐng)導(dǎo)人的追求,也是發(fā)揮自身專業(yè)能力的舞臺。
但在這個環(huán)節(jié)我們往往會出現(xiàn)大問題,就是不能根據(jù)實際情況因地制宜,架構(gòu)體系的彈性很大,沒有嚴格的標準,只有根據(jù)實際情況的平衡,平衡是考驗技術(shù)領(lǐng)導(dǎo)人的架構(gòu)藝術(shù),不要小瞧了這個能力。
很多大廠的牛人去小企業(yè)做架構(gòu),太多失敗的案例,不是架構(gòu)不好,是沒有用對地方。
(1)對于小團隊而言,統(tǒng)一架構(gòu)體系,單體應(yīng)用一樣很美
我們一貫的常識就是,越是獨立的,沒有太多耦合關(guān)系的組件越容易復(fù)用,過去煙囪似的單體系統(tǒng)難以復(fù)用就是模塊和系統(tǒng)本身耦合太深而造成復(fù)用改造的成本很大。
這個理論是對的,但我認為不全面,完全去除耦合是不現(xiàn)實的,只是耦合的深淺和范圍是需要管理的,如果復(fù)用組件的使用者一樣耦合在同樣一個環(huán)境中,其實也是可以復(fù)用的。
這就像 A 系統(tǒng)要復(fù)用 B 系統(tǒng)的模塊其實是很困難的,因為耦合的環(huán)境不一樣,依賴的基礎(chǔ)不同;但是 A 系統(tǒng)內(nèi)要復(fù)用自身系統(tǒng)的某模塊卻非常容易,因為依賴環(huán)境是一樣的。
所以,小團隊如果在代碼層級能夠統(tǒng)一成一個應(yīng)用,然后通過插件化、代碼級的組件化對業(yè)務(wù)模塊進行抽象和管理,單體系統(tǒng)依然是很美的。
我在七八年前帶一個小型互聯(lián)網(wǎng)團隊,自己花了兩三個月時間寫了一套基于 JFinal(當時剛開始推出的小眾框架,現(xiàn)在已經(jīng)非常流行了)插件化的腳手架系統(tǒng)作為我們團隊所有業(yè)務(wù)開發(fā)的載體。
這么多年過去了,這個系統(tǒng)依然在健壯的運行,業(yè)務(wù)也在不斷持續(xù)的開發(fā)著。
我們實施的最新一代的 OA 系統(tǒng),如此龐大的系統(tǒng),通過部署結(jié)構(gòu)來看,其實也是一個大單體應(yīng)用。
所以,不是單體系統(tǒng)不好,只是當它太大以后,我們沒有能力管理好它而已。
(2)有一定規(guī)模的技術(shù)組織,構(gòu)建統(tǒng)一平臺底座
復(fù)用的成本以及難度往往都是組織規(guī)模擴大,尤其分化后才迅速提升的。
在一個多組織中實現(xiàn)組件的復(fù)用需要建立統(tǒng)一的標準,也不要完全去除依賴,而是盡可能依賴單一,大家都依賴這個單一的東西,這個依賴對復(fù)用的影響就會降低。
所以一定規(guī)模的技術(shù)組織,要通過構(gòu)建統(tǒng)一的平臺底座,將共享組件沉淀在平臺底座上,讓不同的業(yè)務(wù)共同依賴同一套底層的環(huán)境,通過平臺底座的共享能力,實現(xiàn)各垂直業(yè)務(wù)的橫向交流和協(xié)同。
這種模式特別適合軟件產(chǎn)品研發(fā)的企業(yè),構(gòu)建在厚實的平臺之上的產(chǎn)品研發(fā),既高效又善于組合和擴展,產(chǎn)品的邊界不會因為系統(tǒng)的隔離而變的僵化。
而且構(gòu)建平臺底座既適合單體架構(gòu)的應(yīng)用也適合分布式的微服務(wù)架構(gòu),平臺底座其實一個組織有規(guī)劃的復(fù)用的體系建設(shè)。
下圖是筆者團隊建設(shè)的平臺體系,后臺引擎由架構(gòu)團隊主要負責建設(shè),業(yè)務(wù)組件(屬于中臺范疇)由各研發(fā)團隊根據(jù)業(yè)務(wù)領(lǐng)域分別負責構(gòu)建,供做參考。
企業(yè)級的復(fù)用體系:中臺架構(gòu)
中臺的廣義上的定義:企業(yè)級能力復(fù)用平臺。
雖然我們的一體化平臺涉及到中臺服務(wù)部分,但是作為研發(fā)企業(yè),我們的中臺架構(gòu)和服務(wù)是面向客戶去交付的,幫助甲方客戶構(gòu)建中臺能力。
一般情況我們所說的中臺,不是廠商的中臺解決方案,而是一個互聯(lián)網(wǎng)企業(yè)或者一個傳統(tǒng)企業(yè)為了滿足自身數(shù)字化轉(zhuǎn)型的需要而構(gòu)建的中臺體系,它是面向企業(yè)運營的中臺體系而不是面向項目交付的中臺服務(wù)。
廣義上的中臺范圍是非常大的,涵蓋了企業(yè)運營的方方面面,而我們更關(guān)注的是企業(yè)中臺的載體即數(shù)字化運營中臺。
企業(yè)首先通過信息化建設(shè),將企業(yè)內(nèi)在業(yè)務(wù)從線下搬到了線上,這個階段我們構(gòu)建了一個個的單體系統(tǒng),這些系統(tǒng)集成都不容易,復(fù)用幾乎就更沒可能。最終導(dǎo)致大量的重復(fù)開發(fā)建設(shè),同時還帶了更大的系統(tǒng)治理的成本。
進入數(shù)字化時代,甚至是智能化時代,面對激烈的市場競爭,企業(yè)降本增效的需求愈發(fā)迫切,更好的復(fù)用,更敏捷的建設(shè)是企業(yè)迫切的愿望。
中臺體系的提出,是順應(yīng)這個時代的產(chǎn)物,所以企業(yè)關(guān)注中臺,嘗試中臺是對的,至于為什么會失敗,后面的文章再去探討。
對于一個有技術(shù)開發(fā)能力的企業(yè),比如互聯(lián)網(wǎng)企業(yè),科技企業(yè)等,中臺的復(fù)用能力不要極端的追求新建。
雖然這樣比較簡單,但對企業(yè)來說著實浪費,如上圖所示,首先單體應(yīng)用架構(gòu)向業(yè)務(wù)中臺架構(gòu)演變,能利用則利用,能改造就盡量不要新建,能沉淀就盡量沉淀。
根據(jù)康威定律,組織要支撐:被復(fù)用的組件需要進行修改定制時,我們需要組件的維護方提供支持,此時就需要相應(yīng)的溝通協(xié)調(diào)成本。
若組件提供方與組件使用方?jīng)]有任何利益關(guān)系,甚至于其利益是沖突的,那么組件提供方則缺乏動力為使用者提供支持,甚至于拒絕提供服務(wù)。
這時候溝通協(xié)調(diào)成本將會特別的大。(本文提到的那位研發(fā)負責人其實很大程度上也面臨這個問題,協(xié)調(diào)不動組件方修改,自己改又太有難度,與其不如自己造一個輪子了)
這個問題實際上不是一個軟件技術(shù)問題,這涉及到組織架構(gòu)的設(shè)計。因此要降低溝通協(xié)調(diào)成本,則需要更高一級的領(lǐng)導(dǎo)設(shè)計調(diào)整組件提供方與使用方之間的關(guān)系,使其達到利益相關(guān)、一致。
如下圖所示,每個人在自己管轄的范圍之內(nèi)都相對比較容易復(fù)用和協(xié)作(對應(yīng)顏色的橫向箭頭),而一旦超出了這個范圍,復(fù)用和協(xié)同的難度和成本就會急劇增加。
重溫下康威定律:
Conway’s law: Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations.
- Melvin Conway(1967)
設(shè)計系統(tǒng)的組織其產(chǎn)生的設(shè)計等價于組織間的溝通結(jié)構(gòu)。
已經(jīng)五十多年的康威定律依然是指導(dǎo)我們做系統(tǒng)設(shè)計和企業(yè)架構(gòu)的重要定律,它詮釋了系統(tǒng)架構(gòu)和組織架構(gòu)的對應(yīng)關(guān)系。
其實這非常容易理解,任何事情都是有人去執(zhí)行的,人的組織結(jié)構(gòu)決定了系統(tǒng)的架構(gòu)設(shè)計,一個分散型的組織很難有高度統(tǒng)一的架構(gòu),也注定難以復(fù)用。
當然一個集權(quán)化的組織,復(fù)用和協(xié)作的成本就很低,相反組織的活性會降低,自主性和創(chuàng)新性不足。
老板最重要的任務(wù)其實是通過設(shè)計組織的結(jié)構(gòu),來匹配做事情的邏輯,最終實現(xiàn)自己想要的效果,否則在一個人、物、事不匹配的環(huán)境里,只有一腔的熱血、殷切的希望和憤怒的咆哮也是無濟于事,這便是規(guī)律的不可違背性。
正如阿里巴巴實施中臺戰(zhàn)略,CTO 行癲(張建峰)親自掛帥負責中臺事業(yè)群,負責中臺戰(zhàn)略的推進。
同時作為當時整個集團的 CTO,在各事業(yè)部橫向推行中臺架構(gòu)體系又有誰不配合呢,可見阿里中臺戰(zhàn)略的執(zhí)行力有多強,這也是為什么阿里的中臺能夠成為行業(yè)的標桿,這與其組織的設(shè)計是分不開的。
最后總結(jié)一下,復(fù)用是老板的合理需求,是技術(shù)領(lǐng)導(dǎo)人的核心職責,是所有技術(shù)人的全局意識。
但復(fù)用的達成,不是老板的念念不忘,不是技術(shù)領(lǐng)導(dǎo)人的行政要求,也不是所有技術(shù)人的滿腹牢騷,它需要一個體系的設(shè)計,一個組織的支撐,一個相互信任的團隊文化,一個不斷完善的過程。任重而道遠,讓我們勵志前行!
作者:老譚
簡介:人人都是產(chǎn)品經(jīng)理專欄作家。經(jīng)歷程序員、技術(shù) Leader、研發(fā) Leader 等多種崗位,現(xiàn)任某公司產(chǎn)品研發(fā)負責人,擅長企業(yè) IT 架構(gòu)及互聯(lián)網(wǎng)產(chǎn)品架構(gòu)。
編輯:陶家龍
出處:轉(zhuǎn)載自公眾號菜根老譚(ID:CGLT_TAN)