ためすう
問い合わせと更新の分離 (リファクタリング-p279)
2019-03-02目的
「リファクタリング」を理解するためにサンプルコードを PHP で書き換えてみました。
今回は「問い合わせと更新の分離」について書きます。
「問い合わせと更新の分離」 について
値を返す関数は観測可能な副作用を持っていなければ、非常に価値があります。
ここで従うべき良いルールは、値を返すメソッドはすべて、観測可能な副作用を持たないと決めてしまうことです。
例
変更前
<?php
class Sample
{
public function foundMiscreant($people)
{
for ($i = 0; $i < count($people); $i++) {
if ($people[$i] === 'Don') {
$this->sendAlert();
return 'Don';
}
if ($people[$i] === 'John') {
$this->sendAlert();
return 'John';
}
}
return '';
}
public function checkSecurity($people)
{
$found = $this->foundMiscreant($people);
$this->someLaterCode($found);
}
private function sendAlert()
{
echo 'sendAlert' . "\n";
}
private function someLaterCode($found)
{
echo 'found: ' . $found . "\n";
}
}
$people = [
'BBB' , 'John', 'CCC',
];
$s = new Sample();
$s->checkSecurity($people);
$people = [
'BBB' , 'CCC',
];
$s->checkSecurity($people);
変更後
<?php
class Sample2
{
public function foundPerson($people)
{
for ($i = 0; $i < count($people); $i++) {
if ($people[$i] === 'Don') {
return 'Don';
}
if ($people[$i] === 'John') {
return 'John';
}
}
return '';
}
public function sendAlertTarget($people)
{
if ($this->foundPerson($people) !== '') {
$this->sendAlert();
}
}
public function checkSecurity($people)
{
$this->sendAlertTarget($people);
$found = $this->foundPerson($people);
$this->someLaterCode($found);
}
private function sendAlert()
{
echo 'sendAlert' . "\n";
}
private function someLaterCode($found)
{
echo 'found: ' . $found . "\n";
}
}
$people = [
'BBB' , 'John', 'CCC',
];
$s = new Sample2();
$s->checkSecurity($people);
$people = [
'BBB' , 'CCC',
];
$s->checkSecurity($people);
表明の導入 (リファクタリング-p267)
2019-03-01目的
「リファクタリング」を理解するためにサンプルコードを PHP で書き換えてみました。
今回は「表明の導入」について書きます。
「表明の導入」 について
コードのある部分が、そのプログラムの状態について何らかの仮定を持っている。
実際、表明は本番コードにおいては取り除かれるのが普通です。
例
変更前
<?php
class Project
{
public function getMemberExpenseLimit()
{
return 9999;
}
}
class Employee
{
const NULL_EXPENSE = -1.0;
private $_expenseLimit = self::NULL_EXPENSE;
private $_primaryProject;
public function __construct()
{
$this->_primaryProject = new Project();
}
public function getExpenseLimit()
{
return ($this->_expenseLimit !== self::NULL_EXPENSE) ?
$this->_expenseLimit : $this->_primaryProject->getMemberExpenseLimit();
}
public function getWithinLimit($expenseAmount)
{
return $expenseAmount <= $this->getExpenseLimit();
}
}
$e = new Employee();
echo $e->getExpenseLimit() . "\n";
変更後
<?php
assert_options(ASSERT_CALLBACK, 'my_assert');
// 本番コード
assert_options(ASSERT_ACTIVE, false);
// 開発コード
// assert_options(ASSERT_ACTIVE, true);
class Project2
{
public function getMemberExpenseLimit()
{
return 9999;
}
}
class Employee2
{
const NULL_EXPENSE = -1.0;
private $_expenseLimit = self::NULL_EXPENSE;
private $_primaryProject;
public function __construct()
{
$this->_primaryProject = new Project2();
}
public function getExpenseLimit()
{
assert($this->_expenseLimit !== self::NULL_EXPENSE ||
!is_null($this->_primaryProject));
return ($this->_expenseLimit !== self::NULL_EXPENSE) ?
$this->_expenseLimit : $this->_primaryProject->getMemberExpenseLimit();
}
public function getWithinLimit($expenseAmount)
{
return $expenseAmount <= $this->getExpenseLimit();
}
}
function my_assert($file, $line, $code)
{
echo 'file: ' . $file . "\n";
echo 'line: ' . $line . "\n";
echo 'code: ' . $code . "\n";
throw new Exception();
};
$e2 = new Employee2();
echo $e2->getExpenseLimit() . "\n";
ヌルオブジェクトの導入 (リファクタリング-p260)
2019-02-28目的
「リファクタリング」を理解するためにサンプルコードを PHP で書き換えてみました。
今回は「ヌルオブジェクトの導入」について書きます。
「ヌルオブジェクトの導入」 について
null値のチェックが繰り返し現れる。
そのnull値をヌルオブジェクトで置き換える。
ポリモーフィズムの真髄は、オブジェクトのタイプを尋ねてその答えに基づいて振る舞いを呼び出すというものではなく、タイプを尋ねずにその振る舞いをただ呼ぶだけですませようというものです。
こうした振る舞いの移動は、ほとんどのクライアントが同じ応答を要求しているときにのみ意味があるということを忘れないでください。
例
変更前
<?php
class Site
{
/* @var Customer */
private $_customer;
public function getCustomer()
{
return $this->_customer;
}
}
class Customer
{
public function getName()
{
// 空実装
}
public function getPlan()
{
// 空実装
}
public function getHistory()
{
// 空実装
}
}
class PaymentHistory
{
public function getWeeksDelingquentInLastYear()
{
return 7000;
}
}
class BillingPlan
{
private $_amount = 1000;
private function __construct($amount)
{
$this->_amount = $amount;
}
public static function basic()
{
return new self(1000);
}
}
$site = new Site();
$customer = $site->getCustomer();
if (is_null($customer)) {
$plan = BillingPlan::basic();
} else {
$plan = $customer->getPlan();
}
if (is_null($customer)) {
$customerName = 'occupant';
} else {
$customerName = $customer->getName();
}
if (is_null($customer)) {
$weekDelinquent = 0;
} else {
$weekDelinquent = $customer->getHistory()->getWeeksDelingquentInLastYear();
}
echo 'customerName: ' . $customerName . "\n";
echo 'weekDelinquent: ' . $weekDelinquent . "\n";
変更後
<?php
class Site2
{
/* @var Customer */
private $_customer;
public function getCustomer()
{
return is_null($this->_customer) ?
Customer2::newNull() :
$this->_customer;
}
}
class Customer2
{
protected function __construct()
{
}
public function getName()
{
// 空実装
}
public function getPlan()
{
// 空実装
}
public function getHistory()
{
// 空実装
}
public function newNull()
{
return new NullCustomer2();
}
}
class NullCustomer2 extends Customer2
{
public function getName()
{
return 'occupant';
}
public function getPlan()
{
return BillingPlan2::basic();
}
public function getHistory()
{
return PaymentHistory2::newNull();
}
}
class PaymentHistory2
{
public function getWeeksDelingquentInLastYear()
{
return 7000;
}
public static function newNull()
{
return new NullPaymentHistory2();
}
}
class NullPaymentHistory2 extends PaymentHistory2
{
public function getWeeksDelingquentInLastYear()
{
return 0;
}
}
class BillingPlan2
{
private $_amount = 1000;
private function __construct($amount)
{
$this->_amount = $amount;
}
public static function basic()
{
return new self(1000);
}
}
$site = new Site2();
$customer = $site->getCustomer();
$plan = $customer->getPlan();
$customerName = $customer->getName();
$weekDelinquent = $customer->getHistory()->getWeeksDelingquentInLastYear();
echo 'customerName: ' . $customerName . "\n";
echo 'weekDelinquent: ' . $weekDelinquent . "\n";
ポリモーフィズムによる条件記述の置き換え (リファクタリング-p255)
2019-02-16目的
「リファクタリング」を理解するためにサンプルコードを PHP で書き換えてみました。
今回は「ポリモーフィズムによる条件記述の置き換え」について書きます。
「ポリモーフィズムによる条件記述の置き換え」 について
オブジェクトのタイプによって異なる振る舞いを選択する条件記述がある。
条件記述の各アクション部をサブクラスのオーバーライドメソッドに移動する。
元のメソッドはabstractにする
ポリモーフィズムの真髄は、オブジェクトの振る舞いがその型によって変わるとき、 明示的な条件記述を書かなくてもいいようにすることです。
例
変更前
<?php
abstract class EmployeeType
{
const ENGINEER = 0;
const SALESMAN = 1;
const MANAGER = 2;
abstract function getTypeCode();
public static function newType($code)
{
switch ($code) {
case self::ENGINEER:
return new Engineer();
case self::SALESMAN:
return new Salesman();
case self::MANAGER:
return new Manager();
default:
throw new Exception('不正な従業員コード');
}
}
}
class Engineer extends EmployeeType
{
public function getTypeCode()
{
return self::ENGINEER;
}
}
class Salesman extends EmployeeType
{
public function getTypeCode()
{
return self::SALESMAN;
}
}
class Manager extends EmployeeType
{
public function getTypeCode()
{
return self::MANAGER;
}
}
class Employee
{
private $_type;
private $_monthlySalary;
private $_commission;
private $_bonus;
public function __construct($type)
{
$this->setType($type);
}
public function getType()
{
return $this->_type->getTypeCode();
}
public function setType($type)
{
$this->_type = EmployeeType::newType($type);
}
public function payAmount()
{
$this->_monthlySalary = 2000;
$this->_commision = 1000;
$this->_bonus = 3000;
switch ($this->getType()) {
case EmployeeType::ENGINEER:
return $this->_monthlySalary;
case EmployeeType::SALESMAN:
return $this->_monthlySalary + $this->_commission;
case EmployeeType::MANAGER:
return $this->_monthlySalary + $this->_bonus;
default:
throw new Exception('不正な従業員');
}
}
}
$e = new Employee(2);
echo $e->payAmount() . "\n";
変更後
<?php
abstract class EmployeeType2
{
const ENGINEER = 0;
const SALESMAN = 1;
const MANAGER = 2;
abstract function getTypeCode();
public static function newType($code)
{
switch ($code) {
case self::ENGINEER:
return new Engineer2();
case self::SALESMAN:
return new Salesman2();
case self::MANAGER:
return new Manager2();
default:
throw new Exception('不正な従業員コード');
}
}
abstract public function payAmount(Employee2 $emp);
}
class Engineer2 extends EmployeeType2
{
public function getTypeCode()
{
return self::ENGINEER;
}
public function payAmount(Employee2 $emp)
{
return $emp->getMonthlySalary();
}
}
class Salesman2 extends EmployeeType2
{
public function getTypeCode()
{
return self::SALESMAN;
}
public function payAmount(Employee2 $emp)
{
return $emp->getMonthlySalary() + $emp->getCommission();
}
}
class Manager2 extends EmployeeType2
{
public function getTypeCode()
{
return self::MANAGER;
}
public function payAmount(Employee2 $emp)
{
return $emp->getMonthlySalary() + $emp->getBonus();
}
}
class Employee2
{
private $_type;
private $_monthlySalary;
private $_commission;
private $_bonus;
public function __construct($type)
{
$this->setType($type);
// 動作確認用にセット
$this->_monthlySalary = 2000;
$this->_commision = 1000;
$this->_bonus = 3000;
}
public function getType()
{
return $this->_type->getTypeCode();
}
public function setType($type)
{
$this->_type = EmployeeType2::newType($type);
}
public function payAmount()
{
return $this->_type->payAmount($this);
}
public function getMonthlySalary()
{
return $this->_monthlySalary;
}
public function getCommission()
{
return $this->_commision;
}
public function getBonus()
{
return $this->_bonus;
}
}
$e2 = new Employee2(2);
echo $e2->payAmount() . "\n";
ガード節による入れ子条件記述の置き換え (リファクタリング-p250)
2019-02-14目的
「リファクタリング」を理解するためにサンプルコードを PHP で書き換えてみました。
今回は「ガード節による入れ子条件記述の置き換え」について書きます。
「ガード節による入れ子条件記述の置き換え」 について
メソッドに正常ルールが不明確な条件つき振る舞いがある。
逆にガード節は「めったに起きないが、起きたときには、何もしないで出て行く」ことを伝えます。
例
変更前
<?php
class Sample
{
private $_isDead;
private $_isSeparated;
private $_isRetired;
public function __construct($isDead, $isSeparated, $isRetired)
{
$this->_isDead = $isDead;
$this->_isSeparated = $isSeparated;
$this->_isRetired = $isRetired;
}
public function getPayAmount()
{
$result = 0;
if ($this->_isDead) {
$result = $this->deadAmount();
} else {
if ($this->_isSeparated) {
$result = $this->separatedAmount();
} else {
if ($this->_isRetired) {
$result = $this->retiredAmount();
} else {
$result = $this->normalPayAmount();
}
}
}
return $result;
}
private function deadAmount()
{
return 9000;
}
private function separatedAmount()
{
return 8000;
}
private function retiredAmount()
{
return 7000;
}
private function normalPayAmount()
{
return 6000;
}
}
$s = new Sample(false, false, false);
echo $s->getPayAmount() . "\n";
変更後
<?php
class Sample2
{
private $_isDead;
private $_isSeparated;
private $_isRetired;
public function __construct($isDead, $isSeparated, $isRetired)
{
$this->_isDead = $isDead;
$this->_isSeparated = $isSeparated;
$this->_isRetired = $isRetired;
}
public function getPayAmount()
{
if ($this->_isDead) {
return $this->deadAmount();
}
if ($this->_isSeparated) {
return $this->separatedAmount();
}
if ($this->_isRetired) {
return $this->retiredAmount();
}
return $this->normalPayAmount();
}
private function deadAmount()
{
return 9000;
}
private function separatedAmount()
{
return 8000;
}
private function retiredAmount()
{
return 7000;
}
private function normalPayAmount()
{
return 6000;
}
}
$s2 = new Sample2(false, false, false);
echo $s2->getPayAmount() . "\n";
制御フラグの削除 (リファクタリング-p245)
2019-02-13目的
「リファクタリング」を理解するためにサンプルコードを PHP で書き換えてみました。
今回は「制御フラグの削除」について書きます。
「制御フラグの削除」 について
一連の論理型の式に対して制御フラグとして機能する1つの変数がある。
代わりにbreakかreturnを使う。
例
変更前
<?php
function sendAlert()
{
echo 'sendAlert' . "\n";
}
function checkSecurity($people)
{
$found = false;
for ($i = 0; $i < count($people); $i++) {
if (!$found) {
if ($people[$i] === 'Don') {
sendAlert();
$found = true;
}
if ($people[$i] === 'John') {
sendAlert();
$found = true;
}
}
}
}
$people = [
'BBB' , 'John', 'CCC', 'Don',
];
checkSecurity($people);
$people = [
'BBB' , 'CCC',
];
checkSecurity($people);
変更後 (breakによる簡単な制御フラグの置き換え)
<?php
function checkSecurity2($people)
{
for ($i = 0; $i < count($people); $i++) {
if ($people[$i] === 'Don') {
sendAlert();
break;
}
if ($people[$i] === 'John') {
sendAlert();
break;
}
}
}
$people = [
'BBB' , 'John', 'CCC', 'Don',
];
checkSecurity2($people);
$people = [
'BBB' , 'CCC',
];
checkSecurity2($people);
変更後 (制御フラグの結果を伴うreturnの使用)
<?php
function checkSecurity3($people)
{
$found = foundMiscreant3($people);
// someLaterCode($found);
}
function foundMiscreant3($people)
{
for ($i = 0; $i < count($people); $i++) {
if ($people[$i] === 'Don') {
sendAlert();
return 'Don';
}
if ($people[$i] === 'John') {
sendAlert();
return 'John';
}
}
return '';
}
$people = [
'BBB' , 'John', 'CCC', 'Don',
];
checkSecurity3($people);
$people = [
'BBB' , 'CCC',
];
checkSecurity3($people);
重複した条件記述の断片の統合 (リファクタリング-p243)
2019-02-12目的
「リファクタリング」を理解するためにサンプルコードを PHP で書き換えてみました。
今回は「重複した条件記述の断片の統合」について書きます。
「重複した条件記述の断片の統合」 について
条件式のすべての分岐に同じコードの断片がある。
上記の場合に適用します。
例
変更前
<?php
function send()
{
echo "send\n";
}
function isSpecialDeal()
{
return true;
}
function main($price)
{
if (isSpecialDeal()) {
$total = $price * 0.95;
send();
} else {
$total = $price * 0.98;
send();
}
echo $total . "\n";
}
main(1000);
変更後
<?php
function send2()
{
echo "send2\n";
}
function isSpecialDeal2()
{
return true;
}
function main2($price)
{
if (isSpecialDeal2()) {
$total = $price * 0.95;
} else {
$total = $price * 0.98;
}
send2();
echo $total . "\n";
}
main2(1000);
条件記述の統合 (リファクタリング-p240)
2019-02-11目的
「リファクタリング」を理解するためにサンプルコードを PHP で書き換えてみました。
今回は「条件記述の統合」について書きます。
「条件記述の統合」 について
条件記述のコードを統合することが重要である理由は2つあります。
1つは、他の条件判定とorで繋げることで実際は単一の条件判定を行うことを示して、 その条件判定を明確にするためです。
もう1つの理由は、このリファクタリングはしばしば「メソッドの抽出」の下準備としての役割を持つためです。
例
変更前
<?php
class Dummy
{
private $_seniority;
private $_monthsDisabled;
private $_isPartTime;
public function __construct($seniority, $monthsDisabled, $isPartTime)
{
$this->_seniority = $seniority;
$this->_monthsDisabled = $monthsDisabled;
$this->_isPartTime = $isPartTime;
}
public function disabilityAmount()
{
if ($this->_seniority < 2) return 0;
if ($this->_monthsDisabled > 12) return 0;
if ($this->_isPartTime) return 0;
// 後続の処理
return 1;
}
}
$d1 = new Dummy(2, 11, 0);
echo (int)$d1->disabilityAmount() . "\n";
変更後
<?php
class Dummy2
{
private $_seniority;
private $_monthsDisabled;
private $_isPartTime;
public function __construct($seniority, $monthsDisabled, $isPartTime)
{
$this->_seniority = $seniority;
$this->_monthsDisabled = $monthsDisabled;
$this->_isPartTime = $isPartTime;
}
public function disabilityAmount()
{
if ($this->isNotEligibleForDisability()) {
return 0;
}
// 後続の処理
return 1;
}
private function isNotEligibleForDisability()
{
return (($this->_seniority < 2) ||
($this->_monthsDisabled > 12) ||
($this->_isPartTime));
}
}
$d2 = new Dummy2(2, 11, 0);
echo (int)$d2->disabilityAmount() . "\n";
JavaScript の正規表現
2019-02-11目的
JavaScript の正規表現を使い、ユーザーエージェントから iPad を判別します
やってみる
iPadのユーザーエージェント を抽出する方法です。
var ipad_log = "Mozilla/5.0 (iPad; CPU OS 8_0_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12A405 Safari/600.1.4";
var a = ipad_log.match(/ipad/i);
console.log(a);
// 実行結果
["iPad", index: 13, input: "Mozilla/5.0 (iPad; CPU OS 8_0_2 like Mac OS X) App…e Gecko) Version/8.0 Mobile/12A405 Safari/600.1.4"]
/ipad/i の i は大文字小文字の区別をなくすオプションです
AWS の ELB について
2019-02-10目的
ロードバランサについて知ることです
ELB(Elastic Load Balanning)とは
複数のAmazon EC2インスタンス間で、アプリケーショントラフィックの負荷を自動的に拡散してくれる、ロードバランサのPaaSです。
ELBの特徴
- スケーラブル
- 高可用性
- トラフィックの料金が低い
Saas、Paas、IaaS とは
- Saas
SaaSとは、「Software as a Service」の頭文字を取った略語で「サース」と読みます。 これまでパッケージ製品として提供されていたソフトウェアを、インターネット経由でサービスとして提供・利用する形態のことを指します。
- Paas
PaaSは「Platform as a Service」の頭文字を取った略語で「パース」と読みます。 アプリケーションソフトが稼動するためのハードウェアやOSなどのプラットフォーム一式を、インターネット上のサービスとして提供する形態のことを指します。
- IaaS
IaaSは「Infrastructure as a Service」の頭文字を取った略語で「イァース」と読みます。 情報システムの稼動に必要な仮想サーバをはじめとした機材やネットワークなどのインフラを、インターネット上のサービスとして提供する形態のことを指します。
参考
- サーバ/インフラエンジニア養成読本
- IaaS PaaS SaaSの違い|クラウドエース(Cloud Ace)