月: 2025年7月

  • テキストをマージしたい(1) – iPhoneメモアプリの挙動から考える

    iPhoneのメモアプリは、私にとって非常に使いやすく優れたツールです。その中でも、特に気に入っているのが 複数デバイス間での自動同期機能 です。

    この機能のおかげで、メモを取るときにネット接続がなくても構いません。ネットに接続されたタイミングで、自動的に他のデバイスに同期されるからです。しかも、ユーザーが意識して操作をすることなく、「気づいたら同期されている」 という自然な使い心地が実現されています。


    同期とマージの難しさ

    このような便利な機能を、自分のアプリでも再現できないかと考えています。
    「ネットに再接続されたタイミングでバックアップ処理が走る」という仕組みは比較的想像しやすいのですが、問題はそのときの テキストのマージ処理 です。

    プログラマーであればお分かりかと思いますが、これは Git のマージコンフリクトの解消に近い処理になります。複数の編集が同じ場所で衝突したとき、どちらの内容を優先するか、あるいはどう統合するかを決めなければなりません。


    実際にiPhoneのメモアプリで試してみた

    挙動を確認するため、iPhoneとMacBookでそれぞれ同じメモを別々に編集し、同期がどのように行われるかを検証してみました。

    なんと、両方の修正が取り込まれている結果になりました。

    これはメモアプリとして非常に良い挙動と思います。どちらか一方の編集だけが残り、もう一方の内容が失われてしまうと、ユーザーにとっては大切な情報の欠落するかもしれません。欠落するより、両方の修正が残った方がユーザにとっては嬉しいはずです。


    Gitで同じことが起きたら?

    先述の通り、通常はコンフリクト解消作業が必要となります。
    たとえば以下のように、ブランチ毎に修正内容が列挙されるので、開発者が差分を確認しながらマージ作業を行わなければなりません。この作業って大変ですよね。

    <<<<<<< HEAD
    beb
    =======
    bfb
    >>>>>>> feature-branch

    技術的解決の方向性

    差分の算出には JavaDiffUtils という優れたライブラリがありました。これを使えば、2つのテキスト間の差分抽出は完璧に行えます。さらに、3-way-merge(3者間マージ) という手法を使うことで、編集前・編集1・編集2の3つのバージョンを比較して、よりスマートなマージが可能になります。

    現在、プロトタイプを作成しています。近いうちに記事として公開予定なので、興味のある方はチェックしていただけると嬉しいです。


    アイコンを使わせていただきました。素敵なアイコンをありがとうございます。
    https://icooon-mono.com
    Offline icons created by NajmunNahar – Flaticon
    Internet-connection icons created by NajmunNahar – Flaticon

    【広告】

  • windows(powershell) でmysqldump の文字化けに苦しむ

    結論

    mysqldump を使う時はオプションの –result-file=dump.sql を付けた方が良い。トラブルを防げます。

    問題の発端

    PowerShell でこのようなコードを書いたことが元凶。

    chcp 65001
    & mysqldump ... > dump.sql

    このdump.sql を後でリストアしようとすると、以下のようなエラーが発生しました。

    mysql ... < dump.sql
    ... invalid character '-◻︎' ...

    理由は、PowerShell のリダイレクト(>)が文字コードに余計な手を加えるため、MySql のパーサが読んでくれません。

    一時回避

    PowerShell 経由でファイルを読み書きしてから、MySql パーサに読ませます。一見無意味に見えますが、実際には文字コードが変わります。

    Get-Content dump.sql | Out-File dump.sql.clean
    mysql ... < dump.sql.clean

    こちらは正しくリストアできます。ただし、dump.sql が巨大な場合はメモリ使用量が問題になり、Get-Content でエラーになります。
    Stream で文字コードを変更する案もあるのですが、試したものの結局MySql パーサは読み込んでくれませんでした。

    根本的な解決方法

    以下のように mysqldump に –result-file オプションを明示的に指定することで解決しました。

    mysqldump --result-file=dump.sql ...

    この方法で出力されたファイルは余計な文字コード変換が起きず、そのままリストア可能です。

    感想

    結局、windows のリダイレクトが余計な気配りをしてくるのが問題でした。個人的には、Unix系OSの方がトラブルが少ないので、運用するにはそちらの方が安定すると思います。

    【広告】

  • Chrome Extension 更新失敗の原因について

    先日、Chrome Extension の更新版をリリースしました。(詳しくはこちら
    その際にいくつかのミスがありましたので、備忘録としてここに記録しておきます。

    (1) 大量データに関する問題

    コメントでご指摘いただき、初めて気づくことができました。
    私は、品質向上のためには性能試験が重要だと考えているにもかかわらず、大量データに対するテストを行わずにリリースしてしまいました。
    自分の Amazon 購入履歴は多くても10ページ程度だったため、それ以上のケースは「テストできない」と思い込んでいました。
    しかし、それは単なる言い訳です。たとえば、1ページを10回ずつ読み込むようにコードを少し変更すれば、簡単に大量データのシミュレーションができます。

    原因と対応策

    エラーの原因は、巨大な配列を String.fromCharCode に展開して渡した際、
    「Maximum call stack size exceeded(スタックオーバーフロー)」が発生していたことです。
    これに対しては、32KBずつに分割して処理することで対応しました。
    該当の修正コミットはこちら

    (2) ZIP 作成ミス

    こちらもコメントでご指摘いただきました。ありがとうございます。
    Chrome Extension は ZIP にまとめて Chrome Web Store にアップロードする必要があります。
    しかし、リリース版にテスト用のデータ水増しコードがそのまま含まれてしまうという、非常に初歩的なミスをしてしまいました。
    私は修正後に git commit をしたことで、未コミットのファイルは ZIP に含まれないと思い込んでいました。
    これは、他のプロジェクトでは CI/CD により自動でビルド・リリース用の ZIP が作成されるため、その感覚が残っていたことが原因です。

    今後の対策

    今後は、ZIP 作成処理をスクリプト化する予定です。
    具体的には、別フォルダに最新コードをクローンし、そこから ZIP を作成する仕組みにします。
    以下は参考までに、macOS 上でのシェルスクリプト例です:

    cd /tmp
    rm -fr ./work
    mkdir work
    cd work
    git clone --depth 1 --branch main git@github-greencode:green-code-developer/chrome_extension_amazon_jp_history .
    zip -r extension.zip ./extension
    ls -l /tmp/work/extension.zip

    ご指摘くださった皆さま、本当にありがとうございました。
    この経験を次回のリリースに活かしていきたいと思います。

    【広告】