ぱいぱいにっき

ぱいぱいにっき

Pythonが好きすぎるけれど、今からPerlを好きになりますにっき

2024年の振り返りと2025年の抱負

2024年もいろんなことがありましたね。もうすぐ2025年です。皆様はいかがお過ごしでしょうか。というわけで去年の振り返りと今年の抱負について書いていきたいと思います。

前回

mackee.hatenablog.com

登壇とイベント

YAPC::Hiroshima 2024

yapcjapan.org

YAPC::Kyoto 2023に引き続き行って登壇しました。そんでもって広島は僕のホームと言える地です。学生時代によく行っていた紙屋町の電停を降りたときは感慨深かったですね。

発表したのはこちらです。YAPC::Kyoto 2023と同様ライブコーディングスタイルでパスキーのサーバーサイド実装を行なっていくものです。

speakerdeck.com

嬉しいことにこの登壇は面白かったとか、そういう声をいただいています。ライブコーディングの登壇を2025年は何回か出来ればなとは思っています。

広島はまたテック系のカンファレンスや勉強会があったら訪れてみたいです。特に母校とは完全に関係が切れてしまっているのですが、学生さんと話してみたいなと思いました。YAPC::Hiroshimaでも来られている方がいるとのことで探してはみたのですが、話すことはできなかった感じです。

あとこの時食べた牡蠣にあたり、その後の旅程が崩壊してしまった反省があるため、現在牡蠣断ちをしています。皆様お気をつけください。

Ya8 2024

hachiojipm.connpass.com

id:uzullaさんの個人主催(?)カンファレンスで、スタッフと登壇をしました。具体的には以下のタイトルで発表をしました。

  • 同人誌組版・印刷入門
  • htmx meetup(Unofficial)
  • 本番コンテナ環境で生きる軽量スクリプト言語の検討
  • 電光掲示板が家に欲しい(LT)

あと、アンカファレンスなどにも参加しました。ああいうゆるくも、誰でもどんな発表ができ、発表一つ一つも興味深い場はなかなかありませんでした。楽しかったですね...

golang.tokyo #34

golangtokyo.connpass.com

プロダクトのリプレイスというテーマだったので、過去にやった動いているサービスをマイクロサービスに変えていった話をしました。

speakerdeck.com

kamakura.go #6

kamakurago.connpass.com

コロナ以前にやっていた勉強会を復活させました。「昔のGo、今のGo」というテーマで募集したのですが、数多くの方に発表していただいて嬉しい限りです。

私もまた発表しました。

speakerdeck.com

湘.なんか #1

shonanpm.connpass.com

id:papixさんが始めた湘南地域の技術系勉強会です。言語や分野に限らずなんでもOKというものです。この時は、作っていたWebアプリケーションフレームワークtanukirpcの発表をしました。

tanukirpcの説明は以下の記事にあります。

mackee.hatenablog.com

Asakusa.go #3

Asakusa.goは#1に行ったんですが、こちらでもtanukirpcのLTをしてきました。

speakerdeck.com

結構鋭い反応とかもあり、なかなかタメになりました。

YAPC::Hakodate 2024

なんと2024年はYAPCが2回ありました。

yapcjapan.org

レポートや登壇については以下の記事にあります。

mackee.hatenablog.com

kamakura.go #7

kamakura.goも2回やりました!えらい! この回もさまざまな人にしゃべっていただきました。本当にありがとうございます。

kamakurago.connpass.com

また登壇しました。

speakerdeck.com

振り返るといっぱい発表してた。なんか作ったものがそこそこあり、発表のネタに困らなかったのを思い出します。場も多くて良かったですね。

仕事

Tonameの仕事は6月で離れて、社内でSREだとか、社内アプリ向けアプリの作成や改修などをやっていました。あと研究開発のような形で、生成AIの検証などもやっていました。

その時の知見がこちら。

techblog.kayac.com

僕自身はプロダクト側の開発・運用をやりたい人間ではあるので、そちら方面ができるようにシフトしつつ、なんらか表にも「これをやっているぞ!」と言えるような立場になりたい感じですね〜。

趣味

ISUCON

また負けた。さまざま課題がはっきりした会だったので、来年はもっと強くなれる。やるぞ

3Dプリンタ

ところでみなさん知っていますか、2024年は3Dプリンタが家電として使えるようになった年です(人によって見解は違います)。しかし僕は2015年に買ったプリンタをずっと改造して使い続け...もうオリジナルから残っている部品はフレームのアルミフレームぐらいしかないわけですが。

またバラしている図

しかし、来年で買ってから10年経つわけですが、最新機種たちの知見をなんとか取り入れて延命させようとしています。

デルタ型になんとかMini-AfterSherpaを使おうとしている

あと我が家に3Dプリンタはこの1台しかないので、バラしている時や調子が悪い時にプリントパーツで補おうとした場合は、JLC3DPなどの外部のプリントサービスに頼ることになります。この時はとにかく硬いパーツが欲しくて、JLC3DPにステンレスで注文したところ、穴が小さすぎて穴を広げようとしている図。

こんなことやっているとドリルが折れて穴の中に残ってパーツが使えなくなるので注意(そうなった

そんなこんなで、海外のちゃんとCNCで出したパーツを買ってそれを使って現在は安定しています。来年はもう一台ちゃんとしたのを増やそうかな...とは思っています。

旅行

YAPC::Hiroshimaの後に行った我が地元、岩国の錦帯橋です。橋のたもとにいっぱい種類があるソフトクリーム屋があります。

スノーボード旅行行ってた。骨を折ってからあんまり行ってなかったのでおっかなびっくりです。これは行きの電車、雪が深い。

沖縄行ってた。美ら海水族館は何度行っても良い...

Ya8 2024のホール。みなさんが来る前の風景。

お台場であったFormula E。近かった〜。

こちらは富士スピードウェイSUPER GT。相変わらず音に迫力がある。

その約1ヶ月後にスーパー耐久富士24時間でキャンプもしました。花火でトヨタマークだのホンダマークが打ち上がるのは笑った。

熊本は阿蘇山に行ってたりしていた。これは草千里のお馬さんです。

神奈川の陣場山から高尾山まで縦走していた。めちゃくちゃ時間かかった。

歩くといえば、関門トンネルも歩いていた。

山といえば谷川岳も途中まで登った(時間の関係で途中で引き返す)。岩山やん!ってなった(それはそう)

越乃*Shukuraという列車に乗った。お料理も美味しかったし、酒も美味しかった。

おもしろレンタカーでMR2(奥の白い車)を借りてドライブ。なかなか刺激的な車でしたね(怖いともいう

福井は恐竜博物館で発掘体験。この写真、恐竜の足跡化石が発掘された現場がそのまま残っている状態。すごくないですか。

函館山からのYAPC。こういうのやってくれるのめっちゃ嬉しいですね。

秋の宝永山。この後の33km歩くイベントに参加したので、その訓練でした。

台湾に弾丸で旅行に行ってきた。これは定番の故宮博物館の角煮です。白菜も見た。あと最近Xで話題だった象牙多層球も見たぞい。

台湾といえば飯ですよね。ルーロー飯を2回、屋台でネギパンを食い、さらに豆乳とかそういうのも飲んだ。また行きたい。次は九份やな。

この前奥鬼怒に行ってました。これは毎年行ってる宿です。今回は雪がめっちゃ降って、冬!!って感じだった。

コンテンツ系

  • 「追放されたチート付与魔術師は気ままなセカンドライフ謳歌する。 ~俺は武器だけじゃなく、あらゆるものに『強化ポイント』を付与できるし、俺の意思でいつでも効果を解除できるけど、残った人たち大丈夫?~」のマンガが面白い
  • 「ウスズミの果て」を読み始めた。面白い感じがする
  • インターステーラーの再上映を見た。やっぱりこの映画がオールタイムマイベストです。
  • 侍タイムスリッパー面白かった
  • ゲームあんまりやってないことに気がついた

来年の抱負

  • 仕事はわりかしチャレンジをする感じなので、がんばるぞい
    • なんか助けが欲しい時があるかもしれないので、みなさん助けてください
  • 体を鍛えないといけないとなったが、何かしら目標がないと鍛えがいがないなと思った。なので来年はフォーシームで100kmを出すを目標にしてみます
    • 走るのはあんまり好きではない
    • 歩くのは33kmウォークをまたやって、タイム短縮を目指す

30年分の後方互換性を保ちながら進化し続けるための言語機能

この記事はPerl Advent Calendar 2024 17日目の記事です。昨日はkarupaneruraさんのString::Secretのご紹介でした。演算子オーバーロードで文字列でないものを文字列に見せかけるのは僕もやったことがありました。

さて、argathさんがAdvent Calendarの13日目に次のPerlはPerl 42(かも)という記事を書いていました。この記事からリンクされているPerl 5 is Perlという記事を読んでみると、

30年前の1994年10月17日に5.0になりました。

とあります。つまり、現在広く使われているPerl 5はリリースから30年を過ぎたということになります。これはとんでもないことですし、この記事にはこれからも進化を続けていく旨が書かれています。あとよくPerlを使わない方から聞かれる点として、Perl 6はいつリリース/移行されるのかという話ですが、Perl 6は既にリリースされた上で、Rakuという名前に変わっています。リリースされた時点でそうですが、Perl 5の後継はPerl 6ではなく、姉妹的な言語であるとされています。

ところで、最新のバージョンである5.40やそれより前の5.38,5.36,5.34には多くの機能が追加されています。目立ったもので言うと以下のような感じです。

  • try/catch/finally
  • class
  • true/false
  • for my ($first, $second) (@list)

使えなくなったものの例: 間接オブジェクト記法

一方で、使えなくなったものもあります。代表例としては、間接オブジェクト記法があります。厳密には使えないわけではなく、最新のPerlの機能を有効にする use v5.40;スクリプト内に記述すると使えなくなります。どういうことか。

まず間接オブジェクト記法をおさらいします。以下のコードでは、Fooクラスを定義し、インスタンスを作成するnewメソッドと、helloメソッドを定義しています。そしてそれらを呼び出しています。 間接オブジェクト記法とは以下のコード中では new Foohello Foo にあたります。

use strict;
use warnings;
use utf8;

package Foo {
  sub new {
    my $class = shift;
    my %obj = (name => "Fooooo");
    bless \%obj, $class;
  }
  sub hello {
    my $self = shift;
    print $self->{name} . ": hello\n";
  }
}

my $foo = new Foo;
hello $foo;

ところで、広く使われるPerlはこのようにクラスのメソッド呼び出しを扱いません。一般的にはこうです。

my $foo = Foo->new;
$foo->hello;

つまり間接オブジェクト記法はアロー演算子->ではなく、Javaなどに近い記法でメソッド呼び出しを行う糖衣構文であると言えます。

一方で、use v5.40;を行うと上記のコードはどうなるでしょうか。strictwarningsプラグマの代わりにv5.40プラグマを入れます。(なぜならv5.40にこれら2つのプラグマは含まれるからです)

use v5.40;
use utf8;

package Foo {
  sub new {
    my $class = shift;
    my %obj = (name => "Fooooo");
    bless \%obj, $class;
  }
  sub hello {
    my $self = shift;
    print $self->{name} . ": hello\n";
  }
}

my $foo = new Foo;
hello $foo;

このコードは動きません。以下にエラーを示します。

Bareword found where operator expected (Do you need to predeclare "new"?) at prog.pl line 16, near "new Foo"
syntax error at prog.pl line 16, near "new Foo"
Execution of prog.pl aborted due to compilation errors.

newという関数がないと起こられています。この書き方でnewFooのメソッドであると認識することはなくなり、単なる関数呼び出しとして解釈しようとしていることがわかります。

ではなぜ、間接オブジェクト記法はなくなってしまったのでしょうか? Perldocの間接オブジェクト記法の説明にしっかりと書かれています。

つまり、上記のコードだと、newhelloが関数なのか、それともメソッドなのかを区別するのが読む側にも難しく、またインタプリタに対しても間違った指示を与えてしまうことがあります。

Try::Tinyを使おうとしたら動くのに、挙動が意図通りにならないという例もあります。

techblog.karupas.org

そんなこんなで、間接オブジェクト記法は当時は書き方がかっこよかったものの(特にnewメソッド)、今となっては非推奨になり、さらにuse v5.36;をすると無効化されるということになりました。

Perlは実は過去に実装されて広く使われているものの、間違いが起こりやすいなどのよくない文法も無効化されるようになってきているんですね。めでたしめでたし。

後方互換性を守る仕組み

これだと他の言語でもよくあることですよね? しかし後方互換性を鬼守るPerlでは少し違います。

さっき言ったように最新のインタプリタであるperl 5.40であってもuse v5.36;以上をしなければ間接オブジェクト記法は使用可能です。厳密には、use feature 'indirect';とすると使用可能です。

そして、間接オブジェクト記法を使用しているコードは無視できない程度には存在すると思われます。それを新しい記法を使いたいから、もしくは自分が間違えてしまうので間接オブジェクト記法を無効化すると既存コードも壊れてしまうということになってしまうと思いませんか?

しかし、Perlの機能スイッチを行うuse VERSION;はスコープに効くという特徴があります。ファイルではありません、スコープに効きます。以下のコードを見てみましょう。

use strict;
use warnings;
use utf8;

package Foo {
  sub new {
    my $class = shift;
    my %obj = (name => "Fooooo");
    bless \%obj, $class;
  }
  sub hello {
    my $self = shift;
    print $self->{name} . ": hello\n";
  }
}

my $foo = new Foo;
hello $foo;

{
  use v5.40;
  my $foo2 = new Foo;
  hello $foo2;
}

my $foo3 = new Foo;
hello $foo3;

Perl{ ... }ブロックスコープを作れます。以上のコードではブロックスコープ内でuse v5.40;を宣言しています。このコードは以下のエラーが出ます。

Bareword found where operator expected (Do you need to predeclare "new"?) at prog.pl line 22, near "new Foo"
syntax error at prog.pl line 22, near "new Foo"
Execution of prog.pl aborted due to compilation errors.

エラーで指摘されている22行目はmy $foo2 = new Foo;にあたります。もっと手前のmy $foo = new Foo;ではエラーが出ていません。そして、22行目をmy $foo2 = Foo->new; 23行目を $foo2->hello;に変えると正常に動作します。use v5.40;の及ぶ範囲がブロックスコープに限定されていることがわかります。

また、このスコープとはレキシカルスコープです。どういうことかというと、use v5.40;と宣言したスコープから宣言していないスコープの関数を呼び出したとしても、呼び出し元のスコープのuse v5.40;は呼び出し先のスコープには適用されません。

つまり以下のコードは動きます。

sub hello_foo {
  my $foo = new Foo;
  hello $foo;
}

{
  use v5.40;
  hello_foo;
}

このことから、自分が新たにいじる範囲のみをuse v5.40;とすることで、間接オブジェクト記法のめんどくささから解放され、また既存のコードには手を入れずに修正することが可能になります。

一方で、ダウングレードには現在一部のバージョンの組み合わせではエラーになり、その他の組み合わせでは警告が出るようになっています。ダウングレードは後方互換性の観点ではまず使わないとは思いますが、ご注意ください。

いかがでしたでしょうか。このほかにもuse VERSION;は言語機能のスイッチをバージョンで動的に管理するなど、部分部分で新しい機能を使えるようにしつつ、既存コードはそのままにできる設計になっています。もし10年以上動かさないといけないが、ちょっとしたスクリプト言語で書きたい場合にPerlを選択するのは、意外と理にかなった選択かもしれません。

明日18日目はxtetsujiさんで「そろそろソースフィルタに挑戦してみたいなぁと」です。気になりますね。

aquaでperlを入れて使えるようになりました

この記事はPerl Advent Calendar 2024、14日目の記事です。昨日はaragathさんによる次のPerlはPerl 42(かも)でした。確かに5.40の5.の部分って変わらないしバージョン番号としては意味がないよな(そもそもバージョン番号ではなく言語名の方含まれる)とは思っていましたが、もし5がなくなると寂しい感じはしますね。ただMySQLも5.7の次が8だったもんな、と考えるとそういう流れかもしれません。

この記事の元ネタ

github.com

aquaって何?

suzuki-shunsukeさんが開発を行なっているCLIツールのパッケージマネージャーです。僕がよく使うのはterraformです。デプロイツールであるecspressolambrollなども入れられます。

他のパッケージマネージャーとしてはhomebrewや、asdfがあります。これらとの違いは、aquaはビルドツールの実行を(ほとんどのケースでは)しないという点です。これにより速やかにツールのインストールができたり、ビルドツールの差異などでインストールが失敗するということがありません。

また、良い点として、インストールされているCLIのバージョンを設定するaqua.yamlが配置されたディレクトリ以下では、そのCLIツールのバージョンに固定される点です。プロジェクトごとに使っているCLIのバージョンが違う場合でも、スムーズに作業ができます。

また、僕は最近は言語ランタイムもaquaで管理しています。具体的にはGoとbun(TypeScript)です。Dockerを使えばいいのにという指摘もあるかと思いますが、この2つの言語はプラットフォームによる差異があまりなく、むしろDockerのオーバーヘッドであったり、制限に振り回されるデメリットの方が大きいので、最近はDockerを使わずにaquaでランタイムを管理し、ホスト側に完結してWebアプリケーション開発を行なっています。

perlを入れて使えるようになりましたとは?

以下のPull Requestでaquaで入れられるツールを管理する、aquaproj/aqua-registryに追加していただきました。

github.com

具体的に使う手順を示します。まず、aquaを使える状態にして、次のコマンドでカレントディレクトリにaqua.yamlを作成します。

$ aqua init

そして、今回追加したパッケージである、skaji/relocatable-perlaqua.yamlに導入します。

$ aqua g -i skaji/relocatable-perl

最後に、以下のコマンドで、実際にパッケージを落としてきてインストールします。

$ aqua i

これでaqua経由で入れたperlが使えるようになりました。

$ which perl
/Users/mackee/.local/share/aquaproj-aqua/bin/perl
$ perl -v

This is perl 5, version 40, subversion 0 (v5.40.0) built for darwin-2level

Copyright 1987-2024, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at https://www.perl.org/, the Perl Home Page.

使用上の注意点としては、cpanmでモジュールを入れた時の、実行スクリプトのパスです。僕の設定の場合は、~/.local/share/aquaproj-aqua/pkgs/github_release/github.com/skaji/relocatable-perl/5.40.0.1/perl-darwin-arm64.tar.gz/perl-darwin-arm64/bin/に置かれてしまいます。インストールされているperlのバージョンごとにパスを通すのは困難なので、次の例のようにcpanm -L localのようにカレントディレクトリ配下に入れて利用するのが良いと思われます。

$ cpanm -L local App::cpm
...
$ ./local/bin/cpm --version
cpm 0.997021 (./local/bin/cpm)
perl version v5.40.0 (/Users/mackee/.local/share/aquaproj-aqua/pkgs/github_release/github.com/skaji/relocatable-perl/5.40.0.1/perl-darwin-arm64.tar.gz/perl-darwin-arm64/bin/perl)

skaji/relocatable-perlって何

skajiさんが作成している、ビルド済みのポータブルなperlパッケージです。perlをインストールするには、本来gccやclangなどのC言語コンパイラや、その他ビルドツールが必要ですが、relocatable-perlではビルド済みなので不要です。また、インストールするディレクトリを選ばない特徴があります。

このような特徴があるため、インストール時にビルドを行わないaquaであってもperlを入れることができます。

なお、Node.jsではこのようなバイナリが公式で配布されています。そしてNode.jsはaquaですでに利用可能です。Pythonではryeが利用しているgithub.com/indygreg/python-build-standaloneがあります。RubyではHomebrewが利用しているHomebrew/homebrew-portable-rubyがあります。python-build-standaloneはすでにaquaの作者の方によるPull RequestがありますがRubyは存在しません。Rubyの方でいいなと思われた方は、コントリビューションチャンスかと思います。

なんでperlなの

僕は常々、シェルスクリプトで複雑なメンテナンススクリプトの類を書くのは思考停止的で違う手段も検討した方が良いのではないかと唱えています。

先日YAPC::Hakodate 2024で発表もしました

一方で、perlはほとんどの開発者の環境に入ってはいるものの、バージョン管理であったりすでに入っているperl環境を汚さずに利用することは少々知識が必要です。なので、aquaというツールに乗って、シェルスクリプトの代わりにperlを利用することを手助けできないかと考えて、利用できるようにしてみました。

さて、明日のPerl Advent Calendar 2024 15日目はAnaTofuZさんで「なんかかきます」です。何が出てくるでしょうね? 楽しみですね

YAPC::Hakodate 2024に行ってきました #yapcjapan

お疲れさまです! ブログ書くまでがYAPCということでやっていきます。

yapcjapan.org

前夜祭

前夜祭ではガラナを受け取って早速北海道に来た感が出ておりました。この後アンカファレンスという形で会が始まり、序盤はmoznionさんやpasta-kさんの話を聞いてたんですが、目線が合ってしまい私も壇上に上がることに。AIとか色々重いテーマでしたが、わりかし今自分が他人と話したいことが話せてよかったかと思います。文芸的プログラミングのくだりとかまさにそうですね。

そのあとは基本的には後ろで話したり(声がもし大きかったらすみませんでした)、別室に移動してきた人と話していました。

懇親会が終わり、たまには知らない人についていこうかなと思ってたら、結局ホテルに帰ってセコマのホットシェフを食ってました。知らない人の飲み会について行くスキルなのか度胸なのか身につけたいですね。

本編

バスに乗る前に爆速で食べた海鮮丼

当日の会場であるはこだて未来大学は市街地から離れたところにあるため、事前に購入しておいたバスチケットでの移動となります。その出発時間が早いのですが、函館朝市の場所が乗り場である函館駅から近くて助かりました。おかげで余裕が20分しかなかったものの、シュッと食べて「とにかく函館に来て海鮮食ったぞ!」という気分は味わえました。もちろん味も良かった。

会場に到着

会場のみらい大ですが、地上から入ったところが3階っていうのは、大学や高専あるあるの構造ではありますが、非常に綺麗かつでかい箱に吹き抜けと釣り廊下を駆使した構造で非常に面白かったです。入ってすぐのフロアに体育室的なものがあるのは、雪が降っても外に出ずに移動できるような工夫でしょうか。普通ああいう建物は他の大学だと独立した建物になってがちだと思ったので。

またブースも色々回って各社色々やっているなあという感じ。弊社もまた出したいなあ。

さてそうこうしているうちに本編が開始しました。ここからは私が聞いた各トークの感想について簡単に紹介してきます。

Perlで始めるeBPF: 自作Loaderの作り方

speakerdeck.com

eBPFは聞いたことはあるものの、まだ具体的に何に使うのかというのがわからない状態で話を聞きました。システムコールカーネル内でトラップして解析するような用途に使うのかなと思ったのですが、もっと広範囲に使える、つまりカーネルモジュール全般を作れる機構であることがここで初めてわかった気がします。

私はPerlはわりかしよく書いている方なのでpack/unpackが来ると興奮します。前回の私のパスキーを実装する発表でもやった感じですね。Perlは意外とバイナリに強いんだなあ(本当かな?) ここではELFのパースに使ったり、syscallでロードする時の引数を作ったりする時に大活躍。

このトークでは最初から「知らなかったを聞く」ができて大変良かったですね。

2024年秋のPerl

これがないとYAPCが始まらない、と私は思っているcharsbarさんの定番トークです。私は新機能が提案されるPPCsや前のバージョンとの差分を出しているperldeltaをちょいちょいウォッチしているんですが、海外の方でのPerl開発の微妙なニュアンスや進行中の状況などがキャッチアップできて、非常に実用的なトークです。

今回の話だと、やはりcpanmのhttps対応どうするかの話がありましたね。私自身もどうなるんだろうと注目していますが、どうなるんでしょうか(どうなるんでしょうか以上が何も言えない)。

PerlPerlによるPerlのための言語サーバーを作る

現代ではVSCodeをはじめ様々なエディタで使われるLanguage Server Protocolの概要について説明しつつ、PerlのLSPをPerlで実装する話でした。

こちらもeBPFの話と同様、技術的要素の入り口として捉えるのにぴったりな発表だったかと思います。LSPは言語関係の機能以外にもエディタに依存しないエディタの拡張を作るのに使える気がするので、何かしらやってみたい気持ちはあります。しかしやりたいことが多すぎるんだな。

perl for shell, awk, sed programmers

speakerdeck.com

私の発表です。現代においてPerlを使う場面としてsedawk, シェルスクリプトの代わりにPerlを使うのはどうかという提案の発表でした。

この発表をする背景について説明します。最近シェルスクリプトがWebプログラミング界隈で昔よりも多く見る気がしますが、それは2つの背景があるかと思います。

  • JVM言語やGo, Rust, TypeScriptなどコンパイルを要する言語によってWebサーバーを記述するようになったため
  • Webの世界でも分業が進み、SREやプラットフォームエンジニアリングの分野でアプリケーション記述言語に依存しないシェルスクリプトが採用されている

シェルスクリプトはどの環境でも入っており、またポータビリティがあるとされている理由から採用されていると私は考えていますが、これらのメリットは実は正しくないのではないか、Perlの方が適しているのではないかというのがこのトークの骨子です。

もちろんRubyPythonJavaScript等をアプリケーション記述言語として用いているのであれば、そちらを採用するのは私は良いかと思います。しかしコンパイル言語のようなそのような適当な手段がないケースでの選択肢にPerlはまず上がることがないと思いますが、選択肢に上げていいんじゃないかなと。シェルの文法とPerlの文法どちらが詳しいですか、どっちがあなたの慣れている言語に似ていますか、などなど言いたいことはたくさんあるのですが、とにかくPerlも忘れないで!っていう話でした。

これでPerlについて一人でも注目していただける方が増えると良いかと思います。この後の懇親会でも僕のトークを聞いてない方にさらりと概要を説明したら「確かに〜」というフィードバックをもらえたので、聞いてもらったら何割かの人はためになるとは思う話をできたかと思います。でもカンファレンスって時間が限られているから、自分が知っているか、隣接領域、もしくは仕事に役立ちそうな話、自分の周りの人が話題にしているような話に行っちゃいがちですよね? それは常識的な行動だと思うので、それに抗って「いかにPerlを書いていない人にPerlの話を聴きに来てもらえるか」っていうのがなんか今後の課題だなあと思っています。

言語ドキュメントを翻訳し、未来に向けて更新し続ける技術 ~perldocjpを例に~

perldoc.jpで公式Perlドキュメントを翻訳している白方さんのトークです。Perlっぽくpodで段落ごとに区切って翻訳して行くのはなるほどな〜と思いました。

ちょうど仕事でLLMとかいじってて段落で区切ってベクトル化するとかやってるんですが、これに向いているドキュメントとそうでないドキュメントがあるように感じます。多分公式ドキュメントなんかは向いているかと思います。コンテキストがちゃんと段落で区切られているとかそういう傾向があるとは思っています。そういった性質があるから段落ごとに翻訳でうまいこといけるんだなあとか、一人で考えていました。

令和最新版Perlコーディングガイド

speakerdeck.com

アナグラさんの発表でしたが、自分がこのテーマでも発表したかったとは思ってましたが、このトークでよかったなあと思いました。そもそも実際にはてな社でガンガン最新記法を採用していっているのが良いですね。Perlも部分的に新しいキーワードを有効にできるなどの機能があるので、そういうやり方に向いているとは思います。

今のPerlの開発はわりかりアグレッシブになっていると思っています。例えばtrue/falseやtry/catchがこのスピードでデフォルト有効になるとは思ってなかったです。そのスピードで発展していってる言語が、このカンファレンスに来るような人のほぼ全てのPCに最初から入っているってすごくないですか? 今、学ぶべき言語はPerlだと思うんですよね(ポジショントーク

ちなみにこの発表で挙げられなかった新機能で私が一番いいなと思うのは、iteration over multiple valueですね。

for my ($i, $j) (@array) {
    say join(" ", $i, $j);
}

こんな感じで一回のループで2個一気に取れます。それの何が嬉しいの?ってなるんですが、hashで回すときに便利で、

for my ($k, $v) (%hash) {
    say $k . '=>' . $v;
}

こんな感じでkey valueがペアで取れます。ハッシュはリストコンテキストで受けるとk, v, k, v ... のリストで返ってくるので「2個同時に取れる」がハッシュのリスト受けの性質と相まって「キーバリュー同時に取れる」に変化するんですよね。Perlっぽいなあと思います。

WebTransportは未来の技術?

speakerdeck.com

Perl関係じゃないですが、Web API大好きっ子でWebSocketに思い入れがある人間なので聴きに行きました。

やっぱりまだライブラリを含めて発展途上な感じはしますが、クラサバモデルでリアルタイムやる時にWebRTCよりは簡単に、WebSocketよりは早く、かつ切断に強くなるのは良いですよねえ。

CloudNative Meets WebAssembly: Wasm's Potential to Replace Containers

speakerdeck.com

WebAssemblyも気になるので聴きに行きました。そういえば去年から今年の序盤にかけてperlをWASM化するチャレンジをしていました。Emscriptenはいけるけれど、WASIはlongjumpの壁があり、WASIXはコンパイルできるがwasmerで動かないみたいな感じでした。

これを聞くとWebAssemblyで動くかどうかは結構今後の鍵になるかなと思います。質問にあったようにDockerからWebAssemblyにするにはサンドボックスとしては確かに一緒かもしれないが、既存コードのリフトアップには大きな飛躍が必要かと思います。

一方スクリプト言語はとにかくランタイムがWebAssembly化されていれば、コンパイル言語に比べたらワンチャンある気がします。perlのWebAssembly化また頑張るかなあ。ruby.wasmのAsyncifyを参考にすればいけるとは思っています。GCとかもRubyに比べたらシンプルですしね。

Lightning Talks

いやーこれぞLTっていうのがどんどん出てきてよかったですね。勢いって共通項はあるとは思うんですが、それぞれスタイルやテーマが違いつつも、オッと食いつくような奴が見れてよかったです。

moznionさんのPerlRubyと聞いてautoboxのこと思い出したんですけれど、メソッド呼び出しがアローとドットで違うので、あの問題には使えないか〜。

キーノート

speakerdeck.com

本人からLTとキーノートでテンションの差がって言ってたんですけれど、どっちかというとLTの方のテンションによっていたかと思いますが、これはこれで楽しいキーノートでよかったと思います。というかコロナ後のYAPCってコロナ前のしっとりって感じよりは結構淡々時々笑いありっていうスタイルになってませんか。大西さん、とほほさんどちらも笑いがあったかと思います。今後のキーノートはこんな感じになるのかもしれない。

moznionさんとは直接一緒に働いたことはないものの、比較的近くから見ることが多く、しかしスライドでそんな感じだったか〜というのはあります。小切手のくだりは、なんかグッとくるものがあります。こうやって他人の人生を俯瞰して見る、さらに身近な人物というのはなかなか、僕にとっても今までにないキーノートでした。

クロージング

次ある!!!よかった!!!! でもなんか大変そうなのでなんか手伝いたいな。しかしトークもしたいな??? どうすればいいんだーーー〜〜!!!! ところで福岡は好きな街です。今年もなんだかんだ博多に行ったんですわ。

というわけでまた次も会いましょう〜〜! 次のYAPCでもPerlに絡んだ話できるように目指します!

ところでこれは翌日に行ったラッキーピエロで食べたmoznion氏おすすめのチャイニーズチキン2段のり弁当です。ドカ食いセットなのは見逃してください。バーガーを結局食べれてないんですけれど、食べている時に「確かにチャイニーズチキン美味しいんだけれど、最初これでいいんだっけ?」となったのは秘密です。

tanukirpcというWebフレームワークを作っています

最近の盆栽ですけれど、tanukirpcというGoのWebフレームワークを書いています。ある程度やりたいことができはじめてきたので、どんなフレームワークかを紹介します。

github.com

TL;DR

  • Webアプリケーションでよくやるようなことを、最短手順で自然に書けるように設計したフレームワーク
    • リクエストをパースして構造体にマッピングする
    • リクエストの内容をバリデーションする
    • レスポンスの構造体をエンコードしてレスポンスとして書き込む
    • グローバルスコープもしくはリクエストスコープでの構造体のコントローラーへの依存性注入
      • DBコネクションやAPIクライアントの保持などに使う
  • 現在の責務範囲はWebアプリケーションのコントローラーだが、Webアプリを作る時によくやるようなことはできるだけやれるようにしてく
    • tanukiup 開発サーバー起動用コマンド。ファイル更新を監視してビルドおよびサーバープロセスの再起動を行う
    • gentypescript クライアントコードの生成コマンド。GoでもtRPCのような開発体験を得るのを目指している

ではそれぞれどういうことなのか見ていきましょう。

routerの作成

tanukirpc*tanukirpc.Routerを作成し、このrouterのGetPostなどのメソッドを使ってAPIエンドポイントを設定していくことでコントローラー全体を定義していきます。なのでまずは、routerを作るところから始めます。

package main

import (
    "github.com/mackee/tanukirpc"
)

func main() {
    router := tanukirpc.NewRouter(struct{}{})
    // do something
}

空struct struct{}{} を渡しているのが気になりますが、こちらは後述するRegistryの項目でお話しします。

APIエンドポイントの定義

まずは基本的なエンドポイントを定義していきます。次のコードではシンプルな GET /hello エンドポイントを定義しています。

package main

import (
    "fmt"
    "net/http"

    "github.com/mackee/tanukirpc"
)

func main() {
    router := tanukirpc.NewRouter(struct{}{})

    type helloRequest struct {
        Name string `query:"name"`
    }
    type helloResponse struct {
        Message string `json:"name"`
    }

    router.Get("/hello", tanukirpc.NewHandler(
        func(ctx tanukirpc.Context[struct{}], req helloRequest) (*helloResponse, error) {
            return &helloResponse{Message: fmt.Sprintf("hello, %s", req.Name)}, nil
        },
    ))

    http.ListenAndServe("127.0.0.1:8080", router)
}

これで完成しました。起動してみます。

$ go run main.go

ログを出していないので何も出力されませんが、HTTPサーバーとして起動しています。別のターミナルを立ち上げて、curlを用いてリクエストを行ってみます。

$ curl 'http://localhost:8080/hello?name=tanukirpc'
{"name":"hello, tanukirpc"}

JSONでレスポンスが帰ってきました。この通り、query parameterのnameとして渡したtanukirpchelloRequest.Nameにバインドされてハンドラー内で利用できます。

また、ハンドラーで返した*helloResponseJSONとしてクライアントに返却されます。

便利な開発用コマンド tanukiup

先ほどはgo run main.goで起動しましたが、ファイルを変更するたびにCtrl+cで終了させて立ち上げ直さなければなりません。そこでtanukirpcでは開発用の便利なコマンドとしてtanukiupを用意しています。

tanukiupは以下のように使います。

$ go get github.com/mackee/tanukirpc/cmd/tanukiup
$ go run github.com/mackee/tanukirpc/cmd/tanukiup -dir ./

-dir ././ 以下を監視対象に入れます。デフォルトでは監視対象のディレクトリのうち、.goで終わるファイルに更新があった場合にビルドとコマンドの再起動が行われます。

こういったWebアプリケーションサーバー開発でよくやるようなことのツール化もtanukirpcの守備範囲です。

リクエストのパース

tanukirpcは以下のリクエスト形式のstructへのバインドに対応しています。

  • クエリパラメーター
    • 例: /hello?name=tanukirpc
  • パスパラメーター
    • 例: /hello/{name}{name} に任意の文字列が入る形式
  • Form
    • 現在はapplication/x-www-form-urlencoded のみ
  • JSON

上記の例ではクエリパラメーターのやり方について解説しましたが、他の形式のケースを紹介します。

パスパラメーター

routerに渡すパスを/hello/{name}とし、request structのfieldのタグをurlparam:"name"とすると、{name}に入る任意の文字列をstructにバインドします。

type helloRequest struct {
    Name string `urlparam:"name"`
}
type helloResponse struct {
    Message string `json:"name"`
}

router.Get("/hello/{name}", tanukirpc.NewHandler(
    func(ctx tanukirpc.Context[struct{}], req helloRequest) (*helloResponse, error) {
        return &helloResponse{Message: fmt.Sprintf("hello, %s", req.Name)}, nil
    },
))
$ curl 'http://localhost:8080/hello/tanukirpc'
{"name":"hello, tanukirpc"}

POST Form

structのfieldのタグにform:"name"のように入れると、リクエストボディに入れられたapplication/x-www-form-urlencoded形式のリクエストの内容をバインドします。リクエストのContent-Typeヘッダーがapplication/x-www-form-urlencodedである必要があります。

type helloRequest struct {
    Name string `form:"name"`
}
type helloResponse struct {
    Message string `json:"name"`
}

router.Post("/hello", tanukirpc.NewHandler(
    func(ctx tanukirpc.Context[struct{}], req helloRequest) (*helloResponse, error) {
        return &helloResponse{Message: fmt.Sprintf("hello, %s", req.Name)}, nil
    },
))
$ curl -XPOST -d 'name=tanukirpc' -H 'Content-Type: application/x-www-form-urlencoded' http://localhost:8080/hello
{"name":"hello, tanukirpc"}

JSON

structのタグにjson:"name"のようにすると、リクエストボディに入れられたJSON形式をパースし、フィールドにバインドします。リクエストのContent-Typeヘッダーがapplication/jsonである必要があります。

type helloRequest struct {
    Name string `json:"name"`
}
type helloResponse struct {
    Message string `json:"name"`
}

router.Post("/hello", tanukirpc.NewHandler(
    func(ctx tanukirpc.Context[struct{}], req helloRequest) (*helloResponse, error) {
        return &helloResponse{Message: fmt.Sprintf("hello, %s", req.Name)}, nil
    },
))
$ curl -XPOST -d '{"name":"tanukirpc"}' -H 'Content-Type: application/json' http://localhost:8080/hello
{"name":"hello, tanukirpc"}

上記のタグは複数の種別を指定可能であり、例えばform:"name" json:"name"のように指定すれば、FormとJSON形式の両方を対応するようなエンドポイントを作成できます。

また、上記以外の形式もCodecというインターフェイスを実装した上で、router作成時にオプションとして渡すことで対応可能になっています。

リクエストバリデーション

tanukirpcではgithub.com/go-playground/validatorによるバリデーションが最初から組み込まれています。go-playground/validatorによるリクエストバリデーションを有効にするには、リクエストstructにvalidateタグを追加します。

以下はクエリパラメーターのnameが必須であることを表すハンドラーです。

type helloRequest struct {
    Name string `query:"name" validate:"required"`
}
type helloResponse struct {
    Message string `json:"name"`
}

router.Get("/hello", tanukirpc.NewHandler(
    func(ctx tanukirpc.Context[struct{}], req helloRequest) (*helloResponse, error) {
        return &helloResponse{Message: fmt.Sprintf("hello, %s", req.Name)}, nil
    },
))
$ curl http://localhost:8080/hello
{"error":{"message":"Key: 'helloRequest.Name' Error:Field validation for 'Name' failed on the 'required' tag"}}
$ curl 'http://localhost:8080/hello?name=tanukirpc'
{"name":"hello, tanukirpc"}

なお、このエラー出力に関しては、tanukirpc.ErrorHooker interfaceを実装し、routerの作成時に渡すことで、カスタマイズが可能です。

レスポンス

レスポンス形式は現在はJSON形式のみ対応しています。Codec interfaceを実装し、router作成時に渡すことで、その他の形式もサポート可能です。

Registry

Registryはこれまで紹介した型付きハンドラーと並ぶ、tanukirpcのユニークな機能です。

上記の例ではrouterの作成時に、空structを渡していますが、ここには任意の値を渡すことができます。ここで渡した値はハンドラー内で利用可能です。

一例として、DBコネクションを組み込んだstructを渡したアプリケーションを示します。以下のアプリケーションに対してPOST /usersにリクエストすると、Registryに組み込まれたdbコネクションを用いて、ユーザーを作成します。

package main

import (
    "database/sql"
    "fmt"
    "log"
    "net/http"

    "github.com/mackee/tanukirpc"
    _ "github.com/mattn/go-sqlite3"
)

type registry struct {
    db *sql.DB
}

func main() {
    db, err := sql.Open("sqlite3", "./users.db")
    if err != nil {
        log.Fatalf("failed to open database: %v", err)
    }

    reg := &registry{db: db}
    router := tanukirpc.NewRouter(reg)

    router.Post("/users", tanukirpc.NewHandler(postUsersHandler))

    http.ListenAndServe("127.0.0.1:8080", router)
}

type User struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

type usersRequest struct {
    Name string `form:"name" validate:"required"`
}
type usersResponse struct {
    User User `json:"user"`
}

func postUsersHandler(ctx tanukirpc.Context[*registry], req usersRequest) (*usersResponse, error) {
    reg := ctx.Registry()
    row := reg.db.QueryRowContext(ctx, "INSERT INTO users (name) VALUES (?) RETURNING id", req.Name)
    var id int
    if err := row.Scan(&id); err != nil {
        return nil, fmt.Errorf("failed to insert user: %w", err)
    }

    return &usersResponse{User: User{ID: id, Name: req.Name}}, nil
}
$ curl -XPOST -d "name=tanukirpc" http://localhost:8080/users
{"user":{"id":1,"name":"tanukirpc"}}

この例ではグローバル変数とあまり変わりませんが、tanukirpc.WithContextFactoryを用いてrouterにオプションを渡すと、リクエストのたびにRegistryを生成することも可能です。DBの都度接続が必要なケースでは有用です。

Registry transformer

tanukirpcではエンドポイントをネストして定義することにより、上流から渡されたRegistryとは別の型のRegistryに変換ができます。この機能がどういう場合に有用なのか例を交えて紹介します。

上記のPOST /usersの例では、作成を行いましたが、次は参照と更新のエンドポイントを作成してみます。以下の例ではtanukirpc.RouteWithTransformerを用いて/users/{id}以下のパスを定義し、またこのパスに対応するuserテーブルの行をRegistryに組み込んでハンドラーで利用できるようにします。

type registryWithUser struct {
    *registry
    user *User
}

var usersTransformer = tanukirpc.NewTransformer(
    func(ctx tanukirpc.Context[*registry]) (*registryWithUser, error) {
        reg := ctx.Registry()
        id := chi.URLParam(ctx.Request(), "id")
        row := reg.db.QueryRowContext(ctx, "SELECT id, name FROM users WHERE id = ?", id)
        var user User
        if err := row.Scan(&user.ID, &user.Name); err != nil {
            if errors.Is(err, sql.ErrNoRows) {
                return nil, tanukirpc.WrapErrorWithStatus(http.StatusNotFound, errors.New("user not found"))
            }
            return nil, fmt.Errorf("failed to get user: %w", err)
        }
        return &registryWithUser{registry: reg, user: &user}, nil
    },
)

func getUsersHandler(ctx tanukirpc.Context[*registryWithUser], _ struct{}) (*usersResponse, error) {
    return &usersResponse{User: *ctx.Registry().user}, nil
}

func putUsersHandler(ctx tanukirpc.Context[*registryWithUser], req usersRequest) (*usersResponse, error) {
    reg := ctx.Registry()
    if _, err := reg.db.ExecContext(ctx, "UPDATE users SET name = ? WHERE id = ?", req.Name, reg.user.ID); err != nil {
        return nil, fmt.Errorf("failed to update user: %w", err)
    }

    return &usersResponse{User: User{ID: reg.user.ID, Name: req.Name}}, nil
}

func main() {
    // 省略
    tanukirpc.RouteWithTransformer(router, usersTransformer, "/users/{id}", func(r *tanukirpc.Router[*registryWithUser]) {
        r.Get("/", tanukirpc.NewHandler(getUsersHandler))
        r.Put("/", tanukirpc.NewHandler(putUsersHandler))
    })
    // 省略
}

usersTransformer内でパスに対応したuserを問い合わせ、ない場合は404を返しています。これにより、ハンドラー内ではuserの存在が前提のコードを書けます。以下は上記コードを書いたアプリケーションの挙動を示したものです。

$ curl http://localhost:8080/users/1
{"user":{"id":1,"name":"tanukirpc"}}
$ curl http://localhost:8080/users/2
{"error":{"message":"user not found"}}
$ curl -XPUT -d "name=go-chi" http://localhost:8080/users/1
{"user":{"id":1,"name":"go-chi"}}
$ curl http://localhost:8080/users/1
{"user":{"id":1,"name":"go-chi"}}

TypeScriptクライアント生成

tanukirpcを作る際に、最初のマイルストーンとして設定した機能です。tanukirpcを作成した動機として、もし私が一人でフロントエンドからバックエンドまで全てこなすとしたら、どんなフレームワークが効率的か、それが世の中にない場合にどういったものを作れば良いかを考えた、というのが始まりです。一人で作成する場合に、gRPCやGraphQL、OpenAPIといったスキーマ駆動の開発はむしろ足枷となります。TypeScriptでサーバーアプリケーションを作成する際の、tRPCのような開発体験を得る手段として、TypeScriptのコード生成をしてみてはどうかと考えました。

クライアントを生成する準備として、以下のgo:generate行を足します。

//go:generate github.com/mackee/tanukirpc/cmd/gentypescript -out ./frontend/src/client.ts ./

そして、生成対象のパスを含んだroutergenclient.AnalyzeTargetに渡します。

まとめると以下のようになります。

//go:generate go run github.com/mackee/tanukirpc/cmd/gentypescript -out ./frontend/src/client.ts ./

func main() {
    db, err := sql.Open("sqlite3", "./users.db")
    if err != nil {
        log.Fatalf("failed to open database: %v", err)
    }

    reg := &registry{db: db}
    router := tanukirpc.NewRouter(reg)

    router.Post("/users", tanukirpc.NewHandler(postUsersHandler))
    tanukirpc.RouteWithTransformer(router, usersTransformer, "/users/{id}", func(r *tanukirpc.Router[*registryWithUser]) {
        r.Get("/", tanukirpc.NewHandler(getUsersHandler))
        r.Put("/", tanukirpc.NewHandler(putUsersHandler))
    })

    genclient.AnalyzeTarget(router)

    http.ListenAndServe("127.0.0.1:8080", router)
}

go generate ./で生成しても良いのですが、上記で説明したtanukiupコマンドはgentypescriptコマンドにも対応しています。tanukiupコマンド起動時にファイル内にgentypescriptが含まれているかをみているので、tanukiupコマンドを再起動します。すると、指定したパスにclient.tsが出力されます。

その様子が以下です。

https://i.imgur.com/78CWrhW.gif

また、この生成したクライアントは、パスに対応したリクエストの型がマッピングされています。使用中の様子を以下に示します。

https://i.imgur.com/1rAJmcJ.gif

まとめ

tanukirpcはまだできたばかりでよちよち歩きのフレームワークですが、私個人が使う分には「これから使っていこう」という気になるような機能がすでに揃っています。私自身はこれから仕事も含めて責任を取れる範囲では使ってみて、足りない機能を見つけては足していこうと思います。

もしこれをご覧の中に、こういったフレームワークが欲しかったけれどあれが足りない、これが足りない、もしくはこういうケースはどう書けばいいかという方がいれば、GitHubのissueなどで言っていただければ何らかの反応はさせていただこうかと思います。フレームワークは実戦で鍛えてみてなんぼかと思います。あなたの実戦に組み込めるような提案ができるとベリベリハッピーです。

また、このフレームワークに関する話をAsakusa.go #3でさせていただきます。今のところ作った動機について話そうかと思いますが、それだとテクっぽくないので、今考えている機能や組み込もうとしている自作ライブラリについての話をするかもしれません。その場合は動機の話は懇親会でしようかなと思います。

そんな感じです。それでは良いDB読み書きJSON返しライフを。

digが入っていない環境で名前解決のテストをするのにperlが便利

これで名前解決できる

$ perl -E 'say join(".", unpack("W4", gethostbyname("example.com")))'

用途

  • EC2インスタンスやらコンテナから外にほんまに出られるんかな?みたいに調べたいことがある
    • VPC内でprivate subnetだとNAT Gatewayとかがないと外に通信できない
  • サービスメッシュとかで名前引けるかどうかを確認したい時がある
    • 特定の環境でしか引けない名前とかある
  • 今回の用途はGuardDuty ECS Runtime Monitoringを導入した際にちゃんと不審な動きが検知されるかどうかで使いたかった
  • digやらnslookupをaptやyumで入れるのは気が引ける or できない
    • 本番環境のコンテナイメージなのでroot取れないとか
  • perlは入っていることがそこそこある
    • debian:bookworm-slimなど
  • アドレス一つしか返ってこないとかそういうデメリットはありますが、使い所はありそう

perlシェルスクリプトの代わりに使うのはどうかという話を3/15か3/16にします

github.com

hachiojipm.connpass.com

2023年の振り返りと2024年の抱負

2023年もいろんなことがありましたね。2024年を迎えて皆様はいかがお過ごしでしょうか。というわけで去年の振り返りと今年の抱負について書いていきたいと思います。

前回

mackee.hatenablog.com

登壇やイベントなど

YAPC::Kyoto 2023

YAPC::Japanが久しぶりにオフラインで開催されて、京都に行ったり、それから登壇もしました。

mackee.hatenablog.com

そんでもって、このトークの内容はlogmiさんで書き起こししていただいているのがあります。

logmi.jp

書き起こしされると、動画やスライドと違い、検索で辿り着きやすくなるので良いですね。また、このトークは個人的には今まで自分がやった中で一番よかったなあというのがあります。今回はライブで解説しながらデプロイしていくというのをやったのですが、こういうライブ感のあるトークはオフラインじゃないと難しいじゃないかな〜と思うし、オフラインだからこういうのをやりたいなあと思います。

と、というわけで、2月にも広島でライブコーディング主体のトークやります。YAPC::Hiroshima 2024です。

yapcjapan.org

今回は、WebAuthnを認証として使うPerlアプリケーションをできるだけ専用のモジュールを使わずに書きます。パスワードレス認証の一つとしての、WebAuthnの仕組みなどもわかるトークにするのでチケット買って見に来てくれ!!!

fortee.jp

チケットはこちら

passmarket.yahoo.co.jp

湘南.pm #1

湘南在住(諸説あり)なので、湘南.pmに参加して喋ってきました。

speakerdeck.com

ずっとsqllaというORMを作っているのですが、ORMの課題であるJOINを含んだ複雑なクエリをビューを使って解決できないかという提案です。sqlla側にいろいろ実装はしております。

湘南.pmは今年も色々イベントをやるそうなので、どんどん参加していきたいですね。

Asakusa.go #1

浅草だいぶ遠いですけれど、Asakusa.goに参加して、LTもしてきました。

speakerdeck.com

趣味ではCloudflare Workersを使っていますが、こちらでもGoを使いたいので、syumai/workersというライブラリを使っています。CF WorkersにデプロイするにはGoのプログラムをWASMにビルドしないといけないのですが、オフィシャルGoコンパイラのWASMはでかいので、TinyGoという別のコンパイラを使っています。ただ、色々動かないのでその時の工夫などについて書いています。

CF WorkersとかWASM関係は今年も攻めていきたいですね〜。

仕事

相変わらずTonamelですが、テックリードは交代して、現在はアーキテクトと名乗っています。

Tonamel関連で書いた記事はこちら。

techblog.kayac.com

他も相変わらずトーナメント表のチューニングとかやっています。

趣味

ISUCON

負けた。来年は勝つ。

mackee.hatenablog.com

3Dプリンタ

色々やってた。デルタ型のエフェクターを自分で設計したやつに入れ替えたりしていた。あとフィラメントをPETG-CFにしてみたり。キーボードのケースなど実用品を作るようになってきた気がします。

旅行 前半

キャンプ。ラウンドグリドルパンで芽キャベツのアヒージョ。2月だったので伊豆の南の方のキャンプ場でした。

箱根の彫刻の森美術館。2022年に直島の地中美術館に行ってから彫刻とかハマってる気がする。

ピカソ館。漫画みたいにでかいPICASO

ステンドグラスの塔。「幸せをよぶシンフォニー彫刻」。映えるな〜。

山中湖近くの忍野八海。富士山が見えると間違いない感じある。

YAPC::Kyoto 2023の前日に京都鉄道博物館行ってました。SLアベンジャーズ感。

またキャンプ行ってた。今度は森の中です。確か設営中雨降ってたな。

西九州新幹線乗りにいってた。軍艦島に上陸するツアーにも行ってたんですが、海が荒れて上陸できず。再チャレンジしたい。

旅行 アメリカ横断編

5月に3週間ほどアメリカに行ってました。目的は車で西海岸から東海岸まで横断することと、インディ500を見ることでした。

ロサンゼルスから出発しましたが、ロサンゼルスにはSpaceXの工場があり、ファルコン9の1段目がありました。

モハヴェ砂漠あたりですが、めちゃくちゃまっすぐだし、スケール感じる。

ラスベガス。派手なアメリカが詰まっている感。

グランドキャニオン。マジで観光している。

アリゾナのメテオクレーター。こんなん残ってるのって感じ。

テキサスのバーベーキュー屋さん。今にも吹き飛びそうな小屋の外観で大丈夫か?と思ったが、めちゃくちゃうまい。他の二人が食ってた塊肉食えばよかったなと思うものの、このコンビーフとかもうまかった

ナッシュビル。ロックの街。ここよかった。

旅の目的のインディ500。熱気がすごい。ドラマチックな展開。優勝した人のファンが、目の前にいて、勝った時に気絶しかけていた。だいぶすごい光景だった。

シカゴはめちゃくちゃ大都会。摩天楼。

ワシントンDCのスミソニアン博物館。いや〜、とにかくよかった。そういえばインディアナポリス近郊の空軍博物館にも行ってます。SR-71見れたのよかった。

そしてたどり着く、目的地のニューヨーク。本場のブルーノートよかったっすねえ。この前に食ったステーキも美味かったし、その前に食ったニューヨークスタイルのピザも美味かったし、とにかくこの旅では美味いものをいっぱい食った感じ。

でした!

旅行 後半

サンライズ出雲出雲市駅まで行って、出雲大社行って帰るっていう予定だったんですけれど、大雨で松江で打ち切りを喰らって、スーパーまつかぜ鳥取スーパーはくとで姫路まで行き、そこから新幹線で帰りました。帰りはやくもの予定だったのですが、次乗る時には車両新しくなってそう。

鉄道と言えば、秩父鉄道パレオエクスプレスにも乗ってました。何気にSL初乗車だった。

富士山近くで夏キャンプ。木に囲まれていて、涼しかったのが幸い。

白馬八方池。車で行ったが遠い。旅館のご飯美味かったのでまた行きたい。今度は電車で。

尾瀬も行きました。尾瀬沼の方を一周した。いやー〜いい体験。

秦野の大山登ってたが、雨で何も見えなかった。帰りに食べたラーメンが美味かった。

ふもとっぱらでキャンプ。毎年行ってる気がする。

奥鬼怒温泉に途中から紅葉狩り目的で徒歩で行った。目的地の宿は自家用車では行けず宿のバスを使う必要がある。前回行った際は宿のバスを使ったが、今回はその部分を歩いた。だいぶよかったですね〜。

カーフェリーで横須賀から北九州まで。山口の実家に自分の車を見せに行くという旅行だったが、フェリーはだいぶ快適でした。

コンテンツ系

  • AC6出て俺たちのやつが来た!ってなったが、途中で止まってしまっている
  • 映画は色々みた気がする。なんだかんだ「君たちはどう生きるか」が一番残っている感じする
  • 怪奇!YesどんぐりRPGにハマってしまっている気がする

2024年の抱負

  • 仕事は求められていることはやりつつ、自分で仕事を作るみたいなのに挑戦したい
  • YAPCベストを尽くす
  • WebAssemblyとかCloudflare Workers関連の興味があるもの何か外に出したいな