讀書心得(未完
本書不厚,第一版範例語言為 Java,
第二版改為大家熟悉的 JavaScript
而且為中文版本(雖然某些地方翻譯怪怪的
總共有 12 個章節,2、3 章節談論心法、
有異味的程式碼。
剩餘章節都在談論重構的範例及方法。
睡前讀書有助於睡眠
不太適合從第一章開始讀,建議先讀後面章節再回來看第一章
先看文字重點
夏令營結束後孩子們離開營地,要打掃衛生保持整潔,讓營地比來時更乾淨。
在重構過程中發現的 bug 也應該在重構之後繼續存在(即使你可以修好它XD)
不會在加入功能時修改既有的程式碼,只會加入新的功能。
也會加入測試程式,藉著讓測試正常執行來了解進度。
重構時,只會重組程式碼,刻意不加入功能。不加入任何測試(除非漏了)
除非為了配合介面的變動而更改測試。
新功能
發現重構後新功能更容易加入
重構
加入新功能
新功能正常後發現程式寫法難以理解
重構
跟著做就對了,免得人家笑我不懂
我希望他做的事情 與 我告訴他做的事情
花一些時間重構,可讓程式碼更明確的傳達他的意圖,讓未來開發者更開心。
Design Stamina Hypothesis
當你第一次做某件事情,儘管去做;
第二次做類似的事情時,因為已經做過了,雖然你有些猶豫,但還是去做那件重複的事情。
當你第三次做類似的事情時,就重構他吧!
重構 與 添加新功能 分成兩個不同的版本,分別提交至系統。優點是可以分別 review
跟批准他們
作者認為重構與新功能是交織再一起的,這種作法會移除重構的背後原因
如果主管真的懂技術,也可以理解設計耐力假說,向他們證明重構合理性並不難。
或是…不要說出來
“If it stinks, change it.”
function printOwing(ivoce) {
printBanner();
let outstanding = calculateOutstanding();
console.log(`name: ${invoice.customer}`);
console.log(`amountL ${outstaning}`);
}function printOwing(ivoce) {
printBanner();
let outstanding = calculateOutstanding();
printDetails(outstanding)
function printDetails(outstanding) {
console.log(`name: ${invoice.customer}`);
console.log(`amountL ${outstaning}`);
}
}逆操作:Inline Function
function getRatig(driver) {
return moreThanFiveLateDeliveries(driver) ? 2 : 1;
}
function moreThanFiveLateDeliveries(driver) {
return driver.numberOfLateDeliveries > 5;
}function getRatig(driver) {
return (driver.numberOfLateDeliveries > 5) ? 2 : 1;
}逆操作:Extract Fuction
return order.quantity * order.itemPrice -
Math.max(0, order.quantity - 500) * order.itemPrice * 0.05 +
Math.min(order.quantity * order.itemPrice * 0.1, 100);const basePrice = order.quantity * order.itemPrice
const quantityDiscount = Math.max(0, order.quantity - 500) * order.itemPrice * 0.05
const shipping = Math.min(basePrice * 0.1, 100);
return basePrice - quantityDiscount + shippingExtract Variable(提取變數)
class Order {
constructor(aRecord){
this._data = aRecord;
}
get quantity() {return this._data.quantity;}
get itemPrice() {return this._data.itemPrice;}
get price() {
return this.quantity * this.itemPrice -
Math.max(0, this.quantity - 500) * this.itemPrice * 0.05 +
Math.min(this.quantity * this.itemPrice * 0.1, 100);
}
}class Order {
constructor(aRecord){
this._data = aRecord;
}
get quantity() {return this._data.quantity;}
get itemPrice() {return this._data.itemPrice;}
get price() {
return this.basePrice - this.quantityDiscount + this.shipping;
}
get basePrice() {return this.quantity * this.itemPrice;}
get quantityDiscount() {return Math.max(0, this.quantity - 500) * this.itemPrice * 0.05;}
get shipping() {return Math.min(this.quantity * this.itemPrice * 0.1, 100)}
}同一段程式,改成類別範例
let basePrice = anOrder.basePrice;
return (basePrice > 1000);return anOrder.basePrice > 1000;
逆操作:Extract Variable
function circum(radius) {...}
function circumference(radius) {...}
let defaultOwner = {firstName: 'Martin', lastName: 'Fowler'};
let defaultOwnerData = {firstName: 'Martin', lastName: 'Fowler'};
export function defaultOwner() {return defaultOwnerData;}
export function setDeafultOwner(arg) {defaultOwnerData = arg;}let defaultOwnerData = {firstName: 'Martin', lastName: 'Fowler'};
export function defaultOwner() {return new Person(defaultOwnerData);}
export function setDeafultOwner(arg) {defaultOwnerData = arg;}
class Person {
constructor(data){
this._lastName = data.lastName;
this._firstName = data.firstName;
}
get lastName() {return this._lastName;}
get firstName() {return this._firstName;}
}let a = height * width;
let area = height * width;function amountInvoiced(starDate, endDate) {...}
function amountReceived(starDate, endDate) {...}
function amountOverdue(starDate, endDate) {...}function amountInvoiced(aDateRange)) {...}
function amountReceived(aDateRange)) {...}
function amountOverdue(aDateRange)) {...}function base(aReading) {...}
function taxableCharge(aReading) {...}
function calculateBaseCharge(aReading) {...}class Reading {
base() {...}
taxableCharge() {...}
calculateBaseCharge() {...}
}