【リファクタリングカタログ】関数宣言の変更

## 書籍 [リファクタリング―既存のコードを安全に改善する 第2版](https://www.yodobashi.com/product/100000009003204206/)
または[Web版](https://martinfowler.com/articles/access-refactoring-web-edition.html)（の方が完全版なんですが）には、
これを補完する [リファクタリングカタログ](https://refactoring.com/catalog/) が公開されています
## これは何
書籍およびカタログはサンプルコードが JavaScript です、
カタログをもとに Python でリファクタリングのサンプルコードを示します

詳細解説は本にお任せして、「ここをこうこうこう」くらいのノリで示します

## カタログ：Change Function Declaration
https://refactoring.com/catalog/changeFunctionDeclaration.html

```javascript:当初コード、JavaScript版
function circum(radius) {
  return 2 * Math.PI * radius;
}
```
```javascript:リファクタリング後
function circumference(radius) {
  return 2 * Math.PI * radius;
}
```
### Python版
```python:当初コード
import numpy as np
def circum(radius):
  return 2 * np.pi * radius
```

### テストコード
```python:テストコード、三角測量
from unittest import TestCase
import numpy as np
class TestCatalog(TestCase):
  def test_circum_10(self):
    self.assertEqual(circum(10), 20*np.pi)
  def test_circum_20(self):
    self.assertEqual(circum(20), 40*np.pi)
```

### ここをこうこうこう
```python:内部関数を追加
import numpy as np
def circum(radius):
  def circumference(radius): # add
    return 2 * np.pi * radius # add
  return 2 * np.pi * radius
```

```python:内部関数を利用する
import numpy as np
def circum(radius):
  def circumference(radius):
    return 2 * np.pi * radius
  return circumference(radius) # edit
```

```python:関数を外部化、変数を抽出
import numpy as np
def circum(radius):
  return circumference(radius)
def circumference(radius): # move
  return 2 * np.pi * radius # move
```

```python:テストの対象を変更
from unittest import TestCase
import numpy as np
class TestCatalog(TestCase):
  def test_circum_10(self):
    self.assertEqual(circumference(10), 20*np.pi) # edit
  def test_circum_20(self):
    self.assertEqual(circumference(20), 40*np.pi) # edit
```

```python:未使用関数を除去
import numpy as np
def circumference(radius):
  return 2 * np.pi * radius
```

### 出来上がり
この例のような変更はエディタのリファクタリング機能が助けてくれることもあると思います、
引数の追加、除去も同様の手順で安全にリファクタリングできます

## 引数の変更の例
オブジェクトの一部だけ使うのに、引数ではオブジェクト丸ごと渡しているのを是正したいケース

```javascript:当初コード、JavaScript版
function inNewEngland(aCustomer) {
  return ["MA", "CT", "ME", "VT", "NH", "RI"].includes(aCustomer.address.state);
}
```
```javascript:リファクタリング後
function inNewEngland(stateCode) {
  return ["MA", "CT", "ME", "VT", "NH", "RI"].includes(stateCode);
}
```
### Python版
```python:当初コード
def inNewEngland(aCustomer):
  return aCustomer.address.state in ["MA", "CT", "ME", "VT", "NH", "RI"]
```

### テストコード
```python:テストコード
from unittest import TestCase
from collections import namedtuple
class TestCatalog(TestCase):
  def test_inNewEngland(self):
    address = namedtuple("address", "state")
    aCustomer = namedtuple("aCustomer", "address")
    customer = aCustomer(address("MA"))
    self.assertTrue(inNewEngland(customer))
```

### ここをこうこうこう
```python:変数の抽出
def inNewEngland(aCustomer):
  stateCode = aCustomer.address.state # add
  return stateCode in ["MA", "CT", "ME", "VT", "NH", "RI"] # edit
```
```python:関数の抽出
def inNewEngland(aCustomer):
  stateCode = aCustomer.address.state
  return xxinNewEngland(stateCode) # edit
def xxinNewEngland(stateCode): # add
  return stateCode in ["MA", "CT", "ME", "VT", "NH", "RI"] # add
```
```python:変数のインライン化
def inNewEngland(aCustomer):
  return xxinNewEngland(aCustomer.address.state) # edit
def xxinNewEngland(stateCode):
  return stateCode in ["MA", "CT", "ME", "VT", "NH", "RI"]
```
```python:テストの対象を変更
from unittest import TestCase
from collections import namedtuple
class TestCatalog(TestCase):
  def test_inNewEngland(self):
    address = namedtuple("address", "state")
    aCustomer = namedtuple("aCustomer", "address")
    customer = aCustomer(address("MA"))
    self.assertTrue(xxinNewEngland(customer.address.state)) # edit
```
```python:未使用関数を除去、そして、関数名の変更
def inNewEngland(stateCode):
  return stateCode in ["MA", "CT", "ME", "VT", "NH", "RI"]
```
### 出来上がり
最後ちょっとジャンプしましたが、関数名の変更はエディタの機能が助けてくれると期待します

以上

## 参考
(Youtube)マーチンファウラーによろしく - リファクタリングカタログ - 関数宣言の変更 @ Tommy109
<iframe width="560" height="315" src="https://www.youtube.com/embed/KzStiWzLwg4" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>