mdqをさくっと使うツール「mdqi」の紹介

mdqiの紹介

Lobi事業部サービス基盤チームの長田です。

この記事はKAYAC Advent Calendar 2017の11日目です。


以前本ブログでmdqというツールを紹介しました。

今回はこれを少し便利にするツールを作ってみました。

モチベーション

mdqは複数のデータベースにクエリを発行して、結果をまとめてくれる便利なやつです。 データベースを水平分割している環境において、調査・集計作業が格段に楽になります。

JSONフォーマットで出力されるため、jqコマンドなどを使って再利用しやすいのですが、 「ちょっと集計して中身を見たいだけなんだけどなー」という場合、つまり人が読む場合にはちょっと読みづらいです。

mdqi

と、いうわけでmdqのインターフェイスとなるmdqiというツールを作ってみました。

mdqのインターフェイスとして動作します。 mdqと同じくGo製です。

mdqが出力するJSONをパースしてmysqlcliライクに表示するのが主な機能です。 mysqlcliとほぼ同じ感覚で使用することができます。

mdq> select * from jewel where month = 12;
+-----|----|--------------|-------+
| db  | id |     name     | month |
+-----|----|--------------|-------+
| db2 | 25 | turquoise    | 12    |
| db2 | 26 | lapis lazuli | 12    |
| db2 | 27 | blue zircon  | 12    |
| db2 | 28 | tanzanite    | 12    |
+-----|----|--------------|-------+

項目数が多いテーブル用にvertical表示があったり、

mdq> /display set vertical
mdq> select * from jewel where month = 12;
*************************** 1. row ***************************
  db    : db2
  id    : 25
  name  : turquoise
  month : 12
*************************** 2. row ***************************
  db    : db2
  id    : 26
  name  : lapis lazuli
  month : 12
*************************** 3. row ***************************
  db    : db2
  id    : 27
  name  : blue zircon
  month : 12
*************************** 4. row ***************************
  db    : db2
  id    : 28
  name  : tanzanite
  month : 12

設定したtagを覚えてプロンプトに表示してくれたりします。

mdq> /tag set main
mdq[main]>

コマンド履歴にも対応しています。

mdqは記憶を持たないツールなので、その記憶部分をmdqiが担当しています。

使用感

mdqiの導入で、サクッと調査したいときのストレスがだいぶ解消されました。 ちなみに、Lobiの本番環境では調査用のクエリ発行はredashから行うようにしているため、 mdq & mdqiは専ら開発環境での活躍がメインとなっております。

おわり

カヤックでは余計なストレスを減らして楽をするために時間を使いたいひとも募集しています!

明日は昨年好評だったキーボードのはなしの2017年版です。

お楽しみに。

Test::MoreからTest2::V0に移行した話

ソーシャルゲーム事業部のサーバサイドエンジニアの飛鷹です。
これはカヤックアドベントカレンダーの10日目の記事です。
今回は担当している案件でのTest2::V0を導入した話をします。

Test2導入経緯

担当している案件でperl 5.24からperl 5.26へのアップデート予定があり、バージョンを上げるのであればYAPC::Fukuokaで話のあったテスト結果がいい感じになると噂のTest2へと移行しようという試みでした。

Test2導入

Test2以前にもTest::SimpleやTest::Moreがあったように、Test2にも

Test2::Bundle::ExtendedOld name for Test2::V0
Test2::Bundle::MoreALMOST a drop-in replacement for Test::More.
Test2::Bundle::SimpleALMOST a drop-in replacement for Test::Simple.
Test2::V00Th edition of the Test2 recommended bundle.

http://search.cpan.org/~exodist/Test2-Suite/

など色々種類があります。
それぞれのテストの環境にあったものを選択してもらうといいのですが、今回は0Th edition of the Test2 recommended bundle. recommendと言われているTest2::V0を使うことにしました。

テストをとりまく環境

Test::MoreでもTest2::V0でも大きく書き方の変更はありませんでした。
基本的には使うモジュールやテスト関数の変更のみで対応できました。

テストファイルの書き方

  • テストファイルでuse t::Util;している
  • t/Util.pmの中でTest2::V0の@EXPORTをexportしたり、Test::mysqldを起動したり、Test::RedisServerを起動したりして、これさえuseしておけばDBでもKVSでも外部APIでも全てのテストができるようにしている
  • アプリケーションやマスタデータやデバッグ用のコードのテスト全てを含め、テストファイルは300程度、テストのステップ数は合計で3000程度

Test2への移行で変更したこと

Test::MoreからTest2::V0への移行で実際に使っていて置換したり実装の変更をしたものを一部紹介します。
この事例として紹介するものは私が担当した案件のもので、他の案件では使っているモジュールや書き方が異なると思うのでベストプラクティスとは限らないと思います。

use_okが使えない

Test::V0以外の他のTest::Suiteにもuseできるかのテスト関数がありませんでした。
use パッケージ名;ができていればそもそもuse_okのはずなのでTest::V0導入でuse_okのテストを削除しました。

is_deeplyが使えない

正確にはTest2::Bundle::Moreにはis_deeplyのテスト関数があるのですが実態はTest2::Tools::ClassicCompareの中にあり、Test2::Tools::ClassicCompare - Classic (Test::More style) comparison tools. との記載が。
せっかくTest2にしたから使わなくていいかという感じで、Test2::V0ではisやlikeで同様のことができるのでisとlikeに変更。

cmp_deeplyが使えない

Test2::Suiteにもないのでこちらもisとlikeに変更。

Test::Deep::Matcherが使えない

is_array_ref, is_hash_refなどTest::Deep::Matcherのテスト関数をかなり多用していました。
Test2::V0にはそれらしきものがなくhash in hashなどを取り出してテストするように置き換えるのは工数的に厳しかったので、t::Utilに自前で正規表現を書きExportするようにしました。
Ref::Utilというのもあるようですが今後あまり増える予定もないので自前でやっています。
正規表現がかなり雑ですが、以前は時間でもis_stringを使ってテストしていましたが専用の正規表現をカジュアルに追加できるので結果としては良かったかなと思っています。

# t::Util
sub is_array_ref { [] }
sub is_datetime  { qr/^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}$/ }
sub is_hash_ref  { +{} }
sub is_http_url  { qr/^http:\/\/.*$/ }
sub is_https_url { qr/^https:\/\/.*$/ }
sub is_integer   { qr/^[0-9]+$/ }
sub is_string    { qr/^[a-zA-Z0-9]+$/ }
sub is_text      { qr/.*/ }

# test
my $result = get_response();
like $result, +{
    player_id   => is_integer,
    created_at  => is_datetime,
    friend_ids  => is_array_ref,
};

Test::Mock::Guard call_countが使えない

テストに欠かせないTest::Mock::Guardですが、Test2ではメソッドをモックするものとしてTest2::Mockがあります。
しかしモックしたメソッドを何回呼ばれたかを知るcall_countっぽい機能がない...
こちらもかなり使っていて自前で書き換えるのも辛かったのでモックはTest2::Mockへの移行は一旦留まりました。

See also

参考にさせていただきました。 ありがとうございます。

http://akiym.hateblo.jp/entry/2017/07/09/214116 http://kichijojipm.hatenablog.com/entry/2017/04/08/234936

まとめ

今回はTest2::Suiteの読み込みからはじまり、テストファイルが多いこともありやることは結構ありました。
途中Test2::Bundle::Moreなら後方互換がかなりありそうなので、recommendを信じすぎてしまったか...と思いましたがなんとかTest2::V0導入できました。

今回軽いノリで移行をスタートしてしまったので、雑になった部分もあって当たり前のことながら

  • 使用しているテスト関数全ての洗い出し
  • どのテスト関数がTest2::Suiteのモジュールに当てはまるのか
  • どのテスト関数を移行するのかしないのか
  • テスト関数が不足していた場合Test2::Suiteへ追加のPRを出せないか

をしっかり決めたうえで移行するとより綺麗で平和な開発ができるのかなと思いました。

明日11日目のカヤックアドベントカレンダーは、@handlenameさんです!

面白法人カヤックでは、空前絶後の超絶怒涛のPerl Monger、Perlを愛し、Perlに愛された男(女性でもPerlを愛していない方でも可)を募集しております!