今日もヤバさをI/O中。

(物理的)大型エンジニアのブログです。基本的に何かが足りません。

LaravelのwhereRawで安易にOR句を使ってはいけない

この記事は、Qiita の Laravel Advent Calendar 2020 20日目の記事です。

qiita.com

LaravelのEloquentやQueryBuilderで使えるwhereRawですが、安易にOR句を使うと落とし穴にはまることに気がつきました。

今回はその落とし穴と回避策について解説します。

laravel.com

TL;DR

  • LaravelのwhereRawでOR句を使うと、SoftDeleteが考慮されなくなったり意図しない条件が実行される可能性がある
  • whereRawでは括弧を自動的には追加しないため、whereRaw("A OR B and C") と記述した時に発行されるクエリは WHERE A or (B and C)となってしまう
  • OR句を使うときはクロージャを使う。どうしてもwhereRawを使いたいときはwhereRaw("(A OR B)")と記述する

なぜwhereRawでOR句を使ってはいけないのか?

例えばwhereRaw('A OR B')というクエリを実行すると、WHERE A OR BというSQL文が発行されます。括弧を記述していないため、WHERE (A OR B)というSQL文は発行されません。

whereRawは記述されたSQL文をそのまま実行しています。なので当然といえば当然ですが、括弧を自動的に追加するなんてことはしません。

この仕様が思わぬ副作用を生むため、安易にOR句を使ってはいけないと結論づけています。

whereRawでOR句を使った時に何が起こるか?

今回使用した動作環境のPHP/Laravelのバージョンは以下の通りです。

PHP8.0 Laravel 8.19

SoftDeleteが考慮されない可能性がある

deleted_atが存在するusersテーブルで、LaravelのSoftDeleteトレイトを使った時の場合を例にします。

クロージャを使ったケースと、whereRawでOR句を使ったケースで、実際に発行されるクエリは以下のようになります。

User::where(function ($query) {
    $query->where('is_admin', 1)
    ->orWhere('is_admin', 1);
})->toSql();
>>> "select * from `users` where (`is_admin` = ? or `is_admin` = ?) and `users`.`deleted_at` is null"

User::whereRaw('is_admin = 1 or is_client = 1')->toSql();
>>> "select * from `users` where is_admin = 1 or is_client = 1 and `users`.`deleted_at` is null"

同じクエリになるかと思いきや、違うクエリになります。クロージャの方では括弧が自動的に挿入されますが、whereRawでは挿入されません。

結果としてwhereRawでOR句を使ったケースで発行されるクエリでは

"select * from `users` where is_admin = 1 or (is_client = 1 and `users`.`deleted_at` is null)"

と同等のSQL文が実行されてしまい、is_admin = 1 and deleted_at is not nullのレコードを抽出してしまうような条件式になってしまいます。

意図しない条件が実行される可能性がある

where句でis_admin = 1 or is_client = 1 and is_corporation という条件を実行します。

orWhereを使ったケースと、whereRawでOR句を使ったケースで、発行されるクエリは以下のようになります。

User::where(function ($query) {
    $query->where('is_admin', 1)
    ->orWhere('is_admin', 1);
})->where('is_corporation', 1)->toSql();
>>>  "select * from `users` where (`is_admin` = 1 or `is_admin` = 1) and `is_corporation` = 1"

User::whereRaw('is_admin = 1 or is_client = 1 and is_corporation = 1')->toSql();
>>> "select * from `users` where is_admin = 1 or is_client = 1 and is_corporation = 1"

こちらも、whereRawでOR句を使ったケースで発行されるでは括弧が挿入されないため、

select * from `users` where is_admin = 1 or (is_client = 1 and is_corporation = 1)

と同等のクエリが実行されてしまい、is_admin = 1 and is_corporation = 0の条件式レコードを抽出してしまうような条件式になってしまいます。

回避策

回避策は幾つがありますが、ここでは2つの例をご紹介します。

クロージャを使う

丁寧に書くのであれば、クロージャを使うと良いです。

User::where(function ($query) {
    $query->where('is_admin', 1)
    ->orWhere('is_client', 1);
})->where('is_corporation', 1)->toSql();

>>>  "select * from `users` where (`is_admin` = 1 or `is_admin` = 1) and `is_corporation` = 1"

クロージャ内でwhereRawを使っても良いです。ただし、発行されるクエリがクロージャ内でorWhereを使った場合と厳密には違うので気をつけましょう。

User::where(function ($query) {
    $query->whereRaw('is_admin = 1 or is_client = 1');
})->where('is_corporation', 1)->toSql();

>>> "select * from `users` where (is_admin = 1 or is_client = 1) and `is_corporation` = 1"

whereRaw("(A OR B)")と記述する

どうしてもwhereRaw単品で使いたい場合は、括弧を明示してあげると上手くいきます。

User::whereRaw('(is_admin = 1 or is_client = 1) and is_corporation = 1')->toSql();

>>> "select * from `users` where (is_admin = 1 or is_client = 1) and is_corporation = 1"

おまけ:一応プルリクを出したが…

whereRaw("A OR B")と記述していても WHERE (A OR B)と自動的に括弧を追加する、という旨の改修をしてプルリクエストを出してみましたが、残念ながらマージされませんでした。

github.com

実際既存機能にどのくらい影響があるのか誰も(コミッターでも)想像つかないので、既存サービスへ影響を出さないことを優先したと考えれば納得です。

ならばドキュメントに注意書きを追加するのはどうだろう!と思ってプルリクエストを出してみましたが、こちらも残念ながらマージされませんでした。

github.com

できればこの記事を見なくても解決できる形にしたい気持ちがありましたが、残念です…

最後に

考えてみればそりゃそうなるよねって感じの仕様だとは思いますが、コードレビューだけではなかなか気づけない落とし穴だと思います。

また、OR句以外でもwhereRawで落とし穴がありそう…そんな予感がします。見つけた方は是非記事にして共有して頂けると嬉しいです!

Javascript 製のE2Eテスト(puppeteer)に纏わるちょっとした工夫

この記事は、ソフトウェアテストの小ネタ Qiita Advent Calendar 2019 の24日目の記事です。 puppeteer を触っているときにちょっとした工夫を2つほど思いついたので、コード例と共に記事にしようと思います。

テスト部分を try ~ catch ~ finally で括ると、テストに落ちた時や終了した時の処理をカスタマイズできる

puppeteer は node 製のライブラリなので、javascript で使われている try ~ catch ~ finally句が使用できます。

テスト部分を try ~ catch ~ finally 句で括ると、catch 句ではテストに落ちた時の処理を、finally 句では終了した時の処理をカスタマイズできます。

コード例

import Puppeteer from 'puppeteer';
import test from 'ava';

test.serial('ログイン_成功', async (t) => {
    const browser = await Puppeteer.launch({
        "ignoreHTTPSErrors" : true,
    });
    const page = await browser.newPage();

      try {
        await page.goto("https://hoge.com");
        await page.type(".mail-address", "hoge@huga.jp");
        await page.waitFor(500);
        await page.type('.password', "test");
        await page.waitFor(500);
        await page.click('.login');
        await page.waitFor('.logout');
        const result = await page.evaluate(() => {
            return document.querySelector('.logout').innerHTML;
        });
        t.true(result.includes('ログアウト'));
    } catch (e) {
        // テストに失敗したら、スクリーンショットを撮って保存する
        const todayDateTime = new Date();
        const formatTodayDateTime = String(todayDateTime.getFullYear())
            + String(todayDateTime.getMonth() + 1)
            + String(todayDateTime.getDate())
            + String(todayDateTime.getHours())
            + String(todayDateTime.getMinutes());
        + String(todayDateTime.getSeconds());

        await page.screenshot({
            path: 'screenshot/' + formatTodayDateTime + '_error_login.png',
            fullPage: true
        });

        t.fail('ログインテストに失敗しました。スクリーンショットをご確認ください。\nエラーメッセージ内容:' + e.message);
    } finally {
        // テストに成功しようが失敗しようがブラウザは閉じる
        await browser.close();
    } 
});

私は上記のように、「失敗した時はスクリーンショットを取って保存する」「テスト終了した時は必ずブラウザを閉じる」処理を追加しています。

環境によって違う値は、定数ファイルに保存しておくと管理が楽

ログインIDやパスワードといった環境ごとに値が違う場合は、定数ファイルにまとめて保存すると管理が楽になります。 仮にテストデータのリセットが行われたとしても、1カ所直すだけですむためです。

私は configと呼ばれる、環境変数(env)によって定数の値を変えるライブラリを使っています。

コード例

test.js

import Puppeteer from 'puppeteer';
import test from 'ava';

test.serial('ログイン_成功', async (t) => {
    const browser = await Puppeteer.launch({
        "ignoreHTTPSErrors" : true,
    });
    const page = await browser.newPage();

    await page.goto("https://hoge.com");
    await page.type(".mail-address", config.get("front.user.mail")
);
    await page.waitFor(500);
    await page.type('.password', config.get("front.user.password"));
    await page.waitFor(500);
    await page.click('.login');
    await page.waitFor('.logout');
    const result = await page.evaluate(() => {
            return document.querySelector('.logout').innerHTML;
    });

    t.true(result.includes('ログアウト'));
    await browser.close();
});

testing.json

{
  "front": {
    "user": {
      "mail": "hoge@huga.jp",
      "password": "Test2"
    },
}

staging.json

{
  "front": {
    "user": {
      "mail": "piyo@foo.jp",
      "password": "Test2"
    },
}

package.json

{
    "name": "e2e-test",
    "version": "1.0.0",
    "description": "",
    "scripts": {
        "test_testing": "NODE_ENV=testing ava --verbose",
        "test_staging": "NODE_ENV=staging ava --verbose"
    },
    "devDependencies": {
        "ava": "*",
        "config": "*",
        "puppeteer": "*"
    }
}

テスト実行時に NODE_ENV という環境変数を使って、使用する定数ファイルを指定しています。

改めて Laravel/framework のコントリビュートガイドを読んでみた

Qiita Laravel #2 Advent Calendar 2019 23日目の記事です。

過去に Laravel/framework にてコントリビュートをしたことがありましたが、
割と雰囲気でコントリビュートしていた感があったので改めてコントリビュートガイドを読み込んでみようと思い立った次第でございます。

ドキュメントを読み込む

Laravel/framework にはコントリビュートガイドが存在するので、コントリビュートガイドを読みつつ個人的に補足すべきところを補足してみます。

laravel.com

貢献ガイド 6.x Laravel

Bug Reports

不具合に関する報告は各 Repository に Pull Request を作成することで対応します。

ただ、Pull Request と言ってもバグ票代わりになるものなので、他のコントリビューターでも簡単にバグが再現・修正できるよう明確にしなければなりません。
「不具合の修正には、バグの報告者とコントリビューターたちで力を合わせて解決する」というスタンスのようですね。

当たり前といえば当たり前ですが、新規機能作成や仕様変更はバグレポートに含まれません。その場合は Core Development Discussion を読みましょう。

Pull Request をざっと眺めてみると、いきなり解決案となるコミットを提示していることが多いです。
「不具合を見つけたけど、どう解決するかまではわからんな…?」と思ったら、以下のように Issue を立ててみると良いかもしれません。

github.com

あるいは Laravel Discord server の #internals チャンネル で話してみるのも良いでしょう!

Support Questions

Laravel の使い方に関する質問や相談は、 Laracasts ForumsLaravel.io Forums などで受け付けるようです。

Issue をざっと眺めると、Laravel の使い方に関する質問や相談のパターンで issue が結構作成されています。(そのあと以下のように他のコントリビューターに Laracasts Forums や Laravel.io Forums などへ促された後、closed されるケースが多いです)

github.com

Core Development Discussion

新規機能作成や仕様変更の場合は、 Pull Request の作成より前に議論を行う流れがあります。

具体的なコード例がある場合は、laravel/ideasで issue を立て、議論しましょう。

github.com

実装できるのであれば、以下のように Pull Request も同時に作ると良いです。
議論が行われてからマージされると思いますので、他の人が Pull Request を作成する前に作成しましょう。(テストコードの実装も忘れずに!)

github.com

具体的なコードがないうちは、Laravel Discord server の #internals チャンネルで話してみましょう!
Taylor さんに話しかける良いチャンスでもあるので、話しかけてみるのもアリですね!

Which Branch?

基本的にコントリビュートで使うブランチは主に3種類です。

  • 現行の LTS のブランチ:サポートポリシーを確認しましょう
  • 最新の安定ブランチ:数値表記されたブランチの中で一番最新のブランチ(default ブランチに設定されていることが多いです)
  • 現在開発中のブランチ:master ブランチ

不具合修正は、基本的に最新の安定ブランチ or LTSブランチ
後方互換性があるマイナー機能は、最新の安定ブランチ
それ以外は、現在開発中のブランチ
ということになります!

これもわからなければ、 Laravel Discord server の #internals チャンネルで話してみましょう!

Compiled Assets

コンパイル済みのファイルをメンテナ(taylor さんなど)がレビューしない以上、
Pull request 上でコンパイル済みの大量コードを含むファイルが表示されるのは無意味です。
少しでもレビューしやすくするため、コンパイル済みのファイルを含めないようにしましょう。

Security Vulnerabilities

セキュリティ脆弱性を見つけたときは脆弱性を突かれる前になるべく早く修正しなければならない他、
対応が完了するまで大っぴらにするわけにはいきません。 そのため、セキュリティ脆弱性に関しては taylor さんにメールを送信するという方法を用いているわけですね。

Coding Style

Laravelは PSR-2 コーディング規約と PSR-4 オートローディング規約に準拠しています。
ただし、StyleCI によって自動で修正されるようなので、あまり気にしなくても良いかと思います。

Code of Conduct

こちらで特に補足することはありません。コントリビュートする際のマインドとして、大切なことなのでしっかり読みましょう。

最後に

私も含めコントリビュートガイドを見る前に、いきなりコントリビュートしてしまう人は多々います。 コントリビュートをする前に、まずはドキュメントと当記事を落ち着いて読むことをオススメします!(自戒の意味も込めて😇)

新卒1年目を終えて、学生時代から今までを振り返ってみた

4月になり、新卒1年目が終わりました。

学ぶことが沢山あり、これからやりたいことも明確になった新卒1年目でした…が、新卒2年目ともなると後輩も入ってくるしもっと大きな成果を求められます。

そのためには今の自分のままではダメで、もっと成長する必要があります。

そこで今回は、自身のエンジニア人生である2年半分の振り返り(超大作)について書こうと思います!

今回も例に沿って YKPWT で振り返ります!

やったこと

開発アルバイト時代(2016/10/01 ~ 2017/03/31)

株式会社ウィルゲートに開発アルバイトとして、入社。

当時は集団で開発した経験がなく、フレームワークもほぼ触ったことがないような状態。Git に至っては初めて存在を知る…

仕事

最初は開発のテストがメイン。また、業務理解のために、画面遷移図やフローチャートを書く。

徐々に業務にも慣れた頃に小規模の機能実装を任されるようになり、CakePHP を使った開発がメインの業務に。

コーディング / Pull Request ルールや、 Git 開発フローなど git を用いた集団開発の基礎を実践しながら学ぶ。

プライベート

大学では通常授業を受けつつ、学生プロジェクトとして Arduino や swift を触ってボードゲームを作成。

また、ボードゲームのコンセプトや内容詰めのために UI / UX やサーベイも実践しながら少しずつ学ぶ。

Kamihira Project 2016

就活も始まる頃だが、企業で働くエンジニアのイメージが1ミリも湧いていない状態。そこで技術的インプットも兼ねて、技術系のイベントに参加し続けていた。

先輩社員の誘いで、若手エンジニアの勉強コミュニティに参加(活動内容は後の時代で触れます)

内定者インターン時代前半(2017/04/01 ~ 2017/09/30)

株式会社ウィルゲートにて4月上旬に内定をもらい、内定者インターンとして働くことになる。

1年以上に渡ってお金を頂いているので、肩書きは開発アルバイト。

仕事

開発アルバイト時代から継続して、CakePHP を使った小規模の機能実装をこなす。

夏休み中は中規模開発プロジェクトに、実装者としてジョイン。

CPM やガントチャートを用いたスケジューリングや結合 / 受け入れテストなど…本格的に集団で開発することについて、実践しながら学ぶ。

プライベート

大学の授業と卒業演習でいっぱいいっぱいだったこともあって、それ以外の動きは乏しかった。

とはいえ、web 系についてのインプットは休日にやっていた(wordpress 構築してみたり、virtual box や vagrant を使ってみたり)

内定者インターン時代後半(2017/10/01 ~ 2018/03/31)

仕事

10, 11月は働きすぎで親の扶養から外れてしまう可能性があったため、お仕事はお休み。

12月以降は小規模の機能実装、3月からはまた中規模開発プロジェクトに、実装者としてジョイン。

業務と直接関係はないが、社内輪読会に参加。

輪読会はじめてます! | ウィルゲート開発ブログ

プライベート

CoinStep という仮想通貨バーチャルトレードゲームを、若手エンジニアの勉強コミュニティメンバーらで集団開発をしていた。

主に Golang を使いながらAPI の実装を担当。他にも、一部フロントで vue.js / vuetify.js を使った実装もした。

あとは初めて isucon に参加したり、イベントに参加したり…コワーキングスペースを借りて開発してたりもした。

新卒1年目時代前半(2018/04/01 ~ 2018/09/30)

正社員になった。同期のエンジニアが皆自分より技術力があることや、業務で一緒に開発をしてきた社員らと同じ立場になったことで緊張と焦りもあった。

仕事

4月中旬では新卒研修、4月下旬 ~ 5月までは、内定者インターン時代後半からジョインしていた中規模開発プロジェクトにて実装をしていた。この時業務で初めて SQS を使った。

SQSで処理を非同期化したらストレスフリーになった - WILLGATE tech blog

また、開発アルバイト・内定者インターン時代ではやらなかった運用保守を担当することになり、お問い合わせに対するログ調査などをやるようにもなった。

6月からは、新しいプロダクトの開発プロジェクトにジョイン。構成はレイヤードアーキテクチャ + Laravel + vue.js 。中でもレイヤードアーキテクチャは社内でも初めての試みで、皆で相談しながら理解を深めつつ、実装をしていった。

また、Laravel も初めて触るフレームワークだったため、チームで勉強会をしつつ自分でも勉強していた。

プライベート

正社員として入社してから3ヶ月ぐらいは思うように時間が取れず、いっぱいいっぱいの状態に。

(当時は実家から通っており、通勤時間は片道2時間15分…。平日に勉強する時間が全く取れないので、通勤時間が1/3の時間になるところへ引っ越した)。

この時期は仕事でレイヤードアーキテクチャに初めて触れたため、DDD やドメイン設計について調べて、どう実装していくのが正解なのか考えて理解を深めていた。

去年若手エンジニアの勉強コミュニティメンバーと一緒に参加していた isucon にも参加した。

新卒1年目時代後半(2018/10/01 ~ 2019/03/31)

仕事

6月から触っていた新しいプロダクトがリリースし、こちらの運用保守も担当することに。

ただ残念ながらこのプロダクトは、様々な観点から見て品質が悪いという課題があった。加えて、当初4人いた開発メンバーも自分と LDR だけに。

どう解決するのか自分で分析 / 提案 / 実行まで LDR に相談しながら協力してサービスの課題に向き合い続けた。

その影響で、初めて E2E テストをプロダクトで書いたり(puppeteer, nightmareJS)、テスト技法やテスト計画書について輪読会で学んだりした。

また、弊社で品質保証 PRJ を立ち上げ、自社の障害分析を行なっている最中である。

プライベート

今までに比べると多くのアウトプットをした。

あとは社内イベントのスタッフをしたり、技術系カンファレンスの当日スタッフに参加したり…

2月ぐらいから QA に興味が出てきたため、独学で勉強しつつ少しずつ勉強したりイベントに参加している最中である。

Keep

エンジニア面

  • 企業で働くエンジニアのイメージがわからない状態から、ここ数年で企業にて働くエンジニアとしてやりたいことがかなり具体化するまでに至った
    • 描きたいキャリアパスが入社前より具体化した
    • 企業に対して自身がどのような価値を提供できるのか、その価値は企業が求めているものなのかも考えるようになった
  • エンジニアとしても社会人としても成長が感じられた(特に新卒1年目後半は自分でもわかるぐらいめちゃめちゃ成長した)
    • 以前よりも自走力が上がったように感じる
    • エンジニアとしての自分に少しだけ自信がついた
  • 着実に技術力を身につけている
  • アウトプットする量が、以前よりも多くなった
    • 以前は「技術力ないからマサカリ投げられるのこわいな〜〜〜」と思っていたが、今は「どうせ技術力ついたところで投げられるときは投げられるんだから、気にするだけ無駄」と考えるようになった
  • 自身の興味(これから専門性として極めたい領域が)設計と QA であることがわかった

それ以外面

  • アウトプットする量が、以前よりも多くなった

Problem

エンジニア面

  • 業務で大きな成果は出せていない
  • 未だ自身の専門性(強み)が弱い
  • 新卒入社前でももっと成長できる余地があったのではないかと感じる
  • お世辞にも、アウトプットの質はまだ良いとは言えない
  • 思わぬところで基礎知識が抜けている

それ以外面

  • まだまだコミュニケーションが下手
    • 説明下手の域を出ていない
  • 「地頭」「論理的思考」「メタ認知力」などが課題に挙げられるが、残念ながら PDCA の回している回数が少ない
  • 「成果」を達成するまでのストーリー立てが下手
  • 段々人前で喋る機会が増えたため、自分の喋り下手なところが露呈した

わかったこと

  • 自分の描きたいキャリアパスが今のところ「まずは QA エンジニアになりたい。そのあと設計と QA を武器にしたアーキテクトを目指したい」っぽい
    • 弊社でも、品質保証の分野は求められているため自身のやりたいこと(Will)と、会社が求めているやるべきこと(Must)は一致している
    • あとは自身の専門性 / できること(Can)が一致すれば、業務でも大きな成果を出せる
  • 新卒入社後(特に新卒1年目時代後半から)成長したのは、実践しよう・試してみようという姿勢と振り返りがあった(≒ とにかく PDCA を回す)から
    • そのためにはインプットとアウトプットの両立と振り返りが大事
  • いきなりアウトプットの質を求めるのは無理
    • 量を重ねてから質を求めるべき
  • 登壇は素振りが大事
    • 喋りが苦手な自分はなおさら回数を増やすべき
  • 「地頭」「論理的思考」「メタ認知力」などが課題に挙げられるが、残念ながら PDCA の回している回数が少ない
  • 「成果」を達成するまでのストーリー立てに適した考えの骨組みがまだないかも

次にやること

  • QA の知識を最優先で身に着け、業務で実践する
    • ただし、最終的に目指したい姿はアーキテクトなので、設計の知識も身につけ実践する
  • 設計の知識を実践する場として、プライベートでプロダクト開発をする
  • 継続的なアウトプットは続けつつ、半年ごとに自分のアウトプットを振り返る機会を設ける
  • 人前で喋る機会を得たときは、絶対に素振りをする
    • 回数をこなせば、喋り下手も改善する道筋が見える
  • 思考法・ストーリー立てに適した思考のフレームワークを見つける
    • これは別途ブログ記事にして考えてみる

PHPerKaigi 2019 に当日スタッフとスピーカーとして参加してきたので振り返ったった

PHPerKaigi 2019?

phperkaigi.jp

2019年3月29日(金)〜 3月31日(日)はPHPerたちのお祭りです! この一文につきると思います!

他の技術系イベントと比べても参加者を楽しませるコンテンツが多数用意してあり、(いい意味で)異色の技術系イベントです!

発表内容共有

今回は LT スピーカーとしても参加したので、振り返りの前にスライドの共有をします!

speakerdeck.com

speakerdeck.com

後日発表時の動画もアップロードされるはずなので、アップロードされ次第こちらの記事にURLを貼り付けます!

振り返り

それじゃあまた振り返りをします!振り返り方法は、例のごとく YKPWT で行います

ただ、前回の振り返りだと詳細に書きすぎたので、少し簡潔にします!

やったこと

  • 当日スタッフ
    • 会場設営
    • ノベルティを用意する作業
    • トラックA の進行
  • LTスピーカー
    • 本編 LT
    • 懇親会 LT
  • 参加者
    • セッション聴講
    • 懇親会参加
      • PHPreParty, PHPer茶会, 懇親会, PHPostParty

Keep

当日スタッフ

  • 3日間という初めての長期間スタッフだったが、無事終えられた
  • 指示された作業よりも、自分で考えて(工夫して)作業した内容の方が多かった
  • 一部の当日スタッフらと後日ボルタリングへ行く約束をした

LTスピーカー

  • 2,300人という大人数の舞台で初めて登壇した
    • というか、応募時点では社外で LT をしたことがなかったが無事終えた
  • 時間内にきっちり喋り終えることができた
  • ちょっとしたハプニングがあったし、緊張もしていたが、素振りで練習した内容通りのことを話せた

参加者

  • やはり無料でセッションや懇親会に出れるのは最高(当日スタッフ・スピーカー特典)
  • 全日程の懇親会を通して交流を深められたので、通常のイベントの3倍(3日分)の繋がりが増えた

Problem

当日スタッフ

  • 明らかに最終日に近づくにつれて、疲れが隠せなくなっていた(小さなミスがいくつかあった)

LTスピーカー

  • 懇親会 LT で割とすべった
  • pdfpc と呼ばれる、pdf のプレゼンツールを使ったが会場の設備との相性が悪くて使えなかった
  • 事前に予告していた内容と少し違う内容になった

参加者

  • 当日スタッフの仕事やスライド作成・修正に時間をかけすぎて、一部積極的に参加できなかったコンテンツがあった(PHPerチャレンジとか)

わかったこと

  • 「最悪コアスタッフに相談すれば大丈夫」という気持ちがあると、色々いい感じに対応することができる
    • そういう安心感を抱かせてくれるコアスタッフの皆さんマジすごい
  • LT に問わず発表の素振り、何回もするの大事
  • LT、すべることもある。そういうこともある
  • 当日スタッフとはいえ、3日分も参加すると達成感とスタッフ同士の繋がり度合いが半端ない

次やること

  • 自分がイベント開催者になるときは、自分がうまく立ち回るのではなく他のイベントスタッフが動きやすいように立ち回る
  • 発表の素振り、何回もやっていき💪
    • 特にスライドが pdf だったら、スライドの内容を覚えこむまでやる(そうでなかったら、大人しく pdf ではなく keynote とかにする)
  • 次は PHP カンファレンス北海道のCfPにレギュラートーク枠で応募する
    • そのためにネタを考える・作る
  • 日頃からダジャレを言って冷たい目線を向けられることに慣れ、すべっても動じない心を身につける
  • 来年の PHPerKaigi も参加する

最後に

関係者、スタッフの皆さま、参加者の皆さまお疲れ様でした&ありがとうございました!

これだけ参加者を楽しませる取り組みがすごいカンファレンスは、そうそう無いと思います!!(現に知人とも「イベント運営面でお手本にしたいけど、正直再現性がわからんし、すぐ真似できなそう」って話をしました)

また次の PHPerKaigi でお会いしましょう!

avgメソッド Collectionメソッドソースコードリーディング100本ノック2本目

メソッド概要

コレクション 5.8 Laravel

avgメソッドは、指定したキーの平均値を返します。

<?php

$average = collect([['foo' => 10], ['foo' => 10], ['foo' => 20], ['foo' => 40]])->avg('foo');

// 20

$average = collect([1, 1, 2, 4])->avg();

// 2

average メソッドも同じ処理です。

ソースコードリーディング

avg メソッド

では早速、ソースコードリーディングをやって行きましょう。

<?php

/**
 * Get the average value of a given key.
 *
 * @param  callable|string|null  $callback
 * @return mixed
 */
public function avg($callback = null)
{
    $callback = $this->valueRetriever($callback);

    $items = $this->map(function ($value) use ($callback) {
        return $callback($value);
    })->filter(function ($value) {
        return ! is_null($value);
    });

    if ($count = $items->count()) {
        return $items->sum() / $count;
    }
}

後で解説しますが valueRetriever メソッドは、$callback をコールバックとして読み取れる値に整形するメソッドです。

$callback の戻り値を、 map メソッドを使って Collection へ整形します。

戻り値が null だった時は、 Collection に含めません。 null を平均の対象へと含めないようにする意図のようですね。

最後に Collection 内の値の平均値を返す…といった処理になります。

参考:

github.com

valueRetriever メソッド

<?php

/**
 * Get a value retrieving callback.
 *
 * @param  string  $value
 * @return callable
 */
protected function valueRetriever($value)
{
    if ($this->useAsCallable($value)) {
        return $value;
    }

    return function ($item) use ($value) {
        return data_get($item, $value);
    };
}

$callback を、コールバックとして読み取れる値に整形するメソッドです。

最初にそもそもコールバックとして読み取れる値だったら、そのまま値を返します。

コールバックとして読み取れない値だったら、コールバックとして読み取れる無名関数を返します。例えば以下のようなコードがあったとします。

$callback = $this->valueRetriever($value) 
$callback($item)

この場合、 $callback($item) は以下のようになります。

$callback($item) =
    function ($item) use ($value) {
        return data_get($item, $value);
    }

data_get は、配列やドット区切りのオブジェクトから要素(配列 or データ型の値)を取り出すヘルパメソッドになります(data_get ヘルパメソッドについては、別の記事にて解説します)。

$item が配列だったり Collection だった時のために、このような処理になっているようです。

参考:

github.com

github.com

useAsCallable メソッド

関数として呼び出し可能 かつ 文字列ではないかを返します。

呼び出し可能な関数名ではなく、関数そのものか判別したい時に使うようです。

<?php

/**
 * Determine if the given value is callable, but not a string.
 *
 * @param  mixed  $value
 * @return bool
 */
protected function useAsCallable($value)
{
    return ! is_string($value) && is_callable($value);
}

最後に

この記事を書いているうちに、 Laravel 5.7 -> 5.8 へとバージョンアップしました。

もたもたしているとすぐバージョンが上がってしまい、過去に書いた Collection メソッドをまた再度検証する…なんてことになってしまうので他のメソッドもどんどん書いていこうと思います!

次は chunk メソッドです!

LaravelJPConference 当日スタッフとして人生初参加してきたので、振り返ってみた!

2/16 開催の LaravelJPConference に当日スタッフとして参加してきました! conference2019.laravel.jp

人生で初めて大規模イベントの(当日)スタッフ参加です…!当日は進行を担当していました!

もちろん LaravelJPConference も、今年初の開催なので初めての参加ですw

ですが、スタッフも含め参加者は334名だったそうです! 初開催なのにすごい!

当日の様子やセッションについては、以下を見ていただければと思います!

ハッシュタグ#laraveljpcon

Laravel JP Conference 2019 スライドまとめ - Qiita

振り返り(YKPWT)

YKPWT を使って個人的な振り返りをしました! cocoeyes02.hatenadiary.jp

以下やったこと、Keep、Problem、わかったこと、次やることになります!

やったこと

  • Laravel Track の準備
    • 機械設備の仕様把握(PCの規格に合わせた表示変更、マイク音量調節、照明調節、空調など)
    • 設営(スピーカー台設置と後方のパネルの組み立て)
  • Laravel Track の進行
    • スピーカー対応
      • お水配布
      • 疎通チェック(スピーカーのPC に合わせて)
    • 司会
      • アナウンス(開始前 / 開始後)
      • 質疑応答
    • タイムキーパー
    • 機械設備操作
    • 質疑応答時のマイク運び
  • Closing Talk 後の片付け
    • 現状復旧
    • ゴミ片付け

Keep

当日スタッフとして
  • 連絡を見逃さないよう、定期的に slack で当日スタッフ用のチャンネルを見た
  • 誰も機械整備の仕様について詳しく知らなかったので、分かったことを随時 slack や口頭にて共有した
  • アナウンス内容を変える対応が何回かあったが、なんとか対応することができた
  • 設営担当の撤去の手伝いなど、特に割り振られていない仕事も少しやった
  • 初開催の LaravelJPConference だったが、大成功かつ無事終えることができた
  • イベント運営の経験を経て、対応力やナレッジなど得られるものがあった
一参加者として
  • Laravel や PHP 問わず知見や知識が深まった
    • しかもタダで!(今回当日スタッフはチケット代無料でした )
  • PHPer 界隈の知人がめっちゃ増えた(フォロワーも40人ぐらい増えた)
  • 自分の OSS 活動が評価されたようにも感じたし、他の人への勧め方など知見を得られた(ういろうさん @nyamucoro ありがとうございます!)
  • お昼御飯がめっちゃおいしかった(ランチサポンサーの株式会社デザインワン・ジャパンさんありがとうございます!)

Problem

当日スタッフとして
  • 事前にアナウンスのテキストを用意されていたので、iPad で確認できるよう持ってきていたが当日に iPad が初期化されていたことに気がついた 😇
  • アナウンス担当時に緊張し過ぎて、その時やってたセッションの内容が頭に入ってこなかった
  • Track がほぼ満員だった時、空き席への案内などの対応が満足にできなかった(コアスタッフの人に任せてしまった)
  • 事前説明会で言われたタスク以上のことが、あまりできなかった気がする
  • スマホの電池残量がギリギリだった(イベント終了時に7%)
一参加者として
  • 恒例(?)のじゃんけんで決勝まで上がったが最後で負けた :kanashii:

分かったこと

当日スタッフとして
  • イベントスタッフ用のワークスペースを用意する時、緊急連絡用のチャンネルがあるとすぐ報告できるし安心
  • 持ち場が固定のスタッフは持ち場以外の状況等が把握できないので、小さな出来事でも slack で共有してあげると良い
  • 会場の設備について、まだ把握していないのであればできるだけ早く理解して共有することが吉
  • イベントスタッフの経験豊富な人がいると、いろいろと円滑に進む(ありがたい。。。)
  • やっぱり午前中にトラブルが起きがち(逆に午後は安定する)
  • 定期的に slack を見たり、ツイートしたらすぐにスマホの電池残量が減る
  • 司会やばいぐらい緊張する
  • 当日スタッフとして参加すると、普通の参加以上に界隈の人と仲良くなれるチャンスがある
一参加者として
  • php 系のカンファレンスでやるじゃんけん大会は、前でじゃんけんをする人がなんの手を出すか予告するので、途中まではその手に勝つ手を出す
    • どこで裏切られるかを推測するのが勝利の鍵
その他
  • 自分のイベントアドリブ対応力の低さが露呈した
    • ホスピタリティが足りない
    • 経験値が足りない
  • デブなので立ち仕事やると、すぐに足に疲れが出てくる

次やること

  • 他のイベントにも参加して、イベントスタッフ経験を積む
    • 今度は自分が進行を円滑に進められるような人へ…
    • 自社のイベントスタッフやコアスタッフになることにも繋がるはず
  • 小さなことでもいいので、なるべく slack に流して共有する
    • ただし、緊急時の内容は、他の共有内容で流れてしまうとまずいので専用のチャンネルで共有する
  • スマホ充電用のモバイルバッテリーを持っていく
    • 持ち歩くことになるので、できるだけ小型の方が良い
  • 前日に自分が持っていくデバイスが正常に起動しているか確認する
  • 次のじゃんけん大会こそ、どこで裏切られるかを推測して景品をゲットする!!!!
  • 運動しよう…

最後に

拙い個人的な振り返りの共有になってしまいましたが、全体を振り返ってみても当日スタッフ参加はとても得るものが多いです!!

他のPHPカンファレンスでも当日スタッフを募集していると思いますので、参加されたことが無い方は是非参加をお勧めします!!!

2019年に開催される全国のPHPカンファレンスのまとめ - Qiita