框架組件,究竟要不要自己重復造輪子?
有朋友在星球問我:
框架組件,究竟要不要自研?究竟要不要建設自研技術體系。
15年加盟到家后,框架/組件/基礎服務/技術平臺,正好也是自己負責范圍的一部分,故談一談自己的想法。

為什么早期不建議自研?
早期研發(fā)人數較少,公司也不確定能走多遠,業(yè)務相對簡單,業(yè)務以“快速迭代”為最高優(yōu)先級,此時一般會選擇“自己熟悉的技術”作為選型:
- 研發(fā)語言:熟PHP選PHP,熟Java選Java;
- 數據庫:熟MySQL選MySQL,熟SQL-server選SQL-server;
- 框架組件:熟Ruby on Rails選ROR,熟ThinkPHP選ThinkPHP,熟Spring boot才選;
- …
此時千萬不要糾結選型,選自己熟悉的,業(yè)務以快速迭代為最優(yōu)先,公司得先生存下來。
多說一句,此時對于技術合伙人的技術視野就有一定要求,如果早期方向不對,等公司發(fā)展若干年,數據量并發(fā)量上漲很多倍,成本以及未來的技術應對恐怕會有麻煩。
58早期選型是微軟技術體系,后來數據量增大,并發(fā)量增大,機器數據庫越來越多,性能扛不住,成本也扛不?。悴乱粋€SQL-server的licence一年多少錢?),后來CTO帶領大家轉型開源陣營,雖然陣痛了1-2年,但長遠來說,絕對是正確的決策。
如今,如果你再創(chuàng)業(yè),選云,選Spring體系,八成不會走太大的彎路。
隨著規(guī)模的擴大,為什么要控制技術棧?
隨著業(yè)務越來越復雜,研發(fā)人數越來越多,如果每個leader都選擇自己擅長的框架,就會出現這樣的情況:
- 站點框架,team A用著SSH,team B用著Spring+SpringMVC+Mybatis;
- 服務框架,team C用著REST,team D用著dubbo,team E用著thrift;
- 數據庫訪問,team X用著mybatis,team Y用著DAO,team Z用著jdbc;
- …
對于整體而言,跨部門的調用越來越麻煩,重復造的輪子越來越多,技術效率會逐步降低,研發(fā)+測試+運維成本都越來越高。
第一個觀點:即使不自研,技術棧也請盡量統(tǒng)一。
統(tǒng)一了技術棧,為什么建議淺淺的封裝一層?
統(tǒng)一了技術棧以后,如果不封裝,redis官方Java客戶端Jedis可能有這樣一些接口:
String Memcache::get(String key)
String Memcache::set(String key, String value)
String Memcache::del(String key)淺淺的封裝一層,會變成這樣:
String DaojiaKV::get(String key) {
String result = Memcache::get(key);
return result;
}
String DaojiaKV::set(String key, String value) {
String result = Memcache::set(key, value);
return result;
}
String DaojiaKV::del(String key) {
String result = Memcache::del(key);
return result;
}這有什么好處呢?
- 對上游屏蔽底層實現的細節(jié),調用方不用關注緩存是memcache還是redis,調用方只關注DaojiaKV;
- 底層變化的時候,對上游透明,當memcache不能滿足需求,要切換為redis時,所有調用方不需要大的變化,升級一個最新的DaojiaKV即可,DaojiaKV的接口不變,實現變?yōu)椋?/li>
String DaojiaKV::get(String key) {
String result = Jedis::get(key);
return result;
}
String DaojiaKV::set(String key, String value) {
String result = Jedis::set(key, value);
return result;
}
String DaojiaKV::del(String key) {
String result = Jedis::del(key);
return result;
}- 統(tǒng)一實現一些通用的功能,就不需要每一個上游升級了,例如,要實現一個緩存訪問時間統(tǒng)計的功能,所有調用方不需要大的變化,升級一個最新的DaojiaKV即可:
String DaojiaKV::get(String key) {
Long startTime = now();
String result = Jedis::get(key);
Long endTime = now();
reportKVTime(startTime- endTime);
return result;
}
String DaojiaKV::set(String key, String value) {
Long startTime = now();
String result = Jedis::set(key, value);
Long endTime = now();
reportKVTime(startTime- endTime);
return result;
}
String DaojiaKV::del(String key) {
Long startTime = now();
String result = Jedis::del(key);
Long endTime = now();
reportKVTime(startTime- endTime);
return result;
}同理,如果要實現統(tǒng)一的告警,調用鏈跟蹤,SQL執(zhí)行時間,也可以用類似的方法。
第二個觀點:第三方庫,不但要統(tǒng)一,還可以淺淺地封裝一層,預留未來的擴展性。
隨著規(guī)模的進一步擴大,為什么需要適當的造一些輪子?
業(yè)務進一步發(fā)展,研發(fā)團隊進一步擴張,雖然使用了統(tǒng)一的技術棧,但不同研發(fā)團隊的痛點是極其類似的:
- 有站點,監(jiān)控服務的可用性,處理時間監(jiān)控需求;
- 有告警需求;
- 有自動化發(fā)布,自動化運維需求;
- 有服務治理,服務自動發(fā)現需求;
- 有調用鏈跟蹤需求;
- 有SQL監(jiān)控需求;
- 有系統(tǒng)層面數據收集與可視化展現的需求;
- …
此時,開源的框架可能滿足不了需求了:
- 開源框架/組件太重了,我們需要的可能只是一個輕量級的框架/組件;
- 開源框架/組件,只能滿足我們的一部分需求;
- 不了解開源框架/組件的設計理念,要二次開發(fā)成本更高(維護dubboX的同學,維護數據庫中間件Atlas的同學可以出來說兩句);
- 有些通用的需求是和業(yè)務緊密結合的,開源框架/組件可能滿足不了;
- …
此時,如果技術實力具備,可以統(tǒng)一研發(fā)一些框架和組件,解決所有技術團隊的通用痛點,滿足所有技術團隊的通用需求。
第三個觀點:適當造一些輪子。
總結
框架組件,是否需要自研?
初期建議:不自研,用熟悉的,業(yè)務快速迭代為優(yōu)先,需要一定技術視野。
長遠建議:
- 統(tǒng)一技術棧;
- 淺淺封裝一層;
- 適當造輪子;






















