ImageMagickで画像処理に入門する

この記事は、ImageMagickと画像加工について発表したときの資料を文章に起こして加筆修正したものです。

ImageMagickとは

  • 画像加工といえばこれという有名ライブラリ
  • メジャーからマイナーまでさまざまな画像形式に対応
    • 機能が多すぎて脆弱性もたびたび発見されるくらい…
  • Cで実装され、多くの言語でバインディングがある

インストール

Mac Homebrew

1
$ brew install imagemagick

Debian / Ubuntu

1
$ sudo apt-get install -y imagemagick

CentOS

1
$ sudo yum -y install ImageMagick

コマンド

  • imagemagickというコマンドはない(!)
  • 機能ごとにconvertidentifyなどのコマンドにわかれている
    • ただし、ImageMagick 7からはすべてmagickコマンドへのシンボリックリンクになっている

ImageMagick 6 (Ubuntu 16.04)

1
2
3
4
5
6
7
8
9
10
11
12
13
$ ls -Alh /usr/lib/x86_64-linux-gnu/ImageMagick-6.8.9/bin-Q16
total 88K
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 animate
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 compare
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 composite
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 conjure
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 convert
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 display
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 identify
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 import
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 mogrify
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 montage
-rwxr-xr-x 1 root root 6.3K Jul 31 13:22 stream

ImageMagick 7 (Mac Homebrew)

magickコマンドへのシンボリックリンクになっていることがわかる

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ ls -Alh /usr/local/Cellar/imagemagick/7.0.7-7/bin | grep -v config
total 64
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 animate -> magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 compare -> magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 composite -> magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 conjure -> magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 convert -> magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 display -> magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 identify -> magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 import -> magick
-r-xr-xr-x 1 shimoju admin 18K 10 9 18:25 magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 magick-script -> magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 mogrify -> magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 montage -> magick
lrwxr-xr-x 1 shimoju admin 6B 10 7 21:02 stream -> magick

identify

  • 画像の情報を出力できる
  • サイズをさっと知りたいときとか、大量の画像の中からサイズが違うものを探したりとかに便利
  • フォーマット文字列はこちら参照:Format and Print Image Properties @ ImageMagick
1
2
3
$ identify *.jpg
original.jpg JPEG 800x533 800x533+0+0 8-bit sRGB 104823B 0.000u 0:00.000
resize.jpg JPEG 400x267 400x267+0+0 8-bit sRGB 37116B 0.000u 0:00.000

JSON形式で出力してjqに食わせる

1
2
3
4
5
$ identify -format '{"width": %w, "height": %h}' *.jpg | jq
{
"width": 800,
"height": 533
}

grep -vで指定のサイズではない画像を抽出

1
2
$ identify -format '%wx%h %f\n' *.jpg | grep -v 800x533
200x200 crop.jpg

convert

  • さまざまな画像加工を行える、ImageMagickのメインコマンド
  • 適当な画像をoriginal.jpgとして用意しておきます

回転 (rotate)

-rotateで指定した角度回転する

1
$ convert -rotate 90 original.jpg rotate.jpg

上下反転

1
$ convert -flip original.jpg flip.jpg

左右反転

1
$ convert -flop original.jpg flop.jpg

上下左右反転

1
$ convert -flip -flop original.jpg flipflop.jpg

サンプル (sample)

ピクセルを間引く

1
$ convert -sample 10% original.jpg sample.jpg

10%になるようにピクセルを間引いたあと、1000%になるように拡大
→元画像と同じサイズでモザイクがかかる

1
$ convert -sample 10% -sample 1000% original.jpg mosaic.jpg

リサイズ (resize)

デフォルトではアスペクト比を変えない:指定した幅・高さに収まるようにリサイズされる

1
2
3
$ convert -resize 400x400 original.jpg resize.jpg
$ identify resize.jpg
resize.jpg JPEG 400x267 400x267+0+0 8-bit sRGB 37116B 0.000u 0:00.000

!をつけるとアスペクト比を無視して指定した値にリサイズする

1
$ convert -resize 400x400! original.jpg resize2.jpg

幅または高さのみ指定できる

1
$ convert -resize 400x original.jpg resize3.jpg

エッジ検出 (edge)

不連続に変化している箇所を検出する

1
$ convert -edge 5 original.jpg edge.jpg

値を変化させてみよう

1
2
$ convert -edge 10 original.jpg edge2.jpg
$ convert -edge 1 original.jpg edge3.jpg

切り抜き (crop)

-gravityで基準点を指定し、-crop widthxheightで切り抜くサイズを指定

1
$ convert -gravity center -crop 200x200+0+0 original.jpg crop.jpg

+/-で基準点からのx,y座標を指定できる
画像右上を基準に、xに140px,yに50px移動し、その点から200x200px切り抜く

1
$ convert -gravity northeast -crop 200x200+140+50 original.jpg crop.jpg

塗り足し (extent)

指定したサイズになるように余白を追加する
正方形のサイズが必要なのに4:3の画像しかないときなどに便利

1
2
$ convert -background black -gravity center \
-extent 800x800 original.jpg extent.jpg

余白の色は-backgroundで指定する
PNG(透過が扱えるフォーマット)であれば、-background transparentで透過できる

1
2
$ convert -background transparent -gravity north \
-extent 1000x1000 original.jpg extent.png

文字の画像を作る

1
2
$ convert -background transparent \
-fill '#ff6060' -font Arial -pointsize 128 label:LGTM lgtm.png

指定サイズで作成

1
2
$ convert -size 400x200 -gravity center -background transparent \
-fill '#ff6060' -font Arial -pointsize 128 label:LGTM lgtm.png

合成 (composite)

original.jpgの上にlgtm.pngを合成して、compose-over.jpgとして出力

1
2
$ convert original.jpg lgtm.png -gravity center \
-compose over -composite compose-over.jpg

-geometryで基準点から移動

1
2
$ convert original.jpg lgtm.png -gravity center -geometry +150+50 \
-compose over -composite compose-over.jpg

描画モード (blend mode)

乗算 (multiply)

1
2
$ convert original.jpg lgtm.png -gravity center -geometry +150+50 \
-compose multiply -composite compose-multiply.jpg

オーバーレイ (overlay)

1
2
$ convert original.jpg lgtm.png -gravity center -geometry +150+50 \
-compose overlay -composite compose-overlay.jpg

減算 (subtract)

1
2
$ convert original.jpg lgtm.png -gravity center -geometry +150+50 \
-compose subtract -composite compose-subtract.jpg

Herokuはスケーラブルなアプリ養成ギプス

社内勉強会でHerokuでの本番運用について発表しました。
いま携わっているSUZURIはHerokuで運用しており、個人でもHerokuで運用しているアプリがあります。その中で経験したことや知見を話しました。

Herokuで本番運用する技術

目次を見るとわかるようにテーマは多岐にわたっており、ざっと&ゆるめに発表しようという趣旨です。

Herokuはスケーラブルなアプリ養成ギプス

Herokuのいいところといえば、マネージドで手軽に使えること、開発者にとって便利な機能が豊富なこともそうですが、アプリケーション設計に良い影響を与える点もあります。

たとえば、Herokuではローカルにファイルを保存できません(正確にはできますが、1日1回自動で再起動され、そのときに消滅します)。この挙動に代表されるように、Herokuではシステムローカルな何かに依存しない、疎結合でステートレスなアプリケーション設計が強制されます。

このHerokuが提唱している方法論をまとめたものがThe Twelve-Factor Appです。初めて読んだときはよくわからなかったのですが、新卒研修でインフラを学んだり、アプリケーション設計の知識がついていくにつれて、なるほどとてもよいポリシーだなあ、としみじみ感じています。

Herokuで動くように作ればスケーラブルなアプリが自然にできていくということで、養成ギプスを思わせます。Dockerなどのコンテナでアプリを運用するときにも同じ考え方を適用できるため、コンテナ時代になってその重要性はさらに高まっているのではないかと思います。Twelve-Factor Appを学ぶのにもHerokuはおすすめです。

おまけ

「おまけ」に書いたのですが、Herokuにはテスト、ステージング、本番環境をシームレスに統合するCI/CD環境であるHeroku Pipelinesがあります。たとえばマージすると自動でデプロイできるGitHub Integration、CI環境のHeroku CIや、ChatOpsもあります。特にHeroku Review AppsはPull Requestを作るたびに新しい環境を自動的に作ってくれてとても便利です。

しかしこの機能はGitHubしかサポートしておらず、会社のリポジトリはGitHub Enterpriseなので使えません😭
"github.com"がハードコードされていて色々大変らしいという話を@hsbtさんから聞いたのですが、本当に書いてあって笑いました。なんとかしてほしいものです。

Heroku's GitHub sync features are hard-coded to connect to and use github.com.
Can I use Github Enterprise with Pipeline Review apps? - Knowledge Base

実はこの日には新卒エンジニア研修の座学で1時間の発表もしており、2回目の発表でとてもヘビーでした。あんまりうまく喋れてなかったのではないかと思います……。


新卒エンジニア研修の座学でImageMagickと画像加工の話をした

ペパボの新卒エンジニア研修では、メニューのひとつとして「座学」を行っています。

メインの研修ではWeb開発・Webオペレーション・モバイルアプリ開発に順番に取り組んでいきますが、座学では知識と興味を広げることを目的として、社内のエンジニアにお願いして1時間自由に発表してもらっています。
たとえば、テストやチーム開発、モバイルの開発手法といった研修内容に関連した話や、あるいは3DCGのシェーダーやReactive Extensionsといった、研修では触れないような技術の話まで様々です。研修の内容については、ペパボの新卒エンジニア研修2017 Vol.1 - ペパボテックブログを見ると雰囲気がわかるかと思います。

私は研修担当者をやっていて座学をお願いする立場ですが、自分でもやってみたかったので立候補しました。

資料はこちらです。「ImageMagick実践入門 画像加工サーバを作ってみよう」と題して、実際にコマンドやコードを書きながら、ImageMagickを使った画像加工と、簡単な画像加工サーバーをGo言語で実装していきます。

1時間話すのはとても疲れました。この座学はハンズオンもあるので資料は50枚程度ですが、全部口述だと70〜80枚にもなるので、資料作成もかなり時間がかかります。
作っていくうちに「本当にこんな内容でいいのだろうか……」とつらくなってきますが、いま学習中のGo言語を使ってみたり、調べる中で自分の理解も深まって、いい経験になりました。

座学講師に立候補してくださった方々には頭が上がりません。


DockerでcronしたいときはBusyBox crondが便利

Dockerコンテナでプログラムを定期実行したいとき、それぞれの言語で実装されたタスクスケジューラを使うほか、手っ取り早くcronを使ってしまう方法もあります。しかしDockerで使うにはやや面倒な点があります。

  • cronで実行するプログラムにコンテナに設定した環境変数を渡したい
  • ログは標準出力・標準エラー出力に書き出したい
    • 標準出力に出せばdocker logsで扱えるし、ファイルだとローテートが面倒

このようなとき、BusyBoxに含まれるcrondを使うと、以上の課題を解決してシンプルに定期実行することができます。

インストール

Debian系ではapt-get install busybox-staticでインストールし、busybox crondで起動します。
Alpine LinuxであればそのままBusyBoxなのでcrondで起動できます。

オプション

-dオプションは比較的最近追加されたようで、Debian jessie(BusyBox v1.22.1)には含まれていませんでした。stretchでもv1.22.1のままのようです。

Alpine Linux 3.6 / BusyBox v1.26.2

1
2
3
4
5
6
7
8
9
10
11
12
# crond --help
BusyBox v1.26.2 (2017-06-11 06:38:32 GMT) multi-call binary.
Usage: crond -fbS -l N -d N -L LOGFILE -c DIR
-f Foreground
-b Background (default)
-S Log to syslog (default)
-l N Set log level. Most verbose:0, default:8
-d N Set log level, log to stderr
-L FILE Log to FILE
-c DIR Cron dir. Default:/var/spool/cron/crontabs

Debian jessie / BusyBox v1.22.1

1
2
3
4
5
6
7
8
9
10
11
# busybox crond --help
BusyBox v1.22.1 (Debian 1:1.22.0-9+deb8u1) multi-call binary.
Usage: crond -fbS -l N -L LOGFILE -c DIR
-f Foreground
-b Background (default)
-S Log to syslog (default)
-l Set log level. 0 is the most verbose, default 8
-L Log to file
-c Working dir

ログレベル

ログレベルが0から8まであってよくわからなかったのでソースを読んだところ、

1
2
3
4
/* Log levels:
* 0 is the most verbose, default 8.
* For some reason, in fact only 5, 7 and 8 are used.
*/

とのことでした。For some reasonとは一体……という感じですが、デフォルトの8でもコマンドの実行ログは出るので特に問題なさそうです。

というわけで、Dockerで使う場合は以下のコマンドにすればよいでしょう。新しく追加された-dオプションが標準エラーに出力しているので、Debianの場合でもこれに統一しています。

1
2
3
4
5
6
7
# Alpine
# crond -f -d 8
CMD ["crond" "-f", "-d", "8"]
# Debian
# busybox crond -f -L /dev/stderr
CMD ["busybox", "crond", "-f", "-L", "/dev/stderr"]

実行する

/var/spool/cron/crontabs/rootにいつものようにcrontabを書いて実行します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ cat crontab
* * * * * echo '=== environment variables ===' && env
$ docker run --rm -e FOO=BAR -v $(pwd)/crontab:/var/spool/cron/crontabs/root alpine:3.6 crond -f -d 8
crond: crond (busybox 1.26.2) started, log level 8
crond: USER root pid 7 cmd echo '=== environment variables ===' && env
=== environment variables ===
USER=root
no_proxy=*.local, 169.254/16
HOSTNAME=eac1d9f28400
SHLVL=1
HOME=/root
LOGNAME=root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
FOO=BAR
SHELL=/bin/sh
PWD=/root

このように、コンテナに設定した環境変数FOO=BARが実行コマンドからも見えること、ログが標準エラー出力に書き出されていることを確認できました。

タイムゾーン

cronと直接関係はありませんが、タイムゾーンを日本時間にしておかないと意図した時刻に動かなくてハマるので注意しましょう……(1時間無駄にしました😇)。

1
ENV TZ=Asia/Tokyo

参考記事


ブログをHexoで作り直してNetlifyにデプロイした

ようやく重い腰を上げてブログを作り直しました。
以前のブログはとりあえずWordPressでやっていたのですが、普段のエディタでMarkdownを書きたい…Git管理したい……となったので移行しました。

静的サイトジェネレータ

静的サイトジェネレータとしてはHexoを採用しました。
当初はGo言語製のHugoを使おうとしたのですが、投稿ごとにアセット用のディレクトリを切って管理できるPost Asset Folder機能など、ディレクトリ構成の柔軟性や機能の充実度を考えてHexoにしました。

WordPressからの移行にはwordpress-to-hugo-exporterを使用(当初はHugoの予定だったので…)。Markdownで書き出したあとの調整はエディタによる一括置換やGit管理で楽ちん。Hexoへの切り替えはfront-matterやヘルパーを少しいじっただけなので、ジェネレータ間の移行もしやすいのがいいですね。

デザイン・テーマ

TumblrテーマのApolloをHexoに移植したhexo-theme-apolloを、さらにフォークして使っています。
コードブロックの空白行が詰まって行番号とずれる問題を修正したりアーカイブページにページネーションをつけたりはてブボタンをつけたりしました。

デザイン自体がシンプルですし、実装も素朴なのでカスタマイズしやすかったことが決め手です。いろいろ変えたいところはあるので次はテーマを自作したいです。今回はDone is better than perfect精神でいっています…。

サーバー

サーバーは、静的サイトのホスティング先として最近話題のNetlifyを利用しています。

チーム機能を使うには有料ですがパーソナルであれば無料で、独自ドメイン利用・Let's EncryptによるSSLも無料。当然のようにHTTP/2対応で、アセットはCloudFrontのCDNで配信されます。
ビルドコマンドを指定すればあとはNetlifyが全部やってくれるので便利です。GitHub連携もあり、masterにマージしたら自動でデプロイされます。おまけにHeroku Review Appsのような、Pull Requestごとにプレビュー用の環境まで作ってくれます。すごい……。

まとめ

静的サイトジェネレータは様々な言語で実装されて、いまや450以上あるようです。機能やエコシステムも洗練されてきているような感覚があります。静的サイトの自動ビルド・デプロイはCIサービスを使う方法が主流でしたが、Netlifyは意外とありそうでなかったサービスですね。すごい。

ロリポップ!マネージドクラウドにもNetlify的な静的サイトをビルドしてくれるコンテナがあると便利そうな気がしました。よろしくお願いします🙏(勤務先です)


コーディング規約チェックを日常に〜無理なくチーム全員で取り組める仕組みを作ろう

この記事はpepabo Advent Calendar 2016の4日目です。
3日目は@r_takaishiさんの「IIJmioのクーポン残量をAWS LambdaとMackerelでプロットしてみよう」でした。

コードレビューでよくある風景

突然ですが、コードレビューを行っていると、このようなコメントを一度はする・されると思います。

細かいコーディングスタイルに関する指摘

インデントやスペースの抜け漏れといった、細かいコーディングスタイルに関する指摘ですね。
人力でフォーマットの指摘をするのは見逃しが発生しやすく、細かい部分を確認するコストがかかります。小言のようなコメントになってしまいがちで、開発者・レビュアー双方に負担が増えてしまいます。

このような作業は機械に任せましょう。RuboCopPHP-CS-FixerESLintといったコーディング規約チェックツール(Lintツール)が役立ちます。
Lintツールを導入することでコーディング規約の実践にかかるコストを減らし、可読性・保守性の向上に貢献したり、より本質的な部分のレビューに時間を使えたりできることは、多くの方が実感していることでしょう。

既存プロジェクトに導入する際の課題

しかし、既存のプロジェクトにLintツールを導入するには課題があります。たとえば、

  • 尋常じゃない量の違反が見つかってどうしたらいいかわからない😱
    • 一度に自動修正すると差分が多すぎて、きちんと動くのか検証が困難とか……
  • 導入したはいいものの、開発サイクルの一部としてチームに定着できていない😇
    • 忘れる、面倒くさい、よくわからない→結局自分しかやってないとか……

Lintツールを導入すること自体が目的ではありません。Lintツールの助けを得て、継続的に、将来にわたって読みやすいコードを作っていくことが目的です。
せっかく導入しても開発サイクルの一部として定着しなければ意味がありません。

つまり、無理なくチーム全員で取り組めるような仕組みを作り、段階的に導入していくことが必要になるでしょう。

今回Lintツールを導入したチームも、上の課題に当てはまっていました。

  • 既存のコードが大量にあり、一度に自動修正すると差分が多すぎる
  • リポジトリにLintツール自体は入っていたが、活用されなかった悲しい過去が……😇

無理なくチーム全員で取り組めるような仕組み

では、「無理なくチーム全員で取り組めるような仕組み」とはなんでしょうか?
様々あるかと思いますが、今回は以下の3つの対策を行うことで課題に対処しました。

  1. Pull Request内で追加・変更したファイルのみを対象にチェックをかけ、段階的かつ確実に直していく
  2. 言語をまたがってチェック・修正を一発でできるスクリプトを用意しておく
  3. CI中に実行することで目に見えてわかる結果を出し、強制力をもって開発サイクルに載せる

では、ひとつずつ紹介していきます。サンプルリポジトリは以下にあります。

Pull Request内で追加・変更したファイルのみを対象にチェックをかけ、段階的かつ確実に直していく

全ファイルを対象にチェックをかけると大量の違反が見つかり、自動修正しても差分が多すぎて正しく動くかの検証が困難になります。
そこで、新しく追加するコードに対してのみチェックをかけるようにします。

ブランチで追加・変更したファイルはgit diffのオプションを使って取得することができます。

1
git diff --name-only --diff-filter=ACM origin/master...HEAD

対象ファイルを限定することで、新しく追加するコード、および差分が出たファイルは確実にコーディング規約が守られた状態になります。
少しずつではありますが、普段行う開発のついでに、無理なく自動的にコードがきれいになっていく世界を作ることができます。

言語をまたがってチェック・修正を一発でできるスクリプトを用意しておく

言語ごとにLintツールは異なるため、(共通点は多いものの)各ツールやコマンド体系を覚える必要があります。
たとえばフロントエンドのコーディングであれば、PHPテンプレート・CSS・JavaScriptファイルを同時に編集する場合もあるでしょう。このときにLintツールをそれぞれで実行する必要があるのは面倒です。

そこで以下のような一括チェック用のシェルスクリプトを用意しました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/bin/bash
function diff-filter-ext() {
git diff --name-only --diff-filter=ACM origin/master...HEAD | grep "\.$1$"
}
lint_langs=()
options=()
for arg in "$@"
do
case "$arg" in
# --で始まっていればオプションとみなし、それ以外はlintする言語指定とみなす
--* ) options+=( "$arg" ) ;;
* ) lint_langs+=( "$arg" ) ;;
esac
done
# 言語指定がなければ全言語に対してlintをかける
if [ ${#lint_langs[@]} = 0 ]; then
lint_langs=(php js)
fi
status=0
for lang in ${lint_langs[@]}
do
diff-filter-ext $lang | xargs -t -n1 -I'FILE' bin/lint-$lang FILE ${options[@]}
if [ $? != 0 ]; then status=1; fi
done
if [ $status != 0 ]; then exit 1; fi

さらに各ツールのインタフェースを合わせるためのラッパースクリプトを用意します。

これでbin/check-coding-ruleを実行すればすべてのLintツールでチェックが行われます。自動修正は--fixオプションで行なえます。
スクリプトはもうちょっといけてる感じにできると思いますが、ツールを意識することなく、コマンド一発でチェック・修正を行えるようにできました。

CI中に実行することで目に見えてわかる結果を出し、強制力をもって開発サイクルに載せる

最後に、コーディング規約チェックをCIで実行し、規約違反があった場合はCIを失敗させるようにします。目に見えてわかるようにすることで、規約チェックがあることを意識でき、自然とチェック・修正を行えるようになります。

実際の業務ではDroneを使っていますが、Travis CIでは以下のように設定できます。

1
2
3
4
5
6
7
8
9
10
11
language: php
php:
- '7.0'
before_script:
- nvm install 6.9 && nvm alias default 6.9
- npm install
- composer install
script:
# コーディング規約チェックチェックスクリプトを実行する
- bin/check-coding-rule
- phpunit

規約違反があるとこのようにCIが失敗します。大抵のLintツールではどこがどのエラーなのか出力するようにできるので、設定しておくととても親切になります。

コーディング規約違反があるとCIが失敗する

強制力をもつことになるため、突然導入されて戸惑わないよう、チームメンバーへ事前共有しておくのがよいでしょう。
ペパボではデザイナーがコーディングまで行うため、事前にデザイナーさんも交えて話を聞き、現状Lintツールが活用できていない要因と、このような対策をとろうと思いますということを話しました。
READMEやWikiに、よくあるエラーとその修正方法をまとめておくことも重要でしょう。

ESLintの例

今回はESLintを新規導入したため、そのTipsもいくつか載せておきたいと思います。

  • すべてのルールのON/OFFが可能なため、コードの現状に合わせて設定することができる
  • ESLintのルール一覧
    • "eslint:recommended"ではチェックマークのついたルールが有効になる
    • レンチマークは--fixオプションによる自動修正が行えるもの
  • Stylistic Issues(,の後のスペースやインデントなど)はロジックに関わらない上に自動修正できるものが多いため、多めに入れておく
    • レビューのときに「細かいところですが…」と言うようなやつを大幅に減らせます
  • 既存のコードのエラーを(雑でいいので)集計し、厳しそうなものをwarningに落とす
    • no-undef(宣言されていない変数の使用禁止)が一番多く、Pull Requestのついでに修正するには厳しそうなためwarningに落としました
  • 今後も調整になるかと思いますが、.eslintrcはこのようにしました

まとめ

コーディング規約チェックを「無理なくチーム全員で取り組めるような仕組みを作る」ことを目指しました。
そのために、以下の対策を行いました。

  1. Pull Request内で追加・変更したファイルのみを対象にチェックをかけ、段階的かつ確実に直していく
  2. 言語をまたがってチェック・修正を一発でできるスクリプトを用意しておく
  3. CI中に実行することで目に見えてわかる結果を出し、強制力をもって開発サイクルに載せる

気になる結果ですが、ESLintの追加はマージできていないため、残念ながら結果はこれからとなります…。
しかし、PHP-CS-Fixerは既に導入されており、非常によいサイクルが回っています。日常的にコーディング規約チェックを行うことができ、既に当たり前のようになっています。
JavaScriptのチェックも同じコマンドで同時にできるようにしたため、同様に良い結果となることを期待しています。

みなさんも、無理なく自動的にソースがきれいになっていく世界、作ってみませんか?

おまけ

記事の内容からは外れるため特に書いていませんでしたが、このタスクは新卒研修のOJTで配属されたチームで行ったものです。
PHP-CS-Fixerの最初の導入は同期エンジニアが行い、ESLintの追加・チェックスクリプトの多言語対応を私が行いました。

ペパボの新卒エンジニア研修については、GMOペパボの新卒エンジニア研修の様子 & テキストを公開します - ペパボテックブログを見ていただけると様子がわかりますので、ぜひご覧いただければと思います。


2016年秋アニメ:1話の感想をざっと

7月までに急いで録画体勢を構築したのはよいのだけど、結局マジェプリ再放送しか見ていなかった夏アニメ。
秋はいっぱい見ようということでブルーレイレコーダーとソファを調達しました。ソファに寝っ転がりながらひたすらアニメを見る連休は最高だった。

というわけで、1話がほとんど出揃ったのでざっと感想を書いていこうと思います。
オリジナル作品も多いし、先が気になる1話が多くてレコーダー大活躍で何より。

見たやつ

終末のイゼッタ

  • おもしろそう。戦争の中に現れた魔女、こういう世界設定好きですね。オリジナルは先の展開がわからないのがいいね

WWW.WORKING!!

  • 今回もWORKINGらしい。なんか安心して見ていられる

魔法少女育成計画

  • 明るそうだけど全体的に不穏な…と思ったら、生き残りをかけて戦うダークファンタジーらしい(原作宣伝のCMで今後の展開を言われるとは…)

機動戦士ガンダム 鉄血のオルフェンズ(2期)

  • 初めてのガンダムがオルフェンズなんだけどなかなか楽しい
  • ビーム兵器がないから戦闘が泥臭くて、鈍器がぶつかりあう効果音がいい感じ

SHOW BY ROCK!!#

  • 2期のキーマンとなりそうなあいつら(名前がよくわからない)、設定がめちゃくちゃすぎて笑った
  • 敵、お前かよって感じになった

刀剣乱舞-花丸-

  • んー、見てはみるけど原作やってないとやっぱりわからんかなー
  • 名前が、覚え、られない……
  • 審神者が描写されないのはちょっと気になる

アイドルメモリーズ

  • CM明けたらいきなり声優が出てきて録画間違ったかと思った。30分枠で半分声優番組をやるのは斬新
  • アイドルアニメ、個人的にはあんまりハマらないかも…

ステラのまほう

  • 割と本気でゲームつくる話っぽい?
  • 硬派なおじさん絵が好きなのうけるな

学園ハンサム

  • 独特な顔とゆるい絵がツボにはまった

装神少女まとい

  • PVからゆるふわ系アニメかと思ってたら、こんな作風なのかよ!って感じ

ユーリ!!! on ICE

  • フィギュア描写すごい(大変そう)
  • 先のドラマや展開の想像が膨らむ1話があると期待が高まるね

フリップフラッパーズ

  • 1話だけでは全然よくわからんかったけど、背景・美術が最高だった。さすがスタジオPablo
  • おばあちゃんが久保田民絵さん

競女!!!!!!!!

  • とても熱くアホらしくて全然エロくなくて笑った。主線が太い。最高。

Lostorage incited WIXOSS

  • 俺待望のWIXOSSアニメ新作。相変わらず不穏。確かに男が入ると雰囲気がまた変わって締まる感じ。
  • 前作のるう子とは違う、バトルは嫌なタイプを主人公にすえて、じゃあどうやって引きずり込むかを考えたときに、記憶を失うこととタイムリミットを設定するのはなるほど感
  • バトルフィールドや白窓の部屋が明らかに繭の世界の成れの果てだけど、つながりは描かれるのかなー。ピルルク(改め清衣)もどうなるか…

クラシカロイド

  • OPが布袋寅泰。

3月のライオン

  • 演出がシャフトっぽいと思ったらシャフトだった
  • 前半の落ち着いた雰囲気も浸れる
  • 茅野愛衣さん、花澤香菜さん、久野美咲さんの3姉妹……なるほど
  • OPもEDもバンプなんて贅沢

うどんの国の金色毛鞠

  • 原作ものだったのね。最後のおまけアニメは一体なんだったんだ…

月曜日のたわわ

→炎上する以前にYouTubeガイドライン違反で消されてて笑った

まだ見てないやつ

  • 12歳。~ちっちゃなムネのトキメキ~ セカンドシーズン
    • 先輩が最高のアニメだと言うので一度見てみようと思う
  • 響け!ユーフォニアム2
    • まだ1期を見ていないんです……
  • 私がモテてどうすんだ
  • ガーリッシュ ナンバー
  • DRIFTERS(ドリフターズ)
  • Occultic;Nine-オカルティック・ナイン-
  • 舟を編む(10/13木から)

再放送その他

銀河機攻隊マジェスティックプリンス(新作25話)

  • 本編は再放送だけど、今度の映画に続く新作25話が放送された
  • メカアクションはもとより特に音響がめちゃくちゃパワーアップしていたし、映画予告も予想以上だったし期待。

進撃の巨人(オリジナルマスター版)

  • 「オリジナルマスター」が何を意味するのかどこにも書かれていないのだけど、提供クレジットの字幕が入っていなかったくらいしか違いがわからない

涼宮ハルヒの憂鬱


研修で1週間でWebサービスをつくった話

  • 「1週間でWebサービスをつくる」研修
    • 「お産ウィーク」と呼んでいる
    • 新卒エンジニア5人+デザイナー1人で2チーム
  • 課題は旅行と料理の2つでどちらかを選ぶ
    • 料理にした
  • 料理は工夫の繰り返し
    • 今日は〇〇を多く入れてみよう、強火にしよう、スパイスを変えよう、…
    • でも結局どれがどのくらい美味しかったのか、自分の料理がどのくらい成長したのかがわからない!
    • →料理の記録をふりかえって、自分の工夫を実感できるサービスを作ろう となった
  • つかれた
    • 何も出てこない
    • 箇条書きで書く
  • まず動くものを作れたことが第一
  • エンジニアの発想の限界
    • かなり素直、というか課題をそのまま作ったような感じ
    • もう一工夫できた
    • 自分たちでは限界がある、他人の視点大事
  • 使ってみると楽しい
    • 使ってみる/使ってもらうと改善点がいろいろ出てくる
    • 最終的に自分が使いたくなるものを作れた
    • 他人のレシピを見ると(ふざけてるのもあるけど真面目に書いてるのもあって)おもしろい
  • やっぱりレシピ公開(共有要素)を入れてよかった
    • そうするとユーザーネームいれたほうがよかった
    • 最初は全部非公開で日記みたいになる想定だった
  • 月額課金で収益を得る想定なので、WebPayを使って支払情報の登録をできるようにしておいた
    • 「こうなる予定でした」と夢物語にならないようにはできた
  • 新卒デザイナーがひとりなので、こっちのチームにはデザイナーがいなかった
    • その割にはがんばった
    • フレームワークを使ってそれなりに仕上げているだけ
    • できることから考えてしまう癖
    • ユーザーにこういう経験をしてもらいたい→じゃあ具体的にこんなデザインにしよう→実装 という形ではなかった
  • 自分の存在意義とは
  • テスト書いたり本番環境で一連の操作をしてみるなど、検証まで含めて機能の完成
    • テスト書かなかったなー
    • 発表1時間前に本番環境で一部の操作にエラーが出ることが発覚
    • 突如ISUCONが開催された
    • 落ち着いてログを見てエラーを潰せたのはちょっと経験値が上がった?
  • 作りたい機能が5個あるけど時間が足りないとなったとき、検証を省いて5個作るんじゃなくて、3個に減らしてそこまでは確実に機能するものをつくる
    • 動かなければないものと同じ
    • 優先順位や「やらないことリスト」
    • 自分たちのやりたいことに最低限必要なものは何なのか(MVP)
    • 自信を持って減らせる
  • 公開したい
    • 使いたいし改善したい
    • 会社のプライベートクラウドにデプロイしているのでアドレスさえわかれば見れる状態
    • ログイン制なのにSSLじゃない
    • テストも書いてないし手動の検証も不足しているので、プライベートなものが本当にプライベートになっているかよくわからない

ヒップホップユニットのミュージックビデオに出演した

「明日は秘密の撮影会があるそうです」
そう研修スーパーバイザーのじょーさんが言う。

会社で、撮影。耳慣れない響きだが、ここペパボにあたってはさほど驚くことではない。
採用やイベントのための社員写真はもとより、サービスのバナー画像といった宣材写真もほとんどを内製でまかなっている。
「ペパボに入社したらフリー素材になる」と言われるほどだ。

新卒1年目の我々も、既に全員1回は、人によっては数度の撮影を経験している。
例えば新卒エンジニアは学生アルバイト・インターンの募集に出たりしている。

やれやれ、いつものあれか。と、脳内の村上春樹が声をあげる。

だが、どうやら今回は様子が違うようだ。
担当者からは「伝説を作ろう」などとわけのわからない言葉が飛び出している。

どんな撮影なのだろうか?
よくわからないまま当日を迎えると、そこにはラッパーがいた――。

……

ここから先は説明するより動画を見てもらったほうが早いのと、一人称小説みたいな文体に飽きてきたので以下の動画をどうぞ。

ミュージックビデオに出演しました。仕事で。
もはやわけがわからない。
ビデオでの撮影で、しかもMVと聞いたときには驚きました。

企画背景と、ここに至るまでの流れは以下のテックブログの記事で。テックってなんだっけ。

プレスリリースも出ているのだけど、タイトルの情報量とつっこみどころの多さに圧倒されるのと、PRの真面目な文体に強烈な画像が流れてくるのがとてもじわじわくるのでオススメ。

【PR】スタッフ積極採用中!

GMOペパボでは、新しい仲間を熱烈に求めています。詳細につきましては、以下をご覧ください。


ペパボ社内ISUCONで撃沈しました

ISUCONとは「いい感じに スピードアップ コンテスト」(Iikanjini Speed Up CONtest)の略だそうで、課題として与えられたWebアプリケーションを制限時間内でチューニングし、ベンチマークツールによる得点を競う大会です。

本物の方は年1回開催され、賞金はなんと100万円。今年は9/17〜18に予選が行われますが、技術力やモチベーション向上の良い機会であることから、社内で開催される事例も増えているようです。
社内ISUCONにはpixivカヤックなどの事例があります。

その流れに乗ってペパボでも開催することになり、今日がその本番。
参加者は全員ではなく立候補ですが、新卒エンジニアはWebアプリ・Webオペレーション研修と学んできたタイミングなので時期的にもちょうどよく、研修の一環のような形で参加しました。

事前知識なしで突っ込むと何もできずに終わりかねないことから、事前に先輩からISUCONとは何かや、基本的な進め方のレクチャーは受けていました。

が、結果は……見事に撃沈。。。

実力を考えればハイスコアは難しいと思ってはいたが、最後までエラーが直せず完全にお手上げ状態になってしまった。
途中からベンチマークが失敗し続けたので、「ここの設定は知ってるぞ!」とできる範囲でチューニングしてもそれが正しいかどうかまったくわからず、闇の中をひたすら歩き続けるつらさだった。

速度が出なかったりエラーが出る原因は複雑に絡み合っていて、そのチューニング自体は正解だったけど実は主要因は別のところにあったとか、原因の見当がつかないと迷走して時間をロスすることになってしまう。

近視眼的になりすぎた

エラー対処をするうちに近視眼的になりすぎたのも反省点。
先輩によるレクチャーや参考記事は少し読んでいたので、MySQLのslow_query_logなど、まずきちんとログを読んで原因のあてをつけたりなど、開始当初はよい心構えでできたと思う。
しかしアプリに500エラーが頻発する問題が発覚。おそらくチューニングポイントとして用意されていたものだが、その原因が一向に特定できず、ベンチマークが全然通らなくなった焦りもあり、その対処で頭が一杯になってしまった。

今回の参考実装にはRubyとPHPが用意されていたので、Rubyでエラーが出続けるならPHPで試してみたらどうだろうとか、アプリケーションサーバはPumaだったがUnicornに変えてみるとか、試してみることはいろいろあった。
Unicornは研修でも使っていて比較的慣れているのもあり試したのだが、その作業タイミングでベンチマークツールがちょっと不安定になっており確認が有耶無耶になってしまった。
Unicorn化がうまくいっていなかったのか、変更はできたけどエラーは出たままだったのか、それとも単にベンチが不安定で失敗していただけだったのか……それもわからない。

アプリケーションに課題はいっぱいあったのに

ミドルウェアの対処に時間をかけすぎた結果、コードやデータベース構成をきちんと読み込んでアプリケーションを把握することができなかった。
「オペレーション(System Engineering)で点を守り、 プログラミング(Software Engineering)で点をとる」のとおりで、もっと早くアプリケーションコードの課題解決に入るべきだった。

リクエストのボトルネックを見るのにブラウザの開発者ツール使えばわかりやすいじゃんと気付いたのはだいぶ後になってからだし、画像を毎回DBから取り出していることがわかって、ここを静的に、あるいはキャッシュにできればよさそうだとわかってももう時間はなかった。
SQLのチューニングも、データベースの行数を確認して効果がよく出そうなポイントだけに絞るとか、SELECT *を必要なカラムだけ指定する基本のリファクタだけはやるとか、慣れていなくてももっとやりようがあったなと。

「原因の切り分け」や「優先順位」って本当に大事だなと痛感する一日だった。
うう……次はリベンジするぞ。

参加したチームの皆様、そして環境構築・運営のtnmtさんとpyamaさん、おつかれさまでした。