TECH PLAY

株式会社モバイルファクトリー

株式会社モバイルファクトリー の技術ブログ

222

こんにちは、エンジニアの id:mp0liiu です。 少し前の話になりますが、5/28にPerlの最新安定バージョンである5.36がリリースされたので、コミュニティ周りの動向も含めて気になった点についてまとめていこうと思います。 use v5.36 一番影響がある変更は use VERSION の効果が変わったことです。 use v5.34 以前はバージョンチェック、要求されたバージョンで利用可能なすべての機能(featureバンドル)の有効化、strict の有効化を行っていましたが、 use v5.36 からは warnings も有効化されるようになりました。 use v5.36 ; my $str ; say $str ; # Use of uninitialized value $str in say at ... 1行だけで strict, warnings, 最新の機能の有効化ができて便利なのと、perl開発チームも use VERSION をもっと普及させたいと考えているよう *1 なので積極的に使っていきましょう! use v5.36 で無効化される機能 5.36 の feature バンドルでは、Perlの構文解析を難しくしたりわかりにくい挙動をしてしまう原因になりがちだった古い機能の一部が無効化されるようになりました。 間接オブジェクト記法 間接オブジェクト記法というのは通常メソッドの呼び出しは次のように書くところを my $ua = LWP::UserAgent->new( timeout => 10 ); my $response = $ua->get ( 'http://example.com' ); このように書く記法のことです。 my $ua = new LWP::UserAgent timeout => 10 ; my $response = get $ua 'http://example.com' ; 間接オブジェクト記法が無効になって特に嬉しいのは Try::Tiny をuseし忘れたときの謎の挙動が発生しないことだと思います。 例えば 5.34 だとこのコードは間接オブジェクト記法で解釈できてしまい、 try {} の中だけ実行して catch {} の部分は実行しないという挙動になってしまいますが、5.36 だとsyntaxエラーになります。 use v5.34 ; try { die 'hoge' ; } catch { if ( $_ eq 'hoge' ) { say 'ok' ; } else { die $_ ; } }; 擬似的な多次元配列 まだPerlで多次元配列が作れなかった頃にハッシュに複数のキーを与えることで擬似的な多次元配列が作れるようになっていたのですが、その機能が無効になります。 use v5.36 ; my %hash ; $hash{ 1 , 2 } ; # Multidimensional hash lookup is disabled 安定化した実験的機能 以下の実験的機能が安定化して use v5.36 や use feature 機能名 で使えるようになりました。 これらの機能はプロダクトの中でも積極的に利用しても問題ないでしょう。 サブルーチンシグネチャ perl5.18 で追加されたサブルーチンシグネチャがperl5.36でようやく安定化して @_ の中身を取り出さなくても引数を受け取ることができるようになりました。 # サブルーチンシグネチャを使わない場合 sub add { my ( $x , $y ) = @_ ; return $x + $y ; } # サブルーチンシグネチャを使う場合 use feature 'signatures' ; sub add2 ($ x, $y ) { return $x + $y ; } use feature 'signatures'; した状態でもサブルーチンシグネチャを使ったサブルーチンと従来と同じ引数を @_ から取り出すサブルーチンは共存できますが、サブルーチンプロトタイプを使っているサブルーチンは :prototype 属性を使わないと共存できません。 use feature 'signatures' ; sub mymap (&@) { # -> syntax error! my ( $code , @args ) = @_ ; my @returns ; for my $arg ( @args ) { local $_ = $arg ; push @returns , $code ->(); } return @returns ; } sub mymap :prototype(&@) ( $code , @args ) { my @returns ; for my $arg ( @args ) { local $_ = $arg ; push @returns , $code ->(); } return @returns ; } また、次のようにサブルーチンシグネチャを使ったサブルーチンの中で @_ を参照することは実験的機能とされているので注意してください。 sub add ($ x, $y ) { my ( $x2 , $y2 ) = @_ ; # Use of @_ in list assignment with signatured subroutine is experimental return $x2 + $y2 ; } サブルーチンシグネチャには型は指定できないので Data::Validator, Smart::Args などの引数バリデータはまだ手放せないですが、書捨てのスクリプトを書くときや初学者のとっつきやすさはかなり良くなったのではないでしょうか。 isa 演算子 isa 演算子は左被演算子に渡した値が右被演算子のクラスのインスタンスまたはそこから派生したクラスのインスタンスなのかを調べる演算子でperl5.32 で実験的機能として追加されましたが、今回の変更で警告はなくなりました。 今まで Scalar::Util::blessed と isa メソッドでクラスのインスタンスかどうかを判定していたところなどを簡潔に書けるようになると思います。 use Test::More; use feature 'isa' ; package Hoge { sub new { bless +{}, shift } } my $obj = Hoge->new; # isa 演算子を使わない場合 use Scalar::Util qw( blessed ) ; ok blessed( $obj ) && $obj->isa ( 'Hoge' ); # isa 演算子を使う場合 ok $obj isa Hoge; done_testing; 追加された実験的機能や改善された点 真偽値が安定して追跡できるようになった 今まで !!0 や !!1 といった構文や真偽値を返す式、コア関数から返されていた真偽値はなんらかの変数に代入すると真偽値としての性質を失ってしまっていたそうですが、 5.36からは変数に代入してもその真偽値としての性質を保持するようになったそうです。 後述する builtin の新しい関数 is_bool() で値が真偽値としての性質を持つかどうかをチェックすることができます。 この変更によって、他の言語との相互運用やデータ型のシリアライゼーションが簡単になりました。 例えば JSON::PP でエンコードする場合、今までは真偽値だと明示するには true の場合 \1 を、false の場合 \0 を渡す必要があり知識がないとハマりがちだったのですが、 5.36 以降は !!1 , !!0 など真偽値として返された値(後述の builtin::true, builtin::false の値も含む)をそのまま渡せばちゃんとエンコードできるようになりました。 use v5.34 ; use JSON::PP qw( encode_json ) ; my $data = +{ hoge => \ 0 }; say encode_json( $data ); # {"hoge":false} use v5.36 ; use JSON::PP 4.09 qw( encode_json ) ; # 真偽値でそのままエンコードするには JSON::PP 4.09 以上が必要 my $data = +{ hoge => !! 0 # builtin::false でも可 }; say encode_json( $data ); # {"hoge":false} 変数に代入しても真偽値としての性質を保持するとはどういうことか? 「変数に代入しても真偽値としての性質を保つ」というのがどういうことかわからなかったので、5.34、5.36それぞれで真偽値を変数に代入した場合の性質の変化を調べてみました。 use v5.34 ; use Devel::Peek qw( Dump ) ; Dump !! 1 ; my $bool = !! 1 ; Dump $bool ; my $one = 1 ; $one . '' ; Dump $one ; 5.34 SV = PVNV(0x236c030) at 0x937720 REFCNT = 2147483644 FLAGS = (IOK,NOK,POK,READONLY,PROTECT,pIOK,pNOK,pPOK) IV = 1 NV = 1 PV = 0x70c924 "1" CUR = 1 LEN = 0 SV = PVNV(0x236c070) at 0x23a3130 REFCNT = 1 FLAGS = (IOK,NOK,POK,pIOK,pNOK,pPOK) IV = 1 NV = 1 PV = 0x237c4f0 "1"\0 CUR = 1 LEN = 10 SV = PVIV(0x238f730) at 0x2391260 REFCNT = 1 FLAGS = (IOK,POK,pIOK,pPOK) IV = 1 PV = 0x23da7b0 "1"\0 CUR = 1 LEN = 10 変数に代入せずにダンプした場合と代入してダンプした場合を比べて異なる点は FLAGSに READONLY , PROTECT がつかなくなった PVが指す文字列バッファの内容が変わった NULL終端文字列が含まれている文字列になった LEN(PVに割り当てられたバイト数)も 0 -> 10 になった といった感じです。 READONLY , PROTECT がつかなくなるのは変更可能な変数に代入した影響でしょう。 となるとperl本体のコードを読まないと断言はできませんが、PVが指す文字列バッファの内容が変わるというのが変数に代入すると真偽値としての性質を失うということではないでしょうか。 変数に代入する前はPVの指すアドレスの先に真偽値としての性質を表す値があるのだが、変数に代入することでPVが指す文字列が普通の文字列になってしまうことで3番目に出力したような普通の値と区別がつかなくなってしまう、というようになっていそうです。 5.36 次に同じコードを5.36で実行してみた場合のDumpした結果を見ていきます。 SV = PVNV(0xca1030) at 0x9537e0 REFCNT = 2147483644 FLAGS = (IOK,NOK,POK,IsCOW,READONLY,PROTECT,pIOK,pNOK,pPOK) IV = 1 NV = 1 PV = 0x727be4 "1" [BOOL PL_Yes] CUR = 1 LEN = 0 SV = PVNV(0xca1070) at 0xcd3ba0 REFCNT = 1 FLAGS = (IOK,NOK,POK,IsCOW,pIOK,pNOK,pPOK) IV = 1 NV = 1 PV = 0x727be4 "1" [BOOL PL_Yes] CUR = 1 LEN = 0 SV = PVIV(0xcc86e0) at 0xcd3f48 REFCNT = 1 FLAGS = (IOK,pIOK,pPOK) IV = 1 PV = 0xcb14f0 "1"\0 CUR = 1 LEN = 10 5.36 の場合、変数に代入してもPVが指す文字列バッファは変わっていません。 また、PVが指す文字列バッファが真値であることを示す PL_Yes であるということも表示されています。 というわけで、 真偽値にはPVの指すアドレスの先に真偽値としての性質を表す値がある 5.34 以前は真偽値に変数を代入することでPVが指す文字列が普通の文字列になってしまっていた 5.36 からは真偽値を変数に代入してもPVの指すアドレスが変わらなくなったので、真偽値であると明確に区別できるようになった ということのようです。 forループの繰り返しごとに複数の要素を参照する構文の追加 for文の括弧内にレキシカル変数を列挙することで複数の要素に対して反復処理を行えるようになりました。 use v5.36 ; no warnings qw( experimental::for_list ) ; my %hash = ( a => 1 , b => 2 , ); for my ( $key , $value ) ( %hash ) { say " $key => $value " ; } b => 2 a => 1 keys を使わずに安全にハッシュをイテレーションできて便利になると思います。 my %hash = ( a => 1 , b => 2 , ); for my ( $key ) ( keys %hash ) { say " $key => $hash{ value } " ; } もちろん一度に3要素以上の繰り返しも可能です。 my @points = ( 0 , - 3 , 5 , 6 , 7 , 9 ); for my ( $x , $y , $z ) ( @points ) { ... } この機能は実験的な機能です。 使用した際に発生する警告を抑制するには no warnings qw( experimental::for_list ) が必要です。 try-catch 構文に finally block が追加 5.34 で追加された try-catch 構文ですが、try, catch ブロックが実行されたあとに実行する処理が書ける finally ブロックも書けるようになりました。 use v5.36 ; use experimental 'try' ; try { die 'hoge' ; say "Success" ; } catch ( $e ) { say "Failure" ; } finally { say "Regardless" ; } finally を書くことは頻繁にはないと思いますが、他の言語や Try::Tiny などで書けていたのに use feature 'try'; では書けないのもいまいちなので良い改善かなと思います。 defer 構文の追加 スコープを抜けるときに後で実行される構文です。 use v5.36 ; use experimental 'defer' ; { say '1' ; defer { say '3' ; } say '2' ; } 1 2 3 今まで Scope::Guard などを使って書いていた処理を簡単に書けるといった感じです。 Go の defer 構文とは実行タイミングや変数の扱いなど挙動が違う点があるのでその点は気をつけたほうが良さそうです。 *2 新しい組み込み関数の追加とそれらの組み込み関数をインポートする仕組みの追加 builtin というコアモジュールが追加され、既存の組み込み関数とは別にインタプリタから完全修飾名ならいつでも呼ぶことができるユーティリティ関数がいくつか追加されました。 say "Reference type of arrays is " , builtin::reftype([]); # Reference type of arrays is ARRAY また、 builtin モジュールの関数は use 文に import パラメータとして列挙することで直接インポートすることができます。 use builtin 'reftype' ; say "Reference type of arrays is " , reftype([]); # Reference type of arrays is ARRAY この仕組みができたことで、よく使うけどコアモジュールからインポートして使っていた様々なユーティリティ関数や、新しい関数を組み込み関数として追加しやすくなりました。 現状、この組み込み関数周りの仕組み及びこれらの組み込み関数は実験的機能の扱いです。 使用した際に発生する警告を抑制するには no warnings qw( experimental::builtin ) が必要です。 builtinモジュールに実装されている組み込み関数を紹介します。 builtin::trim 引数の文字列の先頭、末尾の空白及び改行をすべて削除する関数です。 use v5.36 ; no warnings 'experimental::builtin' ; use builtin qw( trim ) ; print trim " hello! \n " ; # hello! 微妙な使い分けはありそうですが chomp の上位互換になりそうです。 builtin::indexed 引数のリストをリスト内の各要素の順番と各要素のペアのリストにしたものを返す関数です。 use v5.36 ; no warnings 'experimental::builtin' ; use builtin qw( trim indexed ) ; use Data::Dumper; warn Dumper [ indexed 'a' .. 'c' ]; # [ 0, 'a,', 1, 'b', 2, 'c' ] forループの繰り返しごとに複数の要素を参照する構文と使うとforループの中でindexと配列の要素の参照が楽になりそうです。 for my ( $index , $value ) (indexed @array ) { ... } builtin::true, builtin::false, builtin::is_bool true と false はそれぞれ真値と偽値を返し、 is_bool は真偽値として作られた値かどうかを調べます。 true、false で返される値は !!1 や !!0 で返される値と同じです。 これらの true, false を使わなくてもperlは今まで通りどんな値でも真偽値として評価しようとしてプログラムを動作させるわけですが、「真偽値が安定して追跡できるようになった」でも述べたとようにこれらの関数で返された真偽値は内部的に真偽値として作られたと識別することができる値なので、他の言語との相互運用やデータ型のシリアライゼーションが行いやすくなります。 use v5.36 ; no warnings 'experimental::builtin' ; use builtin qw( true false is_bool ) ; use Devel::Peek qw( Dump ) ; Dump true; Dump !! 1 ; SV = PVNV(0x18e9030) at 0x9537e0 REFCNT = 2147483644 FLAGS = (IOK,NOK,POK,IsCOW,READONLY,PROTECT,pIOK,pNOK,pPOK) IV = 1 NV = 1 PV = 0x727be4 "1" [BOOL PL_Yes] CUR = 1 LEN = 0 SV = PVNV(0x18e9030) at 0x9537e0 REFCNT = 2147483644 FLAGS = (IOK,NOK,POK,IsCOW,READONLY,PROTECT,pIOK,pNOK,pPOK) IV = 1 NV = 1 PV = 0x727be4 "1" [BOOL PL_Yes] CUR = 1 LEN = 0 use v5.36 ; no warnings 'experimental::builtin' ; use builtin qw( true false is_bool ) ; use Test::More; ok is_bool true; ok is_bool !! 1 ; ok !is_bool 1 ; done_testing; ok 1 ok 2 ok 3 1..3 builtin::weaken, builtin::unweaken, builtin::is_weak それぞれ弱参照を作る関数、弱参照になっている参照を通常の参照に戻す関数、弱参照かどうかを判定する関数です。 元々 Scalar::Util にあった関数を持ってきた形になります。 builtin::blessed, builtin::refaddr, builtin::reftype それぞれパッケージと紐付いている参照かどうか、参照のアドレス、参照の種類を返す関数です。 これらも元々 Scalar::Util にあった関数を持ってきた形になります。 builtin::ceil, builtin::floor それぞれ引数の数値を切り上げた数値、切り捨てた数値を返す関数です。 これらは元々 POSIX にあった関数を持ってきた形になります。 Perl5.36 ができるまで Perl5.36 が完成するまでにPerl開発チームでも大きな変化がありました。 1つ目は従来の pumpking に変わってPSC(Perl Steering Council)と呼ばれる、コアチームから選ばれた3人のメンバーから構成される運営評議会によって開発が進められたことです。 Perl5.34 もPSCの時代にリリースされましたが、PSCが発足したときには既にほとんどの開発が終了していました。また、そのころはPerl7などPerlの将来をどうするかといった問題などが残っており、具体的な変更よりもそちらの方が主な仕事になっていました。 対してPerl5.36ではPSCのメンバーによって開発プロセスやスケジュールが管理されるようになりました。 PSCのメンバーがうまく連携して開発を進めた結果、Perl5.36では過去のバージョンと比べてより多くの機能の追加や改善が行えたのではないかと思います。 2つ目はRFCが制定されたことです。言語の変更を提出する正式なプロセスとして昨年導入され、Perl5.36 の提案を管理するために使用されました。 結果、かなり透明性が高い状態で提案を管理できているようです。 PerlのRFCは こちらのリポジトリ で見ることができます。 まとめ このように 5.36 では以前と比べて大きめな変更がたくさん入っています。 ここでは書いていない変更もいろいろあるので気になった方は perldelta を読んでみてください。 参考 perldelta - what is new for perl v5.36.0 - Perldoc Browser perl v5.36.0 has been released – rjbs forgot what he was saying – blathering blatherskite *1 : Perl Steering Committee (PSC) #015 Meeting Notes - nntp.perl.org より 将来的にPerl7をリリースするときもPerl7の機能を use v7.0 で有効にすることになるので普及させたいそうです *2 : Shogoさんの こちら の記事で詳しくまとめられています
アバター
こんにちはエンジニアのEadaedaです。 皆さんのチームではGitHub Actionsを使っていますか?ブロックチェーンチームではテストやリンター、デプロイといったワークフローをGitHub Actionsで行っています。 今まで、デプロイ以外のワークフローはGitHub-hosted runnerで実行、デプロイはSelf-hosted runnerで実行していましたが、運用していくうちに特定の環境内にあるサーバーで実行されるように仕組みを見直す必要がでてきました。このため全てのワークフローをSelf-hosted runnerに移行する対応を行いました。この記事では移行の際に見つけた便利なものや困ったことを紹介します。 Self-hosted runner GitHub Actionsでは、基本的にGitHubが用意したVMでワークフローが実行されます。このVMを GitHub-hosted runner と呼んでいるようです。別の方法として、自前で用意したサーバーで各ワークフローを実行することもできます。このときの自前で用意したサーバーを Self-hosted runner と呼んでいます。 サーバーは物理でも良いですし、クラウドに構築するのでも良いです。今回は先の「特定の環境内」という条件を満たすようにEC2を利用することとしました。つまり以下のようなシンプルな構成を考えていました。 シンプルな構成 この構成はデプロイワークフローのために既に構築されているものと同じものでした。なので、各ワークフローをこのSelf-hosted runnerで動作するように書き直せば、一応移行は完了したことになります。 ただし、1つのRunnerにつき同時に実行できるジョブの数は1つですので、今の状態だとCI/CDワークフローをひとつずつ処理していくことになります。これではワークフローの完了待ちの時間が伸びてしまい、開発体験が最悪になってしまいます。 これを解決するパッと思いつくアイデアはSelf-hosted runnerのEC2インスタンスをたくさん用意することです。 たくさんのインスタンス しかしこれはこれで問題があります。たくさんのEC2を手で起動するのは大変ですし、動きっぱなしのインスタンスの費用や、それぞれのインスタンスのメンテナンス工数などのコストがどんどん膨らんでしまいます。これらを解決するには、ワークフローの開始を検知して必要な数のインスタンスが起動、処理が終わったらインスタンスを終了する。というような仕組みにできれば良さそうですが、はたしてできるのでしょうか。 philips-labs/terraform-aws-github-runner でオートスケールするSelf-hosted runnerを整備する できます。ピッタリのOSSがありました。 github.com 簡単に説明すると、ワークフローの開始を検知して必要な数のEC2インスタンスを起動、処理が終わりアイドル状態になったインスタンスはLambdaの定期実行により終了される仕組みを作ってくれるterraformモジュールです。READMEも充実しており良いなという印象です。 READMEに書いてあることなので、ここではセットアップについては説明はしませんが、快適にCI/CDを実行するためにREADME以外のこともやったのでいくつか紹介したいと思います。なお作業時点での最新バージョンはv1.2.0だったので、このあとの説明はv1.2.0での話であることをご了承ください。 terraform-aws-github-runner モジュールの設定を考える このモジュールは非常に多くの設定ができます。自分たちの使い方に合うような設定を考えてtfファイルに記述していきます。今回の構築でも色々考えて設定したのでいくつか紹介します。 AMIの準備 philips-labs/terraform-aws-github-runner ではSelf-hosted runnerの起動テンプレートで使うAMIを自分たちで用意することができます。CI/CDを実行するために事前に準備(例えばソフトウェアのインストールなど)できるものは準備をし、AMIにしておけばいくつかのstepを簡略化・高速化できます。CI/CDは速いと嬉しいので、できる準備はしておきたいです。 tfの記述 自分たちが用意したAMIを使うためには ami_filter の name に使いたいAMIの名前を記述します。また、 ami_owners に利用しているAWSアカウントのIDを渡す必要があります。 今回はAMIのバージョニングを意識して hoge-YYYY-mm-dd という命名ルールにしたので、実際の ami_filter の設定は以下のようになりました。(※ hoge は例です。実際には意味のある単語を使っています) ami_filter = { name = [ "hoge-runner-*" ] } ami_owners = [ data.aws_caller_identity.current.account_id ] AMIの更新は、 terraform apply をすることで行います。 docker pullしておく プロダクトのCI/CDでは一部Dockerを使っています。例えばMySQLやRedisといったミドルウェアですね。これらはワークフローを実行するたびに docker pull されます。イメージのサイズにもよりますが、そこそこ時間がかかってきます。 そこで、先に docker pull しておいて毎回 docker pull する必要が無いようにします。別な効果として docker pull のレートリミットに引っかかりにくくなるというものがあります。これに引っかかってしまうとCI/CDが停止してしまい非常に困るので回避できるのは嬉しいですね。 さて、やることはシンプルです。作業用のEC2インスタンスを起動、インスタンス内で以下のように docker pull します。 $ docker pull mysql:x.x.x $ docker pull redis:x.x.x ... あとは作業用のインスタンスをもとにAMIを作って終わりです。 Self-hosted runnerの最大数を考える 同時に動作させられるSelf-hosted runnerの数の設定は runners_maximum_count で設定できます。 // 最大5台 runners_maximum_count = 5 デフォルト値は3台となっていますが、プロダクトのワークフローは全部で10個以上あるので、確実に詰まります。なので適切な値を考える必要があります。雑に「えい」で決めてしまってもよいのですが、それよりはある程度証拠や説得力のある数値を計算した方が良いでしょう。かかるコストの計算や説明にも便利です。 そこで今回は過去の実績から計算することにしました。具体的には 過去一ヶ月、あるテスト系のワークフローが同時に実行されていた数 * テスト系ワークフローの数 + デプロイ系ワークフローの数 を計算します。実際の値は履歴を ghコマンド で取得し、いもす法で計算します。 # gh apiでワークフローの履歴を取得する # 今回は5ページあったので 5.json まで繰り返す # YYYY-mm-ddは範囲の初日(≒一ヶ月前の日付) $ gh api "/repos/{HOGE_OWNER}/{HOGE_REPO}/actions/workflows/{HOGE_WORKFLOW_ID}/runs?created=>=YYYY-mm-dd&per_page=100&page=1" > 1 .json # awkとかで雑にいもす法をやる。実装あってる…? $ jq -r '.workflow_runs[] | [.created_at, .updated_at]|@csv' *.json | \ tr -d \" | \ awk -F, '{imos[$1]++;imos[$2]--}END{for(k in imos)print k,imos[k]}' | \ sort | \ awk '{sum+=$2;print $1, sum}' | \ sort -k2n ... YYYY-mm-ddTHH:MM:SSZ 3 YYYY-mm-ddTHH:MM:SSZ 3 YYYY-mm-ddTHH:MM:SSZ 3 YYYY-mm-ddTHH:MM:SSZ 3 YYYY-mm-ddTHH:MM:SSZ 4 YYYY-mm-ddTHH:MM:SSZ 4 YYYY-mm-ddTHH:MM:SSZ 4 YYYY-mm-ddTHH:MM:SSZ 4 過去一ヶ月で同時に実行されていた数は4とのことでした。これを元にSelf-hosted runnerの最大数も設定し1ヶ月半ほど運用しましたが、CI/CDの詰まりなどは起きていないようなので、妥当だったのかなと考えています。 Self-hosted runnerの停止タイミングを考える scale_down_schedule_expression に cron の式を書くことで、スケールダウンを行うLambdaの実行間隔を指定できます。デフォルトは5分ごとですが、今回は1分ごととしました。理由としてはCI/CDを実行するインスタンスはできるだけ使い回されたくないなと考えたからです。 例えば、とあるブランチのワークフローが壊れており、それを実行したインスタンスも壊れてしまった場合、使い回されると他のブランチのワークフローも壊れてしまいます。これはあまり体験が良くないですよね。 その他にも、ビルド中に生成された中間ファイルなどが溜まって容量不足になるのを防ぎたい、もしくは中間ファイルによる影響をなくしたいというのもあります。もし使いまわしたい中間ファイルがあるなら、それは actions/cache などを使って明示的にした方が、ワークフローを読み解きやすくなるので良いでしょう。 まとめ 特定環境内で動作するGitHub Actionsを構築するためSelf-hosted runnerを利用することにした しかし、ワークフローが詰まらないようにするにはワークフローの数だけSelf-hosted runnerのサーバーが必要なため管理が大変だった そこで、 philips-labs/terraform-aws-github-runner を使ってオートスケールするSelf-hosted runnerの仕組みを構築した 運用に合わせて設定を考え、快適なCI/CDを構築する事ができた 今後の改善としては Dockerのレイヤーキャッシュまわりで躓き、オートスケールするSelf-hosted runnerにできなかったCI/CDへの対応 CI/CDの詰まりがなかったか?を観測し、Self-hosted runnerの最大数やスケールダウンの実行間隔の再調整 管理できるメンバーを増やすようなドキュメントの整備やハンズオン Ephemeralオプションを試してみる Self-hosted runnerを1つのJobにのみ割り当てるオプション。使いまわしたくないのを確実にできる philips-labs/terraform-aws-github-runner ではまだベータ機能だったので今回は使いませんでした などを考えています。以上です。
アバター
こんにちは。エンジニアの id:kfly8 です。 今月から、 NestJS と ethers.js のスポンサーをはじめました🎉 この記事ではOSSのスポンサーをするにあたり考えたことを書きます。 モバファクは、NestJSとethers.jsの2つのOSSのスポンサーになりました NestJSとethers.jsを選んだ理由 多くのOSSに支えられてプロダクトの開発ができているので、気持ちとしては全てのOSSに貢献したいところですが、そういうわけにはいかないので、次のような基準で絞り込みをしました。 プロダクトで重要かつ頻繁に利用している メンテナーが少ないこと スポンサーメニューが明確で、経理処理や稟議が円滑にしやすいこと 1番目の基準は素直だと思います。ここでは2番目、3番目について補足します。 メンテナーが少ないOSSにスポンサーをした NestJSもethers.jsもどちらも優れたOSSですが、開発体制を見るとメンテナーは実質一人です。企業側の目線で見れば、多くの開発の方に支えられているOSSと比べ、事業リスクが高いと言わざるを得ません。少しでも開発の継続に繋がればと思い、微力ながら、スポンサーをはじめました。 スポンサーメニューが明確で、経理処理や稟議が円滑にしやすいOSSを選んだ 営利企業の視点で考えると、多かれ少なかれ費用をかけるだけのメリットの説明が必要です。普段大いに利用しているので恩返しの気持ちももちろんありますが、費用が有耶無耶になるでなく、ロゴ掲載などわかりやすいメリットがあるとOSSの馴染みのない社内の方にも納得してもらいやすいです。 今回、OSS選定にあたり、プロダクトでがっつり利用していてメンテナーが少ないOSSは他にもありました。しかし、この企業側のメリットが説明しにくいOSSは、泣く泣く除外しました。 お節介ですが、スポンサーを希望するOSS開発者の方は気軽にスポンサー向けの門戸を開けていくと良いと思いました。 ブロンズスポンサーになるとREADMEにロゴを掲載してくれる OSSスポンサー実施の背景 近年、OSSの開発者の負担が高く、またOSSのスポンサーをしやすい土壌が整ってきたため、恩返しの気持ちを込めてOSSのスポンサーをはじめた!というのが9割の理由です。このまま素直に言い切りたいですが、数多ある技術スポンサーの手段の中で、どうしてOSSスポンサーを選んだのか補足したいと思います。 ひとことでまとめると、 OSSスポンサーはエンジニアと繋がる手段として小さく始められると思ったからです。 近年、エンジニアの方との繋がり方が変わったと感じます。 従来は、技術カンファレンスの懇親会でわいわい技術話をして、新しい出会いに繋がることが多かったです。新型コロナが落ち着いたら、本当に本当にまた懇親会を楽しみたいところです。オンラインが普通の今も、技術カンファレンスのスポンサーを総なめする勢いで実施するのも良いかもしれませんが、費用面でのリスクが大きいと考えました。 そこで振り出しに戻って、新しいエンジニアとの出会いについて考えました。 仮説ですが、最近は少人数のコミュニケーション機会が重要になったと感じます。オンラインは「少人数でちょっと話す」と相性が良いと思います。例えば、カジュアル面談でココだけの特別な話を味わったり、技術コミュニティのワーキンググループで、エンジニアの育成について継続して話したり、隙間の時間を使ってコミュニケーションしやすくなったと思います。 OSSのスポンサーは、開発者の方と話をする機会はあまりないですが、開発者の方に直接感謝を伝える機会になり、最近のコミュニケーションの仕方と相性が良いと思いました。そして、スポンサーは少額から始めさせてもらえるので、リスクは小さいです。 つまり、OSSスポンサーはエンジニアと繋がる手段として小さく始められると思ったことがスポンサーをはじめた背景にあります。 まとめ モバファクはOSSのスポンサーをはじめました OSSを選択する際、企業側のメリットが説明しやすいと選びやすい エンジニアと繋がる手段としてOSSスポンサーがいいかもしれない OSSのスポンサーを始める際に考えたことを書きました。 カジュアル面談のリンクはコチラです。ぜひお話しましょう! カジュアル面談の一覧へ
アバター
こんにちは。ブロックチェーンチームのソフトウェアエンジニアの id:odan3240 です。 先日開催された TOKYO BLOCKCHAIN TECH MEETUP 2022 に登壇してきました。 connpass.com 登壇内容 「クラウド KMS の活用」というタイトルで、自作の OSS の cloud-cryptographic-wallet の紹介をしました。 speakerdeck.com 当日の登壇の様子は動画でも閲覧ができます。 youtu.be Q&A Twitter や第二部の懇親会で寄せられた質問に回答します。 クラウドKMSはマルチシグ対応していますか クラウド KMS でもウォレットの種類は EOA なので、MetaMask などのウォレットと同じ機能しか持っていません。そのためマルチシグには対応していません。 クラウドKMSを使ったときのローカルでの開発環境はどうなるんだろう web3.js/ethers の provider を切り替えて対応してます。具体的にはローカルの開発環境では @truffle/hdwallet-provider を使用しています。 結局クラウドのアクセスキーが流出したらリスクは同じか 生の秘密鍵の流出と同様に、アクセスキーが流出すると自由にトランザクションの発行が可能になってしまいます。しかし、生の秘密鍵と比べて アクセスキーに有効期限を設定できる アクセスキーを即座に無効化できる アクセスキーを使用して API を叩くときに送信元の IP アドレスを制限できる などリスクを緩和する手段があるのが利点です。 クラウドKMSでユーザーの秘密鍵を管理するのは向いているか クラウドのルート権限を持つアカウントがある限り、理論上は自由にトランザクションの発行が可能になります。そのためカストディ判定される可能性が高いです。なので開発元の運営が管理するウォレットをクラウドKMSに寄せる運用を想定しています。
アバター
はじめまして。22卒エンジニアの id:kebhr です。 モバイルファクトリーでは、現場で使用されている技術を学ぶ技術研修がおよそ1ヶ月にわたって行われます。私は学生時代から趣味やアルバイト・業務委託の仕事でコードを書いてきましたが、技術研修を通して新たな学びや気付きを得ることができました。 ということで、この記事では、そんな学びや気付きを紹介していきます。 公式ドキュメントは大切 技術研修では、さまざまな言語やライブラリ・ツールの公式ドキュメントを網羅的に読みました。これらの中には、学生時代から既に使っているものもありました。 「ある程度使えているし読まなくても使えるじゃん」と考えがちですが、実際に読んでみると、 どの公式ドキュメントにもかならず知らないことが書かれていました 。 振り返ってみると学生の間は、公式ドキュメントとは「問題が起こったら、ググって見つけた部分を読んで、解決させる」ためのものでした。ですので問題が起こらなければ読むことはありませんでした。 学び・気付き しかし、公式ドキュメントには、その言語やライブラリ・ツールを使う上で「 知らなくてもいいけど知っているともっといい 」という情報が掲載されています。 1つ例を挙げてみましょう。Vue.js で親コンポーネントから孫コンポーネントにデータを渡すとき、これまでは props を使ったバケツリレーで実装していました。 公式ドキュメントを読むことで初めて、子孫コンポーネントに直接データを渡せる Provide / Inject *1 が提供されていることを知りました。 公式ドキュメントを読んだことによって「 既に知っている方法ではない、別の方法が存在する 」ことに気付けました。公式ドキュメントを読み複数の方法を知っておくことで、状況に応じてよりよい方法を比較・検討・選択することができるため、これからは積極的に読んでいきたいです。 実際に手を動かすのは大切 公式ドキュメントを読むことは大切です。読むことで「こんなやり方があったのか!」という気付きが得られます。私はここで「完全に理解した」という気持ちになりました。 しかしこれは、完全に勘違いです。 公式ドキュメントを読んで「こう書けばこう動く」ということを知ったからといって、コードが書けるようになるわけではありません。 これは「コードの写経をする」「コードの流れを追いかける」といったことがらにも当てはまります。 学び・気付き 技術研修では、Perl の基礎 *2 から Web アプリケーションのアーキテクチャまで、具体から抽象を幅広く学びます。また、実際の開発においても、抽象度の異なるものごとについて同時に考える必要があります。 ところが「公式ドキュメントを読む」「コードを写経する」「コードを追う」という、 手を動かさずに得られる知識は具体に寄りがち です。その結果、本質に近い抽象的な学びが不足しました。 しかし、 自らコードを書き手を動かしたことで 、具体的な学びを 抽象的な学びに昇華 することができました。 具体例を挙げてみましょう。技術研修中に扱ったサンプルアプリは CQRS パターンで実装されていました。これは、データの挿入/更新/削除といった状態の更新を伴う Command と、データを読み取る Query を別々に実装するデザインパターンです。 サンプルアプリを触っている時点では CQRS パターンを「参照とそれ以外で分けるもの」と認識していました。このときは Command や Query という文字列を見ても「これは更新系、これは参照系だね」と感じるだけでした。しかし、実際に自分の手で CQRS パターンを用いてコードを書いてみると「副作用が一定の範囲に留まるので嬉しいデザインパターンだね」という抽象的な学びを得ることができました。 脳内を整理するのは大切 人間の脳内のリソースは有限です。だからこそ、脳内に置いておく必要のない情報は外に逃がし、脳内を整理した状態にしておくことが大切です。 開発中に覚えておかなければならないことは多いです。「実装が完了するまでには、あと何をすればいいんだっけ?」とか「このパッケージには何を書くんだっけ?」とか「このメソッドはどこから呼ばれているんだっけ?」とか。慣れていれば覚えておくまでもないことでも、慣れるまではこうしたことが 脳内の有限なリソースを圧迫 します。 その結果、真に集中しなければならないロジックの実装に回せる余裕が削られて、効率が落ちてしまいます。 技術研修のときのエピソードを振り返ります。技術研修では、最後の3日間を使って Web サービス開発研修を行います。これまで学んだ技術スタック *3 を使って、与えられた要件を満たす Web サービスを開発する研修です。バックエンドは Perl を使い CQRS パターンを使って実装していきます。 私は限られた時間の中で進捗を出すために、初日は研修中に作成したサンプルアプリのコードを コピペして時短 を図ろうとしました。変更すべき箇所や進捗、サンプルアプリのアーキテクチャは脳内に保持していました。 しかし、結果として、既にコピペが完了した部分とコピペが完了していない部分、変数名やメソッド名を変更した部分としていない部分が混在し、 いくら直しても動かないコード が生まれました。 学び・気付き これではまずいことがわかったので、次の日はサンプルアプリの アーキテクチャを読み解く ことに時間を使いました。パッケージを列挙し、それぞれのパッケージの目的とそのパッケージを変更する理由を整理していきます。 続いて、要件を満たすために必要な機能ごとに *4 、変更が必要なパッケージを列挙しました。実装が完了するたびにチェックを付けていき、すべてにチェックが付けば実装が完了している状態に持ち込みました。 このようにして、 アーキテクチャと進捗を脳内で保持せず文章化した ことにより、その後の開発効率は高まりました。最終的には、実質2日間で要件を満たした上にいくつかの追加機能を実装することができました。 わからないを共有すると良い 技術研修の中ではたくさんの問題に直面しました。問題を解決するためにいろいろ考えてみるわけですが「どうしてもわからないことはわからない」という場合もありました。そういう時に、1人でずっと抱え込むより、周りにここがわからない!と わからないことを共有 していったほうが、結果的に早く正確な答えを得られることが多かったです。 学び・気付き 問題を人に伝えるためには、「こういう目的のために、こういう手段を取っていて、ここまでできていて、ここができていない」ということを整理する必要があります。その過程で「目的がそもそもズレてないか?」「よりよい手段があるのではないか?」「こうすればできるんじゃないか?」という、 問題を自己解決するための気付き を得られることがありました。 もし気付きが得られなくても、第三者から見るとすごく簡単なことが原因だったり、勘違いが原因だったり、あるいは環境依存の問題だということを知ることができました。 それでも解決できない場合は、Google Meet *5 で画面共有し共同で原因の究明をしてみました。話しながらコードを読んでいくと、 1人でコードを読んでいたときには気付かなかったこと に気付くことができました。 わからないことを共有すると、こうして問題解決することができます。その中で得た気付きを残しておけば、次回同じ状況に出会ったときに1人で解決できるようになります。 ちなみに技術研修では、新卒同期は Google Meet で常に繋がっている状態 *6 で、その日の作業スレにその日のことをなんでも書けるようになっていました。作業スレに書くなり、Google Meet でおもむろに喋り出すなりして、聞きたいことは聞くことができます。 一般的な学び・気付きを書いたワケ ここまで「技術研修で学んだこと・気付いたこと」をいくつか挙げてきました。あえてこの中に技術的な学び・気付きは書きませんでした。 なぜならば、技術的な学び・気付きも重要ですが、 技術研修から得た学びや気付きを一般化して、自分の行動に生かしていくことがより重要 だと感じたからです。一般化された学びや気付きに基づいて、自ら行動を起こすことでより高い成果を上げられたからです。 現場での開発に入るようになり1ヶ月半が経ちましたが、今も一般的な学び・気付きを大切にして日々業務に当たっています。 *1 : https://v3.ja.vuejs.org/guide/component-provide-inject.html *2 : 研修内容についてはこちら: https://tech.mobilefactory.jp/entry/2022/06/30/200000 *3 : バックエンドは Perl, MySQL, Amon2。フロントエンドは Vue.js 3, JavaScript / TypeScript, Vuex。 *4 : 具体的には API のエンドポイントごとに列挙しました。 *5 : ビデオ会議ツール *6 : 実際には、カメラ・マイクは用がなければミュートしていました。
アバター
こんにちは。エンジニアの id:kfly8 です。 先日、技術研修のインタビュー記事を公開し、手を動かしつつ、コミュニケーションをよく取る技術研修といった主旨の内容でした。 tech.mobilefactory.jp こちらのインタビューでは具体的な研修内容は触れていませんでした。今回は、駅メモ!や駅奪取といった位置ゲームや着メロの月額コンテンツサイトなどで利用しているPerlの技術研修について紹介します。ブロックチェーン事業ではフロントエンド、バックエンドの両サイドで、TypeScriptを利用しているのですが、そちらの技術研修の話は追い追いできればと思います。 tech.mobilefactory.jp 技術研修を受ける人は、どの言語でも良いのである程度プログラミング言語に慣れてることを想定しています。そのため、学ぶ意味、特徴は何か、良教材は何か、罠は何か、などポイントを掻いつまむように技術研修を進めています。 この記事でも、要所を掻いつまんで紹介をしたいと思います。 Perlの特徴は何か モバファクの一部プロダクトではPerlが現役バリバリで動いているので、Perlを利用している部署に配属された人はPerlを学ぶ必要があります。もう少し味気ある説明にしたいので、Perlの特徴を書きたいと思います。 先に悪い話から書きます。 Perlのエコシステムは、例えばTypeScriptと比べると勢いが劣っています。開発者向けのツールで、Perlに対応していないことは日常です。ないものは作ろう!の精神で作っても、出来が悪かったり、利用ハードルは高いです。 *1 動的に型が決まるので、ソフトウェアやチームの規模が大きくなると開発が難しくなります。動的型付け言語の共通の悩みでもあると思いますが、RubyのSorbet/Steepなどの型チェッカーなど素晴らしい進化しているなーと思ってみています。 他にはデプロイを容易に、そしてマシンのリソースを有効活用したいと思うと、Golangを羨ましく思います。 そんなこんなで、Perlを利用していることに疑問があっても不思議でないです。 モバファクの一部プロダクトで、当時Perlを採用した理由は、資産、知見が溜まっていることなどが理由ですが、現在も利用し続けることに強いこだわりはなく置き換えコストのバランスだと思っています。実際、新規事業だったブロックチェーン事業では、TypeScriptを選択していますし、状況次第なのかなと思っています。 Perlに良い点もあります。悪い点を上回るほど良いと言いたいわけではないですが、面白いところもあります。 テキスト処理に強い 正規表現リテラル便利 後方互換性が高い バージョンアップして動かなくなる心配が少ない とはいえ、新しい言語機能を追加しにくいトレードオフが発生 けれども最近のPerlをみていると、 v5.36 といった宣言によって、初学者が戸惑うような文法の曖昧さなど減らす向きがあるのは嬉しいです。例えば、間接オブジェクト機能の無効化など。 総じて、運用ツール作るのに便利 GitなどがPerlに依存しているのもあり、たいていのUNIX系システムに入っています 出自がsed/awkをオーバーキルする形でLarry Wallが作ったという話も納得 シュッと書くとき便利! もう少し個人的な趣味で、2つあげると、スコープとコミュニティです。 まず、スコープに関して。スコープを使うと、例えば変数の生存期間を簡単にコントロールできます。変数だけでなく、警告の抑制なども切り替えできます。最近、deferが入りましたが、 Scope::Guard モジュールがPerlのスコープの特性を活かしたモジュールで面白いです。 もう一つはコミュニティの寛容さ。以前、 TPCiP に参加したとき、Golangのワークショップが複数日程を使って開催されていました。廊下で一休みしていたときは、Rustを嬉々と薦められました。先日運営した YAPC::Japan::Online 2022 では、kimusonがTypeScriptのネタで登壇していました。 tech.mobilefactory.jp 技術的に面白いかどうか、技術的課題を解決するかどうかが関心事に感じられて、懐の深さを感じます。自分はPerlコミュニティのこういうところが結構好きです。 研修の中身 Perlの言語学習 まず言語学習を1,2日で実施しています。次の教材を読み進めてもらい、軽い演習問題を解いて手触りを確かめてもらっています。 Minimum Viable Perl Perlでアプリケーションを書くための最小限の知識を入れるためのテキストで、Perlの構文、ライブラリの使い方、依存ライブラリ管理の仕方、デバッグ方法、テストの書き方を学ぶ はてなの教科書(Perl) Perlでつまりがちな所をポイントを抑えたテキスト 公式ドキュメントでも特に大事なドキュメント 初めて読んで理解するのは難しいことが多いが、流し読みでいい。「あーそういえば読んだなー」と思ってもらえれば、勝ち。理解を深めるために結局読むことになるドキュメント perlintro perlがどういう思想で出来た言語か掴むのに良い perl perldoc perlrun perlsyn perldata Scalar、Array、Hash について理解を深めるのに良い 演習問題は、FizzBuzzやすごろくです。 もう少し体系だった言語知識をいれる場合は、 リャマ本 、 ラクダ本 を読んでもらいます。 PerlでWebアプリケーションを作る研修 Perlに限らないですが、Webアプリケーション開発の研修では「HTTPリクエストからレスポンスが返り、クライアントがコンテンツを体験するまでに何が行われてるか」この解像度が高まるといいと思って教材を作っています。 そういった思いがあるので、かなり素朴な実装から徐々にWeb Application Frameworkを使って実装をリッチにしていく研修プログラムにしています。最初からおんぶに抱っこなフレームワークにのっかると「フレームワークのルールはわかるけれど、Webアプリの全体像が掴めない」といったことが起きがちなためです。具体的には、次の通りです。 まず、netcatコマンドを使い、HTTP/1.1のプロトコルを地力で喋って、素朴なテキストやりとりで遊ぶ。 PSGI/Plackを生で利用して、簡単なWeb APIを作る 次にWebアプリケーションフレームワークとしてAmon2を利用 業務ロジック、データ操作が複雑になった時を想定してアーキテクチャを変更する 素朴なサービス層を作るところから、CQRSやInteractorsなどの(表面的に)理解しやすい分割手法を試す ソフトウェアアーキテクチャが開発に与える影響が大きく、重要だと思います。新人への教え方は試行錯誤の段階ですが、面白みを感じてもらえたらいいと思っています。 Perlの技術研修でよくあるFAQ 教材を読み進め疑問に思ったことを雑に話す場を設けて、理解度向上を狙っています。ここでは例年よくあがる話を紹介したいと思います。 1; は何を意味している? モジュールのコード実行がうまくいったことを示すため。 require の実装内容を見ると良い。 https://perldoc.jp/func/require unlessを使う必要ある? ケースバイケースだが、否定は認知負荷を上げるので基本は使わない方がいいと思う。けれど、異常系で早期リターンしたいときはよく使う。 return unless good1 return unless good2 return !! 1 関数呼び出しの :: と -> の違い -> は、インスタンスメソッドやクラスメソッドとして使う場合に利用 $user->name 、 User->list :: は、単純に関数として使う場合に利用 POSIX::abs(-3) :: と -> の関係性 Hello->message('yeah') は、 Hello::message('Hello', 'yeah') と等価 $some_object->method('waiwai') は、 SomeObject::method($some_object, 'waiwai') と等価 EXPORT_TAGはどういうケースで利用する? まとまった意味があれば使うことはあるけれど、使うことは例外だと思ってもらいたい。というのも、どこから関数がインポートされたかわかりづらくなるから。 アプリケーション側のコードを書く時は、何をインポートしているか、できる限り明示する。 基盤のコードの場合は、学習が完了すれば、便利に使えるので、タグや暗黙的なインポートをする場合も許容する場合がある。 そんな感じで私は考えてる。 コンテキストとは? 次を読む。 Perlの勘所をマスターしよう! コンテキストとリファレンスを我が物に! Perlのコンテキストクイズにツールで答えてみた 引数バリデートは実装する関数やメソッド全てに対して行うべき? チームで認識が揃っていない場合もあるので、注意は必要だけれど、 全てではないと思う。 外部から渡ってきた値は、正しい値かどうかできるだけ早く検証する。これがバリデーション。 システム内部での値の受け渡しなど、システムを正しく利用していれば、正しくなる値に関しては、バリデーションする必要はない。 そういった場合は、アサーションを書き、開発環境だけで動かす(≒本番環境では動かさないで済む)のが適切だと思う。 $, @, %ってわかりずらい 次のように覚える $calar - Scalar @rray - Array %ash - Hash $@ , $_ この記号は何?ググりにくい。 perldoc -v $@ のようにperldoc の v ariable optionで特殊記号のドキュメントを調べられる perldoc.jp を使うと、 http://perldoc.jp/$@ のようにすると日本語ドキュメントを調べることもできる perldoc.jp/{キーワード} で、ドキュメントをよしなに探してくれる。 さいごに モバファクのPerlの技術研修の事情をお伝えしました。少しでもイメージが湧けば嬉しいです。 カジュアル面談のリンクはコチラです。ぜひお話しましょう! カジュアル面談の一覧へ *1 : 逆に他の言語にPerlのアレがないといったこともあるある
アバター
こんにちは。ブロックチェーンチームのソフトウェアエンジニアの id:odan3240 です。 モバファクには 「シェアナレ!」という社内勉強会制度 があります。この制度の時間を利用して隔週で「Crypto 勉強会」を開催しています。 「Crypto 勉強会」は前身の「Layer2 勉強会」を含めると2年以上継続的に開催されている勉強会です。この記事では「Crypto 勉強会」の発足の背景や実際に行われていることを紹介します。 「Crypto 勉強会」とはなにか 前身の「Layer2 勉強会」は2020年の1月頃に Ethereum の Layer2 技術のキャッチアップのために始まった勉強会です。この勉強会では隔週で Plasma や Rollup に関する文献の エクストリームリーディング や、モブプロなどを行っていました。 1年半近く継続して勉強会を開催していましたが、2021年10月頃になって業務で Polygon [^1] や Optimism などの Layer2 技術の検討が行われるようになりました。「Layer2 勉強会」では「第二領域」と呼ばれる「緊急ではないが重要な事の領域」にフォーカスすることを目的に始まったため、目的に合致しなくなってきました。 この背景があって「Layer2 勉強会」は発展的解消され、「Crypto 勉強会」の開催が昨年の10月より開始しました。 「Crypto 勉強会」では Ethereum 以外のブロックチェーンやアプリケーションレイヤーに関するトピックも扱うようになりました。 勉強会の進め方 「Layer2 勉強会」はエクストリームリーディングやモブプロが中心だったので、参加メンバーの一人でも欠けると勉強会自体がリスケになることが度々ありました。「Crypto 勉強会」ではその対策に まず最初に参加者で相談してその日のトピックを決める 45分間は各自そのトピックに対して調査やコードを書く 残り15分で調査した内容を共有 という流れにしました。 事前準備もなく、毎回トピックが変わるので前回と参加メンバーが異なっても開催が可能です。最悪参加メンバーの1人でも勉強会の開催が可能な仕組みです。 ここ最近の扱ったトピック ここ最近では次のトピックを勉強会で扱いました。 The Merge STEPN エルフマスターズ Solana Hokusai API RAYS Mining 終わりに 去年の10月から走り始めた「Crypto 勉強会」について紹介しました。 勉強会の参加にあたって事前準備も必要なく、メンバーが欠けても開催ができる仕組みにすることで、無理なく継続的に勉強会を開催できています。 具体的に扱った各トピックどういう議論が行われたか興味がある方は、ぜひともカジュアル面談でお話しましょう。 カジュアル面談の一覧へ [^1]: 厳密には Layer2 ではない
アバター
こんにちは、ブロックチェーンチームの id:d-kimsuon です Vue2 では TypeScript がサポートされており、公式の TypeScript のサポートのドキュメント に従うことで TypeScript で書いていくことができます しかし、素直に書いていくと any 型になってしまったり、実際とは異なる型付けになってしまうポイントがあります この記事では TypeScript で Vue2 (Option API) を書くときに型を厳格にしやすい書き方等を紹介します 省略可能な props には明示的に PropType<型 | undefined> する 型安全な例 型安全でない例 props の型でリテラルに絞っている時、 default には as const をつける 型安全な例 型安全でない例 data の型を as で上書きせず、型注釈を書く 型安全な例 型安全でない例 asyncData の型は推論ではなく Promise<Partial<Data>> を使う 型安全な例 型安全でない例 watch には型注釈を明示する 型安全な例 型安全でない例 ref からメソッドを呼ぶ 最後に 省略可能な props には明示的に PropType<型 | undefined> する Vue の props では required: false または default に値を設定することで、省略可能なプロパティを宣言することができます 型安全な例 PropType で明示的に型を指定することで、型安全に参照することができます Vue.extend ( { props: { foo: { type : String as PropType < string | undefined >, required: false } , } } ) 型安全でない例 次のような素直な実装でも省略可能な props は実現できますが、型付けが厳格でなくなります fooは、いずれも string | undefined に型推論されてほしいですが、 string に推論されてしまいます Vue.extend ( { props: { foo: { type : String , required: false } , } } ) Vue.extend ( { props: { foo: { type : String , default : undefined } , } } ) props の型でリテラルに絞っている時、 default には as const をつける PropType<'ok' | 'ng'> 等で受け取る型をリテラルで絞っていても default 値が指定されていると string に丸められてしまいます as const をデフォルト値につけることで PropType の型でちゃんと推論してくれるようになります 型安全な例 Vue.extend ( { props: { foo: { type : String as PropType < 'x' | 'y' | 'z' >, default : 'x' as const // これがないと string に推論される } } } ) 型安全でない例 Vue.extend ( { props: { foo: { type : String as PropType < 'x' | 'y' | 'z' >, default : 'x' // as constがないため、string に推論される } } } ) data の型を as で上書きせず、型注釈を書く data はミュータブルなデータなので初期値からの推論が適切でないときがあります そういうとき、as で型を上書きする手法が使われがちですが型と値がズレる原因になります 型安全な例 data メソッドの戻り値の型を書くことで安全に data の型を宣言できます Vue.extend ( { data () : { foo: { hoge: string } } { return { foo: { hoge: "hello" } } } } ) 型安全でない例 Vue.extend ( { data () { return { foo: null as null | { hoge: string } } } } ) as だと型注釈とは異なり、型情報を上書きします。値をその型の変数に束縛できるかを緩くしか検証しないので型と値が一致しなくなる原因になります 例えば以下は型エラーがでない、型と値がズレる例です // asで型を書くダメな例 Vue.extend ( { data () { return { foo: {} as { hoge: string } } } } ) 型注釈で書いていれば {} は 型 { hoge: string } に割り当てることはできませんが、as で書いていたために代入できてしまっています 既存のコンポーネントに data を追加する際に型注釈が書いてないと as で対応しがちなのかなと思っているので、最初から型注釈を書いておくのが良いのかなと思っています asyncData の型は推論ではなく Promise<Partial<Data>> を使う ※ nuxt の話題で、 v2.16.0で修正されている のでそれより古いバージョンの前提です asyncData にだけ書いたデータは this.serverData が生えず型安全に参照することができません ですので、data の型に SSR から取得するデータの型も初期値とセットで宣言しておくのがオススメです 型安全な例 // ローカルステートの型を初期化状態とセットで宣言して type Data = { clientData: string , serverData: string | undefined /* 未ロードを undefined にする */ , } Vue.extend ( { // asyncData は Partial<Data> に注釈をつける asyncData: async () : Promise < Partial < Data >> => { return { serverData: 'hogehoge' } } , data () : Data { return { clientData: 'hello' , serverData: undefined // 初期化 } } } ) 型安全でない例 type Data = { clientData: string , } Vue.extend ( { asyncData: async () => { return { serverData: 'hogehoge' } } , data () : Data { return { clientData: 'hello' , } } , methods: { foo () { console .log ( this .serverData ) // 型エラー } } } ) watch には型注釈を明示する watch 対象のプロパティをの型を推論してほしいですが、実際には入ってくれません 型安全な例 やや手間ですが型注釈を明示してあげることで、型安全に利用できます Vue.extend ( { props: { foo: String } , watch: { hoge ( nextValue: string , prevValue: string ) : void { // 明示する } } } ) 型安全でない例 Vue.extend ( { props: { hoge: String } , watch: { hoge ( nextValue , prevValue ) : void { // nextValue と prevValue は string に推論されてほしいけど any になる } } } ) ref からメソッドを呼ぶ ref を使って子コンポーネントのメソッドを呼び出すとき、型安全にメソッドを呼ぶことはできません 子コンポーネントのメソッドを呼ぶこと自体避けたほうが良いかもしれませんが、止むをえず呼ぶ場合は以下のような型の Utility を準備しておくことで型安全に呼び出すことができます type ComponentMethods < Comp > = Comp extends ExtendedVue < Vue , unknown , infer I , unknown , unknown > ? I : never ; type TypedVueRef < Comp extends VueConstructor > = Vue & ComponentMethods < Comp >; 以下のように利用します const ref = this .$refs [ 'v-comp' ] as unknown as TypedVueRef <typeof VComp > 最後に この記事ではVue2系で型安全性を守りやすい書き方を紹介しました Vue で型が厳格にならず困っている方はぜひお試しください!
アバター
「新しい環境に馴染んで活躍できるか?」 この不安を感じる人は少なくないと思います。そういった不安に対応できるよう、モバイルファクトリーでは、できる限り早くチームや会社に馴染んで強みを発揮できるようにオンボーディングを大切にしています。 この記事では、オンボーディングの一環の技術研修について紹介します。技術研修で何をしているか何を大切にしているか、運営の生の声を聞いてみました。 この記事に出てくる人たち モバファクの技術研修の概要 技術研修の工夫、アクシデント さいごに @kfly8 : 今日はモバファクの技術研修について話していきたいと思います。よろしくおねがいします! まずは、みんなが普段、どんなことをしているのか、自己紹介をお願いしたいです。 @dorapon2000 : 今年3年目になるエンジニアです。駅奪取というソーシャルゲームの中の人をやっています。普段の業務は新機能開発、お問い合わせ調査、最近は負荷対策などで、フロントからバックエンド・インフラまで何でも触ります。去年の技術研修の担当もしていて、今年は2回目です。 @yokoi0803 : 駅メモ!の機能開発、主にバックエンドを担当しているエンジニアです。最近はチームの開発パフォーマンスにも関心があって、その計測や改善ができるように動いてたりします。技術研修やメンター制度などで育成に関わらせてもらうことも多くて、技術研修の担当になるのは2回目です。 @kfly8 : ありがとう!インタビュアーの私も簡単に自己紹介すると、普段は組織全体の開発パフォーマンスを良くしていけるように色々動いています。技術研修に関して言えば、きちっとした形に立ち上げて、かれこれ技術研修の運営に7年くらいしています。 この記事に出てくる人たち @dorapon2000 2020年新卒でモバイルファクトリーに入社。エンジニアとして駅奪取の運用・開発に関わる。最近は業務でパフォーマンス・チューニングをしており、手探りで原因を探して改善が数字に現れる体験に感動を覚えている。 @yokoi0803 2018年新卒でモバイルファクトリーに入社。エンジニアとして駅メモ!の運用・開発に関わり、現在は駅メモ!開発チームでテックリードのポジション。 @kfly8 ゲーム開発やプロダクトのマネジメントを経て、現在はエンジニアの人材開発、採用、技術広報などに取り組む。また、技術コミュティ好きをこじらせて、Japan Perl Associationの理事もやらせてもらっている。 モバファクの技術研修の概要 @kfly8 : まず技術研修では何をしていますか? @dorapon2000 : まず技術研修の目的は、研修を行った新卒たちがすぐ実践に入れることを目的にしています。そのために、Webアプリケーションをフロントエンドからバックエンドまで一通り学びます。バックエンドは、Perl、Amon2、MySQLを、フロントエンドは、JavaScript、Vue.jsなどです。実際に手を動かして、コードレビューをしながら学んでもらってます。 @yokoi0803 : そもそもですが、弊社にはいろんなチームがあり、チームによって技術スタックが異なるので、基本はチームごとに技術を学んでもらいます。 例えば、ブロックチェーンのチームであれば、フロントエンドもバックエンドもTypeScriptを利用しているので、そちらをチームで学んでもらいます。駅メモ!と駅奪取の場合は、技術スタックが近いので、合同で技術研修をしています。 tech.mobilefactory.jp @kfly8 : では、どのように技術研修を実施していますか? @yokoi0803 : 大前提として、弊社はフルリモートで働いています。例に漏れず、技術研修もフルリモートで実施していますね。基本の進め方は、教材をひとりひとり読み進めてもらっていますが、適宜コミュニケーションを挟むようにしています。 @dorapon2000 : 1日の流れは、朝会で1日の予定や雑談やわからないことの相談などをするところから始まり、1日の終わりに気づいたことなどをワークログを書きおこしてもらい、1日を締めくくります。 @dorapon2000 : 各技術トピックはだいたい2日程度で終わるようにカリキュラムを組んでいます。技術トピックは、例えば「Vue.jsのチュートリアル」「簡単なAPIサーバをフレームワークを使わずに作る」といったトピックです。各技術トピックごとにキックオフを行い、学ぶ意義やユースケースなどを最初に共有しています。各技術トピックが一通り終わったら座談会と言って、取り扱っている技術トピックに詳しい人と新人で話す場を用意して、わからないことを質問したり、教材から外れて、学び方などを聞くようなこともあります。 @dorapon2000 : トータルして期間は、おおよそ1ヶ月くらいになります。 @yokoi0803 : 慣れない会社で、リモートの環境で、新しいことを学ぶとき、新人が自発的にコミュニケーションを取るのは難しいと思っていて、研修担当としては、こちらから声かけをするように意識しています。具体的には、朝会や夕会や、新人が集まっているmeetにちょくちょく顔を出すようにしていますね。 @dorapon2000 : リモートだと、エレベータや廊下ですれ違って偶然起こるコミュニケーションがない。リモートだと能動的に動かないとコミュニケーションが発生しない。だから、研修実施者側が起こすようにしていますね。 @kfly8 : いい話。極端な話だけど、技術研修で学んだことは忘れる。けれど、技術研修でのコミュニケーションの体験は後々に残る。関係があれば、質問しあったりキャッチアップしていける。 技術研修の工夫、アクシデント @kfly8 : 技術研修の概要は掴めたと思うので、今度は深堀りをしていきますね。 まず、技術研修を実現するにあたり、工夫したポイントがあれば教えてください。 @dorapon2000 : 昨年の研修でギリギリでの準備になってしまったこともあり、早め早めで準備するようにしましたね。いつまでに何が必要かなどを、きちんとしたので、教材の改善をより上げる余裕があるかなどの判断がついた。 @yokoi0803 : dorapon2000の準備は動きやすくてよかったですねー。 @dorapon2000 : 新人と社員が接触する機会が自然と増えるようにも工夫しました。例えば、Vue.jsに詳しい社内の人に協力をお願いして、新人の疑問の解消だったり、雑談をしてもらう場を設けました。 @kfly8 : 新人に好評だったことがあれば教えていただけますか? @dorapon2000 : 手を動かして、アウトプットする研修が人気でしたね。特に、プロダクトの要件だけ与えられてどう作るのか自分で考えるWebサービス開発研修が特に人気。ある程度のレールはひきつつも自由度のある課題。 @yokoi0803 : Webサービス開発を1から作る力を学んでもらいたかったので、その目的は達成できたかなと。 @yokoi0803 : 技術トピックごとに学ぶと、技術トピック同士の繋がりは実感しにくい。より学習効率が上げるには、繋がりを理解する必要があると思ったんですよね。1から作る経験をしてもらって、バラバラだった知識を結びつけることができたと思います。 @dorapon2000 : MySQLのハンズオンも手応えがあったかもしれない? @yokoi0803 : かもですね。インデックスやロックなどは、ドキュメントを読むだけでは分かりづらいが、実際に手を動かして、デッドロックなどわざと発生させることで、実感を持てた。試し方がわかったら、提示した内容以上に実験をしていましたね。 @kfly8 : きちんと準備をする、技術トピック同士の関連性を掴む、実際に手を動かす、どれも大切ですね! では、技術研修が思うように進まなかったことはありましたか? @yokoi0803 : 今年の技術研修実施中に一番インパクトが大きかったことは、リーダーがdorapon2000から私に切り替わったことですね。dorapon2000の所属チームで障害対応を優先する必要があって、仕方がないですが、急遽リソース、タスク調整をしつつ、技術研修のリーダーシップを取る必要があり大変だったかなと。 @yokoi0803 : ただ、リーダーが替わるのは、新人の目線で見れば大きなイベントに見えそうなので、不安を作らないようにさらっとした形で共有しましたね。 @dorapon2000 : リーダーを替えることができたのは、目的を達成するためには、今回、これが一番いい選択だと、みんな思えた。なので、迷いは少なかったですね。やってよかったし、やるべきことができたと思う。 @yokoi0803 : 切り替わったタイミングで、残りの研修期間で、いつ何をすべきか計画が明確だったので、動きやすかったのもありますね。その辺、dorapon2000が準備をきちんとしてくれて助かりました。 @kfly8 : 何年も技術研修に関わってるけれど、技術研修期間中にリーダーが替わったのは初めての出来事。2人とも素晴らしいリーダーシップだね。 さいごに @kfly8 : 今回の技術研修を通じて、2人の学びを教えてください! @dorapon2000 : 技術研修に関わったのは、私たち2人だけではなくて、色々な人に協力してもらった。協力してもらった人に、背景、目的、期待だったりを丁寧に伝える必要を感じた。今回、この辺がうまくいかなかったかなと。文章だけでなく同期的なコミュニケーションで質疑応答をしながら、やれると良いのかなと。 @yokoi0803 : 自分も全く同じことを、頭に思い浮かべた。複数人で物事を進める時は、統一したゴールを思い浮かべられるように、すり合わせをしていくことが大切だと学びましたね。 @dorapon2000 : 本とかよく出てくる話ですが、実際にうまくいかない場面に遭遇して、わかった気になっていたのかもしれないと思いました。 @kfly8 : ぜひ最後にひとことを。 @dorapon2000 : 技術研修は正直大変でしたけれど、新人が質問してきたことに対して、全て真摯に返してきたつもり。放り投げたことはないかなと。何か気になること、学びたいことなどあったら、気軽に質問してもらえると良いなと思っています! @yokoi0803 : 新人たちが技術研修で学んだことは、まだ基本的なことで、実際のプロダクト開発をしていくには、まだ身に着けないといけないことはありますし、優れたエンジニアになるにはもっともっとという話はあると思います。一緒に頑張っていきましょう! @kfly8 : いいね。 dorapon2000、yokoi0803 インタビューありがとうございました! モバイルファクトリーでは、エンジニア採用を行っています。 カジュアル面談も実施していますのでぜひお気軽にご連絡ください。 カジュアル面談の一覧へ
アバター
こんにちは、ブロックチェーンチームの id:odan3240 です。 モバファクには 「シェアナレ!」という社内勉強会制度 があります。この制度の時間を使用してゴールデンウィーク(以下GW)中に個人が趣味開発で行ったことを共有する会を開催しました。 この会は以下の LINE Engineering Blog の記事に触発されたのがきっかけでした。 engineering.linecorp.com この記事ではGW自由研究発表会の様子を紹介します。 発表概要 発表した人は6名でその概要は次の通りです。 Content-Security-Policy などのセキュリティに関するヘッダーを設定してくれる Perl モジュールの開発 TypeScript で Switch を式のように扱うにはどうすればいいかの研究 Go で編集距離を計算する CLI ツールの開発 C# AST から HLSL/ShaderLab AST に変換するトランスパイラの開発 自作サイトを Nuxt.js => Next.js でリライト 自作 MIDI コントローラー開発に向けた調査 発表内容 この中の発表のうちいくつか詳細を紹介します。 HTTP::SecureHeaders 「Content-Security-Policy などのセキュリティに関するヘッダーを設定してくれる Perl モジュールの開発」で発表されたライブラリです。 頑張ったポイントとして、 W3C の仕様を読んで適切でない値なら弾くようにしているそうです。 github.com また、これを利用する Plack のミドルウェアの Plack::Middleware::SecureHeaders も開発したとのことでした。 switch-expression.ts 「TypeScript で Switch を式のように扱うにはどうすればいいかの研究」で発表されたコードです。 発表のモチベーションは、組み込みの switch-case だと各ケースでマッチした条件に当てはまる値を再代入しないといけないのが嫌で試しに書いてみた、とのことでした。具体的には次のコードの let result; を指します。 const condition: string = "hoge" ; let result ; switch ( condition ) { case "hoge" : result = "foo" ; break; case "fuga" : result = "bar" ; break; default : break; } この課題を解決するために switchExpression という関数を作成しマッチした条件に当てはまる値を返すように実装した、とのことでした。 単純に値を返すだけでなく、型ガードを使って case に降ってくる値の型を制御する工夫がされています。 github.com 感想 以下、発表者以外の参加者も含む感想の紹介です みんな思い思いのものを作っており、(おそらく)その人が一番得意で好きなものを知れてめちゃめちゃ良かったです 実際触ってみて周囲の技術でこんなんあったよ!みたいなのが聞けてよかった Web 以外の話も多くて、普段あまり触れないので新鮮で楽しかった(ハードウェアetc) 作ってみた系の発表からは作ってみた系の発表からしか得られない養分がある ハードウェア周りとか普段触れないけどこうやって聞くと楽しそうでちょっと興味出てきました 各々、セキュリティの話からWeb系やハードウェアなど広い分野の話が聞けて、内容もそれぞれの着眼点も含めて面白かった。 様々な分野・内容の興味深い話が聞けてよかったです。創作意欲をくすぐられて、自分も何かやりたくなりました。 終わりに GW明けに「GW自由研究発表会」を開催しました。仕事でも馴染みのある Perl/TypeScript の話題から、Go や ShaderLab や MIDI に関する話題まで幅広い内容が発表されました。 参加者からは好評だったので「シルバーウィーク自由研究発表会」なども検討したいと考えています。
アバター
Falseになります。 なぜか? eqは何か?   eq は、文字列同士が一致しているか確かめる演算子です。より詳しく言えば、SV(Scalar Value/スカラ値)という構造体の中のPV(Pointer Value/文字列)を比較します *1 。スカラ値の文字列を利用することを、Perlならではの用語で言えば「値を文字列コンテキストで評価する」と言います。  Perl以外の言語では、値が一致するか比較する演算子は == だけが用意され、文字列同士で比較したいなら、 a.toString == b.toString のように明示的に値を変換したりします。Perlの場合、数値として比較したいならば、 == を使い、文字列として比較したいならば、 eq を用います。 eq を使った場合、値は暗黙的に文字列として評価された値同士で比較されます。  こういった演算子に呼応し暗黙的に値が変わる背景は、作者のLarry Wall氏が自然言語のようにPerlをした言語設計したことが背景にあります。私なりに解釈で例え話をすると、例えば子供が「牛乳!」と叫んでいれば、親としては「牛乳がほしい」と読み取れると思います *2 。日常のコミュニケーションでは、コンテキスト次第で伝えた文字以上の情報を受け取れます。これは慣れた人同士でのコミュニケーションを円滑にします。一方、知らない人とのやりとりでは、曖昧さを生みます。 !!0は何か?   ! は否定演算子です。 ! を2つ重ねることで、元の値を真偽値としてみなした値となります。banban演算子と呼ばれ、真偽値を表現したい時に使い、 !!0 であれば、Falseを表現しています *3 。  Devel::Peekで !!0 のperl内部の状態を詳しくみてみましょう。 ➜ perl -MDevel::Peek -e 'Dump !!0' SV = PVNV(0x7fd3a58097f0) at 0x10f94d560 REFCNT = 2147483645 FLAGS = (IOK,NOK,POK,READONLY,PROTECT,pIOK,pNOK,pPOK) IV = 0 NV = 0 PV = 0x10f91e415 "" # ←ここに注目 CUR = 0 LEN = 0  PVに注目してください。 PV = 0x10f91e415 "" の意味は、アドレス 0x10f91e415 に、空文字 "" が格納されているという意味です。  この !!0 は何も特別な値ではなく、例えば、 2<1 といった数値の大小比較の結果など偽を返す条件式の返り値と同じ値になります。 ➜ perl -MDevel::Peek -e 'Dump 2<1' SV = PVNV(0x12600a7f0) at 0x126008958 REFCNT = 2147483647 FLAGS = (IOK,NOK,POK,READONLY,PROTECT,pIOK,pNOK,pPOK) IV = 0 NV = 0 PV = 0x102ef6759 "" CUR = 0 LEN = 0 !!0 eq 0の正体   !!0 eq 0 は、文字列の等価演算子 eq を用いているので、 !!0 と 0 を文字列コンテキストで評価します。文字列として評価すると、 !!0 は空文字 "" 、 0 は文字列 "0" となります。空文字 "" と文字列 "0" は値が一致しないので、 !!0 eq 0 の結果はFalseとなります。 *1 : https://github.com/Perl/perl5/blob/d49261a994af573600a092db8e91dea2459b9f8a/sv.c#L7908-L7910 *2 : 親としては、「牛乳!」だけでなく何をしてほしいかちゃんと話してほしいところですが *3 : perl5.36から導入されたbuiltin::falseと、!!0は一致します
アバター
みなさんこんにちはエンジニアのEadaedaです。 皆さんのチームではAPIドキュメントの生成に何をお使いですか?UniqysチームではReDocを使っています。 nestjs/swagger を使ってコントローラーから生成したOpenAPIの定義ファイルを与えるだけでリッチなドキュメントを作ってくれるのでいい感じです。 github.com プロダクトの開発をすすめるうちに、Webhookに関するドキュメントも必要になりました。しかし、 nestjs/swagger (2022/05/25時点のlatestである v5.2.1)では、Webhookのドキュメント生成に標準対応していませんでした。この記事ではこの問題に対処する方法の一つを紹介したいと思います。 前置き OpenAPI 3.1で webhooks フィールドを用いてWebhookのドキュメントを生成する OpenAPI 3.1からは webhooks というフィールドが追加になったので、これを使ってReDocにドキュメントを生成させることができます。例えば以下のような定義ファイルだとして { " openapi ": " 3.1.0 ", " info ": { " title ": " とてもすごいAPI ", " description ": " すごいAPIのドキュメントだよ ", " version ": " 1.0 " } , " components ": { " schemas ": { " Model ": { " type ": " object ", " properties ": { " name ": { " type ": " string ", " example ": " API太郎 ", " description ": " あなたの名前だよ " } , " age ": { " type ": " number ", " example ": " 3000 ", " description ": " あなたの年齢だよ " } } } } } , " webhooks ": { " sugoi-webhook ": { " post ": { " summary ": " すごいWebhook ", " operationId ": " sugoi-webhook ", " tags ": [ " Webhook " ] , " description ": " すごいWebhookを送信するよ ", " requestBody ": { " description ": " Webhookにより送信されるデータだよ ", " content ": { " application/json; charset=utf-8 ": { " schema ": { " $ref ": " #/components/schemas/Model " } } } } , " responses ": { " 200 ": { " description ": "" } } } } } } 以下のようなドキュメントが生成されます。 とてもいい感じですね。これを使ってドキュメント更に充実させていきたいところですが、先にも述べたように、 nestjs/swagger では webhooks を含むような定義ファイルを生成できません。さらに言うとOpenAPI 3.0な定義ファイルを生成するので、 webhooks フィールドも使えませんでした。 OpenAPI 3.0 で x-webhooks フィールドを用いて、Webhookのドキュメントを生成する なにか解決策は無いかと色々探していたところ、ReDocのドキュメントに x-webhooks というものを発見しました。 redocly.com x-webhooks フィールドをOpenAPIのルートに記述することで、OpenAPI 3.1の webhooks で生成されるドキュメントをOpenAPI 2.0/3.0でも生成できるようです。試してみましょう。 { " openapi ": " 3.0.0 ", " info ": { ... } , " components ": { ... } , " x-webhooks ": { " sugoi-webhook ": { " post ": { " summary ": " すごいWebhook ", " operationId ": " sugoi-webhook ", " tags ": [ " Webhook " ] , " description ": " すごいWebhookを送信するよ。OpenAPI 3.0だけど`x-webhooks`を使って書いているよ ", " requestBody ": { " description ": " Webhookにより送信されるデータだよ ", " content ": { " application/json; charset=utf-8 ": { " schema ": { " $ref ": " #/components/schemas/Model " } } } } , " responses ": { " 200 ": { " description ": "" } } } } } } 良さそうですね。 本題 swaggerの定義ファイル生成時に x-webhooks を差し込み、Webhookのドキュメントを生成する OpenAPI 3.0な定義ファイルを生成する nestjs/swagger では、 x-webhooks を使えば良いことはわかりました。ただ、定義ファイル生成のたびに手で追記するのは大変なのでどうにか自動で行いたいです。いくつか方法はあると思うのですが、ここではTypeScriptで生成したドキュメントオブジェクトに直接挿入する方法で行いたいと思います。 import { SwaggerModule , DocumentBuilder } from "@nestjs/swagger" ; import { INestApplication } from "@nestjs/common" ; export function build ( app: INestApplication ) { const options = new DocumentBuilder () .setTitle ( "とてもすごいAPI" ) .setVersion ( "1.0" ) .setDescription ( "すごいAPIのドキュメントだよ" ); const document = SwaggerModule.createDocument ( app , options ); ( document as any ) [ "x-webhooks" ] = { "sugoi-webhook" : { post: { summary: "すごいWebhook" , operationId: "sugoi-webhook" , tags: [ "Webhook" ] , description: "すごいWebhookを送信するよ。OpenAPI 3.0だけど`x-webhooks`を使って書いているよ" , requestBody: { description: "Webhookにより送信されるデータだよ" , content: { "application/json; charset=utf-8" : { schema: { $ref: "#/components/schemas/Model" } } } } , responses: { 200 : { description: "" , } , } , } , } , } ; return document ; } 特に工夫もないですが…。後はこの関数が返してきたオブジェクトをファイルに書き出すだけですね。 まとめ OpenAPI 3.1からは webhooks フィールドを定義すると、ReDocでWebhookのドキュメントが生成されるようになる OpenAPI 3.0では x-webhooks フィールドを代わりに定義することで、同様にReDocでWebhookのドキュメントが生成されるようになる しかし、 nestjs/swagger (v5.2.1)では、 webhooks と x-webhooks に標準対応していない そこで、 x-webhooks を直接差し込むコードを記述し、定義ファイルの生成時に実行することで自動生成をするようにした ちなみに、この対応は以下のIssueが解決するまでの対応となります。 github.com 以上です。
アバター
こんにちは、ブロックチェーンチームのソフトウェアエンジニアの id:odan3240 です。 ブロックチェーンチームでは、 NFT を販売するための Uniqysマーケットプレイス (以下、ユニマ)と、NFT サービス構築支援プラットフォームの ユニキス ガレージ (以下、ガレージ)を開発しています。ユニマはブロックチェーン上の NFT を日本円で売買可能なマーケットプレイスです。 以下の記事でユニマとガレージの技術スタックを紹介しました。 tech.mobilefactory.jp この記事では触れていませんでしたが、どちらのサービスも単一のリポジトリ(いわゆるモノレポ)で開発しています。 この体制の上で見つけた TypeScript のインポートの書式のミスマッチの問題とその解決策を紹介します インポートの書式のミスマッチ 技術スタックの記事でも言及している通り、フロントエンドの実装には NuxtJS を使用しています。NuxtJS はファイルのインポートのパスのエイリアスを設定する思想のフレームワークです 1 。そのためファイルのインポートは絶対パスを使用しています。 一方でバックエンドは、 tsconfig.json の paths を設定するとビルド設定に変更が必要になりプロジェクトの構成のシンプルさがなくなるという問題があります。そのためファイルのインポートには相対パスを使用しています。 このようにフロントエンドでは絶対パス、バックエンドを相対パスを使用していて書式にミスマッチが存在します。 VSCode の Quick Fixes VSCode は解決ができない変数や関数を見つけると、 Quick Fixes でファイルのインポートを提案する場合があります。 この提案で提示されるインポートの書式は typescript.preferences.importModuleSpecifier で決定されます。この設定はデフォルトだと、提案するときに絶対パスと相対パスのどっちを使うかを空気を読んでくれます。しかしモノレポのパッケージごとにインポートの書式が決まっている場合、期待している書式とは別の書式が提案されると開発体験を損ねます。 Multi-root Workspaces による解決 この問題を解決するために VSCode の Multi-root Workspaces を使用した方法を紹介します。VSCode の Workspace には様々な機能、役割がありますが、その1つに設定ファイルの .vscode/settings.json と1:1対応する点があります。 つまり Multi-root Workspaces を使用すると各フォルダごとに .vscode/settings.json を用意できます。 以下はサンプルリポジトリです。 github.com Multi-root Workspaces のために sample.code-workspace を用意します。 { " folders ": [ { " path ": " packages/backend " } , { " path ": " packages/frontend " } , { " name ": " root ", " path ": " . " } ] } これにより、バックエンドとフロントエンドごとに .vscode/settings.json を用意することができます。 packages/backend/.vscode/settings.json は次のとおりです。 { " typescript.preferences.importModuleSpecifier ": " relative " } packages/frontend/.vscode/settings.json は次のとおりです。 { " typescript.preferences.importModuleSpecifier ": " non-relative " } これによりバックエンドでは相対パス、フロントエンドでは絶対パスのインポートができるようになりました。 バックエンドの例 フロントエンドの例 まとめ モノレポ構成において、Multi-root Workspace を使うことで VSCode の設定を各パッケージごとに出し分ける例を紹介しました。 VSCode の設定の競合に困っている方はぜひ検討してみてください。 https://nuxtjs.org/docs/configuration-glossary/configuration-alias/ ↩
アバター
こんにちは。エンジニアの id:kfly8 です。 3/4(金) 3/5(土) に、Japan Perl Associationが主催するPerlに関するオンラインカンファレンス「YAPC::Japan::Online 2022」が開催されました。 yapcjapan.org モバファクでは、 駅メモ! や 駅奪取 などのプロダクトでPerlを利用しています。Perlコミュニティへの恩返しの意味も込めて、モバファクではイベントTシャツスポンサーとして協賛させていただきました。 また、私自身もYAPCの運営として、スポンサー担当、ノベルティ担当、ゲスト対談担当、スピーカー担当、学生交流支援担当、オープニング担当、オンライン会場選定、タスク管理、予算管理などしました。この運営話は追々できればと思います。ここでは、モバファクから登壇したメンバーのコメントを紹介したいと思います! kimuson / TypeScript へ型安全性を高めながらリプレースする speakerdeck.com 今日 YAPC で登壇させていただいた資料です! ありがとうございました! TypeScript へ型安全性を高めながらリプレースする https://t.co/O8UnAdPwrk #yapcjapan — きむそん (@_kimuson) March 4, 2022 ひとこと Perl とはやや離れたネタですが、TypeScript への移行話についてトークさせていただきました。 こういう場で登壇するのは初めてだったので緊張していたんですが、非常に温かい雰囲気で話しやすかったです。 盛り上げてくださった運営・参加者の皆さんありがとうございました! kfly8 / Tシャツに書かれたコードを読む speakerdeck.com tech.mobilefactory.jp github.com ひとこと use Acme::Kusa; wWwWwWwWwWwWwWwWWWwwwWwww wWWwWWwWw wWwWWwwWW WwWWwWwWw wWWwwwwww WwwWwwwWW wwwwwwwWw wWWwWwWWw WwWwWWWwW WwwWWWwWw wwwWWwwWW WwWwwwwww WWWwwwWWw WWwwWwWww wwwwwwWWW wwWwwWWWw WwwWwWWww WWWwWWwww WwWWWwwww wwWwwwWww wWwwwwWwW wWwwwwWwW WwWwwwwWW wwWWWwWWw WWwWwWWww wwwwWwwWw wWWwWwWWW WwWWwWwWw WWWwWwwww WwwwwwwwW wwWwwWWwW wWwwwwwWw wwwwWwWwW WwwwwWwwW wwwWwwwWw Wwwww モバファクでは、「YAPC::Japan::Online 2022」だけにとどまらずOSSやコミュニティの支援を積極的に行っていきます。モバファクに少しでも興味を持っていただけた方は、カジュアル面談を実施していますのでお気軽にお申込みください! カジュアル面談のお申し込み あわせて、こちらの採用サイトもご覧ください。 recruit.mobilefactory.jp
アバター
こんにちは。エンジニアの id:kfly8 です。 技術カンファレンスのノベルティで、コードを載せたデザインってイイですよね。謎解き要素で遊び心をくすぐりつつ、デザイン的にも普段使いしやすくかっこいいんですよね。リブセンスさんから2015年にもらったトートバッグなんかは、未だに使っています。 hiragram.hatenablog.jp そんなノベルティを一度でいいから作ってみたかったんです…… つくりました!!!! 手前味噌ですが、最初にデザインを見せてもらったとき、ビビビときました。カッコイイ。ビ○ムスさんとか街にある服屋さんにあっても、わからない。多分。一目惚れでした。 YAPC::Japan::Online 2022 のロゴは、結び目がモチーフでどこか繋がりを感じるデザインです。結び目から着想した糸を34行のコードの上にあしらい、見かたによってはケーブルコードにも見えるので、”コードにコード”をかけたダジャレにもなっている。いやー本当に最高ですね! はい。 さてイベント T シャツに書かれたこのコード。解読いただけたでしょうか?この後に続く解説を読むことなく、解読した方は個人的にお寿司を奢るので教えてください。 美味しいお寿司の写真です このTシャツを見てみると、赤い点が並んでいます。このままでは意味がわかりません。 しかし、コードに何が書いてあるかわからないまま、このTシャツを着たら気持ちわるいですよね!変なメッセージかもしれません(そんなことはありません) 気持ちよく着れるように責任を持って解説をします。この後に続く解説を読めば誰でも30分くらいで解読できるようになります。個人差はあると思うので、予めご了承ください。 Acme::Bleachとは? 一行目に書かれた Acme::Bleach コードの1行目に、Acme::Bleachとあります。Acme::Bleachというと、次のようなプリント文が書かれたコードを、ホワイトスペースだけのコードに変換してしまうジョークモジュールです。 コードが”漂白”されても動くだと・・?! Perl Best Practiceなどで知られるDamian Conway先生が書いた最初のAcmeモジュール *1 です。Acmeモジュールというと、makamakaさん曰く"一見何の役に立つかわからないけれども、やはり実際役に立たない" *2 …はずなのに、今回、Tシャツ作りで役立ってしまいました。Thank you very much, Dr. Damian. Acme::Bleachの動作原理はシンプルです。 まずコード文字列をビット列に変換し、次にビット列の0をスペースに、1をタブに変換し、ホワイトスペースだけのコードに「漂白」をします。そして「漂白」されたコードを逆変換して元のコードに戻します。大雑把に言えば、スペースとタブでビット列を表しているのが肝です。 この動作原理を利用すれば、.(ドット)と-(ハイフン)を利用し、モールス信号っぽく変換するAcme::MorseといったAcmeモジュールの意味も理解しやすくなると思います。 しかし、まだ、このTシャツのコードを読み解くことはできません。 読み解くには、この動作原理に加え、次の2つのヒントが必要になります。 ヒント1: コードの先頭に、” \t(スペース+タブ)x8”の「ネクタイ」がつけられること ヒント2: 9文字区切りで改行されること Acme::Bleachのコードは16行だけなので、ここから詳解します。もしイベントTシャツの意味が早く知りたい場合は、動作原理とこの2つのヒントを念頭に置いて、読み飛ばしてください。 Acme::Bleachの詳解 Acme::Bleachのコードは以下の通りです。一つ一つ解説をしましょう。 1 : package Acme::Bleach ; 2 : our $VERSION = '1.150' ; 3 : my $tie = " \t " x8; 4 : sub whiten { local $_ = unpack "b*" , pop ; tr/ 01 / \t / ; s/ (.{9}) / $1 \n /g ; $tie . $_ } 5 : sub brighten { local $_ = pop ; s/ ^ $tie |[^ \t ] //g ; tr/ \t / 01 / ; pack "b*" , $_ } 6 : sub dirty { $_[ 0 ] =~ / \S / } 7 : sub dress { $_[ 0 ] =~ / ^ $tie / } 8 : open 0 or print "Can't rebleach ' $0 ' \n " and exit ; 9 : ( my $shirt = join "" , < 0 >) =~ s/ (.*) ^ \s* use \s+ Acme::Bleach \s* ; \n //sm ; 10 : my $coat = $1 ; 11 : my $pressed = '#line ' . ( " $coat \n " =~ tr/ \n / \n / ) . ' ' . ( caller )[ 1 ] . " \n " ; 12 : local $SIG{ __WARN__ } = \ &dirty ; 13 : do { eval $coat . brighten $shirt ; print STDERR $@ if $@ ; exit } 14 : unless dirty $shirt && not dress $shirt ; 15 : open 0 , "> $0 " or print "Cannot bleach ' $0 ' \n " and exit ; 16 : print { 0 } " ${coat} use Acme::Bleach; \n " , whiten $pressed . $shirt and exit ; 3行目: my $tie = " \t"x8; スペースとタブでできたネクタイです。後ほど、シャツにネクタイを結ぶ、といったくだりがでてきます。 4行目: sub whiten { local $_ = unpack "b*", pop; tr/01/ \t/; s/(.{9})/$1\n/g; $tie.$_ } これは改行を加えると次のようになります。 sub whiten { local $_ = unpack "b*" , pop ; tr/ 01 / \t / ; s/ (.{9}) / $1 \n /g ; $tie . $_ } これはコードを漂白をする関数です。呼び出している箇所を見ると第一引数に渡されるのは”シャツ”と呼ぶコード文字列です。 つまりシャツをクリーニングする関数です。シャツと呼ぶコード文字列を、 unpack “b*” して、ビット列にします。 デフォルト引数の $_ にいれ、この後に続く置換を省略して書けるようにしています。 tr/01/ \t/ で、0をスペースに、1をタブに置換しています。 s/(.{9})/$1\n/g で、9文字区切りで、改行コードをいれています。 $tie.$_ で、ネクタイを先頭に結びます。 5行目: sub brighten { local $_ = pop; s/^$tie|[^ \t]//g; tr/ \t/01/; pack "b*", $_ } これも改行を入れると、次のようになります。 sub brighten { local $_ = pop ; s/ ^ $tie |[^ \t ] //g ; tr/ \t / 01 / ; pack "b*" , $_ } s/^$tie|[^ \t]//g で、ネクタイと改行コードを取り除きます。 tr/ \t/01/ で、半角スペースを0に、タブを1に置換し、ビット列にします。 pack "b*", $_ で、ビット列を文字列に戻します。 漂白されたコードに光をあて、元のコード文字列を浮き上がらせます。 6行目: sub dirty { $_[0] =~ /\S/ } ホワイトスペース以外に一致した数を返します。漂白されていない文字は汚いとみなしています。 7行目: sub dress { $_[0] =~ /^$tie/ } ネクタイを結んでいるかどうか確認し、漂白済みかどうかの判定に使います。 コードが、ドレスコードを満たしているかどうかといった命名でしょうか。洒落てますね。 8行目: open 0 or print "Can't rebleach '$0'\n" and exit; open 0 は、実行されているプログラム自身を、openしようとしています。1引数のopenはレガシーな使い方で、 open HOGE のようにファイルハンドラにHOGEを指定すると、同名の $HOGE というパッケージ変数に指定されているファイルパスをopenしようとします。 open 0 であれば、 $0 を開こうとします。 $0 はPerlの特殊変数で実行されているプログラム自身を指します。 9,10行目: (my $shirt = join "", <0>) =~ s/(.*)^\s*use\s+Acme::Bleach\s*;\n//sm;my $coat = $1; my $shirt = join "", <0> で、ファイルの中身を読み込みます。 そして読み込んだファイルを、 use Acme::Bleach; より手前に書かれたコードを、 $coat use Acme::Bleach; 以降に書かれたコードを、 $shirt と命名しています。 11行目: my $pressed = '#line ' . ("$coat\n" =~ tr/\n/\n/) . ' ' . (caller)[1] . "\n"; "$coat\n" =~ tr/\n/\n/ で、 use Acme::Bleach;が書かれた行数を算出しています。 (caller)[1] はファイル名です。 つまり、 use Acme::Bleach; と書かれた行を、“#line 行数 ファイル名”といったコメント行にします。 12行目: local $SIG{__WARN__} = \&dirty; 漂白されたコードで警告を抑制します。 13,14行目: do { ...中略 } unless dirty $shirt && not dress $shirt; このdoブロックを整形すると次のようなコードになります。 do { eval $coat . brighten $shirt ; print STDERR $@ if $@ ; exit } unless dirty $shirt && not dress $shirt ; 漂白済みのシャツであれば、brightenで元々のコード文字列に戻し、evalで実行しています。 15行目: open 0, ">$0" or print "Cannot bleach '$0'\n" and exit; 実行ファイル自身を上書きするためのファイルハンドラを用意します。 16行目: print {0} "${coat}use Acme::Bleach;\n", whiten $pressed.$shirt and exit; 漂白されていないシャツを、漂白してファイルを上書きをしています。 詳解補足 初見では、コードの圧縮や特殊変数や意図のよくわからない変数名で読みにくいと思います。 けれど、動作原理を理解し、丁寧に読むと「コードを、上着とシャツにわける」「クリーニングしたシャツにネクタイを締める」「いらない行はアイロンでプレス」「ネクタイを締めているかどうかがドレスコードになっている」などなど紳士服を思わせる粋なコードです。 Tシャツに書かれたコードは、TMTOWTDI まず、2行目以降の謎の赤い点は何でしょうか? Acme::Bleach はスペースとタブに「漂白」をするので、赤い点はスペースかタブのどちらかと推測できます。 「ヒント1: コードの先頭に、” \t(スペース+タブ)x8”のネクタイがつけられること」から、2行目の1文字目はスペースだと確定します。これにより「赤い点はスペース」と予想できます。赤い点がスペースだとわかれば約1.5cm幅の空白はタブだとわかります。行末の鍵マークは、改行です。文字が判別できるようになりました。 次に各行がなんと書かれているか判別をします。 3行目は`space tab tab space tab tab space tab space` 「ヒント2: 9文字区切りで改行」から、例えば、3行目は、赤い点が4つあり、タブの数は9-4=5個 と判別できます。タブが1.5cm幅なので、定規をあてつつ測れば、 space tab tab space tab tab space tab space とわかります。簡単ですね。 この要領で、34行分数えます。根気のいる作業ですが、鍛えられた目grep力でがんばりましょう! 転写する時、スペースは0に、タブは1と記載すると、ホワイトスペースより見やすく、可読性が上がります。 0101010101010101110001000 011011010 010110011 101101010 011000000 100100011 000000010 000101010 101100100 010101011 110010111 010100010 101000100 010100100 100111010 000001110 001101100 101000000 001110010 011101001 011001110 110001011 100000010 001000100 001010101 011001000 101010111 100101110 101000101 010001000 101001001 001000100 01010000 このビット列から改行とネクタイを除去して、packすると次のコードが見えます。 perl -pe 's/\n//g; s/^0101010101010101//;' hoge.pl | perl -pe '$_ = pack "b*", $_' #line 1 TMTOWTDI.pl print "TMTOWTDI" 解読できました✌✌✌ これなら安心して着れそうですね! まとめ このTシャツには、Perlのスローガンの"There's More Than One Way To Do It." (やり方はひとつじゃない) 、略してTMTOWTDIが込められていました。弊社のエンジニアはもちろん、YAPCに参加される多くの方が好きな言葉の1つだと思います *3 。YAPC楽しいですね!!!! 宣伝 弊社からは、TypeScriptのリプレースの話でkimusonが登壇しました。 tech.mobilefactory.jp モバイルファクトリーでは、エンジニアのカジュアル面談を実施しています。PerlやTypeScriptのお仕事に興味を持っていただけなら、ぜひお気軽にご連絡ください。 カジュアル面談のお申し込み あわせて、こちらの採用サイトもご覧ください。 recruit.mobilefactory.jp *1 : https://gihyo.jp/dev/serial/01/perl-hackers-hub/001901?page=1 *2 : https://b.hatena.ne.jp/entry/s/gihyo.jp/dev/serial/01/perl-hackers-hub/001901 *3 : 個人的には、TMTOWTDIの哲学は好きですが、コードを書く時は、TIMTOWTDIBSCINABTEが好き。 https://blog.urth.org/2011/03/23/reviewing-perl-best-practices-chapter-15-objects
アバター
こんにちは。エンジニアのEadaedaです。 皆さんのチームではGithub Actionsで aws-actions/configure-aws-credentials を使っていますか?GitHub ActionsでAWS SDKやAWS CLIを使うために必要なクレデンシャルなどを設定してくれるactionで、我々のチームでは最近かなり利用するようになりました。 github.com 使うためにはIAM IDプロバイダが必要で、そのリソース管理をTerraformで行っているというパターンは多いと思います。例えば以下のようなtfファイルを書きますよね。 resource "aws_iam_openid_connect_provider" "github_actions_oidc" { url = "https://token.actions.githubusercontent.com" thumbprint_list = [ "ここにthumbprint" ] client_id_list = [ "sts.amazonaws.com" ] } ここで困るのがコード中に書いた ここにthumbprint の部分です。サムプリントは計算方法がAWSより案内されているので、そのとおり計算し結果をコピペするだけです。 docs.aws.amazon.com とはいえ、ルート証明書が変更されるたびにサムプリントの値を計算・コピペ・ terraform apply するというのは少々めんどくさいし、計算・コピペは人間がやる作業なので間違いが起こりやすいです。そこでTerraformの tls_certificate データリソースを使って、サムプリントの計算もTerraformにさせましょう。 registry.terraform.io certificates の0番目はルート証明書を指す ことを利用して下記のように記述できます。 data "tls_certificate" "github_actions_oidc_provider" { url = "https://token.actions.githubusercontent.com/.well-known/openid-configuration" } resource "aws_iam_openid_connect_provider" "github_actions_oidc" { url = "https://token.actions.githubusercontent.com" thumbprint_list = [ data.tls_certificate.github_actions_oidc_provider.certificates [ 0 ] .sha1_fingerprint ] client_id_list = [ "sts.amazonaws.com" ] } 更新時に人間がやることは terraform plan で新しいサムプリントと確認することと、差分が大丈夫であれば terraform apply するだけとなりました。 以上です。
アバター
こんにちは。 id:kfly8 です。 2022年3月4日(金), 3月5日(土)に開催されるYAPC::Japan::Online 2022にて、モバイルファクトリーのエンジニアの kimuson が「TypeScript へ型安全性を高めながらリプレースする」と題して登壇します。 登壇は3月4日(金) 20:00からでゲスト対談の直後の予定です。トーク概要は、次の公式サイトをご覧ください。 yapcjapan.org YAPCは、Perlを軸としたイベントではありますが、バックエンドのエンジニアがWebフロントエンドの実装をすることは少なくないと思います。運用歴の長くフロントエンドの環境がレガシーなプロダクトで開発をしている人や、JavaScript を使ってる or TypeScript に置き換え済みだが緩いオプションで思うように恩恵を受けられていない人に向けて、登壇をします。 kimusonは、最近だと次のような技術ブログを書いています。 tech.mobilefactory.jp tech.mobilefactory.jp tech.mobilefactory.jp 最後に、登壇にあたりkimusonに意気込みを聞いてみました。 こういう場で登壇するのは初めてなので緊張しています。 技術ブログに書いた「メリハリのあるTypeScript」が軸になった内容ですが、今回の登壇ではできるだけ TS にロックインせずに、幅広いエンジニア向けに TypeScript や漸進的型付けについて話せたら(ないし布教できたら)と思ってます。 興味持って頂ける内容になってると思うので、ぜひおこしください! モバイルファクトリーでは、エンジニアのカジュアル面談を実施しています。TypeScriptの裏側など興味を持っていただけなら、ぜひお気軽にご連絡ください。 カジュアル面談のお申し込み あわせて、こちらの採用サイトもご覧ください。 recruit.mobilefactory.jp
アバター
こんにちは、エンジニアの夕凪です。 最近、 GitHub Actions が OIDC を正式サポート し、 AWS や GCP へのセキュアなデプロイが可能になりました。 そのうちの GCP の公式実装である google-github-actions/auth を使って、 Firebase へデプロイを行ってみたので、この記事ではそのやり方を解説します。 前提条件 この記事は以下の環境を前提としています。 google-github-actions/auth v0.4.3 Google Cloud SDK 370.0.0 ( gcloud --version ) Google Cloud Platform へのアクセス権限があること GCP 側でやること まずは GCP 側でサービスアカウントの準備などが必要なので、それらを作成していきましょう。 以下ちょっと特殊ですが、 fish shell からコマンドラインでの操作例を記載しておきます。 $ set -x PROJECT_ID < 対象のGCPのプロジェクトID (Firebase のプロジェクトID) > $ set -x SERVICE_ACCOUNT_NAME < 発行するサービスアカウント名 > # まずは、 Service Account を発行します $ gcloud iam service-accounts create $SERVICE_ACCOUNT_NAME --project $PROJECT_ID Created service account [hogehoge] $ set -x SERVICE_ACCOUNT " $SERVICE_ACCOUNT_NAME @ $PROJECT_ID .iam.gserviceaccount.com" # ここでは最低限のロールを割り当てていきます # 今回は Firebase Hosting と Firebase Functions を使用します # GCP/Firebase 側より細かく設定したい場合は、代わりにそれらを設定してください $ gcloud projects add-iam-policy-binding $PROJECT_ID --role= "roles/iam.serviceAccountUser" --member "serviceAccount: $SERVICE_ACCOUNT " $ gcloud projects add-iam-policy-binding $PROJECT_ID --role= "roles/serviceusage.apiKeysViewer" --member "serviceAccount: $SERVICE_ACCOUNT " $ gcloud projects add-iam-policy-binding $PROJECT_ID --role= "roles/firebaserules.systen" --member "serviceAccount: $SERVICE_ACCOUNT " $ gcloud projects add-iam-policy-binding $PROJECT_ID --role= "roles/firebasehosting.admin" --member "serviceAccount: $SERVICE_ACCOUNT " $ gcloud projects add-iam-policy-binding $PROJECT_ID --role= "roles/cloudfunctions.developer" --member "serviceAccount: $SERVICE_ACCOUNT " # IAM Service Account Credentials API を有効にします $ gcloud services enable iamcredentials.googleapis.com --project $PROJECT_ID # Workload Identity Pool の作成をし、その ID を取得します $ set -x POOL_NAME < Workload Identity Pool の名前; なんでも OK > $ gcloud iam workload-identity-pools create $POOL_NAME --project= $PROJECT_ID --location= "global" --display-name= $POOL_NAME $ gcloud iam workload-identity-pools describe "github-actions-pool" --project= $PROJECT_ID --location= "global" --format= "value(name)" $ set -x WORKLOAD_IDENTITY_POOL_ID (上の出力結果) # OIDC Provider を作成し、その ID を取得します # attribute-mapping の値は必要に応じて変更してください # 今回はプライベートな対象リポジトリに存在するユーザーなら誰でも OK としています $ set -x OIDC_PROVIDER_NAME < OIDC Provider の名前; なんでも OK > $ set -x GITHUB_REPOSITORY "github/actions" $ gcloud iam workload-identity-pools providers create-oidc $OIDC_PROVIDER_NAME \ --project= $PROJECT_ID \ --location= "global" \ --workload-identity-pool= $POOL_NAME \ --display-name= $OIDC_PROVIDER_NAME \ --attribute-mapping= "google.subject=assertion.sub,attribute.repository=assertion.repository" \ --issuer-uri= "https://token.actions.githubusercontent.com" $ gcloud iam service-accounts add-iam-policy-binding $SERVICE_ACCOUNT \ --project= $PROJECT_ID \ --role= "roles/iam.workloadIdentityUser" \ --member= "principalSet://iam.googleapis.com/ $WORKLOAD_IDENTITY_POOL_ID /attribute.repository/ $GITHUB_REPOSITORY " $ gcloud iam workload-identity-pools providers describe $OIDC_PROVIDER_NAME \ --project= $PROJECT \ --location= "global" \ --workload-identity-pool= $POOL_NAME \ --format= "value(name)" 出力結果を控えておく GitHub Actions 側の設定 シークレットに入れても直接書いても環境変数として渡してもなんでも良いんですが、以下のような GitHub Actions を用意します。 このとき、 access_token_scopes を追加設定していること、 actions/checkout@v2 の後に実行していることについて注意してください。 name : Firebase へデプロイ on : # ここは好きにすると良い workflow_dispatch : jobs : deploy : runs-on : ubuntu-latest permissions : id-token : write contents : read steps : - uses : actions/checkout@v2 - uses : google-github-actions/auth@v0.4.3 with : access_token_scopes : 'email, openid, https://www.googleapis.com/auth/cloud-platform, https://www.googleapis.com/auth/firebase' workload_identity_provider : "控えておいた出力結果を貼る, projects/ACCOUNT_ID/locations/global... の形式" service_account : "発行したサービスアカウントの ID を貼る, name@PROJECT_ID.iam.gserviceaccount.com の形式" create_credentials_file : true - run : | yarn firebase deploy --only functions,hosting --project PROJECT_ID 最後に、上記の GitHub Actions をデフォルトブランチに追加して、 on に記述した方法で実行すれば、無事デプロイされます。 ということで、 OIDC を使った Firebase へのデプロイ方法の紹介でした。
アバター
はじめに こんにちは。エンジニアのまえけんです。 1月5日から3日間開催されたスクラムギャザリング2022に行ってきたので、イベントのレポートや感想をまとめようと思います。 2022.scrumgatheringtokyo.org スクラムギャザリングとは 日本のスクラム/アジャイルイベントとしては最大規模のイベント。全部で3日間あり、講演だけでなく、スクラム/アジャイル実践者と直接話せる機会もあります。 ※ギャザリングはgathering、集まりとかまとまりとかの意味 運営母体である一般社団法人スクラムギャザリング東京実行委員会は、スクラムを実践する人が集い垣根を超えて語り合う場を提供するという目的によりコミットしています。 なぜ参加したのか 以前からスクラムに興味があり、チームでもエンジニア兼スクラムマスターとしてスクラムを実践しています。これまでもスクラムガイドや各種本(アジャイルサムライ、エクストリームプログラミング、アジャイルな見積もりと計画づくり、etc)を色々読んでいました。しかし、 本からは知識が得られるが、経験者の知識は得られない スクラムを実践する上での悩みを解決したい スクラムマスターの責任とは 組織に対してスクラムの理解を得るには ふりかえりのコツとは スクラムマスターとしてのキャリア という事があり、ちょうど良い機会だと思ったのでイベントに参加してみました レポート 会場は御茶ノ水。1月5日〜1月7日の3日間開催。 会場は1階と2階にわかれていて、全部で6部屋ぐらいありました。 最初に渡される名札。その下に「CSM(認定スクラムマスター)」とか「SPONSOR」とか書かれている札をつけて、どんな人なのか分かるようになってました。自分は初回なのでFIRST TIMERをつけてました。 1日目と2日目はkeynoteとマルチトラックセッション。マルチトラックは各部屋ごとに講演をやっているので、自由に見に行く形です。どんな講演があったかは こちら 参照。 自分はマネジメント、スクラムイベント、プロダクトゴールを中心に見ていました。 3日目はOST(オープンスペーステクノロジー)とkeynoteでした。 オープンスペーステクノロジーは討論のやり方の形式の1つです。 議論したい人は、テーマを全員に話し、 あとは各自場所に分かれて議論をする。 議論に参加したい人はいつ来てもいいし、いつ抜けてもok。 自分はFIRST TIMERで 寂しかった 似た境遇の人が居ると思ったので初心者同士で情報交換する場にしました。結構たくさん(10人ぐらい?)の人が来てくれてよかったです。 3日目のkeynoteはTsuyoshi Ushioさん。以前バズっていた プログラミングというより物事が出来るようになる思考法 の人。MicrosoftのAzure component開発をしている人です。 アメリカの超巨大クラウドの 「中の人」に転生した ガチ三流プログラマが 米国システム開発の現実を リークする話 from Tsuyoshi Ushio 講演やオープンスペーステクノロジー以外にも、廊下で自然発生的にふりかえりがあったり、 アジャイルコーチの人と1on1で話せる場所があったり、ギャザリングできるような環境がたくさんありました。 コーヒー飲み放題で、お弁当も美味しかったです。 スクラムギャザリングは去年からオンラインとオフラインのハイブリット開催になっていて、講演もオープンスペーステクノロジーもすべてzoomで配信&discordでチャット可能になっていました。すべてオンラインで参加も可能だし、午前はオンライン、午後はオフライン、みたいに選択できたのも良かったです。 学び 3日間を通して得られた学びをまとめます 信頼、尊敬 良いチームに共通しているのは「信頼」「尊敬」の2つだと感じました。しかもそれはIT会社だとかソフトウェア開発だとかは関係無い。 星野リゾート 星野リゾートは以前からフラットな組織とマルチタスクの組織文化がある 現場が一番良く知っている 分業することで生まれる待ち時間を減らすために、マルチタスクでできるようにする 非ITの宿泊業なのに、なぜDXを推進できるのか? from 崇介 藤井 Microsoft 納期が無い(!) マネージャはチームメンバーを信頼し、支援をする アンブロックする メンバーは全力で取り組む また、アジャイルコーチが話していた言葉で 子供扱いすると子供のように振る舞う というのが確かにと思いました。 場(Ba)を作る 信頼、尊敬はじゃあどうやって出来るのかというと、場が必要。 スクラムの創設者の1人、ジェフサザーランド博士も当初から「場(Ba)というコンセプト」について言及していました(Roots of Scrum) 明確なビジョンとゴール ちょっと感想も含まれるんですが、場を作るためにじゃあなにから始めればよいのかというと、まずは明確なビジョンとゴールを作って共有するのが良いかなと思いました。 スクラムギャザリングでも、目標やゴールのセッションは多かったです プロダクトゴールとは?あるいはプロダクトのゴールを設定するには何が必要か? あなたのSprint Goalは、機能してますか? プロダクトバックログDeep Dive そもそも全員が同じ目標を向いていないと漠然とした不安(このままでも良いのか、チームが進んでいる方向は合っているのか)があるしその中で信頼は生まれにくい、と思いました。 感想 どこも同じ悩みを持っている 自分がこれまで持っていた悩みは自分だけじゃなくて他のチーム、他の会社も持っていることがわかったし、それ自体が発見でした。 同じ悩みを持っている人同士で話すのはそれだけでも救われるし、楽しいし、発見もありました。 定期的に他の会社の人と問題を共有する、話すのは今後もやっていきたいです。 銀の弾丸は無く、地道なローカルのアクションを積み重ねる 信頼を持つとか、明確なゴールを共有するとか、これらはまずチームの中で実践できる。「こうすればうまくいく」方法は今の所無い(スクラムも所謂フレームワークでしかない)。 逆に言うとスクラムとかアジャイルとか一旦置いといて、良いチームについて考えてそれを一歩一歩改善しながら目指すのが良いんだと思いました。むしろそうやっていった状態がアジャイルなのだと思います。 以上 スクラムギャザリング、超楽しかったです。来年も絶対行きたい!
アバター
こんにちは。エンジニアの id:kfly8 です。Japan Perl Associationの理事として、YAPCの運営もしているのですが、今回はモバイルファクトリーからのお知らせです。 モバイルファクトリーは、2022年3月4日(金), 3月5日(土)に開催されるYAPC::Japan::Online 2022にイベントTシャツスポンサーとして協賛いたします。イベントの詳細は公式サイトをご覧ください。 yapcjapan.org 今回、このTシャツに、Perlのスローガンの"There's More Than One Way To Do It." (やり方はひとつじゃない) 、略してTMTOWTDIの思いを込めました。弊社のエンジニアはもちろん、YAPCに参加される多くの方が好きな言葉の1つだと思います。YAPCに参加される皆さんが、TMTOWTDIを身につけ繋がりを感じながら、YAPCを楽しんでいただけたら幸いです。 Tシャツに印字されているコードがあるので、ぜひ実行してみてください😊 解説は、弊社の技術ブログで追って公開します。YAPC運営スタッフにお披露目した際は「カッコよい」「普段使いしやすい」と好評でした。感想をいただけると泣いて喜びます。 コードの上にコードが載っていることに気づいたときは痺れました モバイルファクトリーでは、エンジニアのカジュアル面談を実施しています。ノベルティづくりや技術カンファレンスの運営の裏側など興味を持っていただけなら、ぜひお気軽にご連絡ください。 カジュアル面談のお申し込み あわせて、こちらの採用サイトもご覧ください。 recruit.mobilefactory.jp
アバター