NeverBlog::Likk::Unexistable;

見なかったことにして下さい

Perlのテストを `Test::Spec` から `Test2::Tools::Spec` に移行した

Perl でテストを書いてるみなさん。 Test2 にはもう慣れましたよね?私は全然慣れてません。

ということで、最近、個人のプロジェクトで書かれてるテストを Test2 にしました。

その際、それまでのテストを Test::Spec で書いていたので、Test::Tools::Spec に移行させることにしました。 Test::SpecRubyRspec 風に書くことができるモジュールです。

前提として Perl 5.40 での話で、Perlのバージョンによっては Test2 の最新を cpanm などでインストールする必要があります。(5.40 から Test2::Suite がコア入りした)

さくっと置き換えられたもの

use

use Test::Spec; を消して use Test2::V0; se Test2::Tools::Spec; を追加

-use strict;
-use warnings;
-use utf8;
-
-use Test::Spec;
+use 5.40.0;
+use Test2::V0;
+use Test2::Tools::Spec;

runtest

runtests unless caller を消して done_testing を追加 そのまま置き換えられるけど、それぞれ意味することは違うので、理解したうえで置換。

-# XXX: forkprove has caller
-# runtests unless caller;
-runtests();
+done_testing;

context

s/context/describe/g する

-    context 'case call run method without arguments' => sub {
+    describe 'case call run method without arguments' => sub {
         it 'when returns undef' => sub {
             my $res = Oden::Command::AYT->run();
             is $res, undef;
         };
     };

before, after,

all, each まで含めた関数名になり、名前が必要になる。単純に置換 s/before\sall/before_all "XXX"/ して後で埋めるのでもよい。

-    before all => sub {
+    before_all "setup" => sub {
 -    context 'case non-empty message' => sub {
-        before all => sub {
+    describe 'case non-empty message' => sub {
+        before_each "create_test_message" => sub {
-    after all => sub {
+    after_all "cleanup"=> sub {

around

基本的に before, all とやることは同じ。yield()shift->() に置換しても良いが、変数に逃がしておくと安全

-        context "case thread_id is not set" => sub {
-            around {
+        describe "case thread_id is not set" => sub {
+            around_all "mockup" => sub {
+                my $tests = shift;
                 $hash->{api} = Oden::API::Discord->new(token => $hash->{valid_token}, interval => 0);
 
-                yield;
+                $tests->();
 
                 delete $hash->{api};
             };

stubs(mock)

しっかり書き換えが必要。 これは Test2::Tools::Spec ではなく、Test2::Tools::Mock に機能がある。 use Test2::V0 するだけで読み込んでくれる。

Modiule->stubs(+{mock "Modiule" => ( にしつつ、override 配列にいれる必要がある。 動的にメソッドが生えるものは override できないので注意。 Moops の場合は add で通ったがダメなパターンもあるかもしれない。

overrideの例

              $hash->{api} = Oden::API::Discord->new(token => $hash->{invalid_token}, interval => 0);
 
-                $hash->{stubs}->{furl} = Furl->stubs(+{
-                    request => sub {
-                        Furl::Response->new(
-                            1,
-                            '401',
-                            "Unauthorized",
-                            +{
-                                'content-type' => 'application/json'
-                            },
-                            q|{"message": "401: Unauthorized", "code": 0}|
-                        );
-                    },
-                });
-
+                $hash->{mocks}->{furl} = mock "Furl" => (
+                    override => [
+                        request => sub {
+                            Furl::Response->new(
+                                1,
+                                '401',
+                                "Unauthorized",
+                                +{
+                                    'content-type' => 'application/json'
+                                },
+                                q|{"message": "401: Unauthorized", "code": 0}|
+                            );
+                        },
+                    ],
+                );

add の例。

-            $hash->{stubs}   = AnyEvent::Discord->stubs(
-                token            => sub { return 'your token'; },
-                user_agent       => sub { return 'Perl-AnyEventDiscord/' . shift->VERSION },
-                _ws_send_payload => sub { return $_[1]; },
-                _debug           => sub {  },
-                _discord_api     => sub { +{ url => "wss://gateway.discord.gg/" } },
+            $hash->{discord} = AnyEvent::Discord->new;
+            my $mock = mock "AnyEvent::Discord" => (
+                add => [
+                    token            => sub { return 'your token'; },
+                    user_agent       => sub { return 'Perl-AnyEventDiscord/' . shift->VERSION },
+                    _ws_send_payload => sub { return $_[1]; },
+                    _debug           => sub {  },
+                    _discord_api     => sub { +{ url => "wss://gateway.discord.gg.example/" } }
+                ],
             );

hash などに複数いれる場合は () しておくと安全

mock "Hoge" => ( ... ), ではなく mock("Hoge" => ()) にしておく。 こうすることで 2個目のmock() が1個目の mock()の第三引数として扱われないようにする。

-    before all => sub {
-        $hash->{stubs} =+{
-            connect => AnyEvent::WebSocket::Client->stubs(
-                connect => sub {
-                    $hash->{called}->{connect} = 1;
-                    return AE::cv;
-                },
-            ),
-            recv => AnyEvent::CondVar->stubs(
-                recv => sub {
-                    $hash->{called}->{recv} = 1;
-                },
-            ),
+
+    before_all setup => sub {
+        $hash->{mocks} =+{
+            connect => mock("AnyEvent::WebSocket::Client" => (
+                override => [
+                    connect => sub {
+                        $hash->{called}->{connect} = 1;
+                        return AE::cv;
+                    },
+                ],
+            )),
+            recv    =>  mock("AnyEvent::CondVar" => (
+                override => [
+                    recv => sub {
+                        $hash->{called}->{recv} = 1;
+                    },
+                ],
+            )),
         };
     };

they

ない。 Test::Spec#theyTest::Spec#itエイリアスなので素直に it 使おう。 ちなみに 、Test2::Tools::Spec#itTest2::Tools::Spec#testsエイリアスなので、it()they()tests() にするのが正解かもしれない。

ハマったこと

describe/it

Test::Speck でよく書く describe > itdescribe >describe(context) > it の構造について、 構造は正しく保ちますが、実行順は順不同になります。 Test::Speccontext1 ,context2 の順で動くことを前提で書いていたテストが Test2::Tools::Spec で通らなくなったので気付いた。 これは、そもそもテスト順に依存したテストを書くなという話で、Test::Spec で「たまたま許されていた」と受け止めている。

以下にコード例と動作例を挙げておきます

コード例

describe 'about describe' => sub {
    my $hash;                   
                                                                                    
    describe '1st describe' => sub {                           
        it '1st it' => sub {
            ok 1;
        };                      

        it '2nd it' => sub {
            ok 2;
        };                      

        it '3rd it' => sub {
            ok 3;
        };                      

    };                          
                                                                                          
    describe '2nd describe' => sub {                                          
        describe '2-1 describe' => sub {                                                                           
            it '2-1 1st it' => sub {                        
                ok '2-1-1'
            };
            it '2-1 2st it' => sub {
                ok '2-1-2'
            };
            it '2-1 3rd it' => sub {
                ok '2-1-3'
            }; 
        };                      
                                                                             
        describe '2-2 describe' => sub {
            it '2-2 1st it' => sub {
                ok '2-2-1'                                                                                                                                                                                                                                                    };                                                                                                                                                                                                                                                    
            it '2-2 2st it' => sub {                                                                                                                                                                                                                              
                ok '2-2-2'
            };
            it '2-2 3rd it' => sub {
                ok '2-2-3'
            };
        };
    };
};

done_testing();

実行結果

./t/test.t .. 
# Seeded srand with seed '20241212' from local date.
ok 1 - about describe {
    ok 1 - 2nd describe {
        ok 1 - 2-2 describe {
            ok 1 - 2-2 2st it {
                ok 1
                1..1
            }
            ok 2 - 2-2 3rd it {
                ok 1
                1..1
            }
            ok 3 - 2-2 1st it {
                ok 1
                1..1
            }
            1..3
        }
        ok 2 - 2-1 describe {
            ok 1 - 2-1 3rd it {
                ok 1
                1..1
            }
            ok 2 - 2-1 2st it {
                ok 1
                1..1
            }
            ok 3 - 2-1 1st it {
                ok 1
                1..1
            }
            1..3
        }
        1..2
    }
    ok 2 - 1st describe {
        ok 1 - 3rd it {
            ok 1
            1..1
        }
        ok 2 - 2nd it {
            ok 1
            1..1
        }
        ok 3 - 1st it {
            ok 1
            1..1
        }
        1..3
    }
    1..2
}
1..1
ok
All tests successful.

実行結果 別例

describe > it だけの場合でも起きます。 こちらは実行例だけで伝わると思うのでコードは省略してます。

./t/test.t .. 
# Seeded srand with seed '20241212' from local date.
ok 1 - about describe {
    ok 1 - 4th it {
        ok 1
        1..1
    }
    ok 2 - 1st it {
        ok 1
        1..1
    }
    ok 3 - 2nd it {
        ok 1
        1..1
    }
    ok 4 - 3rd it {
        ok 1
        1..1
    }
    ok 5 - 5th it {
        ok 1
        1..1
    }
    ok 6 - 6th it {
        ok 1
        1..1
    }
    1..6
}
1..1
ok
All tests successful.

あきらめたもの

xcontext, xdescriber, xit

ない。 個人的にはコメントアウトするより楽なので使ってただけで、コメントアウトに戻すだけの運用になった。 TODO ブロック代わりに使ってると、面倒臭いかもしれない。

share(), shared_examples_for(), it_should_behave_like()

ない。 今回は shared_examples_for(), it_should_behave_like() を使ってなかったので、 share() を消すだけの変更になった。

 describe 'about XXX' => sub {
     my $hash;
-    share %$hash

どうしても shared_examples_for(), it_should_behave_like() みたいなことをしたい場合、関数に逃がすしか無さそう。 その際は share() に入るべきリファレンスも一緒に渡す感じになる。(あるいは Test::Spec::SharedHash を再実装するか)

Test2::Tools::Spec 以外の話

ついでなので変えたところを挙げていく。 (厳密に言えば stubs(mock) もココに入るが……)

Test::Exception

手を入れれば use Test2::V0 だけで行けます。実態は Test2::Tools::Exception にある。

             it 'throw exception' => sub {
-                throws_ok {
+                my $throws = dies {
                     Oden::API::Discord->new()
-                } qr/require token parameter/;
+                };
+                like $throws, qr/require token parameter/;
             };

Test2::Tools::Exception の SYNOPSIS には

like(
    dies { die 'xxx' },
    qr/xxx/,
    "Got exception"
);

と記載されてるけど 若干見づらい 好みの問題で2行に分けてます。

my $throws = dies { die 'xxx' },
like(throws, qr/xxx/, "Got exception");

Test:Warn

warn は exception と違って use Test2::Tools::Warnings が必要。

+use Test2::V0;
+use Test2::Tools::Spec;
+use Test2::Tools::Warnings qw/waning warnings/;
 
-use Test::Spec;
-use Test::Exception;
-use Test::Warn;

使い方は基本的に Exception と一緒。

-                warning_like {
+                my $warning = warning {
                     my $package = Oden::Dispatcher->dispatch('not_exist');
-                    is $package, undef, 'undef';
-                } qr/Can't locate Oden\/Command\/NotExist.pm in \@INC/, 'throw and warning';
+                };
+                like $warning , qr/Can't locate Oden\/Command\/NotExist.pm in \@INC/, 'throw and warning';
 

、warning が複数出るケースの場合はちょっと面倒

-                warnings_like {
+                my $warnings = warnings {
                     my $res = $hash->{api}->send_attached_file(
                         $hash->{valid_channel_id},
                         $hash->{path}
                     );
                     is $res, false;
-                } [qr/401/, qr/Unauthorized/];
+                };
+
+                like $warnings->[0], qr/401/;
+                like $warnings->[1], qr/Unauthorized/;

isa_ok

isa_ok が多重継承に対応した。基本配列型にすれば大丈夫

-                isa_ok $api, 'Oden::API::Discord';
+                isa_ok $api, ['Oden::API::Discord'];

HASH, ARRAY を期待する場合は ref_ok() にする必要がある

             my $discord   = $hash->{discord};
             my $endpoints = $discord->endpoint_config();
 
-            isa_ok $endpoints, 'HASH';
+            ref_ok $endpoints, 'HASH';

is_deeply

Test2 の is で構造体比較ができるようになったので、 is_deeply は is に置き換えて行ける。 実態は Test2::Tools::Compare#is

-            is_deeply $endpoints, +{
+            is $endpoints, +{

最初は以下の様に Test2::Tools::ClassicCompare#is_deeply を use していたが is() で解決する内容だった。

+use Test2::Tools::ClassicCompare qw/is_deeply/;

explain

テスト中のデバッグ出力の神。無いと生きていけないが、基本 pushする前に消すので、普段 Test::More でテスト書いてても存在を忘れられがち

Test2::Tools::Explain にあるのでデバッグ出力が必要なときだけ use する。 use Data::Dumper; して Dump でもいいけど。

+ use Test2::Tools::Explain;

...

diag explain $hash

まとめ: というか diff 見たほうが早いって人向け

Test::Spec から Test2::Tools::Spec に移行した p-r があるのでそのコード見てください 該当リポジトリ内のコードの大部分を最近別のリポジトリに移行したので最新をみるときはそちらを。(diff の有る方のリポジトリから最新を見ようとすると not found になってます。🙇)

21万6000個のサイコロを簡単に振る方法

news.denfaminicogamer.jp

はてブコメントで

216000D6とか一度でいいから振ってみたい

悲しいことにGoogle先生は99個までしか振ってくれない。

と有りました。気持ちはわかる。 さすがに現実に振ること叶わなくても簡単に多数のダイスを振る方法を一つ思い出した。

Perl のモジュールには 「Games」という名前が付けられていてモジュールがが数多く有り、その名の通りゲームに関連したモジュールが登録されています。 そのうちの一つに、その名の通り Games::Dice というモジュールがあります。これを使って 216000個のダイスを降ってみましょう。

cpanm が入ってれば cpanm Games::Dice で簡単に入ります

$ cpanm Games::Dice
--> Working on Games::Dice
Fetching http://www.cpan.org/authors/id/R/RJ/RJBS/Games-Dice-0.045.tar.gz ... OK
Configuring Games-Dice-0.045 ... OK
Building and testing Games-Dice-0.045 ... OK
Successfully installed Games-Dice-0.045
1 distribution installed

あとはワンライナーでいけます

$ perl -MGames::Dice -E 'say Games::Dice::roll(q{216000D6})'
755615

一回試したときの出目は755615

ダイスロールの表記 nDm のルールを知っていれば個数、面数幾らでも変更できます。 nがダイスを振る個数、mが一個あたりのダイスの面数(最大値)になります。 21面ダイスのように現実ではそうそう手に入らないダイスでも振ることができます。

合計値ではなく、各ダイスの出目を知りたいときは roll_array メソッドを使いましょう。さすがに 216000個の出目を記事に並べる気はしないので各自試してみてください。

わざわざモジュールインストールしなくても perl -E '$c += int(rand(6))+1 for (1..216000); say $c' で一発だし、何ならPerlじゃなくてもいいんだけどね。

Let's enjoy perl

YAPC::Fukuoka 参加してきた(当日編)

YAPC::Fukuoka 参加者側としての記事。当日分です。

先日分:http://likk.hatenablog.com/entry/2017/07/04/170842
発表者分:http://likk.hatenablog.com/entry/2017/07/02/092721

オープニングの途中から参加。過去の参加では昼から参加したり、オープニング後から参加したりが多かった。
会場での禁止事項・諸注意などがあるので実は結構重要なんだなと認識しました。でも途中参加。

以下、聞いて印象に残ったトークと感想。

レガシーperl と今

どうしてもバージョン固定で動かしたい現場のノウハウ。
とっととバージョン上げたいけど、やんごとなき理由でできない。そういう局面は発生しうるよなーと思いながら聞いた。
最後の「流行りだけではなく、チームマッチングも考えた選択をしよう」というひとことにグッと来た。

稼働中の Web サービスの Perl 処理系バージョンアップをしていく話

https://speakerdeck.com/astj/jia-dong-zhong-false-web-sabisufalse-perl-falsebaziyonwoshang-geteiku

  • 上げるのではなく、上げ続けられるようにする体制をつくる
  • パッチバージョンはとっととあげよう
  • マイナーバジョンは2年経ってもう1年使いたいなら上げる
  • どっかの検証環境でバージョン上げて caton insatll おちたら cpan test を見る
  • perlのバージョンアップより、CPANのアップの方で挙動変わる可能性が高いので先にCPANあげる
  • 一度実績があると二度目は楽

ゴールがバージョン上げる話ではなく、バージョン上げる体制をつくる話なのが素敵。
上げる基準や対象も明確になって、聞く人が着手しやすい状態になってるの凄い。

ウェブセキュリティの最近の話題早分かり

実例を挙げ、再現デモをしながらの説明で非常に理解しやい構成。
設定の不備をなくすのと、アプリケーションの脆弱性を潰すのが大事だそう。
脆弱性をキャッチした時点で、場合によってはサービスを止める勇気も必要だそうです。
ドキュメントよく読もう。必用に応じてテストしよう。

分散ユニークID採番機katsubushiとWebアプリケーションへの応用例

katsubushi を利用するかどうかは別として、nginx に振られた時点で一意の ID 発行して引き回すのは使いたい。
katsubushi では発行された一意の ID を元に時間を知ることができるのも便利だ。

はてなブログ最近の開発テクニックと最新の開発風景のご紹介

移行について「連続的に移行できるか、一般的な概念であるか、失敗したら戻せるか」という観点で観ていてグッと来た。
あと、(非エンジニア環境の)エラーと、deploy 促す slack-bot 欲しい。

Web application good error messages and bad error messages

良いエラーメッセージと悪いエラーメッセージの話。
エラーメッセージを出す際は、それは誰が読んでどう対処して欲しいかを考えながら出そう。それができてないのは悪いエラーメッセージと理解した。
時間がないと後者になりがちなので反省している。

cpm

制作過程で一旦立ち止まって、シンプルに機能分解して考えた話を聞けてよかった。
cpm については、そろそろプロダクトで使いたい。少なくとも個人ではガンガン使っていきたい所感。

P6W に基づく Perl6 に於ける Web 開発の基礎となる Crust
  • https://www.slideshare.net/tokuhirom/yapc-fukuoka-crust
    • perl6 web 開発の実際
    • web 開発に必要なものは一通り揃っている
    • perl6 P6W/ゴールはPSGIと同じ
    • 対応する実装がなかった
    • Crust/perl6に於けるplack/直接P6Wを触る必要があまりない
    • plackでできることは一通り揃ってる
    • middle ware 適当に名前だけ用意しておくと、欲しい人が pull-req 投げてくれる
    • CrustはWAFのための framework なので WAF作る人募集中

perl6触る予定が無いのに聞いてしまった。でも、こういうトークがきけるのもYAPCの醍醐味。
かなり息抜き気分で聞いてしまった。

スペシャルセッション
  • 何故、今福岡か。福岡企業の話。
  • 開発拠点としての福岡とその魅力
  • 5年ぐらい前から徐々に盛り上がってきた
  • 技術的なアピールがしやすくなってきた
  • 採用難しい/優秀な人に来てもらうしかない/中途採用送り込む
  • アジア圏のエンジニアとコンタクトを取る
  • ソフトウェアの開発なら場所関係ない
  • コミュニティ、母数が少ない代わりに緊密
  • 義理堅い/仕事変える人(job-hopper)少ない/人材が硬直化
  • 特化した人ほしいけど、中で教育するので特化した無くても良い
  • 専門にこだわり過ぎなくていい/フレキシブルに挑戦できるマインドがあればいい

福岡の魅力と、福岡に来て欲しい人材の話と、採用の苦労・課題の話を聞けた。
以外と地方でも給与テーブルが東京都変わらない企業もあるので、環境が許されるならそれもありかな。

新時代のテストフレームワークTest2
  • https://speakerdeck.com/akiym/xin-shi-dai-falsetesutohuremuwakutest2
  • perl 5.26 から Test2 使える
    • Test::Builder を置き換える
    • test::builder にモンキーパッチあててるとコケる
    • cartonでバージョン固定してない/依存モジュールがTest2に依存
    • 急にテストがコケるまえにTest2に移行しよう
    • Test2でのテストの書き方と便利情報

Test2でのテストはまだ試してない、Testのバージョン上げた際にコケるところありそうだから事前に例を聞けてよかった。

スキップしていいテスト、スキップしてはいけないテスト
  • https://speakerdeck.com/mackee/need-for-speed-of-testing-in-perl5-web-application
    • 局所的にスキップではなく、スキップするなら全部
    • 現状あるテストの改善/ドメイン特化/perl5のテスト
    • テストを書こうという時代はすでに過ぎてる/テストし易い環境の話
    • 一日一回はデプロイする/リリース前にフルテスト
    • デプロイできるタイミングが限られている
    • master データは別でテストする
    • マスタデータはキャッシュする
    • 時々コケるコード -> 時々コケないように治す
    • 差分がなければテストはスキップする
    • DBに突っ込まず、CSVのままテストもできる
    • 速さのためにテストしたいことがが歪まないように気をつける
    • N+1 検知/このメソッドを叩くときは、この prefech が叩かれないといけませんよ。という modifire
    • テストだと壊さないので思い切ったことできる
    • フローの改善にもなる

割りと近いところがあると思った。心に刺さるものがいくつか合ったので、パクら参考にせてもらいます

LT
  • 牛向けウェアラブルバイス
  • 今日のブラウンの帽子はラリー帽子。Perlエンジニア募集中
  • バグ報告者への敬意を払う。適切と思う範囲で上限設定
  • 次回は YAPC::Okinawa 2018 3/2, 3/3
  • ツイートできないエディタはエディタじゃない
  • MySQL Blackhole Engine でうけて、各スレーブに分ける

前夜祭のLTとは違って、比較的真面目なLTが多かった。
やっぱり雰囲気が違う。この雰囲気のなかで、前夜祭で発表したLTは出しづらいなーと思った。
(そもそも応募してないし、応募したとしてもリジェクトされてた可能性ある)

keynote
  • NTで働く @dragon3 さんの話。

海外で働くことの大変さ。家族・家賃・従業員・チーム体制・求人 など色々な話が聞けてよかった。
海外に拠点を設けるのには、拠点に行く本人だけでなく、施設や給料(日本の給与水準ではNYでは住めない)・現地スタッフ・チーム・含め会社全体のかなりの負担があることを知ることができた。
また、海外で働く苦労の話は、それがそのまま、今、社内で働いている海外出身の従業員に当てはまるということも考えさせられた。
帰路にトータルで20時間かかったらしい。大変だ。東京から福岡遠いとか思ってすいません。

全体を通して

まずは会場提供のLINEさんならびに、運営スタッフの皆様有難うございました。毎回楽しく参加させて頂いています。
とにかく広いスペース(会議室というよりは普段はランチ・カフェスペースなのかな?)。カフェもある。スライド写す箇所が複数ある。
スタンディングしながら聞きやすい場所もある。ほわーラインさんすげーわ。あとテンガロンハットのブラウンかわいい。
フリードリンクサービスとにかく飲みまくった気がする。ごちそうさまでした。

今回、比較的Perlセッション多かったのでYAPCにしては珍しいみたいな変な感想を抱いてしまった。いや全然問題ないんですが。(でもベストトーク賞がperlじゃないのはお約束)
毎回ベストトーク賞のセッションのタイミングで別枠のセッションを聞いてて聞き逃すという自体が発生するのですが、今回は聞くことができてよかった。
次回は沖縄らしい。沖縄行きたい。

YAPC::Fukuoka で食べたもの

幾つかYAPC関係なく福岡で食べただけだろ!!っていうのも有るけど気にしない。
ごちそうさまでした。

前夜祭

f:id:likk:20170630191953j:plain
f:id:likk:20170630192006j:plain
f:id:likk:20170630192019j:plain
f:id:likk:20170630192021j:plain
f:id:likk:20170630192027j:plain
プリン以外全て美味しくいただきました。
(プリン気づいたときにはなく無くなってた。油断しすぎ。最初に取るべき)

前夜祭二次会

f:id:likk:20170630225434j:plain
らーそーめんごちそうさまでした。

本編の弁当

f:id:likk:20170701125806j:plain
ランチスポンサー有難うございます。

Okinawa.pm 組と行った屋台

f:id:likk:20170701221345j:plain
中洲の屋台

翌日 (yapc関係ない)

f:id:likk:20170702132825j:plain
本場の明太子ごちそうさまでした。

f:id:likk:20170702205751j:plain
翌日も別の店の屋台行った

翌々日 (yapc関係ない)

f:id:likk:20170703114227j:plain
鯛茶漬けごちそうさまでした。

YAPC::Fukuoka 参加してきた(前夜編)

YAPC::Fukuoka 参加者側としての記事
当日と合わせると無駄にながくなりそうなので分けた。当日の話は明日書く。

前々夜祭 (非公式)

前々日のイベントかとおもいきや、「当日の、前の時間帯」のイベント。
とはいえ、本編が始まる前にワイワイできて非常に温まったと思う。
会場の提供とイベントの実施ありがとうございます。ビールごちそうさまでした。
トークの中で印象に残った箇所は以下。

@linyows Linux認証 octopass の話

githubAPI を使って Organization/Team で名前を解決し、githubの公開鍵を用い、github の Token でPAM認証するらしい。
自分はサーバ管理者側ではないので使う機会が無いと思いますが、小規模チームで構築する機会があれば参考にしようと思いました。
github が落ちていても(初回以外は)キャッシュを用いて使える状態にでてきているのが素敵。

@songumu Mackerelのプラグインの話

mackarel-plguin バイナリが BusyBox になっているらしい。
恥ずかしながら、BusyBoxというのをよく知らなかったので認識できてよかった。

@catatsuy pixivの常時HTTPS化の話とキャッシュの仕組みの変更の話

perl で置換便利、すごくよく分かる。
nginx のテストにperl Test::Nginx を使うの便利そうと思った。

前夜祭

ここから公式のYAPC::Fukuoka
若干迷いやすいロケーションだったと思ったけど、付近で見渡すとYAPC前夜祭案内が通りから見えるところにあり、迷わなかった。
会場は100人ぐらい入る広い会議室で、お酒も料理も種類豊富で、食いまくってた記憶もある。ありがとうごちそうさまでした。
自分のトーク枠もあったので緊張をほぐしつつ、酔っ払いすぎないようにガンガン飲んでた。ありがとうごちそうさまでした。
ざっと覚えてる限り以下な話があったと思う。

時間を戻したい話。。
  • ruby のtimeをhackするのにCのライブラリを上書いたらしい。

時間系操作したいシーンそれなりにありそうなので他の言語での例聞けてよかった。

ターミナルの可能性拡張の話
  • SNS/ミニブログの情報をすべて prompt に突っ込んだ
  • エンター押すたびに最新の情報が取得できてる

便利そう(邪魔そう)

pawooの話
  • 会場にpawoo 知らない人いなかった
  • リリースからのパッチ時系列まとめ

最初から時間内に終わらない前提のLTもありか。

実用的なAcme
  • 寿司食べたいと
  • 五兆円欲しい

ということしか覚えてなくて肝心な Acme モジュール名忘れた
そのあと非実用的なAcmeの話ししてすいません

サークルOG/OB会の話
  • 誰も150人規模の運営したこと無かった
  • YAPCなどのイベントから良かったものパクりまくった

どんどんこうやって外部にイベントノウハウが伝わっていってほしい(他力本願)

mark.vim の話
  • テキストをハイライトする
  • 色ついてると色々幸せ
  • YAPC;:Fukuoka のロゴ(福)を再現
ぼっちの話
  • 自分しかいないTimeline 時々botが返事してくれるらしい

なんか近いものを Slack の自分宛てdirect message やってるけど、ミニブログライクにする発想がなかった。


なお、この後自分のトークがきて、終わった安心感から飲みまくったせいかよく覚えていないしメモがあるけど
「Text::Cabocha!!」 とか、「帰ったらゼルダやりたい」とか断片的すぎてひどい。
LTでも話す側として参加すると、緊張したり、緊張の糸が切れたりするので、ちゃんと聞けないときあるんですよね。
他の参加者さんとかはどうなんだろう。
もっとスピーカー経験積んで、なんともないぐらいになるしか無いのか。

YAPC::Fukuoka 前夜祭で「夏の夜を涼しくするPerlの話」というタイトルでLTしてきた

言いたいこと。

1. YAPC::Fukuoka 前夜祭でLTしてきた
2. Acme::Undead について
3. 場が温まってたのもあってそれなりに笑ってもらえた
4. 参加できなかった人にも伝えたいこと
5. トーク内容の感想とか全体の感想は別途書くよ

以下詳細という名のgdgdな何か

YAPC::Fukuoka お疲れ様でした。ブログに書くまでが YAPC::Fukuoka だそうです。

前述の通り、前夜祭で「夏の夜を涼しくするPerlの話」というタイトルでLTしてきました。
aizen.likk.jp
もともとは、某slack のチャンネルでゾンビとアンデッドの違いは何かという話をしていたときに、なんとなく思いついて、Acme::Undead を書いた感じです。
github.com
git log の initial commit を見るとわかりますが、今年始めのころ大体の挙動はできてました。このタイミングで微調整したり、LTのネタとして発表したりしたのは、どうせなら夏に話したいと思って放置していたせいです。そのままお蔵入りになりそうだったのは秘密です。


実装につきましては、use すると use したパッケージに Acme::Undead の _die() _bless() (と _sleep()) をそれぞれ die(), bless() (sleep()) という名前で export している形です
。例えば main パッケージで use して die を呼ぶと core の die を呼ぶのではなく Acme::Undead::_die() を export した main::die() を呼ぶ形になっております。
あまりないと思いますが、別の目的で元から main パッケージに sub die {} や sub bless {} があるとそれも上書きしてしまいます。(別の目的で書いてある実装があったら目的知りたいのでご連絡いただけると幸いです。)


実にしょうもないAcmeモジュールで、しょうもないネタLT だったので、ウケがとれなかったら、スライドのタイトルの涼しいを通り越して寒い感じになって耐えられそうにないなと思いましたが、場が温まってたこともあり、大ウケまでは行かなくてもそれなりにウケてもらえたようで何よりでした。結局暖かいのか涼しいのかよくわかんない。


スライドの中で、今回、前夜祭に来れなかった人にもどうしても伝えたいページがあります。
http://aizen.likk.jp/slide/acme_undead/#/step-6


JRPG的アンデッド
死者(アンデッド)
L 肉体がないよ派(ホーント)
L 幽霊・ゴースト
L レイス(生前は高位の者/死神)
L ポルターガイスト // 現象の方を指すケースが多い
L 肉体はあるよ派
L あるけど腐ってるよ派
L ゾンビ(操られた死体) // 本来はゴーレムに近い
L グール(死喰鬼)
L レベナント(死に戻り) // 我々のイメージするゾンビはこっちに近い
L あるけど本体は肉体じゃないよ派
L ワイト(肉体を覆う光が本体)
L あるけど骨だけだよ派
L スケルト
L 実は死んでないよ派
L 元は妖精だよ派(でもアンデッドのような特性があるよ)
L デュラハン
L バンシー
L 最初から生きて無いよ(アンデッドじゃないよ)派
L 材料が肉や骨なだけだよ派
L ボーンゴーレム
L フレッシュゴーレム

じゃなくて、こっち。
http://aizen.likk.jp/slide/acme_undead/#/step-20

last/next/redo は無名ブロックも対象になる

どうしてそういう実装になっているのかは分からないですが、以下のようなコードを書くと意図と違う挙動・あるいは実装者の意図と違う理解をメンテナがする可能性があるのでお気をつけください。(そもそもループの中で無名ブロックが必要なケースが出てきたらメソッド分けましょう)

    for (1..10){
        say $_;
            {
                last; #ここでループから抜けたい(実際は無名ブロックから抜けるだけ)
            }
    }

逆にそれを意図してハックっぽい感じのコードを書くとに書くといい感じに混乱を誘えそう

Salck::RTM::Bot を使ったら error message too long が出たのでパッチを用意してもらった

言いたいこと。

1. WebService::Slack::WebApi から Salck::RTM::Bot に乗り換えたら error message too long が出た
2. 原因が Protocol::WebSocket::Message の max_message_size を超える受信量だった
3. Twitter で呟いたらパッチ当ててもらった
4. WebService::Slack::WebApi と同様に コマンドラインから slack見るだけの gist 書いた

以下経緯と言う名のgdgdな何か

2年ぐらい前 http://likk.hatenablog.com/entry/2015/05/08/194754 に書きましたが
slack の内容を拾ってくるのに `WebService::Slack::WebApi`
github.com
をずっと使ってました。
が、業務で使うチャンネルが増えすぎたせいか、全体の発言量が増えたせいか、あるいはAPI側で変更が入ったせいか、今年の2月頃から Groups, や Channels の内容が取り切れなくなりました。正確には取れるのだが、次に取るまでの時間が制限されてしまう感じになってしまいました。

groups や channel のAPIは大量のデータを取得するような内容であれば、次の request までの interval が長く要求され(intervalを無視して取りに行ってもエラーで返される)取得するデータを少なくすれば interval が短くなります。このバランスにたいして、参加している全チャンネルの時間あたりの発言数の方が完全の越えており全てのデータを拾ってこれない量になりました。そのため、API を定期的に叩くのをやめ、Real Time Messagingを取りに行く方法に変えようと考えてました。

今まで使っていた `WebService::Slack::WebApi` にも Real Time Messaging を取るAPI はありますが、得られたwssに対して、自分でsocket 通信を開始し、
event を管理する必要があります。あと、定期的に ping を送らないとslack側から切断されたり、自前で書くつらいそうだなーと思って後回にしてました。
下記に紹介するブログでも頑張ってる感じが窺い知れるます。
hiyoko91.hatenablog.jp

slack がでたばかりの2015年から2年ぐらい経ってるし、良い感じのモジュール新しく誰かが作ってないかなーと思ってググったら、約 11,700 件 (0.38 秒)で TOP に
github.com
が挙がっていたので、それを試す事にした。
中でやってることはやっぱり同じなんですが、そこらへん全く意識せず使えるIFになってたので非常にありがたかった。

が、使ってみたらやっぱり時間辺りの発言量のせいか `error: message too long` が出てしまった。
エラーを出してる箇所を追うと、Protocol::WebSocket::Message の max_message_size を超えるとエラーがでるようになるのがわかったので、
何気なーく`Salck::RTM::Bot` の作者の @duck8823さんをフォローして、
何気なーく


って呟いたら、音速でレスポンスがきて超速でパッチの用意までしてくれました。有難うございます。

正確には完全移行しておらず、ちょっとしたAPI叩いたり、発言周りは `WebService::Slack::WebApi` のままです。
PerlでslackやるならRTMを流したり、発言に対してリアルタイムに反応したければ `Slack::RTM::Bot` をそれ以外の目的では `WebService::Slack::WebApi` が今後も良さそうですね。

あと毎回似たようなことやってるけど、コマンドラインからslack見れるツールを作りましたが、まあこれはどうでもいいですね。