大學畢業4年-回顧和總結(6)-技術研發-重構之法
大部分的公司,開發專案都是作坊式的,沒有產品和專案的需求分析,進而做出技術架構和詳細設計。
很多人,聽到上級和老闆的一個想法,就開始寫程式碼,邊寫邊改,甚至推倒重來。
最終,導致的常見結果之一,專案程式碼混亂,新員工甚至老員工,對專案理解比較吃力。
如果你去改造程式碼,改好了,沒有任何功勞。改出問題了,領導、測試、產品,很可能會說你不行。
這一點,是讓很多程式設計師糾結的地方。
我個人還是傾向重構的,先熟悉專案總體環境,從易到難。
專案開發,從外部看,就是一個個的功能。
從內部看,不就是一個個函式和API嗎。
只要輸入和輸出是穩定的,就不會出現重大的失誤,導致牽一髮動全身的不良後果。
下面記錄一些,我個人自己揣摩的一些重構方法,閱讀《重構》這本書,也帶給了我一些啟發。
1.命名規範化
包名、類名、方法名、變數名,取合適的英文單詞。
比如在一個電商專案中。
包名:com.company.shop.front.controller,前端系統的控制層
類名:OrderController,處理訂單的控制器
方法名:findById,根據id查詢物件,我個人更喜歡用get。
變數名:List<String> memberIdList = new ArrayList<String>();
會員id的list集合
比較坑的命名:Object tagcode = map.get("tagCode");
變數命名,沒有按照Java駝峰式命名規範來寫,“tagcode”和“tagCode”竟然同時存在。
在Java內部程式碼變數名,如果錯了還有提示,在Freemarker和JSP等介面中,字串的值,用錯了,根本沒有提示。
大小寫不統一的bug,還很難發現。
命名要一致:Controller、Service、Dao等,同一個人和不同人的,儘可能遵循一定的標準,閱讀和修改其他人程式碼也更順利。
2.程式碼合理組織
controller:控制器,響應請求,路由控制
service:服務層,處理業務邏輯
dao:資料訪問層
model:資料庫模型
bean:內部用的實體類
util:工具程式碼
interceptor:攔截器
其它程式碼,可以按照功能等進行劃分,讓人一眼望去,就知道這個包下的程式碼,大致做了什麼事情。
3.專案合理組織
合理拆分專案:
移動端,mobile專案
Web前端,front專案
後端管理:backend專案
合理服務拆分:
商品服務系統:ProductService專案
會員服務系統:UserService專案
登入服務系統:LoginService專案
訂單服務系統:OrderService專案
公共程式碼:Model模型、Util工具類
聽說淘寶和京東的電商網站,有幾百上千個服務。
4.使用最小最恰當的作用域
類,大多數類用的是public,public class ProductService,如果只是在包內部使用,可以去掉public。
欄位,儘可能用private, private ProductService productService。如果需要,通過get和set方法,來獲得和修改值。
方法/函式,對外被呼叫的用public,只在類的內部使用的,儘可能用private。
public void add(){
doAdd();
}
private void doAdd(){
}
很多人,內部程式碼都搞成public,乍一眼看上去,還以為外部有呼叫。
必須得看看依賴,才確定。
對外暴露了過多的介面,不該被呼叫的被呼叫了。
5.常量提取
"success",把作用一致並且相同的字串,提取成常量,統一管理。
其中一種方式:
public class FrontConst {
public static final String COOKIE_LOGINNAME = "loginNameCookie";
public static final String COOKIE_PASSWORD = "passWordCookie";
}
6.重複程式碼提取和封裝
業務程式碼,提取成私有方法,內部重複使用。
工具程式碼,提取到工具類中,可以複用,比如日期處理、把list轉換成map。
public class BizUtil {
/**
* 把1個集合,轉換成Map。用法示例:Map<String, Dictionary> dictionaryMap = BizUtil.listToMap("BIANMA", dictionarys);
* @param keyName 集合元素唯一欄位的名稱
* @param list 集合元素
* @return map
*/
public static <K, V> Map<K, V> listToMap(final String keyName, List<V> list) {
if(CollectionUtils.isEmpty(list)){
return null;
}
return Maps.uniqueIndex(list, new Function<V, K>() {
@Override
public K apply(V v) {
try {
return (K)PropertyUtils.getSimpleProperty(v, keyName);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
return null;
}
}
});
}
/**
* 把1個集合,轉換成Map。用法示例:Map<String, Dictionary> dictionaryMap =
* BizUtil.listToMap(String.class, Dictionary.class, "BIANMA", dictionarys);
*
* @param k
* Map的key的class
* @param v
* Map的value的class,集合list元素的型別
* @param keyName
* 集合元素唯一欄位的名稱
* @param list
* 集合元素
* @return map
*/
//這種方式,廢棄了,需要多傳2個引數
public static <K, V> Map<K, V> listToMap(Class<K> k, Class<V> v,
String keyName, List<V> list) {
Map<K, V> map = Maps.newHashMap();
if (CollectionUtils.isNotEmpty(list)) {
for (V val : list) {
try {
PropertyDescriptor pd = new PropertyDescriptor(keyName, v);
Method getMethod = pd.getReadMethod();// 獲得get方法
Object o = getMethod.invoke(val);// 執行get方法返回一個Object
if (o != null && o.getClass().equals(k)) {
map.put((K) o, val);
}
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException | IntrospectionException e) {
e.printStackTrace();
}
}
}
return map;
}
7.函式拆分
1個函式,有5個引數,有2種不同的使用場景。
同一個函式完成了2件不同的事情。
void add(int a,int b,int c);
換成
void addOrder(int a,int b);
void addProduct(int c)。
8.函式合併
2個函式,完成了類似的事情,簡化成1個,
函式是拆分,還是合併,要具體分析。
9.單一職責原則
一個專案、一個模組、一個類、一個函式,完成一件事。
如果完成了多件事,需要進行拆分成多個獨立的函式,至少內部需要進行拆分。
比如:
void add(int a,int b,int c)
可以拆分成
void add1(int a,int b)和void add2(int c)
也可以拆分成
void add(int a,int b,int c){
add1(a,b);
add2(c);
}
10.控制類和函式的行數
一個類,如果函式太多,往往是承載了太多的功能。
把不緊密相關的功能,堆積在了一起。
一個方法,如果程式碼超過了100行,存在問題的可能性就增大了很多。
在我自身的經歷中,很多同事的函式,只要超過100行,一眼望去就能發現問題。
另外,函式程式碼過多,修改bug和新增業務邏輯的時候,很容易引入新的問題。
因此,函式拆分、降低作用域,可以保證過去穩定的程式碼邏輯,不會有改動。
11.提前返回
先檢查錯誤,如果有問題,直接返回,以免巢狀過深。
public String add(){
Member member = this.getMember();
if(StringUtils.isBlank(...){
return error("地址資訊有誤!");
}
}
經常出現下面的情況
if(...){
if(...){
if(...){
}
}
}
return ...;
12.定義列舉
列舉是常量的進一步封裝。
public enum OrderPayStatusEnum {
NO("0", "未支付"), YES("1", "已支付");
private String code;
private String remark;
OrderPayStatusEnum(String code, String remark) {
this.code = code;
this.remark = remark;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public static String getPayStatus(String code){
if(StringUtils.isEmpty(code)){
return null;
}
if(code.equals(NO.getCode())){
return NO.getRemark();
}else if(code.equals(YES.getCode())){
return YES.getRemark();
}
return null;
}
}
13.統一API互動介面
後端和移動端,後端和Web前端的互動,都是Result的json字串。
後端,所有請求,統一都是返回Result。
public class Result {
private Integer code;
private String desc;
private Object data;
}
多人開發的時候,如果沒有架構師之類的角色,各自為戰,真是亂套。
14.模組化和依賴
大多數專案,都會有諸如郵件、簡訊驗證碼、登入服務、圖片雲服務等。
把配置檔案單獨拿出來,可以手動通過Spring的配置檔案,配置bean。
如果需要,引入配置檔案,不引入,程式碼也不會報錯。
spring-mail-config.xml
<context:property-placeholder location="file:${config_path}/config/mail.properties" ignore-unresolvable="true" />
<bean id="javaMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="${mailServerHost}" />
<property name="port" value="${mailServerPort}" />
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">true</prop>
<prop key="mail.smtp.timeout">25000</prop>
</props>
</property>
<!-- 傳送者使用者名稱 -->
<property name="username" value="${mailUserName}" />
<!-- 傳送者密碼 -->
<property name="password" value="${mailPassword}" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<bean id="mailClientServer" class="com.shop.common.mail.MailClientServer">
<property name="javaMailSender" ref="javaMailSender" />
<property name="configuration" ref="freeMarkerConfigurationFactory" />
<property name="mailFromAddress" value="${mailFromAddress}" />
</bean>
還比如,我們們的圖片用的阿里雲的OSS。
統一封裝。
配置檔案
oss.properties
oss.xml
<context:property-placeholder
location="file:${config_path}/config/oss.properties"
ignore-unresolvable="true" />
<bean id="ossConfig" class="com.shop.common.oss.OssConfig">
<property name="endpoint" value="${oss.endpoint}" />
<property name="bucketName" value="${oss.bucketName}" />
<property name="accessKeyId" value="${oss.accessKeyId}" />
<property name="accessKeySecret" value="${oss.accessKeySecret}" />
<property name="imgDomain" value="${oss.imgDomain}" />
<property name="fileDomain" value="${oss.fileDomain}" />
</bean>
Java程式碼
public class OssUtil {}
15.程式碼複用
程式碼複用,是一個廣泛的話題。
前文提到的列舉、常量、函式拆分,目的之一就是為了方便程式碼複用。
一個優秀的程式設計師,抵得上十個差的程式設計師,其中一個原因就是“程式碼複用多”。
總是寫重複的程式碼,把程式設計師這個智力密集型工作,幹成了體力密集型,早晚被累死。
梳理業務需求、做好業務方面的架構設計。
另外,技術方面的架構設計,完全掌握在技術人員手中,對業務的依賴不大。
開發一個功能時,先想好思路,技術方案,再寫程式碼。
架構複用、設計複用、工具類、列舉、常量。
另外還有一種,非常常見的,流程複用。
前端系統:
1.構造url和引數
2.執行請求,獲得資料
3.根據狀態碼,執行不同的操作
4.正常狀態,渲染資料,或執行動作
移動端:
流程類似
後端:
1.穩定並且統一的API介面
2.業務邏輯封裝
無論內部怎麼變,介面穩定,就不會影響Web前端和移動端。
在合適的時機,內部專案拆分,專案服務化。
重構的技巧,還是有很多的,更多還是看個人對程式設計的理解。
對於有經驗的程式設計師來說,《重構》是一本不錯的書,可以用來快速加深平時對專案程式碼的梳理。
對於新手來說,《重構》和設計模式,這種書,受益偏小。
小雷-一個有獨立見解的年輕人
2016年4月16日~清明節剛過,五一又要來了
湖北-武漢~聽說最近有幾條公交專線要開通了
最近,有好多好多的想法和話題要寫,時間不太夠。
更準確來說, 時間是有的,寫文章,也要看心情。
寫一篇嚴肅一點的長篇大論,一般都需要1小時以上。
在寫作之前,大腦裡面一直在不斷地“打草稿”,寫的過程中,需要不斷髮散,要有條理,還要嚴謹,站得住腳。
一些問題的根源,也許是我的身價還是太低了,更多時間忙著搞錢,一些有價值的事情,只能慢慢地去做。
相關文章
- 大學畢業4年-回顧和總結-序
- 大學畢業4年-回顧和總結(7)-全域性觀
- 大學畢業4年-回顧和總結(2)-錢,收入和支出
- 大學畢業4年-回顧和總結(1)-錢,金錢觀
- 大學畢業4年-回顧和總結(5)-投資理財方法論
- 大學畢業4年-回顧和總結(3)-投資理財觀-圖窮而真相現
- 大學畢業4年-回顧和總結(8)-全域性觀-網際網路專案研發-不在其位亦謀其政
- 大學畢業4年-回顧和總結(4)-投資理財無敗績,有圖有真相
- 大學畢業4年-回顧和總結(10)-資金賬務系統的架構設計(產品視角+技術視角)(圖文並茂)架構
- 南通大學《構建之法》課程助教總結
- 創業生活總結回顧創業
- SCM配置管理技術總結及要點回顧
- 一個技術創業者的2018年度回顧和總結 | 掘金年度徵文創業
- 2021年度總結 | 葡萄城軟體開發技術回顧(上)
- 2021年度總結 | 葡萄城軟體開發技術回顧(下)
- oracke閃回技術總結
- 畢業6年,技術人的不惑之路
- 2017 前端技術發展回顧前端
- [活動回顧] 實時音視訊技術專場總結來啦!
- 指尖前端重構(React)技術調研分析前端React
- 《Linux shell變數總結回顧》RHEL6(轉)Linux變數
- JavaScript 建立物件與繼承總結和回顧JavaScript物件繼承
- 年終回顧,為你彙總一份「後端架構技術清單」後端架構
- 2012年創業回顧與總結創業
- 程式碼重構之法——方法重構分析
- 大學總結,技術與技術之外的事 | 掘金年度徵文
- 大學畢業4年-回顧和總結(10)-文件化戰略,執行最成功的戰略,堪比我人生中的“隆中對”(戰略在前,成果在後)
- 經典資料結構和演算法回顧資料結構演算法
- SAP產品增強技術回顧
- 回顧大學本科三年
- 大老師的前生——AlphaMao專案的回顧和總結
- 大學畢業4年-回顧和總結(9)-股權投資1年,給自己一個答卷(好狗狗、皇包車、職業夢、比呀比、易途8)(創業有風險,投資需謹慎)創業
- 年終回顧,為你彙總一份「前端技術清單」前端
- 年終回顧 | 為你彙總一份「前端技術清單」前端
- 快速技術成長:提煉和總結專案中的技術重難點
- 【資料結構】回顧棧ADT和隊ADT資料結構
- 【資料結構】回顧表ADT資料結構
- 圓滿落幕!回顧 eBPF 技術的發展與挑戰eBPF