【リファクタリングカタログ】関数の抽出
書籍 リファクタリング―既存のコードを安全に改善する 第2版
またはWeb版(の方が完全版なんですが)には、
これを補完する リファクタリングカタログ が公開されています
これは何
書籍およびカタログはサンプルコードが JavaScript です、
カタログをもとに Python でリファクタリングのサンプルコードを示します
詳細解説は本にお任せして、「ここをこうこうこう」くらいのノリで示します
カタログ:Extract Function
function printOwing(invoice) {
printBanner();
let outstanding = calculateOutstanding();
//print details
console.log(`name: ${invoice.customer}`);
console.log(`amount: ${outstanding}`);
}
function printOwing(invoice) {
printBanner();
let outstanding = calculateOutstanding();
printDetails(outstanding);
function printDetails(outstanding) {
console.log(`name: ${invoice.customer}`);
console.log(`amount: ${outstanding}`);
}
}
Python版
from logging import getLogger
logger = getLogger(__name__)
def printOwing(invoice):
printBanner()
outstanding = calculateOutstanding()
# print details
logger.debug(f"name: {invoice.customer}")
logger.debug(f"amount: {outstanding}")
と行きたいところですが、書籍を見ると、printBanner, calculateOutstanding の導出前から始まっていて、ぐぬぬ、という訳で改めまして
さらに書籍には無い具体コードを参考動画から拝借しまして
function printOwing(invoice) {
let outstanding = 0;
console.log("***********************");
console.log("**** Customer Owes ****");
console.log("***********************");
// calculate outstanding
for (const o of invoice.orders) {
outstanding += o.amount;
}
// record due date
const today = Clock.today;
invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 30);
//print details
console.log(`name: ${invoice.customer}`);
console.log(`amount: ${outstanding}`);
console.log(`due: ${invoice.dueDate.toLocaleDateString()}`);
}
class Clock {
static get today() {return new Date(2021, 0, 30)}
}
とはいえ Clock の狙いはテスト時にオーバライドすること (bliki) なので、Pythonコードとしてはもうちょい素直に datetime.now を返しておきます
という訳で初期コードはつぎのようになります
Python版、改
from dataclasses import dataclass
from dataclasses import field
from datetime import date
from datetime import datetime
from datetime import timedelta
from logging import getLogger
logger = getLogger(__name__)
def printOwing(invoice):
outstanding = 0
logger.debug("***********************")
logger.debug("**** Customer Owes ****")
logger.debug("***********************")
# calculate outstanding
for o in invoice.orders:
outstanding += o.amount
# record due date
today: datetime = Clock.today
invoice.dueDate = date(today.year, today.month, today.day) + timedelta(days=30)
# print details
logger.debug(f"name: {invoice.customer}")
logger.debug(f"amount: {outstanding}")
logger.debug(f"due: {invoice.dueDate}")
@dataclass
class Clock:
today: datetime = datetime.now()
@dataclass
class Order:
amount: int = 0
@dataclass
class Invoice:
customer: str = ""
orders: list[Order] = field(default_factory=list)
dueDate: datetime = Clock()
テストコード
from unittest import TestCase
from unittest.mock import patch
from logging import DEBUG
class TestPrintOwing(TestCase):
@patch.object(Clock, "today", datetime(2001, 3, 1))
def test_printOwing(self):
_invoice = Invoice(customer="a", orders=[Order(amount=10), Order(amount=2)])
with self.assertLogs(level=DEBUG) as cm:
printOwing(_invoice)
def __logger_debug(message):
prefix = f"{cm.records[0].levelname}:{cm.records[0].name}:"
return f"{prefix}{message}"
expected = [
"***********************",
"**** Customer Owes ****",
"***********************",
"name: a",
"amount: 12",
"due: 2001-03-31",
]
self.assertEqual(cm.output, [__logger_debug(e) for e in expected])
ここをこうこうこう
from dataclasses import dataclass
from dataclasses import field
from datetime import date
from datetime import datetime
from datetime import timedelta
from logging import getLogger
logger = getLogger(__name__)
def printOwing(invoice):
outstanding = 0
logger.debug("***********************")
logger.debug("**** Customer Owes ****")
logger.debug("***********************")
# calculate outstanding
for o in invoice.orders:
outstanding += o.amount
# record due date
today: datetime = Clock.today
invoice.dueDate = date(today.year, today.month, today.day) + timedelta(days=30)
# print details
logger.debug(f"name: {invoice.customer}")
logger.debug(f"amount: {outstanding}")
logger.debug(f"due: {invoice.dueDate}")
def printBanner(): # add
logger.debug("***********************") # add
logger.debug("**** Customer Owes ****") # add
logger.debug("***********************") # add
@dataclass
class Clock:
today: datetime = datetime.now()
@dataclass
class Order:
amount: int = 0
@dataclass
class Invoice:
customer: str = ""
orders: list[Order] = field(default_factory=list)
dueDate: datetime = Clock()
from dataclasses import dataclass
from dataclasses import field
from datetime import date
from datetime import datetime
from datetime import timedelta
from logging import getLogger
logger = getLogger(__name__)
def printOwing(invoice):
outstanding = 0
# logger.debug("***********************") # del
# logger.debug("**** Customer Owes ****") # del
# logger.debug("***********************") # del
printBanner() # add
# calculate outstanding
for o in invoice.orders:
outstanding += o.amount
# record due date
today: datetime = Clock.today
invoice.dueDate = date(today.year, today.month, today.day) + timedelta(days=30)
# print details
logger.debug(f"name: {invoice.customer}")
logger.debug(f"amount: {outstanding}")
logger.debug(f"due: {invoice.dueDate}")
def printBanner():
logger.debug("***********************")
logger.debug("**** Customer Owes ****")
logger.debug("***********************")
@dataclass
class Clock:
today: datetime = datetime.now()
@dataclass
class Order:
amount: int = 0
@dataclass
class Invoice:
customer: str = ""
orders: list[Order] = field(default_factory=list)
dueDate: datetime = Clock()
”関数の抽出”できあがり
from dataclasses import dataclass
from dataclasses import field
from datetime import date
from datetime import datetime
from datetime import timedelta
from logging import getLogger
logger = getLogger(__name__)
def printOwing(invoice):
outstanding = 0
printBanner()
# calculate outstanding
for o in invoice.orders:
outstanding += o.amount
# record due date
today: datetime = Clock.today
invoice.dueDate = date(today.year, today.month, today.day) + timedelta(days=30)
# print details
# logger.debug(f"name: {invoice.customer}") # del
# logger.debug(f"amount: {outstanding}") # del
# logger.debug(f"due: {invoice.dueDate}") # del
printDetails(invoice, outstanding) # add
def printBanner():
logger.debug("***********************")
logger.debug("**** Customer Owes ****")
logger.debug("***********************")
def printDetails(invoice, outstanding): # add
logger.debug(f"name: {invoice.customer}") # add
logger.debug(f"amount: {outstanding}") # add
logger.debug(f"due: {invoice.dueDate}") # add
@dataclass
class Clock:
today: datetime = datetime.now()
@dataclass
class Order:
amount: int = 0
@dataclass
class Invoice:
customer: str = ""
orders: list[Order] = field(default_factory=list)
dueDate: datetime = Clock()
”関数の抽出”の引数がある版もできあがり
from dataclasses import dataclass
from dataclasses import field
from datetime import date
from datetime import datetime
from datetime import timedelta
from logging import getLogger
logger = getLogger(__name__)
def printOwing(invoice):
printBanner()
# calculate outstanding
outstanding = 0 # edit
for o in invoice.orders:
outstanding += o.amount
# record due date
today: datetime = Clock.today
invoice.dueDate = date(today.year, today.month, today.day) + timedelta(days=30)
# print details
printDetails(invoice, outstanding)
def printBanner():
logger.debug("***********************")
logger.debug("**** Customer Owes ****")
logger.debug("***********************")
def printDetails(invoice, outstanding):
logger.debug(f"name: {invoice.customer}")
logger.debug(f"amount: {outstanding}")
logger.debug(f"due: {invoice.dueDate}")
@dataclass
class Clock:
today: datetime = datetime.now()
@dataclass
class Order:
amount: int = 0
@dataclass
class Invoice:
customer: str = ""
orders: list[Order] = field(default_factory=list)
dueDate: datetime = Clock()
from dataclasses import dataclass
from dataclasses import field
from datetime import date
from datetime import datetime
from datetime import timedelta
from logging import getLogger
logger = getLogger(__name__)
def printOwing(invoice):
printBanner()
# calculate outstanding
outstanding = 0
for o in invoice.orders:
outstanding += o.amount
# record due date
today: datetime = Clock.today
invoice.dueDate = date(today.year, today.month, today.day) + timedelta(days=30)
# print details
printDetails(invoice, outstanding)
def printBanner():
logger.debug("***********************")
logger.debug("**** Customer Owes ****")
logger.debug("***********************")
def printDetails(invoice, outstanding):
logger.debug(f"name: {invoice.customer}")
logger.debug(f"amount: {outstanding}")
logger.debug(f"due: {invoice.dueDate}")
def calculateOutstanding(invoice): # add
outstanding = 0 # add
for o in invoice.orders: # add
outstanding += o.amount # add
return outstanding # add
@dataclass
class Clock:
today: datetime = datetime.now()
@dataclass
class Order:
amount: int = 0
@dataclass
class Invoice:
customer: str = ""
orders: list[Order] = field(default_factory=list)
dueDate: datetime = Clock()
from dataclasses import dataclass
from dataclasses import field
from datetime import date
from datetime import datetime
from datetime import timedelta
from logging import getLogger
logger = getLogger(__name__)
def printOwing(invoice):
printBanner()
# calculate outstanding
# outstanding = 0 # del
# for o in invoice.orders: # del
# outstanding += o.amount # del
outstanding = calculateOutstanding(invoice) # add
# record due date
today: datetime = Clock.today
invoice.dueDate = date(today.year, today.month, today.day) + timedelta(days=30)
# print details
printDetails(invoice, outstanding)
def printBanner():
logger.debug("***********************")
logger.debug("**** Customer Owes ****")
logger.debug("***********************")
def printDetails(invoice, outstanding):
logger.debug(f"name: {invoice.customer}")
logger.debug(f"amount: {outstanding}")
logger.debug(f"due: {invoice.dueDate}")
def calculateOutstanding(invoice):
outstanding = 0
for o in invoice.orders:
outstanding += o.amount
return outstanding
@dataclass
class Clock:
today: datetime = datetime.now()
@dataclass
class Order:
amount: int = 0
@dataclass
class Invoice:
customer: str = ""
orders: list[Order] = field(default_factory=list)
dueDate: datetime = Clock()
”関数の抽出”の戻り値がある版もできあがり
from dataclasses import dataclass
from dataclasses import field
from datetime import date
from datetime import datetime
from datetime import timedelta
from logging import getLogger
logger = getLogger(__name__)
def printOwing(invoice):
printBanner()
# calculate outstanding
outstanding = calculateOutstanding(invoice)
# record due date
today: datetime = Clock.today
invoice.dueDate = date(today.year, today.month, today.day) + timedelta(days=30)
# print details
printDetails(invoice, outstanding)
def printBanner():
logger.debug("***********************")
logger.debug("**** Customer Owes ****")
logger.debug("***********************")
def printDetails(invoice, outstanding):
logger.debug(f"name: {invoice.customer}")
logger.debug(f"amount: {outstanding}")
logger.debug(f"due: {invoice.dueDate}")
def calculateOutstanding(invoice):
outstanding = 0
for o in invoice.orders:
outstanding += o.amount
return outstanding
def recordDueDate(invoice): # add
today: datetime = Clock.today # add
invoice.dueDate = date(today.year, today.month, today.day) + timedelta(
days=30
) # add
@dataclass
class Clock:
today: datetime = datetime.now()
@dataclass
class Order:
amount: int = 0
@dataclass
class Invoice:
customer: str = ""
orders: list[Order] = field(default_factory=list)
dueDate: datetime = Clock()
from dataclasses import dataclass
from dataclasses import field
from datetime import date
from datetime import datetime
from datetime import timedelta
from logging import getLogger
logger = getLogger(__name__)
def printOwing(invoice):
printBanner()
# calculate outstanding
outstanding = calculateOutstanding(invoice)
# record due date
# today: datetime = Clock.today # del
# invoice.dueDate = date(today.year, today.month, today.day) + timedelta(days=30) # del
recordDueDate(invoice) # add
# print details
printDetails(invoice, outstanding)
def printBanner():
logger.debug("***********************")
logger.debug("**** Customer Owes ****")
logger.debug("***********************")
def printDetails(invoice, outstanding):
logger.debug(f"name: {invoice.customer}")
logger.debug(f"amount: {outstanding}")
logger.debug(f"due: {invoice.dueDate}")
def calculateOutstanding(invoice):
outstanding = 0
for o in invoice.orders:
outstanding += o.amount
return outstanding
def recordDueDate(invoice):
today: datetime = Clock.today
invoice.dueDate = date(today.year, today.month, today.day) + timedelta(days=30)
@dataclass
class Clock:
today: datetime = datetime.now()
@dataclass
class Order:
amount: int = 0
@dataclass
class Invoice:
customer: str = ""
orders: list[Order] = field(default_factory=list)
dueDate: datetime = Clock()
from dataclasses import dataclass
from dataclasses import field
from datetime import date
from datetime import datetime
from datetime import timedelta
from logging import getLogger
logger = getLogger(__name__)
def printOwing(invoice):
printBanner()
outstanding = calculateOutstanding(invoice)
recordDueDate(invoice)
printDetails(invoice, outstanding)
def printBanner():
logger.debug("***********************")
logger.debug("**** Customer Owes ****")
logger.debug("***********************")
def calculateOutstanding(invoice):
outstanding = 0
for o in invoice.orders:
outstanding += o.amount
return outstanding
def recordDueDate(invoice):
today: datetime = Clock.today
invoice.dueDate = date(today.year, today.month, today.day) + timedelta(days=30)
def printDetails(invoice, outstanding):
logger.debug(f"name: {invoice.customer}")
logger.debug(f"amount: {outstanding}")
logger.debug(f"due: {invoice.dueDate}")
@dataclass
class Clock:
today: datetime = datetime.now()
@dataclass
class Order:
amount: int = 0
@dataclass
class Invoice:
customer: str = ""
orders: list[Order] = field(default_factory=list)
dueDate: datetime = Clock()
from dataclasses import dataclass
from dataclasses import field
from datetime import date
from datetime import datetime
from datetime import timedelta
from logging import getLogger
logger = getLogger(__name__)
def printOwing(invoice):
printBanner()
outstanding = calculateOutstanding(invoice)
recordDueDate(invoice)
printDetails(invoice, outstanding)
def printBanner():
logger.debug("***********************")
logger.debug("**** Customer Owes ****")
logger.debug("***********************")
def calculateOutstanding(invoice):
return sum(o.amount for o in invoice.orders) # add
# outstanding = 0 # del
# for o in invoice.orders: # del
# outstanding += o.amount # del
# return outstanding # del
def recordDueDate(invoice):
today: datetime = Clock.today
invoice.dueDate = date(today.year, today.month, today.day) + timedelta(days=30)
def printDetails(invoice, outstanding):
logger.debug(f"name: {invoice.customer}")
logger.debug(f"amount: {outstanding}")
logger.debug(f"due: {invoice.dueDate}")
@dataclass
class Clock:
today: datetime = datetime.now()
@dataclass
class Order:
amount: int = 0
@dataclass
class Invoice:
customer: str = ""
orders: list[Order] = field(default_factory=list)
dueDate: datetime = Clock()
from dataclasses import dataclass
from dataclasses import field
from datetime import date
from datetime import datetime
from datetime import timedelta
from logging import getLogger
logger = getLogger(__name__)
def printOwing(invoice):
printBanner()
# calculate outstanding
outstanding = sum(o.amount for o in invoice.orders)
recordDueDate(invoice)
printDetails(invoice, outstanding)
def printBanner():
logger.debug("***********************")
logger.debug("**** Customer Owes ****")
logger.debug("***********************")
def recordDueDate(invoice):
today: datetime = Clock.today
invoice.dueDate = date(today.year, today.month, today.day) + timedelta(days=30)
def printDetails(invoice, outstanding):
logger.debug(f"name: {invoice.customer}")
logger.debug(f"amount: {outstanding}")
logger.debug(f"due: {invoice.dueDate}")
@dataclass
class Clock:
today: datetime = datetime.now()
@dataclass
class Order:
amount: int = 0
@dataclass
class Invoice:
customer: str = ""
orders: list[Order] = field(default_factory=list)
dueDate: datetime = Clock()
出来上がり
この例のような変更はエディタのリファクタリング機能が助けてくれることもあると思います
以上
参考
(Youtube)マーチンファウラーによろしく - リファクタリングカタログ - 関数の抽出 @ Tommy109
Author And Source
この問題について(【リファクタリングカタログ】関数の抽出), 我々は、より多くの情報をここで見つけました https://qiita.com/kfjt/items/f5afee3dbd02804a4937著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .