Discussion: Could we merge project/packages both MeCab.DotNet and LibNMeCab
こんにちは、komutanさんの方の更新が続いていて良かったです。
私の方のMeCab.DotNetの方も、主に環境面でのissueについて更新を行っていますが、komutanさんの方の変更に追従できていなくて、どうしようかと思っています。いっそのこと、こちらのプロジェクトとの統合を考えてみたらどうだろうかと考え、まずは意見を聞きたくてissueを立てました。
MeCab.DotNetは、そもそも私がとあるイベント向けに.NET Core環境で使いたくて移植した、という経緯があったのですが、公開後、海外の方にも使われていることが分かり、(主に開発環境面での更新、例えば.NET Coreの新しいバージョンが出たなどで困らないよう)半ば義務感で更新を続けている状況です。
(イベントについては長文ですが私のブログにまとめています)
いくつか私的なプロジェクト(主に非公開)で使用しているのですが、形態素解析自体の知識があるわけではないので、あくまで前述の範囲での更新となってしまっているのが気になっています。恐らくは、コア部分の機能改善についてはkomutanさんの方が進んでいると思いますので、例えば現在のように開発環境面での更新や機能強化という点で協力できる部分があると思います。
そこで、2つのプロジェクトの統合を考えたのですが、別々にforkしていた方が開発がやりやすいとか何か理由があるようでしたら、それはそれでも一向に構いませんので、そのように言って頂ければと思います。
統合した場合の問題点について、まだあまり深く考えていませんが:
- ソースコードの統合: 何とか頑張ってやる :)
- 外部インターフェイスの問題としては、一番大きなのは名前空間かなと思います。
- 私案では、しばらく2つの名前空間のどちらでも参照できるような構造をとって、Obsoleteつけるなどして、最終的にどちらかに移行するのが良いかなと思います。
- NuGetパッケージ: 上記のようなダブルインターフェイス定義されたライブラリを、別々のパッケージで(中身は同じで)配布しつつ、Obsoleteを付けて、最終的にどちらかに統一するという方法を考えます。
- メソッドやプロパティの一部の(同居できない)非互換があれば、そこはbreaking changeで妥協する。
とりあえず、今思いついていることは書き出してみましたが、何か意見があればお願いします。
@kekyo さん こんばんは。
ご提案ありがとうございます。 思いがけない内容で驚きました。 しかし大変嬉しいところです。
kekyoさんが、MeCab.DotNetのユーザーを獲得されて、更新を続けていらっしゃること、敬服いたします。 そして、NMeCabの新版の開発時にMeCab.DotNetのコードの流用を快諾頂いたこと、なにより感謝しております。
ネットで拝見するに、ご活躍が素晴らしく、大変お忙しい中であること、期待されるお仕事が多くあること、お察しします。
私がこちらで公開したNMeCabの新版は、過去版とのbreaking changeをあまり厭わない方向でやっていました。 しかし大規模なものではなく、現状、色々な意味で、仰るような統合も頑張れば可能なレベルではあると思います。 互換APIを作成し、名前空間も互換とし、あとは公開方法の調整がつけば、ユーザーの方にも満足して貰える統合ができそうかと思うところです。
私も今は深くは考えきれていないですが、以上のように、基本的にはkekyoさんのご提案に賛同します。
いまヤボ用があって…しばらくは着手できないですが… 計画させてください。 もちろん細かい作業もお引き受けできます。 気長に見て頂けたらありがたいです。 それではまた
@komutan ありがとうございます、私もこの件は急いでいる話でもないので、ゆっくりと進めることが出来れば良いかなと思っています。 そちらの都合が付きそうでしたら、改めてメンション頂ければと思います。
具体的な進行が開始されるまでは、このissueを保持しておきたいのですが良いでしょうか?
@kekyo ありがとうございます!なにもかもありがたく思います。仰るように保存して、またメンションさせてください!
@kekyo ご無沙汰をしています。 こちらの件の続きをと思いまして、検討させていただきました。
MeCab.DotNetのリポジトリを拝見し、2つのMeCabTaggerクラスのメソッドのシグネチャーを以下に書き出しました。(ポインタ型引数のやDisposeは省略です。)
MeCab.DotNet
public static MeCabTagger Create() { }
public static MeCabTagger Create(MeCabParam param) { }
public string Parse(string str) { }
public MeCabNode ParseToNode(string str) { }
public IEnumerable<MeCabNode> ParseToNodes(string str) { }
public IEnumerable<MeCabNode> ParseNBestToNode(string str) { }
public string ParseNBest(int n, string str) { }
https://github.com/kekyo/MeCab.DotNet/blob/main/MeCab.DotNet/MeCabTagger.cs
NMeCab (v0.10.1)
public static MeCabTagger Create(string dicDir = null, IEnumerable<string> userDics = null) { }
public MeCabNode[] Parse(string sentence) { }
public Enumerable<MeCabNode[]> ParseNBest(string sentence) { }
public MeCabNode[] ParseSoftWakachi(string sentence, float theta = MeCabParam.DefaltTheta) { }
public MeCabLattice<MeCabNode> ParseToLattice(string sentence, MeCabParam param) { }
https://github.com/komutan/NMeCab/blob/master/src/LibNMeCab/MeCabTagger.cs https://github.com/komutan/NMeCab/blob/master/src/LibNMeCab/MeCabTaggerBase.cs
MeCab.DotNet と NMeCab最新版 を単純に取り替えて使う場合には
- Createのパラメータが違う
- 戻り値string型のメソッドがなくなる
- 戻り値の多くが配列型になる
- 部分解析という機能がなくなる(MeCabParamの中のフラグがなくなってます)
といった差異がでてきます。
@kekyoさんに、ご検討いただきたいのですが、MeCab.DotNetのAPIはやはり維持しますでしょうか。 その場合、私のほうでコードを書かせていただきます。(仕様を知っているので、大した手間ではないです。そのあとでもちろん@kekyoさんに自由に作り直して頂いて大丈夫です。)
以下のようなものを私では考えています。
- MeCab.DotNetからNMeCabを参照(NuGetを使うか他の方法にするかは検討)
- MeCab.DotNetのTaggerクラス内でNMeCabを呼び出すようにして、そこでできるだけAPIの差異を吸収する。
- 部分解析だけは、NMeCabの中核的部分に手を加えなければ実現できず、Obsoleteとする。(MeCabParamのフラグが立っているとき例外を返すようにする)
このコードをMeCab.DotNetにPRで送るのがよいでしょうか。
(後々、まとめて維持することを考えると「リポジトリの一本化」という案もでますが、、そうするとドキュメント等がユーザーから分かりにくくなりそうですし、変更履歴も消えてしまうので、やはりそれはなさそうですね)
ご検討・ご意見を頂きたいと思いました。よろしくお願いします。
@komutan なるほど、案について理解しました。
現状のMeCab.DotNet側のシグネチャを、NMeCabベースの実装で再現が可能ということであれば、明らかに不要となりそうでも、一旦両者のインターフェイスを出来るだけ再現するのが良いと思います(一般的なリファクタリングの原則に従って)。
例えば、Parseの戻り値がNMeCabでリッチな方向に変更されているのはそういった理由があると思いますので、最終的にはMeCab.DotNetのstringを返すバージョンは廃止するように寄せたほうが良いと思っています。
戻り値の型だけが異なるオーバーロードは許されませんが、MeCab.DotNetとNMeCabでは名前空間が異なるので、案の方法で寄せるので良いと思います。部分解析についてもOKです。例外で検出できることと、アナウンスすれば良いでしょう。
(部分解析が必要なユーザーは、最終版を使い続ける選択肢を残せます)
リポジトリの一本化ですが、
- NMeCab(GitHubのここ)ベース
- MeCab.DotNetベース
- 両者を維持しつづける
- その他
とあると思います。このうち3はそもそもこの作業をやる意味がなさそうなので無いと思っています(ずっと両者を維持し続けるという意味です)が、どうでしょうか? 1や2の場合は、organizationを立ててそちらにリポジトリを移設し、しかる後にどちらかをアーカイブして片方に誘導する、ということにすれば、片方の履歴は継続され、片方はアーカイブで残るので良いと思います。
私的には、私の方の履歴はほぼ移植作業(NuGetのパッケージ作るところとかあったかもしれない)なので、実質的には参照さえできればアーカイブで問題ないかなと思っています(アーカイブでも参照したい人がいるかどうか疑わしいですが :)
NMeCabの履歴を残す場合の案(NMeCabリポジトリを使う):
- NMeCabリポジトリ側でMeCab.DotNetの互換実装を行う
- NMeCabリポジトリ側でMeCab.DotNetのパッケージ生成できるようにする
- 融合されたパッケージのリリース
- リポジトリを、organizationに移動
- MeCab.DotNetリポジトリからポインタを張り、アナウンスする
- NMeCabリポジトリ側で第二のリリース作業をする(Obsoleteを実際に削除するなど?)
- NMeCabリポジトリ側で第二のリリース
- MeCab.DotNetをアーカイブにする
MeCab.DotNetの履歴を残す場合の案(MeCab.DotNetリポジトリを使う):
- MeCab.DotNetリポジトリ側でNMeCabの互換実装を行う
- MeCab.DotNetリポジトリ側でNMeCabのパッケージ生成できるようにする
- 融合されたパッケージのリリース
- リポジトリを、organizationに移動
- NMeCabリポジトリからポインタを張り、アナウンスする
- MeCab.DotNetリポジトリ側で第二のリリース作業をする(Obsoleteを実際に削除するなど?)
- MeCab.DotNetリポジトリ側で第二のリリース
- NMeCabをアーカイブにする
リポジトリのorganizationへの移動は、URLが自動的にリダイレクトされるので、今まさに参照している人への影響は少ないと思います(GitHubはローカルのURLの修正を推奨しているので、アナウンスは必要でしょう)
https://docs.github.com/ja/github/administering-a-repository/transferring-a-repository#whats-transferred-with-a-repository
最終的なリポジトリ名を何にするか、については、変更した場合、そのタイミングがorganizationへの移動前後によって、リダイレクトがちゃんと機能するかどうかはわかっていません(一応試した方が良いかも...)
なお、第三の案として、NMeCabの履歴を残しつつMeCab.DotNet側のコードベースで作業する場合(あるいはその逆)は、その時点のソースコード一式を無理やり全入れ替えしてcommitを作るという方法も無くはないです。例えば:
# NMeCabのcloneで
git clean -xfd
# 現在のファイルを全部削除 (.git/ 以外)
rm -rf * .gitignore
# MeCab.DotNetのコードをコピー
cp -R ../MeCab.DotNet/* ../MeCab.DotNet/.gitignore
# コミットすると、NMeCabの履歴ベースでMeCab.DotNetのコードになる(強引)
git commit -m "Imported from MeCab.DotNet"
# 以後、NMeCabのコードを手動で取り込む...
# 取り込みが終わったらSquashすれば、差分が多少マシになるかもしれないです。
@kekyo 遅くなりました。🙏
APIについてもリポジトリに関しても、詳しく複数案いただいており、ありがとうございます。 どれもなるほどと思うところです。 たしかに、リポジトリを一本化しなければ作業の意味がなくなってしまいますね。まったくおっしゃる通りです😆 そして「リポジトリを、organizationに移動」のところも、なるほど必然的だと思いました。 よろしいようでしたら、NMeCabのリポジトリベースで進めさせて頂ければと思います。
この週末に融合したパッケージのコーディングの時間が取れると思います。 仕様はわかっているのですが、作業が遅いことはすみません。ご了承ください。
@komutan 了解しました、ではNMeCabのリポジトリで作業を進行して、リポジトリの以降は次の段階でやりましょう。
開発速度については全く気にしていませんので(GitHubでやる上にOSSの活動なので、非同期進行で一向に構いませんよ :) 無理のない範囲でやって下さい。
とりあえず最初のそちらの変更分が出来たら、こちらでもそれを評価してみます。ブランチ切った時点でPR立てて、実際の修正はその上でやるのが良いかと思います。
@kekyo コーディングを終えたので、PR #34 をレビュー可能にしました。ご確認いただけたら幸いです。
@komutan
コーディングを終えたので、PR #34 をレビュー可能にしました。ご確認いただけたら幸いです。
すいません、reactしてたのに完全に見落としていました orz レビューします