Edited at

英文で考える関数の作り方


この記事について

ふと、自分はどうやって関数名やシグネチャを決めているのか、というのをあまり意識していなかったことに気づいたので、そこら辺の思考回路というか暗黙のルールみたいなのを言語化しておきたいと考えて記事にすることにしました。いつもなんとなくですが、英文で考えるようにはしていて、自分では可読性の高さはどれだけ自然な英語の表現になっているかに依る、という基準があるので、そこら辺にも言及しています。


はじめに

言語は私が慣れ親しんだ PHP で書きます。

関数の構成要素としては、

function 関数名(仮引数): 戻り値型宣言

{
処理
}

のような感じになっています。これがメソッドなら function の前にアクセス指定子やら static やら abstract やらがつきますが、今回は忘れてください。あくまでも関数名と引数の話です。

基本的には英語の文法に沿った形になってるかなぁ、と思います。

S + V + O みたいな構成になっているとき、S はオブジェクトであり、V が関数であり、O が引数である、という感じです。

以下、具体例を書きますが、英語で書くとどうなるか、というのも併せて載せておきます。関数の構成と見比べてみるとよさそうです。


具体例


1. 数値同士を足し合わせる

(This function) adds n to m.

最初は素の関数です。関数なので主語がありません。

function add(int $n, int $m): int

{
return $n + $m;
}

add(1, 2);


2. 計算機が足し算を行う

A calculator adds n (to the value in it).

計算機クラスには現在の値を持たせて、add が呼ばれると即時評価して現在の値を更新します。上の英語を見ると、括弧でくくられた部分が暗黙知となっていて、少し良くない雰囲気を感じます(個人の感想です)。

class Calculator

{
private $value;

public function __construct()
{
$this->value = 0;
}

public function add(int $n): void
{
$this->value += $n;
}
}

$calc = new Calculator();
$calc->add(2);


3. メッセージが自身を送信する

A message sends itself.

Laravel の Log ファサードとか Mail クラスなんかをイメージしてもらうといいかもしれないです。コンテキスト次第ですが、Message というクラスが自分自身をどこか固定された場所に送信する、というユースケースはあり得ると思います。クライアントはどこに送信するかは感知しないので、上の英文も副詞句がなく単純な SVO になっています。

class Message

{
private $body;

public function __construct(string $body)
{
$this->body = $body;
}

public function send(): void
{
echo 'sending message "' . $this->body . '" by self...' . PHP_EOL;
}
}

$message = new Message('Hello, world.');
$message->send();


4. 送信者がメッセージを送信する

A messenger sends a message.

メッセージを送信する主体を別のクラスにしてみると、メッセージは S から O になります。こちらも前の例と同様、具体的にどこに送るのか、というのはクライアントからは見えません。

class Messenger

{
public function send(Message $message): void
{
echo 'sending message "' . $message->body() . '" by Messenger...' . PHP_EOL;
}
}

$messenger = new Messenger();
$messenger->send(new Message('Hello, world'));

ちなみに、コンストラクタも関数の一種であるので、何を引数に取れば、そのクラス(オブジェクト)が十全であるか、というのは意識しています。

あえて完全性を崩すことはありますが、基本は、生成されるオブジェクトが、そのクラスのインスタンスとして成り立っていることがそのシステム内で確かになる、という引数を持たせるように意識しています。たとえば、TODO管理アプリケーションにおいて、ほとんどのケースで new Task() というのは成り立たないと思います(少なくとも title みたいなプロパティがないとどうやってタスクと認識するんでしょう?という意味で)。

閑話休題


5. メッセージが自身を「どこかに」送信する

A message sends itself somewhere.

メッセージクラスが自身を送信するパターンにおいて、送り先をクライアント側から指定できるようにした場合、メソッド名を send から sendTo に変化させます。英語の自然な文法だと、副詞が来た場合前置詞は来ませんが、コード上では具体的な送信先が指定されてくるので to をつけています。

class Message

{
private $body;

public function __construct(string $body)
{
$this->body = $body;
}

public function sendTo(OutputInterface $somewhere): void
{
$somewhere->write('sending message "' . $this->body . '" by self...' . PHP_EOL);
}
}

$message = new Message('Hello, world');
$message->sendTo(new StdOutput());


6. 送信者がメッセージを「どこかに」送信する

A messenger sends a message somewhere.

こちらはメッセージ送信の主体が別のクラスの場合です(それ以外は前の例と同様)。

class Messenger

{
public function sendTo(Message $message, OutputInterface $somewhere): void
{
$somewhere->write('sending message "' . $message->body() . '" by Messenger...' . PHP_EOL);
}
}

$messenger = new Messenger();
$messenger->sendTo(new Message('hello, world'), new StdOutput());


7. 送信者がメッセージを「どこかに」「与えられた設定を用いて」送信する

A messenger sends a message somewhere with options.

引数に送信する際のオプション(ちょっといい例が思い浮かばなかったのでメソッドの中では使っていません)を指定できるようにしたパターンです。

with で連結しています。

class Messenger

{
public function sendTo(Message $message, OutputInterface $output, SendOptions $options = null): void
{
$output->write('sending message "' . $message->body() . '" by Messenger...' . PHP_EOL);
}
}

$messenger = new Messenger();

$messenger->sendTo(new Message('hello, world'), new StdOutput(), new SendOptions['immediate' => false]);


おわりに

他にもバリエーションがありそうな気はしてるんですが、ひとまず思いついたのを列挙しました。こんなパターンもあるんじゃない?というのがありましたら、ぜひコメント欄にて教えてください :bow: