物理の可視化で楽しくカイゼンを回しているヴァル研究所に遊びに行った

ヴァル研究所(以下、ヴァル研)さんに遊びに行ってきました。

www.val.co.jp

f:id:zuckey_17:20180209174211j:plain:w300

サービスとしては、「駅すぱあと」などで有名ですが、ある一方では会社全体で、アジャイルおよびアジャイルのプラクティスを導入され、業務改善にすごく良い感じで取り組んでおられることで有名な会社さんです。

遊びに行ってきた聞いたきたこと、感想などをメモ的に残しておこうと思います。

何をしに行ったのか

f:id:zuckey_17:20180209174251j:plain:w200

有名なスライドで、↓のようなものがあるのですが 、

www.slideshare.net

この発表者のぷぽさん id:pupupopo88 と面識があり、

について事例を見たり、それについて議論したりするという目的で見学に行ってきました。

公開できない情報が記載されていたので、KPTボード、リリーストレイン、カレンダーボード、スプリントボードなどは写真に収めてこれなかったのが残念です。

中の人のブログがあって、物理ボードの雰囲気などは伝わるかなと思っています。

hiiiiiiihikaru.hatenadiary.com

KPTについて

KPTは振り返りツールで、

  • Keep=よかったこと
  • Problem=悪かったこと
  • Try=次に試すこと

の頭文字を取っています。

僕が所属する開発チームでも導入していましたが、「T」が消化されず、意味を見出せなくて立ち消えてしまったという経緯がありました。

話しているうちに、継続させていくにはいくつかポイントがありそうだなと思いました。

物理でやったほうが良い

ヴァル研さんは本当に物理ボードが多く、いろいろなことを物理的に可視化されています。 その中でもKPTは物理でみんなで囲みながらやった方が良いとのことでした。

ワイワイやるのが大事

KPTで振り返りを始めます」といっても、業務が忙しかったり、やり方に馴染みがなかったりすると辛いというメンバーがいたりします。
そういったことを解消するには、楽しく続けて、習熟させていくということが重要ということでした。
KPTでよく言われるのは「ちょっとくだらないことをあげて発言のハードルを下げる」、というテクニックですが、同じ感じで始めはKを多めにして、より楽しくするということが重要なようです。

PをPのままで放置しない

「やるやら」をまず決める、対応するものをTに落としてマトリクス化(重要度と難しさを軸にする)することが重要とのことでした。 やらないものについては2種類あって、

  • 大した問題ではない
  • 大きな問題すぎる

後者は、別で深掘りするための会議などを設けるといったTにすることが重要とのことでした。
大きすぎる問題について、Tを無理やり作ってしまうと、結局重い問題だけが溜まってしまうというのは僕のチームに起こった問題に近いかもしれないと感じました。

また、「やるやら」や、やらないことの大きさの判断については、本当の課題を見出す技術などが重要というのがありました。
そういったことに長けた外の人を呼んだりしつつ、併せて技術力を磨いていくしかない、ということでした。

リリーストレイン + カレンダーボード + スプリントボード

この3つのボードが、ヴァル研の多くのチーム(特に開発関係)で導入されていたように感じました。

規模の順に リリーストレイン => カレンダーボード => スプリントボード という関係性です。

基本的には

  • リリーストレイン
    • 半年間の大まかなスケジュール(半月単位で見直しあり)
  • カレンダーボード
    • 月1のものリリーストレインからブレイクダウンしたやること、イベント
  • スプリントボード(カンバン)
    • 1週間(1スプリント)単位でのタスクとそのポイント

という風に分類をされているようでした。

すべて物理でやられているところも多かったのですが、開発チームについては、PRとタスクを紐付けたり、リモートワークに対応するためにスプリントボードのみデジタルにされているチームが多いということでした。

また、スプリントボードのタスクはそれぞれに、

  • やる理由
  • ゴール
  • 大まかな方法

を書くことをルール付けされていました。 粒度や書き方などは修正すれば良くて(例えば小さすぎるタスクには何も書かれていなかったりしていました)、徹底することよりも、始めること、それを続けることが大事なのだな、という印象を受けました。

その他

開発以外のチームで導入する良さ

純粋に、そのチームの業務が改善するということ以外にもメリットがあるようでした。
開発以外とも含めたチーム間でアジャイル用語や、アジャイルのプラクティスの言葉が伝わるという状況はかなり嬉しいということでした。
確かに、開発には「それは優先順位低いから次のスプリントでやりますね。」というので伝わることも、営業さんやその他のビジネスサイドの方には、違う言い方をしないと行けないのは積もるとコストなのかなとも思いました。
共通言語の本として、SCRUM BOOT CAMP THE BOOKを導入されていて、一時期購買の書籍購入履歴がそればかりになったという話もされていました。

VSM(Value Stream Mapping)*1

僕も初めて知ったのですが、VSMというものが、開発島の至る所に貼ってありました。
僕のかんたんな理解では、開発にかかった時間を可視化することで、どこのプロセスにどれだけの時間がかかっているかを可視化し、効果が高いタスクや改善ポイントを見極めることができる、といったものです。
いろいろな壁に貼ってあるのをざっくりと眺めて、サービスの流れが見えるような気がしたので、本来の目的だけではなくサービス全体を見渡す意味でも良さそうだなと感じました。
また、ヴァル研では、そのプロセスを誰が担当していたかということも書かれており、その部分に詳しい人もわかりやすくなっているのも良さそうでした。

物理ホワイトボード、壁が豊富

自社ビルということもあり、広く、(開発以外も)1チーム5~10人に2枚ずつくらいのホワイトボード があり、さらに壁際に基本的に机がなく、壁がフリーでした。
壁一面をホワイトボードして活用されているところも多かったので、僕の会社にはない感じだなと思いました。*2

物理での可視化は、

的な意味で良いなと思いました。
自社ではどのように実現するのか、物質的な問題は個人では解決が難しいなと悩ましいところだと思いました。

週の真ん中に振り返りをやる

スプリントレビューについてもKPTも週の真ん中にやるのが良いということでした。
理由としては、金曜日になると疲れも溜まって生産性が下がったり、ネガティブな意見が多くなったりするとのことです。
水曜午後1が一番のおすすめポイントらしく、なんとなくキリがいいというだけで週の最後にしていましたが、それだけで雰囲気が良くなるなら即採用なんじゃないかなと思いました。

まとめ

とりとめのないものになってしまいましたが、今回の見学では、「圧倒的な物理の可視化とその維持のノウハウがすごかった」、という印象でした。
組織にアジャイルの概念、プラクティス、そしてカイゼンの文化を導入しようとしたのは、上からのお達しだったらしいですが、それを受けて社員のみなさんがしっかり続けられていたのがすごいなと思いました。
真面目な人間性がそれを実現している、という話をされていまたが、それ以上に本当にカイゼンが必要だと思って、ちょっとつらくても明るく楽しそうにカイゼンしていく人がいたからこそなんだろうな、と思いました。

今回僕は非公式に個人としてでお邪魔させていただきましたが、ヴァル研では会社単位などでも公式に職場見学を受け入れておられるそうです。

お招きいただいたぷぽさんも、 DMにて、

何かを変えたいと思ったとき、特に組織的な事の場合はひとりでやるのはやっぱり厳しくって、仲間を見つけた方がいいです。今はいなくても、仲間にしたい人、なってくれそうな人。

そういう人と会社見学に来ると、また違ったものが得られると思います。(ということもあり、昼間に会社単位で見学、現場の生の声を聞いてもらってます)
(原文ママ)

というふうにおっしゃっていたので、検討してみてはいかがでしょうか? 実物見るとすごいと思います。

PR

ぷぽさんは僕がパーソナリティを務めているPodcastでもアジャイル関連の話をしていただいているので、よかったらそちらも聞いてみてください。

*1:cf. https://qiita.com/i35_267/items/1c2d75861b55c537f1e0

*2:バーンダウンチャートが物理になっているのはすごいなと思いました。

感想とメモ | WEBエンジニア勉強会 #5@ITプロパートナーズイベントスペース 20180202

OSCAさんの主催されているWEBエンジニア勉強会#5に参加してLTもしてきました。 その反省と他の方の発表の感想を書きます。

web-engineer-meetup.connpass.com

OSCAさんは僕がパーソナリティをしているしがないラジオでもゲスト出演されています。勉強会を主催しようと思った経緯なども話されているので、興味があれば聞いてみてください。

また、会の様子はtogetterにまとまっています。

togetter.com

参加者の構成

ノージャンルということもあって、おなじみとなっている、会の参加者の構成の発表がありました。*1

経験年数

年数 人数
0~1年 12人
1~3年 13人
3~5年 7人
5~10年 12人
10年~ 9人

仕事の分野

分野 人数
サーバーサイド・プログラマー 27人
サーバサイド・アプリ基盤エンジニア 11人
フロントエンドエンジニア 15人
フロントエンドデザイナー 12人
WEBディレクター/プロジェクトマネージャ 6人
インフラ・ネットワークエンジニア 7人
スマートフォンアプリエンジニア 3人
その他 8人

経験年数については、10年以上の人はまとめられてしまっていますが、短い人から長い人まで同程度の分布なのかなと思います。
分野については、サーバーサイドが最も多いですが、その他はまばらにいらっしゃるようでした。ただ、WEBエンジニア勉強会と銘打っているのでスマートフォンアプリエンジニアは少なかったのだな、という印象でした。

自分の発表

Redashの導入とチームをまたいだ変化の話

speakerdeck.com

最近、会社にRedashというOSSのデータ可視化ツールを導入しそこで変わったこと、良かったことを話しました。 内容は資料のとおりなのですが、反省としては次のようなことが挙げられたかなと思っています。

  • 具体例を上げてもう少し詳しくRedashについて紹介すべきだった
  • (時間的に巻いていたとはいえ)かなり早口で喋ってしまった

社内のものだったので具定例を多く書けなかったということもあるのですが、イメージを持っていただくためにももう少し時間があれば環境を作って、例示できれば最高だったなと思いました。

他の方の発表

HTTPレイヤーで行うパフォーマンスチューニング(@engineer_osca)

speakerdeck.com

主催であるOSCAさんの発表です。
これまで通り初心者向けのテーマを選びながらも、実際に動くところまでをデモされているのが素晴らしいです。
年末年始に自分の趣味のプロダクトで試してみた、というエピソードも話されてましたが、サンドボックス的に触れる自分のプロダクトを持つのはすごく良いなと思いました。

とにかく分かりづらいTwelve-Factor Appの解説を試みる(@suke_masa)

www.slideshare.net

僕は知らなかったのですが、クラウドで動くアプリケーションが従うべき12個のベストプラクティスというのがTwelve-Factor Appらしいです。
こういう宣言とか定義みたいなものは、一読してパッと理解できるものというよりは例があったり実際に困ったりしたことがないとわからなかったりするな~という印象です。
発表で、「こういうときありますよね?」「こういうときどうですか?」などと問いかけをしてくれると理解が深まるな、と思いました。

なにか作ったらプレスリリースを出そう(@binbin4649)

www.slideshare.net

サービスのPRをするための戦略を話してくださいました。
あまり聞いたことがない話で興味深く聞けたのと、最後に「PRバズーカ」というサービスのPRをされていて進め方がうまいな〜と思ったりしました。

Amazon Rekognitionを用いてフォロワーの男女比を出す(@kzkohashi)

speakerdeck.com

顔認識のAPIを利用した事例の紹介でした。
SNSのフォロワーをアイコンの顔認識で分析するというのは事例としてかなり面白いなと思いました。
またそういう画像認識APIの各クラウドサービス間の比較を行った話や、意外と安く使えるといった話まで、知ってはいつつも触れていない僕にはすごく興味深い発表でした!

Dockerを利用したローカル環境から本番環境までの構築設計(@kkoudev)

www.slideshare.net

Dockerについて利点や、なぜこうしたほうが良いのか、というのを丁寧に解説してくださいました!
Twelve-Factor Appの話と合わせて聞くと「なるほど~」感が強かったです。

非機能要件を考えてみよう!(@iwanaga0918)

昨今のセキュリティの問題やosushiさんの話*2も例に、非機能要件について、定量的にちゃんと考えていますか、という問いかけの話でした。
発表者の方が、SIerということで、IPA非機能要求グレードをチェックリストとしてやると良い、と言った話もされていました。
もちろんサービスごとにいろいろな側面がありそうですが、非機能要件がある程度定量的に指標化されてチェックリストになっているのは嬉しいんじゃないかなと思いました。

まとめ

WEBエンジニア勉強会は5回目ですが、僕は#1,2,3,5と参加していますが、大規模でなく2時間くらいの規模の勉強会で、テーマをあえて絞らず、幅広い分野の話が一気に聞ける勉強会はなかなかないので面白い試みだな、と思います。

主催者のOSCAさんが、いろんな人に発表されているので、暖かく迎えてくれている感もあって発表しやすい空気があったと思います。

コミュニティとしてもっと活発にしたい、という話もあったので、会のあとにその場でビアバッシュなどがあるともっと交流ができたりするのかなとも思ったりしました。

次回、4月初旬頃に1周年の会があるらしく、日程が合えば是非参加したいなと思いました。

*1:connpassのアンケート機能で調査されています。

*2:https://togetter.com/li/1195320

Eloquent ORMのChunkとCursorをメモリ使用量で比較した

前回書いた記事で、Eloquent ORMにおけるChunkとCursorメソッドの挙動について、発行されるSQL文の観点から調べました。

blog.zuckey17.org

そこで、まとめでも書きましたが、主にメモリ使用量を抑えるために使われるChunkとCursorのメソッドについて、実際にメモリ使用量を調べてみました。

メモリ使用量について、実際に計測してみようと思った

※ 僕自身、PHPのコードでメモリ使用量を意識したことはそこまでなく*1、どのように書けば特定の処理のメモリを調べることができるのか、というところから調べたのでその辺についても少し記載しています。

※ 本エントリで利用しているコードはすべて

github.com

にあります。

また、

  • PHP7.1
  • SQLite3

という環境で実行しています。

目次

PHPの最大メモリを変更する

100,000レコードものテーブルを全件取得しようとすると

PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 4096 bytes)

と言って怒られてしまいました。 まず、手元のmacPHPの設定を見にいきます。

$ php -i | grep php.ini
Configuration File (php.ini) Path => /usr/local/etc/php/7.1
Loaded Configuration File => /usr/local/etc/php/7.1/php.ini

$ cat /usr/local/etc/php/7.1/php.ini | grep memory_limit
memory_limit = 128M

ということで128Mということがわかりました。

常に変更するのは避けたいので、ファイルのはじめに

ini_set('memory_limit', '256M');

と変更を加えておきました。

データセットを用意

歩行者移動支援サービスに関するデータサイト

こちらを利用して、約100,000件のレコードを用意しました。

php-sandbox/migration.php at master · zuckeyM-17/php-sandbox · GitHub

メモリ使用量を測定するスクリプト

php-sandbox/check.php at master · zuckeyM-17/php-sandbox · GitHub

php-sandbox/check-memory-usage/src/scripts at master · zuckeyM-17/php-sandbox · GitHub

<?php

$capsule->getConnection()->enableQueryLog();

echo "CHECK MEMORY USAGE\n";
echo "==================\n";
$start = microtime(true);

// 処理

$time = microtime(true) - $start;
$memory = memory_get_peak_usage(true) / 1024 / 1024;
echo "\n==================\n";
printf("time: %f memory: %f MB" . "\n", $time, $memory);

$queryLog = $capsule->getConnection()->getQueryLog();
foreach ($queryLog as $i => $query) {
    echo 'Query' . ($i + 1) . ': ' . $query['query'] . PHP_EOL;
}

このようなスクリプトを書いて、処理にかかった時間、最大メモリ使用量、発行したクエリを出力しました。

結果

結果は以下のようになりました。

$ php check.php all
CHECK MEMORY USAGE
==================
縄文の宿まんてんル華耀亭や亭ザ・サンプラザート
==================
time: 1.418852 memory: 172.007812 MB
Query1: select * from "inns"
$ php check.php chunk10
CHECK MEMORY USAGE
==================
縄文の宿まんてんル華耀亭や亭ザ・サンプラザート
==================
time: 59.299147 memory: 10.000000 MB
Query1: select * from "inns" order by "inns"."id" asc limit 10 offset 0
Query2: select * from "inns" order by "inns"."id" asc limit 10 offset 10
...
Query9780: select * from "inns" order by "inns"."id" asc limit 10 offset 97790
Query9781: select * from "inns" order by "inns"."id" asc limit 10 offset 97800
$ php check.php chunk100
CHECK MEMORY USAGE
==================
縄文の宿まんてんル華耀亭や亭ザ・サンプラザート
==================
time: 9.412318 memory: 4.000000 MB
Query1: select * from "inns" order by "inns"."id" asc limit 100 offset 0
Query2: select * from "inns" order by "inns"."id" asc limit 100 offset 100
~~~~~
Query978: select * from "inns" order by "inns"."id" asc limit 100 offset 97700
Query979: select * from "inns" order by "inns"."id" asc limit 100 offset 97800
$ php check.php chunk1000
CHECK MEMORY USAGE
==================
縄文の宿まんてんル華耀亭や亭ザ・サンプラザート
==================
time: 1.720385 memory: 6.000000 MB
Query1: select * from "inns" order by "inns"."id" asc limit 1000 offset 0
Query2: select * from "inns" order by "inns"."id" asc limit 1000 offset 1000
~~~~
Query97: select * from "inns" order by "inns"."id" asc limit 1000 offset 96000
Query98: select * from "inns" order by "inns"."id" asc limit 1000 offset 97000
$ php check.php cursor
CHECK MEMORY USAGE
==================
縄文の宿まんてんル華耀亭や亭ザ・サンプラザート
==================
time: 1.620625 memory: 4.000000 MB
Query1: select * from "inns"
処理 経過時間(s) 最大メモリ使用量(MB) クエリ数
all 1.418852 172.007812 1
chunk、10件ごと 59.299147 10.000000 97790
chunk、100件ごと 9.412318 4.000000 979
chunk、1000件ごと 1.720385 6.000000 98
cursor 1.620625 6.000000 1

まとめ

前回のブログで、

1回のクエリでアクセスしている分cursorのほうが実行速度は速いものの、メモリの使用量を抑えるという意味では、あまりにも膨大な量のレコードを処理する場合にはcursorよりもchunkのほうが有用なのではないかと考えられると思います。

と書きました。 しかしながら、上記の表を見る限り、Chunk1000以上にするとCursorとでは速度、メモリ使用量でそれほどの違いがなかったという結果になりました。

また、実行速度はさておき、Chunk1000とCursorとでは、

  • 1回のループで作成するモデルインスタンスの数が違う
  • 1回のクエリで取得するレコードの数が違う

にも関わらず、メモリ使用量が同じ値になったのは疑問が残りました。 Cursorの仕組みについて、Eloquentの実装方法について調べて行く必要がありそうに感じました。

検証方法や考察について間違いなどがあればどんどん指摘して欲しいです!! また、こういうこと検証、試したら面白い、調べて欲しいなどがあればTwitterやコメントなどで言っていただければ嬉しいです!!

*1:Circle CIでのテストがメモリのせいで失敗した時くらい

Eloquent ORMのChunkとCursorについて調べた

前回書いた記事では、Eloquent ORMにおける参照系メソッドについて紹介しました。

blog.zuckey17.org

その中で、ChunkとCursorという項目について、

こちらについては、僕自信の理解が曖昧なため、もう少し調べる必要があると思います。 詳しく理解されている方がいらしたら、コメントで参考サイトなど教えていただきたいです。

と書いたところ

chunk, cursorは発行されるSQLを確認した方がいいと思います

というフィードバックをいただいたので、もう一度調べてみました。

※ 本エントリで利用しているコードはすべて

github.com

にあります。

目次

(もう一度)Chunk と Cursor

公式ドキュメント(和訳)によると以下のように書かれています。

ChunkとCursor

数1000行ものEloquentのレコードを処理する場合、chunkを利用します。chunkメソッドはEloquentのモデルを"塊"で取得し、それを引数として受け取ったクロージャに渡して処理をします。chunkメソッドを使うことによって、巨大なクエリ結果を扱うような処理において、メモリ使用量を防ぐことができます。 chunkメソッドの第1引数は取得する"塊"ごとのレコードの数です。第2引数として渡されるクロージャは、データベースから取得した塊ごとに呼ばれます。そのため、クロージャに"塊"を渡すたびに、毎度クエリが発行されます。

Cursorを使う

cursorメソッドはカーソルを利用して、ただ1回のクエリによってデータベースから取りだしたリストに対し1行ずつ処理を繰り返すことができます。大量のデータを処理する場合、cursorメソッドによってメモリ使用量をかなり削減することができます。

つまり、どちらのメソッドについても、大量のデータを取得する際にメモリ使用量を抑えるためのもののようです。

Eloquentで実際に発行されるSQL文を確認する

Eloquentではいくつか発行されるSQL文を調べる方法があります。

toSqlメソッド

最もシンプルな方法はtoSqlメソッドです。
getメソッドを呼ぶ代わりに、クエリビルダーのインスタンスに対してtoSqlメソッドを呼ぶことでSQL文を取得することができます。
例) php-sandbox/toSql.php at master · zuckeyM-17/php-sandbox · GitHub

<?php
$sql = Book::query()
    ->where('author', '=', '川原 礫')
    ->toSql();

echo 'Query: ' . $sql . PHP_EOL;

// Query: select * from "books" where "author" = ? and "books"."deleted_at" is null

結果から分かる通り、where句でauthorカラムが「川原 礫」さんで絞っていますが、出力されるSQL文の中では指定が?に変わっているのがわかると思います。 *1 これを回避できるのがもうひとつの方法です。

getQueryLogメソッド

もうひとつの方法は、getQueryLogメソッドです。1プロセスでこのメソッドが呼ばれるまでに実際に発行されたSQL文を出力することができます。
例)php-sandbox/getQueryLog.php at master · zuckeyM-17/php-sandbox · GitHub

<?php

$capsule->getConnection()->enableQueryLog();

$books = Book::query()
    ->where('author', '=', '川原 礫')
    ->get();

var_dump($capsule->getConnection()->getQueryLog());

/**
array(1) {
  [0]=>
  array(3) {
    ["query"]=>
    string(73) "select * from "books" where "author" = ? and "books"."deleted_at" is null"
    ["bindings"]=>
    array(1) {
      [0]=>
      string(12) "川原 礫"
    }
    ["time"]=>
    float(8.81)
  }
}
 */

getQueryLogメソッドは、事前にIlluminate\Database\Connectionクラスのインスタンスに対して、enableQueryLogメソッドを呼んでおく必要があります。
このIlluminate\Database\Connectionクラスは、Laravelフレームワーク内で利用している場合はDBファサード経由でアクセスができ、

DB::enableQueryLog()

と書くことができます。
本エントリではEloquentを単体で利用しているため、事前に用意したCapsuleインスタンスに対して、getConnectionメソッドを呼び、Illuminate\Database\Connectionインスタンスを取得しています。

※ またenableQueryLogをしてそのまま放置すると、そのプロセス中で呼ばれたクエリをすべて保持してしまうので、開発中無駄なSQL文の出力を避けるために、処理の最後にdisableQueryLogメソッドを呼ぶというように使うようです。

ChunkとCursorのSQLを比較する

Chunk

<?php
$capsule->getConnection()->enableQueryLog();

Book::chunk(2, function ($books) {
    foreach ($books as $book) {
        echo $book->name , "\n";
    }
});

$queryLog = $capsule->getConnection()->getQueryLog();

foreach ($queryLog as $i => $query) {
    echo 'Query' . ($i + 1) . ': ' . $query['query'] . PHP_EOL;
}

// Query1: select * from "books" where "books"."deleted_at" is null order by "books"."id" asc limit 2 offset 0
// Query2: select * from "books" where "books"."deleted_at" is null order by "books"."id" asc limit 2 offset 2
// Query3: select * from "books" where "books"."deleted_at" is null order by "books"."id" asc limit 2 offset 4

Cursor

<?php
$capsule->getConnection()->enableQueryLog();

foreach (Book::cursor() as $book) {
    echo $book->name , "\n";
}

$queryLog = $capsule->getConnection()->getQueryLog();

foreach ($queryLog as $i => $query) {
    echo 'Query' . ($i + 1) . ': ' . $query['query'] . PHP_EOL;
}

// Query1: select * from "books" where "books"."deleted_at" is null

ドキュメントの通り、chunkは第1引数に渡される数ごとにクエリを発行しており、cursorは1回のクエリ発行のみとなっているということがわかります。
また、chunkの場合は、クエリ発行を複数に分けるため、必ずORDER BY "PRIMARY_KEY" ASCを指定しています。

上記からわかることとしては、
1回のクエリでアクセスしている分cursorのほうが実行速度は速いものの、メモリの使用量を抑えるという意味では、あまりにも膨大な量のレコードを処理する場合にはcursorよりもchunkのほうが有用なのではないかと考えられると思います。

まとめ

  • Eloquentのchunkとcursorについてもう少し深く調べてみた
    • toSqlメソッドは知っていたが、getQueryLogメソッドによるSQL文の取得はより開発中に役立つと思った
    • ORMのSQL文生成の流れをもう少し深掘りしてみたくなった
    • メモリ使用量について、実際に計測してみようと思った*2

*1:Bookモデルはソフトデリートの設定をしているためdeleted_atカラムがnullのもののみを取り出すようなSQLとなっていることもわかります

*2:次回やります

Eloquent ORMについてなにも知らなかった(1) - 基本的な使い方編 -

先週に書いた記事で、Eloquent ORM(以下Eloquent)をライブラリとして導入する方法を書きました。

blog.zuckey17.org

この記事の中ではじめ、次のようなコードを書いてbooksテーブルについてBookクラスを作り全件を取得して表示しました。

<?php
// ダメなコードです

class Book extends Model {
    protected $table = 'books';

    protected $fillable = [
        'id',
        'isbn',
        'name',
        'author',
        'created',
        'updated',
    ];
}

===

$books = Book::all()->toArray();
foreach($books as $book) {
    echo $book['name'];
}

このコードは動いてはいましたが、2点の指摘をいただきました。

  1. toArrayするのはやめましょう
  2. table、fillableフィールドの指定はいりません。

非常にはずかしいことに、普段Laravelを書いて、Eloquentを使っているというのに知らないことがありすぎたので、本エントリではこれらの指摘とその他に調べた基本的だと思われることをまとめておきます。

以下で記載しているコードの省略なしは、

php-sandbox/basic-eloquent-usage at master · zuckeyM-17/php-sandbox · GitHub

にありますので、確認に使ってみてください。

指摘について

1. toArrayするのはやめましょう

eloquentのcollectionを利用するように変更 · zuckeyM-17/php-sandbox@029ad50 · GitHub

全件取得 ->表示するのは、以下のようにして書けます。

<?php

$books = Book::all();
foreach($books as $book) {
    echo $book->name;
}

Eloquentは、allgetのメソッドを利用するとCollectionクラスという便利なリストのインスタンスを戻してくれます。
例のようにforeachで回すと、単一のModelが取得できますし、Modelであれば、->でフィールドにアクセスできます。
toArray()を使うとそれらの恩恵に預かることができないので、ORMを使う旨味が激減します。

また、取得には、他にfindfirstlastなどのメソッドがあります。
それぞれプライマリキーで検索やlimitを書けているのですが、これらは単一のModelを取得することに利用します。

※ findの引数が配列になっている場合は、Collectionが戻ります。

2. table、fillableフィールドの指定はいりません。

不要なfillableとtableの記述を削除 · zuckeyM-17/php-sandbox@1e42688 · GitHub

tableフィールド

EloquentはActiveRecordパターンの実装*1 なので、1つのModelインスタンスは1テーブルの1レコードと完全に一致します。
そのため、テーブルの名前が複数形のスネークケースという慣例に則っていれば、EloquentはbooksBookモデルに紐付けるといったように、テーブルの指定を推測してくれます。

この他にも、connectionというフィールドも良く明示的に書いていましたが、DBが複数あるなどの特殊な場合を覗いてはDefaultの設定を見るため、指定する必要はありません。

fillableフィールド

fillableフィールドは悪意のあるユーザーがアプリが意図しない変更をDBに与えないように変更可能かどうかをカラム名ホワイトリストで縛るものです。

以下のようにfillableフィールドに指定した名前のカラムには、fill値を指定してレコードを作成することが可能です。
もし、指定されていたとしても、その値は無視されます。

<?php

class Book extends Model {
    protected $fillable = [
        'isbn',
        'name',
        'author',
    ];
}

===

$newBook = new Book();
$newBook->fill([
    'id' => 111, // 無視される
    'isbn' => '978-4-04-429201-0',
    'name' => '涼宮ハルヒの憂鬱',
    'author' => '谷川 流',
]);
$newBook->save();

同様の役割にguardedというフィールドが存在します。
こちらは、fillableとは逆でブラックリストです。変更されたくない値を明示的に指定することができます。

<?php

protected $guarded = [
    'created',  // createdをfillすることができない
];

その他の基本事項

ここから先は、指摘を受けてからその他に調べて、使ってはいたもののしっかりと理解していなかったり、知らなかったものなどについて紹介します。

ChunkとCursor

公式ドキュメントの以下の項目に記載のあったchunkメソッドとcursorメソッドですが、どちらも大量のデータを取得する際にメモリ使用量を抑える際に使うメソッドのようです。
https://laravel.com/docs/5.5/eloquent#chunking-results

ざっくりとした理解だと、

  • chunk => 複数回に分けてqueryを発行することにより、メモリ使用量を少なくする
  • cursor => カーソルによって1クエリで1行ずつデータを舐めることによりメモリ使用量を少なくする

こちらについては、僕自信の理解が曖昧なため、もう少し調べる必要があると思います。
詳しく理解されている方がいらしたら、コメントで参考サイトなど教えていただきたいです。

Chunk

<?php

Book::chunk(2, function ($books) { // 2冊ずつSQLを回す
    foreach ($books as $book) {
        echo $book->name , "\n";
    }
});

Cursor

<?php

foreach (Book::cursor() as $book) { // カーソルで1行ずつ処理をする
    echo $book->name , "\n";
}

上記どちらも、結果として全件の本のタイトルが表示されます。

Query Scope

クエリスコープはallgetメソッドを発行する際に、結果を絞り込むのに便利な機能です。

Global Scope

Global Scopeはその定義をそれぞれのModelのbootメソッド内にてaddGlobalScopeにて宣言すれば、すべてのクエリにて絞込みが利用できます。

<?php

use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class BookScope implements Scope
{
    public function apply(Builder $builder, Model $model)
    {
        $builder->where('id', '>', 2);
    }
}

===

class Book extends Model {
    ~~~
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope(new BookScope);
    }
    ~~~
}

===
$books = Book::all(); // idが2より大きい`Book`のCollectionを取得

また、addGlobalScopeで設定していても、

<?php

$books = Book::withoutGlobalScope(BookScope::class)->get();

とすると、絞込みを回避することもできます。

Anonymous Global Scope

こちらは、Scopeクラスを作らなくても、以下のようにbootメソッド内で絞込み条件を付け足すこともできます。

<?php

class Book extends Model {
    ~~~
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope('id', function (Builder $builder) {
            $builder->where('id', '>', 2);
        });
    }
    ~~~
}

Local Scope

Local Scopeは各Modelに定義します。 scopeというプレフィックスをつけてpublicなメソッドとして宣言し、クエリを引数に取って、決まった絞込みを利用できます。

<?php

class Book extends Model {
    ~~~
    public function scopeRecent($query) // scopeはプレフィックス、recent()というメソッドがqueryBuilderで使えるようになる
    {
        return $query->where('id', '>', 3);
    }
    ~~~
}

===
$books = Book::recent()->get(); // idが3より大きい`Book`のCollectionを取得

Dynamic Scope

Dynamic ScopeについてもLocal Scope同様各Modelに定義します。 Local Scopeの定義に引数を増やして、絞り込む値を利用時に入れることができます。

まとめ

  • 前回のブログについて指摘していただいた実装を見直し、調査しました
    • ブログを書くことで改善できてよかったです!
  • その他にもEloquentの知らなかった基本的な機能がたくさんあったので、まとめて、自分で書いてみました
    • まだ基本の「き」なのでこれからも少しずつ調べていこうと思います

次回はCollectionの様々な使い方、Eventあたりをやりたいです。

ピュアなPHPアプリケーションにLaravel標準ORMのEloquentを導入した

本エントリでは、ピュアなPHPで書かれたWebアプリケーションにLaravel標準のORMであるEloquentを導入した際にやったことを簡単にまとめています。

実施した際はPHP5.6でしたが、学習のためも含めて本エントリ内のソースコードはPHP7.2で動作させています。
経緯でも書かせていただいていますが、データベースはSQLite3を使っていますが、macOSで動かす場合にはすでにインストールされていると思うのでsqlite3 -versionで確認してから動かしてみてください。

経緯

事前に、Eloquentを導入するに至った経緯を簡単に説明しておきたいと思います。

SQLite3をデータソースにしたレガシーなプロジェクト

あるプロジェクトが素のPHPで書かれています。すべてのAPIがその1つのモノリシックなPHPアプリケーションとなっています。
ここで問題となっているのが、データベースとしてSQLite3を利用していることでした。
SQLite3はデータベースをファイルとして扱うため、

  • ファイルI/Oが遅くなる
  • サーバの分散ができない

という問題を抱えています。
また、行ロックではなくテーブルロックであるため書き込みが多いようなアプリケーションには向かない、という問題もありました。
嬉しいことに、サービスの成長によってサーバをスケールアウトできるようにしてリソースに余裕がほしいという要望が出てくることになりました。

Laravelへの移行は一朝一夕ではできない

ほかのプロジェクトではLaravelを利用しており、データベースは一部SQLite3を引き継いでいるものの、多くはMySQL(AWS Aurora)です。
ただ、前述のアプリケーションの大きさゆえに、Laravel + MySQLへの移行はすぐには難しく、まずは、MySQLへの移行をする準備として、Laravel標準のORMであるEloquentを既存のコードに入れていくという運びとなりました。

クライアントごとにSQLite3のファイルが異なる

また、管理していたSQLite3のファイルは複数存在しました。
グローバルな情報を扱うアプリケーションに唯一のデータベースと、クライアントにつき幾つか存在するデータベースがあり、リクエストの方法によって、クライアントごとに書き込みや参照をするデータベースを変えるということをしていました。
今回は、こちらの話には触れず、Eloquentの導入部分のみを書きます。
こちらの話も今後別記事として書きたいと思います。

やったこと

あとは淡々とやっていったこと、その際に調べたことを書きます。

※ 簡単な例を用意しました。
https://github.com/zuckeyM-17/php-sandbox/tree/master/use-eloquent-at-pure-php-app

4ステップでできます。

  1. PHPのバージョン管理ツールであるcomposerをインストール
  2. illuminate/databaseというパッケージをインストール
  3. illuminate/databaseの設定
  4. 必要なEloquentモデルを作成

1. PHPのバージョン管理ツールであるcomposerをインストール

$ cd ./src
$ curl -sS https://getcomposer.org/installer | php

用意した例では、環境を汚さないようcomposer.pharというファイルをsrcディレクトリ直下にダウンロードするという方法を取っています。

2. illuminate/databaseというパッケージをインストール

$ ./composer.phar require illuminate/database

ステップ1で用意したcomposer.pharを利用して illuminate/databaseというパッケージをインストールします。
Larvelを構成するライブラリはすべてgithubilluminateというところに所属します。
そこでdatabase部分を担当する、illuminate/databaseをインストールするわけです。

illuminate/databaseのREADME.mdの日本語訳が見当たらなかったので、和訳しました。

3. illuminate/databaseの設定

ほぼ、illuminate/databaseのREADMEを読めば簡単に作ることができます。
READMEではデータソースがMySQLだったため、例ではSQLiteで指定しました。
SQLiteで必要な項目は、ファイルへのパスのみなので簡単です。

<?php

use Illuminate\Database\Capsule\Manager as Capsule;

$capsule = new Capsule;

$capsule->addConnection([
    'driver'    => 'sqlite',
    'database'  => SRC_DIR . '/app.db',     // ここにSQLiteファイルへのパスを入れる
]);

$capsule->setAsGlobal();
$capsule->bootEloquent();

4. 必要なEloquentモデルを作成

illuminate\Database\Eloquent\Modelというクラスを継承したモデルクラスを作成します。
EloquentはActiveRecordの実装となっているため、Modelクラスはテーブルについて1つ作成し、Modelクラスに生えた便利なメソッドでテーブルにアクセスすることができます。
最低限な実装をすると以下のようになります。

<?php
require_once dirname(__FILE__).'/database.php';
use Illuminate\Database\Eloquent\Model;
class Book extends Model {}

これで、Bookモデルがアプリケーションで使えるようになりました。
以下ではBookの中身を取り出して表示しています。

<?php
define('SRC_DIR', dirname(__FILE__));

require_once(SRC_DIR . '/vendor/autoload.php');
require_once(SRC_DIR . '/database.php');
require_once(SRC_DIR. '/Book.php');

$books = Book::all();

foreach($books as $book) {
    echo $book->isbn, "\t" , $book->name, "\t", $book->author, "\t", $book->created, "\t", $book->updated, PHP_EOL;
}

まとめ

Eloquentをライブラリとして導入しました。
illuminate/databaseというパッケージを入れることで可能でした。
ただ、 illuminate/database単体では、マイグレーション周りをサポートしていないらしく、今回のユースケースでは既存のテーブルに対して行うということだったので、ただ純粋にEloquentをライブラリとして使うということを目的とすると、調査が甘かったようです。
EloquentのModelは便利なメソッドがたくさん生えているので、そちらについても今後紹介して行こうと思います。

また、illuminateなどOSSとしてのLaravelのプロジェクトについて少し知識がついたので、これからもう少しソースコードをしっかり追っていきたいなとも思いました。

間違っている部分、この施策についてのフィードバックなどありましたら、いただけると嬉しいです!

2017年を読んだ本とともに振り返る

僕が2017年の1年間で読んだ本をベースに一年を振り返ります。
書評メインではなく、あくまで個人的な振り返りになります。
が、基本的に駆け込みでざっと書いているため、まとまりの無い文章になっております。ご了承ください。
また以前、本ブログのTech系Podcast『しがないラジオ』をはじめて変わった5つのことというエントリにて、

パーソナリティの間でも議論し、積極的に本を読んでその報告をすることにしました。 結果、技術書を1ヶ月に2~3冊くらいのペースで読むようになりました。

と書いてしまったので、おそらく6月くらいだったとは思いますが、それ以降で実際に読めているのかを確認するためにもこれを書こうと思います。*1

振り返り、という名目なので、途中でやめてしまったものについても、言及します。

最後に、リンクはアフィリエイトリンクになっています。2018年の書籍購入の助けになれば本当に嬉しいので、もし興味をお持ちの本があればこちらから購入していただければ嬉しいです。

1月

はじめてのAndroidアプリ開発 第2版 Android Studio 2対応

Urban Data Challengeという地方自治体を中心とする団体が公開している公共データを活用してアイデアやサービス、プロダクトを作り、競い合うコンテストがあり、僕は友人たちと出場しました。
1月末のプロダクトの提出期限に向けてAndroidアプリを作成しました。Androidアプリは書いたことはなかったですが*2Javaは新卒の研修で3週間ほど学習したため、この本さえ読めば大丈夫なのでは、という話になり年末年始を使って読みました。

できたアプリはこちらです。 histleap -タイムリープ型観光アプリ- 1次審査であえなく敗退したため、このアプリについての詳細は省きますが、Androidアプリを初めて作ってリリースできたのは良い経験だったと思います。 また、

をしっかりめに追うことができたのでそれも良かったです。

この本については、ページ数もある程度ありますが、コード例が豊富にあってAndroidアプリについて順を追って解説してくれているので分かりやすかったのではないかなと思います。
完全に初心者向けのため、少し冗長で簡単なのでは?という部分もあるので、少しでも触ったことがある方はつまらないと感じられるかもしれません。

2月

JavaScriptで学ぶ関数型プログラミング

2月時点で業務ではReactを利用したフロントエンド開発を全体の半分ほどの割合で担当していました。
もう少しJavaScriptについて詳しくなりたいと漠然と思っていた僕は会社の本棚にあったこの本を手に取りました。

第一級関数や高階関数という言葉の存在すら知らなかった僕には、この本はかなり難しいものだったように思います。
実際今何がかいてあったかを詳細に思い出そうにも思い出せない程度には理解できなかったので、もう一度読んでみるのもありかもしれません。

3月

Reactビギナーズガイド ―コンポーネントベースのフロントエンド開発入門

前述の通り、Reactを業務で書いており、2月初旬にできた未経験エンジニアの後輩がReactをやる、ということだったのでこの本を会社に買ってもらって先に読んでおきました。
簡単な表アプリを作ったりするので、Reactの概要をつかむには良い本でしたが、JSXを使わずにcreateClassを使ったりとすでに古い記述がありました。
この辺の本をやってようやく、"React周りのみについては"少しはできるようになったんだなという自覚を得ることができました。

ちょうどこの本は僕が2017年最もお世話になった勉強会であるWe Are JavaScripters!さんのもくもく会に参加した日に発売され、Reactの話をその場でしたことも相まって3月末の人生初LT登壇につながりました。

Reactつながりでいうと、その他にも、React Nativeを、同じくしがないラジオのパーソナリティであるid:jumpei_ikegamiと学習し、錯視を利用した簡単なアプリを作成しました。
React Nativeについては、5月くらいに勉強会にも参加しましたが、書いたのはこれきりでした。 ReactのLearn Once Write Anywhereを実感できたという点で良かったなと思います。

そして3月はPodcastしがないラジオを始めた月でもありました。

4月

なぜ、この人と話をすると楽になるのか

この時期、外部連携などの仕様を詰めたりと他のビジネスサイドの方々と話をする機会が増えてきていました。
前職では、部門や会社をまたいだコミュニケーションが多かったにも関わらず、エンジニアとしてコードを書く、ものを作るようになった自分は、ビジネスサイドの方々とうまく話せない、という問題に当たりました。
そこでとりあえず尊敬するラジオパーソナリティの1人である日本放送アナウンサー吉田尚記さんのこの本を手に取りました。
実際、この本の中では、雑談をある種のゲームと考えて、自分を捨てて話すということが書かれており、確かに普段あまり関わりのない他部署の方と、業務外で話す際に相手が気分が良くなるような話し方をすることは、仕事上重要なコミュニケーションを円滑に回す上で必要なことで、そのコミュニケーションをルールのあるゲームという風に考えてしまうと、ゲームを攻略するために動いてコミュニケーションを成功させる、ということはできるのではないかな、と思いました。
これは現在もまだまだ完全に実行できてはいませんが、これからも意識することになるだろうと思います。
しがないラジオでも、ep.7 楽しい雑談で紹介しているので、ぜひ聞いていただければと思います。

これと同時期に仕事ができる人はなぜモチベーションにこだわらないのかを購入しました。
こちらは半分程度しか読めていないのですが、この購入履歴を見た母*3から「大丈夫か?元気にしているか?」と電話がかかってきたのを覚えています。

Electronではじめるアプリ開発 ~JavaScript/HTML/CSSでデスクトップアプリを作ろう

Reactをやっているということもあって、業務の幅が何か広がるのではないかと思い、購入して読みました。
この本はElectronの本と書かれていますが、Reactの小さな良いサンプルが詰まっている本と考えたほうが良いでしょう。
Electronについても書かれていますが、あくまで入門書で、多くは書かれておらず、何かプロダクトで作ろうという際には公式ドキュメントなどを読む必要があります。
この本を読んで簡単な社内ツールを作ってみました。
Electronは、普段フロントエンドをやっているならば、簡単にGUIを作れるので、ビジネスサイドに感謝されるツールを短期間で作るのにはちょうど良いかなと思います。

5月

10年戦えるデータ分析入門 SQLを武器にデータ活用時代を生き抜く

ゴールデンウィークに読みました。
普段はPHPのEloquentというORMを利用して簡単なクエリを発行していたり、Sequel Proを用いてMySQLに対してクエリを実行したりしています。
サーバーサイドを書いているならSQLくらいまともに書けない*4といけないだろうということで、評価の高かったこの本を読みました。
巷では「10年本」と言われているようです。
本の概要としては、対象読者はリテラシー高めなビジネスサイドから初級アプリケーションエンジニアなどで、分析の話に絡めて参照系のクエリの基礎から応用までを紹介しているという感じです。
「この商品買った人はこれ買いがち、みたいな分析とかやりたいよね?こんな感じで書くんだよ。さっき紹介したこれとこれを組み合わせて」みたいな感じでかかれていてどういうタイミングで使うのか、を意識して学習することができるので、かなり良かったと思っています。
PosgreSQLを対象に書かれていますが、途中のウインドウ関数以外は、MySQLでもほとんど問題なく使える内容だと思います。
この本を読んで、SQLチョットカケルくらいには成長したと思います。

Fearless Change アジャイルに効く アイデアを組織に広めるための48のパターン

5月10日にあったReact反省会にてサイボウズの方がReactを導入するのを会社に広めるという話で紹介されていたのがきっかけで知りました。
僕もエンジニア歴の浅い人間がエンジニア組織、ひいては会社に対してどうやって影響力を持っていくかについて考えないことはなかったので、読みました。
ダラダラと読んでしまったので、結局1ヶ月時半くらいかかってしまいました。
何かを組織に導入するときに必要な48のパターンがエピソードと共に紹介されています。
1つ1つが当たり前のようで実践しきれないことが書かれていていい本だと思いました。*5
常に意識することはなかなか難しいなと感じましたが、時々、今のあの本のアレじゃね?というと気があると嬉しいです。
部内でのKPTのときに一度実践したのですが*6、「何か食べながら」というパターンはすぐに使えておすすめです。
僕がよく聞くPodcastである #omoiyarifmでもコーナーとして、各パターンを紹介されています。

6月

成功するシステム開発は裁判に学べ! ~契約・要件定義・検収・下請け・著作権・情報漏えいで失敗しないためのハンドブック

プロジェクトの失敗はだれのせい? ~紛争解決特別法務室“トッポ―”中林麻衣の事件簿

対個社の仕事はこの時期も続いており、かなり大きなクライアントの仕事が入る気がしたので、契約について学びました。
「あまり受託開発的な仕事をしたくないな〜」と思って事業会社に入ったのでこういうことに手をだすとは思っていませんでしたが、契約とか法律についてよりも、結局は顧客とよく話して良いものを作る、何か不具合があったときは迅速に誠意を持って対応することが重要、ということがどちらの書籍にも書いてあり、そうだよなあと思うと同時に事業会社にいるエンジニアはそのあたりを少し忘れてしまうこともあるかもなという反省があったことが一番良かったと思います。
しがないラジオでも、ep.15 楽しいエンジニアのIT契約入門で紹介しているので、ぜひ聞いていただければと思います。

エラスティックリーダーシップ ―自己組織化チームの育て方

この本は途中で読むのをやめてしまいました。 このブログでもまとめを書いたまつもとゆきひろさんの"若手エンジニアの生存戦略"という勉強会で紹介されていたので購入しました。
雑な感想とメモ【まつもとゆきひろ氏特別公演】若手エンジニアの生存戦略 @DRECOM #colab_matz 20170520

まえがきにもある通り、序盤でざっくりとしたこの本の考えが書かれており、それを読んで少し進んだところで脱落してしまいました。
その後は第6部にて、日本人の有名エンジニアによるエッセイが紹介されているので、時々つまみ食いする、という感じで楽しんでいます。

サバイバルフェーズ、学習フェーズ、自己組織化フェーズ、などチームの状態を言語化して述べてくれていて、そういう考え方はいいなと思いました。
リーダーだけでなく、チームのメンバーもそのチームの状態によって振る舞いを変える必要があるんだなと思うと同時に、それができるのはかなりモチベーション高く、実力がある水準以上で周りで起こっていることが俯瞰できている状態だけなんだろうな、とも思いました。

ZERO BUGS シリコンバレープログラマの教え

こちらの本も2割くらいで読むのが止まってしまいました。
エンジニアとしての様々な心構えが書かれた本、ということで読まなくてはと思い購入したのですが、例えがよくわからなかったのか、語り口が合わなかったのか、あまり面白くなくやめてしまいました。
すべて読んでいないので、なんとも言えませんが、リーダブルコードなどを読むので十分では?と思いました。

5、6月のブログ活動について

5、6月では、自分が参加した勉強会について、まとめと感想をなるべく早く書いてブログにするということを数回しました。
やっていると、公開するのが早ければ早いほどリツイートしていただくことも多く、それだけで承認欲求が満たされるような気持ちになりましたが、メモを取ることに必死になって重要なことを聴き逃しているような気がすることと、あとで公開してくださるスライドのコピーを取ることにあまり意味を見いだせずブログの内容も薄くなってしまうと思ったのでやめることにしました。

7月

食べる!SSL! ―HTTPS環境構築から始めるSSL入門

SSL?なにそれ美味しいの?という状態だったので、読みました。美味しかったと思います。
会社の先輩と話をしていたとき僕がちんぷんかんぷんなことを言い出したときにこれを勧めてくださいました。
amazonのレビューにもある通り、初学者には非常に読みやすく簡単にSSLのことを解説してくれています。
安いですし、分量も多くないので良かったと思います。

サーバーレスシングルページアプリケーション ―S3、AWS Lambda、API Gateway、DynamoDB、Cognitoで構築するスケーラブルなWebサービス

こちらのcommpassで公開されていた書籍プレゼント企画にて見事当選したので、読んで、しがないラジオでフィードバックしました。(ep.19 楽しいSPAとサーバーレス)
サーバレス、SPAというトレンドをおさえていて、2017年多く売れた技術書の1冊だと思います。
ピュアなjQueryで画面を作りつつ、Jasmineでテストを書きつつ、AWSのサーバレスなサービスを理解しつつと、1冊で多くのことを学べる本でした。
業務でフロントエンドの開発をしているとはいえ、ES6で書いたReact.jsしか経験がなかったため、jQueryで1からSPAを構築していく、さらにJasmineでUIのテストも書く、というのは面白く読み進めることができました。
また、AWSのいろいろな機能を簡単に使うというところで、ざっくりとした概要をつかめたことも良かったです。

またポッドキャストの中での発言を監修されている方に取り上げていただきました。

特にポッドキャストでは「雑にアウトプットする」というのを意識的にやっていますが、それによって良い学びが得られた素晴らしい体験だったと思います。

8月

Guide to ScalaーScalaプログラミング入門

社内で、PHPで書かれているサーバーサイドを徐々にScalaに移行したいという話が、2017年の年始より出ていました。
年始から主要なメンバーの転職もあって難しかったのですが、そろそろ本格的に考えるか、となったのでこちらの本を読みました。
Scalaといえば、コップ本がバイブルとして有名ですが、まず初心者が簡単に触る分にはこちらの本は分量的にも値段的にもちょうど良かったように思います。
ざっと書きつつ読みましたが、結局2018年1月現在で社内のScalaのプロダクトコードは1行もなく、PHP5.6 => PHP7.2移行を進めよう、という段階なので違うパラダイムの言語の学習ができてよかった、くらいの気持ちでいます。

ダークサイド・スキル 本当に戦えるリーダーになる7つの裏技

4月に「なぜ、この人と話をすると楽になるのか」を読んでから、コミュニケーションに対してある種ドライなスタンスの取れる、"清濁併せ呑める"ような人間になりたいとぼんやり思っていて、この本がamazonで目に入ったので購入しました。
ただ、この本はある程度大企業の中間管理職、30代後半から40代をターゲットに書かれた本のようで、組織をまたいだ人脈の作り方、チーム運営時の判断の方法論などが書かれており自分が求めているものと少し違うな、というふうに感じて6割くらい読んだところで脱落してしまいました。

9月

ザ・コーチ

こちらの本は、しがないラジオのep.20 楽しい!?目標設定のエピソードに対して、リスナーのid:tbpgr さんがフィードバックとして紹介してくださった本でした。
はじめは、会社の目標設定が難しいということを話していましたが、自分のエンジニアとしての目標にも話が広がりました。
この本は目標、目的、夢、ビジョン、ゴールといった、違いが曖昧な言葉たちについての詳細な説明から始まり、それらを決めていく過程、決めてから実行する過程を小説ベースで読者に伝える自己啓発本です。
読んだ感想などをep.25 楽しいエンジニアがマネージャーをやる理由で話しています。

2017年は、インプットもアウトプットもそのときどきの流れで無計画に行ってきましたが、より大まかな進みたい方向をしっかり決めていきたいと思っています。
本当にそんなことできるのだろうか、と思ったりしますが、確かに周りにできている人はかなりいます。
2018年はよりそれをより明確に描けるようにして、第1歩が踏み出せれば良いかなと思います。

わかばちゃんと学ぶ Webサイト制作の基本

LT loversというイベントで知り合い、そこからしがないラジオでもゲスト出演していただいている湊川あい(Twitter @llminatoll)さんの本です。
普段からエンジニアとして仕事をしているので対象読者ではありませんでしたが、出演してくださるということで予習として読みました。
Webサイトを制作、運用するための必要な知識がマンガでわかりやすくまとめられていて、初心者の方が概要をつかむにはすごくいい本だと思いました。
特に、文字でわかりづらいポイントを絵で理解できること。ただ単に作るというだけでなく何のために作るのかを考えることが必要だ、と説明してくれていること。が非常に良いなと思いました。

どのような思いを持って書かれたか、著者の湊川あいさんがどのような人柄なのかについては、

で語られています。

10月

わかばちゃんと学ぶ Git使い方入門〈GitHub、Bitbucket、SourceTree〉

こちらも湊川あいさんの本で、Gitの初心者のための本でした。僕は普段からGitである程度のことは自分で調べつつできていたため、対象の読者かというとそうでもないかなという感じでした。
しかし、この頃、社内のデザイナーの方がHTML、CSS、JSなどのコーディングもチャレンジするということで、フロントエンドを担当していた僕がGitについての質問を受けるが多くなっており、この書籍を購入し、その方に読んでもらうことにしました。
すると、瞬く間にある程度のことは1人で問題なくこなせるようになっていました。
僕も経験がありますが、Gitは少ししか触っていないとオーバースペックに感じることがあったり、概念的に字面だけではわかりづらい部分があったりするためマンガというアプローチはすごくいいなと思いました。
すすめるにあたり僕も読みましたが、rebaseなど、必要なときに調べ、理解もそこそこに忘れてしまうことなどがあったので、これ一冊で業務で使えるレベルになる良い入門書だなと思いました。

テスト駆動開発

普段聞いているPodcastである#ajitofmのAjitofm 6: Worse Is Betterajitofm 13: Test Driven Developmentにて訳者のid:t_wadaさんを交えて紹介されており、それを聞いて読みました。
それまで、ユニットテストはなんとなく書いていましたが、実際それが意味のあるものなのかわかりませんでしたし、それによって救われたなということも特になく、よくわかっていませんでした。そういうことへの理解が深まるのだろうなと思って読みました。
しかし、この書籍を読んでから理解ができたのは、ユニットテストが意味のあるものなのか、とか、テストによって変更を加えた際のミスに気づいて救われた、などはテスト駆動開発の目的とは違うのだということでした。
僕の理解ではテスト駆動開発で重要なのは、機能追加の前にテストを書いて、追加する機能について考察し理解し設計する、ということなのだと思いました。
そういう意味で、僕の当初の期待はうまく満たされませんでしたが、 id:t_wada さんの推奨する写経の方法をいい感じに実践できたりすることができ、楽しく読み切ることができました。

この辺の話は、ep.28 楽しい『新訳版・テスト駆動開発』の読み方でも話しています。

11月

Java言語で学ぶデザインパターン入門

しがないラジオでは10~12月とゲスト回が続き、多くの方がこの書籍を紹介されていました。
業務などでも「デザインパターンでいうアレだよ」、みたいな会話があり、読むとより実のある議論ができるのではないかと、購入し読みました。
はじめの3章は、前述の通りの写経をしたのですが、他の本も読みたいなということで、それ以降はざっと読むことをしました。
すでに読んだことのあった同僚と話すときに意識して「ファクトリーで」などと会話してみることでパターン・ランゲージの強さを認識することができました。

nginx実践入門 (WEB+DB PRESS plus)

業務でnginxを触る必要ができたので急ぎ購入しざっと読みました。前半特にリファレンス的な要素が強買ったため、あっさりと読み、触りつつわからなければ参照するという読み方をしました。
nginxについてまとまりがって読みやすい日本語の本はこちらくらいなんじゃないかなと思います。
今まではすでにあったnginxの設定を見てもわけがわからず、そのあたりで何か不具合があっても手も足も出ないという感じだったのですが、読めるようになり、怖さがなくなったのが良かったです。
業務では、アプリケーションの状態によってリクエスト先のサーバを変えるという処理を今回の実装でnginxの役割として実装しました。
その部分がnginxでやるべきことなのか、アプリケーション側でやるべきことなのか、ということが未だによくわかっておらず、そのへんも今後学習していきたいです。*7

Chef実践入門 ~コードによるインフラ構成の自動化 (WEB+DB PRESS plus)

こちらも、上記のnginxと同様に必要に迫られたので会社の本棚から借りて読みました。
しかしながら、元あったChefのコードをベースに書いたため、公式サイトで事足り、導入部分のみ読みました。

まとめ

12月はふつうのLinuxプログラミング 第2版 Linuxの仕組みから学べるgccプログラミングの王道を読み始めましたが、いろいろあって、全く進めることができませんでした。
1月上旬でとりあえず読みたいです。

これまでざっくり2017年に読んだ本を振り返りました。
インプット量は思っていたよりも少なく、少しがっかりしました。
また、学んだことについて思いのほか忘れていることが多く、Podcastだけでなく、文字でも一冊一冊でまとめておこうと思いました。 振り返りは、途中でも書きましたが、以下に尽きるのかなと思います。

2017年は、インプットもアウトプットもそのときどきの流れで無計画に行ってきましたが、より大まかな進みたい方向をしっかり決めていきたいと思っています。 本当にそんなことできるのだろうか、と思ったりしますが、確かに周りにできている人はかなりいます。 2018年はよりそれをより明確に描けるようにして、第1歩が踏み出せれば良いかなと思います。

とりあえずまとめたので、もしかすると読み返して追記するかもしれないです。

*1:この言及はかなり微妙で、技術書以外を含めても振り返るとそこまで読んでませんでした。すごい、とおっしゃっていただいた方が何人かおられたのに本当に申し訳ないです。

*2:というかその当時Android端末を持ってすらいませんでしたが

*3:母は僕が昔使っていたkindle保有しているので僕が買った本は全て知っている

*4:いや~な苦手意識、ありますよね?

*5:いい本はそういうのが散らばりがちじゃないですか?

*6:続いていないです

*7:今回はもろもろの事情によりアプリケーションに手を入れないでなんとかするという制限がありました。