孤独プログラマー譚

孤独死が近い。

PHP 引数の多いメソッド対策

以下のように、同じような引数が羅列されているソースコードをよく見る。

<?php
$this->getMemberAddress('秋元真夏', '乃木坂46', 'ソニーミュージック');
$this->getMemberAddress('白石麻衣', '乃木坂46', 'ソニーミュージック');
$this->getMemberAddress('山下美月', '乃木坂46', 'ソニーミュージック');

乃木坂46ソニーミュージック
の部分が重複しており、大変見苦しい。

そういう時は、カリー化して、引数の数を減らしてやる。

<?php
$curryingFunc = function($group, $company) {
    return function($name) use($group, $company) {
        return $this->getMemberAddress($name, $group, $company);
    };
}

$getMemberAddressByName = $curryingFunc('乃木坂46', 'ソニーミュージック');

echo $getMemberAddressByName('秋元真夏'); // 東京都…
echo $getMemberAddressByName('白石麻衣'); // 東京都…
echo $getMemberAddressByName('山下美月'); // 東京都…

重複部分が無くなった。

以下のように、部分適用としても良い。

<?php
$getMemberAddressByName = function($name) {
    return $this->getMemberAddress($name, '乃木坂46', 'ソニーミュージック');
};
echo $getMemberAddressByName('秋元真夏'); // 東京都…
echo $getMemberAddressByName('白石麻衣'); // 東京都…
echo $getMemberAddressByName('山下美月'); // 東京都…

引数が10個くらいあるメソッドを見てると、気が滅入ってくるよ。

PHP ユーザー定義関数に永続変数を持たせる

やりたいことは、JavaScriptで言うクロージャを作ること。
関数外のスコープにある変数を、関数内で保持していく。

useを使えば出来ると思ったら出来なかった。
useを使えるのは無名関数のみだったのか…。

<?php
(function() {
    $cnt = 1;
    function increment() use(&$cnt) { // syntax error, unexpected 'use'
        echo $cnt;
        $cnt++;
    }
})();


正解は、静的変数を使うこと。

<?php
function increment() {
    static $cnt = 1;
    echo $cnt;
    $cnt++;
}
increment(); // 1
increment(); // 2
increment(); // 3
var_dump($cnt); // null

無名関数 + use(参照渡し)
= 関数定義 + 静的変数
JavaScriptクロージャ

お粗末さまでした。

if文を考える

以下のような if 文をよく見かける。

if has_white_skin && is_good_looking
  p 'まいやん' # 色白で美人なのが、まいやん
elsif has_white_skin && is_cute
  p 'さゆにゃん' # 色白で可愛いのが、さゆにゃん
end

ありがちだが、良くない。以下はもっと良くない。

if has_white_skin
  if is_good_looking
    p 'まいやん' # 色白で美人なのが、まいやん
  elsif is_cute
    p 'さゆにゃん' # 色白で可愛いのが、さゆにゃん
  end
end

今後、スパゲティコードとして成長していくことが目に浮かぶ。


まず大切なのは、この処理には「白石麻衣」の場合と「井上小百合」の場合、その2通りの状態があること。

白石麻衣は「色白で美人」である。だが、どのような条件で「白石麻衣」と判断するか…それはどうでもいい。

大切なのは「白石麻衣」という状態が存在することだ。

状態を判断:色白で美人(どうでもいい)
↓
状態:白石麻衣(大切)
↓
処理:まいやん(ニックネーム。どうでもいい)


下の処理を見てみると、状態を判断(どうでもいい)と、処理(どうでもいい)だけしか書かれていない。

if has_white_skin && is_good_looking
  p 'まいやん' # 色白で美人なのが、まいやん

「状態が白石麻衣」であることは、どこにも書かれていない。
これを初めて読んだ人は「は?これ何について書かれているの?」となる。


以下の書き方が正解となる。

if has_white_skin && is_good_looking
  who = '白石麻衣'
elsif has_white_skin && is_cute
  who = '井上小百合'
end

if who == '白石麻衣'
  p 'まいやん'
elsif who == '井上小百合'
  p 'さゆにゃん'
end

「状態の判断」と「処理」が分離された。
状態として、「白石麻衣」と「井上小百合」の2パターンが存在することが見て分かる。

JavaScript バブリング中毒

以下、セレクトボックスが3つ並んだHTML。
全てのセレクトボックスが選択完了した時、何か処理を実行したいとする。

<div id="wrapper">
  <select id="select1">
    <option value="">---</option>
    <option value="1">aaa</option>
    <option value="2">bbb</option>
  </select>
  <select id="select2">
    <option value="">---</option>
    <option value="1">aaa</option>
    <option value="2">bbb</option>
  </select>
  <select id="select3">
    <option value="">---</option>
    <option value="1">aaa</option>
    <option value="2">bbb</option>
  </select>
</div>


昔の自分なら、こう書き始めていたと思う。

$('#select1').on('change', function() {
})
$('#select2').on('change', function() {
})
$('#select3').on('change', function() {
})


だが、今日知ってしまった。
changeイベントだって、上位のDOMにバブリングすることを…。

$('#wrapper').on('change', function(e) {
  // 全て選択されたら、CSSを変更
  if ($('#select1').val()
  && $('#select2').val()
  && $('#select3').val()) {
    $('#wrapper').css('background-color', '#0FF')
  }
})


もう全部バブリングでええんちゃう…?

Ruby 元のクラスを触らずに機能を拡張する

機能を追加することになった。
だが、元のクラスは触りたくない。
だってバグりそうだから。前のテストのやり直しをさせらせるかもしれない…。

自分の身を守るためにも、安全に機能を拡張する方法をまとめる。


以下クラスを拡張する。
フルネーム「白石麻衣」と表示出来れば、OK。

class Family
  def name
    '白石'
  end
end

1.継承する

定番。ぱっと見、分かりやすい。
インスタンス変数に依存した実装になりやすい。副作用大。

class Full < Family
  def name
    super + '麻衣'
  end
end

full = Full.new
p full.name # 白石麻衣

2.委譲する

委譲先から委譲元のインスタンス変数を触れないので、疎結合。良い。

class Full
  def name
    family = Family.new
    family.name + '麻衣'
  end
end

full = Full.new
p full.name # 白石麻衣

3.特異メソッドを定義

インスタンスにメソッドを定義する。

family = Family.new
def family.full_name
  name + '麻衣'
end
p family.full_name # 白石麻衣

4.モジュールをextend

インスタンスにモジュールをミックスインする。

module Full
  def full_name
    name + '麻衣'
  end
end

family = Family.new
family.extend Full
p family.full_name # 白石麻衣

5.Decoratorパターン

委譲の発展版。
インスタンス変数を内側・外側で、それぞれどう持ち回すかは謎。工夫が必要っぽい。

class Full
  def initialize(family)
    @family = family
  end
  def name
    @family.name + '麻衣'
  end
end

full = Full.new(Family.new)
p full.name # 白石麻衣


うーん、前任者のコードを触りたくない…。

Ruby クロージャを使ってインスタンス変数を減らす

インスタンス変数は悪である。
だって、クラス内のどこからでも、値を改変できるから。


そこで、インスタンス変数を減らす手立を考えてみた。


以下、ゲッターもどき。
構造体を返す。構造体はラムダをgetメンバに持っている。
ラムダはクロージャになる。変数immutable_varは保持される。
変数の中身(yield)は、後ほどブロックで渡す。

def make_getter
  immutable_var = yield
  struct = Struct.new(:get)
  struct.new(
    -> { immutable_var }
  )
end


以下、ゲッター兼セッターもどき。
getメンバ、setメンバを持つ。もちろんクロージャ

def make_accessor
  immutable_var = yield
  struct = Struct.new(:get, :set)
  struct.new(
    -> { immutable_var },
    -> new_var { immutable_var = new_var }
  )
end


以下で変数の中身を定義する。
'白石麻衣'、'平手友梨奈'となっているブロックの中身は、がっつり処理を書いてよい。
それら変数をまとめて、こちらも構造体で返す。

def make_immutables
  struct = Struct.new(:nogi, :keyaki)
  struct.new(
    make_getter { '白石麻衣' },
    make_accessor { '平手友梨奈' },
  )
end


コンストラクタで、上記構造体をインスタンス変数に入れる。インスタンス変数を使ってしまうが、これはしょうがないと思う。

def initialize
  @immutables = make_immutables
end


変数を呼び出す。
呼び出し方が冗長な気もするが、憎きインスタンス変数を減らせたので、良しとする。

def execute
  p @immutables.nogi.get.call # 白石麻衣
  p @immutables.keyaki.get.call # 平手友梨奈
  @immutables.keyaki.set.call('長濱ねる') # 長濱ねるをセット
  p @immutables.keyaki.get.call #長濱ねる
end


うーん、他に良い方法あるのかなぁ…。

Ruby ブロック付きメソッドの活用

普通は、スクリプトを読みながら、どういう順序・条件で処理が進むのかを調べる。

それがつらい。処理の詳細を見ないと、実行順や分岐の条件が分からないのがつらい。

だから、実行順や分岐の条件を、処理の詳細から分離する。

OOPのTemplateパターンやStateパターンを使えば、実現できる。だが、他に良い方法は無いだろうか。

if group == '乃木坂46'
  func1
  func2
  func3
elsif group == '欅坂46'
  func1
  func3
  func4
end

上記のように書けば、実行順と分岐が分離できたことになる。

うーん、でも何と言うか…。メソッド間の結合が弱いというか。

func1 と func2 の順番を逆にすることもできるし、間に処理をスッと挟むことも出来る。簡単に改変できるのが気持ちが悪い。

そこで、以下のような形を考えた。

def f1
  p 1
  yield
end

def f2
  p 2
  yield
end

def f3
  p 3
end

f1 do
  f2 do
    f3
  end
end

# 1
# 2
# 3

ブロック渡しをする。PHPJavaScriptだと、無名関数でネストさせることになる。

副次的なメリットとして、次のメソッドに渡したい引数を、返り値に含める必要がない。

# 返り値経由で渡す
result = func1
func2 result[:arg1]

# 返り値に含める必要がない
def func1
    arg1 = 'foo'
    yield arg1
end

func1 do |arg1|
    func2 arg1
end


うーん、イマイチかなぁ…。