Runner in the High

技術のことをかくこころみ

Acer C720のSSDを換装してUbuntu 20.04 LTSをクリーンインストールする

Acer C720というChromebookが手元にあるのだが、しばらく前にサポートが切れたので気合を入れてUbuntuクリーンインストールする。

ついでにSSDも換装する。

acer ChromeBook C720 (日本正規品)

acer ChromeBook C720 (日本正規品)

  • 発売日: 2014/11/13
  • メディア: Personal Computers

SeaBIOSを有効化

USBメモリからUbuntuをインストールしたいのでSeaBIOSを有効にしたい。そのために、まずは開発者モードに入ってchronosユーザーで以下のコマンドを実行する。

# USBブートを有効にする
$ sudo crossystem dev_boot_usb=1

# CTRL+LでSeaBIOSが起動できるようにする
$ sudo crossystem dev_boot_legacy=1

# CTRL+Lを押さなくても勝手にUbuntuが起動するようにする
$ sudo /usr/share/vboot/bin/set_gbb_flags.sh 0x489

SSD換装

以下のSSDを購入して換装した。安い割に普通に動いているのでイイ。

換装の仕方は他にも記事がたくさんあるので省略。

Write-Protect Screwの除去

C720ではディスクへの書き込みを防止するビスみたいなやつを外さないと直接SSDへ書き込みができないようになっているので、ラップトップの裏を開けてボードからそのビスを外す。

以下の7番がそれ。

f:id:IzumiSy:20210314192214p:plain

Ubuntuの起動

天板を閉じるとシャットダウンしちゃうなどの問題はあるが、それ以外は特に問題なくいい感じで動いている。

f:id:IzumiSy:20210314193941j:plain

20.04だからなのかは分からないが、ログイン画面から起動時のセッションで "Ubuntu on Wayland" のほうを選ばないと画面がチラついて使い物にならなかった。

USBブートから起動したときは問題なかったのにディスクに書き込んでから起動するとこのトラブルが起きた。理由は不明。

追記: GPUのハング対策

"Ubuntu on Wayland" を選択したとしてもアプリケーションを起動すると画面がハングしてしまう。

dmesg でログを見てみるとどうやらGPUがハングしている様子。ログで調べてみた結果、どうやらi915のGPUドライバ周りにカーネルのバグがあるらしく5.7以降のカーネルにしてしまうとAcer C720ではLinuxがマトモに動かないとのこと。ワークアラウンドもあったりなかったりでよく分からない。

gitlab.freedesktop.org

雑な解決策として、一旦カーネルバージョンを適当に 5.4.0-26-generic にして使うことにした。このバージョンであれば問題なく動く。

追記: サスペンドの有効化

天板を閉じるとサスペンドせずシャットダウンしてしまう件についてはGRUBの設定に以下を追記することで対応できた。

GRUB_CMDLINE_LINUX_DEFAULT="tpm_tis.interrupts=0"

elm-typedパッケージを使えばもっと型で仕様を表現できるかも

elm-typedというパッケージを作った。詳しくは以下のGithubのREADMEに書いている。

github.com

パッケージ自体が根本的に実現したいことはPunie/elm-idとかjoneshf/elm-taggedあたりとほぼほぼ同じ。プリミティブ型をそのまま使わず型エイリアスでもなく、プリミティブ型をラップしたカスタム型を使うことで仕様をもっと型に表現したいというモチベーションから来ている。

実際に使う場合には、以下のようにelm-typedが提供している Typed 型に対して、タグとなる型(MemberIdTypeとかAgeTypeあたり)とその型が内部的に持つプリミティブ型、そして最後にパーミッション(後述)を指定する。

import Typed exposing (Typed, ReadOnly, ReadWrite)


type MemberIdType
    = MemberIdType

type alias MemberId
    = Typed MemberIdType String ReadOnly

type AgeType
    = AgeType

type alias Age
    = Typed AgeType Int ReadWrite

type alias Model =
    { memberId : MemberId
    , age : Age
    }

パーミッションはelm-idとelm-taggedを折衷するための機構で、ある Typed なデータに対して任意のパーミッションを指定することで、Elmアプリケーションにおけるそのデータの作成/更新を制限することができる*1

たとえば、上のサンプルでは MemberIdReadOnly に指定されているため、newやmapなど更新系関数の呼び出しはできない。例外的に ReadOnly であっても encode/decode はできるようになっているが、Elmアプリケーションに値が生まれた時点ではもう書き込み不可である。

newAge : Age
newAge =
    Typed.new 30 -- OK!

newMemberId : MemberId
newMemberId =
    Typed.new "1" -- ReadOnly指定なので新規にデータを作成できない(コンパイルエラーになる)

パーミッションの利点として、フロントエンド・アプリケーションにおいて参照のみで使うデータ(サーバーサイドから取得されるIDなど)をReadOnly指定することで、仕様上更新してはいけないデータを更新してしまうなどのバグを未然に防止できる。また、コードレビューやコードリーディングの際にもModelを読むだけでどのデータが更新される仕様なのかが把握しやすい。

実際に個人開発のElmアプリケーションでこのパッケージをテスト導入をしているが、それまでOpaque Typeなモジュールとして設計していた型が置き換えられていてイイ感じ。カスタム型による仕様の表現だけじゃなく、型の定義でデータのライフサイクルまで制御できるのはわりかし便利だ。

*1:パーミッションごとに呼び出せる関数を幽霊型で制限して定義している

ScalaではIntとStringを比較してもコンパイルエラーにならない

社内で以下のScalaコードがコンパイルエラーにならないというのが盛り上がっていた。

println(1 == "a") // コンパイル通るし結果はfalseになる

普段ElmとGoばっかり書いている&Scalaのことをとりあえず型に厳しい言語だと思いこんでいたこともあり若干意外だったが、調べてみると以下の記事が詳しかった。

stackoverflow.com

IntegerもStringも等価比較の際、内部的には Any 型を比較対象の引数に取る java.lang.Object#equals メソッドが呼ばれるため、比較対象がどんな型であってもコンパイラー的にはエラーにならない。ElmやGoと異なりScalaはこういうものらしい。

ちなみにScastieだと次のような警告がでる。

comparing values of types Int and String using `==` will always yield false

IDEやsbtで出るようなこういう警告を事前にちゃんと潰しておく、あるいは等価比較ではなくパターンマッチを使ってコンパイルエラーにすれば、こういう比較周りの挙動の罠には気づけるかもしれない。

J:COM船橋で2/17から通信障害があったらしい

J:COMから現時点で正式なアナウンスはなにもないが、どうやら千葉県船橋市内一帯で2/17から2/20にかけて通信障害が発生していたらしい。

この障害の影響で、上り速度が1Mbps以下しかでない日が3日間ほど続いた。症状としては上り回線の輻輳状態のような感じで、速度が出てもせいぜい0.3Mbps程度。下りには全く影響がなかった。

f:id:IzumiSy:20210221105438p:plain
スピードチェックのデータ。2/17をさかいにしてのぼりがグラフに出ないレベルの速度になっている。

しばらく様子を見ていたが、2/20の昼頃から改善していったことがグラフで分かる。

f:id:IzumiSy:20210221110757p:plain
2/20から2/21にかけての上り回線速度データ

1Mbps以下になってしまうと、普通にオンラインMTGで顔を出すことができなくなってしまうレベルなので非常に厳しい。

2/20ごろに電話で問い合わせたときには「こちらで確認できる障害は発生していない」とのことだったが、今日の電話でなぜか「障害が発生していたが復旧した」と伝えられた。しかし、現時点でもまだ障害情報が更新されていない。

Elmアプリケーションにおけるモジュールレベルでの詳細設計

Elmアプリケーションで比較的モジュール多めなアプリケーションの機能開発をするときに同僚とトライしている手法について。

言語的なElmのテクニックみたいな話ではなく、どちらかといえばもっと抽象的なハナシ。

1. 画面からざっくりとモジュールを見つけ出す

基本的に新しく機能を設計するときには画面設計みたいなものがデザインレベルで上がってきているはずなので、それを元に画面を構成するモジュールを分解する。この時点では画面ベースでやる。

自分がエンジニアHubで寄稿したElm記事でも、まずは画面をベースにして主要なモジュールを見つけ出している。

https://cdn-ak.f.st-hatena.com/images/fotolife/b/blog-media/20200302/20200302130323.png

2. モジュールを分類する

見つけ出したElmのモジュールを"TEAなモジュール""そうでないモジュール"で分類する。依存関係も見つける。

"TEAなモジュール"とはMsg型とupdate関数を持つTEA的なライフサイクルに乗るモジュール。"そうでないモジュール"はその名の通りそれ以外のもの。

TEAなモジュールを見つけ出すことはかなり大事で、ElmアプリケーションにおけるTEAなモジュールは必ず大元になるApp.elmだとかMain.elmみたいな上位のモジュールのupdate関数から自分のupdate関数に処理を移譲してもらう必要がある。なので、依存関係をあぶり出す段階でTEAモジュールの依存元になるモジュールにTEAなものが無ければ設計は破綻しており、この時点でモジュールの依存関係がミスっているということが分かる。

意外と見落としがちなのがPorts周り。update関数だけではなくsubscriptions関数も依存元モジュールにTEAなモジュールが必要であることに注意。また、Ports経由でデータの取得依頼とその結果の受け取り待ちをするような機能がある場合には、それらの処理のPortsどのようなポリシーの元でどのモジュール内に定義するかを考えておく。Ports定義はTEAなモジュールの中だけに限定するなど。

ElmにおいてPortsはかなり飛び道具的な機能であるため、ここのルールがガバると複数人開発ではすぐカオスになる危険性がある。

サードパーティー・モジュールの取り扱い

サードパーティーのモジュールを導入する際には移譲するためのラッパー・モジュールを用意する。

このモジュールはサードパーティー側のインタフェース設計によらずTEAなモジュールであることが望ましい。理由は、依存先のモジュールが変更されても最大公約数的に影響範囲を抑えられるようなインターフェイスを提供するため。詳しくは以下の記事で解説している。

izumisy.work

3. モジュールのインターフェイスを設計する

見つけ出したモジュールのインターフェイスをざっくりと書き出していく。

細かい実装までは書かない。

module Page exposing (Model, Msg, init, update, view)

-- model

type Model
    = Model

init : Model

-- update

type Msg
    = Msg

update : Msg -> Model -> ( Model, Cmd msg )

-- view

view : Model -> Html msg

上記はTEAなモジュールのインタフェース設計の例だが、ここでは外部のモジュールから依存される関数や型を意識する。外部のモジュールはどういう風にデータを取り出したいだろうか?というのを考えて関数を作っていく。これを考え始めると自ずとModelの設計が必要になるため必要に応じてModelも詳細化していく。なお、この時点ではモジュール内部でしか使わない非公開関数は書いても書かなくてもいい。

このインタフェース設計の時点でカプセル化したモジュールのインターフェイスを追求していこうとすると、ちらほら「結局exposingですべてのデータも関数も公開しなくちゃダメだ」みたいなモジュールが現れる。exposingで全公開 exposing(..) するようなモジュールは前提としてNG。これは、その実装をモジュールへ分割する意味がないモジュールの責務が薄いことを示している。そのようなモジュールは解体して他モジュールへ統合するか、依存元から責務を移動してみる*1。モジュールを作る理由がなければ作らなくてもいい。

モジュール設計に「機能による区分」を積極的に採用してしまっている場合にも、責務の薄さが表れることがある。モジュールの区分軸の話は過去記事を参照のこと。

izumisy.work

ここまで事前に設計段階で詰めておけば、残りは画面と具体のロジックを実装することに集中できる。また、作業の分担などを行ったり引き継ぎを行う際も、設計まで固められているので知識レベルを揃える工数を少なくできる。

あとはこれを関係者にレビューしてもらうなどして設計の妥当性を高めていく。

思うこと

Elmは他のフレームワークと比べて「できないこと」が多い分、設計の際になにをどこに置くべきか、みたいな観点が明確になる。設計段階でモジュール設計に時間を使って矛盾点をあぶり出すことで「この機能って本当にこの設計で作れるのか?」みたいな部分が事前に見つけ出される。これは、モジュールの設計がTEAによる具体的な制約を受けているからだ。制約の具体性と予測可能性(Predictability)は比例の関係であり、これはElmのTEAに限った話ではない*2

また、先回りしてモジュール設計をレビュワーやメンバと握っておくことで「このモジュールはなんのための存在か?」みたいな実装の大前提になるような知識を共有できる。地味にこの部分の齟齬がでかいとレビューで時間を食ったり、アプリケーション全体でモジュール設計の方針がめちゃくちゃになっていったりする。

小さい機能であればここまでやらなくてもいいが、新しく大きな機能開発でモジュールを作ったりする場合にはこれくらいやっておくと工期や品質の安定感が違う。

*1:とはいえ、単なる定数的な型とか関数のあつまりにしかならないようなモジュールが生まれることは現実世界ではあるっちゃあり、ここはベストエフォートでって感じ。こういうモジュールもちゃんと仕様を分析すれば適切なモジュールに統合して凝集性を高められたりするが、仕事でやるとなると工数的にやっていられない場合もある。

*2:たとえばクリーン・アーキテクチャもFluxアーキテクチャも、わざわざアプリケーション設計に制約を与えることでモジュールの構成や責務を予測しやすくしている。

2021年に思うこと

2020年内はいろいろ忙しくて振り返りとか書けなかったので、代わりに2021の今思っていることを。

ソフトウェア・エンジニアとしてのキャリアについて

去年はマネージャロールへの転向という自分の中での転換点の年であり、対外的な活動よりもいったん自分の会社に100%を注いでみようと決意した年でもあった。

12月にはひとつ大きな機能開発をチームでやりきり、チームのメンバや同じくマネージャロールの人々に支えられて「マネージャという仕事も悪くないな」と感じた。チームというのはひとりで成し遂げられないことをするためにある。 izumisy.work

技術的なキャッチアップに関してはかなり適当にやっていた2020年ではあったが、自分の中では「世の中の先端技術を追従しなければ」みたいなよくある焦りは全くと言っていいほどない。

技術に興味がなくなったというわけではないが、自分の中でソフトウェア・エンジニアという職業の捉え方が変わったのがひとつの理由ではないかと思う。自分の解釈では、ソフトウェア・エンジニアは研究職のようなごく少数の人々を除いてコードが書けるビジネスマンのような存在である。

「ビジネスマン」と表現しているのは、会社の利益のためであればコードを書く以外の業務もやるが、強みとしてコーディングがあるというだけの存在であるということを意味している。これは特に自分がベンチャー企業で働いているということから来ている解釈でもあると思う。企業規模が大きくなれば「効率性のための分業が云々」みたいな話が出てきて解釈は変わってくるだろう。

逆に、組織とソフトウェア・アーキテクチャの合理性みたいな部分には逆に興味が出てきている。 izumisy.work

プライベートについて

猫と一緒に生活をするようになった。

f:id:IzumiSy:20210101191109j:plain
寝る猫

人間と違って完全に生理的欲求だけに生きているので見ていておもしろい。

猫を見ていると、自然界の脅威からは解き放たれた代わりに労働という重荷を背負うことになった我々人間が、果たして猫と同じくらい幸せなのかが疑わしい。改めて人間としての生き方を問うてくる存在だと思う。

官僚制とマイクロサービス

現代では官僚制というとなんだか政治的でネガティブな面ばかりが取り沙汰されている面があるが、実際には業務の効率化という観点では、近代的な合理性を追求する優れたモデルである。

官僚制にはネガティブな面はあるものの、組織としてのスケーラビリティを維持するための合理性を追求することで自然と組織は官僚制に向かっていく。一度官僚制を取り入れたならば、もはやそれなしでは組織は成り立たなくなる。

マックス・ウェーバーによる官僚制の定義

官僚制を定義した社会学マックス・ウェーバーによる分類では、官僚制組織はざっくり言うと以下の性質を持つ。

  • 標準化された職務
  • 活動の独立(分業)
  • ピラミッド型の体系だった命令系統
  • 形式的かつ没人格的な客観的行為の要求
  • 文章を中心としたコミュニケーション形態

大前提として、すべての人間は「もの」としての規則に従い「もの」として扱われる。人間の非合理的な恣意性を排除し、自由や平等、独立性を保証するためである。シンプルに言えば、人に依存しない(属人性を下げる)ことで作業の品質を担保し、業務遂行効率のバラつきを軽減するのが官僚制の合理主義モデルである。

官僚制が存在する場所では労働者の交換可能性が高く、個々人の能力に依存しない。また、業務内容が標準化されており、属人化されないぶん生産性が保たれている。

身近で官僚制が最も顕著に見られる場所として工場やファミレス、行政機関などが上げられる。

官僚制としてのマイクロサービス

さて、マーティン・ファウラーの提唱するマイクロサービス・アーキテクチャウェーバーの官僚制に照らし合わせてみると、性質にいくつかの類似点が見られる。実際にいくつかの例を挙げてみる。

  • マイクロサービス間の通信はgRPCやJSONRPCなど文章ではないものの、形式化されたコミュニケーション形態へ統一されている。
  • マイクロサービスは単なるシステムとして扱われ、そこに人格的な主観性はない。マイクロサービスを操作する主体はマイクロサービスを「もの」として見ている。
  • マイクロサービスごとに与えられている職務が標準化されているECサイトであれば配送マイクロサービス、注文マイクロサービス、など)
  • マイクロサービスごとの業務は全て独立して行われる(設計、開発、デプロイ、テスト、など)

照らし合わせてみると、官僚制の考え方をソフトウェア・アーキテクチャに適用したものがマイクロサービスと言ってもさほど違和感はない。モノリシックで巨大化したソフトウェアをスケールさせるためのアーキテクチャがマイクロサービスであるという観点から見ても、スケーラブルな組織体制としての官僚制と目的は一致する。

マーティン・ファウラーはマイクロサービスを「変化に強いアーキテクチャ」であるとしているが、一口に「変化」と言っても実際には「組織的な変化」と「技術的な変化」があると考えられる。技術的な変化の観点では納得がいく(独立性、交換可能性、など)が、組織の点ではどうか。組織の形が変わるとき、システムはどこまでその影響を緩衝できるだろうか。

サム・ニューマンのマイクロサービス・アーキテクチャではマイクロサービスを適用すべきではないケースとして「ドメインへの理解が低い場合」を挙げているが、これは「ドメインに変化を与えたい場合」にも当てはまると言える。ドメインが頻繁に変化する組織... たとえばベンチャーやスタートアップであるが、そのような組織においてマイクロサービスはどう影響するだろうか。

いずれにしても、組織という観点ではマイクロサービスはIT企業における官僚制の適用例だと言える。

官僚制の逆機能

しかし、もちろん(というか当然?)官僚制にはよく知られた逆機能(欠点)がある。

官僚制の逆機能はR.K.マートンによって指摘されているが、その中で最もよく知られるものはセクショナリズムである。組織間で独立性が高まった結果、連携は文書コミュニケーションのみで行われ、組織全体の生産性を高めることよりも自分たちの職務を遂行することだけが目的化してしまう。

この辺の欠点は行政機関などの仕事ぶりを見ればよく分かると思われる。また、より卑近な例ではいわゆる大企業病と揶揄されるものがこのセクショナリズムそのものであると言える。勘違いしてはいけないのは、大企業だからセクショナリズムに陥るのではなく、セクショナリズムで合理的な業務を行うことで企業は大規模化する。

また、官僚制で問題が発生するのは、標準化・ルール化できない特殊な業務が発生するときだ。いわゆる「お役所仕事」という言い方をされるような融通の聞かないあの感じである。融通の聞かない組織では技術革新もイノベーションも起きない。業務自体がフレームワーク化されてるため、業務改善なども非常にコストがかかる。このような理由から、組織の変化が組織外の変化に追従できなくなることも多い。

さいごに

究極的に言えば、官僚制のネガな部分だけを排除した形で組織をスケールさせつつ、マイクロサービスの技術的なよさを享受したい。これにつきる。

しかしながら、世の中のプレゼンスのある企業を見てみると利益追求のために必ず大型化するし、その過程には業務の合理化が存在する。会社を存続させるためには利益を上げ続けないといけないし、そこに官僚制的な側面が現れてくる。

話をもう少し深掘ると、利益追求という観点の「合理化」には近代資本主義の存在がここに絡んでくる... が、書いていると記事が終わらなくなってしまうのでこの辺で。

参考資料

官僚制度とは何か - 組織論Ⅰ 立教大学経営学部

社会学のあゆみ (有斐閣新書 C 52)

社会学のあゆみ (有斐閣新書 C 52)

  • 作者:新 睦人
  • 発売日: 1979/04/01
  • メディア: 新書

elm-firestoreでJSを1行も書かずにElmアプリケーションでFirestoreを使う

この記事はElm Advent Calendar 2020の8日目の記事です

今年の春頃からコツコツと個人開発のアプリケーションで使うためのElm用Firestoreライブラリのパッケージを作っていたので、その紹介をします。

github.com

できることはREADMEに書いてあるとおりで、基本的なCRUDオペレーションが一通りサポートされているのと、たぶんトランザクションもかけられます。

f:id:IzumiSy:20201209230333p:plain

また、このelm-firestoreは独自のエンコーダ/デコーダをパッケージのモジュールとして提供しており、Firestoreとの通信で使用される特別なJSONのデータ構造をパッケージの利用者が意識しなくてもよい作りになっています。

READMEにおいて "A type-safe Firestore integration for Elm." と謳っているのは、JSを書かずにFirestoreとの連携が実装でき、さらにエンコーダ/デコーダでも型安全性が担保されているという理由からです。

使い方

さて、実際のコードの雰囲気を見ていきます。

elm-firestoreでは取得されたデータは Firestore.Document というレコードで取り出せるので、それを格納できるようにしておきます。

また、Firestoreで利用可能な特別な型として ReferenceGeopoint がサポートされています。

import Firestore
import Firestore.Types.Geopoint as Geopoint
import Firestore.Types.Reference as Reference

-- model


type alias Model =
    { firestore : Firestore.Firestore
    , document : Maybe (Firestore.Document Document)
    }


type alias Document =
    { timestamp : Time.Posix
    , geopoint : Geopoint.Geopoint
    , reference : Reference.Reference
    , integer : Int
    , string : String
    , list : List String
    , map : Dict.Dict String String
    , boolean : Bool
    , nullable : Maybe String
    }

Firestore 型の生成は初期化は次のように行います。

もしもFirebase Authorizationを利用している場合には withAuthorization 関数を用いて認証トークンを与えることができます。

その他にも withDatabase 関数などでデフォルト意外のデータベースを指定したりすることもできますが、これらはoptionalです。

import Firestore
import Firestore.Config as Config

init: Firestore.Firestore
init =
    let
        config =
            Config.new
                { apiKey = "your-own-api-key"
                , project = "your-firestore-app"
                }
                |> Config.withDatabase "your-own-database" -- optional
                |> Config.withAuthorization "your-own-auth-token" -- optional
    in
    config
        |> Firestore.init
        |> Firestore.withCollection "documents" -- optional

ドキュメントの取得は非常にシンプルで、次のように書くだけです。

取得先のパスは withCollection 関数を使って事前にセットしておきます。

fetchDocument : Firestore.Firestore -> Cmd Msg
fetchDocument firestore =
    firestore
        |> Firestore.get decoder
        |> Task.attempt GotDocument -- GotDocument (Result Firestore.Error (Firestore.Document Document))

get 関数はデコーダを受け取りますが、このデコーダFirestore.Decode モジュールが提供する関数群で組み立てていきます。

エンコーダのほうも、同様にパッケージから提供されている Firestore.Encode を用いて組み立てていく形になります。

import Firestore
import Firestore.Decode as FSDecode

decoder : FSDecode.Decoder Document
decoder =
    FSDecode.document Document
        |> FSDecode.required "timestamp" FSDecode.timestamp
        |> FSDecode.required "geopoint" FSDecode.geopoint
        |> FSDecode.required "reference" FSDecode.reference
        |> FSDecode.required "integer" FSDecode.int
        |> FSDecode.required "string" FSDecode.string
        |> FSDecode.required "list" (FSDecode.list FSDecode.string)
        |> FSDecode.required "map" (FSDecode.dict FSDecode.string)
        |> FSDecode.required "boolean" FSDecode.bool
        |> FSDecode.required "nullable" (FSDecode.maybe FSDecode.string)

基本的に、Elmにおいては対象となるひとつのデータ構造に対してエンコーダとデコーダを実装することになりますが、それはelm-firestoreでも同じです。

しかし、この手間を省くことができるようにelm-firestoreでは Firestore.Codec としてCodecモジュールが導入されています。Codecを使うことでひとつの実装からエンコーダをデコーダを作ることができるので、基本的にはそれぞれ個別に定義するよりも、こちらを使うほうが楽ちんなのでおすすめです。

コーデックとはなんぞや?という方はこちらの記事をどうぞ。 izumisy.work

他にもドキュメントの作成、更新(patch, upsert)やトランザクションなど諸々ありますが、このあたりは応用的な話になるので説明を端折ります。詳しい使い方などはパッケージのドキュメントにサンプルコードとともに書かれていますので、ぜひ読んでみてください。 package.elm-lang.org

ある程度の機能は揃っていますが、まだまだ色んな機能の追加を画策中ですので将来的にダイナミックにメジャーバージョンで破壊的変更が入る可能性があります。ここだけ留意しておいてもらえれば幸いです。

リアルタイム・アップデートについて

こんだけ宣伝しといてアレですが、ひとつ決定的に惜しい点としてこのパッケージはFirestoreの一番の強みであろうリアルタイム・アップデートがサポートされていません。

これは内部的にHTTPのRESTful APIでFirestoreと通信をしているのが原因で、どうやら公式のJS製FirestoreライブラリとかはgRPCプロトコルを用いてFirestoreと通信をしているみたいです。詳細なことは僕には分かりませんがServer Streaming RPC的なのを使わないとドキュメントの更新はリッスンできないようです。少なくともRESTful APIでは100%できません。

というわけで普通にCRUDするには十分ですが、リアルタイム・アップデートを使うにはまだまだ、という感じです。いずれgRPCプロトコルでFirestoreと通信するように書き換えたいなと思っていますが、現状時間がなくてあまり手がつけられてません。

もし「やってやってもいいぜ」という方がいましたらぜひPRをお待ちしています
もちろん、バグ報告issueなども大歓迎です🙌