中の人について
スタバでドヤ顔している人を見るとMacを叩き割りたくなるaikawameです。ごきげんよう。
はじめに
所謂ブログというやつの最初の記事に自己紹介とか痛すぎないかと思ったけれども、意外と色々なブログを巡ってみても自己紹介記事のあるブログが余り見当たらなかったので、逆に書いてみたくなった。
年齢
昭和57年(1982年)生まれ。PC-98誕生の1ヶ月後に生を受ける。
住んでいる所
東京都新宿区、歌舞伎町の銃声が聞こえてくるくらいの所。
主に住んでいた所
- 三重県鈴鹿市、サーキットのF1レースが聞こえてくるくらいの所。生誕から高校まで。
- 滋賀県彦根市、夏になると彦根城のお堀が臭ってくるくらいの所。大学の4年間。
- 滋賀県大津市、「中二病でも恋がしたい!」の主人公自宅の近所。仕事で3年ほど。
言葉
伊勢弁と近江弁のごった煮。
京滋圏の人からは名古屋人と思われ、それ以外からは京都人と思われやすい。東京弁には意地でも染まらない。
仕事
ウェブ系のエンジニア。サーバーサイドを中心に、インフラやフロントもぼちぼち。
- 2005年から新卒でSIerに入るも、すぐに辞める。
- 2007年から携帯電話向けのサービス開発に携わる。
- 2010年からソーシャルゲームの開発に携わる。
- 2017年から普通のウェブ系スタートアップへ。
好き
プログラミング、鉄道、社寺巡礼、アニメ、音楽、ソニー
嫌い
チャラい系、煙草、現金決済、カタカナ語、運動、Apple
性格
見た目は紳士、中身は中二。決して厨二ではない(ここ重要)。
普段は口外しないが、大抵は「俺はあいつらとは違う」みたいなことを考えている。「中二病でも恋がしたい!」については、「厨二病でも恋がしたい!」に改名すべきだと壁に向かって言い続けているが、なかなか聞き入れてもらえない。
コミュ障と言うと意外な顔をされるが、大のコミュ障。
中学に入るまでは担任の教師ともまともに話せなかった。大人になってから一般人に擬態することを覚え、仕事でマネージャー的な立場だったような時期もあるが、本当は人よりもPCとキャッキャウフフしていたい。
なぜブログを始めたのか
一番の理由はタイトルにもある年齢。「エンジニア35歳定年説」なるものも囁かれる中で、寄る年波に抗うおっさんエンジニアの生態について書き綴っていくのは、それなりに意味のあることではないかと思ったため。
ちなみに、ブログを書こうと思ったことは何度かあった。ただ、文章を書くのは割と好きなのだが、凝り性なのでついつい時間を掛けてしまい、これでは続かない、と最初の記事も公開せずに投げ出してしまうことの繰り返しだった。
そんな事情もあり、とにかくその時々に思った内容をあっさりと書いていくことを念頭に、無理せず続けていければと思っている。ちなみに、大晦日に最初の記事を公開したのは、年明けだと在り来りだからに決まっている。皆まで言わせるな。
これからのこと
僕は健康でいられる限りはエンジニアという人種であろうと思っている。また、生涯中二病なのも変わらないと思っている。その辺りを軸に、僕の興味対象となる技術や時事ネタ、鉄道・社寺巡礼など趣味の話をつらつらと綴っていきたいと思う。
Mac使い向けのはかどるGUIツール10選
自分の使っているツールが会社のメンバーに意外と知られていなかったので、紹介してみたら好評だった。そこでこちらでも紹介してみることにした。
Alfred
- マカーな開発者にはお馴染みのイケてるランチャー
- むしろ使っていない人を知りたい
- さらにはかどるWorkflowの使えるPowerpackは£19~
Stay
- ウィンドウ位置記憶ツール(有料)
- アプリ毎やウィンドウ毎に、位置とサイズを覚えてくれる
- デュアルディスプレイ時と通常時で別々に記憶してくれる!
- ノートPCでデュアルディスプレイするなら必須かも
- 公式サイトかApp Storeから約$18で買える
HyperSwitch
- ウィンドウ切り替えツール
- Cmd+Tabのすごい版
- Windowsのようにウィンドウ単位で切り替えられる!
iTerm2
- 痒いところに手が届くターミナル
- フォントとか色とか変えて、自分好みに
- キーバインドも弄れる
Sequel Pro
- GUIのMySQLクライアント
- これに慣れるとphpMyAdminが苦痛でしかなくなる…
Tower
- GUIのGitツール(有料)
- リビジョングラフが直感的に追いやすい
- 指定したブランチから見たグラフを追える
- コミットログのインクリメンタルサーチ
- 個人的にはSourceTreeよりもかなり使いやすい
- ¥7,499/年と若干お高め
- リビジョングラフが直感的に追いやすい
Paw
- 高機能なRESTクライアント(有料)
- 変数を設定して、モック・開発・本番等の環境を切り替えられる
- GUIがかなりイケてて入力しやすい
- API Blueprintからインポートできる(若干微妙だが…)
- お値段は$49.99
Insomnia
- 高機能なRESTクライアント、しかも無料
- GUIの使い勝手はPawより落ちるが、大体同じことができる
IntelliJ IDEA
- Android Studio開発元によるIDE(有料サブスクリプション)
- 言語毎に特化したIDEが用意されている
- Eclipseよりかなり軽い
- NetBeansよりかなりカスタマイズ性が高い
- お値段は高めだが個人ライセンスで仕事にも使えるので、趣味と仕事で併用するエンジニアも
OmniFocus
- GTD(すごいToDo管理)ツール(有料)
- 脳内にしか無い「やるべきこと・気になることリスト」をゼロに!
- GTDはそれだけで勉強会を開けるくらい奥が深い…
- 公式サイトかApp Storeで約$40で買える
おわりに
開発が滞っているものの、代替ソフトが見つかっていないというツールもあるので、オススメがあればぜひ教えてほしい。ちなみに、エディターについては宗教戦争になるので書かないでおくが、VimかEmacsの二択を迫られたらEmacsである。
OpenShift難民が自分用PaaSを作った話
個人ウェブサービスをOpenShift v2で無料運用していたのだが、残念ながら2017年9月でサービス終了の運びとなった。v3やHerokuではコスト的に複数サービスを回すのが辛いので、これを機会に自前のPaaSを構築することにした。
やりたいこと
- 小規模な個人サービス4つを¥1,000/月以内で運用
- うち1つはRails+MySQL、1つはPHP+MySQL、残りはPHPのみ
git push
でデプロイ(OpenShift v2やHerokuと同様に)
IDCFクラウドでDokkuなら楽勝のはずが
条件に合う事例として、次の記事がすぐに見つかった。
IDCFクラウドの最小構成は¥500/月で安いし、DokkuはミニHerokuとして使えそうだ。この記事はIDCF公式のBlogでも紹介されていたこともあり、そのまま従っていけば楽勝だろうと高をくくっていた…のだが。
確かにDokkuの公式ドキュメントとこの記事を参考にしてスムーズにappを構築していけたのだが、3サービス目のappを立ち上げた所でストレージの空きが0%になってしまった。
何が問題だったのか
DokkuはHerokuと同様に、コンテナ管理にはDockerを使用している。そのベースイメージとしてherokuishを利用しているのだが、これが曲者で、なんとイメージサイズが1.35GBもあった。MySQLのイメージも400MB近いし、加えて色々な実験をするうちに15GBのストレージを全て食ったようだ。
なお、現状のherokuishはHerokuのイメージであるcedar-14をベースとしているが、最新のheroku-16では465 MBまでスリム化されているようだ。とはいえ、Dokkuでいつ採用されるかは不明であるし、採用されたとしてもDockerイメージとしてはまだ巨大なため、別のやり方を検討することにした。
どのように解決したか
Dokkuの公式ドキュメントにDockerfile Deploymentとあるように、自前のDockerfileもデプロイに使えるということで、試してみることにした。
今回はストレージを食わない事を優先したかったのと、複数コンテナの連携をうまくDokkuで実現できるのかという懸念があったため、邪道とは思いつつもPHP-FPMとnginxを同一コンテナで立ち上げる最小限のイメージを作ることにした。以下がそのDockerfileの内容である。
FROM php:7.1-fpm-alpine RUN curl -sS https://getcomposer.org/installer | php \ && mv composer.phar /usr/local/bin/composer \ && docker-php-ext-install \ mbstring \ pdo_mysql \ && apk add --update --no-cache \ nginx \ && mkdir -p /run/nginx \ && echo -e "#!/bin/sh\nphp-fpm -D\nnginx -g 'daemon off;'" \ > /usr/local/bin/php-nginx \ && chmod +x /usr/local/bin/php-nginx EXPOSE 80 CMD ["php-nginx"]
Alpine Linuxにしたこともあって、イメージサイズは70MBほどに収まった。なお、一応イメージはDocker Hubにも公開している。
このイメージをベースに(Railsのサービスについては既存イメージを使用)各appを構築したところ、特にハマる事も無くDokku上に展開できた。気になるストレージの使用率は35%程度で落ち着いている。メモリーの使用率が80%近くなってはいるが、こちらはswapを1GB確保しているのでひとまずは問題無いだろう。
おわりに
安価なクラウドやVPSで自前PaaSを構築する事例は多々あり、いずれもメモリーを確保する事に注意を促しているが、実際に複数サービスを運用するとなると、留意すべきはむしろストレージの方であった。
Dokkuの場合、自前のDockerfileも使えるため、スリムなイメージを用意すればストレージの小さい環境でも複数サービスを運用できそうである。小規模な個人サービスを複数運用しているのであれば検討しても良いかもしれない。
Ansibleでカーネルチューニング
LinuxのカーネルパラメーターやPAM limitsの設定は、大規模なサービスで抜けが発生すると大変な事になるので、Ansibleで一気に適用してしまいたい。最近のバージョンではどちらも専用のモジュールが用意されているため、備忘録がてら記載しておく。
カーネルパラメーター
sysctlモジュールを使用する事で、/etc/sysctl.conf
を編集できる。
デフォルトで設定は即時反映される。
- sysctl: name: "{{ item.name }}" value: "{{ item.value }}" state: present ignoreerrors: yes with_items: - name: net.core.somaxconn value: 8192 - name: fs.file-max value: 5242880
PAM limits
pam_limitsモジュールを使用する事で、/etc/security/limits.conf
を編集できる。
なお、PAM認証を介さない制限には当然ながら使えないので、nginx等のdaemonの制限は別途行う必要がある事を忘れずにおきたい。
- pam_limits: domain: "{{ item.domain }}" limit_type: "{{ item.limit_type }}" limit_item: nofile value: 655360 with_items: - domain: root limit_type: soft - domain: root limit_type: hard - domain: "*" limit_type: soft - domain: "*" limit_type: hard
GDの画像圧縮率と処理速度
よくPHPのGDは重いと言われるが、重い中でも圧縮率の設定次第で大きくパフォーマンスが変わるという落とし穴にハマってしまったので、備忘録がてら綴っておきたい。
何が起こったのか
- 商用サービスにおいて、アバターの合成・圧縮処理にGDの
imagepng()
関数を使用していた。 - 元々はデフォルトの圧縮率
6
だったのだが、ストレージの都合上アバターのサイズを抑えるため、圧縮率を最高の9
に上げる事になった。 - その後、アバター合成に使用しているサーバーの高負荷状態が頻発するようになったが、先の変更時には他にも各所変更が行われており、かつ時間も経過していたため、原因に気付けなかった。
どのように解決したか
- 前置きすると、僕は高負荷状態が頻発するようになった後でサポートに入ったため、今回の問題は単にユーザー増加による負荷上昇だと認識していた。
- 元々は画像合成専用のサーバーを新しく構築する方針だったが、GDの設定変更や他の画像処理エンジンを使う事で改善できないかと片手間で調べてみた。
- すると、GDの圧縮率設定で大きくパフォーマンスが変わるという例が散見されたので、試してみると確かに大きく改善できた。
- 詳細検証の上、商用サービス上に圧縮率
1
を適用すると、負荷は軽減された。
実際どの程度変わるのか
以下は、1.8MBのPNG形式画像に対し、imagepng()
関数を使用して1,000回連続で圧縮した結果である。
圧縮率 | 所要時間(s) | 画像サイズ(byte) |
---|---|---|
0 | 28.009 | 1,846,883 |
1 | 31.094 | 285,950 |
2 | 31.165 | 283,031 |
3 | 32.331 | 279,795 |
4 | 38.613 | 268,360 |
5 | 40.412 | 267,109 |
6 | 44.709 | 266,506 |
7 | 49.050 | 266,224 |
8 | 83.864 | 265,515 |
9 | 198.975 | 264,067 |
これを見てわかる通り、圧縮率を 8
以上にすると一気に所要時間が増えていく。一方で圧縮後の画像サイズは 4
以上では大きく変わっていない。今回の問題で圧縮率を 6
から 9
にした事で高負荷状態が頻発するようになった事は、これで裏付けられた。
おわりに
GDの圧縮率設定は、8
以上にすると急激に所要時間が増える。上記のケースでは、所要時間と圧縮率のバランスを鑑みた場合、デフォルトの 6
付近で調整するのが妥当と言えるだろう。ただ、合成の手順や対象の画像によって結果が変わってくる可能性があるため、実際に使用するケースで上記のような検証を行った上で微調整するのが良いだろう。
ちなみに、先述の商用環境においては負荷は軽減されたものの、上記のケースのような劇的な効果は得られなかった。これは圧縮だけでなく、合成部分の負荷も合わさっているためと考えられる。合成部分の処理速度については今回は取り上げていないが、機会があれば検証してみたい。
JMS Serializerのデバッグ設定でハマる
JMS SerializerはPHP標準のシリアライザーよりも強力なため重宝している。ただ、開発時にデバッグ設定にしたにも関わらずキャッシュが作成されてしまう現象に遭遇したので、備忘録がてら記載しておく。
ダメな例
以下は、キャッシュが作成されてしまう例である。 一見すると問題無さそうであるが…。
$isDebug = true; $serializer = JMS\Serializer\SerializerBuilder::create() ->setCacheDir('/path/to/cache') ->setDebug($isDebug) ->build();
正しい例
実は、 setCacheDir()
でキャッシュディレクトリーを指定してしまうと、デバッグ設定に関わらずキャッシュが作成される。そのため、以下のようにデバッグフラグが有効の場合のみキャッシュディレクトリーを指定すると、開発環境と本番環境の切り分けがうまくいくようになる。
$isDebug = true; $serializer = JMS\Serializer\SerializerBuilder::create() ->setDebug($isDebug); if ($isDebug !== true) { $serializer->setCacheDir('/path/to/cache') } $serializer->build();
Laravelのルーティングをアノテーションで指定する
Laravelのルーティングは、設定ファイル(routes.php)に記述するのが標準のやり方である。だが、僕は個人的にルーティングに関しては「設定より規約」でやりたい質である。そこで、わざわざ設定ファイルを見に行く、或いは作るという事をやらずに済むような方法を探す事となった。
Laravel Collective
理想としているのは、何もしなくてもコントローラー名とアクション名からデフォルトのルーティングを組み立ててくれるというものなのだが、それを実現できるような既存の仕組みは見当たらなかった。しかし、これを利用すればコントローラー上にアノテーションを記述する事でルーティングを指定できるというので、利用してみた。インストールするのは、Laravel Collectiveの中でもアノテーション記法を利用するためのパッケージである。
なお、Laravel CollectiveはLaravelコアから取り除かれたコンポーネントをメンテナンスしているプロジェクトである。利用する際にはその点を念頭に置いておきたい。
インストール
まずは以下のComposerパッケージをインストールする。
composer require "laravelcollective/annotations":"^5.3.0"
次に、サービスプロバイダークラスを追加する。 設定内容については後述するので、まずはそのまま貼り付けておこう。
<?php namespace App\Providers; use Collective\Annotations\AnnotationsServiceProvider as ServiceProvider; class AnnotationsServiceProvider extends ServiceProvider { /** * イベントのアノテーションをスキャンするクラス * * @var array */ protected $scanEvents = []; /** * ルーティングのアノテーションをスキャンするクラス * * @var array */ protected $scanRoutes = []; /** * モデルのアノテーションをスキャンするクラス * * @var array */ protected $scanModels = []; /** * local環境の場合に自動的にスキャンするか * * ドキュメントではfalseだが、僕はtrueにしている。 * * @var bool */ protected $scanWhenLocal = true; /** * コントローラーのディレクトリー (Serend\Http\Controllers) から、 * ルーティングのアノテーションを自動的にスキャンするか * * 注意:スキャン対象はControllers直下のみとなる。再帰的ではない。 * * @var bool */ protected $scanControllers = false; /** * 名前空間内の全てのクラスから、 * イベント・ルーティング・モデルのアノテーションを自動的にスキャンするか * * 注意:アプリケーションのサイズに応じて、スキャン時間が長くなる。 * * @var bool */ protected $scanEverything = false; }
最後にお約束通り、サービスプロバイダーを有効にする。
'providers' => [ // ... App\Providers\AnnotationsServiceProvider::class // ... ];
サービスプロバイダーの設定とスキャンについて
サービスプロバイダーの設定で、「スキャン」という言葉が何箇所か出ている。これは何かというと、記述したアノテーションを読み込んで有効化する事である。ルーティングのアノテーションをスキャンする方法は幾つかあるが、先述の通り設定した場合は、次の通りとなる。
- local環境の場合、常に自動的にスキャンされる。
- local環境以外の場合、
php artisan route:scan
コマンドを実行する。
他には protected $scanRoutes
にスキャン対象のコントローラークラスを指定する事もできるが、先の設定にしておけばデプロイ時に毎回artisanコマンドを実行する事で全てのコントローラークラスをスキャンしてくれるので、そちらをお薦めする。
アノテーションの記述方法
@Resource
まずはAPI等を実装する際に役立つ @Resource
について。
/** * @Resource('users') */ class UserController extends Controller { }
これは、以下と同義である。
Route::resource('users', 'UserController');
アクションを絞りたい場合は、 @Resources('users',only={"index","show"})
のように記述すれば良い。
@Get
@Get
はそのままの意味で、HTTPのGetリクエストである。
/** * @Get("users/login") */ public function login(Request $request) { }
これは、以下と同義である。
Route::get('users/login', [ 'as' => 'users.login', 'uses' => 'UserController@login' ]);
@Post, @Put, @Delete, etc...
Get以外のHTTPリクエストについても、同様の記法が利用できる。
おわりに
Laravel Collectiveのアノテーションパッケージを使えば、ルーティングをコントローラー上にアノテーションで記述できる。「設定より規約」的な考え方で、原則としてコントローラー名とアクション名から規則的なルーティングを行っている場合などは特に、扱うファイルが減る分だけ効率的に開発できるだろう。
なお、Laravel Collectiveにはこれ以外にも様々なパッケージがあるし、アノテーションパッケージの中にも紹介し切れていないものがある(実際、僕は @Middleware
等も利用している)。それらについては公式ドキュメントが充実しているので、適宜参照していただくと良いだろう。
LaravelのORMとしてDoctrineを使う
新規サービスでLaravelを採用するにあたり、標準のORMであるEloquentを学習しようかとも考えたが、Doctrineに載せ替えればアノテーションでスラスラとスキーマ定義できるし、DDDとの親和性も高いので、うまく導入できる方法を調べてみた。
Laravel Doctrine
出オチとなってしまうが、その名の通りのパッケージがあった。これをComposerでインストールする。migrationsとextensionsは別パッケージになっているが、どちらもDoctrineを本格活用する上で必須となるため、同時に導入しておきたい。
composer require "laravel-doctrine/orm:1.2.*" composer require "laravel-doctrine/migrations:1.0.*" composer require "laravel-doctrine/extensions:1.0.*" composer require "gedmo/doctrine-extensions=^2.4"
なお、インストールや利用方法の詳細は公式ドキュメントが詳しいのでそちらを参照していただくとして、ここでは押さえておきたいポイントを掻い摘まんでいくこととする。
Artisanコマンドとの連携
これはSynfonyでDoctrineを扱う感覚そのままと言っても差し支えないほどによくできている。proxyクラスの生成からマイグレーションまで完璧に揃っているので、そのままで十分に実用可能だ。参考までに、ORM、Migrations、Extensionsの各パッケージを導入した場合に利用できるArtisanコマンドを以下に挙げる。
doctrine:clear:metadata:cache doctrine:migrations:generate doctrine:migrations:rollback doctrine:migrations:refresh doctrine:migrations:version doctrine:clear:result:cache doctrine:migrations:execute doctrine:migrations:migrate doctrine:migrations:latest doctrine:migrations:status doctrine:generate:entities doctrine:ensure:production doctrine:clear:query:cache doctrine:migrations:reset doctrine:generate:proxies doctrine:convert:mapping doctrine:migrations:diff doctrine:schema:validate doctrine:mapping:import doctrine:config:convert doctrine:schema:create doctrine:schema:update doctrine:dump:sqlite doctrine:schema:drop doctrine:info
Debugbarとの連携
LaravelのDebugbarを利用している場合、SQLのクエリーログは手放せないだろう。だが、当然ながらORMをDoctrineに置き換えれば、そのままでは使えなくなってしまう。
…と思っていたのだけれども、ありがたいことにLaravel Doctrineは標準でログの吐き出し先を指定できるようになっており、Debugbarとも、そして先の記事で触れたClockworkとも連携できるようになっている!
return [ /* |-------------------------------------------------------------------------- | Enable query logging with laravel file logging, | debugbar, clockwork or an own implementation. | Setting it to false, will disable logging | | Available: | - LaravelDoctrine\ORM\Loggers\LaravelDebugbarLogger | - LaravelDoctrine\ORM\Loggers\ClockworkLogger | - LaravelDoctrine\ORM\Loggers\FileLogger |-------------------------------------------------------------------------- */ 'logger' => env('DOCTRINE_LOGGER', false), ];
このように.envで簡単に切り替えられるようになっているため、迷うことは無いだろう。
IDE補完
LaravelはIDE補完が優秀だが、その恩恵はDoctrineに切り替えても基本的に受けられる。find系のメソッドで取ってきたEntity等もバッチリである。ただ、今の所Repositoryに追加したメソッドについては補完の方法がわかっておらず、ここは大きな課題である。
Eloquentに対するデメリット
性能面はチューニングによっても変わってくるので触れないものとして、特に標準のEloquentと比べて劣ると感じた箇所は無かった(本格的にEloquentを触ったわけではないが)。ただORMとしての方向性は全く違うので、用途に応じて使い分ける必要はあるだろう。
おわりに
Laravel Doctrineを使えば、Synfony上で使うのと似たような感覚で便利にDoctrineを扱うことができる。現状だと日本語の情報は皆無に等しいが、公式ドキュメントが充実しているため導入には困らないだろう。Eloquentの代替となるORMの選択肢としては、十分検討に値するものと思われる。
Laravel DebugbarをAPI開発でも使う
Laravelのデバッグツールとしては、Laravel Debugbarがよく使われている。ただ、これは情報をHTML上に描画しているため、API開発でレスポンスがJSONとなる場合などは表示されなくなる。そこで、Chrome/Firefox拡張であるClockworkを導入することによって、レスポンスがHTML以外の場合でもDebugbar相当の情報を出力できるようにする。
実行環境
- Google Chrome 53
- Laravel 5.3
Laravel Debugbarの導入
まだDebugbarを導入していない場合は、barryvdh/laravel-debugbarを参考にインストールしてHTML上で表示できるようにしておく。
ブラウザー拡張のインストール
Chromeの場合は、Chromeウェブストアからインストールする。
Firefoxの場合は、Add-ons for Firefoxからインストールする(要Firebug)。
Composerパッケージのインストール
composer require "itsgoingd/clockwork": "~1.12"
アプリケーションのConfig設定
Service Providerを以下の通り追加する。
'providers' => [ Clockwork\Support\Laravel\ClockworkServiceProvider::class, ],
Middlewareの設定
バージョンによっては$middlewareの場合があるので適宜読み替える。
protected $middlewareGroups = [ 'api' => [ \Clockwork\Support\Laravel\ClockworkMiddleware::class, ], ];
DebugbarのConfig設定
最後にDebugbar側のConfigでClockworkを有効にする。
HTML上の描画を止めたい場合は、injectを false
にしておく。
'clockwork' => true, 'inject' => false,
おわりに
以上が最低限の設定だが、これでブラウザーのデバッグツールに以下のようなLaravelのデバッグ情報を表示するタブが追加されるはずだ。
なお、Clockworkの詳細についてはGitHubを参照されたい。