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

新卒1年目のエンジニアブログです。基本的に何かが足りません。

Eloquent ORM vs Query Builder (+ DB Facade )

Laravel で データ取得の方法と述べると、Eloquent ORM と Query Builder (+ DB Facade )の2つが上げられると思います。

今回は、二つのメリットとデメリットを見比べつつ、どういう状況で使えば良いのかを書きます。

Eloquent ORM

Eloquent ORMは、Laravel が提供している O/R マッパです。

ActiveRecord ライクにデータの取得ができます。

メリット

O/R マッパ のメリットを享受できる

  • SQL という別の言語を、アプリケーション( Laravel )に介入せず済む
  • テーブル同士の関係性を定義できる
  • 再利用性や拡張性が高い

など...

今回は、O/R マッパについて述べるわけではないので、詳しくは書きません。

色々柔軟に設定できる

何ができるかは、ドキュメントを読めば一目瞭然です。

Eloquent:利用の開始 5.7 Laravel

  • 独自のグローバルスコープ適応による、独自メソッド実装
  • 特定のイベントをフックにした処理の実行(いわゆるObserverパターン)

拡張性に優れた機能を、有していると言えます

デメリット

O/R マッパ のデメリットを享受する

  • SQL が書けなくても、データ取得ができる
  • ぱっと見、どういうクエリを発行しているのかわからない
  • Eloquent O/R マッパは ActiveRecord パターンで実装されているので、ActiveRecord パターンを覚える必要がある

など...

こちらも、O/R マッパについて述べるわけではないので、詳しくは書きません。

ですが、「ぱっと見、どういうクエリを発行しているのかわからない」は、次のデメリットで関連して触れることになります。

特定のメソッドを使うと、サブクエリを使って実行する

例えば has や whereHas では、exists を使ったサブクエリを実行します。

参考: qiita.com

当然ながら、サブクエリを実行するわけなので、クエリの実行時間が長いことになります。中には join 句を使えばサブクエリにしなくて良いような内容も、サブクエリで実行します。

このデメリットは、O/R マッパのデメリットで挙げた「ぱっと見、どういうクエリを発行しているのかわからない」が躊躇に現れていると思います。

どういう時に使えば良いか

  • パフォーマンスよりも安全性を取りたい
  • 確実に、リレーションに沿ったデータ取得をしたい
  • 特定の状況下での条件付けや、処理の実行を実装したい

Query Builder (+ DB Facade )

Laravel が提供しているクエリを生成するためのメソッド群。

SQL ライクにクエリを書くことができる( Query Builder )他、SQL をそのまま書いて実行する( DB Facade )こともできます。

メリット

Eloquent と比べて高速

join 句を使ったクエリを書けば、Eloquent でサブクエリを使って取得している処理よりも早くなります。

また、以下 URL では、同じ実行結果でも、Eloquent O/R マッパ に比べて Query Builder (+ DB Facade )の方が早いことを主張しています。

参考:https://www.youtube.com/watch?v=3TJfR1Ta4GU

どういうクエリを実行しているのかはわかりやすい

SQL 文と書き方に大きな差はないので、なんのクエリが発行されているかは非常にわかりやすいです。

SQL を書けさえすれば学習コストは低い

どんなメソッドがあるかは覚える必要があるものの、それ以外に必要なことは、SQL 文を書けることだけです。

デメリット

自力で考慮しなければいけない点がある

  • テーブル同士の結合は自身で行う必要があるため、リレーションを正しく把握して反映する必要がある
  • 論理削除の条件は、自分で条件指定する
  • そもそも SQL 文で間違った書き方を書いてはいけない

など...

これらを正しく考慮できていないと、意図しないデータを取得してしまう場合があります。

また、個人開発ではなくチームによる開発であれば、レビュアーが上記の点を考慮してコードレビューしなければなりません。

どういう時に使えば良いか

  • 複雑な条件や大量のデータを扱うので、パフォーマンスを求めたい(検索画面、一覧画面とか)
  • 複雑な条件のクエリを、発行したい

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

メソッド概要

コレクション 5.6 Laravel

allメソッドはコレクションの裏の配列表現を返します。

<?php

collect([1, 2, 3])->all();

// [1, 2, 3]

裏の配列表現なんて仰々しい事を言っていますが、単純にコレクションの中身を配列で返すだけのメソッドです。

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

allメソッド

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

<?php

/**
 * Get all of the items in the collection.
 *
 * @return array
 */
public function all()
{
    return $this->items;
}

itemsプロパティの値を取得する。以上。第3部完ッ!!

…これだけだと切なすぎるので、items プロパティに何の値が代入されているのか construct を見ましょう。

Collectionのconstruct

<?php

/**
 * Create a new collection.
 *
 * @param  mixed  $items
 * @return void
 */
public function __construct($items = [])
{
    $this->items = $this->getArrayableItems($items);
}

$items を引数にして、getArrayableItems メソッドを呼び出しています。

とりあえず getArrayableItems メソッドの中身を覗きましょう。

getArrayableItemsメソッド

<?php

/**
 * Results array of items from Collection or Arrayable.
 *
 * @param  mixed  $items
 * @return array
 */
protected function getArrayableItems($items)
{
    if (is_array($items)) {
        return $items;
    } elseif ($items instanceof self) {
        return $items->all();
    } elseif ($items instanceof Arrayable) {
        return $items->toArray();
    } elseif ($items instanceof Jsonable) {
        return json_decode($items->toJson(), true);
    } elseif ($items instanceof JsonSerializable) {
        return $items->jsonSerialize();
    } elseif ($items instanceof Traversable) {
        return iterator_to_array($items);
    }

    return (array) $items;
}

Collection や Arrayable から配列を作成するメソッドのようです。 条件式が複数あるので、一つずつ何をしているのか処理を追っていきましょう。

条件式:is_array($items)

<?php

if (is_array($items)) {
    return $items;
}

$items が配列だったら、そのまま $items を返します。 配列なら、わざわざ変換する必要はありませんからね。

条件式:$items instanceof self

<?php

} elseif ($items instanceof self) {
    return $items->all();
}

$items のインスタンスが self(Collection) だったら、all メソッドを実行しその返り値を返します。

ここで、ちょっとした例を出してみます。

<?php

// IN: $items = new Collection([1])
$this->items = $this->getArrayableItems(new Collection([1]));
$this->items = new Collection([1])->all();
$this->items = $this->getArrayableItems([1]);
$this->items = [1];


// IN: $items = new Collection(new Collection([1]))
$this->items = $this->getArrayableItems(new Collection(new Collection([1])));
$this->items = new Collection(new Collection([1]))->all();
$this->items = $this->getArrayableItems(new Collection([1]));
$this->items = new Collection([1])->all();
$this->items = $this->getArrayableItems([1]);
$this->items = [1];

つまり、2次元の Collection でも3次元の Collection でも、1次元の Collection にしてくれます。以下が実際に実行した結果です。

<?php

dd(new Collection(new Collection([1])));
Collection {#450 ▼
  #items: array:1 [▼
    0 => 1
  ]
}

dd(new Collection(new Collection(new Collection([1]))));
Collection {#450 ▼
  #items: array:1 [▼
    0 => 1
  ]
}

条件式:$items instanceof Arrayable

<?php

} elseif ($items instanceof Arrayable) {
    return $items->toArray();
} 

$items のインスタンスが Arrayable だったら、toArray メソッドを実行しその返り値を返します。

Arrayable

Arrayable は、Laravel が提供しているinterfaceです。

<?php

namespace Illuminate\Contracts\Support;

interface Arrayable
{
    /**
     * Get the instance as an array.
     *
     * @return array
     */
    public function toArray();
}

toArray メソッドのみが定義されています。

別クラスに Arrayable を implements した上で、変換処理を記述した toArray メソッドを実装する、という使い方でしょうか。

配列じゃない別クラスでもtoArrayメソッドを使うことで、配列へ変換できるようにするため用意されている interface のようですね。

条件式:$items instanceof Jsonable

<?php

} elseif ($items instanceof Jsonable) {
    return json_decode($items->toJson(), true);
}

$items のインスタンスが Jsonable だったら、json_decode 関数を実行しその返り値を返します。

json_decode 関数の第二引数が true なので、$items は配列にデコードされます。

Jsonable

jsonable は、 Laravel が提供している interface です。

<?php

namespace Illuminate\Contracts\Support;

interface Jsonable
{
    /**
     * Convert the object to its JSON representation.
     *
     * @param  int  $options
     * @return string
     */
    public function toJson($options = 0);
}

toJson メソッドのみが定義されています。

こちらも別クラスに Jsonable を implements した上で、変換処理を記述した toJson メソッドを実装する、という使い方でしょうか。

json 形式じゃない別クラスでも toJson メソッドを使うことで、json 形式へ変換できるようにするため用意されている interface のようですね。

Arrayable とちょっとだけ似ている気がします。

条件式:$items instanceof JsonSerializable

<?php

} elseif ($items instanceof JsonSerializable) {
    return $items->jsonSerialize();
}

$items のインスタンスが JsonSerializable だったら、jsonSerialize メソッドを実行しその返り値を返します。

JsonSerializable

JsonSerializable は php が提供している interface です。 ( PHP: JsonSerializable - Manual )

<?php

/**
 * Objects implementing JsonSerializable
 * can customize their JSON representation when encoded with
 * <b>json_encode</b>.
 * @link http://php.net/manual/en/class.jsonserializable.php
 */
interface JsonSerializable  {

    /**
    * Specify data which should be serialized to JSON
    * @link http://php.net/manual/en/jsonserializable.jsonserialize.php
    * @return mixed data which can be serialized by <b>json_encode</b>,
    * which is a value of any type other than a resource.
    * @since 5.4.0
    */
    public function jsonSerialize ();

}

jsonSerialize 関数のみが定義されています。( PHP: JsonSerializable::jsonSerialize - Manual )

別クラスに JsonSerializable を implements した上で、 jsonSerialize 関数を定義し、配列への変換処理を記述する。

使い方自体は Arrayable や Jsonable と一緒のようですね。

条件式:$items instanceof Traversable

<?php

} elseif ($items instanceof Traversable) {
    return iterator_to_array($items);
}

$items のインスタンスが Traversable だったら、iterator_to_array 関数を実行しその返り値を返します。

Traversable

Traversable は php が提供している interface です。( PHP: Traversable - Manual )

<?php

/**
 * @link https://wiki.php.net/rfc/iterable
 */
interface iterable {}

/**
 * Interface to detect if a class is traversable using &foreach;.
 * @link http://php.net/manual/en/class.traversable.php
 */
interface Traversable extends iterable {
}

iterable を継承していることと( PHP: rfc:iterable )、コメントの内容からforeachで繰り返し可能なクラスに実装するようです。

抽象 interface なので Traversable 単体では動きません。ですので、Traversable を継承している Iterator もしくは IteratorAggregate に、foreachをした時の細かい挙動を実装する必要があります。

その上で、iterator_to_array を使って配列へと変換していきます。( PHP: iterator_to_array - Manual )

<?php

/**
 * Copy the iterator into an array
 * @link http://php.net/manual/en/function.iterator-to-array.php
 * @param Traversable $iterator <p>
 * The iterator being copied.
 * </p>
 * @param bool $use_keys [optional] <p>
 * Whether to use the iterator element keys as index.
 * </p>
 * @return array An array containing the elements of the iterator.
 * @since 5.1.0
 */
function iterator_to_array ($iterator, $use_keys = true) {}

条件式:上記に当てはまらないとき

<?php

return (array) $items;

上記に当てはまらなかった時は、配列に漢のキャストをします。

最後に

と言うわけで、Collection メソッドソースコードリーディング100本ノック1本目が終わりました!

all メソッドの内容だけでは寂しいと深掘っていったら、 Laravel どころか php の内部実装まで触れてしまいました。

次は avg と average メソッドです!

マサカリや「ここちげえぞ!!!」と言う怒りのコメントまで、お待ちしております!

Collectionメソッドソースコードリーディング100本ノック、始めます

久々の記事になります。最後に書いたのはお正月…実に10ヶ月ぶりの記事になります。 突然ですが、本日よりLaravel5.6 Collection メソッドソースコードリーディング100本ノックを始めます!

要は Collection メソッドのソースコードリーディングです

まず、僕が指し示している Collection というのは、Laravel が提供している配列のラッパークラスです。

コレクション 5.6 Laravel

Laravel を使った Web 開発をする時には、ほぼ確実と言っても良いぐらい使用されます。そして、その Collection で使用できるメソッドが…

f:id:cocoeyes02:20181111203606p:plain

数えてみるとわかるのですが、100個存在します。

そこでこの Collection メソッド100個全てのソースコードリーディングを、野球の100本ノックの如くこなすことにしました!

何故そんな事をするんだい

今回の Collection メソッドソースコードリーディング100本ノックを決行した理由は2つあります。

Larave のソースコードを読んだことがないから

一つは、Laravel のソースコードリーディングをしたことがなかったためです。

フレームワークを使用しているの中で、時にフレームワークがどんな処理をしているのか調べなければいけない時があります。

理由はバグ調査のためだったり、ドキュメントに書いていない仕様を知るためだったり…

僕は、2018年になってから、会社のプロダクトで Laravel を触り始めました。なので、がっつり Laravel のソースコードを読んで理解を深めよう! と考えたわけです。

ブログ記事を全然書けていないから

もう一つは、単純にブログ記事を全然書けていないからです。

エンジニアとして生きていくからには、アウトプットをすることが重要です。しかし、僕はここ10ヶ月ブログを投稿していません。

理由は忙しかったり…というのもありますが、一番の理由は「大したネタがない」です。

大したネタがなくても、アウトプットはして行くべきなのですが…どうもブログ記事にしたいネタが見つかりませんでした。

そこで、「ソースコードリーディングのついでに、ブログも書いちゃえばいいんじゃね?」と思い、ブログを書くことにしました!

1メソッド1記事書くつもりですので、これで100記事分のネタができたわけです。ブログが書けるよ! やったねたえちゃん!

Laravel 5.6、理解を深めていこう

今回の前提条件として、Laravel のバージョンは5.6で確認して行きたいと思います。

というわけで、100本ノック1本目の all メソッドについて、書いていこうと思います!

仮想通貨でお財布を厚くしたい!-3本勝負と開発中の仮装通貨バーチャルトレードサービス-

新年明けましておめでとうございます!久々の更新になります。

今回は今まで株もFXもやったことがない僕が仮想通貨でお財布を厚くできるのか?ということについて書きます!

去年の10月ごろから口座を開いて入金し出したので、今日に至るまでに起きたことを3本勝負形式で追っていきたいと思います!

ROUND1

まず結果から申しますと、初めての仮想通貨投資チャレンジはほぼ利益ゼロ(ちょっとマイナス)ぐらいで終わりました。

我ながらこれはひどい・・・

今まで株もFXもやったことなく、手探りでやった結果がこれです。振り返ってみると・・・

  • 他の仮想通貨が上がる上がるという買い煽りに負けてしまった。
  • 急に暴落し始めたのに対して深く考えず慌てて利確した。
  • 販売所(今回はコインチェック)でJPYや他の仮想通貨から仮想通貨を買うとき、まあまあ無視できない手数料が発生しているのに気にしていなかった。
  • etc...

色々と反省事項がありましたが、とりあえず「むやみに他の仮想通貨に変えない」「ブレない心を持つ」という意志を持ってROUND2に臨みました!

ROUND2

今度はBCHがどんどん上がっていく様子を見せていたのでBCHに4万円ほど注ぎ込みました。

今度はブレないぞ!利確もせず上がるまで待つんだ!

そう思った矢先に起きたチャートがこれです。

ファッ!?うーん…(死亡)

さながらデットコースタージェットコースターのように上昇、急降下していきました。

このあとある程度は価格が元に戻ったものの、最終的に1割ほどマイナスでBCHを売ることになりました。敗北した理由は間違いなく「チャートの上昇具合しか見てなかった」ことです。

この件でトラウマを植えつけられてしまったのか1ヶ月半ほど仮想通貨を買いませんでした。かなしい。。。

番外編

やはり慣れていないものに手を出すのがマズかったんだ・・・と肩を落としていた思っていた頃の話です。仲間内で「仮想通貨バーチャルトレードができるゲームを作ったらバズるのでは?」という話題が上がりました。

何それ面白そう!!と思い、開発メンバーとして参加することになりました!

現在パブリックβテスト中でございますので、興味がある方は是非触っていただき、気になる点や要望などをフィードバックしていただければと思っています!

coin-step.com

とはいえ開発メンバーとして参加する際、「そんなサービスがあったら損せずに投資の学びを得られたではないかファ〜〜〜wwww」

というやつあたりのような気持ちがあったのも事実ですw

だからこそ最初の僕のように「株もFXもやったことないけど仮想通貨には興味あるな〜」という人に仮想通貨投資の練習ができるような場を提供したいと考えております!

どうぞよろしくお願いします!

ROUND3

ROUND3ではチャートだけでなく、その仮想通貨のイベント(ハードフォークや企業連携など)に着目して購入するという方針にしました。

ちょうどこの時はXRPが「coinbase上場」と「リップル、大企業2社と提携」という材料があったためXRPを買いました!

途中でちょくちょく買い足したりして15万ほど入金した状態になっていますが結果は・・・

祝!初めて利益がプラスに!

一時は+13,4万ぐらいになっていたので3回目の投資にしてやっと成功したと言えるでしょう!

読売新聞一面に「国内メガバンク地方銀行で銀行間送金としてXRPを扱う。インターネット銀行や地銀など数行は再来月から運用開始する」という旨の記事が出たことによる急騰が利益をもたらしたようです。

買った時に予測していたイベントとは違う理由で利益が出てしまいましたがまあいいでしょう!(coinbase上場に至っては否定されてしまいましたし)

というわけで今まで株もFXもやったことがない僕でも利益を出すことができましたが、僕が買ったXRPのポテンシャルや今後のイベントを見ている限りまだまだ上がると思っています!

なので、もう少しこのまま握り続けて様子を見たいと思います!

僕の仮想通貨ライフはこれからだ!

PHPカンファレンス2017に参加してきました!

f:id:cocoeyes02:20171009120309j:plain

実は2回目の参加です。今年のテーマは「Challenge!」だそうです!

セッション自体はPHPカンファレンス2017公式ホームページで確認できるので、
個人的な所感とか補足とか無知故に知らなかったワードとか雑に書きとめていきます!  

聴講したセッション

できるPHP7アップグレード

  • 人が多すぎてサテライトが2つ設営されるほど大盛況でした!
  • 内容はペパボテックブログの記事からのようです。
  • PHP5.2だとComposerが使えないのでなかなかしんどそう・・・
  • 「Fluentd + Norikra を利用したログの集約・解析基盤を構築し、アプリケーションのPHPエラーログをSlackにリアルタイムで通知」ぜひ普段の開発から使っていきたい意欲があります。
  • 未使用ファイルはボディブローのように後々作業の邪魔になったりしますし、是非この段階で消したいですね!(なおシステムに詳しい同僚がもう社内にいない場合は…)
  • E2Eテストの環境も知見も全然ない状態なのでこの辺りは積極的に勉強しないと…。

Lancersのバージョンアップ施策について

  • インターン先でもPHPCakePHPのアップグレードが行われた(行われている)ので、いくつか見覚え・聞き覚えのある話がありました。
    • htmlHelperの変更や$this->param, $this->dataの変更など、今でもCakePHPのバージョンごとでどういう違いだったか混乱する時があります。
  • Codeceptionの存在を初めて知りました。なるほど、テストフレームワークですか…phpunitによるテストコードは現在も書いていたりしますが状況によってはこういったテストフレームワークを取り入れることになったりするのかなと思いました(小並感)。
  • できるPHP7アップグレードのセッションでもCIによるテストの話が出ていましたが、CIツールの使い方学ぶのも個人的な課題の一つですね・・・。

Serverless FrameworkでAWSフルマネージドなツールをいくつか作って得たアーキテクチャ設計の知見

  • AWS Lambda中心の話でした。
  • 「インフラもアプリケーションコードも一括管理できるデプロイツール」甘美な響き!
  • かなり講演者のノウハウを詰め込んだセッションだったので、AWS Lambdaを利用したbotとか作るときに非常に役に立ちそうなセッションでした。

大規模WebサイトURL刷新の方針と実装

  • 昔から頻繁にピクシブ利用していて、最近もURL見ていてすごいことになってるなあと思っていたところだったので、すごいタイムリーなセッションでした。
    • 結構サイトとか見るときにURLから規則性を予測してURL直打ちでショートカットしたりするので個人的にはうれしい改修だったりします。
  • MFIを発表してから何となくどのサイトでもモバイル版のWebサイトやレスポンシブデザインのサイトが増えた気がします。
  • ルータの作成についてはこちらのピクシブの記事が詳細に書いてあるようですね。
  • 相対パスのリンク組み立てはさすがにヤバそう:yabasou:

PHP Version Up と AWS への移行

  • 全チームや領域によらず一丸となってバージョンアップに取り組んでるのはとても素晴らしい!
  • パフォーマンス改善は副産物。互いのシステムの理解を得たり組織を超えたチームワークが次の大きなチャレンジとなる!
    • 「技術負債は人的資源に変える大きなチャンス!」名言ですね
  • 普通にPDCA回すことの大切さ
  • 「50%ほどLoad Averageが改善、Webサーバを40%削減」削減しすぎィ!!!

運用、追加開発しづらいPHPアプリケーションに未来を与える方法

  • サポーターズのお話です。就活では大変お世話になりました。
  • APMツールも実際に自分で使って見ねば…
    • Error Rate:最大30%強、761secのメチャ遅エンドポイントはさすがに笑いましたが人ごとでもないなとも同時に思いました。
  • ぼく「1メソッド140行8重ネストで会場にいる皆が笑っているということは…よくある話ではないのか…」

LT会

  • MDDと結果にコミットするセッションのインパクトが強すぎて帰り道「筋肉ファースト」なる単語が頭に焼き付いて仕方がなかったです!
  • ただそんな中でも「良いテストデータ、悪いテストデータ」の話は聞いてて耳が痛かったです…
    • いつでも見られるところにスライドの内容をメモとして置いておこうと思うぐらいあばばばとなってました。
  • 「告白に学ぶHTTPステータスコード」は是非漫画化を期待します(迫真)

セッション以外では

  • ふと書籍のコーナーを見てみると、既に読んだり積ん読として家に置いてある本が結構見かけました。
    • 前回参加した時よりもいろいろ読むようになったなあ…と実感しました。
  • 懇親会LTもなかなか個性的なものが多くて面白かったです!
    • MySQLのバグのLTは特に面白くて、毎年楽しみにして見ていますw

感想

  • 今年はインターンでもPHPフレームワークのバージョンアップを実施しているので、バージョンアップ系の話を中心として聞いていましたが、やはりテストコードやCI、APMツールの使い方は時間とって実際に触ったり勉強するべきだなと思いました。
  • セッションごとに準備の仕方や環境が違ったりしていますが、上記のことについては共通で述べられていたので勉強不足を感じました。
    • でもただ知見を得るだけでなく、自分の知識や理解度を確認する意義でも参加しているので至らぬ点を見つけてなんぼだと思っています。

最後に

  • 懇親会の様子をみて、皆PHPが大好きなんだなあとひしひし感じました。
  • あとHDMIケーブルが無いときでも誰かがすぐに持ってきたり、感謝の気持ちを込めたLTを発表したり、このPHPカンファレンスをコンテンツとして1人1人が盛り上げていこうとしているのが伝わってきました。
    • 今後何かのイベントに参加するとき、この光景を絶対忘れないようにしたいと思います!

それでは参加者、及びスタッフや登壇者の皆様、PHPカンファレンスお疲れ様でした!来年も必ず参加します!