array-diff-itemsを開発・公開しましたGlobalエンジニアリンググループの冨岡(@jooohn1234)です。年末までM3USAの開発をサポートするため、USに滞在しています。ハンバーガーがうまい現在、M3USAが運営するMDLinxにて利用するCMSサービス(Contentful)をサポートする内部向け機能を作成しています。その一環で、Contentfulが提供するRichTextのバージョン間の差分を検出・表示するというエンジニアっぽいことをやったのでそれを紹介します。背景エムスリーUSAでは、医療従事者に向けた記事等を発信しています。(Contentful)の利用を検討しています。www.m3tech.blogM3USAのワークフローでは、世界各国のコントリビューターに執筆依頼、レビュー、修正依頼などをしながら一つの記事を作成していきます。これを補助する機能の1つとして、各編集者による変更の履歴・差分を表示する機能が強く望まれています。GitHubのコミットやレビュー機能のようですね。Contentfulがビルトインで提供するワークフロー機能はやや貧弱です。私たちのユースケースで致命的なのが以下です。私たちのワークフローを実現する場合、Contentfulからの提案としては、以下のようでした。ある記事の編集によってトリガーされるwebhookの通知を受け、そのときの内容を自前で保存する自前でdiffを表示する基本的にContentfulはCMSインフラを提供する立場であるため、表示に関してはこちらに任されている節があります。(プレビューなども自前のサイトを用意する。)ここで、RichTextの差分を表示するという要求が出てきました。"変更"を検出するということがあったので、差分を検出するarray-diff-itemsというライブラリを自作しました。よければ使ってみてください!github.comリポジトリのMotivationの項にも書きましたが、一番のモチベーションは"変更"を検知することです。RichTextの差分を表示する際に、文章の一部を変えただけで以下のように差分が表示されるのはあまりUXがいいとは言えませんよね。いう文字列を追加しただけで全く別のparagraphとして差分が表示される一方、全く違う文章を頑張ってマッチングされるのも困り者です。)が配列として並ぶのですが、これを"いい感じに"差分を検出して表示させたい、というモチベーションでこのライブラリを作成しました。以下のように二つの要素間のコスト関数を与えることで、コストが最小になるような差分を検出します。]このコスト関数を調整することで、"ほどよく"差分を検出することができます。Paragraph内の差分は[変更]触れるデモも用意しました。https://array-diff-items-example.netlify.com/TypeScriptを使っている場合は、DescriminationUnionの機能で型安全に返却された各dIff項目の処理ができます。Graphをベースにしています。(変更後の列長+1)]のNodeが存在するGraphの中で、下への移動は元の要素の削除を、右への移動は変更後の要素の追加を意味します。左上が未変更、右下が全て変更後の状態を示すことになります。今回は右下への斜めの変更にコスト関数を用いました。このコストが0の場合は"変更なし"を意味します。0でないとしても右・下というパス(追加・削除)のコストにくらべて変更のコストが低い場合は、変更のほうが好ましいパスといえます。(ほとんど同じ文章のparagraphブロックは、追加・削除よりも変更したい、という意図をここで反映できます)そのコストも考慮に入れた上でこの左上のノードから右下のノードへの最短経路を解くという、比較的シンプルな問題です。今回の実装では、全てのNodeへの最短経路を解いていき、右下のNodeのパスを導き出しています。Graphの性質から探索するNodeを距離順に解いていけばいいので実装がわかりやすくシンプルです。Queueを用いたダイクストラ法も試しましたが、あまり性能が出なかったので今回はシンプルに実装しています。今回のユースケースには十分な性能が出ていますが、最強の実装を習得している方からのコントリビュートも、もちろん大歓迎です!まとめ今回はRichTextの差分を表示するためのライブラリを作成した話を紹介しました。今回のアルゴリズムの検討では、文字列比較のスペシャリストでありルームメイトの笹川(@SassaHero)と二人でああでもないこうでもないと議論しながら進めました。hiringエムスリーでは、今回のようにエンジニアリングの力で問題を解決する仲間を募集しています。興味を持たれた方はぜひ以下のリンクからご応募ください。サーバーサイドの足回りの試行錯誤録エンジニアリンググループの矢崎(id:Saiya)です。月別アーカイブ注目記事はてなブログをはじめよう!m3techさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。