こんにちは。個人開発で夫婦で家庭管理できるファミリーログというアプリを作っている内田です。このブログは、 #ヌーラボブログリレー2024 for Biz Advent Calendar 2024の20日目のブログとして更新しています。
Backlogのドキュメント機能が9月10日にリリースされました。そこでドキュメント機能ができるまでを書いていきます。ほとんど技術的な内容はなく、ドキュメントを作り始める話は最後の方に少しあるだけなので、そこだけ読みたい方は途中は読み飛ばしてください。
目次
始まり
私はヌーラボに2015年に入社したのですが、その当時BacklogのベースはJavaだったんですが、それをScalaにしようという感じの流れがありました。私はScalaをその当時全く知らなかったのでScalaを学ぶために何か開発しようと思いました。そして有名だったGitBucketのコードのWikiの部分を読んでいる時に面白いことを思いつきまして。GitBucketのWikiはデータの保存にGitが使用されていて、ブラウザ上で書き込んだ内容をベアリポジトリに直接入れるようになっていました。ここで私はこれを使ってドキュメント管理サービスを作ったら面白いのでは?と思いScalaで作り始めました。その名は Monster Docs 、最初のコミットは2017/05/18になっていました。
Monster Docsの共同編集機能
最初のコンセプトである「Gitベースのドキュメントサービス」これ自体は割とすぐできました。そこで私は、これにさらに共同編集機能があったらいいのでは?と思い共同編集機能を実装していくことにしました。ヌーラボでは私が入社した当時朝会でEtherpadというプロダクトをホスティングして使っていました。その後HackMDというプロダクトをホスティングしていくようになり、私はこのHackMDのコードを読んで実装していくことにしました。
苦闘の日々の幕開け
HackMDはバックエンドがNode.jsでできていてすでにライブラリとしてあるot.jsを共同編集で使っていました。私はバックエンドをScalaで作っていたためそれをScalaに置き換えて作ろうとしていたんですが、この当時共同編集という技術がよくわかっていなかった私はどの部分をScalaにすればいいのかさっぱりわからず、わけがわからないままひたすらHackMDのバックエンドをScalaにリプレイスする作業をしていてしかもクライアントと繋げてないので動くかわからないという超ストレスフルな作業を何ヶ月も仕事が終わった後のプライベートな時間でしていました。で、この作業は挫折して3ヶ月くらい辞めた後に再度最初から実装し始めたら何を置き換えればいいかこの時は結構わかっていて綺麗に実装できました。
Monster Docsの迷走と開発をやめる
Monster DocsはMarkdownとプレビューを並べて共同編集できて、Gitで履歴管理できるサービスになったのですが、この当時Scrapboxが流行っていたこともあり、1カラムでリッチテキストっぽく見せて、テキストをクリックしたらMarkdownが編集できるみたいなものに作り変えてみました。それを同僚のJuliusに見せると「なんでcontenteditableが使ったエディタ使わないの」と言われまして。何それ状態の私は色々調べてみると昔の頑張って作っていたリッチテキストエディタがcontenteditable属性を使って綺麗に使えるProseMirrorやDraft.jsなどのライブラリが出ていました。そこで次は完全なリッチテキスト化にチャレンジすることにしてエディタをProseMirrorにして共同編集の方式をProseMirrorが提供するコラボレーションの方式に変更しました。しかし、これが不味かったのがProseMirrorのコラボレーション機能はコンフリクトフリーではなく、コンフリクトが起こったら再送する実装になっており5人くらいで共同編集すると破綻する状況でした。
さらにそもそも共同編集とGitというのが相性があまり良くなく、Gitの良さを消してしまう結果になったり、なんだか私もだんだん飽きてきて・・。(まぁ、飽きてきてっていうのもアレなんだけど・・。)結局開発を辞めてしまいました。最後のコミットが2018/12/10になっていました。
Quillとの出会いとサービスをまた作り始める
そこからさらに2年くらい経った時に、この当時私はどうやったらリッチテキストで綺麗な共同編集ができるんだろうとモヤモヤしていたんですが、OTにDeltaフォーマットというものを使うことでリッチテキストを共同編集できるということは知っていたんですが、Quillがそれを完全サポートしていることを知り、またScalaをバックエンドにリッチテキストの共同編集サービスを作り始めました。その名も PadIO 。QuillはjsなのでまたQuill DeltaをScalaでリプレイスする作業を始めました。これは2ヶ月くらいでできたんですが、リッチテキストが共同編集できるだけだと他のサービスと差別化できないのでWebRTCを使って2カラムで片方で共同編集して片方は共同編集している人とミーティングできるものにしました。これを橋本さんにサービス化して売り出したらどう?って提案したんですが、理由はよく思い出せないんですが、却下になり。このサービスも作るのを辞めました。
当時書いたコードはGitHubに公開していますので、興味がある方はぜひご覧ください。(今でも動くと思います。)
https://github.com/yuichi0301/scala-quill-delta
ちなみに Monster Docsもサービス化の提案をしていたんですが、橋本さんの意向はこれをBacklogの機能としてつける方がいいということで一旦置きとなりました。
Gitを使ったノートアプリを作り始める
私の中でどうしてもGitをベースにしたドキュメント管理アプリというのが頭にあったみたいで、個人開発で全てGitベースでElectronを使ったノートアプリを作り始めました。このアプリは今でもダウンロードできるので試したい人は使ってみてください。
https://github.com/yuichi0301/dl.gitnotebook/releases
ついにBacklogのドキュメント機能を作り始める
ある時、その当時のPdMからWikiチームっていう独立するチームを作ってそこでWikiの保守とか新しい機能開発やっていくからリーダーをよろしくということを言われました。ということで2022年の1月からBacklogにリッチテキストで共同編集できるドキュメント機能を作り始めました。これまでの経験から共同編集するサービスのノウハウみたいなものは身についていたので、プロトタイプはすぐにできました。ただ、この時大きく選択を変えたのはバックエンドをScalaにしないことでした。もう二度のリプレイスで疲れていたこともあり、共同編集系の技術の多くはNode.jsで提供されているため、新しい技術が出るたびにScalaにリプレイスする作業を挟むと進化や保守に大きく影響するということで既存のライブラリをそのまま使うことにしました。
OTからCRDT
Quillを使ったプロトタイプはすぐできたものの、実際に共同編集をしてみると英語での共同編集はうまくいくものの日本語だと全然うまくいかなかなかったです。というものQuillはcjk imeの問題が多く、うまくいきませんでした。結局cjk imeに強いエディタを探したところProseMirrorを再び使うということになり、ProseMirrorはこの時点で課題機能での実績もあり採用しました。ただ、ProseMirrorでOTを使って共同編集機能を作るのは大変だったため、yjsを使ってCRDTで共同編集機能を作成することにしました。(まぁ、この時もAutoMerge使ったり色々試してみたんですが・・。)
苦労したところ
ドキュメント機能の作成で一番苦労して時間がかかったのがBacklogの機能の一部として載せるというところでした。新しい機能なので大元のBacklogに影響を与えないようにする必要があり、できるだけ影響を与えないようなアーキテクチャを考えたり負荷試験したりに1年くらいかかったと思います。
まとめ
ということでMonster Docsの最初のコミットからユーザーさんの手にドキュメント機能が届くまで7年と116日かかりましたが、今後もBacklogドキュメントは機能がどんどん追加されていきますのでぜひご活用ください!