読者です 読者をやめる 読者になる 読者になる

Shin x Blog

PHPをメインにWebシステムを開発してます。Webシステム開発チームの技術サポートも行っています。

openssl_encrypt() による PKCS#7 パディング

PHP の openssl_encrypt() にて、ブロック暗号による暗号化を行うと PKCS#7 パディングが行われます。この動きを確認してみます。

http://php.net/manual/ja/function.openssl-encrypt.php

PKCS#7 パディング

ブロック暗号では、決められたブロック長を単位として暗号化を行います。対象となる平文がブロック長の倍数の長さであれば良いのですが、そうではない場合、不足分を補う必要があります。これがパディングです。*1

PKCS#7 パディングは RFC 5652 で定義されたパディング方式です。補ったバイト数を 1 バイトの値として埋めます。例えば、3 バイトを補うのであれば、0xXXXX030303 のように 3 が 3 つ並びます。PKCS#7 では、1 バイトで不足バイト数を示すので、1 - 255 バイトまでを補うことができます。

01     <--- 1 バイト分
0202   <--- 2 バイト分
030303 <--- 3 バイト分

https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7

これと似た動きをするのが、PKCS#5 パディングで、こちらは 8 バイトを倍数とした場合のパディングを行います。つまり、取り得る値は 1 - 8 となります。

余談ですが、Java の javax.crypto.Cipher にある PKCS5Padding は、名前は PKCS5 ですが、実質は PKCS#7 相当の動きをするようです。

他のパディングには、0 で埋める ゼロパディングなどがあります。

openssl_encrypt() によるパディング

openssl_encrypt() のデフォルトでは、PKCS#7 パディングが行われます。

この動きを見ていくためのサンプルが以下です。このサンプルでは、openssl_encrypt() で暗号化、openssl_decrypt()で復号を行っています。

ここでは、AES(Rijndael)を利用しているのでブロック長は 128bit(16バイト)です。平文は plain の 5 バイトなので、不足分の 11 バイトがパディングで埋められます。

<?php
$plaintext = 'plain';
$key = hash('sha256', 'this is a secret key.');
$method = 'aes-256-cbc';
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($method));

$encrypted = openssl_encrypt($plaintext, $method, $key, 0, $iv);
printf("encrypted: %s\n", $encrypted);

$decrypted = openssl_decrypt($encrypted, $method, $key, 0, $iv);
printf("decrypted: %s\n", $decrypted);

これを実行すると下記のような出力になります。暗号文はデフォルトで base64 エンコードされています。復号した結果を見ると元の平分が出力されています。ここではパディングが見えないですが、これは openssl_decrypt() にて復号時にパディングを除去するためです。

encrypted: vGZiiLXzuiGnOBkJbWAiHw==
decrypted: plain

暗号文にパディングが含まれているかを確認するために復号時に OPENSSL_NO_PADDING を指定して、パディング除去が行われないようにします。

<?php
$plaintext = 'plain';
$key = hash('sha256', 'this is a secret key.');
$method = 'aes-256-cbc';
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($method));

$encrypted = openssl_encrypt($plaintext, $method, $key, 0, $iv);
printf("size: %d bytes\n", strlen(base64_decode($encrypted)));

$decrypted = openssl_decrypt(base64_decode($encrypted), $method, $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv);
printf("decrypted: %s\n", bin2hex($decrypted));
printf("size: %d\n", strlen($decrypted));

これを実行したのが下記です。

パディングが見えるように復号した結果は bin2hex() で出力しています。前半の 706c61696e の部分は平文の plain です。それにつづく 0b が 11 回連続している箇所がパディングです。ブロック長 16 バイトから平文の 5 バイトを引いた 11 バイトがパディングとなるので 0x0b が 11 回連速しています。

復号した結果は 16 バイトとなっており、これもブロック長と一致します。

encrypted: iwBv6P3euwwdct8DHutBNA==
decrypted: 706c61696e0b0b0b0b0b0b0b0b0b0b0b
size: 16

平文サイズがブロック長と一致している場合

では、平文サイズがブロック長と一致している場合はどうなるでしょう。

平文を plainplainplaina の 16 バイトにして実行したのが下記です。

復号結果は、なんと 32 バイトになりました。内容を見ると 10 が 16 回連続しています。これは、ブロック長分のパディングです。つまり、1 ブロック分が追加されているわけです。

平文の後にはパディングが付いていることを前提とするため(そうでないと平文なのかパディングなのか判断できない)にこのような動きになっているのでしょう。

encrypted: PFZ8G+XYhs9x22aP/a7Jy88eQJv6GVaKMXrBfq5/bGU=
decrypted: 706c61696e706c61696e706c61696e6110101010101010101010101010101010
size: 32

さいごに

openssl_encrypt() によるパディングを見てきました。

デフォルトのまま、openssl_encrypt() で暗号化し、openssl_decrypt() で復号するならパディングを意識する必要はあまりありません。

しかし、別システムで暗号化されたものを復号したり、その逆の場合は、どのような形式でパディングを行うのかというのは共有しておく必要があります。

参照

*1:実際には、後述するとおりブロック長倍数であってもパディングが追加されます。

アプリケーションから例外を投げる派、投げない派

例外をどのような状況に投げるかもしくは投げないか、というのはわりと意見が分かれるところです。もちろん、プログラミング言語によっても異なりますが、同じプログラミング言語ユーザ同士でも様々です。

基本の考え方

ベースとしては、Effective Java の項目 39 にある下記の方針が参考になります。

例外的な状況の時にのみ例外を使う。

Effective Java

禅問答のような定義ですが、これには異論は無いでしょう。例外を正常フローで利用したり、制御構造に用いるべきではありません。

人によって異なるのは「例外的な状況」の解釈です。

例外的な状況

この「例外的な状況」の解釈は人によって異なるようで、これまでも議論になっていました。これまで聞いた解釈を乱暴に分けると以下の 2 パターンに分かれます。

1. アプリケーションから独自の例外を投げる派

ランタイムやミドルウェア連携などプラットフォーム起因のエラーだけではなく、 アプリケーションやドメインにおけるエラーを例外としてスローする派です。例外クラスも必要に応じて定義します。

例外をエラー処理に積極的に利用する考え方ともいえ、例えば、入力値におけるバリデーションエラーやドメインロジックのエラーにおいても例外を利用します。

2. プラットフォームやフレームワークが投げる例外以外は使わない派

ランタイムやミドルウェア連携などプラットフォーム起因のエラーなど深刻なエラーでのみ例外を利用し、アプリケーションにおけるエラーにおいては例外を利用しない考え方です。

この考え方の人の中には、例外クラスはアプリケーション独自で定義せず、アプリケーションからは例外をスローしない(ランタイムやフレームワーク、ライブラリからの例外のみ扱う)という意見もありました。

アプリケーションのエラーは、戻り値で通知することになります。(特殊な値(null や false)を使ったり、原因別に戻り値を返すなど)

アプリケーションから独自の例外を投げる派の意見

私は、前者の「例外を積極的に使う派」です。理由としては、下記のようなメリットを感じています。 (なお、ここでは PHP を対象として、検査例外のことは考えていません。)

  • [実装][利用] エラー処理を例外に統一できる。
  • [利用] 呼び出す側は例外だけ対応すれば良い。(catch する / 対応しない(上位にスロー))
  • [利用] どのレイヤでエラー処理するかを呼び出し側が選べる。(上位レイヤに伝播できるので、フレームワークの統一的なエラー処理に任せてしまうなどが簡単)
  • [実装] エラー時は例外を投げれば良いので、ガード節の代わりにもなる。
  • [実装] テストでは、@expectedException でテストを書けば良いので、何のテストか分かりやすい。(正常時は例外飛ばないので)
  • [利用] try / catch を書けば、try の中は正常系、catch の中は異常系と処理が分かれて分かりやすい。
  • [利用] 戻り値のエラー判定が不要。例外が飛ばなければ正常終了と判断できる。
  • [利用] 例外クラスが持つ情報量が多い。(特にスタックトレース)

さいごに

例外については、人それぞれ思いがあるようで、議論になりやすいところです。この機会に色々な人の意見を聞いてみたいですね。

今日開催の関西 PHP 勉強会でも、話しましょう。

https://kphpug.doorkeeper.jp/events/55554

EFFECTIVE JAVA 第2版 (The Java Series)

EFFECTIVE JAVA 第2版 (The Java Series)

追記

Twitter へ頂いたコメントをまとめました。色々な意見がありますね。

togetter.com

はてぶでも多くのコメントがあったので、こちらも追記。

b.hatena.ne.jp

子どもの iPhone SE に行った設定リスト 2016年12月

子ども(13 才以上)用に iPhone を購入したので、セットアップしたメモです。

iPhone

IIJmio を利用するために、Apple Store で SIM フリーの iPhone SE を購入しました。

www.apple.com

SIM

私が、IIJmio を利用していて、何ら不都合が無いので、同じく IIJmio にしました。連絡は、LINE(チャット or 電話)で行うつもりなので、データ通信専用 SIM を申し込みました。

3GB プランで、900円/月です。(後述する i-フィルター for マルチデバイス を申込んだので、+ 360円)

www.iijmio.jp

ペアレンタルコントロール(機能制限)

利用できるアプリやアクセス先を制限できる機能です。必要な箇所を設定しました。

support.apple.com

Apple ID

利用者が、13 才未満なら子ども用の Apple ID が作成できます。

support.apple.com

今回は、13 才を超えているので、Google アカウントを作成し、Gmail のアドレスで、Apple ID を取得することにしました。

インストールするアプリを許可制にする

iCloud のファミリー共有を使えば、子どもが自由にアプリをインストールすることができなくなります。 アプリをインストールすると、親(管理者)へ承認を求めるようになります。承認が要求されると、親の iOS デバイスに通知が来て、ここで許可 or 拒否を指定できます。

www.apple.com

support.apple.com

ファミリー共有すると、家族の端末にインストールしたアプリや現在位置を管理者の端末で確認できます。反対に管理者の情報を家族の端末で見ることもできますが、どの情報を共有するかは ON / OFF できるので、管理者のものは共有しないことも可能です。

support.apple.com

Apple Music

Apple Music を家族で利用できるようにします。すでに個人メンバーシップには登録していたので、これをファミリーメンバーシップに切り替えて、子どもの Apple ID を招待しました。

support.apple.com

support.apple.com

LINE

LINE アカウントを作成するには電話番号か Facebook アカウントが必要になります。今回は、データ通信のみの SIM にしたので、Facebook アカウントを作成しました。

LINE アプリをインストールして、「Facebook アカウントでログイン」を選ぶと、Facebook連携でアカウントで LINE アカウントが作成できます。

official-blog.line.me

あと、意図せず友達申請が来たりするのを防ぐために幾つか設定しておきます。

  • プロフィール - 「IDで友達追加を許可」を off(年齢確認できていないので、off のはず)
  • プライバシー管理 - 「メッセージ受信拒否」を on (友達以外からのメッセージ受信を拒否)
  • 友だち - 「友だち追加」を off (アドレス帳の連絡先を自動で友だちに追加しない)
  • 友だち - 「友だちへの追加を許可」を off (電話番号を保有している LINE ユーザが自動で友だち追加したり、検索できるのを拒否)
  • タイムライン - タイムラインは使わなくて良いけど、もし使うなら「友だちの公開設定」「新しい友だちに自動公開」を確認。

i-フィルター for マルチデバイス

フィルタリングソフトを一応導入しました。まだ、どれほど活用できるかは分からないですが、やってみて、不要なら解約する予定です。

www.iijmio.jp

さいごに

メールアドレスも無い、Apple ID も無い状態から iPhone を設定したのは、はじめてなので思ったより手間取りました。

ある程度慣れている人なら調べながら自分でできますが、詳しく無い人だとほんと大変ですね。

格安 SIM を利用する人が増えていますが、3 キャリアにはこうしたセットアップを店舗でサポートしてくれるサービスがあるので、月々の通信費は割高でも、サポートが必要な人にとってはそちらの方が良いのかもしれません。

はじめに手にした iPhone 。大事に使って、良い思い出を作っていって欲しいものです。

公開 Podcast のような勉強会セッションをやってみる

動機

  • 内容が大事で、それが聞きたいだけなのに、スライド作ってとか表現への準備が大変。
  • 技術系勉強会では、スライドを作ることは本質ではない。(内容が伝われば手段は何でも良い)
  • かといって、登壇する時にスライド無しで一人で話すのも大変。
  • 運営としても、発表者としても前々か解決したいテーマだった。
  • Podcast は、音声だけだが、十二分に伝わる。緩い雰囲気も聞きやすい。
  • あ、これだ!

考えていること

  • 話し手と聞き手がいて、二人が話すのをみんなで見る。
  • 話し手が、公開しているコンテンツ(blog、発表スライド、OSS、tweet 等々)をベースに話していく。
  • 話し手は、過去に公開したものがベースなので、スライド作るより準備が楽。当日も聞き手がいる方が話しやすい。
  • 場合によっては、コード書いて見せたりするのもあり。
  • 話し手は、事前に質問を考えておく必要がある。負担を双方で受け持つ。

期待していること

  • 聞きたいことを聞きたい人に負担を少なめで聞ける。
  • 懇親会で話すような雰囲気でくだけた話をしたい。(「懇親会が本番」を本編で)
  • 参加している人も、二人が対話している方がリラックスして聞きやすいし、入りやすいのでは。
  • 間があってもいいし、二人いるから、どちらかが話せば良い。
  • パネルディスカッションに比べると、各人に話を振っていく必要が無いから楽。

さいごに

こんなセッションを 12/27 開催の関西 PHP 勉強会でやってみます。

どうせなら、録音して Podcast とかで出せるといいかなとかも考えてますが、予定は未定なので、ご都合が付く方は参加お待ちしています!

Amazon Dash Button にみるドメイン特化クラスのヒント

この投稿は、PHP Advent Calendar 2016 - Qiita の 7 日目です。

DDD のようなドメインを意識した開発手法でなくても、ドメインコンテキストで必要な操作のみを実装したクラスを作ってみましょう話です。

Amazon Dash Button

Amazon Dash Button は、ボタンが一つだけあるデバイスです。このボタンを押すと、あらかじめ決められた商品の注文が Amazon に送信され、商品が配送されるというシンプルなものです。

サントリー天然水 Dash Button

このデバイスは、「商品を届けて欲しい」というユースケースに対して、ボタンを押すというシンプルなインターフェイスを実装しています。単にボタンを押すだけなので、その裏側でどのようにして実現されているかを知らずとも、誰もが利用できます。違う言い方をすれば、ボタンを押す(商品を注文する)ことしかできないので、操作方法を覚える必要もなく、想定外の使い方もやりようがありません。*1

このように、ドメインやそのユースケース、関心事に特化したインターフェイスを用意すれば、そのコンテキストの中では迷うことなく、自然に理解でき、扱い方を間違えることもありません。

ドメイン特化クラス

「ユーザに現在の年齢を尋ねる」というユースケースの実装を考えてみます。

User クラスとして実装したのが、下記です。

現在の年齢を算出するには、生年月日が必要となるので、コンストラクタで渡しています。生年月日は、cakephp/chronos パッケージの Date クラスで表現しています。

年齢を尋ねるには、age メソッドを利用します。

<?php
namespace Acme\Generic;

use Cake\Chronos\Date;

class User
{
    /**
     * @var Date
     */
    private $dateOfBirth;

    /**
     * @param Date $dateOfBirth
     */
    public function __construct(Date $dateOfBirth)
    {
        $this->dateOfBirth = $dateOfBirth;
    }

    /**
     * @return int
     */
    public function age(): int
    {
        return $this->dateOfBirth->age;
    }
}

このコードを実行するのが、下記です。生年月日をコンストラクタを渡して、age メソッドを呼ぶだけなのでシンプルです。

<?php
// 現在日を設定
// Chronos::setTestNow(Chronos::create(2016, 12, 8, 12, 34, 56));

$user = new User(Date::create(2000, 1, 1));
echo $user->age(), PHP_EOL; // 16

このままでも動作は問題は無いのですが、気になるのは、Date クラスです。これは、日付を扱うクラスなので、挙動としては問題ありません。ですが、このクラスは汎用クラスなので、ドメインのコンテキストで扱う生年月日ではありません。プロパティ名を見れば、生年月日であることは想像できますが、より明示するために生年月日を示すクラスを実装します。

生年月日を示したのが、下記の DateOfBirth クラスです。内部表現としては、Date クラスを利用しているので、ただのラッパーのようにも見えます。ここで大事なのは、Date クラスのインスタンスを内包して、DateOfBirth クラスでは、年齢を算出する age メソッドのみを実装しているという点です。これにより、DateOfBirth クラスが担うのは、年齢を算出するだけということが分かります。

<?php
namespace Acme\Domain;

use Cake\Chronos\Date;

class DateOfBirth
{
    /**
     * @var Date
     */
    private $date;

    /**
     * @param Date $date
     */
    public function __construct(Date $date)
    {
        $this->date = $date;
    }

    /**
     * @return int
     */
    public function age(): int
    {
        return $this->date->age;
    }
}

DateOfBirth クラスを使った User クラスは下記です。コンストラクタの型宣言が変わっているだけなのですが、Date クラスに比べると生年月日であることが読み取れます。もちろん、User クラス内で生年月日を操作する際も age メソッドしかできないので、間違いようがありません。

もし、配送日などの別の日付クラスが存在したとしても、誤って User クラスに与えることができません。要求されている仕様が分かりやすいだけでなく、誤った引数に対するガードとしても有効です。

<?php
namespace Acme\Domain;

class User
{
    /**
     * @var DateOfBirth
     */
    private $dateOfBirth;

    /**
     * @param DateOfBirth $dateOfBirth
     */
    public function __construct(DateOfBirth $dateOfBirth)
    {
        $this->dateOfBirth = $dateOfBirth;
    }

    /**
     * @return int
     */
    public function age(): int
    {
        return $this->dateOfBirth->age();
    }
}

ドメイン特化クラス実装のポイント

このようなドメインに特化したクラスを実装するには色々な方法がありますが、いくつかポイントを書きます。

操作を必要最低限に絞る

PHP には、数多くの組み込みクラスやライブラリ、フレームワークがあります。一般的なデータ型を示すためのクラスは探せば見つかると思うので、多くの場合、それをベースとして利用するでしょう。

その場合、継承ではなく上記の DateOfBirth クラスのように委譲を使って実装します。

例えば、DateOfBirth クラスを Date クラスを継承して実装したとします。この時、DateOfBirth クラスは、Date クラスの public / protected メソッドを受け継ぐので、Date クラスと同様の操作が可能です。Date クラスには、日付の加算、減算といったメソッドがありますが、このコンテキストの生年月日に関してはそういった操作は不要です。不要なだけでなく、うっかり使ってしまうと想定外の動作を招く場合もあります。

こうした違いは、IDE で開発すると明確です。委譲版 DateOfBirth は、age メソッドのみ補完候補となります。一方、継承版では、age メソッドに加えて、Date クラスのメソッドが多数出現します。一つしかボタンが無いのと、たくさんのボタンがあるのと、どちらが利用者として分かりやすいかは一目瞭然です。

  • 委譲版 DateOfBirth

f:id:shin1x1:20161207135012p:plain

  • 継承版 DateOfBirth

f:id:shin1x1:20161207135019p:plain

対象に特化する(汎用性を求めない)

上記、継承が使われる理由として、DRY を意識しすぎるため、継承で実装の再利用を行いたいというものがあります。

例えば、このシステムに配送日といったモデルがあったとしましょう。生年月日も配送日も日付を示すものなので、Date クラスを基底クラスとし、それぞれ継承したとします。しかし、生年月日と配送日を同種のものとして扱う場面というのは、現実世界ではあまり思い当たりません。

ドメインに特化したクラスの実装では、汎用的に実装する必要はなく、対象にのみフォーカスして実装します。

これは、一般的な汎用クラスとは指向している方向が異なります。あくまでドメインに特化したクラスなので、汎用性を考える必要はありません。*2

もし、実装を共有したいという目的であれば、共通処理を行う別クラスを実装して、そこに委譲するか、トレイトにまとめるという手法を取ると良いでしょう。

一つの概念を表す小さなクラスを作る

今回の生年月日のように、一つの概念のみを示すクラスを作るようにします。凝集度が高い小さなクラスを作ることで、実装しやすく、使いやすく、テストしやすいクラスになります。

こうしたクラスは取り回しが楽なので、どのようなアーキテクチャであっても、取り入れることができます。特に、DDD のようなドメインを意識したアーキテクチャでなくても、一部だけでも、一つの概念だけでも、簡単に取り込むことができます。

実際の開発では、ValueObject(値オブジェクト)として実装するところから始めると良いです。

コンテキストによって異なる

DDD でも「境界付けられたコンテキスト」があるように、コンテキストというのは重要な概念です。

同じ「生年月日」でも、本エントリで扱う「生年月日」と別のシステムで扱う「生年月日」では、あるべき振る舞いが異なるかもしれません。今回は年齢の算出のみを実装しましたが、「今日が誕生日かどうか」「今月が誕生月か」といった振る舞いが必要となる場合もあるでしょう。むしろ、この2つのみが関心事であれば、「年齢を算出する」は不要かもしれません。

このように、同じ用語、概念であっても、コンテキストによって求められるものは異なります。つまり、生年月日とはこうあるべきといった汎用の生年月日クラスを実装したとしても、それがそのまま適用できるかどうかは、コンテキストによって異なるということです。

ユースケース

こうしたドメインに特化したクラスを少しづつ導入したい場合は、ValueObject として導入するのが実装するのが良いでしょう。ValueObject にすれば、操作が限定できるだけでなく、オブジェクトの不変条件を内包したり、内部表現をカプセル化することができます。

例えば、下記のようなものが考えられます。

  • 日付(日付ライブラリは高機能なわり、ドメインで要求されるものは一部。)
  • 数値、特に演算が行われるもの(金額、ポイントなど。演算の限定、制約条件の付与。)
  • 要求仕様が明確なデータ(商品コードなど。)

それ以外でも、サービスのように状態を保持しない処理もドメイン特化クラスで実装しやすい箇所です。

例えば、暗号処理なら、実際の暗号化や複合処理は別クラスで実装し、後はユースケース別のクラスからこれらのクラスを委譲で利用して、暗号化や複合を行うという場合に使えます。暗号処理は、暗号化と複合をペアで行う場合が多いので、ベアごとにクラスを分けると、ここで処理で暗号化したものは、あそこで複合しているというのが分かりやすくなります。

さいごに

こうしたドメインに特化したクラスを作るというのは、一見面倒なように見えますが、やってみると面白いものです。

生年月日も、汎用日付オブジェクトで表現すれば、それで終わりです。一方、生年月日クラスを実装すると、生年月日にどのような振る舞いが求められているかを考えることになります。このような視点で仕様を見ていけば、一つ一つの用語にも関心がいき、より深くドメインを理解して、コードに表現するようになります。

これは、教条的なものではなく、むしろ感覚に近いもので、こうしたプラクティスを重ねていくことで、身についていくもののように思います。

ドメインに必要な部品を少しづつ作っていき、それを組み合わせて構築していくという作業は、安心感もあり、とても楽しい作業です。身近なところから、取り組んでみてはどうでしょうか。

blog.shin1x1.com

*1:誤って押して、想定外の注文が飛ぶことはありますが

*2:ドメインコンテキスト内で汎用性を持たせるということは有り得ます。

「DDD パターンを活用した Laravel アプリケーション開発」を Laravel Osaka 2016 で発表しました。

2016/10/19 に大阪で開催された Laravel Osaka 2016 にて、「DDD パターンを活用した Laravel アプリケーション開発」を発表しました。

f:id:shin1x1:20161110215814j:plain

会場の MOTEX さん。巨大スクリーンが 2 面あり、話しやすい環境でした。

発表資料

Laravel の具体的なテクニックに比べると抽象的な内容なので、どれだけ伝えられるか思案したのですが、聞いて頂いた方からのフィードバックや参加者アンケートでも概ね良い評価を頂けたので安心しました。

ValueObject については、さらに掘り下げて話せるテーマなので、これ単体でもまた話してみたいです。

いつも blog や資料を参考にさせて頂いている増田さんに tweet して頂きました。インターネットっていいですね :)

質疑応答

発表の後の質疑応答では、多数の質問がありました。質問に対して的確な答えができたかは別にして、その場で今話した内容について意見交換ができるのは楽しいですね。

さらに、イベント終了後の懇親会や、後日、別の場でも発表についての質問や意見があり、そこから議論に発展することもありました。

話したことに対するリアクションが貰えるのは嬉しい限りで、発表者冥利に付きますね。

質問頂いた内容は、ざっと下記のようなものでした。(発表後の質疑応答以外のものも含む)

  • DDD をはじめるには、どこから手を付ければ良いか?
  • ValueObject を多数作った際のパフォーマンスについて
  • デメテルの法則について
  • なぜ、あえて Laravel を使っているのか?
  • リポジトリパターンと Eloquent について
  • 遅延評価クエリをどう組み込むか
  • 例外の使い方

今回の発表内容は、Laravel に関する内容は一部のみで、大筋はどういったフレームワーク、言語でも関連することなので、色々な人が自分なりの解釈で考えやすい題材であったのが一つ理由としてあるでしょう。

また、各技術の紹介や解説の発表に比べ、それらをどういった考え方で、いかに組み合わせるかというものは少ないように思います。

システム開発を行うならば、誰もが日々頭を捻りながら行っている行為なのですが、こういった話が勉強会などで表に出ることはあまり多くありません。

ドメインやコンテキストがそれぞれ異なるので、他人に話しにくいというのはありますが、今回のようにある程度抽象化すれば、みんなで考えられる題材になるので、もっと色々な人がこういった話をすると良いですね。(私はぜひ聞きたいです!)

さいごに

Laravel Osaka 2016 は、おそらく国内での Laravel 単体のイベントとしては最も大きい規模だったと思います。 第 1 回目ということで、関西だけでなく、東京や福岡からスピーカーも参加者も集まっていて、どのセッションも興味深い内容でした。

スタッフのみなさん、楽しいイベントをありがとうございました!

「正規表現再入門」を PHP カンファレンス 2016 で発表してきました

2016/11/03 に開催された PHP カンファレンス 2016 にて、「正規表現再入門」を発表してきました。

資料

speakerdeck.com

togetter.com

内容は、正規表現のマッチングの動き、量指定子のマッチングパターン、バックトラックやパフォーマンスへの影響についてです。

下記のエントリを下地にして、マッチングの動きを分かりやすく伝えることを意識してお話しました。 blog.shin1x1.com

参加された方からは、「分かりやすかった」といった好意的なフィードバックを頂けたので、発表して良かったです。

これから正規表現を学ぶにしても、マッチングがどのように行われるかをざっくりと知っておけば、正規表現を書く際にも動きが想像できるので、この発表がお役に立てると嬉しいです。

偶然、同じ時間帯に発表があった徳丸さんのセッションでも正規表現に触れられていたようで、Twitter の TL が微妙に交錯しているのが面白かったです :)

SQL と似た感覚

下地となったエントリでも書いたのですが、正規表現と SQL はやはり似ているなあと感じます。 懇親会でも、発表を聞いて頂いた方との会話で話題になりました。

宣言的に書く言語は、記述しやすく理解しやすいのですが、どのように実行されるかはブラックボックスになります。 もちろん、それは利点(How ではなく、What に集中できる)なので、実行エンジンが良しなにやってくれる時は全く持って問題ありません。

ただ、今回のバックトラック爆発のように仕組み上発生しうる挙動に関しては、利用側がそれを意識して書く必要があります。

特に、正規表現はバリデーションで外部から来た値をそのまま扱う場面でよく利用されるため、問題があればすぐに影響を受けることになります。

SQL を書く時にデータベースエンジンの動きをざっくりでも意識するように、正規表現でも意識すると良いですね。

さいごに

今年は、午後最後のセッションで、途中にサイン会などもあったので、t_wada さんのセッションだけ参加しました。

このセッションは素晴らしくて、同じように参加した人からも大絶賛でした。 内容はもちろんのこと、構成や説明など伝え方がとても参考になりました。自分の発表にも取り入れられる要素があったので、今後に生かしていきたいです。

懇親会やその後の N 次会でも、色々な方とお話ができて、楽しい時間でした。毎年そうですが、蒲田の PHP カンファレンスは最高ですね!

運営のみなさん、今年も楽しいイベントをありがとうございました。