/dev/sdr2

東方見聞録

データベースの日次バックアップを取るようにした

前提

  • 色々なサービス向けの共用データベースを自宅で動かしている
    • PostgreSQL 16でレプリケーションはやってない
    • 色々なサービスと言っても個人用のサービスが大半
    • 対外的に公開されている(=落ちると自分以外に迷惑がかかる)のはmisskeyだけ
  • データベースのバックアップを今までやっていなかった(!)
    • 以前は半年おきにDBを載せるサーバーを移転していたのでダンプファイルがどっかに転がっている状態ではあったのだが,自宅に移転してからは何もしていなかった
    • misskeyはDBに署名用の鍵が保存されており,読み出せなくなるとアカウントを全部作り直さないといけなくなる

 

事前調査

  • そもそも何を保存する?
    • pg_dumpを使うのかpg_basebackupを使うのか
      • 増分ではなく毎回単純にバックアップ取れば良いと思ったのでpg_dumpをそのまま使った
    • DBユーザーを含めたフルバックアップなのか,特定のデータベースだけなのかを考える必要があった
      • DBユーザーは相対的に必要性が薄いだろう(再設定すれば良い)と思ったので特定のデータベースのみ保存するようにした
  • どこに保存する?
    • ローカルにおいたら意味がないのでクラウドストレージに置く
    • 今何かしらの用途で使っているのはAWSとCloudflare
    • Cloudflare R2 - Pricing Calculator というのを見つけたので使ってみた

      • R2が最安
      • 数年前のダンプは20GBくらいあった記憶があり,7世代保存すると140GBくらいになるだろうという予測を元に計算してみた
      • R2だとおよそ300円くらい,S3だと450円くらいだろうという試算
  • どれくらいの周期でやる?どうやって周期的に実行する?
    • 周期はとりあえず1日で良いだろうということにした
    • 1日でそれなりに投稿が貯まるはず(外部のサーバーからも飛んでくるため)なので,2日周期にするとだいぶ失われてしまうのではないかという懸念があった
      • 2日周期だとジョブに失敗しても気づけないかもしれないという個人的な事情もある
    • タダでやりたいので,手元環境にLXCコンテナを立ててやることにした
      • cronではなくsystemd-timerを使うようにした
      • one-shotなserviceを作り,timerを設定して決まった時間に発火するように設定した
  • 圧縮とか暗号化とかどうしよう
    • 圧縮は普段zstdを使っているのでzstdでやる
      • そこそこな圧縮率,速度はかなり速いはず
    • 暗号化も普段使っているageを使う
      • gpgとかで使えるAESよりも速度が出る
      • モダンで良い

 

動かす

  • バックアップに使うコマンドはRubyから実行するようにした
    • Shell Scriptは書き慣れていないし,AIもあんまり得意じゃないだろうという読みがあった
    • サッと動かしたいのでRubyを選択
      • Pythonはvimとかnanoで書きたくないので除外(インデント...)
    • Claude Code (Claude Opus 4.6 effort: medium)にやってもらった
      • 先回りしてメソッドを書いておいて,それぞれのメソッドがどういう処理をすれば良いか与えたらうまく行った
        • ちょっと伝わらなかった部分もあったが品質としてはそこそこ良かったのでまぁいいでしょう
  • systemd serviceとtimerを書いた
    • これもAIにやってもらった
    • そんなに行数ないので手書きでも余裕です
    • 実行に必要な環境変数はファイルに書いて渡した
      • 便利
  • テスト実行したらめちゃくちゃ遅い上に失敗した
    • ダンプを圧縮するステップで20分食っていた
      • 圧縮レベルが高すぎたせい
      • デフォルトは3で十分小さくなるので変更した
        • 15GBのダンプファイルが4.3GBになった
          • 思っていたよりも元々のダンプファイルが小さく,圧縮したことにより予想の1/5程度で済んだ 
            • 速度は約11倍(1100秒→100秒)に
  • 暗号化は超高速
    • 大体10秒くらい
    • CPUを少し食ったかなという感じで特に重いとかはなくて最高
  • アップロードはrcloneを利用
    • AWS CLI(R2はS3互換ストレージなのでそのまま使える)は使わなかった
      • 使い慣れているのはrcloneなので
    • 事前にconfigを書いておく
      • Cloudflareのドキュメントにrcloneを使ったR2の操作方法のページがあった
  • 実行のログをDiscordに流す
    • WebHookのURLを環境変数に入れておくだけ
    • ステップごとに開始/終了と実行時間を通知するようにした

 

今後やりたいこと

  • ちゃんと動いているかどうかの監視
    • Discordのログだけでは不十分なので何かしら別の方法でチェックする必要がありそう
  • それ以外のデータのバックアップ
    • 今のところ他に保存するべき物は見当たらない
  • バックアップからの復旧訓練
    • スクリプトを書いておけば実行するだけで環境が元通りになるとかできそう

 

サーバーのログを収集するようにした

背景

  • 自宅でサーバーを動かしている
    • VMが全部で20台くらい動いている
    • 全てのVMがインターネットから直接アクセス可能なわけではない (必要に応じてリバースプロキシしている
  • セキュリティー強化したい
    • 一般的なセキュリティー設定(SSH周り)はやっているが,実際にどれくらいログイン試行があるか等を可視化したい
  • HTTPのアクセスログを保存しておきたい
    • 基本自分向け or 特定少数の知人向けなのであまり保全する必要はないのかもしれないが,一応何かあった時のために保存しておきたい
  • アプリケーションのログをちゃんと見たい
    • たまにクラッシュしたり不具合が起きたりするので,何が起こったのかが後から追いやすいようにしておきたい

何をしたか

  • Grafana Lokiを使ってログを収集・管理できるようにした
    • Docker Compose上で動かしている
      • k3sも動かしているが,k3sが壊れた時にどうにもできなくなるとまずいので避けた
    • 可視化やアラートはGrafanaを使う
  • サーバーからはjournalのログを流すようにした
    • Grafana Alloyを使ってログを収集,Lokiに送るように
      • Promtailは非推奨になっていたので乗り換えた
        • Promtail is now deprecated and will enter into Long-Term Support (LTS) beginning Feb. 13, 2025. This means that Promtail will no longer receive any new feature updates, but it will receive critical bug fixes and security fixes. Commercial support will end after the LTS phase, which we anticipate will extend for about 12 months until February 28, 2026. End-of-Life (EOL) phase for Promtail will begin once LTS ends. Promtail is expected to reach EOL on March 2, 2026, afterwards no future support or updates will be provided. All future feature development will occur in Grafana Alloy. If you are currently using Promtail, you should plan your migration to Alloy. The Alloy migration documentation includes a migration tool for converting your Promtail configuration to an Alloy configuration with a single command.

        • Promtail agent | Grafana Loki documentation
    • Alloyのインストール,設定の反映はAnsibleのPlaybookを書いて自動化した
      • いきなり全てのVMに入れずに,特に重要なものを動かしているVMに絞った
        • 動かしているもの( = 監視対象)がそれぞれ違うので,真面目に設定を書かないといけないため...(Ansible何もわかっていない)
    • Systemdで管理しているserviceのログが取れる
      • sudoを使った時のログ,sshのログイン(試行)履歴,ファイアウォールのブロックログ など
      • Dockerなどのコンテナ上で動く or ログがファイルに出るアプリケーションのログはまだ設定を書いてないので何もない状態

できたもの

  • UFWのブロック数の可視化
    • 本当は宛先ポートをリストにしたいが,なんかいい感じのクエリが出せず...

難しいポイント

  • LogQLが難しい
    • { job = "journal"} | = "UFW" | logfmt みたいな感じで書く必要があって...
      • エディタの補完はあるが補完があっても書きやすくなるわけではなく...
    • 可視化する時にクエリで頑張ってデータを絞って使いやすくするのか,後処理(取得したログデータを整形する)で頑張るのかどちらが良いのかわかってない
    • データ量が増えるとクエリを頑張るしかなくなりそう
      • 自宅サーバーだから1回のクエリにかかるコストとかを考える必要がないのは良いこと
  • Lokiの設定を真面目にしていない
    • ログを収集するのは良いが,圧縮とかバックアップとかを考えていない
      • 稼働しているコンテナが壊れたら終わりな状態
    • Cloudflare R2に転送するのが良いのかな〜
  • 特にログを見る機会がない
    • 定期的に見る会を自主的にやるとかすれば良いのかな
    • アラートを設定しておかしくなったらすぐ見る,みたいな習慣をつけると良いと思う

今後

  • 全VMに導入する
    • ログだけではなくOpenTelemetry経由でトレース/メトリクスも取りたい
      • VM同士の通信量とか取れないかな
  • 真面目にAnsibleやる
    • Alloyのバージョンアップは定期的にやると良さそう

Kotlinを書き始めた

この記事は はてなエンジニア Advent Calendar 2025 16日目の記事です.
昨日は id:Windymelt さんの HNSWのビジュアライザを作成したでした.

さて,表題の通り最近 Kotlin を書きはじめたので,この記事ではKotlinを書いてみた感想を書いてみようと思います.

ファーストインプレッション

私のバックグラウンドとしては TypeScript をメインにたまにGoやRubyを書くという感じで,いわゆるJVM系言語はほとんど触ったことがありませんでした. 書き始めるまでのKotlinの雑なイメージはこんな感じでした:

  • JetBrainsが開発している
  • JVMの上で動く
  • 記法がJavaに近いだろう

書いてみて面白いなと思ったところ

クラスの種類が多い

まずはじめに思ったのはクラスの種類が多いことでしょうか. TypeScriptではclassだけですが,Kotlinにはdata classsealed classenum classなど様々種類のクラスが存在しています.まだ正しい使い分けが理解できていません...

それぞれの役割や特性としては:

  • data class: データ保持が目的.自動的にデータをコピーできるcopy()メソッドが実装される.
    • このcopy()メソッドはかなり便利で最初に見たときは感動した覚えがあります.
  • sealed class: 継承できるクラスを同じパッケージ内に制限する.whenで網羅性チェックができる.
  • enum class: 固定値を列挙できる.各値はインスタンスになる.

when式が強い

when式はswitch文より表現力が高く,分岐が結構簡潔に書けます. TypeScriptやGoには無い機能なので,チュートリアルを走っている途中には結構強力な構文だなと思っていました

大分雑な例ですが,例えばプログラミングのテストで出てきそうな*1こんな感じのコードが

function formatScore(score: number): string {
  if (score >= 90) return "秀";
  if (score >= 80) return "優";
  if (score >= 70) return "良";
  if (score >= 60) return "可";
  return "不可";
}

Kotlinだとこう書けます:

fun formatScore(score: Int): String = when {
  score >= 90  -> "秀"
  score >= 80  -> "優"
  score >= 70  -> "良"
  score >= 60  -> "可"
  else -> "不可"
}

named arguments

関数呼び出しの時に引数名を指定できる機能です.

data class User(
  private val id: String,
  private val name: String, 
)

val user = User(id = "20251216", name = "laminne")

これがなかなか便利です. 引数が増えてくると順番を意識して書く必要がありますし,同じ型の引数を取り違えることも良く発生します. 同じような構文はRubyなどにもあります.

同じようなことをTypeScriptで書こうとすると,まずinterfaceやtypeを使ってオブジェクトの型を定義する必要があります:

interface UserArgs {
  id: string,
  name: string,
}

class User {
  private readonly id: string
  private readonly name: string

  constructor(args: UserArgs) {
    this.id = args.id
    this.name = args.name
  }
}

const user = new User({ id: "20251216", name: "laminne" })

TypeScriptのクラスにはコンストラクタでメンバ変数を定義できる構文があり,上のコードはこんな感じに書き直すことができます

class User {
  constructor(
    private readonly id: string,
    private readonly name: string, 
  ) {}
}

とはいえこの方法だとオブジェクトを使って受け取ることができないので,コンストラクタでメンバ変数に代入し直す必要があって辛い...

スコープ関数

スコープ関数はラムダ式を使ってオブジェクトを操作するための関数*2です. letrunwithapplyalsoの5種類が存在していて,それぞれ少しずつ違う効果があります.使い分けるのが難しい....

例えばlet: ?.演算子と一緒に使うことが多い,nullableなオブジェクトに対して「中身がnullではない時だけ実行する」処理を書くときに使う.

val email: String? = user.getEmail()

val trimmedEmail = email?.let {
  it.trim()
}

// 繋げて書くこともできる
email
  ?.let { it.trim() }
  ?.let { it.lowercase() }

TypeScriptで同じことを書くと

const email: string | null = user.getEmail()

const trimmedEmail = email !== null ? email.trim() : null

というようになります. if文や三項演算子で分岐させるのとメソッドチェーンのどっちが良いかは場合によると思っていますが,個人的にはメソッドチェーンできる方がわかりやすくて好きです.

不満点

最近書き始めたばかりで理解していないことの方が多い状態なので,あまり不満はありませんが,強いて言えば:

  • ビルドが思ったより重たい
    • lintなどの周辺ツールも数秒待つことが多かったです(これは私の設定が悪いかもしれない...)
    • 差分ビルドとかをうまく使うともっと早くなるかも
  • たまにJavaのメソッドを呼び出して困る
    • 「このメソッドはKotlinじゃないからnamed arguments使えないよ」とIDEに怒られることがよくある
    • 適当に関数ジャンプしようとするとデコンパイラー使いますか?と聞かれてびっくりする

まとめ

  • 思ったより便利な構文や機能が多くて簡潔に書けるなという印象を持った
  • まだ書き始めてからの時間が経っていないので試せていない機能や理解できていないことが結構ある
    • Coroutineは全く理解できていない.使えると便利そう
    • Kotlin Nativeが気になっている
  • Pure Kotlinでちゃんとしたアプリケーションを作ったり,大きなコードを読んでみようかなと思っている

以上です.

*1:実際に学校のテストでこんな感じのコードをCで書いた覚えがあります

*2:https://kotlinlang.org/docs/scope-functions.html

独立行政法人国立高等専門学校機構 松江工業高等専門学校 情報工学科 を卒業しました

 

 

表題の通り,3/21に 独立行政法人国立高等専門学校機構 松江工業高等専門学校 情報工学科 を卒業しました.なんと!5年で卒業できてしまった...

私のソーシャルアカウントをフォローしている人はほとんどが高専について詳しいと(勝手に)思っているので高専本体の説明は最小限にしますが,高専はこういう学校です

  • 正式名称が長い(大体 "独立行政法人国立高等専門学校機構" が長すぎるのが悪い)
    • これのせいで銀行や就活サイトの登録がだいぶ面倒になってしまう
    • 松江高専情報工学科の正式表記は空白を含めて33文字ある
  • 大学生でも高校生でもない謎の経歴
    • 高専は5年で卒業するもの(高校相当の3年+短大と同じで2年)で,卒業できないと中卒になる(5年通って初めて"高専卒"を名乗れる)
  • 大体立地が微妙
    • 用地確保の都合で多くの場合各県の第二第三の市の外れにある
    • 松江高専は中国地方唯一県庁所在地に存在するが,中心地から離れた場所にある

 

5年間でやったこと

スーパーダイジェストでお送りします.

  • 発狂
    • おかげさまで人生狂いました
    • フォォゥ〜〜〜〜!!!!!!!!(爆発)
  • 留年の回避
    • いわゆる"万年留年候補"でした
  • インターン(4年次)
    • 途中で腹を壊した
      • その節は申し訳ありませんでした
  • 苦行(変な旅行)
    • フリーきっぷ 一筆書き @東京 (5年次)
    • 青春18きっぷ苦行 広島-東京 往復1800km (5年次)
  • 各種 限界開発
    • ドメインなしプログラミング (2年次)
      • 2週間以下で書いたMVCもどきの 動けば良い(なお動かない) Webバックエンド
      • ??「種無し餃子」
    • 設計とその実装に時間がかかって動かないプログラムを出展 (3年次)
    • 結合テストしてないシステムを納品したら本番稼働でぶっ壊れる (4年次)
      • とりあえず人力で補完することになった
      • 1年後(5年次)にちゃんと改良して正常動作させました
  • 各種 登壇
    • Rubyアソシエーションのオンラインセミナーでインタビューされる (1年次)
    • RubyWorld Conference スポンサーセッションでリレー形式で話す (5年次)
  • コミュニティー/技術チームの設立など 
  • 部長 (2-4年次)
  • 卒業研究
    • ビジュアルプログラミングツールで書いたプログラムをRuby(の軽量バージョン)に変換して,マイコンで動かす研究をしました

 

今後について

25卒のプログラマーとして就職します.どこに就職するのかについては特に名言するつもりはありませんが,直接会う機会がある人には多分話すと思いますし.何かしらのカンファレンスに出たときに名刺交換するだろうからその時にわかるはず?です.

 

 

 

 

 

 

 

新しい分散/連合型SNS「Pulsate」を開発している

タイトルの通り、新しい分散/連合型SNSを開発している。

ソフトウェアの名前は"Pulsate"*1(パルセート と読む)で、プログラムは以下のrepositoryにある。

github.com

注意:

残念ながら後述する通りまだかなり荒削りな状態であり、プロダクション運用できる状態ではない。

この記事の内容は基本的に私の考えていることをダンプしたものであり、プロジェクトの公式見解ではないことに注意されたい

 

これは何

Pulsateは

  • ActivityPubに対応する
  • 短文投稿型で
  • 絵文字リアクションが利用可能で
  • 引用が可能な
  • サーバー側実装

である。

Mastodon のような思想を持ち、misskey のような機能セットを提供し、それでいてどのソフトウェアとも関係のない独立した実装だ。

 

機能の名前は基本的にmisskeyと同じ*2

投稿: ノート

再投稿: リノート

引用再投稿: 引用リノート

 

技術スタックとしては:

を採用している。

このプロジェクトでは新しい技術を取り入れつつ他の部分では多少枯れた技術も採用していくつもりだ。

 

1/17 補足:

PulsateではバックエンドでもTypeScriptを採用している。理由は:

  • 発起人(7人いました)の中で全員が共通して書ける言語がTypeScriptしかなかった
    • TypeScriptでバックエンドを書いていた人が多かったためそれでも問題がなかった

というような感じです。開発開始後も何回か言語を変更するか?といった検討がなされたことがありましたが、すでに書かれているコードを放棄するよりは継続開発した方が良いだろうといった結論になり、結局TypeScriptを採用し続けているというわけです。

補足終わり

 

フロントエンドは?となるかもしれないが、Pulsate は標準のフロントエンドを同梱しない。Pulsate 向けのフロントエンドは同じ団体(Pulsate Project)が開発する別ソフトウェア扱い*3で、Caramel (カラメル)という別の名前が付いている。

現在時点でのCaramelの技術スタックは:

という感じになっている。Remixの雲行きが怪しくなってきているので別のスタックに切り替えることを検討している。

Caramelは"とりあえず使い物になる"レベルの実装しかしていない最小かつ最軽量なフロントエンドであるため、恐ろしくシンプルで消極的なUIである。

 

Pulsateのフロントエンド、Caramelのトップページ。
タイムラインページ。複数のアカウントの投稿が表示されている。
アカウントページ。そのアカウントの投稿が表示されている。
Cramelのスクリーンショット
(表示内容はあくまでテストデータであることに注意)

ほとんどCSSは書かれいていないし、リアクションは👍の1種類しかつけることができず誰がつけたのかも知ることができない。あとはフォローもできない。

ただ単に(フロントエンド側が)未実装なのもあるが、バックエンドで実装される全ての機能に対応するつもりがないのは事実だ。

 

もし"なんだこのけしからんフロントエンドは!"と思う人がこの記事を読む人の中にいるなら、この記事を一番下まで読んでぜひ私たちと一緒にこのけしからんソフトウェアを改善して、Fediverseの世界をもっと良くしよう。

 

Pulsate関連ソフトウェアのライセンスはApache2.0で、他ソフトウェアで広く採用されているAGPLは採用していない。

理由としてはAGPLは 厳格なコピーレフト型ライセンス であり、フォークの開発者にかかる手間が多いためライセンス違反が発生する可能性がほかと比べて高く、それに対する対処などが複雑になると考えたから と、単に開発開始時にApache2.0ライセンスが一番合っているだろうと判断したからだ。

 

(注: この類のSNSは一般的には"分散型SNS"と表記することが圧倒的に多いが、この記事では後述する理由によってあえてこう表記する)

 

目指すもの

公式サイトに書いてあるプロジェクトが目指すものはこんな感じだ:

1. 高いパフォーマンス

Pulsateの開発開始時に"最も解決したいこと"であったものの一つ。

他実装では"大量のユーザーの投稿や操作をどうさばくか"が重要視されるのに対し、Pulsateでは"そこまで多くない投稿や操作をいかに効率よく処理するか"を重要視していくつもりだ。

 

分散/連合型SNSの統計をとっている FediIndex (https://fedi.wrm.sr/) によると、ユーザー数100人以下のインスタンスが93.23%と大半を占めている。

FediIndexによる分散/連合型SNSのユーザー数の分布グラフ。

ほとんどのインスタンスは非常に小規模であるので、何千何万というレベルの同時接続に耐えることが可能な大掛かりな仕組みよりも運営にかかるコストを削減したり、維持に必要な操作を自動で行ったりできる仕組みを導入したほうが効果があると考えている。

 

Pulsateは中小規模(〜1000人)のインスタンスをメインタゲートに絞って開発していく予定だ。

 

2. ユーザー中心の設計

分散/連合型のSNSをあまり使ったことがない人にとって、リモート/ローカルの概念やフォローの方法を理解するのは相当に難しいことだと思う。

Pulsateは技術者や分散/連合型SNSを使ってきたユーザーだけではなく、標準的なSNSのユーザーやあまり短文投稿系のSNSに触れてこなかったユーザーもターゲットにしたいと考えている。

そのために、シンプルかつ直観的に使いやすい(フロントエンドの)デザインであるとか、極力難しい単語(技術用語)を排除するなどの対応を行っていくつもりだ。

 

3. 開発者向けのサポートや網羅的なドキュメントの用意

PulsateではDiscordに開発者同士、ユーザー同士がコミュニケーションできるようなコミュニティーサーバーを設けている。もちろん開発に関連する(ほぼ)全ての会話はここでオープンな形で行われている。

コミュニティーサーバーは以下からアクセスできる。

discord.com

Pulsateの開発チームにはオープンソースであるのなら開発方針や開発の様子は基本的にオープンにしていくべきという考えがあり、それの一環としてこのようなコミュニティーを設けている。

こうすることで、

  • ユーザーからのフィードバック/ユーザーインタビュー が容易になる
    • ユーザーや外部の開発者が今何を考えているのかということがわかりやすくなる
  • プロジェクト全体の透明性を上げられる
    • 意思決定の透明性の確保は非常に重要

といったメリットがあると考えている。

 

また、内部のアーキテクチャ/設計ドキュメントなどのPulsate自体の開発ドキュメントを完全にオープンにする。具体的にどのようなドキュメントを書き、どのように活用するかは決まっていないが、外部コントリビューターの確保やプログラムの維持管理に活かせると考えている。

 

かなり荒削りで不完全ではあるが*4、すでに一部のモデルの仕様が公開されている。

spec.pulsate.dev

 

さらに、様々なプログラミング言語向けのAPIクライアントライブラリを公式提供する予定だ。Pulsateは他のSNSAPIの互換性がないため、Botやアプリの開発を行うためにはAPIクライアントを自作する必要が出てきてしまう。

他のSNSではそういった場合でも公式でライブラリが提供される事例はほぼ無いが、Pulsateではいくらかの需要の大きいプログラミング言語向けのライブラリを公式で提供する予定だ。

すでにAPIドキュメントと全てのエンドポイントの型はOpenAPI Spec(OpenAIではない)方式でコードから自動生成されているので、公式提供されないプログラミング言語向けのライブラリも手書きすることなく自動で生成できる。

 

4. 他実装との高い相互運用性(互換性)

この記事では"分散型SNS"という表記をせず"分散/連合型SNS"と表記しているが、これには理由がある。

個人的に分散 と 連合 は指す意味が違うと考えているからだ。

おおむねこんな感じに理解している:

分散: 大きいSNS(インスタンスのこともある)を複数に分け、ユーザーを散らす

連合: 複数の(種類の違うこともある)独立したSNSを繋いで1つにする

 

"分散型SNS"と表記すると単にユーザーやインスタンスがバラバラになる印象が大きくなると考えていて、そのために"連合型"という 複数のものがつながる という意味の言葉を採用している。

 

Pulsateのプロジェクト全体の標語(キャッチコピー)は「繋がりを"再定義する"」だが、ここで言うところの 繋がり にはユーザー同士の関係だけでなくインスタンス/サービス/ソフトウェア同士のつながりも含まれている。

 

Pulsateは歴史的経緯*5からActivityPubに関連した処理をSNSの基本機能(ログインや投稿、フォローなど)から完全に独立させる形で設計している。

 

アプローチはmisskeyのそれとほとんど同じで、先に最低限独立したSNSとして使えるようにしてからActivityPubに関連する機能を実装していく という形式を取っている。

とはいっても、連合に対する考え方はmisskeyとほぼ真逆である。

misskeyは「あくまで連合(分散)は従」であり、基本機能を最優先として連合に対して消極的である*6*7

一方Pulsateは「連合は重要な概念であり、既存のSNSとの互換性を保ちどのインスタンスにいてもシームレスに繋がり続けることができること」を重要視する。

このようなスタンスを"連合志向"と言う。Pulsateは連合志向な独立実装である。

 

具体的には:

  • Pulsateは基本的に連合しない機能はリリースしない
    • 基本的にどのインスタンスでも相互に利用可能とし、インスタンスの内側に閉じない機能設計をする
      •  misskeyの"連合なし"公開範囲や(連合しない)チャンネルは実装予定がない
    •  通報やモデレーション機能などは除く
  • ローカルタイムラインは無い
    • 連合するチャンネルをローカルタイムラインのようにして、別のインスタンスのローカルタイムラインを(そのインスタンスから)見たり投稿したりできると良いなとは思っている
    • 大昔(公式インスタンスであった時代)のmisskey.ioはローカルタイムラインを時間封鎖していた時期があり、misskey開発者もローカルタイムラインには問題が多く(少なくとも公式のインスタンスでは)有効にするべきではないという趣旨の記事を書いていたりする*8

 

5. オープンソースであり続ける

前述した通りPulsateはApache2.0ライセンスで配布されている。コードがオープンでも開発がオープンでないこともあるが、Pulsateの開発はオープンに行われている。

 

独立性に関してはPulsateの開発チーム(pulsate-dev)とPulsateに関連する全てを管理するPulsate Projectは完全に非営利かつ独立であり続ける。(Pulsateを利用した)巨大インスタンスの運営団体や法人の傘下に入ることはないし、そうした組織から意思決定に干渉されることもない。意思決定に重要なのはあくまでユーザー本位、分散/連合型SNSとしてどうあるべきかということだけだ。

 

コントリビューターや利用者の数が増え、プロジェクト規模が大きくなった際には透明性の高いガバナンスの導入を計画している。私が今考えている主な取り組みは以下の通り:

  • 開発を計画している機能リストは全て公開する
  • 全ての意思決定は議事録を含め全て公開する
    • 外部の団体との契約も内容を含め全て公開する
  • プロジェクトに関連する全てのプログラムはオープンソースライセンス下で公開する
  • プロジェクトが使用する/受け取る資金は金額、使用用途を含めて公開する

簡単なレポートの形で数ヶ月おきに最近の進捗などを公開するところから初めていくつもりだ。

 

現在時点の目標:

現在時点で考えている目標はこのような感じにしている。

 

長期的(今後5年間で達成したい)目標:

  • 定期的なリリース(おおむね3ヶ月おき)
  • Pulsateを利用したインスタンスの総ユーザー数: 500人以上
  • インスタンス数: 25以上
  • 総ユーザーに対しての(準)公式インスタンスのシェア率: 30%以下
  • コントリビューター(貢献者)数: 50人以上
  • 継続的財政支援者数: 10人以上
    • 収入: 3万円/年

 

短期的(おおむねこの1年〜2年で達成したい)目標

  • v1のリリース
  • コントリビューター数: 20人
  • 総ユーザー数: 100人

 

あまり具体的ではないし、目標も高いのか低いのかよくわからないが、とりあえず私個人としてはこれくらいの目標でいこうと思っている。

 

宣伝: 私たちと一緒にPulsate/Caramelを開発しませんか

現状、Pulsate Projectは他のプロジェクトに比べてかなり小規模だ。アクティブに活動しているプログラマーは実質私1人で、PulsateもCaramelもどちらも私が書いている。

もう1人アーキテクト/レビュワー兼プロダクトオーナー(最終的意思決定者)がいるが、やはり開発者の人手が足りない。

 

注: 現在私ともう一人の開発者は卒業研究が佳境に入っており、(私は)2月中旬ごろまでそこまでプログラムをかけない状態になっている。

 

基本機能(ノート、リノート、リスト、フォロー、タイムライン)についてはPulsateで実装済みではあるものの、その大部分がCaramelで利用できない状態だ。

 

そんな状態ではあるが、プログラム自体は腐らずに保たれている。

misskeyのコードについてコントリビューターが嘆いていたのを見ていたのでかなり丁寧にソフトウェア設計を行っており、単体テストもほぼ全てのロジックについて書かれている*9

 

ActivityPub関連の実装はまだほとんど行われていないが、既存の処理を適切に呼び出せば実装はできる状態にはなっている。

また、JSON-LD(ActivityPubのサーバー間通信で使われるJSONに似たフォーマット)からJSONとの相互変換や、かなり実装が難しいとされるリクエストの署名の処理周りは、最近ActivityPub実装自作の世界で注目を集めている Fedify を利用するつもりだ。

 

github.com

もともとはDeno向けに書かれたようだが、Web標準APIを利用しているためPulsateが使っているNodeでも利用可能なので非常に助かる。

こうした便利なライブラリを利用することで開発にかかる手間を減らすことができ、結果的にユーザーに価値を提供し続けることのできる力を生み出すことができるのではないかと考える。

 

さて、見出しの通りPulsate/Caramelの開発に参加しませんか。

(開発以外にもアイデアを提供したり、コミュニティーサーバーで発言したりするなどの貢献方法がある。)

 

プロジェクトや開発に興味があるという方はコミュニティーサーバーにぜひ。

discord.gg

ソースコードを読んで全体の様子を見てみたいという場合は GH: pulsate-dev/pulsate にコードがある。

github.com

あまり発言はないがFediverseにもアカウントがある。

mi.growthers.dev

TwitterかFediverseで #pulsate をつけて投稿していただければ(筆者が)何かしら反応する。

(Fediverseの方はnotestockをお使いならばすぐ反応できると思う)

 

ActivityPubに関連したアプリケーションを書いてみたい人、

つくりたいものが特にないがWebアプリ開発がしたい学生(今まで開発に関わった人は全員学生)、

"misskey 連合 つらい うんざりザリガニ" *10 という感じの人は Pulsate Project にぴったりな人*11だと勝手に思う。

 

まとめ

  • Pulsate/Caramelという"連合志向"な分散/連合型SNSを開発している
  • おもにユーザー数1000人以下のインスタンスで使われることを想定している
  • ユーザー中心の(UI)設計をする予定
  • ソフトウェア自体のドキュメントを整備し公開する
  • 高い相互運用性を維持し、どのインスタンスにアカウントがあってもシームレスに繋がれる状態を目指す
  • プロジェクト規模が拡大したら透明性の高いガバナンスの導入を行う

 

以上だ。

Fediverseの世界がより良いものになることを願って。

 

*1:Indigo la end のアルバムの名前に由来するらしい

*2:ActivityPub上での投稿のオブジェクト名もNoteなのでそちらに影響を受けているとも言える

*3:公式クライアントを使わないという選択肢も尊重するため

*4:いまあるドキュメントをどのように維持していくかが喫緊の課題になりつつある。

*5:開発開始した2023年9月頃はBlueskyなどのActivityPub以外のプロトコル実装が乱立しており、ActivityPub以外のプロトコル実装も行う必要性が0ではなかった

*6:開発者が「連合はおまけ」と発言し物議を醸したことがある

*7:この数ヶ月最大インスタンスの運用者が資金など様々な理由から連合の終了を示唆して批判されている

*8:ソース: https://misskey.io/@syuilo/pages/ltl

*9:バリデーション用の型定義などのテストを書けない部分を含めた全プログラムに対するカバレッジ: 49.54%

*10:元ネタ: https://blog.3qe.us/entry/2024/04/19/200735

*11:Pulsateはmisskeyの連合関連の不満やソフトウェアに対する考え方に異を唱える会話の中で生まれた

新年の抱負2025

2025年の抱負。遅すぎるというのはそうかも。
記事というよりメモになりそう。

技術関連の雑多

  • 新しい言語を習得する
    • 就職したら何か一つは必然的に習得する必要がありそう
    • すでに習得済みの言語の再入門もやりたい
  • 雑にプログラミングするのをやめる
    • 計画性を持つ/やることを明文化して不連続にタスクに取り組めるようにしたい
    • ドキュメントを上手く書けるようになりたい
      • 文字を打つのが苦手なのでそれをどうにかしなきゃ...
    • Pull Requestを立てる時にしょうもないミスをした状態のコードを上げるのをやめる
    • 作業メモ.txtがあってもいいかもしれない
      • 卒業研究ではそうしている
  • 物事を抽象的に考えられるようになる
    • ソフトウェア設計/アーキテクチャ関連の理解に手こずったことがあるのでだいぶ苦手意識が強い
      • 抽象的な概念を適当な例をつけて具体化した上で考えるようになれれば達成できそう?
    • 結局慣れ(いいえ)
  • 技術記事というか今やっていることを記事にできるようにしたい
    • ほとんど書いたことがないのでどれくらい難しいことなのかがわからない
    • 毎月今月やったことリストみたいなのを書いてもいいかもしれない
      • 日記レベルにしてしまうと面倒すぎてやらない気がする
  • 正しく批評できるようになる
    • これが苦手なので技術や製品に対する議論に参加できない
      • 変なことを言いたくないので当たり障りのないことだけ言おうとして結局黙っているように見える
    • そもそも会話するのが苦手なのでそこから改善する必要がある?
  • フロントエンドをまともに書けるようになる
    • ずっとほぼバックエンドだけしか書いてこなかったのであまり得意ではない
    • バックエンドとフロントエンドの開発を両立させるのどうやるんですか?私はわかりません
  • 他人が書いたプログラムを読めるようになる
    • 自分が書いたプログラムすら読めない時がある
      • メモとかドキュメントがないプログラム位しか読んでないからかも?
    • そのせいもあって再実装か再設計しかしてない
      • やめたい(やめたい)
  • 今やっているOSSプロジェクトをまともにする
    • 外部コントリビューターを迎えたい
      • 私の直接の知り合いでないという意味
    • 開発速度が遅いのでその辺りをどうにかしたい
      • おもに私のモチベーションと技術力と単純に必要な実装量が多すぎるだけ
      • 試算すると同じようなプロジェクトと同じ規模になるまで30年かかるらしい,,,

各種人生周り

  • 話のタネを作る
    • 食事会とかで話すネタがあんまりないのでいくつか作っておく
    • プログラミングのことですら話すことないのにそれ以外のことで話すことなんかあるわけないよ!
  • 常人的な趣味を作る?
    • 現時点で趣味と言えそうなモノ:
      • プログラミング
      • 旅行
  • 新しいコミュニティーに入る or 作る?
    • そこまで必要ではないかもしれない
    • これまでの数年間でほぼ毎年新しいコミュニティーを作るか参加するかしてきた
  • 集中力を長く維持できるようにする
    • 1Hくらいで集中が切れてしまうのでどうにかしたい
    • 周りの環境音が影響してそうな感じがある
      • 今は音楽なりなんなりを流して誤魔化しているけど、根本原因の解消にはならない気がする
  • 英語が読めるようになる
    • 英検2級は持ってるけどそんなに読めない
    • 技術文書(おもにOSSのリファレンス)を読むのを諦めることがあるのでやめたい
    • 読むだけでなく話す/書く能力もあげたい
    • 利用可能な語彙が少ないので思考を単純にしたい時に英語を使うのでもう少しできるようになりたい

終わり 適当に更新するかも