• T, M T, M
  • — 1 month ago
Laravel で開発をして思ったこと②

前回に引き続き、Laravelで開発した過程で思った、良かった点や悪かった点を書いていきます。

Laravelについては、あくまでちょっと触った時点での感想です。
熟練者からみたらもっと凄い説明ができる部分もあるかもしれないので、ご理解を。

それでは、今回はLaravelのコレクションというクラスついて紹介します。

◆コレックションクラスについて

このクラスは端的に言えば、配列型の機能を拡張した型と思っていいです。
使った感想で、良かった点と悪かった点について記載してみようと思います。

◆良かった点について

①配列内の検索が少し楽になる

ちょっとしたDBみたいな抽出が簡単にできるようになります。
通常でも書く事はできますが、手間が省ける感じです。
具体的には下記のような形になります。

例:
    [テストデータ]
    // 配列のままのデータ
    $data = [ 
        ['id' => 1, 'type'=> 'dog', 'kind' => 'チワワ' ],
        ['id' => 2, 'type'=> 'dog', 'kind' => '豆柴' ],
        ['id' => 3, 'type'=> 'cat', 'kind' => 'ロシアンブルー' ],
        ['id' => 4, 'type'=> 'pig', 'kind' => 'ハンプシャー' ],
        ['id' => 5, 'type'=> 'pig', 'kind' => 'バークシャー' ],
        ['id' => 6, 'type'=> 'pig', 'kind' => 'ヨークシャー' ]
    ];

    // コレクション化したデータ
    $collectionData = collect($data);

    上記のようなデータから、type='dog'、kind='チワワ'のデータのデータを抽出するとします。
    その場合、配列のままで書くのと、コレクションにして書くのとでは下記のような違いがでてきます。

    [配列の場合]

        $result = [];
        foreach($data as $item) {
            if ($item['type'] == 'dog' && $item['kind'] == 'チワワ') {
                $result[] = $item;
            }
        }

    [コレクションの場合]

        $result = $collectionData->where('type', 'dog')->where('kind','チワワ');

見て分かりますが、ソースが解りやすい形でスッキリしています。
筆者は基本的に「解りやすくかつ、ソース量が減る=正義」と思っているので、良い機能だと思ってます。

②DBアクセスを減らす事が容易になる。

処理内で検索条件を変えて何度も同じテーブルを参照する必事が多々あります。
当然の事ですが・・・DBの参照(通信)回数が増える = サーバ負荷の増加です。
なので、1テーブル1アクセスというロジックにするためPGを調整するのですが、これが意外と大変です。
具体的には下記のようになります。

    [テストデータ]

    // DBのd_usersテーブルのデータ
    | id | name     | job      | lv | hp | atk | def | int | act |
    -------------------------------
    |   1| ユーザA  | 勇者     | 20 | 40 |  40 |  40 |  40 |   1 |
    |   2| ユーザB  | 戦士     |  5 | 18 |  15 |  18 |   5 |   1 |
    |   3| ユーザC  | 戦士     | 21 | 74 |  63 |  74 |  21 |   1 |
    |   4| ユーザD  | 僧侶     | 10 | 15 |  10 |  10 |  30 |   1 |
    |   5| ユーザE  | 魔法使い |  4 |  4 |   4 |   4 |  16 |   1 |
    |   6| ユーザF  | 賢者     |  3 |  3 |   3 |   3 |  11 |   1 |
    |   7| ユーザG  | 武道家   |  6 | 24 |  18 |  18 |   6 |   1 |
    |   8| ユーザH  | 武道家   | 14 | 56 |  42 |  24 |  14 |   1 |
    |   9| ユーザI  | 旅芸人   | 45 | 68 |  68 |  68 |  68 |   1 |
    |  10| ユーザJ  | バトマス | 18 | 45 |  72 |  27 |   9 |   1 |
    |  11| ユーザK  | 僧侶     | 18 | 27 |  18 |  18 |  54 |   0 |
    |  12| ユーザL  | 戦士     | 30 |105 |  90 | 105 |  30 |   0 |

    上記のようなテーブルデータから、下記の3種類のデータを抽出するとします。
      1.アクティブで戦士のユーザ情報
      2.アクティブで魔法使いのユーザ情報
      3.アクティブで勇者のユーザ情報

    [普通に検索を行った場合]

      $results = [];
      $targets = ['戦士','魔法使い','勇者']

      // それぞれの職業毎にデータを抽出
      foreach ($targets as $target) {
        $sql = "select name from d_users where act = 1 and job = " . $target . " and atk > 40";
        $result[$target] = $con->query($sql);
      }

    [コレクションを活用して検索を行った場合]

      $results = [];
      $targets = ['戦士','魔法使い','勇者']

      // ①アクティブなユーザのみ抽出
      $users = DUsers::query()->where('act', 1);

      // ②①の抽出結果を使い回し、それぞれの職業毎にデータを抽出
      foreach ($targets as $target) {
        $result[$target] = $users->where('job', $target);
      }

見て分かると思いますが、ソース的には大差はありません。
しかし大きな違いは、DBへのアクセス回数です。

普通に検索を行った場合、抽出ループ毎にDBにアクセスするので、抽出ループ数、つまり3回DBへアクセスします。
ですがコレクションを活用して検索を行った場合、DBへのアクセスは最初の抽出のみで、後は抽出結果を使い回すためDBへアクセスは1回だけです。

多くのユーザが同時使用する大規模システムでは「DBへのアクセス回数を減らす=負荷の軽減」となります。
たった1回のアクセス軽減と思いますが、数百人、数千人がアクセスするプログラムになるとこれで大きな差が出てきます。

もちろん通常の方法でもアクセスを1回にするようにPGを組むことは可能ですが、結構なロジックを書く必要があります。
またコレクションを使って検索する場合でも、最初の1回で抽出するデータ量が多くなりすぎると逆に遅くなる場合があります。
基本的にはデータが大きくなりにくいマスタデータ、ユーザデータの場合は、特定ユーザに絞った形で抽出して使い回す。
・・・といった形にするのが良いのではと思います。

◆悪かった点について

①使う上でのお作法が多く、習得し辛いため、引継いで長く使うには向かない。

Laravelを使い慣れた人ならいいのですが、知らない人が見ると、お作法が多すぎて混乱してしまうのではないでしょうか。
基本的にフレームワークで「覚えなければ多い事が多い=解り辛い」と個人的に思っています。

Laravelの1機能のコレクションでも100以上のメソッドが用意されています。
詳細は下記リンクより、コレクションのイントロダクションを見て頂ければと思います。
https://readouble.com/laravel/7.x/ja/collections.html

上記コレクションのリファレンスページを見ると、いきなりこんなソースが出てきます。

$collection = collect(['taylor', 'abigail', null])->map(function ($name) {
  return strtoupper($name);
})
->reject(function ($name) {
  return empty($name);
});

ご覧の通り、Collectionクラスは・・・・と説明が続きます。

正直筆者は最初なんじゃこれ?となりました。

リファレンスで、初っ端からいきなり無名関数を使ったり、mapメソッドを使ったりと、説明が複雑です。
プログラムに強い人に色々聞きながら、なんとか理解しましたが、プログラム初心者がいきなり見ても理解できないのでは…と思います。

Laravelを使うようなそこそこの規模のプロジェクトだと、個人でソースを全て管理する事はあまりありません。
また、長くソースを使い続ける場合、ソースを別の人へと引き継ぐ場合もあります。
必ずしもLaravelを深く理解してる人が後任に見つかる訳ではありません。
Laravelが分からない人が引き継がざる負えない場合もあります。

そのため後任が素早く理解できるソースがベストなのですが、お作法が多すぎために、後任は泣くのでと思います。

◆感想

今回コレクションについて軽く説明しましたが、このクラスはメソッドがとても多く、使って行くともっと良い使い方や、面倒な事が沢山でてきます。
ともあれ使えるメソッドが増えてくるとソースの効率化は進んでくるので、基本的には良い機能だと思います。
後は、筆者は英語が得意なエンジニアではないので、日本語のリファレンスがもう少し分かりやすければなぁ…とは思いますが。

てな感じで、次回は、Middleware回りの機能について書いてみたいと思います。
この機能については、筆者はあまり使いこなせていません。
・・・上手く書けると良いなぁ…と思いつつ。

T, M

System engineer

Laravel で開発をして思ったこと②

お気軽に
お問い合わせください。

お問い合わせ