【実装】リファクタリング


#テスト駆動開発時によく使うリファクタリング方法
##1.Extract Function
```javascript:before.js
function printOwing(invoice) {
  printBanner();
  let outstanding = calculateOutstanding();

  //print details
  console.log(`name: ${invoice.customer}`);
  console.log(`amount: ${outstanding}`);
}
```
```javascript:after.js
function printOwing(invoice) {
  printBanner();
  let outstanding = calculateOutstanding();
  printDetails(outstanding);
}
function printDetails(outstanding) {
  console.log(`name: ${invoice.customer}`);
  console.log(`amount: ${outstanding}`);
}
```
##2.Inline Function
```javascript:before.js
function getRating(driver) {
  return moreThanFiveLateDeliveries(driver) ? 2 : 1;
}

function moreThanFiveLateDeliveries(driver) {
  return driver.numberOfLateDeliveries > 5;
}
```
```javascript:after.js
function getRating(driver) {
  return (driver.numberOfLateDeliveries > 5) ? 2 : 1;
}
```
##3.Extract Variable
```javascript:before.js
return order.quantity * order.itemPrice -
  Math.max(0, order.quantity - 500) * order.itemPrice * 0.05 +
  Math.min(order.quantity * order.itemPrice * 0.1, 100);
```
```javascript:after.js
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 + shipping;
```
##4.Inline Variable
```javascript:before.js
let basePrice = anOrder.basePrice;
return (basePrice > 1000);
```
```javascript:after.js
return anOrder.basePrice > 1000;
```
##5.Change Function Declaration
```javascript:before.js
function circum(radius) {...}
```
```javascript:after.js
function circumference(radius) {...}
```
##6.Encapsulate Variable
```javascript:before.js
let defaultOwner = {firstName: "Martin", lastName: "Fowler"};
```
```javascript:after.js
let defaultOwnerData = {firstName: "Martin", lastName: "Fowler"};
export function defaultOwner()       {return defaultOwnerData;}
export function setDefaultOwner(arg) {defaultOwnerData = arg;}
```
##7.Rename Variable
```javascript:before.js
let a = height * width;
```
```javascript:after.js
let area = height * width;
```
##8.Introduce Parameter Object
```javascript:before.js
function amountInvoiced(startDate, endDate) {...} 
function amountReceived(startDate, endDate) {...} 
function amountOverdue(startDate, endDate) {...}
```
```javascript:after.js
function amountInvoiced(aDateRange) {...} 
function amountReceived(aDateRange) {...} 
function amountOverdue(aDateRange) {...}
```
##9.Combine Functions into Class
```javascript:before.js
function base(aReading) {...}
function taxableCharge(aReading) {...} 
function calculateBaseCharge(aReading) {...}
```
```javascript:after.js
class Reading { 
  base() {...}
  taxableCharge() {...} 
  calculateBaseCharge() {...}
}
```
##10.Combine Functions into Transform
```javascript:before.js
function base(aReading) {...}
function taxableCharge(aReading) {...}
```
```javascript:after.js
function enrichReading(argReading) {
  const aReading = _.cloneDeep(argReading);
  aReading.baseCharge = base(aReading);
  aReading.taxableCharge = taxableCharge(aReading);
  return aReading;
}
```
##11.Split Phase
```javascript:before.js
const orderData = orderString.split(/\s+/);
const productPrice = priceList[orderData[0].split("-")[1]]; 
const orderPrice = parseInt(orderData[1]) * productPrice;
```
```javascript:after.js
const orderRecord = parseOrder(order);
const orderPrice = price(orderRecord, priceList);

function parseOrder(aString) {
  const values = aString.split(/\s+/); 
  return ({
    productID: values[0].split("-")[1], 
    quantity: parseInt(values[1]),
  });
}
function price(order, priceList) {
  return order.quantity * priceList[order.productID];
}
```
---
#後記
>「リファクタリング 既存のコードを安全に改善する」の読むメモ