builderscon 2024で登壇

はじめに

2024-08-10にbuildersconというテックカンファレンスがあり,スピーカーとしてこれに参加させていただきました.

builderscon 2024

builderscon 2024 #builderscon - fortee.jp

buildersconは,「「知らなかった、を聞く」をテーマとした技術を愛する全てのギーク達のお祭り」ということで,エンジニアが何かを作りたくなるような新しい知識の共有ができるカンファレンスでした.本記事ではその参加記として,なぜプロポーザルを提出しようと思ったのか,当日どのように過ごしたのか,どのような発表があったのかなどについて述べます.

プロポーザルの提出

CLIジェネレータ「cyamli」を開発した私は,この成果を誰かに知って欲しいと思い,以前からいくつかのLT会に参加してcyamliの様々な側面を発表してきました.

github.com

しかし,短時間のLTでは自分のこだわりや思いを伝えきることができないと感じていました. そんな中で,「LTの内容が興味深かったが,カンファレンス等に応募することは考えていないのか?」というフィードバックをいただき,テーマの合うカンファレンスを探し始めました. そこで,見つけたのが以下のプロポーザル募集ツイートでした.

テーマにも合うと考え,早速プロポーザルを書いて提出しました.

キーワード

CLI, YAML, コード生成, 静的型付け, Go言語

概要

CLI(Command Line Interface)を備えたコンソールアプリケーションを開発する際には、CLIを定義・解釈する仕組みが必要となります。この仕組みを実現するために、私は「cyamli」という名前のCLIジェネレータを開発しました。「cyamli」は、YAMLファイルに記述されたCLIスキーマに基づき、型付けされたCLIを扱うためのコードを生成します。

本発表では、「cyamli」について詳しく紹介したいと考えています。具体的には、まず以下の「cyamli」の特徴について説明します。

  • コマンドライン引数の定義・解釈:CLIとして、サブコマンド、オプション引数、位置引数で構成されるコマンドライン引数を定義・解釈することができます。
  • 型付けされたCLI:生成されるコードは、型付けされたCLIを適切に扱えるため、静的チェックやコード補完といった機能を活用できます。
  • 情報源の集約:CLIスキーマの情報源をYAMLファイルに集約して管理できるため、コードの一貫性を維持しやすくなります。
  • 様々な出力形式:現時点で、GoとPython3をサポートしており、テキストおよびMarkdown形式のヘルプメッセージも出力できます。

さらに、以下の内容についてイメージしてもらえるように、実際にデモンストレーションを実施して、例を示しながら解説したいと考えています。

  • CLIスキーマをどのように定義するのか
  • どのようなコードが生成されるのか
  • 生成されたコードをどのように利用するのか

対象者

以下のような方々に興味を持っていただけると思います。

  • Go言語を使う方
  • コンソールアプリケーションを開発する方
  • スキーマ駆動開発に興味のある方

リファレンス

https://github.com/Jumpaku/cyamli

CLIジェネレータ「cyamli」によるコンソールアプリのスキーマ駆動開発 by Jumpaku | トーク | builderscon 2024 #builderscon - fortee.jp

プロポーザルを書く上で心がけたのは以下の点です.

  • テーマに沿っていること
  • 自分のこだわり・主張を示すこと
  • 発表内容をできるだけ詳細に示すこと
  • 幅広いエンジニアに発表内容を想像してもらえるようなキーワードを含めること

プロポーザルの採択

プロポーザル募集締切から期間をおいて,採択を知らせるメールが届きました. 何度も読み返して採択のお知らせであることを確かめると,嬉しさに任せてすぐに受諾の手続きを進めました.

全プロポーザルが46個くらいあったと思いますが,その中で採択されたプロポーザルの個数を数えてみると6個しかなく,採択率が2割未満と低いものであると知りました. 自分に大役が務まるのかという不安とレビューを突破したという自信がないまぜとなって気合が入りました.

発表準備

発表時間を40分もいただけるということで,普段のLTで触れることのできない深いこだわりや充実したデモを含めることができると考えました.そこでこれまで発表したLTを元にしつつ,cyamliの設計方針,実装の詳細,こだわった点をふんだんに盛り込み,スライド枚数と表現を調整しました.

当日

行き

当日は,早朝に起床し発表スライドを仕上げた後,発表が40分に収まるかどうかを通して確認しました. 会場は埼玉県にある埼玉会館というところで,JR浦和駅から徒歩10分程度の場所にありました. JR浦和駅は,JR渋谷駅から湘南新宿ラインで30分程度で行くことができ,意外と行きやすいと思いました. 浦和駅に着くと,電車酔いと空腹で具合が悪くなっていたのでおにぎりと飲み物を買って,できるだけ涼しい日陰を通りながら埼玉会館へ向かいました. 埼玉会館の入口では,会場となっている部屋までの案内をしていただき,部屋の前で受付をしてTシャツをいただきました. 空いてる席に座ってすぐにおにぎりを食べ,Tシャツを着て,デモの準備と動作確認を進めながら,午前の部の開始を待ちました.

午前の部

「誰が作成しても1つの構造になるモデリング作成技術、Theory of Models⁠ に夢を見る」by mokuo

fortee.jp

午前の部の最初の発表は,仕様に対して定型操作により個人の主観やスキルに依らずにモデリングするための設計手法の紹介でした. 具体的なケースを例として説明された定型操作は,設計において自分が経験と勘に頼っていた点や見落としがちな点をカバーしながら,妥当なモデルを導くことができていてとても興味を持ちました. 一方で気になったのは,定型操作が実際のところどの程度妥当なモデルを導くことができるのか,特に仕様変更に対してどの程度ロバストなモデルが導くことができるのかという点で,実際,そのような質問もありました. しかし少なくとも,どのようにモデリングすれば良いかわからない複雑な仕様に直面した時や,考えたモデルが妥当かどうか判断するのが難しい時などにはとても強力なツールとして使うことができると思いました.

「法律に準拠した本人確認システムを0から作った話 〜家計簿プリカB/43でのeKYC開発実例〜」by 三谷 昌平

fortee.jp

次の発表は,本人確認システムを要件策定から運用体制まで構築した話の紹介でした. ここでは資金移動業に関する法律に基づいて本人確認機能が備えるべき要件を策定し,これを実現するための要素技術を選定し,構築したシステムをどのような体制で運用してきたのかについて,詳細に踏み込んだ具体的な話を聞くことができました. もし自分が本人確認システムを構築することになった時に何を調べ何を実装する必要があるのかイメージできるようになった気がします. あとは,自分がシステムを構築しきって運用を支える自信さえ持てれば,自分でもできるかもしれないと思わせる説得力があり,とても興味深く聞くことができました.

お昼

お昼は近くの狼煙という名のつけ麺屋へ行きました.

tabelog.com

注文したのは,限定メニューの坦々まぜそばです.

タレの絡まった麺の上の刻み玉ねぎ,メンマ,チャーシュー,ひき肉,ガーリック,海苔,卵黄,チンゲン菜などが乗っている
狼煙の坦々まぜそば

とても美味しくいただきました.つけ麺を注文しているお客さんも多かったので,次機会があればそちらも食べてみたいと思いました.

お昼ご飯を食べたあとは次の発表開始まで時間があったため,散歩をすることにしました.埼玉会館の周りには埼玉県庁や埼玉地方裁判所などの大きな建物がありとても立派で見応えがありました. また埼玉会館自体もいくつかのパーツからできていて内部も入り組んでいて探検し甲斐がありました.

午後の部

「React Server Component の疑問を解き明かす」by mizdra

fortee.jp

React Server Componentの導入により,サーバーで実行されるコンポーネント(Server Component)とクライアントで実行されるコンポーネント(Client Component)を同居させながらUIを構築することができるようになり,パフォーマンスや管理性の改善が可能になるというような話だと理解しました. この仕組みがないとパフォーマンスの改善に限界があるという点についてはよく理解できるのですが,管理性が改善されるかどうかに関しては理解が追いつきませんでした. これはJSXのように文書構造とロジックをまとめてコンポーネントにするという考え方やServer ComponentをClient Componentを同居できるようにするという考え方が,これまでのUIの実装におけるコード分割の考え方(CSS,HTML,JavaScriptに分ける,サーバー/クライアントで分ける,モデル,ビュー,コントローラに分けるなど)に関する自分の理解と整合しているように見えなかったためだと思います.

この発表は,自分に対してとてもクリティカルで,自分のUI実装に対する考え方を見直すきっかけとしなければいけないと思いました.

「すこやかなサービス運営のための PWG (Performance Working Group)」by Takafumi ONAKA

fortee.jp

こちらは,元々予定されていた発表がキャンセルとなったことによる,代打での発表でした. 関係者が集まってダッシュボードを眺める「PWG (Performance Working Group)」という会を実施しているという話でした. 自分の開発・運用経験につながるイメージが掴めず,実感をもって理解できなかったことが少し悔しいと思いました. これは,私の関わるプロダクトや組織より,規模が大きかったり,難易度が高かったり,文化が異なったりすることが理由かもしれないと思います. もしくは,集中力が弱まっていただけかもしれません.

「ホー○ページビルダー 2024」by Masayuki Matsuki (Songmu)

fortee.jp

こちらも代打の発表で,個人ブログの運用に関する様々な話題や考えが紹介されました. 特に印象に残った話題が,自分の死後にデジタルの成果物はどうなるのかというものでした. どうなっても良いという場合は簡単ですが,消したいまたは残したいという場合にどのような手段があるかということは考えたことがありませんでした. 自分は,自分のデジタルの成果物をどうしたいのか,少し考えてみようと思います.

CLIジェネレータ「cyamli」によるコンソールアプリのスキーマ駆動開発」by Jumpaku

fortee.jp

こちらは,私の発表となります.

自作OSS「cyamli」について紹介しました.

発表直前には,これまでの発表が全て時間通りでバッファが全く消費されていないという話が聞こえてきたため,自分も時間通りに終わらせないといけないというプレッシャーを感じる一方で,ここで時間通りに発表を終えることで自分も格好良くキメるチャンスだと考えました.

発表では,型付けされたCLIを適切に扱うための自作ツールを開発する上でのこだわりについて余す所なく示しました. また,型付けによる恩恵をより実感してもらうために,統合開発環境でコード補完を効かせながらデモを実施しました. このデモは「cyamli」の有用性を示すためにとても有効だったと感じています. デモにおいて,両手でキーボードを操作しようとするとマイクを持てないことに気がついたスタッフの方がマイクを持ってくださって,とても助かりました.

発表資料を以下に示します.

drive.google.com

発表後,以下の質問を受けました.

  1. サポート言語を追加するためには,どのような作業が必要になるか?
  2. グローバルなオプション引数などの追加仕様を提案する余地はあるか?

1.に対する回答として,コード生成のテンプレートとそれに流し込むデータを実装しcyamliのサブコマンドの追加することが必要で,サポート済みの言語用の実装をコピペして変更することで実現できるというような内容を返したつもりです. また,2.に対する回答として,公開済みの仕様は完成されたものとは考えておらず,仕様追加の提案を受け入れる余地もあるが,議論も必要だと思うというような内容を返したつもりです.

「1000 行で実現する Linux on Browser」by bokuweb

fortee.jp

最後の発表は,CPUを中心とした計算機のエミュレータをブラウザ上に実装し,そこでLinuxを起動するという内容でした. CPUの仕様やバスによるデバイス間の連携など今まで潜ったことのない低レイヤーの話でしたが,Rustで書かれたエミュレータソースコードの要点を掻い摘みながら示しつつ,それでいて全体のつながりが分かるように説明されたことで,とても理解しやすくて面白いと感じました. 計算機のエミュレータを実装するというのがどういう作業なのかイメージできて,自分の世界が広がった気がしました.

懇親会

一通りの発表が終わり集合写真の撮影が済んだあと,懇親会までの間に休憩時間がありました. 懇親会で実施されるLTが募集されていて気になるものにシールを貼るように周知されていたため,全ての候補にシールを貼ったところ,直後に一人一枚までという話が聞こえてきてとても申し訳なくなりました.

懇親会では,他のグループに入っていくのが苦手なためか少しおどおどしてしまいましたが,近くにいた方と話をすることもできました. スピーカーである三谷 昌平さん,mokuoさんには近くでお話しする機会があったため,それぞれ発表を聞いた感想として上で示したような内容を伝えました. また,私の発表テーマのcyamliについて近くにいた聴講者と話したりもしました. 他にも,私の所へ飛び込んできて話をしてくれる方もいました. 懇親会も楽しく過ごすことができて良かったです.

帰り

20時半ごろに,懇親会が終わるとJRで帰宅しました. 電車内では,Twitterで #bulderscon のついたTweetを見返しながら,自分の発表の振り返りをしました.

「cyamli 自体も cyamli で作られているのだろうか」という質問があり,その通りである旨をリプライしました.

また,「usageの生成とかしてくれたら便利そう」というコメントに対して,実装済みである旨をリプライしました.

これについてはデモで示しておけば良かったと思いました.

そして,「情報源の集約というのは CLI ツールのインターフェイスの定義を 1 ファイルにまとめることを指してるのかな?」という質問がありました.

これに関しては,何と答えるべきか分からずリプライできませんでした. インターフェイスの定義について,1ファイルにまとめることというよりは,コード内に散乱させないことと過不足なく整理することの両方を指すという方が自分の思いに近い気がします. 一貫性を維持しやすくしたり保守しやすくするためには,これらが必要な気がします. もしかしたら,情報源の集約ではなく,SSOT(Single Source of Truth)な設計の実現と表現した方が適切だったかもしれません.

この日は21:00からAtCoderのコンテストがありましたが,疲労のため参加を見送りました. 疲れていても出るべきだったと少し後悔しています.

AtCoder Beginner Contest 366 - AtCoder

まとめ

builderscon への参加や,テックカンファレンスでのプロポーザル提出とLT以外の登壇は,初めてでした. 聴講においては,どの発表も歯ごたえがあり,面白いものでした. 発表においては,40分という時間の中で,自作ツールのこだわりを詳細に話すことができ,充実したデモを示すこともできたと思います. 懇親会でも,人見知りな割に,近くにいた方といろいろ話すことができて楽しむことができました.

浦和駅周辺においても,埼玉会館の他に美味しいつけ麺屋,埼玉県庁周辺などを巡ることができました.

ここで得た感覚は,仕事でも趣味でも開発の中で思い返すことがあると思います. また,cyamli を含めた自分の開発のモチベーションも高まりました.

展望として,今後機会があれば,懇親会の2次会も行ってみたいと思いました.

謝辞

buildersconの運営スタッフ,スピーカーの方,私の発表を聴講していただいた方,懇親会で話をした方に感謝します.

cyamli: YAMLからCLIを自動生成するツール

概要

本記事は,OSS Advent Calendar 2023の12月14日の記事です.

qiita.com

本記事では,自作OSSとして,YAMLからCLIを自動生成するツール「cyamli」を試作しましたので,これについて紹介します.

※本記事はバージョンv1.0.0より前のcyamliについて記述しており,バージョンv1.0.0以降のcyamliと互換性のないコードもありますが,ツールのコンセプトは同じです.(追記 2024-06-17)

背景

最近,Goでプログラムを書いています.その中で,作業の自動化を目的としてコンソールアプリケーションを作成することがよくあります. コンソールアプリケーションは,CLI(Command Line Interface)を備えたプログラムで,サブコマンド,オプション引数,位置引数を含むコマンドライン引数を取り扱うことが必要となります.

コマンドライン引数を取り扱うためには,コマンドライン引数を定義・解釈する仕組みとしてが必要となりますが,Goの既存のライブラリの中で以下の条件を満たすAPI(本記事では,APIApplication Programming Interface)といえばWeb APIではなく,ライブラリ等のプログラミング言語のためのインターフェースのことを指します.)を見つけることができませんでした.

  1. コマンドライン引数として,サブコマンド,オプション引数,位置引数を定義・解釈することができる.
  2. 型付けされたAPIとして提供される.
  3. SSOT(Single Source of Truth)となる.

例えば,Goの標準ライブラリにあるos.Argsは,最も原始的なAPIで,コマンドライン引数をstringを要素とするスライスとして表現しますが,1も2も満たしません. pkg.go.dev

Goの標準ライブラリにあるflagパッケージは,型付けされたオプション引数を扱うことができますが,サブコマンドや位置引数を定義する機能は持ちません.また,オプション引数の定義は,var helpFlag = flag.Bool("help", true, "show help")のように行うのですが,変数名helpFlagとオプション引数名"help"のように情報が重複してしまうことがあり,3を完全に満たしているとは言えません. pkg.go.dev

外部ライブラリであるcobraは,サブコマンド,オプション引数,位置引数を定義・解釈することができますが,位置引数の型を指定することができないため,2を完全に満たしているとは言えません.また,flagパッケージと同様にソースコード内で情報が重複してしまうことがあり,3を完全に満たしているとは言えません. github.com

別の外部ライブラリであるdocoptは,独自のフォーマットに沿って記述されるヘルプテキストによって,サブコマンド,オプション引数,位置引数を含む複雑なコマンドライン引数を定義することができ,これを元にコマンドライン引数を解釈することができますが,型を指定することができません. github.com

YAMLからCLIを自動生成するツール「cyamli」

上で示した条件1は,自分がコマンドライン引数を扱うコンソールアプリケーションを開発する上で,必要だと感じた最低限の機能です. 条件2は,エディタや統合開発環境の支援を享受したり,コンソールアプリケーションのビルド時に網羅的な型チェックを実施するために必要ものです. 条件3は,プログラムを管理する上で,一貫性を保ちやすくするために必要なものです.

コマンドライン引数を定義・解釈する仕組みとして,これらの条件をみたすものを実現するために「cyamli」というツールを開発しました. GitHub上で公開しています. github.com

「cyamli」の仕組みと特徴

「cyamli」は,以下の図に示すような仕組みで動作します.

cyamliは,CLIの定義を記述したYAMLファイルを読み込んで,CLIを解釈するAPIを書き出す.内部では,型の構築とコード生成が行われる.
「cyamli」の仕組み

「cyamli」は以下の特徴を持ちます.

  • サブコマンド,オプション引数,位置引数をサポートします.
  • CLI定義の情報源が1つのYAMLに集約されるため,SSOTが実現できます.
  • コンソールアプリケーションをビルドする前にCLIの型が決定されるため,型付けされたAPIを提供することができます.

以下は,前節で挙げたライブラリと「cyamli」を比較する表です.

「cyamli」は「機能」「型付け」「SSOT」を全て満たす.
前節のライブラリと「cyamli」の比較

「cyamli」の使い方と使用例

「cyamli」の使い方は,次の通りです.

  1. CLIYAMLで定義する.
  2. CLIを解釈するAPIを自動生成する.
  3. 自動生成されたAPIに関数を割り当てる.

使用例を以下に示します.

1. CLIYAMLで定義

ここでは例として,データベースからテーブルの情報を取得するコンソールアプリケーションの作成を想定して,以下のようにCLIを定義します.

# cli.yaml
name: demo
description: demo app to get table information from databases
subcommands:
  list:
    description: list tables
    options: 
      -config:
        description: path to config file
        short: -c
  describe:
    description: show information of tables
    options: 
      -config:
        description: path to config file
        short: -c
      -format:
        short: -f
        description: "output format: json or sql"
        default: json
      -unique:
        description: includes unique constraint information
        type: boolean
      -foreign-key:
        description: includes foreign key constraint information
        type: boolean
      -check:
        description: includes check constraint information
        type: boolean
    arguments:
      - name: tables
        variadic: true
        description: names of tables to be described

このYAMLファイルでは,コンソールアプリケーションについて以下の内容が定義されています.

  • 名前がdemoである.
  • サブコマンドとしてlistdescribeを持つ.

また,listサブコマンドについては以下の内容が定義されています.

  • 以下のオプション引数を持つ.
    • -config:文字列型の値を取り,コンフィグファイルのパスを指定する.短縮バージョンとして-cがある.

describeサブコマンドについては以下の内容が定義されています.

  • 以下のオプション引数を持つ.
    • -config:コンフィグファイルのパスを指定する.短縮バージョンとして-cがある.
    • -format:出力のフォーマットを指定する.短縮バージョンとして-fがある.デフォルト値は"json"である.
    • -uniqueブーリアン型の値を取り,ユニーク制約を含めるかどうかを指定する.
    • -checkブーリアン型の値を取り,チェック制約を含めるかどうかを指定する.
    • -foreign-keyブーリアン型の値を取り,外部キー制約を含めるかどうかを指定する.
  • 以下の位置引数を持つ.
    • tables:取得対象のテーブルを0個以上指定する.

2. CLIを解釈するAPIを自動生成

「cyamli」を実行してAPIを生成します. 「cyamli」の実行は以下のように行うことができます.

# cyamli のインストール
go install "github.com/Jumpaku/cyamli/cmd/cyamli@latest"

# cyamliの実行
# cli.yamlを入力し,cli.gen.goに出力する.
cyamli golang -schema-path=cli.yaml -out-path=cli.gen.go

単に以下のように実行することもできます.

go run "github.com/Jumpaku/cyamli/cmd/cyamli@latest" golang -schema-path=cli.yaml -out-path=cli.gen.go

これにより,以下のようなAPIが生成されます(一部省略).

// Code generated by cyamli v0.0.11, DO NOT EDIT.
package main

// ...

type Func[Input any] func(subcommand []string, input Input, inputErr error) (err error)

type CLI struct {
    List     CLI_List
    Describe CLI_Describe
    FUNC     Func[CLI_Input]
}
type CLI_Input struct {
}

type CLI_List struct {
    FUNC Func[CLI_List_Input]
}
type CLI_List_Input struct {
    Opt_Config string
}

type CLI_Describe struct {
    FUNC Func[CLI_Describe_Input]
}
type CLI_Describe_Input struct {
    Opt_Check      bool
    Opt_Config     string
    Opt_ForeignKey bool
    Opt_Format     string
    Opt_Unique     bool
    Arg_Tables     []string
}

// ...

func NewCLI() CLI {
    return CLI{}
}


func Run(cli CLI, args []string) error {
    // ...
}

このように,cyamliが生成するコードには以下のAPIが含まれます.

  • CLI:ルートコマンドを表現する構造体
  • CLI_Input:ルートコマンドに渡すコマンドライン引数を表現する構造体
  • CLI_<サブコマンド>:サブコマンドを表現する構造体
  • CLI_<サブコマンド>_Input:サブコマンドに渡すコマンドライン引数を表現する構造体
  • Run:エントリーポイントとなる関数

3. 自動生成されたAPIに関数を割り当て

CLI構造体とCLI_<サブコマンド>構造体は,FUNCフィールドを持ちます.FUNCフィールドは,コマンドライン引数を表現する構造体を受け取ることが可能な関数の型を持っており,コマンドが実行するべき処理を設定することができます.

以下は,コマンドが実行するべき処理を設定したmain.goの例です.

// main.go
package main

import (
    _ "embed"
    "fmt"
    "os"
)

func main() {
    // CLIオブジェクトを生成
    cli := NewCLI()

    // ルートコマンドの処理を設定
    cli.FUNC = func(subcommand []string, input CLI_Input, inputErr error) (err error) {
        fmt.Printf("%#v\n", input)
        fmt.Println(cli.DESC_Detail())
        return inputErr
    }
    // listサブコマンドの処理を設定
    cli.List.FUNC = func(subcommand []string, input CLI_List_Input, inputErr error) (err error) {
        fmt.Printf("%#v\n", input)
        fmt.Println(cli.List.DESC_Detail())
        return inputErr
    }
    // describeサブコマンドの処理を設定
    cli.Describe.FUNC = func(subcommand []string, input CLI_Describe_Input, inputErr error) (err error) {
        fmt.Printf("%#v\n", input)
        fmt.Println(cli.Describe.DESC_Detail())
        return inputErr
    }

    // コマンドライン引数の解釈と対応する処理の呼び出しを実行
    if err := Run(cli, os.Args); err != nil {
        panic(err)
    }
}

以下は,ルートコマンドの実行例です.

go build -o demo . && ./demo

main.CLI_Input{}
demo:
demo app to get table information from databases

Usage:
    $ demo


Subcommands:
    describe:
        show information of tables

    list:
        list tables

自動生成されたヘルプテキストが利用できることがわかります.

以下は,listサブコマンドの実行例です.

go build -o demo . && ./demo list -c=./demo.config

main.CLI_List_Input{Opt_Config:"./demo.config"}
list tables

Usage:
    $ <program> list [<option>]...


Options:
    -config=<string>, -c=<string>  (default=""):
        path to config file

短縮バージョンのオプション引数-cで指定した文字列"./demo.config"を,オプション引数-configの値として渡すことができたことがわかります.

以下は,describeサブコマンドの実行例です.

go build -o demo . && ./demo describe -check Table1 Table2 Table3

main.CLI_Describe_Input{Opt_Check:true, Opt_Config:"", Opt_ForeignKey:false, Opt_Format:"json", Opt_Unique:false, Arg_Tables:[]string{"Table1", "Table2", "Table3"}}
show information of tables

Usage:
    $ <program> describe [<option>|<argument>]... [-- [<argument>]...]


Options:
    -check[=<boolean>]  (default=false):
        includes check constraint information

    -config=<string>, -c=<string>  (default=""):
        path to config file

    -foreign-key[=<boolean>]  (default=false):
        includes foreign key constraint information

    -format=<string>, -f=<string>  (default="json"):
        output format: json or sql

    -unique[=<boolean>]  (default=false):
        includes unique constraint information


Arguments:
    [0:] [<tables:string>]...
        names of tables to be described

オプション引数-formatにデフォルト値である"json"が渡されていることがわかります. また,オプション引数-checkにより,ブーリアン型の値trueが渡されていることがわかります. さらに,位置引数を可変長とすることも可能であることがわかります.

まとめと展望

以下に本記事のまとめを示します.

  • コンソールアプリケーションを作成する際には,CLI(サブコマンド,オプション引数,位置引数を含むコマンドライン引数)を定義・解釈する仕組みが必要となります.
  • YAMLからCLIを自動生成するというアプローチにより,この仕組みを実現する「cyamli」を開発し,公開しました.
  • 「cyamli」を紹介し,型付けされたAPIを提供できること,SSOTを実現できることを示しました.

以下に展望を示します.

  • 「cyamli」は,その内部のコード生成処理を置き換えることで,様々なプログラミング言語をサポートすることが可能なため,今後はサポートするプログラミング言をGo以外にも広げていきたいと考えています.
  • 本記事を読んでくださった方には,ぜひ「cyamli」を使ってみてもらいたいと思っています.

追いコンを開催した

はじめに

本記事は,競技プログラミング Advent Calendar 2022の12月23日の記事です. qiita.com


追いコンとは,追い出しコンテストの省略形で,組織から抜ける者が組織に残る者に対して開催するコンテストを指します. 例えば,大学のサークルなどでは,卒業生がお世話になった下級生に対して感謝の思いを込めて競技プログラミングコンテストを開催することがよくあります. 実際私も,先輩が自身の卒業のタイミングで開催した競技プログラミングコンテストに参加させていただいたことがあります. chut1130m.hatenablog.com

そして,2022年の9月30日に,私も無事に半年留年して博士課程を修了したため,それまでお世話になったプログラミングサークルの後輩に感謝の思いを込めて追いコンを開催しました. 本記事では,この追いコンについて述べます.

追いコンの概要

追いコンの概要は以下の通りです.

  • 参加者:私の所属するプログラミングサークルの中で,お世話になった方々(コンテスタント7人,協力者1人)
  • 時間:1時間30分
  • 問題数:30問
  • 難易度:AtCoder Beginner Contestの100点から500点までの間程度
  • 日時:2022年12月11日の18:00から19:30まで
  • 会場:Discord
  • プラットフォーム:QingdaoU/OnlineJudge github.com

準備

以下の準備を行いました.

  1. 参加者の確保と日程調整
  2. プラットフォームの準備
  3. 問題の作成

参加者の確保と日程調整

まず,開催に必要な最低参加者数を,4人と定めた上で,最も参加してくれそうな数人に声をかけ,参加を確約してもらいました. 彼らをコア参加者と呼ぶこととします. コア参加者を確保できたことにより,最低参加者数が達成できました. また,協力者も1人確保しました.

次に,コア参加者が参加可能な日程を複数確保し,これを開催候補日程としました.

その後,顔を思い出せるサークルメンバーにDiscordでDMを送って追いコンに誘い,参加したい場合は開催候補日程の中から参加可能な日程を教えてもらい日程調整を行いました. 具体的には,調整さんというサービスを利用し,開催候補日程の中で参加可能な人の最も多い日程のうち最も近い日程に決定しました. chouseisan.com

プラットフォームの準備

追いコンのプラットフォームとして,QingdaoU/OnlineJudgeというオンラインジャッジシステムを使用することとしました. このシステムはOSSのオンラインジャッジシステムで,コンテストサイトとジャッジサーバーを含むdocker-compose.ymlを起動するだけで準備が整います. https://github.com/QingdaoU/OnlineJudgeDeploy/blob/2.0/README.en.md

実際の作業として以下の作業を行いました.

  1. 私が契約しているVPS内でオンラインジャッジシステムを起動する.
  2. 私が持っているドメインにコンテストサイト用のサブドメインを設定する.
  3. VPS内のリバースプロキシにコンテストサイト用の設定を加える.

ここで1つ躓いたことがありました.ローカル環境でオンラインジャッジシステムの起動を確認しようとして失敗しました.原因は定かではありませんが,ローカル環境がApple M1チップ搭載のMacBook Airだったからかもしれません.

問題の作成

準備の中で最も時間がかかったのが問題の作成でした.問題の作成では1人の協力者と協力して,問題文の作成,テストケースの作成,解答の作成,問題のチェックを行いました. 問題の構成は以下の通りとなりました.

Number Title Score
1 Hello 20
2 Naming rules 40
3 Go 20
4 Linear Transformation 30
5 Numbers 20
6 Count vowels 20
7 max - min 20
8 Compare 20
9 Memoized Recursion 50
10 GCD Rectangle 400
11 Shepherd 300
12 Segment Eraser 500
13 String Power 20
14 Sum of numbers 20
15 Tri Tri Tri 400
16 Java 20
17 Parallelogram 40
18 Many Swaps 20
19 Calc 30
20 Transaction 40
21 Recursive Parity 50
22 Quadratic Equation 50
23 MAX LCM 300
24 ASC 20
25 Sort Unique 20
26 Compare2 50
27 Compare3 40
28 Switch Case 20
29 Sorting integers as strings 20
30 Linear Equation 20

Scoreは,難易度の高い問題ほど高くなるように設定しました. AtCoder Beginner Contestで100点以上300点未満くらいの点数になりそうな難易度の問題は,大量に用意した上でScoreが100点未満となるように調整しました. AtCoder Beginner Contestで300点以上の点数になりそうな難易度の問題は,その点数をScoreとしました. このような構成としたのは,参加者のレベルにばらつきがあったとしても,難し過ぎて手が止まってしまったり,易し過ぎて時間が余ってしまったりすることがないようにするためでした.

問題の作成で最も大変だったことは,厳密な問題文を記述することでした. また,注意が必要だったこととして,追いコンで利用したオンラインジャッジシステムは,AtCoderと異なり,テストケース毎にACとなればScoreが加算されるということが挙げられます.

問題のチェックは,問題文に不備が無いか,制約は適切か,テストケースは正しいか,難易度に対するScoreは適切か,といった点について協力者と互いにチェックすることができました.

開催

追いコン当日のスケジュールは以下のようになりました.

17:30に集合して最初に,オンラインジャッジシステムのアカウントを作成してもらいました. アカウント作成の間に,私から卒業の挨拶として,同級生がおらず寂しかった博士課程の私に,構ってもらったことへの感謝を述べました. また,アルバム鑑賞ということで,私のツイートを画面共有して遡りながら思い出を懐かしみました.

18:00になるとコンテストがスタートしました. 私は協力者と一緒に順位表を見てお喋りをしたり,質問への対応をしていました.

19:00を過ぎた頃,コンテスタントからの質問により異変に気がつきました. コンテスト終了時刻を19:30と設定していたのに,コンテストが終了してしまったのです. 原因はVPSの時刻が10分以上進んでいたことだったため,ずれた時間の分だけコンテスト終了時刻を遅く設定し直しました.

19:30にコンテストが終了した後は,AmongUsをして遊びました.

21:00からはAtCoder Beginner Contest 277に参加しました. 終了後はAtCoder反省会の中で,AtCoder Beginner Contest 277や追いコンの問題について振り返りました.

追いコンの結果と振り返り

追いコンの結果は以下の通りでした.

参加者の得点と順位

以下に追いコンの振り返りとして,良かった点,悪かった点,今後に向けてするべきことを示します.

良かった点

  • 参加者や協力者を集めることができた.
  • 自分の作成した問題を解いてもらえるのがとても嬉しかった.
  • オンラインジャッジシステムの準備と操作の仕方を習得できた.
  • 全員1問以上ACすることができた.
  • 全問ACしてしまう参加者が出なかった.
  • 得点のグラデーションが緩やかで,問題の構成や配点が適切だった.
  • 協力者と互いにチェックできたため,問題に大きな不備が無かった.
  • 当日,協力者と順位表を見ながらおしゃべりを楽しめた.
  • AmongUsも楽しかった.
  • AtCoder Beginner Contest 277の直前での開催だったため,ウォーミングアップにもなった.

悪かった点

  • オンラインジャッジシステムを動作させているVPSの時刻が狂っていて,終了時刻前に終了してしまった(終了時刻を設定し直すことで復帰するができた.).
  • Discordで質問を受け付けたが,質問内容や質問への回答が参加者全体に共有されてしまうことがあった.

今後に向けてするべきこと

  • VPSの時刻合わせをする.
  • 質問方法について検討する.
  • 今回は,追いコンということでサークルでお世話になった後輩に参加してもらったが,次は,他の知り合いや会社の同僚にも参加してもらえるようなコンテストを企画したい.

まとめ

  • 博士課程を修了したため,それまでお世話になったプログラミングサークルの後輩に感謝の思いを込めて追いコンを開催しました.
  • QingdaoU/OnlineJudgeというオンラインジャッジシステムを利用しました.
  • 参加者全員に楽しんでもらえるように,問題の構成と配点を工夫しました.
  • 問題の作成はとても時間がかかりましたが,みんなに解いてもらえてとても嬉しかったです.

謝辞

追いコンに参加してもらった方々に感謝します.

APG4bとSiv3Dを利用して勉強会を開催した

はじめに

今年度,サークル内で,APG4bとSiv3Dを利用して2つのプログラミング勉強会をオンラインで開催しました. APG4bは,AtCoderC++学習用の資料です.

atcoder.jp

Siv3Dは,可視化やインタラクションに関わるプログラムを作成するためのフレームワークです.

siv3d.github.io

本記事では,開催したプログラミング勉強会について,それぞれその目的や内容などについてまとめます. その上で,APG4bとSiv3Dを利用して良かったと感じたことや勉強会の反省などについてそれぞれまとめます.

本記事はSiv3D Advent Calendar 2021の12月19日の記事です.

qiita.com

APG4bを利用したプログラミング勉強会

APG4bを利用して以下のようにプログラミング勉強会を開催しました.

目的

この勉強会の目的は以下の3つでした.

  • 参加者にプログラミングの楽しさを知ってもらうこと
  • 参加者にプログラミングに興味を持つ人と交流してもらうこと
  • 参加者にプログラミングの基礎知識を身につけてもらうこと

期間

2021年5月12日から2021年7月2日まで間,毎週1回1.5時間程度の勉強会を開催しました.

対象者

この勉強会の対象者は,私の所属サークル内で,初心者を含む全ての部員でした.

講師陣

この勉強会には,私を含めて8名が講師として参加しました. それぞれの講師は,最大で2回の勉強会を担当し,司会と解説を行いました.

内容

内容
1回目 1.00.はじめに,1.01.出力とコメント,1.02.プログラムの書き方とエラー,1.03.四則演算と優先順位
2回目 1.04.変数と型,1.05.プログラムの実行順序と入力
3回目 1.06.if文・比較演算子・論理演算子,1.07.条件式の結果とbool型,1.08.変数のスコープ
4回目 1.09.複合代入演算子,1.10.while文,1.11.for文・break・continue
5回目 1.12.文字列と文字,演習
6回目 1.13.配列,演習
7回目 1.14.STLの関数,1.15.関数
8回目 2.01.ループの書き方と範囲for文,2.02.多重ループ,2.03.多次元配列
9回目 2.05.再帰関数
10回目 3.04.構造体
11回目 3.05.ビット演算

APG4bを利用することにした理由

資料がそれ自体で完結している

自分で資料を探して調べながらプログラミングを勉強することは,プログラミングに初めて触れる初心者の多くにとっては難しいことだと考えています. 実際,私も最初は一通りのC言語を先輩から教えてもらうことでプログラミングを勉強しました.

APG4bは,資料がそれ自体で完結しており,後ろで述べるようなプログラミングの基本知識がこの資料だけで学べるようになっていると思いました. ここには,演習問題も含まれており,このおかげで,講師達がオリジナルの資料や演習問題を用意する手間を省くことができると考えました.

また,資料がそれ自体で完結していることにより,参加者が講師の解説を聞かないで自分のペースで進めることも可能となっていると思いました.

プログラミングの基本知識が網羅されている

私は,型,配列,構造体,変数,四則演算,繰り返し,条件分岐,関数のように多くのプログラミング言語で共通して存在するような概念をプログラミングの基本知識だと考えています. APG4bはこれらの基本知識を網羅しており,プログラミングに初めて触れる人が,自分で調べて勉強できるようになるために必要なキーワードを把握できるものとなっていると思いました.

Web上に実行環境が用意されている

プログラミングに初めて触れる人にとって実行環境を構築することは簡単なことではなく,ここで挫折してしまうのは悲しいと思います. APG4bには,コードを書いてプログラムを実行できるコードテスト機能が備わっており,環境構築に手間をかけなくてもプログラミングの勉強を始められるようになっていると考えました.

ここで勉強したC++をSiv3Dによる開発に応用できる

APG4bで学べるC++は,Siv3Dを使った開発にそのまま生かすことができ,相性が良いと考えました.

その他工夫したこと

この勉強会では,APG4bを利用して準備の手間を省いたことの他にも,交流の時間を設けるという工夫をしました. 交流の時間とは,勉強会の後に,AmongUs,麻雀といったゲームで遊んだり勉強会の復習をしたりする時間です. これを設けることによって部員同士が仲良くなれば,部員の幽霊化を抑えることができると考えました.

振り返り

APG4bの資料をそのまま使ったため,準備に手間をかけずにプログラミング勉強会を開催できたと思います. また,元の資料がそれ自体で完結しているため,講師の力量や相性によらず,最低限の質は保たれていたと思います.

交流の時間を設けたことで,部員の幽霊化を抑えることができたと考えています. 昨年度,似たような形式で勉強会を開催したときは,最初10人程度いた参加者が最後には2人まで減ってしまいました. 交流の時間を設けるというアイデアは,ここでのの反省の結果として生まれたものでした. 実際,今年度の参加者は,最初20人くらいで最後は15人くらいだったと記憶していますが,昨年度ほど大きく参加者が減ることは無かったのは,交流の時間を設けた効果が少なからずあっただろうと考えています.

また,AtCoderのコンテンツを利用した勉強会だったため,そのままAtCoderのコンテストに参加する部員も多く,競技プログラミング勢が増えました.

改善すべき点として,参加者の理解度をもっと把握できるようにすることが挙げられると考えています. AtCoderの提出一覧から提出されたコードを確認できるため,これを利用すれば参加者ごとにアドバイスをしたり,参加者がどこで躓いているか把握することができたと思います. そのために,可能なら事前にユーザ名を教えてもらったり,解けない場合にも提出してもらうように言っておけば良かったと考えています.

Siv3Dを利用したゲーム開発勉強会

OpenSiv3D v0.4.3の資料を利用してゲーム開発勉強会を以下のように開催しました.

目的

この勉強会の目的は,参加者に,ゲーム開発など,AtCoder以外のプログラミングにも興味を持ってもらうことでした.

期間

2021年8月27日から2021年8月30日まで間,毎日午前中に2時間,午後に2時間の勉強会を開催しました.

対象者

この勉強会の対象者は,私の所属サークル内で,ゲーム開発などグラフィカルなアプリの開発に興味がある部員でした.

講師陣

この勉強会には,私を含めて3名が講師として参加しました.

内容

内容
1日目午前 構造体と関数についての復習
1日目午後 Visual Studioの使い方,追加の演習問題
2日目午前 Siv3Dのインストール,1. Siv3D の基本
2日目午後 2. 図形を描く(2.1 円を描く,2.2 色を付ける,2.3 背景の色を変える,2.4 長方形を描く,2.5 枠を描く)
3日目午前 3. 動きを作る(3.1 経過時間を使ったアニメーション(Scene::Time(),Scene::Center(),Scene::DeltaTime()),3.2 ストップウォッチ)
3日目午後 4. あたり判定
4日目午前 5. 画像を描く(5.1 絵文字を描画する,5.5 アイコンを描画する,5.6 画像ファイルを読み込んで描画する)
4日目午後 8. フォントを使う(8.1 Font,8.8 フォントのスタイルを変える,8.13 縦書きでテキストを描画する,8.14 指定した長方形の中にテキストを描く,8.15 テキストを 1 文字ずつ表示する)

Siv3Dを利用することにした理由

日本語の公式資料が充実している

Siv3Dの公式資料では,環境構築からライブラリの使い方までが日本語で示されています. 以前にDXライブラリというものを使用した時には,新しいプロジェクトを作成した後に必要な設定の手順が多くて大変だった思い出があります. これに対して,Siv3Dでは環境構築自体もVisual Studioのインストールと,Siv3Dのインストーラを起動することだけで難易度が低めだと感じています. また,Siv3Dの公式資料は,単なるリファレンスではなく,機能の解説がコピペで動作確認できる短いサンプルコードとともに示されており,動かしたり改造しながら勉強できると思いました.

APG4bで勉強したC++を使用できる

Siv3Dを利用すると,APG4bで勉強したC++によるプログラミングの延長として,アプリケーション開発を行えると考えています. そういう点でSiv3DはAPG4bと相性が良いと思いました. これに対し,例えばUnityでは,エディタとフレームワークを利用する中の一部にプログラミングがあるという感じがしますし,また,使用できるプログラミング言語C++ではなくC#です.

その他工夫したこと

この勉強会では,Siv3Dを利用して準備の手間を省いたことの他にも,以下の工夫をしました.

  • 構造体の復習を設けた.
  • 独自のSiv3D演習問題を設けた.
構造体の復習

Siv3Dはクラスベースのフレームワークであるため,構造体への理解が重要であると考えました. そこで,APG4bで学んだ構造体を復習する時間を最初に設けました. 具体的には,APG4bの3.04構造体のキーポイント,細かい話(コンストラクタ)について解説し,演習として,EX24 - 時計の実装に取り組みました.

また,独自の演習問題として以下を解きました.

  • 構造体に関する追加の演習問題

構造体の練習として、和とスカラー倍の定義されたベクトル表す構造体を実装してみましょう。 以下のプログラムの雛形のコメントに従って構造体を実装してください。 github.com

この演習問題は,Visual Studioの使い方に慣れるためにも,APG4bのコードテストではなく以下を参考にしてVisual Studioで解くこととしました.

www.fenet.jp

独自のSiv3D演習問題

2日目以降は,Siv3Dの演習問題を以下のように準備しました.

演習問題
2日目午前 Siv3Dのサンプルを5個選びそれぞれコピペして実行してみる.
2日目午後 5種類の図形を別の色で描画してみる.
3日目午前 マウスカーソルがウィンドウの左側にある間は円を左に動かし,右側にある間は円を右に等速度で動かしてみる.
3日目午後 クリックした円を分裂させる(元の円を消し,少しずらした位置に二つの円を描画する.).
4日目午前 アイコン,画像を拡大縮小,回転させてみる(5.2 テクスチャを拡大縮小して描画する,5.3 テクスチャを回転して描画するを参考にする.).
4日目午後 3人のキャラクタを表示し,クリックされたキャラクタに何か喋らせる.

難易度としては,サンプルコードを組み合わせたり,少し改造することで解けるものを設定しました. 解答例は以下のリポジトリにあります.

github.com

振り返り

Siv3D(Open Siv3D v0.4.3)の資料をそのまま利用したため,演習問題以外の多くの準備の手間を省くことができたと考えています. また,少なくともゲーム開発勉強会を通して,参加者が今後アプリケーションなどを作りたいと思った時にSiv3Dのことを思い出してもらえるようになったかなと思っています.

しかしながら,改善すべき点として,勉強会中に参加者が演習問題をどの程度解けているのか把握できなかったことが挙げられると考えています. 実際,サンプルコードの実行ができていない参加者が何人かいたようだったのですが,勉強会中には把握できませんでした. 勉強会はオンラインで開催されたため,参加者から声がかからない限り講師が参加者の様子を把握することはできません. これに対する解決案として,勉強会中に参加者が質問をしたりヘルプを求めたりしやすいようにするために,演習ではグループに分かれてそれぞれのグループに講師がつくことなどが挙げられるのかなと考えました.

APG4bを利用したC++勉強会で触れることのできなかったC++文法がSiv3Dのサンプルで使用されていることも多いので,これに対するフォローをもっと手厚くするべきだったと思いました.

また,この勉強会は夏休み中に集中して開催されたのですが,せっかくなら合宿らしく,夜にはオンラインでできるゲームをして盛り上がればもっと楽しくなったかもしれないと思いました.

勉強会を開催する中で,私と他の講師の一人がそれぞれ資料中に誤植を発見し,これを修正するプルリクエストを送ってマージされるということもありました.

MacBook Air (M1, 2020)で環境を構築するためには,以下の記事を参考に設定を修正する必要がありました.

qiita.com

まとめ

  • 今年度,サークル内で,以下のプログラミング勉強会を開催した.
    • APG4bを利用したプログラミング勉強会
    • Siv3Dを利用したゲーム開発勉強会
  • 勉強会の資料としてAPG4bやSiv3Dを利用することには,以下のような多くのメリットがあった.
    • 資料が網羅的であり,それ自体で内容が完結している.
    • 資料をそのまま利用することで講師陣の負担を減らすことができる.
    • 環境構築の難易度が高くない.
    • APG4bやSiv3Dの相性が良い.
  • これらのコンテンツを活用するために以下の工夫をした.
    • APG4bを利用したプログラミング勉強会では,交流の時間を設けた.
    • Siv3Dを利用したゲーム開発勉強会では,構造体の復習の時間と独自の演習問題を設けた.
  • 個人的に反省した結果,これらのコンテンツをオンライン勉強会で最大限活用するための工夫として以下のものが考えられた.
    • AtCoderの提出一覧を意識的に活用できるようにする.
    • 演習では小グループに分かれてそれぞれにコーチがつくようにする.

謝辞

  • 素晴らしい資料とプラットフォームを提供してくれているAtCoderに感謝します.
  • 素晴らしい資料とフレームワークを提供してくれているSiv3Dに感謝します.
  • 講師を含めて,勉強会に参加してくれた方に感謝します.

AtCoder反省会してたはずが気が付くと規格読みながらcpprefjpにプルリク投げてた

はじめに

本記事では,私の所属サークルでAtCoderコンテストABC218の反省会していたはずだったのに,気が付くとC++の規格書を読みながらcpprefjpにプルリクエストを送信していた,という話をします. 本記事は,室蘭工業大学 Advent Calendar 2021の3日目に割り当てられた記事です.

adventar.org

本記事の内容は,【LT会】Acompany競技プログラミングLT会 #1で発表したLTの内容をもとにしています.

acompany.connpass.com

経緯

まず,C++の規格書を読みながらcpprefjpの記事を修正するまでの経緯を述べます.

私の所属サークルのAtCoder反省会

私の所属サークルにはAtCoder反省会という会があります. これは,AtCoderのコンテストの時間になったら,オンラインで集合してコンテストに参加し,コンテスト終了後にそのコンテストの問題の解き直し,感想戦,解説などを行う会です. この会は,競技プログラミングをする部員同士で交流することを目的として始まりました.

ABC218

2021年9月11日に開催されたABC218では,100分間のコンテストの内82分経過した時点でA,B,D,Cを解くことができ,残り18分間でEに挑みました.

atcoder.jp

辺を報酬に関して昇順に並べた上で,グラフが連結になるまで,報酬が低い方からまだ連結していないノード同士を繋ぐ辺をグラフに追加していけば良さそうだなあと感じ,DSUを使って実装しました. しかしながら,結果はWrong Answerで,コンテスト中にデバッグを完了することができませんでした.

atcoder.jp

ABC218のAtCoder反省会

ABC218が終了した後,所属サークルのAtCoder反省会が始まりました. Eの解説をチラッとだけ見てみると,コンテスト中に思いついた解法は想定解法と同じっぽい雰囲気がありました. 運の悪いことにサンプルのテストケースは通ってしまっていたので,テストケースをいくつか自作してプログラムの内部状態の変化を確認しました. そうすると,辺を報酬に関して昇順に並べる処理に失敗していることに気が付きました. この処理は以下のようにしてstd::multiset<tuple<ll,ll,ll>>型の変数Cに辺の情報を追加することで実装していました.

/* 省略 */
using ll = /** __int128; //*/ std::int_fast64_t;
/* 省略 */
void solve(){
  /* 省略 */
  auto cmp = [&](tuple<ll, ll, ll> const &t0, tuple<ll, ll, ll> const &t1) {
    return get<0>(t0) < get<0>(t1) || get<1>(t0) < get<1>(t1) ||
           get<2>(t0) < get<2>(t1);
  };
  std::multiset<tuple<ll, ll, ll>, decltype(cmp)> C(cmp);
  /* 省略 */
}

ここで,Cにはそれぞれの辺の情報が次のようなタプルとして格納されます.

  • 要素として報酬,一つ目のノード,二つ目のノードをこの順に持つタプル

また,Cに格納される辺が報酬に関して昇順に並ぶようにするために,コンパレータcmpを指定しています.

このコンパレータは,とりあえずtuple<ll, ll, ll>のコンパレータのデフォルトの実装と同じものを用意しておいて,後で考察しながらいじれるようにするつもりでした(実際にはデフォルトの実装からいじる必要はありませんでした.). しかし,デフォルトの実装のつもりで記述したコンパレータが実際にはデフォルトの実装と異なったものとなっていました. これが,Wrong Answerを解消できなかった根本的な原因であり,ここに誤りがある限りいくら考察を進めてもAcceptedには辿り着けません.

コンパレータの実装の誤りに気が付いたので,以下のサイトの記事を読んで正しい実装を確認することとしました.

cpprefjp.github.io

この記事を読んでいると,記事のコードの中に「`」が紛れ込んでいるのを見つけたため,この1文字を削除するだけのFix typoプルリクエストを軽い気持ちで送りました.

github.com

その時点では,「翌日にはマージされているだろう,また一つ,Fix typoのプルリクエストを送ってしまった」と思っていました.

プルリクエストがマージされるまで

翌日,プルリクエストにコメントが送られました. 私は,コメントの内容を以下の通りに解釈しました.

  • 私がプルリクエストを送る前の説明が,そもそも不完全であったため,それを完全なものとする必要がある.
  • 私がプルリクエストを送る前の説明が,C++17における説明であり,C++20においての説明にする必要がある.

私は,元のプルリクエストの修正範囲を超えていると感じ,プルリクエストを閉じようとしました. そうしたところ,C++17における説明を完全なものとすることにも意義があるため,その修正をこのプルリクエストでやったらどうかという主旨のコメントが追加されました. C++の規格書として参照すべきURLも与えられていたため,これを見ながら修正を行いました. 修正は,基本的に規格書の内容を日本語訳することにより試みました. これに合わせて,プルリクエストのタイトルを変更し,レビューをお願いしました.

これに対して返されたレビューについて,私は以下の通りに解釈しました.

  • 修正内容には問題は無い.
  • コミットの単位をsquashにより修正するべきである.

squashをするのが初めてだった私が少し自信なさげに「やってみます」と返答したところ,なんとレビューコメントにsquashのやり方まで追記してくれたのでした. コミットのsquashを行うと,プルリクエストは無事マージされました.

私のFix typoでないプルリクエストで,個人的なプロジェクト以外のリポジトリにマージされたのはこれが初めてでした.

Fix typo以外でマージされた初めてのプルリクエス

ABC218のE問題のAccepted

コンパレータはstd::tupleのデフォルトの動作で十分であると考察したため,デフォルトのコンパレータを使用するように変更したところ,デバッグも順調に進み無事Acceptedとなりました.

atcoder.jp

誤りのあったコンパレータを,あえて明示的にデフォルトの動作と同様の動作をするように修正すると以下のようになります.

/* 省略 */
using ll = /** __int128; //*/ std::int_fast64_t;
/* 省略 */
void solve(){
  /* 省略 */
  auto cmp = [&](tuple<ll, ll, ll> const &t0, tuple<ll, ll, ll> const &t1) {
    return get<0>(t0) < get<0>(t1) ||
           ((!(get<0>(t1) < get<0>(t0))) &&
            (get<1>(t0) < get<1>(t1) ||
             ((!(get<1>(t1) < get<1>(t0))) && get<2>(t0) < get<2>(t1))));
  };
  /* 省略 */
  std::multiset<tuple<ll, ll, ll>, decltype(cmp)> C(cmp);
  /* 省略 */
}

【LT会】Acompany競技プログラミングLT会 #1

私の友人の所属先が開催するLT会で,競技プログラミングに関するテーマでLTを募集していました. 私も何か発表してみたいなあと考え,上記の内容を5分程度にまとめてLTを申し込みました. LTに対しては,予想していたよりも良い反応をいただくことができ,発表した甲斐があったと思いました. また,LT後の雑談も盛り上がり,Androidアプリの開発やRustをおすすめされたりしました.

私のLTの他に,2つのLTがありました. 一つは,作問をすることにより,解けなくても思考を続ける粘り強さを養いましょう!という内容でした. 解ける解けないといったことの他に,考察そのものの楽しさを忘れないようにしたいと思いました. もう一つは,ICPCに出場しましょう!という内容でした. ICPCに出場したり,コーチとしてついて行ったりしたことを思い出して,懐かしく感じました.

LT会の後で,LTの内容が競技プログラミングと少しずれていたかもしれないと思いました. 友人にそのことを言ってみると,ずらし方が巧妙で気が付かなかったと言われました.

まとめ

やったこと

  • 所属サークルのAtCoder反省会でABC218Eをデバッグした.
  • cpprefjpのtypoを発見してプルリクエストを投げた.
  • 元の説明が不完全だったため,規格を読んで書き直した.

得たこと

  • ABC218EでAcceptedとなるコードを提出できた.
  • C++の規格を読む」という体験をした.
  • コミットの内容だけでなく,形式まで意識してプルリクエストを送信した.
  • Fix typo以外のプルリクが,自分以外のリポジトリに初めてマージされた!