《重構:改善既有代碼的設計》 讀書筆記 第一章
鏈接: https://pan.baidu.com/s/1b3cTGmABb66zeCV-5DY-LQ 提取碼: 6a9n
里面存在的個人觀點,我都會用斜體來表示。
重要的結論,我會用粗體表示。
序言
開篇講了一個故事,說一個顧問建議一個團隊去重構,重構使得代碼變得更美了,但重構花費了時間,并沒有新增加功能,項目經理其實很不滿意,這個項目也在6個月后失敗了。有一句古老的工程諺語:“如果它還可以運行,就別去動它”。
那么重構是什么呢?
重構的定義是,在代碼寫好之后改進它的設計。
第一章
下面介紹了一個戲劇演出團的程序
首先是數據的格式:
plays.json,劇目數據
{
"hamlet": {"name": "Hamlet", "type": "tragedy"},
"as-like": {"name": "As You Like It", "type": "comedy"},
"othello": {"name": "Othello", "type": "tragedy"}
}
invoices.json 賬單數據
[
{
"customer": "BigCo",
"performances": [
{
"playID": "hamlet",
"audience": 55
},
{
"playID": "as-like",
"audience": 35
},
{
"playID": "othello",
"audience": 40
}
]
}
]
然后有了一個程序來輸出這個賬單的情況
function statement (invoice, plays) {
let totalAmount = 0;
let volumeCredits = 0;
let result = `Statement for ${invoice.customer}\n`;
const format = new Intl.NumberFormat("en-US",{ style: "currency", currency: "USD",minimumFractionDigits: 2 }).format;
for (let perf of invoice.performances) {
const play = plays[perf.playID];
let thisAmount = 0;
switch (play.type) {
case "tragedy":
thisAmount = 40000;
if (perf.audience > 30) {
thisAmount += 1000 * (perf.audience - 30);
}
break;
case "comedy":
thisAmount = 30000;
if (perf.audience > 20) {
thisAmount += 10000 + 500 * (perf.audience - 20);
}
thisAmount += 300 * perf.audience;
break;
default:
throw new Error(`unknown type: ${play.type}`);
}
// add volume credits
volumeCredits += Math.max(perf.audience - 30, 0);
// add extra credit for every ten comedy attendees
if ("comedy" === play.type) volumeCredits += Math.floor(perf.audience / 5);
// print line for this order
result += ` ${play.name}: ${format(thisAmount/100)} (${perf.audience} seats)\n`;
totalAmount += thisAmount;
}
result += `Amount owed is ${format(totalAmount/100)}\n`;
result += `You earned ${volumeCredits} credits\n`;
return result;
}
執行這個程序的話,得到的輸出就是
Statement for BigCo
Hamlet: $650.00 (55 seats)
As You Like It: $580.00 (35 seats)
Othello: $500.00 (40 seats)
Amount owed is $1,730.00
You earned 47 credits
1.2 評價這個程序
其實這個代碼很小,也非常簡單,就是一個算賬的程序。
如果你發現加一個特性因為代碼缺乏良好結構而導致比較難加這個特性的時候,你應該先重構這個代碼,然后再加特性
(個人評價:我覺得這句話是句廢話,如果我覺得這個代碼很好加特性的時候,我當然就直接把這個特性加進去了;但是如果我加不進去,我當然就只能重構了呀。)
這時候作者開始提需求了:
需求一:假設現在想要輸出html的格式怎么辦?
-
部分程序員會采用if else 來判斷輸出為html還是輸出為log,這樣會使得代碼變得非常麻煩。
-
部分程序員會采用復制一遍,然后變成兩個函數來輸出。當然這個做法顯然不可行,未來假設要改的時候,就要必須修改兩個地方。
需求二:假設演員有更多的表演類型了怎么辦?不同的表演類型肯定有不同的計費方式。
這里作者強調了一句話:如果代碼現在能正常工作,且不會被修改,那就別重構;除非有人想看你的代碼,且別人看不懂,你可以改進一下。
(我覺得主要還是看收益吧,假設原工程總量為V,重構實際上花費了t的時間,增加了未來的效率dx。那么只要V/(x+dx)+t < V/x 就可以開始重構。當然里面的問題是t和dx根本不好評估。)
1.3 重構的第一步
重構的第一步是良好的測試。
(但國內的公司其實并不在乎這個,特別是自動化測試,往往log看上去對了就ok了,可能是習慣問題?)
1.4 分解statement函數
中間那一大坨的計算函數,實際上是可以抽離出來的,作者也進行了抽離。
function amountFor(perf, play) {
let thisAmount = 0;
switch (play.type) {
case "tragedy":
thisAmount = 40000;
if (perf.audience > 30) {
thisAmount += 1000 * (perf.audience - 30);
}
break;
case "comedy":
thisAmount = 30000;
if (perf.audience > 20) {
thisAmount += 10000 + 500 * (perf.audience - 20);
}
thisAmount += 300 * perf.audience;
break;
default:
throw new Error(`unknown type: ${play.type}`);
}
return thisAmount;
}
做完這個改動后,主程序就會變成
function statement (invoice, plays) {
let totalAmount = 0;
let volumeCredits = 0;
let result = `Statement for ${invoice.customer}\n`;
const format = new Intl.NumberFormat("en-US",
{ style: "currency", currency: "USD",
minimumFractionDigits: 2 }).format;
for (let perf of invoice.performances) {
const play = plays[perf.playID];
let thisAmount = amountFor(perf, play);
// add volume credits
volumeCredits += Math.max(perf.audience - 30, 0);
// add extra credit for every ten comedy attendees
if ("comedy" === play.type) volumeCredits += Math.floor(perf.audience / 5);
// print line for this order
result += ` ${play.name}: ${format(thisAmount/100)} (${perf.audience} seats)\n`;
totalAmount += thisAmount;
}
result += `Amount owed is ${format(totalAmount/100)}\n`;
result += `You earned ${volumeCredits} credits\n`;
return result;
注意做完每一次小改動后,都應該過一次測試。
重構技術應該以微小的步伐進行修改程序,如果你犯錯,這樣會很容易發現問題。
然后提煉函數是一個可以用ide自動完成的重構。真的嗎??idea居然真的可以自動抽離函數
然后作者不停的進行重構,這里重構過程略。要看重構方法可以見:https://blog.csdn.net/qq_31126175/article/details/90085409
好代碼的定義應該是 人們能夠很簡單的修改它
對于我而言,我覺得他的重構部分還是比較繁瑣。比如我就從沒用過多態

浙公網安備 33010602011771號