がんばるぞ

がんばります

【相談】Eloquent/QueryBuilderでカラムの値をincrementする書き方が知りたい

僕は個人的に初心者エンジニアからのお悩み相談を受け付けていて
以前、以下のようなツイートをしたのですが

まぁこれが出会い厨に見えると。
友人からそういった指摘を受けまして

それの対策として、ちゃんと相談に答えている風景を公開するのはどうかという案をもらったので、これからはそうしたいと思います!!!! (もちろん許可は取ります)




相談者:
相談に乗っていただける旨のツイートを拝見し、DMさせていただきました。

現在、Laravelでアプリを作成中なのですがわからないことがあり、詰まっています!

記事テーブルに、iine_countカラム(integer) があり、ある記事にいいねをすると
その記事のiine_countを+1するクエリビルダorエロクエントの書き方を教えていだけないでしょうか。


吉田あひる:
なるほどー

ちなみに質問の背景は、

  1. どういうSQLを発行すれば目的が達成されるのかわからない
  2. SQLはわかるがQueryBuilderを使った書き方がわからない

のどちらでしょうか?


相談者:
1番です!


吉田あひる:
了解しました!

Eloquentを使用していると、SQLの知識が抜けがちになってしまって、学習のバランスが難しいですよね!

ただ単純に値を+1するだけであれば、以下のようなSQLを出力できればOKだと思います。

UPDATE posts
   SET iine_count = iine_count + 1
 WHERE post_id = ?

取得できたレコードの iine_count の値に +1 をして再代入してる感じですね
UPDATE文について詳しくはこちらを参照すると良いと思います!

また、テーブルに更新日時のカラムなどがある場合は、SET句に追加で
update_at = YYYY-MM-DD HH:MM:SS
みたいに追記する必要があるかもしれません *1

で、さらにじゃあこれをEloquent/QueryBuilderでどうやるのかというと
Laravelのドキュメントにやり方が載っていまして

<?php
Post::where('id', $postId)->increment('iine_count');

のようにすれば、最初に書いたようなクエリが発行されるんじゃないかなと思います


ちなみに僕の書いたSQLのフォーマットはこちらのスタイルガイドを参考にしています


で、これはちょっと話が大きくなってしまうのでアレなのですが
Postsテーブルにいいねの数を記録できればいいだけではなく、誰がいいねをしたのかというデータも必要になった場合は
今のデータの持ち方だと実現出来ないと思うので、その時はまたテーブル設計の仕方を考えてみると良いと思います!


相談者:
すごく丁寧にありがとうございます。。。😭
やってみます!


吉田あひる:
はーい!がんばってみてください!
自力でアプリケーションを書くのはものすごく勉強になるので、応援してます!!

また何かわからないことがあれば気軽にご連絡ください!




はい、こんな感じで相談にのってますので、みなさんお気軽にご相談ください!!!
(間違った回答をする可能性はめっちゃあるので、鵜呑みにはしない方がよいですけどね!!!!)

おわり

*1:カラムに更新時のタイムスタンプの更新が定義がされてない場合 https://dev.mysql.com/doc/refman/5.6/ja/timestamp-initialization.html

ahiru.yakiniku #1 を開催しました

日頃から焼肉を奢れという脅迫を受けている僕ですが 6/21(金)にとうとうahiru.yakinikuという、焼肉を(割り勘で)食べるだけのイベントを開催しました。

話したこと

  • エンジニアのコミュニティは最高
  • コミュニティ運営はむずい
  • 吉祥寺.pmはすごい
  • 先輩焼肉エンジニアのSさんに一度挨拶をしたい
  • laravel.shibuya をもっと盛り上げたい
  • BEAR.Sundayはいろんな可能性に気づかせてくれるフレームワーク
  • オブジェクト指向のハードコアってなんだったんですか
  • まつぴーさんとはまこさんはヤバイ
  • nさんもだいぶヤバイ
  • 転職の時くらいはwishlistは公開してほしい
  • でも誕生日に毎年wishlistを公開されるのはちょっとキツイ
  • Symfonyはもう1回くる
  • カンファレンスのチケットはもう1万円くらいにしてもいいんじゃない

なんかもっと色々話した気がしますが、もうだいたい忘れました。

開催してみて

直前の参加者のツイートを見て、穏やかじゃない雰囲気を感じましたが

めっちゃくちゃ楽しかったです!!!!

*1

やっぱり大好きな人たちと話すのは本当に楽しい! 楽しいことは何回でもやりたい!!

というわけで#2もやります!

ahiru-yakiniku.connpass.com みんな参加してくれよなっっ!!

*1:奢ってないです

Laravel Meetup Tokyo #12 にて登壇してきました。

かなり今更ですが、 Laravel Meetup Tokyo #12というイベントで登壇してきました。

Eloquentに別れを告げるタイミングについて考えたというタイトルで20分ほど話をさせていただきました。

登壇の反応はTogetterでまとめましたので、よければみてください。 togetter.com

スライドはこちら speakerdeck.com


なぜ話そうと思ったのか

EloquentはLaravelで使われるActiveRecordベースのORMです。

ActiveRecordは様々なORMで採用されていると思いますが、やはり有名なデザインパターンなだけあって非常に便利です。

しかし、便利な一方で批判的な意見も存在します。

その中の多くは「アプリケーションコードを複雑な仕様に耐えられるような設計にすること」に挑戦する人たちから発せられているように思います。

そこで、ActiveRecordの「得意な領域」や「批判されている側面」をそれぞれ整理して どういった場合にActiveRecordは有効なのか、またどういった場合にActiveRecordを採用すべきでないのかというのを一度自分の中で整理したいと思ったからです。

ActiveRecordの話なのですがLaravelの勉強会だったのでEloquentを例に挙げさせていただきました。

どんな内容だったのか

別れを告げるタイミングということで、自分が思う「Eloquentの辛いところ」をピックアップして それが本当にEloquentに別れを告げる理由になるのか考えてみるというスタイルでいきました。

おおまかにはスライドを見ていただければという感じなのですが、結論としては

純粋なドメインオブジェクトが必要になったら、別れを告げる必要があるのではないか

ということになりました(僕の中では)


純粋なドメインオブジェクトとは何かという説明の前に、ActiveRecordの制約について説明します。

ActiveRecordの制約の1つに「データベースのテーブルあるいはビューと1対1で作成する」というものがあります。

つまり、ドメインオブジェクトのプロパティはテーブル設計と密結合な状態になるということです。

usersテーブルにnameカラムとemailカラムがある場合は、対応するActiveRecordのクラスには必ずnameプロパティとemailプロパティがあるみたいな意味ですね。

これによってActiveRecordは非常に早い開発スピードを得ているわけですが それは同時に、テーブル設計に影響を受けないドメインオブジェクトを作成することが出来ないことを意味します。

これを「純粋でないドメインオブジェクト」と定義して、その逆に「テーブル設計から独立した(疎結合な)ドメインオブジェクト」のことを「純粋なドメインオブジェクト」とスライドの中では呼んでいます。(この呼び方が適切かどうかは微妙なところですが)

単純なCRUDだけでは済まないような複雑なアプリケーションがあった場合に、テーブルorビュー=ドメインオブジェクトというような設計では どうしても複雑な実装にならざるをえなくなってしまったり

「テーブルAのa,b,cカラムとテーブルBのd,eカラムを合わせてモデルAとしたい」というような状況が発生した場合はActiveRecordの責務を越え、対応が非常に難しくなると思います。

なので、

  • ドメインロジックをよりシンプルに実装するため
  • テーブル構造と一致しない概念(ドメインオブジェクト)が存在する場合
  • ドメインオブジェクトから永続化周りのロジックを切り離したい時

などの理由を背景に純粋なドメインオブジェクトが欲しくなった時がEloquent(ActiveRecord)とお別れするタイミングなのではないかと思いました。

話してみて

設計を学んでいる人からするとおそらく当たり前であろう結論になったので、本当にこの内容で登壇をするか少々悩んだのですが 実際に話してみると「勉強になった」という声をそこそこいただけたので、話してよかったなあと思いました。

また、設計の話はマサカリがすごく飛んでくるイメージだったので結構ビビりながらの登壇だったのですが あまり飛んでこなかったのでホッとしました(マサカリを投げてもらって勉強したかった気持ちもちょっとありましたが)

機会があればまた何か話したいと思います。


おわり

トゥギャッター株式会社に転職しました

2019/4/1からトゥギャッター株式会社というところで働いています。
前職はWebアプリケーションの受託開発をやっていましたが、次は自社サービスの開発をしていきます。

誰?

吉田あひるです。
今まではWebアプリケーションの受託開発を営んでいる会社に勤めていて
設計・開発・テストを一人でやってました。
PHPが大好きです。

なぜ転職したのか

技術力をもっと上げたかったのが一番です。
前職では技術力を伸ばすという面で少しだけ問題があって

  • 技術の話を出来る人がいない
  • 業務量が多く、プライベートで勉強する時間があまり取れない

という点が悩みでした。

開発環境や開発組織がある程度成熟している会社では勉強しなくても業務の中で自然と身につくようなことでも
前職では自発的に勉強しないといけなかったりで、そこらへんがどうしたもんかなあと思っていました。

具体的にはGitlabを運用するために実践Gitlabのような本を読んだりですね、まぁそういう本を読むのはそれはそれである程度楽しいので良いのですが
もっと知りたいことが山ほどある中で、かなりもどかしい感情を抱いていました。

そういった中でトゥギャッター様とご縁があり、話を伺ってみると

などですね、単純に楽しそうだなと思ってしまい、ぜひ僕を仲間に入れてくださいという感情を抱くことになりました

このままだと前職がアレな会社だと思われそうなのでフォローしておくと
前職は人間関係がおそろしく良好で、やりたいことはなんでもやらせてくれるような非常に良い会社でした。

なので、僕が「技術力は自分のペースで上げつつ、楽しみながら生活を送りたい」というような願望を持つ人間であれば転職することはなかったかなと思います。
僕はなるべく早く技術力を上げる必要があるので転職という手段をとりましたが、今でも前職は大好きです。

働いてみて

社風

まだ働いて1週間程度ですが、自由だなと思います。
1週間で2回もお花見をしました。お花見大好きか

大学生エンジニアのアルバイトの人たちは全員フルリモートで働いてます。すごいな。
木曜日はリモート推奨日なので、僕もリモートで働いてます。

あとは文化に造詣の深い人が多そうだなという気がしてます。
僕はエンジニアになってからプログラミング関連の情報以外何も学んでいないので、何らかの文化に触れなければという気持ちになっています。

残業ですが、定時から1時間後までにはほぼ全員帰ってるような感じです。
残業が無くなったのでプライベートの時間が増えるかと思いきや、通勤時間が9倍(往復20分->3時間)になったので、家にいれる時間はあまり変わってないですww
ただ、通勤中に読書ができるので、勉強時間を増やすことには成功しました。やったね。
通勤中にエンジニアの基礎力に繋がるような知識を蓄えようと企んでます

まだ1週間しか働いていないので、社風に関して語れることはほとんどないですが、第一印象としてはこんな感じです

技術面

社員のみなさんはもちろんなのですが、大学生のアルバイト(インターン?)の方々もかなり優秀でビビってます。
Webエンジニアを募集している各社、Togetterでバイトしてる大学生はめっちゃ優秀なのでチェックしておくといいですよ

開発環境ですが、モダンな環境にしていこうという気持ちがみんなにしっかりあって、なおかつそれぞれが実際に行動しているという状況がすごく居心地が良いです
僕目線ではすでにだいぶモダンに感じますが、まだまだ改善できるところは確かにあるかなという印象です。

10年もの歴史があるサービスなので、歴史的事情でモダンにしきれていない部分などもあり、そこらへんのアンバランス感も楽しいです。
解決するべき課題がある状況は、エンジニア的には遊び道具がたくさんあって嬉しいなという気持ちになります

開発中のコミュニケーションですが、Togetterでは各人にtimesと呼ばれるSlackのチャンネルが用意されていて、開発中に感じたことを適当に呟きます
詰まったりしたときや、なんでこここんな実装になってるんだ?みたいな疑問を呟くと他のエンジニアが反応してくれたりして非常に良い仕組みだなと思いました。
業務版Twitterみたいな感じですね。
もともと独り言が多いタイプなので、僕のtimesが一番活発になってます

あとは技術の話が出来るようになったり、設計についての議論が出来るようになったのがすごく嬉しいです。
一番設計に関心がありそうなエンジニアの方がフルリモートなので、うまいことコミュニケーションを取っていきたいなと思っています

まとめ

まぁとりとめもない感じでまとめも特にないんですが
今の所とても楽しいです。

受託開発とやることが異なりすぎてわからないことだらけですが
とにかく手を動かしながら調整していくのが性に合ってると思うので、何も考えずに手を動かしていこうと思います 。

重要な宣伝

Togetterは現在Webデザイナーを募集しているらしいので、全人類応募してください。


P.S.

関係ないですが、僕は吉田で、社長も吉田なので
誰かが社長の吉田さんを呼ぶと高確率で僕が反応してしまって困っています。誰かなんとかしてください。

何回も反応してしまうので反省している図
何回も反応してしまうので反省している図


P.S. P.S.

wishlistを公開してほしいという奇特な方がいるようなので公開します・・・!ありがたい・・・。
https://www.amazon.jp/hz/wishlist/ls/39ZZSAV18ZJQB?ref_=wl_share

おわり

Circle CIでIlluminate\Contracts\Container\BindingResolutionExceptionが発生する

Circle CIで、全てのテストが通っているのにCIが落ちるエラーが発生しました。

#!/bin/bash -eo pipefail
./vendor/bin/phpunit

PHPUnit Pretty Result Printer 0.25.1 by Codedungeon and contributors.

PHPUnit 7.5.7 by Sebastian Bergmann and contributors.

/* 省略 */

Time: 6.08 seconds, Memory: 36.00 MB

OK (155 tests, 234 assertions)

Fatal error: Uncaught Illuminate\Contracts\Container\BindingResolutionException: Target [Illuminate\Contracts\Debug\ExceptionHandler] is not instantiable. in /home/circleci/lec/vendor/laravel/framework/src/Illuminate/Container/Container.php on line 962

Illuminate\Contracts\Container\BindingResolutionException: Target [Illuminate\Contracts\Debug\ExceptionHandler] is not instantiable. in /home/circleci/lec/vendor/laravel/framework/src/Illuminate/Container/Container.php on line 962

Call Stack:
6.0873   36298904   1. Illuminate\Foundation\Bootstrap\HandleExceptions->handleException() /home/circleci/lec/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php:0
6.0878   36328616   2. Illuminate\Foundation\Bootstrap\HandleExceptions->renderForConsole() /home/circleci/lec/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php:87
6.0878   36328616   3. Illuminate\Foundation\Bootstrap\HandleExceptions->getExceptionHandler() /home/circleci/lec/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php:101
6.0878   36328616   4. Illuminate\Foundation\Application->make() /home/circleci/lec/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php:159
6.0878   36328616   5. Illuminate\Foundation\Application->make() /home/circleci/lec/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:757
6.0878   36328616   6. Illuminate\Foundation\Application->resolve() /home/circleci/lec/vendor/laravel/framework/src/Illuminate/Container/Container.php:619
6.0878   36328616   7. Illuminate\Foundation\Application->build() /home/circleci/lec/vendor/laravel/framework/src/Illuminate/Container/Container.php:671
6.0878   36328728   8. Illuminate\Foundation\Application->notInstantiable() /home/circleci/lec/vendor/laravel/framework/src/Illuminate/Container/Container.php:800

調べてみると、どうやらcodedungeon/phpunit-result-printerのAnyBarなるものがenableになっていると発生するエラーのようでした。 参考

なので、laravelのルートディレクトリにphpunit-printer.ymlを作成し

options:
  cd-printer-hide-class: false
  cd-printer-simple-output: false
  cd-printer-show-config: true
  cd-printer-hide-namespace: false
  cd-printer-anybar: false
  cd-printer-anybar-port: 1738
markers:
  cd-pass: "✓ "
  cd-fail: "✖ "
  cd-error: "⚈ "
  cd-skipped: "→ "
  cd-incomplete: "∅ "
  cd-risky: "⌽ "

のようにすることで解決しました

2018年を振り返る

2018年ももうすぐ終わります。

https://twitter.com/strtyuu/status/1079567851717943296

こんなツイートをしましたが、改めて今年を振り返ってみようかなと思います

仕事

2018年は、昨年に引き続きとにかく仕事を頑張った年でした。

給料もそこそこあげていただきました。
具体的にはベース給が年収50万弱上がりました。
ボーナスも含めると100万弱上がりました。本当にありがたいことです。

そしてさらにありがたいことに役職も少しだけにあげてもらい、それに伴い業務がほんの少しだけ変化しました。

  • 後輩(一応部下らしいですが、あまり部下という言葉がしっくりこないので後輩です)という存在が発生しました。
  • マネージャー会議というものへの参加権が与えられました
  • 従来の仕事に対する責任が多少増しました

ここらへんでしょうか。
入社一年半ほどでこういった評価をいただけるのはありがたいことです。

反省点としては、勉強したことのアウトプットが少なさすぎたことです。
自分が担当する案件では勉強した技術を使用していたので、僕自身はスキルアップ出来た実感があります が、それを社内へ共有していなかったため、会社へのポジティブな効果はあまり生み出せていなかったかなと思います。

また、だいたい僕は1人で案件のほとんどの部分を担当するため、技術的な挑戦・実験した結果のノウハウは社内勉強会などでしっかりアウトプットしないと誰とも共有出来ない感じです。
(最近は後輩の方と二人で案件をこなすことが増えてきましたが)

なので、せめて少しは共有しようということで2018/12/26に DDD、クリーンアーキテクチャ、CQRS などの話を100枚近いスライドにまとめて社内勉強会で発表しました。
来年はアウトプットをもっとやっていきたいですね

あ、あと多分2019年の4月に転職します。
一応内定はもらっているので、あちらからお断りされない限りは転職します。

給料はまだどうなるかわかりませんが、おそらく今と同じくらいかちょっと上がるかくらいだと思います。
残業がほぼなくなるらしいので、その分勉強や趣味に使える時間が増えます。やったね。

技術

技術的な大きな変化といえば、設計をそこそこ勉強したことですかね。

6月にDDDと出会い、DDDをきっかけにクリーンアーキテクチャ、CQRSなどの概念を知ることができました。
イベントソーシングに関しては全然試せていないので、来年は手を出したいですね。

設計に興味を持ったきっかけとしては、エンジニア歴半年ごろに担当した案件で 遺憾コード 、ようは技術的負債を自ら生み出してしまったことですね。
技術的負債を生み出さないために何か手がかりはないかと色々調べた結果、非常にピンときたのがDDDだったわけです。

見つけるまで半年近く時間がかかってしまったのがちょっともったいないですね。

DDDを通してOOPも多少は理解できたような気がしてます。
といってもOOPそのものをがっつり勉強したわけではないので、来年はOOP自体も勉強したいです。

あとはLaravelもだいぶ詳しくなりました。
来年はSlimなどのマイクロフレームワークもやりたいなあ。
言語もほぼPHPオンリーなので、別言語もやりたいですね。今興味あるのはRustとGoとScalaかな。でもGoはみんなやってるからRustにしようかな。

勉強の用途でのGithubの使い方がある程度わかってきた気もします。Githubめっちゃ楽しい。

音楽

ほぼギターを弾かなくなりました。指がどんどん動かなくなっていっている・・・。

とはいえ、何回かライブはやりました。
来年はオリジナルあるいはがっつりアレンジしたコピーとかやりたいなあ。
あとライブじゃなくてYoutubeでの活動を主にしようかなー。

来年は転職でプライベートの時間が増えるはずなので、ギターもしっかり練習したいですね。

リスナーとしてはネオソウル?とかいうジャンルにめちゃくちゃはまってます Artistでいえば

とかです、Lianne LaHavas超かわいい。
一番はまってるのはMoonchildです。
Robert GlasperのSmells Like Teen Spiritのカバーもめちゃくちゃすごいな。ああ。

というとりとめもないですが、今年の振り返りはこんな感じですかね。

来年もよろしくお願いいたします!!!!

route()の第二引数にはEloquentを渡そう

route('foo.bar', $eloquent->id)

みたいなことをしている人は

route('foo.bar', $eloquent)

といった感じで、Eloquentごと渡した方が良いですよ、という話。

なぜか

<?php
// vendor/laravel/framework/src/Illuminate/Routing/UrlGenerator.php

    public function formatParameters($parameters)
    {
        $parameters = Arr::wrap($parameters);

        foreach ($parameters as $key => $parameter) {
            if ($parameter instanceof UrlRoutable) {
                $parameters[$key] = $parameter->getRouteKey();
            }
        }

        return $parameters;
    }

これは、 route() でURLを生成する処理の中で、URLパラメータを取得している部分である。

<?php
if ($parameter instanceof UrlRoutable) {
    $parameters[$key] = $parameter->getRouteKey();
}

ここで、$parameterがUrlRoutableである場合は getRouteKey とかいうメソッドが呼ばれているのがわかる。

これは Illuminate\Contracts\Routing\UrlRoutable というインターフェースで、Eloquentクラスを見てみると

<?php
// vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php

abstract class Model implements ArrayAccess, Arrayable, Jsonable, JsonSerializable, QueueableEntity, UrlRoutable
{
    ...
}

ばっちり実装されているのがわかる。

つまり、Eloquentを渡すと getRouteKey という関数からURLパラメーターを返せるようになる

何が嬉しいのか

例えば、今まではURLのパラメータにautoincrementsなidを使用していたが
何らかの理由でuuidに変更したくなったとする。

そうするとEloquentの getRouteKeyName というメソッドをオーバーライドするだけで、全ての route() に修正が適用されることになる。 ※getRouteKeyメソッドではない

つまり、route() メソッドを使用してる場所を全検索などをせずに済む

これが嬉しい。

試しにやってみる

php artisan tinker で軽く実験

まずはデフォルトの状態。

>>> use App\User;
>>> $user = new User;
=> App\User {#2908}
>>> $user->id = 1;
=> 1
>>> $user->uuid = 'foo-bar';
=> "foo-bar"
>>> route('user.edit', $user);
=> "http://localhost/user/1"

次に、RouteKeyNameをオーバーライドする

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function getRouteKeyName()
    {
        return 'uuid';
    }
}

もっかい。php artisan tinker を実行

>>> use App\User;
>>> $user = new User;
=> App\User {#2908}
>>> $user->id = 1;
=> 1
>>> $user->uuid = 'foo-bar';
=> "foo-bar"
>>> route('user.edit', $user);
=> "http://localhost/user/foo-bar"

おっけー!