読者です 読者をやめる 読者になる 読者になる

まっしろけっけ

めもてきなやーつ

Rubyエンジニアが語る、2016年の振り返りとこれからに登壇して来たよ

プログラミング 開発 web ruby rails 雑談

株式会社 Speee さんと自分が勤めるペパボが共同で開催した下記のイベントに登壇して来ました。

speee.connpass.com

経緯

経緯としては、CTL になったし喋らない?って声をかけられたからなのですが、
個人的に昨年のアウトプットが圧倒的に少ないこと、
その反面インプットは大量にあり話せることはいっぱいあるぜ!って感じだった即答で喋りますって言った記憶がある。

発表内容

当日の資料は下記
最初作って練習してみたら 30 分超えの大作になってしまったのでだいぶ削った。

www.slideshare.net

内容としては 2016 年に行った minne の API の改善の一部を紹介
問題だと思ったことを 1 つずつ改善しましたって話なのですが、
この問題に対して技術的負債と言う人もいると思いますが、
自分は特に負債とは思っていなくて minne の急成長には必要なものだったと思っていて、
管理のしやすさとかよりも、急成長する為にスピードを優先した結果なので必要なものだったと捉えています。
成長の機会を逃し、サービスが終了しては本末転倒なので...

また、ペパボでは今後を見据えてこういうことの改善をしたいですと言えば、
非エンジニアの人も納得してくれる環境があるのでいいバランスが出来ているのではないかと思っています。

発表後の質問や懇親会でも質問を幾つか頂いたのでそれなりにみんな興味のある内容だったのかなという感じでよかった。

イベント全体

Speee さんのオシャレなオフィスのカフェで開催され、
PHP から Ruby への移行の話を聞きながら 3 年くらい前に自分もやったな...って思ったり、
縦に長すぎるコントローラやばいな...と言う話、独自言語辛いという話など面白い内容が多かったのではという感じ。

懇親会でも質問を幾つか頂いたり Speee さんの若者に色々お話を伺ったり楽しかった。

最後に

最初の方に CTL になったとさらっと書いたのですが、それについては別で記事を書く予定です。

昨年のアウトプットが圧倒的に少なかったので今年は 2 ヶ月に 1 回くらいのペースでなんか喋りたいなという気持ちでいます。
昨年は API 改善,検索改善,開発基盤改善とかやりつつ普通の機能追加などの開発やってたりしたのでそこら辺の話とか
昨年から今年 1 月に Rails 5 対応してるのでそこら辺とかネタはあるのでまぁ大丈夫だろうという気持ち。

2016 年振り返り

雑談

はじめに

約 4 ヶ月ぶりのブログ...
今回は 2016 年の振り返りをしてみようと思います。

お仕事

シニアエンジニアになったり、テクニカルリードになったりした。
ペパボに入社した時から 1 年以内にシニアになると決めてたのでなれてよかったね。

技術的な話だと前半は Elasticsearch 使って検索周りで色々やってた。
後半は API のテクニカルリードとして検索や他になんかやってたら Apple Pay の対応やることになったのでそればっかりやってた。
Apple Pay は色々な意味で辛かったりしたけど、Apple公式サイトに minne が載ったり新 MBP の CM に使って貰ったりしたので報われたなという感じ。
Apple Pay 終わった後は Rails 5 の対応とかやってる(現在進行形)

2017 年から僕自身の minne 内で求められる役割が変わるという話を 11 月頭に聞いて、
人生で初めて 11 月から次の年のことを真剣に考えてた。

API のテクニカルリードとしてもっと API 関連のあれこれやれればよかったというのが心残り

アウトプット

OSS

何個か gem 作ったり、バグ見つけて PR 出したりとかしてた。
ここら辺は別で記事を書きたい気持ち。

ブログ

...あまり書けてない...ただのメモのつもりで書いているブログなのでもっとメモを残していこうというお気持ち。

執筆

WEB+DB PRESS Vol.92 の Web 開発新人研修の web アプリケーションのパートを担当した。
今読み返すとまだまだな部分が多いなと感じるが本当に良い経験になった。

発表

社外で何か発表したということはなかった気がする。
社内では幾つか発表してた。

今年は社内、社外含めて幾つか声を掛けて貰ったりしてるので頑張っていく気持ち。

その他

お見合い

面白年賀状をもらった


読書

技術書 20 冊
ビジネス書(?) 5 冊
数学関連 2 冊

記憶にあるのだけでこんなもん。
本は実物を持っていたい + 実物をさらっと眺めて買いたいという謎のこだわりがあるので
Amazon とかに購入履歴があまり残ってないので把握できないのが辛いところ

あと、本読む速度が遅いので速読スキルが欲しい...

旅行

30 手前で初の一人旅をした。
行き先は京都だったのだが同僚が京都の便利情報を次々教えてくれて便利だった。
歩き疲れたけどめっちゃ楽しかったので、また旅したい。

ちなみにこの旅の為にカメラ買った。

運動

ほぼ毎週スポーツをしているし、ジムにも週 2,3 行っているが今年は週 2, 3 いけない週が結構あったなぁという記憶
忙しかろうが強い意志で週 2 は行きたい。

健康

5 月頭、8 月中旬、 11 月末と 3 ヶ月 + 1 週間くらいの周期で急性腸炎になってて辛い感じ...
真剣に健康について考えていこうという気持ちになった。

ペパボに転職して 1 年経ってた

雑談

はじめに

転職から 1 年経っていたのでペパボに入って何してたとか、
思ったことを書いていく。

転職した経緯は下の記事に書いてあります。

shiro-16.hatenablog.com

なにしてたの?

  • EC で 2 ヶ月だけカートの開発してた
  • minne で API 開発することになった
  • 検索のあれこれをやることになった
  • 本に記事を書いた
  • お見合いした
  • API チームのテクニカルリードになった
  • シニアエンジニアになった

ざっくりという感じ(他にもあるけど)

EC で 2 ヶ月だけカートの開発してた

EC 事業の求人に応募して採用されたので、EC 事業で働き始めた。
なぜ 2 ヶ月だけかというと社内で minne というサービスの API 開発者を募集していたので応募して通ったから。

2 ヶ月で応募するということで、悩みはしたのですよ。
EC 事業の求人に応募して採用されたので申し訳ないなとか、入社 2 ヶ月で異動ってとかその他いろいろ
申し訳ないなというのは本当に思っている

でも、単純に面白そうだなって思ったので面白そうだと思ったらとりあえず一回やってみるという考えで生きてるのと
アプリに関わる開発から離れてみてやっぱりそっちが自分には合ってるのかなという考えから。(別に EC の仕事がつまらなかったとかでは全然ない)

minne で API 開発することになった

ということで minne の API 開発することになり、minne チームは当時はフロアが違ったり、福岡と一緒に開発を行っているということもあり独特な雰囲気があったという気がしている。

  • hsbt さんと仕事で絡む機会が大幅に増えた
  • class 設計の知識が大幅に向上した(気がしている)
  • web アプリケーション開発以外の面白いと思えるものが見つかった
  • 目標にするべき人と仕事が出来ている

他にも多々あるが上記の理由から結果的に minne に来て正解だったなと思った。

hsbt さんと仕事で絡む機会が大幅に増えた

これは説明する必要もないのだが、自分自身がペパボに転職した理由の 1 つだったので単純に嬉しいという感じ

class 設計の知識が大幅に向上した(気がしている)

レビュー等を通して class 設計だったり綺麗なコードのとは?とか、それに対して妥協しない姿勢というものを身につけることができた。
今までも出来ていたつもりでいたが、ワンランク上のステージでそういうのを考えられるようになった気がする。

既にペパボを退職してしまった人だが、その方にそういうことに関して感心させられることが多々ありその人みたいになりたいと思ったこと。
その人が退職するということを知った日から出来る限り盗めるところは盗もうと思い行動する(コードを書く)ようになった。
あわせて年末にリファクタリングの本を読みながらコード書いてたのもよかった点かなと思う。

※あくまで個人の感想です。

web アプリケーション開発以外の面白いと思えるものが見つかった

これは後述する、検索のこととか画像のこととか
web アプリケーションの一部といえば一部なのだが…

目標にするべき人と仕事が出来ている

class 設計の知識が...で書いた方の他にも、今目標にしている人がいるのだが
自分の場合目標にする人が近くにいる方がやる気が出るっぽい。

目標にするというか、開発が好きだから負けたくない人、勝ちたい人といった方が良いのかもしれない。

検索のあれこれをやることになった

minne の検索をいい感じにするみたいな話になった時に、面白そうだなって思ったのでやってみたいと手を挙げたのが始まり。
ペパボは手を挙げればやらせて貰える環境なのでとても良い。
日本語って難しいなとか思いながら、いい感じの検索とは?みたいなのを日々やっていて凄く難しいと思う反面凄く楽しいなと思いながら開発している。

その一環で画像を解析して物体を抽出してその色を判別するみたいなことをやって色検索をリリースすることが出来た。
画像を解析するのも楽しいなと思い始めた。

ここら辺は結構ネタを持っているので、どこかで発表したいと思っている。

本に記事を書いた

shiro-16.hatenablog.com

上記参照

今年の目標の一つ言語化を頑張るという自分が苦手としていることに挑戦するいい機会だと思った。
自分の頭の中で理解している技術的なことを他人が理解出来る言語にするのはとても難しいというかとても苦手なので、
出来るだけがんばっていこうというのを目標の一つにしていて日々の業務で作成している PR や issue 等でも言語化することに気をつけて日本語を書くようにしている。
そういう意味でも記事を書けたことはとても勉強になることが多かったし、みんなこんな感じで記事をかいてるのかぁなるほどとなれたのはよかった。

お見合いした

haken.inte.co.jp

面白そうだと思ったのでやった(強制されたとかは無い)

API チームのテクニカルリードになった

API の開発を行う人が増えてテクニカルリードというものをやることになった。
テクニカルリードはこちらの記事が参考になりそう。
とりあえず頑張っているという気持ち

シニアエンジニアになった

ペパボの職位制度に関してはここらへん
シニアになって思うのはペパボのいるだけで成長できる環境というのはその通りだと中の人として思うのだが、
シニア以上になる人はそれだけでは満足せずに自分から成長する為の何かを取りに行くことが出来る人なのかなと思う。

自分の場合は検索周りのこととか上に書いてないことも面白そうだからやってみるかという思いから取りにいって、
一定の成果を出し、終わってみたら成長を感じられたということが多く結果としてシニアになれたのでシニアになる為にとかではないのだが…

※あくまで個人の感想です。

でこれがシニアエンジニアになった際の抱負(?)
シニアの面談のフィードバックであんちぽさんに頂いたノリが良いっていうのは個人的にとても気に入っている。

やっておきますというのはタイポとかではなく、今までだと「いい感じによろしく」と言われてからの「やります!」という返事だったのを、
これからは「いい感じによろしく」と言われた際に「やっておきました!」と言える機会を増やすという意味での(言われる前に先に)やっておきますという意味です。

ということで頑張ります。

さいごに

ということで約 1 年何やってたかというのとペパボで働いて感じたことを書いてみた。
優秀な人が多くて毎日楽しく開発出来るという環境なので最高かという気持ち


最後に自戒の念を込めて貼っておきます…

MySQL の binlog について調べたメモ

mysql web 開発 プログラミング ツール

MySQL の binlog について

実際に実行された更新系クエリの情報が記述されていてなんらかの理由によりデータが壊れた際の
データ復旧とかにも役にたつ。

binlog の format には以下の 3 種類ある

フォーマットの種類 設定値(文字列) 設定値(数字) 備考
ステートメントベース STATEMENT 1 実際に実行された SQL を記録
行ベース ROW 2 実際に変更された行のデータの情報を記録
ミックス MIXED 0 基本的にはステートメントベースと同じで非決定性のクエリの際は行ベースと同じ形式のログを出力する

ここら辺は DB server を構築する際にレプリケーションとかを考えると思うので
基本的には理解している内容だと思われます。

今回は binlog の中身を除いて実際にどうなってるの?というところを調べた。

実際にログを出力させて比べる

環境
my.cnf

my.cnf を変更して binlog を出力するようにする

[mysqld]
log_bin
binlog_format = 1 # ステートメントベースのログを出力する
table

今回は下記の table を使用する

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;
使用する SQL
INSERT INTO users SET name = UUID(), created_at = NOW(), updated_at = NOW(); # 非決定性のクエリ
INSERT INTO users SET name = "test", created_at = NOW(), updated_at = NOW();

ステートメントベース

$ mysqlbin mysql-bin.000001
# 一部抜粋
BEGIN
/*!*/;
# at 247
# at 279
#160612 14:56:46 server id 1  end_log_pos 279 CRC32 0xc624c39f 	Intvar
SET INSERT_ID=20/*!*/;
#160612 14:56:46 server id 1  end_log_pos 476 CRC32 0x6a52b700 	Query	thread_id=1	exec_time=0	error_code=0
use `db`/*!*/;
SET TIMESTAMP=1465711006/*!*/;
INSERT INTO users SET name = UUID(), created_at = NOW(), updated_at = NOW()
/*!*/;
# at 476
#160612 14:56:46 server id 1  end_log_pos 507 CRC32 0xf803a15e 	Xid = 21
COMMIT/*!*/;
# at 507
#160612 14:56:53 server id 1  end_log_pos 634 CRC32 0xd617f39d 	Query	thread_id=1	exec_time=0	error_code=0
SET TIMESTAMP=1465711013/*!*/;
BEGIN
/*!*/;
# at 634
# at 666
#160612 14:56:53 server id 1  end_log_pos 666 CRC32 0xe6f7f9d2 	Intvar
SET INSERT_ID=21/*!*/;
#160612 14:56:53 server id 1  end_log_pos 863 CRC32 0x765b9f4d 	Query	thread_id=1	exec_time=0	error_code=0
SET TIMESTAMP=1465711013/*!*/;
INSERT INTO users SET name = "test", created_at = NOW(), updated_at = NOW()
/*!*/;
# at 863
#160612 14:56:53 server id 1  end_log_pos 894 CRC32 0x828b94cf 	Xid = 22
COMMIT/*!*/;

確かに発行された SQL がそのまま出力されている

行ベース

$ mysqlbin mysql-bin.000002
# 一部抜粋
BEGIN
/*!*/;
# at 220
#160612 14:58:55 server id 1  end_log_pos 295 CRC32 0xa71dbfff 	Table_map: `db`.`users` mapped to number 83
# at 295
#160612 14:58:55 server id 1  end_log_pos 383 CRC32 0xb2425e19 	Write_rows: table id 83 flags: STMT_END_F

BINLOG '
H/pcVxMBAAAASwAAACcBAAAAAFMAAAAAAAEAGGJsb2dfc2FtcGxlc19kZXZlbG9wbWVudAAFdXNl
cnMABAMPEhIE/QIAAAL/vx2n
H/pcVx4BAAAAWAAAAH8BAAAAAFMAAAAAAAEAAgAE//AWAAAAJABiZjYwNTc0MC0zMDYyLTExZTYt
OGQ2Zi0yZjg2MTFjNWE2ZjGZmZjut5mZmO63GV5Csg==
'/*!*/;
# at 383
#160612 14:58:55 server id 1  end_log_pos 414 CRC32 0xf290e6c8 	Xid = 21
COMMIT/*!*/;
# at 414
#160612 14:58:57 server id 1  end_log_pos 514 CRC32 0xc1908135 	Query	thread_id=1	exec_time=0	error_code=0
SET TIMESTAMP=1465711137/*!*/;
BEGIN
/*!*/;
# at 514
#160612 14:58:57 server id 1  end_log_pos 589 CRC32 0x96559f32 	Table_map: `db`.`users` mapped to number 83
# at 589
#160612 14:58:57 server id 1  end_log_pos 645 CRC32 0x56be64d2 	Write_rows: table id 83 flags: STMT_END_F

BINLOG '
IfpcVxMBAAAASwAAAE0CAAAAAFMAAAAAAAEAGGJsb2dfc2FtcGxlc19kZXZlbG9wbWVudAAFdXNl
cnMABAMPEhIE/QIAAAIyn1WW
IfpcVx4BAAAAOAAAAIUCAAAAAFMAAAAAAAEAAgAE//AXAAAABAB0ZXN0mZmY7rmZmZjuudJkvlY=
'/*!*/;
# at 645
#160612 14:58:57 server id 1  end_log_pos 676 CRC32 0x24726578 	Xid = 22
COMMIT/*!*/;

な、なるほどわからん
もっと詳しく見れるようにオプションを追加する

$ mysqlbinlog -vvv --base64-output=DECODE-ROWS mysql-bin.000002
# 一部抜粋
BEGIN
/*!*/;
# at 220
#160612 14:58:55 server id 1  end_log_pos 295 CRC32 0xa71dbfff 	Table_map: `db`.`users` mapped to number 83
# at 295
#160612 14:58:55 server id 1  end_log_pos 383 CRC32 0xb2425e19 	Write_rows: table id 83 flags: STMT_END_F
### INSERT INTO `db`.`users`
### SET
###   @1=22 /* INT meta=0 nullable=0 is_null=0 */
###   @2='bf605740-3062-11e6-8d6f-2f8611c5a6f1' /* VARSTRING(765) meta=765 nullable=1 is_null=0 */
###   @3='2016-06-12 14:58:55' /* DATETIME(0) meta=0 nullable=0 is_null=0 */
###   @4='2016-06-12 14:58:55' /* DATETIME(0) meta=0 nullable=0 is_null=0 */
# at 383
#160612 14:58:55 server id 1  end_log_pos 414 CRC32 0xf290e6c8 	Xid = 21
COMMIT/*!*/;
# at 414
#160612 14:58:57 server id 1  end_log_pos 514 CRC32 0xc1908135 	Query	thread_id=1	exec_time=0	error_code=0
SET TIMESTAMP=1465711137/*!*/;
BEGIN
/*!*/;
# at 514
#160612 14:58:57 server id 1  end_log_pos 589 CRC32 0x96559f32 	Table_map: `db`.`users` mapped to number 83
# at 589
#160612 14:58:57 server id 1  end_log_pos 645 CRC32 0x56be64d2 	Write_rows: table id 83 flags: STMT_END_F
### INSERT INTO `db`.`users`
### SET
###   @1=23 /* INT meta=0 nullable=0 is_null=0 */
###   @2='test' /* VARSTRING(765) meta=765 nullable=1 is_null=0 */
###   @3='2016-06-12 14:58:57' /* DATETIME(0) meta=0 nullable=0 is_null=0 */
###   @4='2016-06-12 14:58:57' /* DATETIME(0) meta=0 nullable=0 is_null=0 */
# at 645
#160612 14:58:57 server id 1  end_log_pos 676 CRC32 0x24726578 	Xid = 22
COMMIT/*!*/;

column 名が書かれているわけではなく @1 とか書かれてあるのだなぁ。
定義した table の column の順番通り @1 = id, @2 = name, @3 = created_at, @4 = updated_at という順番っぽい
UUID() も展開後の文字列が入っているのがわかる。

ミックス

$ mysqlbin mysql-bin.000003
# 一部抜粋
BEGIN
/*!*/;
# at 220
#160612 15:05:14 server id 1  end_log_pos 295 CRC32 0x3b4cb14b 	Table_map: `db`.`users` mapped to number 83
# at 295
#160612 15:05:14 server id 1  end_log_pos 383 CRC32 0x9905bb6a 	Write_rows: table id 83 flags: STMT_END_F

BINLOG '
mvtcVxMBAAAASwAAACcBAAAAAFMAAAAAAAEAGGJsb2dfc2FtcGxlc19kZXZlbG9wbWVudAAFdXNl
cnMABAMPEhIE/QIAAAJLsUw7
mvtcVx4BAAAAWAAAAH8BAAAAAFMAAAAAAAEAAgAE//AYAAAAJABhMTY1OWFmNi0zMDYzLTExZTYt
OTc1Yi1hZjExNDczMDFkMDGZmZjxTpmZmPFOarsFmQ==
'/*!*/;
# at 383
#160612 15:05:14 server id 1  end_log_pos 414 CRC32 0x84766030 	Xid = 21
COMMIT/*!*/;
# at 414
#160612 15:05:16 server id 1  end_log_pos 541 CRC32 0xe4c9b7a8 	Query	thread_id=1	exec_time=0	error_code=0
SET TIMESTAMP=1465711516/*!*/;
BEGIN
/*!*/;
# at 541
# at 573
#160612 15:05:16 server id 1  end_log_pos 573 CRC32 0x10f97ca5 	Intvar
SET INSERT_ID=25/*!*/;
#160612 15:05:16 server id 1  end_log_pos 770 CRC32 0xd9adc7e3 	Query	thread_id=1	exec_time=0	error_code=0
use `db`/*!*/;
SET TIMESTAMP=1465711516/*!*/;
INSERT INTO users SET name = "test", created_at = NOW(), updated_at = NOW()
/*!*/;
# at 770
#160612 15:05:16 server id 1  end_log_pos 801 CRC32 0xa8cd90ff 	Xid = 22
COMMIT/*!*/;

本当にミックスされている
もっと詳しく見てみる

$ mysqlbinlog -vvv --base64-output=DECODE-ROWS mac-no-MacBook-Pro-bin.000003
# 一部抜粋
BEGIN
/*!*/;
# at 220
#160612 15:05:14 server id 1  end_log_pos 295 CRC32 0x3b4cb14b 	Table_map: `db`.`users` mapped to number 83
# at 295
#160612 15:05:14 server id 1  end_log_pos 383 CRC32 0x9905bb6a 	Write_rows: table id 83 flags: STMT_END_F
### INSERT INTO `db`.`users`
### SET
###   @1=24 /* INT meta=0 nullable=0 is_null=0 */
###   @2='a1659af6-3063-11e6-975b-af1147301d01' /* VARSTRING(765) meta=765 nullable=1 is_null=0 */
###   @3='2016-06-12 15:05:14' /* DATETIME(0) meta=0 nullable=0 is_null=0 */
###   @4='2016-06-12 15:05:14' /* DATETIME(0) meta=0 nullable=0 is_null=0 */
# at 383
#160612 15:05:14 server id 1  end_log_pos 414 CRC32 0x84766030 	Xid = 21
COMMIT/*!*/;
# at 414
#160612 15:05:16 server id 1  end_log_pos 541 CRC32 0xe4c9b7a8 	Query	thread_id=1	exec_time=0	error_code=0
SET TIMESTAMP=1465711516/*!*/;
BEGIN
/*!*/;
# at 541
# at 573
#160612 15:05:16 server id 1  end_log_pos 573 CRC32 0x10f97ca5 	Intvar
SET INSERT_ID=25/*!*/;
#160612 15:05:16 server id 1  end_log_pos 770 CRC32 0xd9adc7e3 	Query	thread_id=1	exec_time=0	error_code=0
use `db`/*!*/;
SET TIMESTAMP=1465711516/*!*/;
INSERT INTO users SET name = "test", created_at = NOW(), updated_at = NOW()
/*!*/;
# at 770
#160612 15:05:16 server id 1  end_log_pos 801 CRC32 0xa8cd90ff 	Xid = 22
COMMIT/*!*/;

非決定性のクエリの際は行ベースと同じ形式のログを出力することがわかった。

mysqlbinlog コマンドのオプション + SQL

よく使いそうなオプションをまとめる

$ mysqlbinlog -h host --read-from-remote-server mysql-bin.000001 # リモートサーバの binlog を見ることができる
$ mysqlbinlog --start-datetime="2016-01-01 00:00:00" --stop-datetime="2016-01-01 12:00:00" mysql-bin.000001 # 日時を指定して binlog を見ることができる

binlog 情報を出力してくれる SQL をまとめる

mysql> SHOW GLOBAL VARIABLES LIKE 'binlog_format'; # binlog format を表示
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | MIXED |
+---------------+-------+

mysql> SHOW BINARY LOGS; # server の binlog 一覧を表示
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       531 |
| mysql-bin.000002 |       437 |
| mysql-bin.000003 |       933 |
+------------------+-----------+

mysql> SHOW BINLOG EVENTS; # binlog 内のイベントを表示
+------------------+-----+-------------+-----------+-------------+----------------------------------------------------------------------------------------+
| Log_name         | Pos | Event_type  | Server_id | End_log_pos | Info                                                                                   |
+------------------+-----+-------------+-----------+-------------+----------------------------------------------------------------------------------------+
| mysql-bin.000001 |   4 | Format_desc |         1 |         120 | Server ver: 5.6.27-log, Binlog ver: 4                                                  |
| mysql-bin.000001 | 120 | Query       |         1 |         247 | BEGIN                                                                                  |
| mysql-bin.000001 | 247 | Intvar      |         1 |         279 | INSERT_ID=16                                                                           |
| mysql-bin.000001 | 279 | Query       |         1 |         477 | use `db`; insert into users  set name = UUID(), created_at = NOW(), updated_at = NOW() |
| mysql-bin.000001 | 477 | Xid         |         1 |         508 | COMMIT /* xid=24 */                                                                    |
| mysql-bin.000001 | 508 | Stop        |         1 |         531 |                                                                                        |
+------------------+-----+-------------+-----------+-------------+----------------------------------------------------------------------------------------+

最後に

ということで今回は MySQL の binlog についての format による違いを確認してみました。
binlog にどのような情報が記述されているか最低限覚えておくと
ここぞという時に役に立つかと思います

Ruby と Google Cloud Platform の Cloud Vision API で画像を解析して貰う

gem ruby web ツール プログラミング 開発

Vision API is 何?

画像のさまざまな情報を解析してくれる API です。

物体検知、有害コンテンツ検知、ロゴ検知、ランドマーク検知、OCR、顔検知、色検知等を行ってくれる。

料金は下記に詳細が書いてありますが 1000 ユニット / 月 は無料で利用出来るので、
どんなものか遊んでみたいとか Google すげぇって思ったりするのは問題ないかと思います。
cloud.google.com

実際に使って見る

事前準備

事前準備としては Google Cloud Platform のアカウントを作成して、
API KEY を取得しておく必要があります。(クレジットカードの登録が必要)

google-api-client を使う

Google の様々な API の client がまとまっている gem の google-api-client を使って Vision API に画像を投げてみます。
物体検知と色検知を指定しています。

$ gem install google-api-client
require 'google/apis/vision_v1'
Vision = Google::Apis::VisionV1
vision = Vision::VisionService.new
vision.key = "API KEY"

request = Google::Apis::VisionV1::BatchAnnotateImagesRequest.new(
  requests: [
    {
      image:{
        content: File.read("1.png")
      },
      features: [
        {
          type: "LABEL_DETECTION",
          maxResults: 10
        },
        {
          type: "IMAGE_PROPERTIES",
          maxResults: 10
        }
      ]
    }
  ]
)

vision.annotate_image(request)

gcp-vision を使う

google-api-client は require した際に一瞬固まる(load に時間がかかる)のが気になったので Vision API 専用の軽量な client を自作してみた。

$ gem install gcp-vision
require 'gcp/vision'

Gcp::Vision.configure do |config|
  config.api_key = "API KEY"
end

request = {
  requests: [
    {
      image:{
        content: Base64.encode64(File.read("1.png"))
      },
      features: [
        {
          type: "LABEL_DETECTION",
          maxResults: 10
        },
        {
          type: "IMAGE_PROPERTIES",
          maxResults: 10
        }
      ]
    }
  ]
}

Gcp::Vision.annotate_image(request)

レスポンスとしてどんな情報が返ってくるか?

実際にどんな情報が Vision API から返って来るのか?
ということで自分が普段 SNS 等のアイコンに使用している下記の愛犬の画像を Vision API に投げてみました。
f:id:shiro-16:20160508183558j:plain:w100

{
  "responses": [
    {
      "labelAnnotations": [
        {
          "mid": "/m/068hy",
          "description": "pet",
          "score": 0.98951507
        },
        {
          "mid": "/m/0bt9lr",
          "description": "dog",
          "score": 0.98687589
        },
        {
          "mid": "/m/04rky",
          "description": "mammal",
          "score": 0.9618566
        },
        {
          "mid": "/m/0jbk",
          "description": "animal",
          "score": 0.95587397
        },
        {
          "mid": "/m/02cyl6",
          "description": "maltese",
          "score": 0.89896905
        },
        {
          "mid": "/m/09686",
          "description": "vertebrate",
          "score": 0.89741188
        },
        {
          "mid": "/m/01lrl",
          "description": "carnivoran",
          "score": 0.85160905
        },
        {
          "mid": "/m/0kpmf",
          "description": "dog breed",
          "score": 0.77777779
        },
        {
          "mid": "/m/036hyn",
          "description": "toy dog",
          "score": 0.7
        },
        {
          "mid": "/m/0b26w3",
          "description": "schnoodle",
          "score": 0.68533921
        }
      ],
      "imagePropertiesAnnotation": {
        "dominantColors": {
          "colors": [
            {
              "color": {
                "red": 197,
                "green": 199,
                "blue": 195
              },
              "score": 0.53806108,
              "pixelFraction": 0.33916494
            },
            {
              "color": {
                "red": 86,
                "green": 84,
                "blue": 82
              },
              "score": 0.030347142,
              "pixelFraction": 0.046761185
            },
            {
              "color": {
                "red": 220,
                "green": 230,
                "blue": 229
              },
              "score": 0.31318155,
              "pixelFraction": 0.19654006
            },
            {
              "color": {
                "red": 165,
                "green": 162,
                "blue": 158
              },
              "score": 0.047778718,
              "pixelFraction": 0.19640999
            },
            {
              "color": {
                "red": 53,
                "green": 55,
                "blue": 55
              },
              "score": 0.021588614,
              "pixelFraction": 0.016324142
            },
            {
              "color": {
                "red": 123,
                "green": 116,
                "blue": 115
              },
              "score": 0.017005477,
              "pixelFraction": 0.10022113
            },
            {
              "color": {
                "red": 63,
                "green": 92,
                "blue": 77
              },
              "score": 0.009515699,
              "pixelFraction": 0.012291883
            },
            {
              "color": {
                "red": 25,
                "green": 28,
                "blue": 29
              },
              "score": 0.0089049507,
              "pixelFraction": 0.0029916754
            },
            {
              "color": {
                "red": 35,
                "green": 56,
                "blue": 49
              },
              "score": 0.0033917534,
              "pixelFraction": 0.0018210198
            },
            {
              "color": {
                "red": 89,
                "green": 121,
                "blue": 105
              },
              "score": 0.0033548647,
              "pixelFraction": 0.017364724
            }
          ]
        }
      }
    }
  ]
}

物体検知の結果は pet, dog, mammal, animal, maltese... 等が返ってきた。
dog だけではなく maltese といった感じで正確な犬種まで返って来るのには驚くばかりだ。

次に色検知だが RGB だとわかりづらいので下記のようにしてみた。
⬛︎⬛︎⬛︎⬛︎⬛︎
全体的に白いのでまぁこんな感じかぁ

最後に

その他の検知方法を使用したい場合などは下記のマニュアルに載っているので興味があれば調べてみるのが良いかと。
cloud.google.com

Elasticsearch の勉強会を社内で行なった話

elasticsearch rails web 開発 雑談

最近圧倒的インプットによって、圧倒的にアウトプットが減っている僕です。
ということでリハビリがてら 4 月の初めに Elasticsearch の勉強会を社内でやったのでそのことについて書いてみます。
そこまで技術的に深い話はないので期待しないでください。

勉強会の開催経緯

今のプロジェクトで検索に関してあれこれ頑張っていく中で Elasticsearch を使用することになり、
index の設計とか Rails から Elasticsearch 使うとことか作ったわけですが
チームメンバーから知見を共有してくれ!という要望があったのと自分自信も自分だけわかっても後々辛い感じになるだろうという感じだった + 弊社はいるだけで成長出来るらしいのでみんなを成長させようではないかという思いから、
やるぞ!ってなったのが 2 月末です。

で開催したのが 4 月初め...だいぶ遅い...(反省はしている)

実際の内容

Elasticsearch とは?みたいなところをざっくり説明した後に、
tokenizer, filter, analyzer の説明を行なった後に実際に設定している settings 周りの解説を行なった。

その後、実際に設定している mappings 周りの説明をしたり、ドキュメントが登録される際の流れや、クエリを投げた際の流れを説明

最後に、ハンズオンとして index を定義した後に基本的な CRUD + 検索クエリを投げる、現在プロジェクトで実際に投げられているクエリの解説という流れで行なった。

若干資料作成をミスって手順がグダッてしまった感はあったが、所々で @monochromegane さんがナイスな質問を投げてくれたので参加者のみんなの理解が深まったのでは?と勝手に思っている。

同時間内で @yano3クラスタについてより詳しく話してもらう予定だったのだが、
時間が押してしまい別日で説明をしてもらった。その内容が下記の記事になります。

yano3.hatenablog.jp

最後に

Elasticsearch をリアルタイムログ解析以外で触ったことがなかったので色々大変だったのですがそれはまた別のお話。
やるぞ!って言ってから 1 ヶ月経過したのは本当に反省している。
Elasticsearch を ES と略すのに若干の違和感を覚えている僕なのでした

圧倒的インプットによりネタはいっぱいあるので、またちょいちょいブログ書いていこうと思っています。。。

WEB+DB PRESS Vol.92 「Web開発新人研修」の一部を書きました。

雑談 開発 web

久しぶりのブログです。
4 月なのに 2016 年初ブログです。

本題

4 月 23 日発売の WEB+DB PRESS Vol.92 内の特集の一つである「Web開発新人研修」をペパボのエンジニアで寄稿させていただきました。
献本を頂いたのでざっくりと説明をしていこうと思います。
Web 開発とはどんなものなのかを浅く広く把握できる内容になっています。

自分は 3 章の「Web アプリケーションを作ろう」を担当しました。
Web アプリケーションの概要、フレームワークについて、Rails を使用して MVC を解説しながら、
ToDo アプリケーションを開発するという内容になっています。

コード自体は scaffold で作成されるファイルの中でも必要最低限なコードの作成と解説をしています。
scaffold は凄いのですが、凄過ぎてよくわからないけど動くという状況になることもあるかと思うので
このような形式で解説をさせて頂きました。


説明を行おうと思えば記事では触れていない部分もいくらでも説明出来るのですが、
今回は新人研修というのが目的の記事になるので、詳細な説明を省いている為説明不足な点も多いかと思います。
そのような点はイケメン先輩エンジニアが新人さんに教えてあげたり、逆に新人さんは先輩エンジニアにがんがん聞いていくのが良いのではないでしょうか

記事のまとめにも書いたのですが、Web アプリケーションを作るのは本当に楽しいので
今回の記事を読んでそのようなエンジニアが増えてくれたら嬉しく思います。

最後に、執筆の機会を下さった @june29 さん、執筆でお世話になりました株式会社技術評論社の池田さんありがとうございました。

gihyo.jp