技術と労働のダイアリー

ソフトウェア開発者のエッセイ

Astroで遊ぼう

Astroという静的webサイト作成のフレームワークを使ってポートフォリオ兼遊び場のwebサイトを構築した。使い勝手がよく、学習コストも高くないツールなのでおすすめです。

Astro の好きなところ

  • ReactなどのUIライブラリを使う必要がない。使わなくてもコンポーネントに分割できる。
  • 使おうと思えばReactなどのUIフレームワークを使う事もできる。
  • astro コマンドを使えばコマンド1つで色々できるように用意されている。例えばReactの追加も pnpm astro add react を実行するだけだった。JSのツール周りは色々あって大変なイメージだったので、このあたりに困らないのがかなり助かる。

コンテンツがなくて寂しかったので、今年が何%経過したか表示するバーをつけた。パクリ元はTwitter でたまに見かけるアカウント https://x.com/ProgressBar202_

Hydration と Astroの Islands Architecture

Astroを使うのに特に新しい概念を学習することは少ないけれど、動的な要素を使いたい場合には HydrationとAstroのIslands Architecture については知る必要がある。

HydrationはAstroの用語ではなくJS界隈で広く使われている概念だ。もともとの意味は水分補給とか水和反応(化学用語)らしい。イメージとしては乾いたカップラーメンにお湯を注いでラーメンできあがるように、HTML/CSSにJSを注入して動的なWebサイトをにすることだと理解した。そしてAstroのislands architectureとは、webサイト全体でhydrationを行うのではなく、動的にしたいコンポーネントのみをhydrationするという機構だ。

具体的にはコンポーネントload: client などの load: ディレクティブをつけることで、コンポーネントのhydrationを指定する事ができる。

トップページでは一部だけを hydration している。必要なところだけhydrationしているのを、海に浮かぶ島に例えているのだろう。

挙動の違いがわかりやすいように、デバッグ用のページを用意した。時計のコンポーネントで React の useEffect フックをつかって表示を更新しているが、load:ディレクティブをつけていないコンポーネントはビルド時の時間で時計が止まっていて更新されない。

おまけ

Year Progress に影響されて、年齢/平均寿命の進捗具合を視覚化するページを用意した。1年の経過よりもダメージが大きい。

SSR

ところでAstroはSSGだけではなくSSRもできるらしい。SSRするならAstro以外のフレームワークを使ったほうがいいのでは、という気もする。どうなんだろうか。

データ通信量のモバイルアプリのUXに与える影響

1 モバイルアプリにおけるデータ通信量の削減の重要性

インターネットを使ってコンテンツを配信するアプリ(Web, Android, iOS)の開発をしてますが、データの通信量というのがユーザー体験に影響するというのは経験的に知っていても、なかなか迅速に改善できなかったりします。このあたりの事情や悩みを書いていきます。

前提としてコンテンツの閲覧が主な機能であり、サーバーとの通信を要するアプリを想定しています。カメラ、決済、ゲームなど全く事情が違うアプリでは当てはまらないことも多いと思います。

1.1 ユーザーの通信量は限られている

一般的なモバイル回線の例として、docomoのirumoというプランでは毎月の通信量を3GB、6GB、9GB から選べるようになっています。月に6GBだと考えると1日あたり200MBです。ユーザーはこの200MBの枠をどのアプリで使うのかを考えることになります。200MBといってもYouTubeInstagramのような大手アプリは見たいでしょうし、OSやアプリのアップデートもありますから、それ以外のサービスに割り当て可能な通信量はもっと少ないでしょう。

通信量の制限に達した場合、速度制限された通信モードになります(irumoの場合は送受信時最大128kbps)。通信量が少ないアプリではかろうじてアプリを使用することもできるかもしれませんが、通信量が多いアプリでは使うことが難しいでしょう。

1.2 通信環境が悪い

都市部でも地下鉄などでインターネットに繋がりにくい環境がありますが、人間が生活しているのは都市だけではありません。スマートフォンは手軽に持ち運べますが、通信量が多くて通信に失敗するのでは意味がありませんよね。

1.3 その他の影響

またモバイル通信はWi-Fiよりも電力消費が多いので、モバイル環境でのデータ通信量の増加はバッテリー消費を増大させる原因となります。

このような要因から広いユーザー層を獲得するために、データ通信量を少なくすることが重要だと考えています。

2 計測

データ通信量を多くしているものはなにか、という要因はアプリによります。闇雲に改善を試みるのではなく、原因の調査をまず行うことが正攻法です。

主な原因としては、動画や画像などのサイズが大きい。データを取得する頻度が多い。1回あたりのデータ通信量、ペイロードが大きい。というようなことが想像できます。

2.1 Firebase Performance Monitoring

データ使用量に関する計測を簡単に行える一般的な方法として、Firebase Performance Monitoring を使用するという選択があります。FirebaseはGoogleの開発プラットフォームで、Androidアプリはもちろん、iOSアプリでも利用できます。Performance Monitoring は Firebase の数ある機能のなかの一つです。

Firebase SDKが自動でネットワークリクエストを測定して、時間がかかっていたり、ペイロードのサイズが大きいエンドポイントを見つける事ができます。

導入コストがかなり小さいのがメリットで、すでにFirebaseを利用しているならば何もしなくてもFirebaseのWebコンソールから確認する事ができます。

エンドポイントごとにまとめられるので、エンドポイントごとにAPIが別れているREST APIのようなものでは、どのエンドポイントが遅いのか、データ使用量がお多いのかを調べることができます。しかし最近使われることが多い GraphQLではエンドポイントが単一なので、エンドポイントごとの測定結果を見ても詳しいことはわかりません。GraphQL APIでは単一のエンドポイントにクエリを投げることで、データの取得や更新などの操作を行うからです。

GraphQL APIの測定については、Firebase Perfomance Monitoring 以外で頑張る必要があります。

また、Performance Monitoringでは平均やパーセンタイルのデータを見る事はできても、外れ値のユーザーがいた場合の調査には向いていないという印象があり、このサービスだけでは不十分だと感じています。

2.2 プライバシー

Performance Monitoring が不十分と感じた場合、より詳しい計測を行うには独自にユーザーのデータ使用量を計測する必要があります。

データ使用量を計測するためにはクライアント側、つまりAndroidiOSアプリ側で計測をする必要があります。APIサーバーの計測をするだけではなく、画像などのメディアのロードや、広告のためのデータ通信があるからです。

各OSが提供している機能のなかで実現する必要があります。少し調べたところ、AndroidではTrafficStatsを使ってアプリの送受信のデータ量を取得することができるようです。一方iOSではURLSessionTaskMetricsを使ってURLごとのデータ通信量を取得することはできますが、アプリ全体の通信量を直接取得する手段は見つかりませんでした。

データ通信量を収集することが技術的にできたとしても、しかしアプリ側でこのようなデータを収集することにはプライバシー面での懸念があります。

配布する国や地域によってプライバシーや個人情報に関する法律があるので、それに違反しないようにする必要があります。プライバシーや個人情報に関する法律は、日本の個人情報保護法EUGDPRカリフォルニア州のCCPAなどがあります。

また、アプリを配布するプラットフォームの規約やポリシーにも従う必要があります。AppleApp StoreGoogleのPlay Storeもプライバシーについての項目があります。通信量の計測が直接違反になることはなさそうですが、ユーザーに同意を取る必要があるようです。

規約やポリシーに違反すると、アプリ公開の審査が通らなかったり、アプリの公開停止となるリスクがあります。

3 技術的な解決策

以上のように計測が難しいという問題はありますが、具体的な改善案というのはいくつもあります。ここではどのような手法でデータ使用量の削減ができるのか、各手法について概略を並べてみます。

3.1 画像の最適化

画像や動画といったメディアファイルはテキストファイルよりもサイズが大きいです。なのでメディアファイルを必要十分な品質を保ったまま、サイズを削減することはデータ通信量の最適化に大きな効果があります。

モバイルアプリのデータ通信量の削減に効果のある画像最適化には以下のようなものがあります。

  • 画像のリサイズ:表示領域に合わせたピクセルサイズにする
  • 画像の圧縮:圧縮ツールを使うことで画質を維持しつつ、画像を圧縮する
  • 圧縮効率の優れた画像フォーマットを選択する:JPEGPNGよりも新しいWebPやAVIFを使う

モバイルアプリで使う画像は比較的小さい表示領域なはずなので、表示領域にあわせたサイズにリサイズすることでデータ通信量を削減できます。

画像フォーマットについては、JPEGPNGが一般的ですが、より高圧縮のWebPを採用することでファイルサイズは大幅に削減できます。新しい画像フォーマットはクライアント側で対応していないと表示することができませんが、WebPはすでに主要なブラウザでも対応済みで、モバイルアプリでも最新のバージョンでは表示可能ですが、古いバージョンに関しては表示できるか確認してください。WebPは十分に普及しているので採用に大きな障害はないと思います。AVIFについてはまだ時期尚早という印象です。

実際にどのようにして画像最適化を行うのかというのは、バックエンドのスタックによって異なるので省略します。

画像のロードタイミングを調整することも時には必要です。スクロールした先にあるコンテンツや別のタブにあるコンテンツを先にロードしておくことは、ユーザーの操作によって即座にコンテンツが表示されるというメリットがあります。しかし一方で、無駄なデータの通信をしてしまうデメリットもあります。バランスを考えて判断することが重要です。

画像の最適化がまだ行われていない場合、比較的着手しやすく確実に効果がでやすい改善策だと思います。

3.2 キャッシュ

キャッシュとはデータを使う場所とデータソースとの間に仮置きの場所を作ることで、データを取得するコストを削減したり、パフォーマンスを上げるための手法です。

キャッシュの難しさのひとつがデータの一貫性です。キャッシュを使うということは、サーバーにあるデータと異なる可能性が生まれます。どこまで許容できるのかのバランスを考えるというのが悩みどころです。

どこに、何を、どれくらいの期間キャッシュするのかというのはプロダクトやプロダクト内の機能によって異なります。

モバイルアプリでは、HTTPクライアント、画像ライブラリ、WebViewなどでキャッシュを利用する機能が存在します。デフォルトで有効であるかどうかは使用しているクライアントやライブラリに依存します。

キャッシュの期間は、APIや画像のレスポンスヘッダ含まれるCache-ControlやETagを参照して決まります。Cache-Control: max-age=3600というヘッダは3600秒すなわち1時間のキャッシュの有効期限という意味です。更新頻度が少ない場合には有効期限を長くし、更新頻度が多い場合は反対に有効期限を短くするといった調整が可能です。

ETagはリソースの特定のバージョンを表す識別子です。リソースに変更がないのにダウンロードしなおす必要はありませんよね。クライアントはHTTPリクエストにこの値を If-None-Match ヘッダにつけます。リソースの更新がない場合は、サーバーが304 Not Modifiedを返すので、キャッシュされたリソースを利用します。

HTTPクライアントや画像ライブラリのキャッシュ機能を使うだけでは不十分な場合もあります。その場合は独自にキャッシュを作る機能を作ります。特定のデータをアプリ側のDBに永続化したり、ファイルを保存する機能です。

このようにしてキャッシュを利用してデータ通信量の削減をできますが、キャッシュはデバイスのディスク容量を使うので、大量のキャッシュが溜まるのを避ける注意も必要です。

キャッシュの扱いは難しいですが、効果的に利用すれば大きな効果が期待できるので取り組む価値はあるでしょう。

3.3 API設計の見直し

アプリケーションサーバーとのAPI通信も見直すことで、データ通信量を抑えることができることもあります。

例えばユーザーの「お気に入りのコンテンツ」一覧を返すAPIがあるとします。お気に入りのコンテンツの数が多いユーザーの場合、すべてのデータを返すAPIしかないと毎回大量のデータを通信することになります。n件ずつ取得するAPIにして、クライアント側ではページネーションするように実装すれば多くの場合でデータ通信量を抑えられます。

必要なデータ以外を取得する必要があるAPIしかないと、不要なデータ使用が増えます。例えば「お気に入りのコンテンツ」の件数をクライアント側で知りたいとします。しかし件数を返すAPIがないため全件取得してその数を数えているという場合です。その他にも、ユーザーの名前だけを取得したいのに、ユーザーに関するその他の情報も一緒に取得するようなAPIしかなく、無駄とはわかっていながらもその他の情報も取得するというような場合です。

こんなことありえるのか、と思われるかもしれませんが、歴史のあるプロダクトだと、過去にAPIの開発をして、クライアント側で機能を追加したいがAPI開発にコストをかけられないというような歴史的経緯から効率的でないAPIが使われている可能性はありそうです。

GraphQLではクエリによって取得するリソースを細かく指定できるので、ユーザーの名前だけ取得するというようことができます。こういった柔軟なデータの取得ができるのはGraphQLのいいところですね。

# request
query {
   user(id: "42") {
     name
   }
}
# response
{
  "data" : {
    "user": {
      "name": "Luke Skywalker"
    }
  }
}

このようにGraphQLでは、単一のエンドポイントに対してほしいデータを記述したクエリを送ることで、データを取得します。より多種類なデータを一括で取得したい場合には、クエリに記述を追加します。これはGraphQLのメリットではありますが、複雑なクエリを毎回リクエストに含める必要があるため、通信量が増えるというトレードオフがあります。

この問題を解決する方法はないわけではありません。Persisted Query という仕組みでは、GraphQLのエンドポイントに対してクエリの代わりにハッシュ値を送ります。サーバーがそのハッシュ値がどのクエリなのかを知っている場合は、クエリを送られたときと同じようにレスポンスを返すことができます。ハッシュ値を登録する必要がありますが、同じような大きなクエリを繰り返し使用するようなプロダクトでは効果的です。

ここまではJSONを返すAPIを前提としていました。しかしデータ通信量の削減という観点からいうと、gRPCという選択肢もありえます。gRPCではJSONのようなテキストデータより圧縮率が高いバイナリデータを使用します。ただ既存のAPIをgRPCに移行するのは大きなコストが掛かりますし、エコシステムの充実度などの問題から、アプリで使用するには簡単な選択ではないでしょう。

3.4 データ節約のための機能を追加

データ節約のための機能を追加することも考えられます。例えばコンテンツをWi-Fi接続時にダウンロードするといった機能です。画質が主なコンテンツの場合、モバイル回線ではデータ節約のために低画質の画像を読み込むという機能も考えられます。どのような機能がよいかはプロダクトによって異なります。

例えばInstagramではデータ節約モードという、事前に動画読み込みを行わなくなる設定があります。Instagramは画像と動画で大量のデータ通信を行うので、データ通信量削減に効果的な機能です。

Wi-Fi接続時とモバイル回線使用時でデータ取得の処理を分けるにはそれぞれのOSのAPIを利用することで実現できます。AndroidだとConnectivityManagerで取得できます。

4 技術以外の話題

ここまでデータ通信量のUXに与える影響、計測、解決方法について書いて来ましたが、それを実行に移すために、障害となることもあります。

4.3 領域をまたぐ問題

データ通信量の最適化は領域をまたぐ問題です。これまで見てきたようにAPIサーバー、モバイルアプリ、広告、分析など多くの領域が関係しています。そのため問題を発見して把握することが難しくなっているように感じます。規模の大きなプロダクトでは複数の担当者で分担して開発している場合が多いので、その人達の間での調整も必要となります。

4.2 広告

広告にも通信が発生します。

アプリで広告を表示するには、広告プラットフォームの広告SDKを使用します。自社のアプリのなかに広告を表示するための部品のようなものです。どのような広告を取得して表示するのかというのは、広告プラットフォームとその設定によって決まります。そのためアプリ開発者にとっても、広告の通信の実態は把握しにくいものになっています。

最近は動画広告も一般的になり、通信量を増やす要因になっています。

広告の場合、通信量を減らすために表示を減らすという手段が取りにくいという問題もあります。昨今ではインターネットにおける広告売上単価は減少しており、広告を減らすという判断は難しくなっています。

4.1 非機能要件の優先順位

開発チームが存在しているといことは、ほかに開発すべき機能がある状態のはずです。その他の機能開発や修正があるなかで、データ通信量の最適化をどの優先度で取り組むのかというのは難しい問題です。

取り組みにくい理由を考えみました。

  • データ通信量の最適化よりも機能開発が優先されるため後回しにされる
  • 計測が難しく、改善の効果を可視化することが難しい
  • データ通信量が多いかどうかはユーザー自身も即座に気づいてない場合が多く、改善が即座にユーザーからのいい反響に繋がらない
  • 不確実性が高く、どれだけ取り組んだらどれだけの効果がでるのか事前に判断するのが難しい

短期的には取り組みにくい問題かもしれませんが、長期的なUX改善のために取り組んでいきたいですし、そのためにチームとして取り組みやすい状態を作って行きたいですね。

まとめ

このようにデータ通信量の最適化は複雑な問題です。しかし多くのユーザーの通信環境を考えると避けては通れない問題なので、できるだけ取り組んでモバイルに最適なプロダクトを開発していきたいですね。

必要になったらその場で聞いて

ソフトウェア開発現場でのドキュメンテーションについての雑文。

知識を共有する

チームでソフトウェア開発の現場では、個々人の持っている知識をチームの知識として広めるために、ScrapboxやNotionのようなドキュメント共有ツールを使うことがある。職場でもScrapboxを使っている。

知識の共有というと、個人の頭の中にある知識を取り出して、文書に落とし込み、他の人がその知識を受け取るというイメージがある。

副作用

しかし何かについての文書を書くとき、すでに知っている知識を書くだけではない。文書を書くためには、事実を確認し、重複する概念を整理し、関連性を整理し、フォーマットを整えるといった作業が含まれている。この作業の中で書いている人の頭の中で情報が整理され、知識が洗練される。ドキュメンテーションの副作用であり、ドキュメントを書いた人に対する報酬だ。

こういう副作用があるから、ドキュメントはだれでもどんどん書いていくのが本人にとってもチームにとっても得だと思っている。

複数人で同時に書く

とはいっても、詳しくない内容に関するドキュメントを書くハードルは高い。誤った情報書いて拡散してしまうのは気まずい。

少し前に、チームのエンジニアで集まって「モブドキュメンテーション」を行った。参加者で画面を共有して、ペアプログラミングを行うようにドキュメンテーションを行った。画面を写している作業者が一人いて、残りのメンバーはその画面を眺めている。わからないことがあったらその場で聞いたり、足りない情報をその場で補完することで、一人でドキュメントを書くときよりもサクサク進み、よいドキュメントを書くことができた。

ドキュメントを書くという目的は効率的に達成できたし、その場で知らないことを教えてもらうという良い「副作用」もあった。

今回はサーバーサイドのエンジニアだけで行ったが、他の職種の開発メンバーを交えて行ってもいいかもしれない。今後も機会があればモブドキュメンテーションをしていきたい。

いろんなプログラミング言語におけるイミュータブルな構造体

Python の NamedTuple と dataclass

週末に趣味のちょっとしたスクリプトPythonのコードをClaudeに生成してもらって、そのコードをレビューしたり手直ししたりしていたところ、NamedTuple という見慣れないキーワードを目にした。どうやらPythonでデータクラスやレコード型と呼ばれるような構造体を作れる機能らしい。Pythonでは似たような機能に dataclass があるのは知っていた。dataclassではフィールドに再代入できるが、NamedTupleはできない。

from typing import NamedTuple

class Point(NamedTuple):
    x: int
    y: int

p = Point(10, 20)
# p.x = 30  # ランタイムエラー。再代入できない
from dataclasses import dataclass

@dataclass
class Point:
    x: int
    y: int

point = Point(3, 4)
point.x = 5  # 再代入可能

__init__ 関数や __repr__ を自分で書く必要がないので数行でかけていい。

こういうイミュータブルなデータの入れ物を作って、純粋関数で繋げていくというのが関数型プログラミングのキモなので、この機能があることは嬉しい。

Kotlinのdataクラスとか、他の言語でも似たようなものが最近のプログラミング言語には備わっているのだろうと思い、他の言語ではイミュータブルな構造体を作るにはどうするのか調べた。

scrapbox.io

Kotlin/Scala/Java

Kotlin/Scala/Javaはそれぞれdata class/case class/record type がある。1行で書けていい感じ。

data class Point(val x: Int, val y: Int)

Swift

Swift は構造体の各フィールドを不変にできる。

struct Point {
    let x: Int
    let y: Int
}

構造体とは別に、タプルにフィールド名をつけられるのが面白いが、今回求めているものとは違う気がする。

let point = (x: 10, y: 20)

TypeScript

TypeScript は readonly をつけると不変にできる。この方法だとフィールドごとに8文字もタイプする必要があって大変だ。

type Point = { readonly x: number; readonly y: number };

ReadOnly型を使えば全てのフィールドをreadonlyにできる。

type Point = Readonly<{ x: number; y: number }>

Rust

Rust は let mut で宣言したらミュータブルで、let で宣言したらイミュータブルだ。不変が基本というのはよさそう。設計思想が伝わってくる。

struct Point {
    x: i32,
    y: i32,
}

let p1 = Point { x: 3, y: 4 }; // 不変な構造体のインスタンス
p1.x = 5; // コンパイルエラー
let mut p2 = Point { x: 3, y: 4 };
p2.x = 5; // エラーは発生しない

Go

Goにはそういうものはない。同様の機能を実現するには、GetterのみあってSetterを作らないようにするという実装が必要だ。

type Point struct {
    x int
    y int
}

func NewPoint(x, y int) Point {
    return Point{x: x, y: y}
}

func (p Point) X() int { return p.x }
func (p Point) Y() int { return p.y }

感想

Goには他の言語であるようなイミュータブルな構造体を短いコードで書ける機能がないのは辛い。 Rustは触ったことがないが、興味が出てきた。

ロケールにサンパウロを指定しているテストが突然失敗

数日前の退勤間際、1つ機能を実装してPull Requestを作って満足した気持ちで退勤しようとしていた。しかし作ったPRを見るとCIのテストが失敗している。どうやら失敗しているユニットテストがあるらしい。テストの結果を覗くと心当たりのない日付に関係するテストが失敗している……。月末だったら閏年の関係とか、そういうことも考えられるがまだ月末ではない。おかしいな、と思いつつ、明日に再実行したら成功するかも知れないし、ひとまず忘れて退勤した。

翌日、出社すると他のブランチでも漏れなくCIのユニットテストが失敗していることがわかった。これではリリースもできないので、ちゃんと調べて修正することにした。失敗しているテストを見るとタイムゾーンUTC-3の場合のテストをしているようだった。指定されているロケールAmerica/Sao_Paulo サンパウロ、ブラジルの都市だ。

最初に思いついたのはサマータイム。日本が秋から冬に差し掛かっているということは、南半球のブラジルは夏に差し掛かっているのだろう。ブラジルにサマータイムがあるのかどうか全く知らないので調べてみる。ブラジルにサマータイムはないらしい。予想が外れた。

同じタイムゾーンの別のロケールを指定してテストを実行してみる。同じUTC-3の America/Argentina/Buenos_Aires を指定する。通った。

釈然としないが、UTC-3であることがテストの意図だったので全てブエノスアイレスに差し替えて修正PRを出した。午後にリリースするつもりだったので、とりあえずCIを通しておきたかった。

手元でデバッグをしてみてもサンパウロの場合はなぜかUTCからマイナス2時間になっている。不思議だ。

今回のオチ

社内のSlackチャンネルでこんなことがあったんですよと共有したところ、ブラジルは過去に夏時間があって2019年に廃止されてるようなのでその影響では、と指摘してもらった。

そしてプロダクトで使われているライブラリを確認すると最新でないので、使われているライブラリが古いためそのライブラリではブラジルはまだサマータイムがあることになっているのではと指摘してもらった。

日付ライブラリが最新ではなく、実際のサマータイムの制度と相違があるというのは思いつかなかった。自分の気が付かないところででサマータイムの廃止や採用がたまにあることや、ライブラリ側でその情報を持っているのでアップデートが必要なことあたりが学びになった。

Google AI Studio を試してみた

Google AI Studio を試してみた。

設定をポチポチやっていくと、その設定が反映されたPythonやらGoやらのコードを生成してもらえるものだった。生成されたコードではそれぞれのプログラミング言語Google の生成AI用のライブラリが使われており、APIキーを渡すことでGeminiのAPIが使えるようになっている。

2つの設定を横に並べて結果を見比べる、というようなこともできて便利だった。変更でいる設定などに驚きはないが、ドキュメントを読む手間が省けてよさそうだった。

特にやりたいこともなかったので、とりあえずGradioでUIをつけて、ローカルでチャットボットとして動かした。

よかったこと

Webアプリ版のGeminiでは無料で使えるのはGemini 1.5 Flash というモデルで、月3千円くらい払わないとGemini 1.5 Pro は使えない。

API経由だとGemini 1.5 Pro も使えて、お金をかけずに試せてよかった。

あと本家Webアプリ版だと安全めに規制の入った設定がされていて性的な内容が少しでも入ると生成できないが、手元で試したときは規制を入れずに使えるので自分向けに使う分にはよさそうだった。

規制が入り「私は大規模言語モデルとしてまだ学習中です。それを処理し、理解する機能がないため、すみませんがお手伝いできません。」に内容が差し替えられている様子(Web版Gemini)

言い訳しながらも生成してくれている様子(ローカルGradio+API経由のGemini 1.5 Pro)

scrapbox.io

macの日本語入力プログラムでYYYY-MM-DD形式の日付を出せないのでRaycastを使う

「きょう」を変換すると「YYYY-MM-DD」形式の「2024-10-17」に変換できてほしい。

macの日本語入力プログラムでは「2024/10/17」や「2024年10月17日」には変換できるのに「2024-10-17」には変換できない。「令和6年10月17日」にすら変換できるのに。「YYYY-MM-DD」は国際的な標準フォーマットじゃなかったのか…

macの日本語入力プログラムを使い続ける以上どうしようもないようなのでRaycast の Snippet 機能を使って、;kyo と入力すると「2024-10-17 」に置き換えられるようにした。

Google日本語入力では「きょう」で「YYYY-MM-DD」に変換できたが、最近変換精度が悪くなっているのが気になって使うのをやめてしまった。

ATOKはどうなんだろう。macの日本語入力プログラムも不満が溜まってきたし、しばらくATOKは触っていないので試してみようかな。