おそらくはそれさえも平凡な日々

同僚をどう呼ぶか ~ さん付けやあだ名など

数年前から業務上では同僚に通りの良いあだ名がない場合、極力「さん」付で呼ぶように意識している。新卒やインターンの大学生を無条件で君付けで呼ぶみたいなのをやめたいと思ったのだ。

呼称から暗黙の権威勾配が生まれることは少なくない。例えば、上司が部下を君付けで呼び、部下が上司をさん付けで呼ぶという光景はよく見られる。上下関係が前提にあり、逆転させると違和感を感じるはずだ。こういう暗黙の権威勾配は双方の心理に染み付いてしまい、構造を変えるのが難しくなる。

逆に、我々のIT業界では、新卒やインターン生が数年後に自分の上司になることも珍しくない。流動性が高くて素晴らしいことである。その時に呼び方を「君」から「さん」に変えるのもおかしな話である。そもそも上下関係によって呼び方が変わるのはナンセンスだと私は思っていて、仕事の上ではお互い一人前の大人でリスペクトしあいたいし、個人的にフラットさを志向しているというのもある。

それも踏まえて、自分は以下の判断基準で相手をどう呼ぶかを決めている。

本エントリーでは、その私のポリシーについて解説していく。

どう呼んで欲しいか表明すること

相手が望む呼び方がある場合、よっぽどおかしいものではない限り、それを用いている。

呼ばれる側がどう呼んで欲しいか表明してくれるのもありがたいと思っていて、最近の ossanfm ep.256 でゲストのKaoriさんが、結婚後の姓の山本よりも香織の方がアイデンティティがあり、どちらかと言うとKaoriさんと呼んで欲しいため、SNS上の表示をそれに変更した、という話があって、良い表明方法だと感心しました。

場合によっては、フラットじゃない呼び方を相手が望む場合もあります。例えば「社長」や「部長」と言った肩書付加を望むなど。この例は今どきなかなかないとは思いますが。これも自分のポリシーに反しない限りは相手に合わせています。

また、相手がどう呼んで欲しくないかを尊重するのも大事だと思っています。これもまたossanfmの話で、パーソナリティの栗栖さんがどこかのエピソードで「栗栖社長と呼ばれると違和感がある」的なことをおっしゃっていました。実際、栗栖さんは「栗栖さん」と呼ばれる方を望ましく思っているだろうから、そう呼んだ方が良かろう、ということです。

組織においては、自分がどう呼んでほしいか表明しやすくする雰囲気作りも大事で、最近ヘンリー社では、社員にNotion上で「ユーザーマニュアル」を書いてもらうことを推奨していますが、そこのテンプレートに「どう呼んでほしいか」の項目を設けています。例えば私は以下のように書いています。

ちなみに、皆が呼称を表明すべきだという話ではなく、特に当人にこだわりがなければ、私からは普通に「名字+さん」で呼ばせてもらえれば良いと思っています。

あだ名/ハンドル/ID文化の良さと危うさ

フラットさを志向して、あだ名で呼びあう会社がある。結構なことだと思う。あだ名/ハンドル/ID等の宣言は「自分をどう呼んで欲しいか」という自己表明・開示なので、前項の通り尊重すればよい。それを表明しやすくする施策としての、あだ名文化は良いと思っています。私も、はてなという社員全員がはてなIDで呼び合うのが前提の会社にいたことがあり、その有用性は感じています。

ただ、自分にあだ名的なものを付けること気恥ずかしさを感じる人は当然多いし、同僚とそういう距離感で仕事をしたくない人もいるので強制することでもないと考えている。

更に言うと、あだ名を別の人につけてもらうケースは危うい。エンジニアはよく知っていると思うが、命名には力がある。「名付け親」という言葉があるように、名付けというのは権力的な行為で、暗黙的な権威勾配を生む可能性があるのだ。特に「社長が新入社員にあだ名を付けてみんなでそれを呼ぶ」とかやるのは非常に危険。

あだ名文化であっても、自分で決めるのが大事。もちろん、あだ名をつけるのが上手い人というのはいて、そういう人の案を採用するのは良いですが、ちょっとでもしっくりこなかったらNoを言うのも大事です。変にあだ名圧に負けずに「普通に〇〇さんと呼んでください」と表明するのも良いと思います。

ちなみに、あだ名にさん付けするのか、呼び捨てなのか問題というのもありますが、対称性を意識しつつ、なんとなくしっくりくる呼び方をチョイスするようにしています。

具体的には、基本はさん付けですが、敬称をつけないほうがしっくり来る場合には敬称を略させてもらうこともある (例: achiku, astj)。君付けは基本はしないけど、あだ名にクンがついている場合はそのまま呼んでいる (例: ninjinkun, dekokun)。

対称性重要

これまで何度か述べてきた通り、呼称には対称性を求めたいと思っている。お互いが「さん」づけ、お互いが「君」付けだったり呼び捨てなのであれば違和感は無い。ただ、相手が「さん」付けで呼んでくるのに、相手を「君」や呼び捨てで呼ぶのは避けたい。私の方が上だと思われてしまうような呼び方は避けたいのだ。

少なくとも、こちらが「さん」付けで呼んでおけば、敬称の面では自分が暗黙的な権威勾配の上に立つことは少なかろうと思っている。お互いの距離感もあるので、相手が望む呼び方を表明していないのであれば、最初は基本は「さん」付けスタートとなる。

ビジネス上はさん付けじゃないといけないと思っているわけではない。例えば、新卒の同期だったり、大学からの同級生同士が、君付けだったりあだなや呼び捨てで呼び合ってたりするのを見ると、良いなーとか思って見たりしています。これはちゃんと対称性があるし。個人的には業務上そういう関係性の人はいないので少し羨ましくもあります。

私自身のケースだと、大学時代の中国語クラス関連の友人たちは「ソンムー」と呼び捨てにしてくれるが、仕事や技術コミュニティでは「ソンムーさん」と呼ばれてしまうことが多い。まあ、残念ながら私はなんか圧があるみたいだしね。なので、こちらも多くの場合は「さん」付けさせてもらうことになる。

ちなみに、ISUCONフレンズの、白金動物園のsorah、rosylillyとかは、私のことを「ソンムー」呼びしてくれるので、私も「そらはー」「ロージー」と呼んでいる。

私を君付けしてくださる人たち

矛盾するようようなことを書くが、明らかに人生の大先輩の方が私を「松木くん」と呼んで、私が「〇〇さん」と呼ぶ関係性がある。それは別に嫌ではなくて、むしろそう呼んでいただける人がいるのはありがたい。例えばyamazさんだったり、カヤック社でお世話になった佐田俊樹さんや佐藤純一さんがそう。今でも食事など連れて行っていただくこともありますが、引き続きよろしくお願いします。

外国人や日本語以外の場合

最後に、外国人だったり、日本語じゃないケースについて軽く触れておきます。

日本語コミュニケーションの場合は、外国人でも普通にさん付けすれば良い。さんはジェンダーニュートラルだし便利。中国語だと「先生」「女士」とか使い分ける必要あるし。

さんが便利だからと言って、英語で -san を使うのは色々意見があるみたいですが、個人的にはポジ寄りです。ただ、英語の場合、同僚間の距離感でも敬称を使わない事が多いし、そもそも自己紹介の段階で "Call me 〇〇" と、どう呼んでほしいか表明することが多いと思う。なのでやはり、どう呼んで欲しいかの表明は大事だし、そういう文化があるのは好ましいことです。

持続可能で幸せなOSS開発 ~ YAPC::Kyotoを終えて

もうだいぶ前になってしまいましたが、3月に京都でYAPC::Kyotoに参加してきました。

YAPC::Kyotoは運営の皆さま、本当にお疲れ様でした。コロナ渦で運営の継続には色々苦労があったかと思います。そんな中、世間的にコロナ明けの雰囲気になってきている中、ちょうど先陣を切るような形でオフラインイベントが開催できて、大きな盛り上がりを見せたのは、皆様の苦労が報われたようにも思いました。旧交も温められたし、それだけではなく、学生支援制度などのお陰で、若い人も参加していて交流が盛り上がってよかったです。

思えば、2019年のYAPC::Tokyoのときに僕がベストトーク賞を受賞した勢いで、懇親会の最後にで胴上げされた後に、無責任に「次は京都でやるぞ!」と、勝手に宣言したのが実現した形でした。JPAにも禄に関わっていないのに(当時は一応末席で参加することもあった)。とはいえ、懇親会で @__papix__ が「次は京都もアリだと思ってるんですよ」とか言っていて、僕が「KRP開催で大西さん(id:onishi)がキーノートだったら最高だよね」と返し、papix「京都開催だったら僕が動きますよ」とかそういう会話はしていたので、まあ目のない話ではないだろうと思った上であの発言をしたと記憶している。事前に何もなしにいきなりあの発言をするとも思えないので。しかし、papixもあまり覚えていないようなので、全部記憶違いかもしれない。

延期もありましたが、KRP開催で大西さんのキーノートが実現できたのは本当に嬉しかった。単なる外野の無責任なファンボーイとしては満足だけど、実現にあたっては難しい点もあったでしょう。papixのお疲れ様エントリーにも、自社への利益誘導にならないかどうか気にしている記述もあって、その点含めて誠実にYAPCに向きあったことが伺えて素晴らしかった。僕は、YAPC::Tokyo時点では、はてな社所属でしたが、その後3回も転職してしまいました。

あらたまさんのベストトーク

あらたまさんベストトーク賞おめでとうございます。このトークは予てから楽しみにしており、僕のトークの中でも「あらたまさんのトーク楽しみですね」という話もしていたのでした。

というのも、YAPC::Japan::Onlineのキーノートを担当させてもらったときに、「ハッカーに憧れた原体験を大事にしたい」という話をしていたのですが、このタイトルは明らかにその先の景色を見せてくれる話だろうと期待していたからです。果たしてその通りの内容でした。

yusukebeの復活

yusukebeの最近の活躍はカッコいい。一時期コードから完全に離れていたのに、ハッカーとして舞い戻ってきた。

元々yusukebeと僕は同世代で、Perl界でも近い立ち位置にいて、ハッカーに憧れつつもハッカーが作ってくれたものを「使う」立場だった。それでいいじゃんというメッセージを込めて"Perl Casual"を立ち上げたのもyusukebeだった。

Perl Casualは盛り上がり、その後のMySQL Casualなどのカジュアル勉強会ムーブメントにも繋がった。

そのようにハッカーに憧れる側だし、それでいいじゃん、というメッセージを発していた彼が、Honoというキラーソフトウェアを引っ提げ、フレームワークやモジュールを使う側ではなくて「作る側」のハッカーとして舞い戻ってきたのはアツい。

それに、Honoを見る人が見るとPerlの影響を感じる作りになっているのもエモい。明らかにPSGI/Plack, Router::Simple, Router::Boom 等からの影響があることがわかってニヤリとしてしまうのである。

moznionと個人技の話

moznionの話は良かった。彼が学生の頃から知っているが、彼のソフトウェア開発の力における「腕力」は凄まじく、時には「異常な努力」などと言われることもある。その一つの集大成がゲストトークとして見られたと思う。

裏テーマとして「個人技」というのがあったというのも納得で、彼の「極限まで求めた個人技と個人技のせめぎあい、そしてその技の協調によって形成されるチームこそが最強のチーム」という意見には全面的に同意する。

#yapcjapan YAPC::Kyoto 2023に行ってきた・喋ってきた

彼もまた「ハッカー」に影響を受けた世代なのだな、とも。

ハッカーと無縁の世代

無縁とは言い過ぎかもしれないが、最近面白いのは、はてなで活躍中の id:yigarashi さん。YAPC::Kyotoでトークはしていなかったが、YAPC::Japan::Onlineではトークをしていた のもあって注目していた。

あまり交流したことが無いので勝手な想像だが、彼は優秀なソフトウェアエンジニアでありながら、おそらく世代もあって、ハッカーであることにこだわりが無く、最強のエンジニアリングマネージャーを素直に目指している。新世代だと感じる。

ハッカーに憧れた世代が、それに対してそれぞれのアプローチ方法を見つけ、ハッカーに強いこだわりを持たない世代も出てきている、という多様さに対して胸がアツくなるYAPC::Kyotoだった。

自分のトーク

資料は荒削りだが、手直しがいつまでもできそうにないので公開することにする。

https://junkyard.song.mu/slides/yapc-kyoto-2023/#0

元々は自分の事例を例にとって、OSSに関わっていく方法について話していく技術的なTips集的な話にする予定だったが、エモい内容も含まれてしまい、とっ散らかってしまった。このトークの原案は、元々の2020年のときに話そうとしていた内容だったが、そこから数年経って醸成されすぎてしまった。

このトーク資料を作っているときや実際に登壇していた気づいたが、自分は「持続可能で幸せなOSS開発」について論じたい、というモチベーションがあることに気づいた。

OSS開発者が燃え尽きてしまったり、資金難になったりして開発を続けられなくなる話は度々耳にするようになってきた。また、サプライチェーンアタックなど、元々性善説で運用されてきたものが通用しなくなり、悪意が混入するようになってきた。

OSSの影響範囲が大きくなるに連れ、責任が求められてしまったり、悪意の混入を防ぐために重厚なプロセスが敷かれてしまったり、暗黙的なマナーなどが勝手に設けられているケースがあったりと、OSSへの参加に対する敷居が高く感じられてしまっている空気も感じていた。

それらに対して個人的に心を痛めていたのだ。だからこそ「それでもOSSは楽しいよ、気軽にやっていいよ」という無垢な立場を取り続けていた。

ただ、悪意の混入については本当に悩ましい。また、Web3等の一部の人たちが「OSSだからガバナンスがうまくいく」といった、そこだけ切り取ると、あまりにもイノセントに聞こえる発言を聞くと、無垢を気取りすぎるのも良くないと思うようになってきた。

自分にとってはOSS開発やそのコミュニティに関わったことが、大きな人生の転換期だった。「持続可能で幸せなOSS開発」を多くの人が体験できる状況であって欲しい。これについてはまたどこかで論じたいと思う。

WEB+DB PRESS

話がそれるが、このGWのビッグニュースとしてWEB+DB PRESSの休刊というのがあった。

WEB+DB PRESSではPerl Hackers Hubというリレー連載が今でも続いている。リレー形式でPerl Hackerの方にPerlに関する記事を書いてもらうものだ。僕は、2014年と2018年に寄稿し、2016年からは連載の監修チームに関わっていた。2019年の初頭までは執筆者のアサインを担当していて、第35回~第53回まで延べ19名(重複含む)をアサインした。

WEB+DB PRESSはコミュニティに関わっていなかった頃から毎号買っており、誌面からコミュニティとのつながりを感じ取れる気がしたものだ。Perl Hackers Hubに寄稿できたときは非常に嬉しかった。その後、執筆者のアサインをする中で、執筆者の人たちがコミュニティと更に繋がる手助けができたと感じることもあった。

このPerlの連載もいつまで続けられるのか、と思うこともあったが、雑誌のほうが先に休刊してしまうのは残念である。とはいえ業界への貢献も僕が言うまでもなく大きかった雑誌なので、お疲れ様と感謝の意も伝えたい。

YAPCの話からそれてしまったが、Perlやそのコミュニティに関することで、僕にとって大事な話なのでとりあげておく。

はてなと旧交

YAPC::Kyoto期間中、連日はてなオフィスにお邪魔して飲んでいました。各所の懇親会の最後の受け皿となっていて面白かったし、その懐の深さはすごかった。旧交を温められてよかったです。ありがとうございました。

ついでに、はてな社で取材を受けてきました。写真はいい感じに撮ってくれてますが、この日はYAPC::Kyoto明けでまだYAPC気分が残存しており、実は、 id:onk ともどもだいぶYAPC疲れがある中での対談でした。その後の編集でカバーしたこともあり、面白い内容にはなっていると思うので、是非ご覧ください。

ヘンリーで活躍中の id:Songmu を訪問 | はてな卒業生訪問企画 [#3]

ヘンリーに入社しました

1月から株式会社ヘンリーに入社しました。ヘンリーは「社会課題を解決し続け、より良いセカイを創る」というミッションを掲げ、現在はHenryというレセコン一体型クラウド電子カルテサービスを主力として医療DXに取り組んでいるスタートアップです。

https://corp.henry-app.jp/

ヘンリーのことはあまり知らなかったのですが、ずっと一緒に働きたいと思っていたエンジニアの一人である縣さんが所属しており、今回私が転職活動を始めたのを彼が早々に察知して誘ってくれたのがきっかけです。

彼と話したところ、開発に色々課題は抱えつつも前向きに、楽しそうに働いていると感じたのが印象的でした。ナイスガイな彼がそれくらい魅力を感じているのであれば、良いチームで面白い社会課題を解いているだろうなと。

その後、2週間で様々なポジションの7名とお話しました。どの方もモチベーション高く、顧客や事業やプロダクトに取り組んでいるのが感じられ、やはり良いチームだと確信でき、事業やプロダクトにも魅力を感じられそうだったので、入社することに決めました。

比較的年齢が若い会社ですが、CEOの一人も含め、働きながら子育てしている社員も多く、健康に活力を持って生きながら、柔軟にモチベーション高く働ける環境を志向している点も、ミッションや事業と言行一致していて魅力的でした。

人数もまだ30人程度で、リモートワーク中心で入社する上で、自分にとってちょうど良く感じる組織規模だったというのもあります。

入社して

入社して早くも2週間近く経ちましたが、ちょうど全社員参加のワークショップがあってチームメンバーや業務をキャッチアップできて助かりました。各メンバーのモチベーションの高さも改めて感じられ、これくらいの人数のスタートアップの良さを感じましたし、人がこれから増える中でもそれを維持したいですね。月末にはオフラインの新年会もあるようですし、良いタイミングで入社できて嬉しいです。

入社後驚いたことの一つに、営業チームの各メンバーがHenryをSaaSとして売っていくことをしっかりと理解していたことがあります。カスタマイズを極力避け、自分たちの製品がフィットする病院をターゲティングしてリストアップし営業をかけている点が非常にクレバーだと感じました。開発側としても迷いを減らして生産性を上げられるので嬉しいポイントです。

とはいえ、医療というドメインはなかなか難しく、入社したら予想通り情報量も多くて大変です。私自身も自分が直接のユーザーにならないサービスを開発するのはSIer時代以来でだいぶ久しぶりのことで、その点もチャレンジングではあります。

ただ、私も歳を重ねるに連れて、医療機関にお世話になる機会も増え、医療は、今後一層自分ゴト化せざるを得ないドメインです。また、電子カルテ自体も実はまだ普及率が50%程度にとどまり、業界にDXの余白が多く残っている状況で、事業にもまだまだ伸びしろがあります。日本は世界一の高齢化先進国の一つになることが宿命付けられているので、その分野で世界をリードできるチャンスもあります。そんな中で良い仲間と有意義な社会課題を面白く解いていくことを楽しみにしています。

また、今はレセコン一体型電子カルテがメインサービスで、しばらくはそれが注力事業ですが、長いスパンでは医療ドメインや隣接分野でも新規サービスを展開していきたいと考えているようですし、新規事業がどんどん生まれる会社になると嬉しいですね。

技術

システムとしてはいくつかのマイクロサービスに分割されていてバックエンドは主にKotlin、BFFにNode.js, TypeScript、フロントはReact, TypeScriptです。BFFのプロトコルは後ろはgRPCで前はGraphQLです。クラウドはGCPで主にCloud Runを実行環境としています。

結構モダンな技術選定ではありますが、その分苦労している点もあるようです。お陰様でお客様も付き始め、その過程で当初想定していなかったことや、運用の難しさなどにも当然直面しています。当初の設計も振り返りが必要なタイミングだとも感じているようです。

また、当然品質が大事な製品なので、QAフローを厚くやりつつも、そこが開発サイクルのボトルネックにならないよう全員がQAを意識して開発に取り組む必要性も感じています。言うのは簡単ですが、これは開発に携わるメンバー全員が感じている大きな課題意識です。

採用

ということで、各職種絶賛採用中なので、お問い合わせいただけると嬉しいです。

https://jobs.henry-app.jp/

また、1/24(火)にオフラインのエンジニアミートアップをやるのでヘンリーが少しでも面白そうだと思ったらお申し込みください。ピザやビールを片手にラフに技術について雑談できればと思います。そういう機会も久しぶりなので楽しみですね。


https://henry.connpass.com/event/271976/

お待ちしています!

退職

12月末でLaunchableを退職します。実際には11月30日が業務最終日で12月は求職活動をしていました。幸い12月中に転職先を決めることができ、1月から次の会社で働きます。次の会社は年明けにお知らせします。

求職活動中は多くの方や会社から連絡をいただき本当にありがたかったです。全てにお返事をすることができず申し訳ありませんが、直接お知らせできなかった方にはこちらでお知らせとなることをご了承ください。

以上でお知らせは終わりで、以降は単なる中年男性のしょうもない独白です。


退職は非常に残念で、Launchableでまだまだやりたいことはあり、これからというところでもあったのですが、言ってしまえば西海岸外資の洗礼を受けたということです。

今回の僕の挑戦はあっけなく終りを迎え、ほろ苦い体験となりました。とはいえ間違いなく良い経験にはなりました。Launchableの事業は引き続き応援していきます。ありがたいことにSOもいくらか付与されているので、折角なので行使できる分はするつもりです。未上場外国株式を持てる機会もなかなか無いですし。

今回の退職は僕の能力不足起因ではないと会社からは伝えてもらったし、よくある決り文句ではなく実際にそう思ってくれているのも分かったのですが、僕としてはやっぱり実力不足だったなと受け止めています。

錯覚資産に自分が錯覚させられていた話

僕はアウトプットが多い分、実力に対して過大評価されているとは常々思っています。必要以上に自分を大きく見せたくない自分としては居心地の悪さを感じつつも、過度にへりくだることは自分を評価してくれる人を貶める態度なので、その評価に見合うように頑張ろうと思ってやってきました。

それに評価していただくと思わぬ面白い機会をいただくことも増え、その機会に乗って結果を出すことが自分の成長につながるのも感じていました。過大評価に自分の実力を合わせていくということで、それもまた自分の持ち味だとも捉えていました。「過大評価よりも過小評価されることを恐れたほうが良い」といったことをkazuhoさんが以前どこかでおっしゃっていたように記憶していますが、自分を大きく見せたくない人間に取って、それは余計留意すべきポイントだとも思っています。

そういった自分のスタイルを受け止めつつも、周りからの評価に対して詐欺師的なジレンマを感じたり、「有名エンジニアは実は仕事ができない」みたいな言説が定期的にSNSで話題になるたびに心にチクリと痛みを感じることもありました。

とはいえ、やはり、あまりにもうまく行き過ぎていた。特に30歳以降、キャリアを望めば望む方向に進める感じがありました。それは、偶然歯車が噛み合ってうまく動き出した。つまり運が良かったからだ、とは思っていたはずです。しかし、努力は必ず報われる、はずがない、という当たり前のことがもしかしたら自分には当てはまらないのではないかと傲慢になっていたのかも知れません。過大評価が自分の実力だと勘違いしてしまうことが怖いと思っていたのですが、結局勘違いしていたのではないか。

努力をしていたつもりでもその土俵で戦えなくなることはあるし思い通りにならないからこそ人生は面白いのでした。今回の挫折は良い薬になり、自我の肥大にブレーキをかけるきっかけにもなりました。

20代の頃は苦労したし、その経験もあって、自分のような頭が良いだけで社会性のない人間がいつ転落するかわからない。そのように思っていました。しかし、近年はその感覚が薄れていたし、転落のような劇的な変化が自分に起こりうると思ってしまう事自体、中二病的な恥ずかしい感覚なのかもしれない、とも思うようにもなっていました。しかし、改めて自分はどうなるかわからないし、程よい危機感を持って生きる必要があると思い直しました。

しかし、ここまで書いて読み返してみると、だいぶ気持ち悪い文章ですね…。退職が決まった12月頭に書いたらもっとひどい文になっただろうと思い、すぐには書き出さず、少し落ち着いた今なら大丈夫だろうと思って書き出したらこの有様です。

今回の求職活動

それくらいショックを受けていたのですが、12月に求職活動を始めながら何人か知人に相談にのってもらい、そして、ありがたいことに色々な会社から声をかけてもいただきました。皆様その節は本当にありがとうございました。その中で、何社か選考に進み、12月にオファーを出してくださった会社の中から次の会社を決めました。

当初は焦って決めたくないし、1月は休みたいとも思っていて、2月から働く想定でした。その勤務開始時期も応募した会社にはそれぞれ伝えていたにもかかわらず、12月で決めてしまい、他社の選考を中断したのは申し訳なかったです。

次の会社が、拙速な判断にならないように何度も面接のステップを踏まえつつ、意思決定早く選考からオファーまで進めてくださったので、こちらも早くお返事したくなったのと、他社も含めた求職活動の中で元気が出てきたので1月から働く気になったというところです。

妻からも「求職活動を引き伸ばして選択肢を増やしても迷いが増えるだけだし、他の会社に選考コストを無駄に払わさせることにもなるから、そこが良いと思ったのならさっさと決めても良いんじゃないの?」のようなことを言われ、僕も最後は直感で決めるのが良いと思っているのでさっさと決めてしまって動くことにしました。

採用ツールやフロー

ちなみに、求職活動をしていることをTwitterでは告知しませんでした。連絡が多くなりすぎて捌けなくなるだろうと思ったからです。なので、広報範囲を絞る意味で、まずは登録した後あまり活用していなかったYOUTRUSTで転職ステータスを変更し、メッセージも投稿しました。それで集まらなかったら、facebookやLinkedInでも告知するつもりでしたが、YOUTRUSTだけで返事しきれないほどの連絡をいただきました。ステータス変更だけで多くのメッセージがすぐさま届きました。各社の人事仕事してるし、エンジニア採用事情が大変なのだな、と感じました。

Twitterやfacebookでのコネクションは維持したいと思いつつも、もはや誰とつながっているかわからないのでキャリアSNSという切り口でソーシャルグラフが再構築されている点、条件面含めた希望面もある程度具体的に書いても角が立たない雰囲気がある点など、YOUTRUSTは有用でした。

そういえば同時期に転職活動をしている人がTwitterサークル機能を使って転職を告知していて、なるほどそうやって広報先を絞る方法があったか、と膝を打ちました。

それと、10年近くぶりに日本のエンジニアの通常の採用選考を受けましたが、選考フローは以前と比べてどこも格段に洗練されていました。エンジニア採用が難しくなっていることも影響しているのでしょう。

事前準備が必要な技術課題が課されるケースも多くありました。ただ、そうすると選考のリードタイムが伸びてしまう悩ましさもあると感じました。しかし、採用は失敗するとダメージが大きいので、ちゃんと見極めるためには大事なステップですし、有名人だからといって変に特別扱いせずフェアにやるべきだし、むしろ技術的にマッチしない有名人を雇ってしまうとダメージがもっと大きくなりますし、ジレンマですね…。

なんにせよ、数年前まではエンジニア採用に積極的に関わっていて採用活動は嫌いではないし、次の会社でも採用に関わることもありそうなので、良い会社の選考を受けられたことは今後の参考になるありがたい体験となりました。

ミドルエイジクライシス

それに、選考を受け、その中で自分の考えや過去のエピソードなどを話せたのは、自分の思考を整理して自分を見つめ直す良い機会にもなりました。ミドルエイジクライシスとか言い出すの嫌だなーと思ってたのですが、今後のキャリアも人生も長いし、変化の早い時代の中で定期的に自分を振り返るのは必須だなと思うようになりました。

僕はわがままで自分の欲望を大事にしたいし、つらいと感じたら何かが間違っていて、その苦しさに陶酔してはいけないと考えています。などと言いながらそれなりに苦悩しながら生きている現実もあります。

以前、yamazさんに「松木くんは悩める人だから」と言われたことがあり、それから「これは自分のパーソナリティで、ずっと付き合っていくものなのだな」と肯定的に受け入れられるようになったことがありました。その後補足で「それはむしろ才能なんじゃないか」的なことも言われ、自分の持ち味なのだとも思うようにもなりました。

一流と超一流の間

ということで、僕のことを結構すごいエンジニアだと思ってくださっている方も多いでしょうし、僕自身もそんなに悪くないエンジニアだとは自己認識するようにしていますが、他の多くの皆様同様に悩みを抱えていたりするわけです。人生を楽しみたいと思い、もちろんかなり楽しみつつも、何故か苦しんでもいる。人生そんなもんです。虚勢を張って自分を良く見せすぎても余計自分を苦しめるだけなのです。

僕は自分を一流エンジニアだと思うようにしていますが、超一流では決してありません。そこには自分の中で明確な線引きがあり、それを決して超えられないとも感じているのですが、そのあたりの言語化はそのうち試みるかも知れません。

とはいえ、OSSやTwitter、ブログ等のアウトプットをレバレッジにする自分のスタイルは変えるつもりはないし、変えられないとも思っています。それを所属企業の広報的にも活かしていくのが僕の強みの一つだとも考えているので。

ただ、このブログを含め文章については日本語のアウトプットが大半なので、そこに閉じていないで英語を使うチャレンジは増やしたい。Launchableでそれを狙っていましたが残念ながらうまくいきませんでした。とはいえ、ここ数年、英語学習量、会話や読み書きの頻度を増やす中で英語は少しづつながら着実に成長している手応えは感じているし、面白味も感じています。これはまた、ソフトウェアエンジニアリングと同じで、ライフワーク的に続けていくものだと思うようになりました。

ということで、キャリアの惑いは尽きないものですが、自分も含め、幸い世のソフトウェアエンジニアの仲間たちが変化に富んだ多様な生き方を示してくれています。一緒に考えながら、基本的には愉快に、時には悩みながら面白い人生を歩んでいきたいと思っています。

直近2社は短期間の所属になってしまったので、次は長く勤めたい。僕の志向として短期的に発揮できる技術だけではなく、自分の能力を長期的な事業貢献に繋げたいし、そこでバリューを発揮できるとも考えています。会社としてもそういう動きを僕に求めるでしょうし、次はそういう手応えを感じられる充実した働き方を長く継続できるようにしたい。

ササミの漬け - お手軽高タンパク常備菜

バズレシピアドベントカレンダーの24日目です。リュウジさんの鶏胸肉のレモン漬けをベースにして、ササミの漬けを定期的に作っているので紹介です。

多めに仕込んで、常備菜として一週間程度で食べきっています。お手軽高タンパク食でアレンジも効いて美味しいので、食事に一品足したいときとか、料理したくない時や間食でぱっと食べるのに便利です。

アウトライン

リュウジさんのレシピと異なる点は、ササミを使っている点、ブライン液に漬けて吸水する工程がある点、漬け汁に酢とワサビを加えて長期保存が効くことを期待している点です。

ササミは、自分の場合500g強のパックが近くのスーパーに安めに売っていて、それをまとめて仕込むのが都合が良いのと、切りやすいこと、胸肉と違って皮の処理を考える必要がないことなどの理由で採用しています。

ブライン液とは水に対して5%の分量の砂糖と塩を溶かした溶液です。肉に吸水させる方法は色々試したのですが、これに浸すシンプルな方法に行きつきました。P2B Hausのよだれどりが感動的に美味しく、お店の人に調理方法を聞いた時に教えてもらいました。

材料

漬け汁は元のレシピで使われている「これ!うま!!つゆ」があれば素直に使うと良いでしょう。ウチにはヤマキの白だしと創味のつゆが常備されているので使っているだけです。

味の濃薄の好みもあると思うのでアレンジするといいでしょう。ワサビは結構入れてしまっても大丈夫です。私は刺身パックの余った小袋を2,3個まとめて使ったりしています。風味付けにもなりますし、ワサビが苦手な妻も美味しく食べています。

手順

1. ササミをそぎ切りにする

切りやすい厚さでよいですが、厚みによっては茹で時間を多少調整する必要が出てくるかも知れません。筋取りはしていませんが、丁寧にやりたいならどうぞ。

2. 切ったササミをブライン液に一晩以上つける

ブライン液は浸透圧等の関係で分量が大事らしいのでしっかり計量しましょう。特に塩分は5%を超えず、3~5%の範囲に収まっていると良いようです。また、この工程は吸水が目的なので、それ以外の調味料を加える必要はありません。

漬け時間は冷蔵庫で半日~丸一日。

3. 片栗粉を絡める

冷蔵庫から出して水を切り、ボウルのまま片栗粉をふりかけて手で絡めます。片栗粉は大さじ2としていますが全体に絡めばいいので厳密に計る必要はありません。

この片栗粉が水晶鶏のようなプルンとした食感を生み出します。

4. 沸騰したお湯でさっと茹でる

沸騰したお湯に肉をまとめて投入し、たまに軽く混ぜながら火の通りが均一になるようにします。茹で時間は様子を見ながら大体2-3分。実際は肉を投入後に再沸騰を待ち、そこから30秒-1分程度で茹であげとしています。

元のレシピの茹で時間は1分程度になっていますが、僕の腕前の問題で切り方が厚めなのと、このレシピでは冷蔵庫で漬けておいた肉を取り出して直ぐに茹でることになるので、長めに茹でています。常温に戻す工程をいれても良いかも知れませんが、手間ですし、戻す時間によって逆に茹で上がりがブレそうなのでやっていません。

茹で汁も旨味が出て美味しくなっているので、味を整えてスープなどにしても良いでしょう。

5. 保存容器に入れ漬け汁に浸す

茹で上がった肉を保存容器にあけ、漬け汁を注ぎます。保存容器はこのジップロック コンテナー正方形 700mlがジャストサイズで気に入っています。漬け汁を注ぎすぎると蓋を閉めるときに溢れてしまうので気をつけましょう。

実は私は実際には漬け汁を注ぐのではなく事前に水以外の調味料を保存容器に入れておいて、そこに肉をあけてから水を加えて水位を調整するという工程を取っています。洗い物を増やしたくないので。

6. 仕上げ

元のレシピにもある通り、蓋を閉める前に、黒胡椒をお好みでこれでもかと振りかけましょう。

薄切りレモンを乗せられると嬉しいですが、無くても構いません。酸味の強い系の柑橘の皮が余っていれば乗せるのはオススメです。私は柚や小夏(日向夏)を使いましたが良かったです。

あとは冷蔵庫で数時間置けば食べられます。私は1週間弱を目処に食べきるようにしています。ラー油や柚子胡椒などを加えて食べても美味しいです。

まとめ

簡単にでき、高タンパクで多めに仕込んでおけるので、ダイエッターやトレーニーにとっても嬉しい一品となっております。是非お試しください。

tagpr を機能強化してv1.0.0をリリースしました

前回のtagprの紹介エントリの反響が思ったより大きくて喜んでいます。ということで、積み残し及び、要望やヒントから着想を得て幾つかの機能を追加実装しv1.0.0をリリースしました。

https://github.com/Songmu/tagpr/releases/tag/v1.0.0

ありがたいことに、public repoだけでも十数名の方に既にご利用いただいているようで、フィードバックから細かいエッジケースの修正も幾つかおこなって敲かれたため、だいぶ使い物になるソフトウェアになったと言って良いでしょう。

ということで、追加された機能等について解説していきます。

uses: Songmu/tagpr@v1

これまではワークフロー上で uses: Songmu/tagpr@main とブランチ直指定してもらっていましたが、uses: Songmu/tagpr@v1 と指定できるようになりました。こっちのほうが、tagpr自体のリリースタイミング的にも若干安全なので、既にお使いの方にはお手数ですが切り替えを推奨します。

併せてMarketplaceへの公開もしました。GitHub ActionsのカスタムワークフローのMarketplace公開は初めてなので嬉しいですね。

https://github.com/marketplace/actions/automate-pull-request-generation-and-tagging-for-releases-using-tagpr

CHANGELOG.md を自動変更しないオプション

CHANGELOG.mdを自動更新しない設定を .tagpr 設定ファイルに書けるようになりました。

[tagpr]
    changelog = false

前回の紹介エントリを書いたらすぐにsiketyanさんからpull requestいただきました。ありがとうございます!

https://github.com/Songmu/tagpr/pull/86

Conventional Labelsの強化

リリース対象のpull request一覧を拾い、それらのラベルに"major"か"minor"が含まれていた場合、それを考慮して次バージョン番号候補をtagprが生成するpull request上に出力するようにしました。

これは便利だと思います。

GitHub Releases作成挙動の変更オプション

tagprはデフォルトでtagを打つと同時に、GitHub Releasesも作成しますが、この挙動を設定可能にしました。tagpr.release設定キーに、true, false, draftの何れかを指定できます。

[tagpr]
    release = false # [true/false/draft]

GitHub Actions用出力により後続のタスクとの連携が容易に

tagprがtagを打った後、別途ジョブを動かしたいケースは多いでしょう。実行ファイルやコンテナをビルドしてパッケージングし、それらを何らかのリポジトリにアップロードしたり、deployフローを動かしたりなど。

これは、tagをトリガーにして別ワークフローを動かすのが良いと思いますが、前のエントリで説明したように、GitHub tokenの権限周りの仕様の関係でトークン発行処理を組む必要が出てくるなど少し複雑になります。

ですので、tagpr実行後に直接後続のタスクを動かせれば一つのワークフローの責務は多めになりますが、お手軽です。

それを実現しやすくするために、GitHub Actions用の出力を出すようにしました。具体的にはtagpull_requestというoutputsを出力します。このtagが空か否かを見ることで後続のフローを動かすかどうかの判定を簡単におこなえます。具体的には以下のような具合です。

- uses: actions/checkout@v3
- id: tagpr
  uses: Songmu/tagpr@v1
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: ./.github/actions/release
  with:
    tag: ${{ steps.tagpr.outputs.tag }}
  if: "steps.tagpr.outputs.tag != ''"

このサンプルでは、後続のリリースフローをリポジトリローカルのカスタムアクションにまとめています。.github/actions/release/action.yml に処理を記述することになるでしょう。

このようにしておくと便利な点としては、上記のtagprのワークフローが途中で意図せず失敗してしまった場合に、リリースフローをリカバリするために手動でタグを打つワークフローを別途用意しやすくなることです。

name: release
on:
  push:
    tags:
    - "v[0-9]+.[0-9]+.[0-9]+"
jobs:
  release:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - uses: ./.github/actions/release
      with:
        tag: ${{ github.ref }} # Note that github.ref is formatted like refs/tag/v1.2.3

tagprがタグを打った時、secrets.GITHUB_TOKEN を使っている限りはこのワークフローがトリガーされることはありませんが、手動でタグを打った場合にはこのワークフローが動くという具合です。

FUNDING.yml

FUNDING.ymlを配置してGitHub Sponsorsへの導線をつけました。ワンショットスポンサーのメニューもあるので、是非スポンサーをご検討下さい。

https://github.com/sponsors/Songmu?frequency=one-time

スポンサーのみならず、引き続きpull requestや感想や要望等お待ちしております!

Shodo校正APIの結果をpull requestのレビューコメントに自動反映する

Shodo AI校正APIのベータ版に申し込み、利用させていただいています。Shodo、日本語校正のSaaSということで注目していて、今回のAPIベータ版の話がTLに流れてきたので申し込み、当選することができました。

日本語校正サービス・ソフトウェアは商用のものの質はやはり高く、例えば老舗ジャストシステムのJust Right!などは友人のライターが利用していて、評判の良さも聞いています。

ただ、それらはいかんせん良いお値段します。もちろん、良質なサービスに対価を払うことはやぶさかではありませんが、私のようなホビーライターからするとちょっと厳しいお値段です。

ただ、私もブログは細々と継続していて、不定期で有償の記事や執筆をお受けすることもあるため、何らかの校正サービスを使いたいと思っては常々思っていました。

その点、スポットで従量課金的に利用できるSaaSモデルであるShodoは魅力的です。また、APIがあればCI/CDに組み込むのも容易です。私はGitHubで文書を管理することが多いため、そこも嬉しいポイントです。インストールライセンス型のパッケージでは実現しづらい部分でしょう。

action-shodo-lint

ということで、ShodoのAPIを利用して、pull rquestにレビューコメント及び変更提案をしてくれるGitHub Acitonsのカスタムアクションを作りました。

https://github.com/Songmu/action-shodo-lint

ブランチを切ってpull requestを作ると、デフォルトブランチとの差分があるマークダウン(.md)ファイルを校正APIにかけ、以下のような変更提案をしてくれます。

ワークフローも以下のように簡単に書けます。

name: action-shodo-lint
on: [pull_request]
jobs:
  shodo:
    name: runner / shodo
    runs-on: ubuntu-latest
    steps:
    - uses: Songmu/action-shodo-lint@main
      with:
        github_token: ${{ secrets.github_token }}
        api_token: ${{ secrets.SHODO_API_TOKEN }}
        api_root: 'https://api.shodo.ink/@{your_organization}/{your_project}/'

Shodo 校正API自体がベータであるため、このアクションも割と実験的なものにはなりますが、現在のベータ利用者はすぐにご利用いただけます。

スクリーンショットからわかる通り、内部的にはreviewdogを使っています。また、今回別で作った、Go版のShodo API CLIツールであるgoshodoも活用しています。

goshodo

https://github.com/Songmu/goshodo

公式のPython CLIがありますが、個人的にはGoのほうが早く書けるのと、とりあえずやりたいことを実現するためにGoで別のCLIを作りました。

この goshodo は公式の shodo コマンドの lint サブコマンド相当の機能のみ備え、かつ、それを拡張しています。

具体的には、複数ファイルを引数に持てるようにしたことと、-f checkstyle オプションを指定することでCheckstyle形式のXMLを標準出力に出せるようにしたところが拡張点です。

なにがしかの規格に準拠したフォーマットで出力を出せれば、他のツールと連携しやすくなります。実際、reviewdogもcheckstyle入力フォーマットを受け付けているため、とりあえずそれで出せるようにしました。

action.shを見てもらうとわかりますが、やっていることは以下の一行がほぼ全てです。

echo "$files" | xargs goshodo lint -f checkstyle | \
  reviewdog -f="checkstyle" \
    -name="shodo" \
    -reporter=github-pr-review \
...

checkstyle を選んだのは action-textlinttextlintとreviewdogの連携で使われていたため、それに倣った形です。

ただ、checkstyleフォーマットにも不満があって、具体的には指摘の開始位置を指定できるのですが、仕様上終端を指定できない点が困ります。

なので、現状action-shodo-lintでは無理やりsuggestionsを出力しているのですが、それは校正範囲とその提案が一行に収まる場合のみに限っています。

このあたりの課題感については、reviewdog repository内の以下のドキュメントにまとまっており、読み応えがあるのでおすすめです。

Reviewdog Diagnostic Format (RDFormat)

これを読んだ結論として変更提案をより良く出したい場合には、以下のフォーマットへの対応を検討すると良さそうです。

Shodo APIやCLIへのフィードバック

ベータ版を使わせて頂いている身として、この場でフィードバックを何点か書いてこの記事を終了しようと思います。

校正結果APIのレスポンスの"after"

https://github.com/zenproducts/developers.shodo.ink/blob/master/docs/api.md

レスポンスには必要な情報が網羅されていて良かったです。

一点だけ対応してほしい点として、推奨される置き換えテキストが格納されているafterフィールドに「トル」という校正指示が入るケースがあるのが気になりました。校正後の置き換えテキストは空文字列にしつつ、校正指示文言は別のフィールドに格納されている方がプログラムから扱うには嬉しいです。

また、カラム位置やインデックス番号がすべてUTF-8文字数になっているのはプロダクトの思想の問題だと思うので構わないと思います。ただ、合字などの扱いがどのようになるのかは調べていませんが、気になりました。

校正ルールのAPI管理

校正ルールを設定ファイルやAPIで管理できると、GitHubを用いたような執筆フローにより組み込みやすいと思いました。

公式CLIのlint出力

公式のCLIの出力は、デフォルトでは人間が読みやすい出力になっていて、それは問題ないと思います。

それに加えて、私がgoshodoで拡張したように、複数ファイルを受け取れるようにして、-f オプションで各種出力フォーマットを選択できるようになると嬉しいと思いました。textlintが多くの出力フォーマットに対応していて参考になります。

公式CLIのXDG_CONFIG_HOME対応

これは本当に些細な指摘で好みの話ですが、公式CLIは現状 ~/.shodo/credentials に秘匿情報を書き込みますが、近年はホームディレクトリが汚れないように、 $XDG_CONFIG_HOME/shodo, ~/.config/shodoにこういった情報を書き込むのがセオリーになってきています。特にこだわりがなければそのように変更してみるのはいかがでしょうか。

ref. https://wiki.archlinux.jp/index.php/XDG_Base_Directory

何にせよShodoのことは応援しています!

GitHubのリリースノート自動生成機能からCHANGELOG.mdを生成する

tl;dr

本題

GitHubには、リリースノートを自動生成する機能がある。これは、リリース間でマージされたpull requestのタイトルを一覧し、リリース項目としてGitHub Releases上に出力してくれるものです。リポジトリ上に.github/release.yml設定ファイルを配置すれば、pull requestの作者やラベルを元にグルーピングしたり非表示にするといった出力内容のカスタマイズもできる。

このあたりの実際の運用方法については以下のBlog記事を参考にすると良いと思うし、僕も参考にさせてもらいました。

また、r7kamuraさんの記事にも書かれていますが、このリリースノートはAPIからMarkdownを得ることもできます。そして、このAPI出力を、keep a changelog形式に近いMarkdownに変換し、CHANGELOG.mdを出力するgh2changelogというツールを作った。これはtagpr を作る中の副産物で、別ツールとして切り出したものでもあります。

https://github.com/Songmu/gh2changelog

ちなみに、keep a changelog形式は、これもまたr7kamuraさんの記事に書かれていますが、Changelogのガイドラインとして2015年頃に提案され、受け入れられてポピュラーなフォーマットになったものです。参考リンクを載せておきます。

pull requestのタイトルをChangelogに転記するコンセプト

個人的にもともと、Changelogは作りたいが、書く手間をあまり取られたくない、しかしcommit messageを一覧してChangelogするのは粒度がマチマチで見づらくなるし、後から書き換えるのも煩雑になるで避けたい。なのでpull requestのタイトルを一覧してChangelogとするのは良い落とし所だと考えていました。

実際、そのコンセプトを実現するためにghch というツールを以前作り、今でも活用しています。ありがたいことに200 starsを超え、僕のOSSの中では代表的なものになっています。

そして、冒頭に書いたGitHub公式のリリースノート生成機能は去年追加されたのですが、これも既に書いたとおり、まさにpull requestのタイトルベースでChangelogを生成するものでした。

公式がそういう機能を出してきたのであれば乗るのが正道であり、そこで作ったのがgh2changelogです。なのでghchの一部機能の後継ツールでもあります。

.github/release.ymlでのカスタマイズも嬉しい点で、keep a changelog形式で提案されているAdd, Changed, Deprecatedといったタイプ別に、ラベルを用いたカテゴリ設定を記述すれば、理想的なCHANGELOG.mdを出力できます。

ちなみに、gh2changelogは敢えてのkeep a changelog形式決め打ちの出力であり、ghchはJSON出力もできて自由度が高いツールです。コンセプトが異なるため、完全にgh2changelogghchを置き換える訳ではありません。

CHANGELOG.md欲しい?

GitHub Releasesが熟れてきたし、そっちのリリースノートに更新内容が書いてあれば、もはやCHANGELOG.mdを配置する必要は無いし、むしろ二重管理になるのも困るという意見は正しいと思います。

なので、CHANGELOG.mdを配置するというのは僕個人のちょっとしたこだわりでしかないとも思います。ただ、以下のような利点から配置するようにしています。自動生成する分には二重管理の問題も解消されているので。

ということで、私同様にChangelogが好きな方は、一度gh2changelogをご利用いただけると嬉しいです。

リリース用のpull requestを自動作成し、マージされたら自動でタグを打つtagpr

常々GitHubにtag requestが欲しいと言ってきましたが、それを実現するツールを作りました。OSSなど、バージョニングとリリースが伴うソフトウェア開発のリリースエンジニアリングをとにかく楽にしたいという動機です。既に自分が管理している幾つかのOSSでは導入して便利に利用しています。

https://github.com/Songmu/tagpr

アイデア

基本の発想は以下のようにシンプルです。

リリース用のpull requestを自動で作りマージボタンを以てリリースと為す、というのは、みんな(僕が)大好き git-pr-release と同じ発想です。git-pr-releaseではブランチをdevelopとmainに分けることでマージをリリースとしていましたが、tagpr ではmainブランチ一本で、マージコミットにタグを打つ点が異なります。

タグが打たれるので、それをトリガーにして成果物の生成などを別途行うと良いでしょう。

CHANGELOG.mdについては、GitHubのリリースノート生成機能を利用しているため、.github/release.ymlで表示が調整できます。

ref. https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes

導入

リリース時にsemver形式のtagを打つフローのリポジトリであれば、今すぐ導入できます。GitHub Actionsでの実行を前提としており、以下のワークフローを配置するだけで導入完了です。

# .github/workflows/tagpr.yml
name: tagpr
on:
  push:
    branches: ["main"]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: Songmu/tagpr@main
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

tagが打たれた後に、更に別のAcitonを動かしたいときには GITHUB_TOKEN の扱いについて気をつけるべき点があり、それは後で説明します。

実際のフロー

tagpr の実際のフローをもう少し詳細に説明すると以下のようになります。

  1. (自動) mainブランチが進むとリリース用のpull requestが作られる
    • mainブランチの先頭からブランチングされる
    • mainブランチが更に進むと自動で追随する
  2. 1で出来たブランチに必要なら更新を加える
  3. pull requestを好きなタイミングでマージする
  4. (自動) タグが打たれ、GitHub Releasesも作られる

作られるpull requestは以下のようなものです。

pull requestの内容 https://github.com/Songmu/tagpr/pull/69

作った動機

個人のOSS開発上の課題意識から。OSS開発のリリース作業は、定形作業ではあるのですが、細々した作業が発生し、案外漏れが出たり、属人的にもなりやすい。例えば以下のような作業です。

特に、リリースに必要なファイル変更は、機能開発とは関係ないちょっとした変更なのでリリース担当者がサッと済ませてしまうことも多く、案外暗黙知となります。それで、他の人が見様見真似でやると必要なファイル更新が漏れる事故などが起こりがち。

これは、ちゃんと引き継げばいいと言うよりかは、引き継がなくても恙無くリリースできる状況を作るのが理想です。

なので、これもpull requestにしてレビュー可能な状況を作るとともに、pull request及びその変更も可能な限り自動で作られ、それがマージされたらリリースされるようにしたい。それを実現したのがこのtagprというわけです。

リポジトリに訪れた人も、そのpull requestを見れば、未リリース項目が把握でき、マージすれば新バージョンがリリースされることがわかるという、見える化・透明性の向上効果もあります。

リリース作業時にリポジトリ上で追加で変更したいファイルがある点や、tagを以てリリース完了としたいという点で git-pr-release とユースケースが異なります。

pull requestのタイトルと本文

上記のスクショを見てもらうとわかるように、pull requestの本文に、"What's Changed"で始まるリリース項目が自動で一覧されるのがお役立ちです。これはGitHub標準のリリースノート生成機能を利用しています。

このタイトルと本文は、設定ファイル.tagprtagpr.template キーにGo形式のテンプレートを指定することでカスタマイズ可能です。

pull requestのcommit内容

tagprはpull request生成時に標準で以下のファイル更新を行います。

また、初回実行時に以下のファイルが存在しない場合、最小限設定済の雛形を生成します。

リリース作業時に他にも自動更新させたいプロジェクト固有の項目がある場合、tagpr.command 設定にコマンドを指定し、commit前に任意のコマンド実行ができます。

また、リリース前の変更作業を手動でおこないたい場合、pull requestのブランチを直接編集し、commitを重ねてしまって構いません。

後はこのpull requestをマージすれば、マージコミットに自動でtagが打たれます。merge commitを作る形式でもsquash mergeでも構いません。

tagと同時にGitHub Releaseも作るのですが、これをオフにするオプションも設けるかもしれません。

次バージョン指定方法

tagprのバージョンインクリメント挙動はデフォルトではpull request上で単にpatchバージョンをインクリメントするだけです。しかし、major, minorバージョンを上げたいことも当然あるでしょう。これには二つの対応方法があります。

後者は、versionfileを利用しない運用の際に採用すると良いでしょう。また、リリース対象項目のpull requestに付与されたラベル等を見て、major,minor,patchのどれをインクリメントするかを推測する機能を将来的に追加したい。

secrets.GITHUB_TOKEN が次のActionsをキックしない問題

tagprは自動でgit tagを打つところまでやってくれるため、そこから別のGitHub Actionsのワークフローをトリガーしたいこともあるでしょう。成果物の生成やアップロード等。

しかし、tagprの動作にGitHub Actionsが自動で提供してくれる secrets.GITHUB_TOKEN を利用すると、後続のワークフローは動きません。これは、ワークフローの意図しない再帰的な連続実行を防ぐための仕様です。

ref. https://docs.github.com/en/actions/security-guides/automatic-token-authentication#using-the-github_token-in-a-workflow

このため、後続のワークフローをトリガーしたい場合、tagprを別の権限で実行する必要があります。以下は、secrets.GH_PAT にpersonal access tokenを指定した例です。git push --tags も別権限で行いたいので、actions/checkoutにもこのtokenを指定しています。secretsはリポジトリ設定から別途指定してください。

name: tagpr
on:
  push:
    branches:
    - main
jobs:
  tagpr:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
      with:
        token: ${{ secrets.GH_PAT }}
    - uses: Songmu/tagpr@main
      env:
        GITHUB_TOKEN: ${{ secrets.GH_PAT }}

簡単のためにpersonal access tokenの例を書きましたが、GitHub Apps等を用いてtokenを都度生成するような手法を使ったほうが安全でしょう。

まとめ

他の細かい設定等についてはドキュメントをご確認ください。長々と書きましたが導入は簡単で便利です。実際個人的に便利に使っていますし、結構頑張って作ったので使ってもらえると大変喜びます。

とはいえ主張が強いツールなので、色々適用しづらい場合もあるかとは思います。そのあたりはフィードバックがあると大変嬉しいです。

ちなみに、今回のtagprを含め、これまでOSSのリリースエンジニアリングに関わるOSSを幾つか自作したり開発に携わったりしてきたので、どうやら私はこの分野が好きなようです。

そのあたりの話を来月のGo Conference mini 2022 Autumn IN SENDAIでお話する予定です。「OSSの最適なリリースエンジニアリングを求める旅路」というタイトルです。

私は仙台に行く予定ですが、現地枠もオンライン参加枠もまだあるようなので是非お申し込みください。仙台で交流できることも楽しみにしています。

https://sendaigo.connpass.com/event/256463/

git-pr-releaseとGitHub Actionsでワンクリックデプロイを実現する

突然ですが、git-pr-releaseのなんちゃってコラボレーターである私が僭越ながら、その王道の使い方を皆様に伝授していきます。何番煎じかの記事ではありますが、現代の、特にGitHub Actions出現以降の使い方をまとめたいというのが動機です。

git-pr-releaseはGitHubを業務開発で利用している場合に便利なツールで、デフォルトブランチにマージされたpull requestをリリース項目として一覧し、それをpull request化してくれるものです。これにより以下のことが実現できます。

導入

git-pr-releaseはCIで自動実行するのが基本です。今はGitHub Actionsがあるので、なんと、以下の1枚のYAMLをGitHub上のリポジトリに配置するだけです。

# .github/workflows/git-pr-release.yaml
name: git-pr-release
on:
  push:
    branches:
    - develop
jobs:
  git-pr-release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0 # git-pr-release needs the git histories
      - uses: actions/setup-ruby@v1
        with:
          ruby-version: 3.1
      - run: gem install --no-document git-pr-release
      - run: git-pr-release --squashed
        env:
          GIT_PR_RELEASE_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GIT_PR_RELEASE_BRANCH_PRODUCTION: main
          GIT_PR_RELEASE_BRANCH_STAGING: develop
          GIT_PR_RELEASE_LABELS: pr-release
          # GIT_PR_RELEASE_TEMPLATE: .github/git-pr-release.erb
          # TZ: Asia/Tokyo

もちろん環境によって多少は調整が必要です。GIT_PR_RELEASE_BRANCH_STAGING にデフォルト開発ブランチを、GIT_PR_RELEASE_BRANCH_PRODUCTION に本番ブランチ名を指定してください。このブランチについては少し後に説明します。

成功イメージ

トピックブランチがマージされるなどしてデフォルト開発ブランチのコミットが進むと、GitHub Actionsにより以下のようにデフォルトブランチから本番ブランチへのpull requestが自動で作られます。マージされたpull reqeustの一覧がリリース項目として表示されており、開発ブランチのコミットが進む度にリストは自動で更新されます。

折を見てこのpull requestをマージすれば、mainブランチのコミットが進み、それによりdeployされるという寸法です。deployフローは各自のものをお使いください。

前提とするブランチングモデル

git-pr-releaseは以下のようなブランチングモデルを前提としています。ここではmainとdevelopという名前にしていますが、名前は先に述べたように設定可能です。

メインで開発を進めるdevelopブランチと並走するmainブランチがあります。developからmainへのマージによりmainブランチのコミットが進むことがdeploymentのトリガーとなり、deployフローが走り始めることを想定しています。

mainは基本的にはdevelopからのマージでしかコミットは進みませんし、マージされた時点ではdevelopとmainの内容は等しくなります。

このブランチングモデルは、物議を醸しがちなgit flowの簡易版とも言えるもので、割とポピュラーなのではないでしょうか。developが進んだ時点でステージングやQA環境を自動デプロイしている組織も多いでしょう。

他のブランチングモデルとしては、本番ブランチ(ここではmain)を分けて作らずに、デフォルトブランチにマージされた時点で本番deployを走らせるようなフローや、トピックブランチのレビューが通った時点でそのトピックブランチを本番deployし、それが成功したらデフォルトブランチにマージするようなフローもあるでしょう。

そういったスタイルに比べて、このモデルのデリバリー速度は少し落ちるかもしれませんが、ステージング環境が用意できること、リリースのタイミングを制御できること、複数のフィーチャーブランチが近いタイミングでマージされた時にdeployが混雑せずリリースフローを直列化できるところなどにメリットがあるでしょう。

GitHub Actions用のYAMLの解説

冒頭のYAML上のいくつかのポイントについて解説していきます。

shallow cloneとgitの履歴

git-pr-releaseはリリース項目の抽出のためにgit logを使います。なのでshallow cloneで履歴が少ないケースでは上手く動きません。ですので、clone時にshallow cloneを防ぐ設定が必要です。

- uses: actions/checkout@v3
  with:
    fetch-depth: 0 # git-pr-release needs the git histories

実は、shallow clone時に自動でunshallowする挙動 が近々リリースされるので、この設定せずとも動くようになりますが、余計なfetchが減らせるので、この設定を入れるメリットはまだほんの少しだけあります。

squash mergeのための--squashed オプション指定

pull requestのmergeにsquash mergeを使っている場合、--squashed オプションを指定してください。

squashしないプロジェクトではこのオプションを付ける必要はありませんが、付けても多少APIリクエストが増える可能性があるだけなので、常につけて大きな損はないでしょう。

ちなみに、開発ブランチへのコミットがすべてマージコミットである場合には--squashed オプションによる追加のAPIリクエストは一切発生しません。なので、このオプションを標準挙動にしてしまっても良いのではないかとも思っていますが、そのあたりはメンテナ陣と議論が必要ですね。

pull requestへのラベル自動付与

GIT_PR_RELEASE_LABALS 環境変数にpull requestに自動付与するラベルを設定できます。カンマ区切りで複数指定も可能です。これは後でリリースを抽出して振り返りたい場合等に便利です。あまり言及されていることは少ないのですが、設定することをおすすめします。

TZ環境変数によるタイムゾーン設定

標準ではpull requestのタイトルに時刻が表示されますが、GitHub Actions上で実行する場合UTC表示になります。開発チームにわかりやすいタイムゾーンで時刻表示したい場合、TZ環境変数を設定すればお手軽に表示を変更できます。

JSTで表示したい場合GitHub ActionsのYAMLの適切な箇所に以下のようなenv設定書くことになるでしょう。

TZ: Asia/Tokyo

独自テンプレートの活用

pull requestのタイトル及び本文はテンプレートでカスタマイズできます。GIT_PR_RELEASE_TEMPLATE 環境変数でファイルパスを指定します。erb形式のテンプレートで、デフォルトの内容は以下です。一行目がpull requestのタイトルになり二行目以降が本文になります。

Release <%= Time.now %>
<% pull_requests.each do |pr| -%>
<%=  pr.to_checklist_item %>
<% end -%>

最近の自分のユースケースだと、リリース方法、手順、ロールバック方法等を冒頭に載せているのと、mergeされたpull requestをそれぞれチェックリストとして表示する必要性は感じなくなったので、以下のようにしています。

## How to deploy
...

## Items to be Released
<% pull_requests.each do |pr| -%>
- #<%=  pr.number %> <%= pr.mention %>
<% end -%>

テンプレートが意図通り出力されるかどうかの確認には、手元で git-pr-release --dry-run を実行すると良いでしょう。

落ち穂拾い

マージボタンに対するワークフロー

個人的にはあまり厳密にやらないのですが、git-pr-releaseが作成したpull requestのマージを、特定メンバーのレビューや何らかのチェックが通るまではブロックしたいこともあるでしょう。そういった場合はBranch ProtectionやCODEOWNERS機能を活用すると良いです。

リリース障害時の切り戻しはどうするの?

リリースしたコードに不具合があり、手動で切り戻しが必要になった時にどうするか。

ロールバックが作り込まれていればそれを使えばよいですが、個人的には本番ブランチを変更してcommitを進めてリリースしてしまうのがお手軽だと思っています。具体的にはgit-pr-releaseのpull requestをrevertしたりhotfixを入れるなどする。

「本番ブランチのcommitが進めば新しいリリースが作られてdeployが始まる」というメンタルモデルに寄せてしまったほうが覚えることや混乱が少ないというのが理由。障害時に普段使わない不慣れなロールバック作業をすると余計なミスが生まれるリスクも高まります。

もちろん、直前に稼働していたコンテナイメージなどの成果物を再利用できたほうが切り戻しが早いというのはあります。そのためにロールバックを整えるのも手ですが、例えば、成果物を特定するためのidentityにコミットハッシュを使うのではなく、git rev-parse HEAD^{tree} でツリーオブジェクトのハッシュ値を使えば、revert commitでも直前の成果物をつかってくれる仕組みを組むことが可能でしょう。

参考: 同じソースツリーでテストが通っていたらテストをスキップする

さて、本番ブランチにrevertやhotfixを入れると、開発ブランチと本番ブランチの内容に食い違いが出てしまいます。そういった時にどうするか。

本番ブランチと開発ブランチの食い違い問題

結論を書くと、普段とは逆向きに、本番ブランチから開発ブランチに向けてmergeしてしまえば良いです。

git-pr-releaseは前述の通り、本番ブランチと開発ブランチの内容はマージ時点で同一になることを想定しています。そして、通常時は開発ブランチから本番ブランチへのマージでしか本番ブランチのコミットは進まないため、それがほぼ担保されます。

しかし、前項のような緊急オペレーションを行なったなどの理由で乖離が発生する可能性があります。こういったときは、気持ち悪く感じるかもしれませんが、本番ブランチから開発ブランチに、通常とは逆向きのマージをしてしまえば大体問題ないです。ここはちょっと手作業が必要になってしまいますが。

それで問題が起きたことは、これまで10年近く複数プロジェクトに渡って長らく使ってきましたが、特にありません。いざとなったら本番ブランチを消すなりリネームして新たに開発ブランチから作り直しても良いと思います。また、厳密には本番ブランチと開発ブランチに乖離が無いかのチェックを簡単なスクリプトでCIしても良いのかもしれませんが、やったことはなく、困ったこともありません。

設定ファイル .git-pr-release

git-pr-releaseには設定ファイルがあります。リポジトリルートに .git-pr-release というファイル名で配置して、git-config形式で設定を記述します。

ここに書ける設定はすべてここまでで解説した GIT_PR_RELEASE_* 環境変数で代用することができます。特にこの記事ではGitHub ActionsのYAML一枚でわかりやすく完結させるために、このファイルは使っていません。

ただ、手元で git-pr-release を動かす場合、具体的にはテンプレートの動作確認のために --dry-run をつけて動かしたいなどの場合、設定ファイルがあったほうが都合が良いこともあります。

また、リポジトリルートにこのファイルがあることで、git-pr-release を利用していることがわかりやすいという話もあります。ただ、近年はリポジトリルートにファイルが散乱しがちなので、逆に置きたくないという向きもあるでしょう。

カスタムアクション化しないの?

メンテナンス体制との兼ね合いで、メインメンテナ(@onk)的に提供する気は無いようです。

実際、冒頭のYAMLを見てもらえれば分かりますが、やってることは gem install git-pr-release && git-pr-release だけなので、いちいちカスタムアクションをかぶせるのも大袈裟とも言えます。

有志の方でカスタムアクションを作られてる方もいて、僕もそれを利用していたこともありましたが、最新機能を使いたくなったこともあり、最近はそれらを使わない素朴な形になりました。

都度インストールすると、オーバーヘッドやRubyGemsのダウンリスクなどが気になるかもしれませんが、gem install git-pr-release の所要時間は2秒程度ですし、そういった些細な事象を気にして複雑度を上げる必要もないと考えます。

Go化などは考えないのか?

git-pr-release はRuby製のツールですが、オリジナル作者の @motemen や私は最近はGo Hackerでもあります。なので、私も個人的にGoで作り直すことを考えたこともありましたが、必要ないと思うようになりました。

Rubyによる実行オーバーヘッドは些細なものです。それに、言語自体のパフォーマンスよりもリモートリポジトリやAPIへのアクセスが実行時間に対して支配的です。それに、git-pr-release 自体の実行時間は差分の量にもよりますが精々10秒程度です。そこが開発スピードの全体ボトルネックになることは考えづらいでしょう。

erbでテンプレートが書ける点もRuby製ならではの嬉しさと言えます。

git-pr-release は長年使われており、メンテナンスもされ、より安定して使いやすくなっていっています。例えば、squash merge関連の機能が整備されたこと等が、ここ一年の地味に嬉しい機能拡張として挙げられます。そのあたりも後発ツールに比べた強みがあるので、是非ご利用ください。(ポジショントーク)

--no-fetch オプションは現状全く意味がない

余談ですが、 --no-fetch というオプションがあるのですが、これは現状全く動いていません。このオプションを指定してもなんと何も動作が変わらないのです。

これについては、以下のissueで過去の経緯や、今後どうするかを議論しているので興味がある方は御覧ください。

https://github.com/x-motemen/git-pr-release/pull/33