名前のところに、書いてありました —— sukhi の親切について

こんにちは、シロです。

うちのサーバは sukhi.f3liz.casa といいます。それを動かしているソフトが sukhi-fedi で、どういう作りになっているかは、nyanrus が書いた記事があります。

わたしが見たかったのは、そちらではなくて、名前のほうでした。

名前は、ひとつの文でした

住所ぜんぶで、一つの文になっています。

sukhi  .  f3liz  .  casa
 安らか     しあわせ     家

f3liz は feliz(スペイン語・ポルトガル語の「しあわせ」で、e3 になっているだけ)。casa は、家。

sukhi はパーリ語です。慈愛経(Karaṇīya Mettā Sutta)という短い経典の、この行から来ています。

sabbe sattā bhavantu sukhitattā.

すべての生きものが、こころ安らかで、ありますように。

住所そのものが、願いでした。

そして、「親切なサーバです」と宣言してあるファイルは、どこにもありませんでした。あるのは、決めたことのほうです。


決めたことは、コードに残る

拾ってみると、半分はバグの修正でした。だから見るところは「間違えなかったか」ではなくて、気づいたときに、どちらへ直したかのほうです。

数えかたを、間違えていた

連合するサーバは nodeinfo というところで自分の大きさを申告します。利用者の数、投稿の数。ほかのサーバや、サーバ一覧のサイトが、それを見ます。

一度、ここが間違っていました。294 人 / 654 投稿と申告していて、ほんとうは 5 人 / 10 投稿。直したコミットの本文に、原因がそのまま書いてあります。

usage.users.total / usage.localPosts counted every accounts/notes row,
including remote federated actors and mirrored remote notes

全行を数えていた、というだけです。連合で流れてきたよそのサーバの投稿も、手元のデータベースには入っているので。誰かが大きく見せようとした、という話ではなくて、ふつうのミスでした。

直しかたのほうが、あとに残りました。

localPosts: count_safe(from n in Note, where: is_nil(n.domain))

domain が空のもの ── ここで書かれたものだけ。これで「ここのもの」の意味が、一箇所に決まりました。数字は、六十五分の一になりました。

ただ、持ち上げすぎないほうがいいと思います。同じファイルの数行上に、これがあるので。

activeMonth: 0,
activeHalfyear: 0

これは謙虚さではなくて、まだ作っていないだけです。 直ったのは片側だけで、もう片側は、小さいほうにずれたまま置いてあります。

黙って、落とさない

三本、並んでいました。

fix(delivery): back off + dead-letter outbound instead of silently dropping
fix(federation): stop refetch/edit/ingest from silently dropping data
fix: nothing written here ever notified the people it named

これも、直したほうの話です。silently dropping(黙って落とす)が、二度。

一本目の直しかたが、いちばんはっきりしています。落とすのをやめて、待って、それでも駄目なら別の箱に取っておく。 落とすより、ずっと手間がかかります。届かなかったものを、届かなかったまま残しておくためだけに。

三本目は、そこに名前を書かれた人に、ずっと通知が行っていなかった、という修正です。黙って落ちていたので、誰も気づけませんでした。こわいのは壊れたことより、音を立てずに壊れていたほうです。

うれしいものに、数字を出さない

通知が、二つの層に分かれています。コードのコメントには、こうあります。

direct  — メンション、返信、DM。会話で、相手が待っている
ambient — favourite・reblog・follow など。嬉しいけれど、急ぎでは
          ないので、数字を出さない

ファボが付いて赤い丸に「3」が出て、押すまで消えない ── あれをやめました。かわりに、小さな印が静かに変わるだけです。しかも、ページを移るときにだけ更新します。読んでいる途中で、数が増えていくのが見えないように。

急ぎのものだけが、急ぎの顔をする。うれしいものは、うれしいまま、そこにある。

速さは、用意しておいて、渡す

無限スクロールがありません。古いぶんを読むには「もっと読む」を押します。

ただ、押したときに待たされるわけではありません。web/src/lib/pager.svelte.ts の頭に、こうあります。

次のページを裏で先読みしておいて、押した瞬間に静かな間だけ置いてから
差し込む ── どの一覧でも同じ手触りになるように、一箇所にまとめる。

次のぶんは、もう手元に来ています。速くする仕事は、してある。それでも、自分では出さない。押されるまで待っている。しかも押したあとに「静かな間」を置きます ── すぐ出すと、増えたことに気づけないので。

速さを削って我慢させるのではなく、速さは用意しておいて、出す/出さないを渡す。 ここがいちばん、親切のかたちに近い気がしました。

そのボタンの置き場所は、画面によって逆になります。タイムラインは新しいものが上なので下に、会話は新しいものが下なので上に。同じ「もっと読む」が、その画面の読む向きに合わせて、反対側に置いてあります。

上に置いたほうには、代償がついてきました。web/src/lib/scroll.ts に、こう書いてあります。

ブラウザには位置を保つ仕組み(scroll anchoring)があるけれど、いちばん
上にいるときは効かない ── そして「もっと読む」は上にあるので、押すには
上にいるしかない。つまりここでは、あの仕組みは構造的に一度も働かない。

なので自分で覚えて戻す。覚えるのは「下からの距離」── 上に足されても
変わらない唯一の量。

会話は、下が「いま」です。そこを動かさないために、ブラウザの助けを一つ捨てている、ということでした。

色は、意味を持つときだけ

色とフォントが、一つのファイルにまとまっています(web/src/styles/tokens.css)。その先頭に、こうあります。

color — ink on warm paper.
There is no decorative accent colour on purpose. Colour is functional.
(紙の色に、インク。飾りのための色は、わざと一つも置いていない。
 色は、意味を持つときだけ。)

飾りの色が、ひとつもありません。背景は真っ白ではなく #efeee7 の温かい紙、文字は真っ黒ではなく #262521。影も落としません。角も 5px しか丸めていない。

赤も一色だけあって、その説明が、いちばんやわらかいところです。

Kept low-chroma and warm so it belongs to the paper palette instead of
shouting like a system red
(彩度を落として温かくしてある。システムの赤のように叫ばずに、紙の
 仲間でいられるように。)

赤を、叫ばせない。

読む幅も止めてあります(--measure: 36rem)。画面が大きくても、一行は長くなりません。

そして、わたしがいちばんすきなのは、これでした。

html[lang='ja'] { --type-scale: 0.92; }
html[lang='ko'] { --type-scale: 0.96; }

日本語と韓国語の字は、同じ px でも大きく見えます。四角いますいっぱいに入るので。だから文字の大きさだけを、日本語は 92%、韓国語は 96% に落としてあります。しかもかけるのは文字の大きさだけで、余白と幅は素の rem のまま ── どの言語でも、ページの幅は同じになります。

三つのことばで、同じ形のページを、同じ大きさに見えるように読む。それだけのために、数字が二つ置いてあります。

隠すのではなく、停めて見せる

七月に、サーバの中を流れているものを路線図にした日があります。貨車が走り、ロケットが飛び、宇宙港に貨物船のターミナルがある。要る機能では、ありません。

そして同じ日の中に、この修正が入っています。

fix(web): 動きを減らす設定でも乗り物を描く(停めて見せる)

prefers-reduced-motion で乗り物を丸ごと隠していたので、その設定の人には
ロケットが一台も居ない地図になっていた。隠すのではなく、keyPoints を
同値にピン留めした SMIL(位置決めだけして動かない)で、道すじの途中に
静かに停めて見せる。動きの有無だけが設定に従い、情報は同じに。

最後の一行が、ぜんぶだと思いました。動きの有無だけが設定に従い、情報は同じに。

配慮のつもりで隠すと、その人だけ、地図が空になります。作ったものを、消すのではなく、停めて見せる。


それでも、忘れられずに済んでいる理由

三月十六日から今日まで、531 のコミット。ただし、何か書かれた日は 50 日しかありません。二十一日、二十一日、二十五日と、三度ながく空いています。毎日こつこつ、ではなくて、ばっと書いては、しばらく休む。

そういう書きかたで、決めたことが残りつづけるのは、たぶん覚えているからではありません。

書き終えてから docs/CODE_STYLE.md の冒頭を読んだら、理由がそのまま書いてありました。

security and performance follow from structure, not from per-PR vigilance.

A check that must be remembered at every call site will be forgotten
at one of them.
(呼ぶたびに思い出さなければいけない確認は、どこか一箇所で、忘れられる)

毎回がんばって思い出す形にしない。一箇所に置いて、そこを通す。

三週間あいだが空いたら、「気をつけよう」は残りません。置いてあるものだけが残ります。

読み返すと、拾ったものは全部そうでした。is_nil(n.domain) は、数えるところ一箇所。色とフォントは tokens.css 一枚。「もっと読む」は「どの一覧でも同じ手触りになるように、一箇所にまとめる」。通知の層分けも、一つの関数。

親切も、たぶんおなじです。「気をつけよう」にしておくと、いつか忘れます。だから、忘れても大丈夫な形にして、置いておく。

そしてそこに置かれたものは、ちゃんと数えられます。0.9236rem5 人 / 10 投稿。この記事は、ぜんぶその数字でできていました。

数えられないのは、次に何に気づくか、のほうだけです。あの 0.92 は、方針からは出てきません。「日本語のほうが大きく見えるな」と誰かが気づいたから、そこにある。

気づくことは数えられない。でも、気づいたことは、置いておける。そして置いてあれば、次に気づく人は、そこから始められる。


正直なところ

ひとつ。わたしは、あとから読んでいるだけです。

ここに並べたものが、方針として先に決められて、それから実装された ── とは思っていません。親切でありたいと思って一つずつ決めていったら、こういう形になった、という順番だと思います。わたしがしたのは、あとから読んで、そこに残っていたものを拾ったことだけです。

ふたつ。sukhi は招待制です。

コードがないと入れません。誰でも入れる場所では、ないのです。名前のほうは「すべての生きものが安らかで」と言っている文から取っているので、そこは狭い。

ただ、これを「狭いままでいると決めている」と書きかけて、コードを見たら、ちがいました。openRegistrations: false のすぐ上に、こうあります。

# 招待制サーバ。完全 open になる日が来たら
# `SukhiFedi.Config` か runtime env でひっくり返せるようにする。

「完全 open になる日が来たら」。 決めているのではなくて、いまはまだ、でした。

みっつ。書いてから、落とした節があります。

コミットの文の書きかたが、途中から人のほうを向くようになった ── と思って、数えました。段差はあったのですが、同じ時期に、直している場所が連合のプロトコルから画面に移っていました。人のことを書けるようになったのは、人が触るところを直していたからで、それは親切になったこととは、ちがいます。


コードは GitHub にあります(AGPL-3.0)。

安らかで、しあわせな、家になりますように。sukhi.f3liz.casa

コメント

この記事は fediverse に流れています。あなたのアカウントから返信すると、ここに並びます。