LaraVue勉強会 #10 開催しました!

こんにちは、株式会社ROXXの佐藤( @r_sato1201 )です。

先日、Laravue勉強会#10を開催いたしました。
はやいもので、今回でなんと10回目。 今回もたくさんの方に参加して頂き、非常に有意義な勉強会となりました。
その模様を報告させて頂きたいと思います。

laravue.connpass.com

会場

今回は、heyさんのオフィスをお借りしました。開放感のあるとてもきれいなオフィスでした。

f:id:ryonnsui1201:20190721002315j:plain

発表内容

スポンサー枠も含め、6名の方に発表していただきました。
すべて紹介するのは冗長なので、私が気になった発表を紹介させていただきます!

Storybookを用いたVue.js共通コンポーネント開発との戦い (@howdyさん)

f:id:ryonnsui1201:20190721003110j:plain

トップバッターはスポンサー枠の@howdyさん。
storybookを使った共通コンポーネント集を使う際の苦悩、戦いについて話していただきました。
予期せぬUI崩れに気づくために、REG-SUITという画像回帰テストを行ってくれるツールの話など、とても興味深かったです。

speakerdeck.com

Vuex-ORMの紹介 (@Yasshieeeeさん)

f:id:ryonnsui1201:20190722113816j:plain

VuexをDBとして使い、ORMライクなアクセスをすることができるVuex-ORMについてご紹介いただきました。
ノーマライズしてくれるので、複雑にネストされたデータ構造を持っているとき便利そうです。

www.slideshare.net

Laravel + AWSでCI/CDしてみた話 (@mjimaさん)

f:id:ryonnsui1201:20190721020257j:plain

AWSのCodePipelineでLaravelプロジェクトをCI/CDする話をしてくださいました。
AWSCodeBuild内のビルドの流れなど、詳しく知ることができました。

slides.com

Laravelのイベントディスカバリー (@niisan-tokyoさん)

f:id:ryonnsui1201:20190721020318j:plain

弊社からは、@niisan-tokyoさんにLaravel5.8.9から実装されたイベントディスカバリについて発表していただきました。
5.8.9以前だと、イベント・リスナーが増えるたびにEventServiceProviderが膨らんでいくが、イベントディスカバリを使うとリスナー側のhandlerに指定されているイベントの型宣言を読んで、その型のイベントのリスナーに自動で登録してくれるというお話でした。
非常に便利ですし、興味深い話でした。

qiita.com

PHPUnit + openapi-validator で「スキーマが正、実装が追従」にする (@kon_shouさん)

f:id:ryonnsui1201:20190721020345j:plain

スキーマが正、実装が追従となるようPHPUnitで、APIスキーマと異なるレスポンスを返したら、落ちるテストを書く話をしてくださいました。
OpenApiでAPIに関するインターフェース定義のyamlを吐き出し、openapi-validatorでそのyamlPHPUnitに取りこむ、という方法で実現していました。

qiita.com

懇親会

f:id:ryonnsui1201:20190721020218j:plain

発表後は、heyさんが提供してくれた美味しいケータリングを囲み懇親会をしました!
多くの方に残っていただき、会場の使用時間ギリギリまで親交を深めていただきました。

まとめ

今回は、Laravel,Vueの発表が半々でまさに「LaraVue勉強会」を体現する勉強会になったと思います。

次回の開催は未定です。詳細が決まり次第connpass上で告知いたします!

最後に

ROXX社では一緒に頑張ってくれる方を募集しております。 デザイナー、エンジニアの皆さん興味のある方はご応募お願いします!

www.wantedly.com

www.wantedly.com

www.wantedly.com  

スクラムマスターとして失敗したと思った2つのこと

こんばんは今年の3月から3ヶ月だけですがPOをやり今月からスクラムマスターをやることになりましたhirokinishizawaです。

スクラムマスターになってから1ヶ月がたつので本記事で振り返りつつ、スクラムマスターになってから失敗したなと思ったことを話していければと思います。

はじめに

SARDINEの開発チームは2軸でやっています。その中で1チームだけ10月頃からスクラムを導入し始めました。

当時自分はスクラムを導入した方のチームに所属しており、3月からもう一つのチームがスクラムを導入するタイミングで3ヶ月だけですがPOをやりました。そして今月6月から現在そのチームでスクラムマスターをやっています。

スクラムチームのそれぞれの役割

  • PO(プロダクトオーナー): 開発チームから生み出されるプロダクトの価値を最大化すること
  • 開発チーム: 開発チームの開発効率を最適化すること
  • スクラムマスター: スクラムの促進と支援をし目的を実現する確率を最大化すること

スクラムマスターの責任

スクラムマスターはスプリントを円滑に進めることに責任を持ちます。

その中には

  • 開発チームが行ったスプリント計画の障害になるものを取り除く
  • 次のスプリントをよくするために気づきやコミュニケーションを促す
  • プロダクトオーナーのプロダクトバックログの作成や並び替えを支援する
  • プロダクトオーナーと開発チームの会話を促す

などまだまだありますが基本的になにかを決定をするのではなくあくまでサポートする動きをしてスプリントを円滑に進めるように動きます。

スクラムマスターになってからの失敗談

POをやっていたときはなるべく要件から仕様までやってプランニング(見積もり)readyの状態をつくるようにしていました。なるべくというのはどうしてもバックログの調査や整理などが間に合っていなく、必要なときはタスクを作っていて開発チームがプランニングをするために障害がなくなることに注力してしまっていました。

その状態のままスクラムマスターになって失敗したなと思ったことを書いていこうかと思います。

POから要件を受け取りプランニングreadyの状態にする

POをやっていた時はゆくゆく仕様なども開発チームに降ろすようにしなければいけないと思っていました。ですがスクラムも始まったばかりだったので基本的にはプランニングの時に見積もりが出来る状態を意識してやっていました。そんな状態のままスクラムマスターになり、POから降ってきた要件を見積もりが出来る状態までタスク分解をやったことにより

  • プランニングがただポイントをつけるだけの作業になってしまっていた
  • スクラムマスターで閉じてしまっているため質問がないと共有出来ていないことがあり共通認識があわなかった

のような状態になってしまった。

開発チームの中継役になってしまう

実際にスクラムマスターとしてサポートするというのがどういうことなのか深く理解できていませんでした。最初はサポートとしてタスクの管理やアサイン、スプリント内であった開発チームの不安要素などを吸い上げPOに確認を自分が行っていました。ですがそれを続けたらPOと開発チームの中継になりコミュニケーションをスクラムマスターを通すというルールになっていきそうだったためやめました。基本的に開発チームがPOやステークホルダーとコミュニケーションを取っては行けないというルールはありません。

現在はスプリント内で上がった不安要素や技術課題などの優先順位をつけるためにPOとのコミュニケーションを促すようにしています。

まとめ

スクラムマスターの最終目的としてスクラムチーム にスクラムマスターってもういらないよね? というチームにしなければいけないと思っています。なのでスクラムマスターが見積もりが出来る状態までやるのはやりすぎに入ってしまいます。

見積もりするために何を準備すればいいのではないか、またどのように解決すればいいのではないか。というのように決定・命令はせずスクラムチームに気づきを促すサポートをしていくのがスクラムマスターなのではないかと思います。

まだまだ未熟なので間違っているところなどご指摘いただけると幸いです!8/7~8/9の間CSM行ってまいります!

最後に

で8/7~8/9でCSMを受けに行ってくるので終わったらいろんな人が書いていますが自分もブログを書きたいと思います!

現在、株式会社SCOUTERでは、エンジニア、デザイナーの募集をしております。

興味のある方は、是非下記からご応募お願い致します!

www.wantedly.com

www.wantedly.com

www.wantedly.com

Laravelのイベント&リスナについてまとめてみた

こんにちは、 株式会社SCOUTERエンジニアの佐藤(@r_sato1201)です

今回は、Laravelのイベント機能についてまとめたいと思います。

Laravelのイベントとは?

ReaDouble(公式リファレンスサイトを和訳したサイト)には以下のように記述してあります。

Laravelのイベントはシンプルなオブザーバの実装で、アプリケーションで発生する様々なイベントを購読し、リッスンするために使用します

参考:Laravel5.7 イベント

Laravelのイベント機能はObserverパターンで実装されています。
Observerパターンとは、観察される側(Subject)と観察する側(Observer)の2つの役割が存在し、観察される側の状態が変化した際に、観察する側に通知されるデザインパターンです。
Laravelではイベント(観察される側)とリスナ(観察する側)とに分かれており、イベントの変化をリスナが補足することで処理を行うという流れになっているようです。

イベント、リスナの登録

ここからは、「アカウント登録した際に、ユーザーに登録完了メールを送信する」機能を例に説明したいと思います。
まずはイベントとリスナの登録です。Laravelでは基本的にEventServiceProviderで管理されているので、listenプロパティに以下のように記述します。

app/Providers/EventServiceProvider.php

/**
 * The event listener mappings for the application.
 *
 * @var array
 */
protected $listen = [
    // アカウント登録
    Events\RegisterAccount::class => [
        Listeners\SendRegisterAccountNotification::class,
    ],
];

イベント、リスナの作成

次は、イベントとリスナの作成です。

php artisan event:generate

上記のコマンドを実行することで、EventServiceProviderに記述してあるイベントやリスナを生成してくれます。なお、既に作成済みのものには、変更を加えません。
app配下にEventsディレクトリとListenersディレクトリが生成され、RegisterAccount.phpとSendRegisterAccountNotification.phpが生成されます。

イベント定義

次に、イベントの定義をしていきましょう。

app/Events/RegisterAccount.php

<?php

namespace App\Events;

use App\Entities\User;
use Illuminate\Queue\SerializesModels;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;

class RegisterAccount
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * @var User
     */
    private $user;

    /**
     * Create a new event instance.
     *
     * @param User $user
     */
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function getUser()
    {
        return $this->user;
    }
}

メンバ変数のuserを定義して、getUser()でいつでも取り出せるようにしています。

リスナ定義

次に、リスナの定義です。

app/Listeners/SendRegisterAccountNotification.php

<?php

namespace App\Listeners;

use App\Events\RegisterAccount;
use App\Notifications\RegisterAccountMailNotification;

class SendRegisterAccountNotification
{
    /**
     * Handle the event.
     *
     * @param  RegisterAccount $event
     *
     * @return void
     */
    public function handle(RegisterAccount $event)
    {
        $user = $event->getUser();
        $user->notify(new RegisterAccountMailNotification($user));
    }
}

ここでは、Eventでキャッチした$userを、ユーザーにメール送信するNotificationである RegisterAccountMailNotificationに渡しています。
※RegisterAccountMailNotificationの内容はここでは省きます。

ちなみに、app/Entities/User.phpで、Notifiableトレイトを定義しておかないとNotificationが動かないので注意してください。

class User extends BaseModel 
{
    use Notifiable {
        notify as traitNotify;
    }
}

イベント発行

最後に、これまで記述してきたイベント処理を発行させる処理を記述します。
app/Http/Controllers/Api/RegisterController.php

<?php

namespace App\Http\Controllers\Api\Company;

use App\Events\RegisterAccount;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class RegisterController extends Controller
{
    /**
     * Create a new user instance
     *
     * @param array $data
     *
     */
    protected function create(Request $request)
    {
        $user = ([
            'email' => $request['email'],
            'password' => $request['password'],
        ]);

        RegisterAccount::dispatch($user);
    }
}

先程作成したイベントファイル(RegisterAccount)をuseし、dispatchしています。 これで、ユーザーがアカウント登録をした際に、ユーザーに対してアカウント登録メールを送信することができるようになりました。

まとめ

以上で、「アカウント登録した際に、ユーザーに登録完了メールを送信する」機能を一通り実装することができました。

今後は、

・イベントリスナのキュー投入
・ブロードキャスト

などを学び、理解してアウトプットしていけたらと考えています。

さいごに

現在、株式会社SCOUTERでは、エンジニア、デザイナーの募集をしております。

興味のある方は、是非下記からご応募お願い致します!

www.wantedly.com

www.wantedly.com

www.wantedly.com

参考資料

saml2awsを使ったセキュアなTerraform管理

saml2awsを使ったセキュアなTerraform管理

こんにちは kotamatです。

本日発売の WEB+DB PRESS Vol.111に 【第2回】コードの書き方の統一 ……PHP_CodeSnifferによる規約への準拠,PHPStanによる静的解析……というタイトルで寄稿させていただいております。

gihyo.jp

PHPをチームで開発されている方にはぜひ読んでいただければと思っております! が、今日は最近触っているインフラに関して、工夫したところを紹介させていただきます。

Terraform の provider管理

インフラ構築をよりセキュアにするために、SARDINE全体的にインフラを再構築しました。 今までTerraformでインフラを構築してきましたが、providerを下記のようにAWS のIAM keyを用いて実装してきておりました。

provider.tf

# Configure the AWS Provider
provider "aws" {
  region     = "ap-northeast-1"
  access_key = "my-access-key"
  secret_key = "my-secret-key"
}

GitHubでインフラ構成を管理しているのですが、もちろんこれだとコードベースにkeyがコミットされてしまい、必要以上のメンバーに共有されてしまいますので、Terraformのvariableを使い、コミットしない形で運用しておりました。

provider.tf

provider "aws" {
  region     = "ap-northeast-1"
  access_key = var.access_key
  secret_key = var.secret_key
}

variable.tf

variable "access_key" {}
variable "secret_key" {}

こうすることによって、対象のユーザごとにIAMユーザを作成し、適切な権限のみを与えることによってユーザを管理する事ができました。不必要になったタイミングで当該ユーザを消したりaccess keyを失効することによってログイン出来ないようにできますが、このような運用は頻度が多くなると大変ですし、なんといってもアカウント発行、失効の属人性も上がり、更にはPC側にkeyが残ってしまうことによって端末紛失などに耐えられない構成となっていることが課題でした。

この問題を解決するために、applyユーザだけはステップサーバーなど別のインスタンスだけで実行できるようにし、自動的にapplyが走るという環境を整備されているところもありますが、いくらplanやvalidateをしているとはいえ、apply時に実行時エラーが出ることもあるため、何かが発生したときの対応が難しく、やはりある程度は手元で実行できるようにしておきたいです。

AWS SSO as SP

そこで、今回導入したのが、SAMLベースでの認証形式を用いた構成です。 AWSにはSSOの仕組みがありますが、通常はIdPをAWSのIAMとした上でのSSOの構成を行うと思います。 ただ、逆にAWSのIAMにIdPを登録することによって、SAML形式かOpenID Connect形式によるAWSへの認証を行うことができます。

詳細の設定方法はAWSのブログが詳細を紹介されておりますので、こちらをご覧ください。

aws.amazon.com

こちら見てもらえるとわかりますが、ユーザごとにSession時間を設定する項目があり、デフォルトは1時間ですが、Terraformの設定中は1時間以上の作業時間を設ける事があると思いますので、こちらの設定項目を随時変更する事によって作業時間中にセッションが切れることがなくなります。

SSOをどうやってつかうのか

通常SSOはコンソール上で使用しているため、webの画面で使用するものかと思います。 しかしsaml2awsというものを使うことによって、任意のプロバイダーでのSSOログインをCLI上のみで行い、かつそのユーザをセッション付きで ~/.aws/credentials に保存することができ、そのユーザを用いてTerraformのproviderを設定することができます。

内部構造としては、go queryを用いてWebページにアクセスし、認証しているようです。

具体的な使用方法

saml2awsの設定

まずはsaml2awsに使用するIdPを設定します。

~/.saml2aws

[gsuite]
app_id               =
url                  = <GSuite側のログインURL>
username             = <GSuiteアカウント>
provider             = GoogleApps
mfa                  = Auto
skip_verify          = false
timeout              = 0
aws_urn              = urn:amazon:webservices
aws_session_duration = 3600 # 秒。必要であれば伸ばす
aws_profile          = saml # 使用したいprofile名
resource_id          =
subdomain            =
role_arn             =

設定後下記のコマンドでログインします。

saml2aws login -a gsuite

もしユーザ名、パスワード入力を省略したい場合は下記のようにします(端末にパスワードが残ってしまうので、あまりおすすめはしません)

saml2aws login -a gsuite --username=username --password='password'

Using IDP Account gsuite to access GoogleApps <GSuite側のログインURL>
To use saved password just hit enter.
? Username username
? Password

Authenticating as username ...
Open the Google App, and tap 'Yes' on the prompt to sign in

MFAを有効にしている場合、こちらが出たら端末側でYesをおします。

? Please choose the role  [Use arrows to move, type to filter]
  Account: XXX / role1 
  Account: XXX / role2 
  Account: XXX / role3 
❯ Account: XXX / role4 
  Account: XXX / role5 
  Account: XXX / role6 
  Account: XXX / role7 

そうすると、当該ユーザに紐付いているroleの一覧が表示されるので、適切なユーザを選択するだけです。

そうすることによって、 ~/.aws/credentialsに saml2awsに設定したprofile名でcredentialが保存されます。

Terraformのproviderを修正

最後にproviderの設定を修正します。

provider "aws" {
  region     = "ap-northeast-1"
-  access_key = var.access_key
-  secret_key = var.secret_key
+  profile = "saml" # saml2awsで設定したprofile名
}

Terraformの設定ファイル上では、saml2awsの内容ではなく、あくまでAWSのprofile名という抽象レイヤーで記述するので、他ツールに移行も簡単なのが便利ですね。

ログイン情報の除去

いくらSTSで期限付きのユーザを発行したとはいえ、ログイン情報をアカウントに保持させ続けるのは不安です。 そういった場合でも、GSuiteなどのIdP側のAttributeから、当該ロールを除外してあげるだけで、そのユーザからは二度とログインができなくなり、実質Terraformの実行権限がなくなります。

まとめ

AWS STSを用いたログイン方法を紹介させていただきました。 Terraformのベストプラクティスは結構各々実装しており散在している印象です。 この記事がなにかの手助けになれば幸いです。

最後に

弊社ではエンジニアを募集しております!

ぜひご応募ください!

www.wantedly.com

Flux パターンが解決した課題

SCOUTER 社でエンジニアをしている匠平(@show60)です。

突然ですが、私は Flux の無い世界を知りません。

エンジニアとして物心ついた時には、すでに世の中に Flux が存在していました。

開発業務では Vue.js (Nuxt.js) で Vuex を使用して開発していますが、改めて Flux の登場した背景を知ることは Vuex や Flux を理解する上で重要かと思いますので、あらためて調べてみました。

Flux が解決した問題

Flux が広く世に出たのは 2014 年の Facebook の開発者カンファレンス「 F8 」です。

既存の MVC パターンを放棄し、より機能的なアーキテクチャを支持する方法として紹介されています。


Hacker Way: Rethinking Web App Development at Facebook

(YouTube, 2014/05/04)](https://youtu.be/nYkdrAPrdcw)

Delivering reliable, high-performance web experiences at Facebook's scale has required us to challenge some long-held assumptions about software development. Join us to learn how we abandoned the traditional MVC paradigm in favor of a more functional application architecture.

React 以前のアーキテクチャ

JavaScript のフレームワークとして人気となった AngularJS の登場が 2010 年 10 月。

当時のフロントエンドのフレームワークにおけるアーキテクチャの原則は、すでにサーバーサイドで確立されていた MVC モデルを拝借する形で作られていました。

They borrowed practices that were already well established for server-side architecture. And at that moment, all the popular server-side frameworks involved some sort of implementation of the classic MVC model (also known as MV* because of its variations).

参考: Is Model-View-Controller dead on the front end?

React の登場

AngularJS の登場から約 2 年半後の 2013 年 5 月、 JSConf US で React が オープンソース化されました。

Facebook は、この MVC モデルをあらゆる箇所で実験したが、コード量が多く、開発が大きくなるとあらゆることが急激に複雑になることが分かったそう。

上記の動画では、そのデータフローについて "unpredictable" 、「予測不可能」という言葉を使い、フロントエンドフレームワークと MVC モデルが不適合であることを表現しています。

f:id:show-hei:20190612003637p:plain

この問題を解決するため、 Flux パターンが考えられました。

Flux is a pattern for managing data flow in your application. The most important concept is that data flows in one direction.

Flux とはアプリケーション上のデータを管理するパターンの一つ。

最も重要なコンセプトは、データの流れを単一方向にする、ということです。

Flux はどのように問題を解決するか

Flux とは設計概念と原則のことで、その実装方法を限定しているものではありません。

データの流れを単一方向にすることを設計概念とし、 データの流れを Action, Dispathcer, Store, View で構成することを原則としています。

flux/examples/flux-concepts at master · facebook/flux · GitHub

データの状態は Store が持っていますが、 Action から Dispatcher を経由しないとそれに変更を加えられないという強い制約があります。

f:id:show-hei:20190612003913p:plain

Flux がデータの流れにこの強い制約を与えることで、 Store を安全な状態に保つことができます。

Store の状態を予測可能にできることで、 MVC モデルで抱えていた複雑さの問題を解決しているというわけです。

Vuex と Flux

React で Flux パターンを実現するためのライブラリとして最も人気のあるのが Redux。

Vuex は Flux, Redux などから影響を受けた状態管理のライブラリです。

上記の通り、 Flux はその実装方法を限定していませんが、 Vuex もその構造化する方法を制限していません。

「原理原則を守ろう」と強調しています。

  1. アプリケーションレベルの状態はストアに集約されます。
  2. 状態を変更する唯一の方法は、同期的に処理を行うミューテーションをコミットすることのみです。
  3. 非同期的なロジックはカプセル化されるべきであり、それはアクションによって構成されます。

アプリケーションの構造 | Vuex

これらのルールに従っている限り、プロジェクトをどのように構造化するかはあなた次第です。 と記述されており、制限を持ちながらも柔軟な実装方法を許可しています。

開発チームやプロジェクトによって変えられるということは、チームやプロジェクトによって一定のルールを決める必要があるということですね。

最低限持つべきルールとして、 弊社の石岡が書いた記事がとてもわかり易いので、ぜひこちらもご参考ください。

techblog.scouter.co.jp

まとめ

過去の記事を振り返って見ると、フレームワークの登場からしばらくの間、フロントエンドのアーキテクチャは長い答え探しのだったようにも思えます。

Flux パターンが世に出て 5 年が経ち、 React のみでなく Vue.js やそのユーザーからも支持されているということは、フロントエンドのアーキテクチャの一つの答えであるということでしょう。

その恩恵を受けて楽しく開発ができていることに、感謝を惜しんではいけません。

Flux を考えた人たちに足を向けて眠れないですね。

さいごに

私達 SCOUTER では、一緒にプロダクト開発を行うエンジニア、デザイナーを募集しています。

ぜひご応募ください!

www.wantedly.com

www.wantedly.com

Laravelのテストで使うFactoryのstateのちょっと細かい話

こんにちはみなさん
@niisan-tokyoです。

Laravelを使うなら、当然テストも一緒に書くわけですが、テストの条件とかがどんどん複雑になってくると、可読性も落ちていろいろとやりにくくなります。
Laravelのテストデータを作成するFactoryには、複雑さを緩和するためにstateという機能があって、各条件・状態ごとに名前をつけることができ、そのstateごとに値を変えたり、後処理を入れたりすることができます。 ということで、今回はそのFactoryに実装されるstateをどのように使っていくか見てみましょう。

Factoryのstate

早速Factoryのstateを使ってみましょう。
まず、普通にUserのFactoryを作ると以下のような感じになります。

<?php
use Faker\Generator as Faker;

$factory->define(App\User::class, function (Faker $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'password' => bcrypt('secret')
        'is_admin'   => false
    ];
});

こうして作成されたユーザーはis_adminfalseになります。ここでis_adminが管理者フラグを表すとすれば、Factoryで作られたユーザーは管理者ではありません。 管理者ユーザーをFactoryを通して作成するためには、テストの中で以下のように書きます。

<?php
//...
$user = factory(User::class)->create(['is_admin' => true]);

データを作るたびに['is_admin' => true]を書くのはちょっと面倒くさいです。
そこで、「ユーザーが管理者である」という状態をFactoryに追加します。

<?php
//...
$factory->state(App\User::class, '管理者', function () {
    return [
        'is_admin' => true
    ];
});

これを追加しておくことで、テストでは

<?php
//...
$user = factory(User::class)->state('管理者')->create();
$this->assertTrue($user->is_admin);

のように書けます。

複数stateの持ち方

公式マニュアルにないので使って良いものかとは思うのですが、複数のstateを指定する方法もあります。 まず、

<?php
//...
$factory->state(App\User::class, 'Bob', function () {
    return [
        'name' => 'Mr. Bob'
    ];
});

こんな感じのstateを定義したあと、

<?php
//...
    public function testMultiState()
    {
        $user = factory(User::class)->states('管理者', 'Bob')->create();
        $this->assertTrue($user->is_admin);
        $this->assertEquals('Mr. Bob', $user->name);
    }

のように書くことで、複数のstateを同時に指定できます。

なお、複数stateでのmakeやcreateの実装を見ると、stateによる生成データの上書きは後勝ちになるため、

<?php
//...
$factory->state(App\User::class, 'Bob', function () {
    return [
        'name' => 'Mr. Bob',
        'is_admin' => false
    ];
});

のように、重複要素が指定されると、statesの引数の順番によってデータの状態が変わります。

<?php
//...

    /**
     * @test
     */
    public function 後勝ちなのでadminになるケース()
    {
        $user = factory(User::class)->states('Bob', '管理者')->create();
        $this->assertTrue($user->is_admin);
    }

    /**
     * @test
     */
    public function 後勝ちなのでadminにならないケース()
    {
        $user = factory(User::class)->states('管理者', 'Bob')->create();
        $this->assertFalse($user->is_admin);
    }

statesにたくさんの引数をもたせると、問題になるケースはありそうですので、最小限のstateにしぼりましょう。

afterCreating**

テストデータ生成後に追加で他のデータを生成したり、何らかのコールバック処理をしたい場合はafterCreatingを使ってコールバックを定義できます。
(なお、afterMakingでも同じような議論ができますが、割愛します。)

コールバック処理の定義は以下のようにFactoryに書きます。

<?php
//...
$factory->afterCreating(App\User::class, function ($user) {
    factory(App\Post::class)->create(['user_id' => $user->id]);
});

一方で、特定の条件下でのみコールバック処理したい場合はstateを利用することができます。

<?php
//...
$factory->afterCreatingState(App\User::class, 'Bob', function ($user) {
    echo $user->name;
});

このように定義することで

<?php
//...
$user = factory(User::class)->state('Bob')->create();
// Mr. Bob

「Bob」というstateを指定したときだけ、標準出力にMr. Bobというユーザー名が出力されるようになります。

afterCreatingの実施順

基本的に、実施する順番に依存するのはよくないのですが、そうも言ってられない場合があります。
実際にどのようにコールバック処理が実施されるかを検証してみましょう。

<?php
//...
$factory->afterCreating(App\User::class, function ($user) {
    \Log::debug('no state');
});

$factory->afterCreatingState(App\User::class, '管理者', function ($user) {
    \Log::debug('管理者');
});

$factory->afterCreatingState(App\User::class, 'Bob', function ($user) {
    \Log::debug('Bob');
});

のようにコールバック処理を定義したとき、以下の処理を実行してみます。

<?php
//...
        factory(User::class)->create();
        //  no state

        factory(User::class)->state('管理者')->create();
        //  no state
        //  管理者

        factory(User::class)->states('管理者', 'Bob')->create();
        //  no state
        //  管理者
        //  Bob

        factory(User::class)->states('Bob', '管理者')->create();
        //  no state
        //  Bob
        //  管理者

コメントアウトしたものがログに出力されたものになります。
afterCreatingで設定された処理は必ずデータ生成後にはじめに呼び出され、その後、stateごとのコールバックが呼び出されます。
複数のstateを設定している場合はstatesの引数に指定した順にコールバックが呼び出されます。

defaultの扱い

stateにおいて、「default」という名前は特殊な扱いを受けます。
おもむろに

<?php
//...
$factory->afterCreatingState(App\User::class, 'default', function ($user) {
    \Log::default('default');
});

と書いて、先の実施順の処理を実行すると

<?php
//...
        factory(User::class)->create();
        //  no state  
        //  default  

        factory(User::class)->state('管理者')->create();
        //  no state  
        //  default  
        //  管理者  

        factory(User::class)->states('管理者', 'Bob')->create();
        //  no state  
        //  default  
        //  管理者  
        //  Bob  

このように、どんなときでも「default」で指定した処理が流れます。
実装上はafterCreatingの内部ではafterCreatingState($class, 'default', $callback)が呼ばれているので、さもありなんです。

defaultはもともと一番はじめのstateのない状態なので、明示的に定義する必要はないと思いますので、stateに定義したり、使用したりしないほうがいいでしょう。

まとめ

というわけで、LaravelのFactoryのstateの細かい話をしました。
LaravelのFeatureテストを書いていると、テストデータ作成がどんどん膨らんでいくので、そのあたりをstateを使って効率化したいところです。
また、マニュアルにはないものの、複数の状態をもたせることもできるので、stateの定義数も最適化していけるといいと思います。

最後に

弊社は急速に成長しているプロダクトを複数抱えており、この成長を支えてくれるデザイナーやエンジニアを募集しています。

www.wantedly.com

www.wantedly.com

SCOUTER Conference vol.1を開催しました

こんにちは、株式会社SCOUTERの石岡将明( @masaakikunsan )です。

2019/05/28に、弊社にて SCOUTER Conference という新しいイベントを開催しました。

connpass.com

今回は、準備から実際にどうだったかをまとめていきます!

SCOUTER Conferenceとは

まず、SCOUTER Conference について説明します。 NuxtMeetupやLaravueやこのSCOUTER開発者ブログで徐々にSCOUTERの認知は上がっていっているが、結局何してる会社なの?どういう人がいるの?って思ってる方が多いと思います。

そこで、今回弊社エンジニアと話せるイベントを開催することでSCOUTER社のことメンバーのことを知ってもらえる機会を設けようと思い開催に至りました。

開催準備

今回イベント公開まで一日という爆速で準備をしました。

開催に至り、考えていたコンテンツは以下です。

  • SCOUTER社についての説明
  • メンバー紹介
  • メンバーとお酒を呑みながらワイワイ
  • 希望者はCTOとカジュアル面談

このコンテンツを元に、バナーを作成しました。 バナーでは、イベント名、何があるのか、お酒を飲んでワイワイする雰囲気が伝わるようなものを想定し、作成しました。

僕がまず手書きでイメージを作成し、デザイナーにそれをいい感じでデザインしてもらい、一緒にfontを選ぶ流れで大体3時間ぐらいで作成できました。

f:id:masaakikunsan:20190529151904p:plain

あとは、イベントページを connpass で公開し当日のお酒や食べ物の準備をしました。

今回はSCOUTER社のメンバーとつながりがない方の参加も想定していたので誰かわかるようにネームプレートを用意しました。 connpassからアイコンを入手し、バナーのメインカラーに合わせデザインしました。

f:id:masaakikunsan:20190529152243p:plain

イベントの模様

20人の募集に対し、22人の応募があり実際の参加は16人でした。 当日は雨も降っていたのでもう少し来ないかと思っていたのもあり、参加率は悪くなかったと思います。

最初の挨拶

今回企画を進めていた僕の方から軽い挨拶と会場についての説明をさせていただきました。

f:id:masaakikunsan:20190529153953j:plain

SCOUTERの事業紹介

SCOUTER社についての説明はCTOの松本からしていただきました。

SCOUTER社の生い立ち、SARDINE事業・back check事業、開発組織としてなにを目指しているのかをスライドと共に発表しました。 今回はそのスライドから見せてもいいところのみ抜粋します。 詳しい話を聞きたい方は是非vol.2にご参加ください。

f:id:masaakikunsan:20190529154346p:plain f:id:masaakikunsan:20190529154413p:plain

メンバー紹介

メンバー紹介のスライドは僕が作成させていただきました。 メンバー紹介は顔とその人が一致するようにしてほしいと思いもあり、写真撮影、自己紹介の内容から作成しました。 以下当日発表したメンバー紹介のスライドです。

docs.google.com

メンバーとの交流

参加者とメンバーでご飯とお酒を呑みながらワイワイと盛り上がっていろいろな話をしました。

f:id:masaakikunsan:20190529155607j:plain

大変私ごとで恐縮ですが、イベントの日が誕生日でして、知り合いの参加者がわざわざケーキを買ってきてくれたのでみなさんで美味しくいただきました。 本当にありがとうございました。

f:id:masaakikunsan:20190529155708j:plain

まとめ

SCOUTER社やメンバーや会社の雰囲気を知っていただくいい機会になったかなと感じています。

vol.2に関してはまだ未定ですが、今後もこういう場をやっていきたいと思うのでSCOUTER社をどうぞよろしくお願い致します。

最後に

SCOUTER社では一緒に頑張ってくれる方を募集しております。 デザイン、エンジニアの皆さん興味のある方はご応募お願いします!

www.wantedly.com

www.wantedly.com