ShuttleがSerenityの0.12に対応したぞ!!(ただし自分に関わりのある部分のみ紹介)

:::note warn
Zennにも同様の内容を投稿しています
:::

## TL;DR

- DB使う場合のエントリポイントの関数の引数の仕様変更
- Serenity0.12をデフォルトに
- CHANGELOG､大事

## 破壊的変更とは

 よく英語ではBREKING CHANGEなんてかかれている｡読んでそのまま昔のコードのままだと動かなくなる変更の事｡Conventional Commit(コミットログ規約みたいなもの)においてはPrefixに`!`を追記する｡

 自分の作成しているプログラムを継続して開発していく場合､つまり運用や保守をする場合､使っているライブラリやクレートは､最新のものを使うのが好ましい｡(この理由に関しては様々あると思う､脆弱性の対応やパフォーマンスの改善､全体的に見た場合の書きやすさとか)
 
 新しくなっていく際に､そのライブラリの開発メンバーたちが｢こうしたほうがいい!｣というもとで､既存のコードが使えなくなる変更が生じることがある｡それが破壊的変更だ｡

 現時点でそうしたリリースを行っているOSSは基本的にはチェンジログといってリリース時の変更をまとめたものを出してくれる｡その中にBREAKING CHANGEなどとかかれたものがあればそれが破壊的変更で､最新バージョンのライブラリを使う場合それに追従する必要がある｡

 今回はメンテする中でライブラリの破壊的変更に対応したのでその話｡

:::note warn
あくまでここで紹介するのは自分が開発しているプロジェクトで関わりのある部分のみになります｡その他は[公式のリリースノート](https://github.com/shuttle-hq/shuttle/releases/tag/v0.37.0)を見に行ってください｡
また現時点(2024年1月28日)Shuttleの[ドキュメント](https://docs.shuttle.rs/)では`0.37`に対応した書き方に変更されていないので注意が必要です｡
:::

## Shuttle 0.37の(自分に関わりのある)変更点

GitHubはエンジニアのSNSなんて言われているが､ぶっちゃけ私はそんなに見ない｡
なので今回気づいたのはShuttleの公式DiscordコミュニティのEveryoneメンションで｢0.37リリースしたから確認してチョ!｣というものだった｡
そのメンションを見たときはホーンという感じだったが､リリースノートにかかれていた文言が私をやる気にさせた｡

>  shuttle-serenity now uses 0.12 by default. Using 0.11 is still possible with a feature flag. More info in the crate docs.
([リリースノート](https://github.com/shuttle-hq/shuttle/releases/tag/v0.37.0)より)

ShuttleはRustでかかれたプロジェクトをホスティングしているサービスで､Discrod API用のライブラリであるSerenityについてもサポートしている｡
ただ､前のバージョンの0.36まではSerenityの`0.11`までをデフォルトのサポートとしており､私も`0.11`に合わせて開発をしていた｡[^1]

今回のバージョンリリースでついに最新のSerenityのメジャーバージョンを使える用になったわけなので､早速対応をしよう､というのが今回のことの始まりである｡

また今回先に述べた破壊的変更として､`shuttle-shared-db`などのDBに接続する時の引数をPoolにしていたのが今回の変更で接続先のロケーターの文字列を渡すようになったのが変更点｡
以下はリリースノートからの引用↓

```rust
// Use the connection string
#[shuttle_runtime::main]
async fn main(#[shuttle_shared_db::Postgres] conn_str: String) -> ... { ... }

// 🚨 Add the "sqlx" feature flag to get a PgPool like before
#[shuttle_runtime::main]
async fn main(#[shuttle_shared_db::Postgres] pool: sqlx::PgPool) -> ... { ... }
```

今回は`feature-flag`の変更で対応｡今回この変更に真っ向から追従する､つまり上の実装に変更するのが面倒そうだと感じたので､Cargo.tomlの`shuttle-shared-db`部分を変更して対応した｡

```toml:Cargo.toml
shuttle-shared-db = { version = "0.37.0", features = ["postgres", "sqlx"] }
```

## Serenity 0.12の(同上)変更点

こちらも一部だけ抜粋｡ちなみこっちの変更も破壊的変更(のはず)｡

> The closure-based API for constructing requests using the builder pattern has been ripped out and replaced. In place of closures, users must now pass in builder types directly.
([リリースノート](https://github.com/serenity-rs/serenity/releases/tag/v0.12.0)より)

これまでメッセージを送信する際に使っていた`CreateMessage`のビルダーのAPIがクロージャベースの設計を廃止し､普通のメソッドチェーンのような書き方ができるようになった｡

書き方としてはかなり直感的になったので今回の変更は現時点では個人的にはいい変更だと感じた｡

<details> <summary>クロージャって?</summary>

基本的な事は [TRPL](https://doc.rust-jp.rs/book-ja/ch13-01-closures.html) で確認してほしいが､JavaScriptのアロー式やPythonでのラムダ式に近しいものと言う認識で筆者はいる｡Rustでは環境をキャプチャできる[^2] 点もクロージャを扱う利点の一つ｡
</details>

```diff:差分
-                   .send_message(&_ctx.http, |message| {
-                       message
+                   .send_message(
+                       &_ctx.http,
+                       CreateMessage::new()
                            .reference_message(&msg)
-                           .allowed_mentions(|mentions| mentions.replied_user(true))
-                           .add_embed(|embed| {
-                               embed.description(description).timestamp(msg.timestamp)
-                           })
-                   })
+                           .allowed_mentions(CreateAllowedMentions::new().replied_user(true))
+                           .add_embed(
+                               CreateEmbed::new()
+                                   .description(description)
+                                   .timestamp(msg.timestamp),
+                           ),
+                   )
                    .await,
```

## こうした変更の対応はどうすればいいのか

Rustの場合､VSCで開発していると拡張機能のCratesがバージョンが最新かどうかを判定してくれるし､ mend.ioのrenovateなどの依存更新ツールもあるため最近の開発においては察知するのはあまり難しいものではない｡ただ､日本語話者にとってはだいたい有用なプロジェクトは英語なので､とっつきにくい印象もある｡まぁLLMの要約に入れたりなんだりかできる世の中にもなったので､キャッチアップのアンテナだけきちんと張っておけば実装自体はきちんと変更点を読めばいい｡


## おまけ

今回対応したRepoのPRをおいておきます｡

https://github.com/raiga0310/vxbot_shuttle/pull/15

[^1]: 0.36時点でもSerenity0.12を使うことは可能だった｡[参考](https://docs.rs/crate/shuttle-serenity/0.36.0/features) `features = ["serenity-0-12/rustls_backend"]`など｡今回のリリースではそのデフォルトを切り替えたよ､ということである｡

[^2]: ｢環境をキャプチャ｣という表現はTRPLでも用いられており､クロージャ内のコードブロックにおいてクロージャが定義されたスコープの変数を扱える､というもの｡これには所有権などのメモリ管理に関する話も混ざるのできちんと理解したい場合(~~というか私も完全に把握はしてない~~)は[TRPL](https://doc.rust-jp.rs/book-ja/ch13-01-closures.html)を参照されたし｡