47

短縮版

私の「ケース」を読みたくない人にとって、これが本質です。

  1. 新しいパッケージが既存のコードを壊す可能性を最小限に抑える、つまり、作成するコードを可能な限り堅牢にするための推奨される方法は何ですか?
  2. 名前空間メカニズムを最大限に活用するための推奨される方法は何ですか

    a)提供されたパッケージを使用しているだけですか(たとえば、一部のR分析プロジェクトで)?

    b)独自のパッケージの開発に関して?

  3. クラス(AFAIU)に匹敵する名前空間メカニズムすら存在しないため、正式なクラス(私の場合は主に参照クラス)に関する競合を回避するにはどうすればよいですか?::


Rユニバースの仕組み

これは、約2年前から頭の中で悩んでいることですが、満足のいく解決策に到達したとは思えません。それに、悪化しているように感じます。

CRANgithubR-Forgeなどでパッケージの数が増え続けていますが、これは非常に素晴らしいことです。

このような分散型環境では、Rを構成するコードベース(簡単にするために、ベースR寄与R)が、堅牢性に関して理想的な状態から逸脱するのは当然です。人々はさまざまな規則に従います。S3、S4があります。 、S4参照クラスなど。規則を適用する「中央クリアリングインスタンス」があった場合のように、物事を「調整」することはできません。大丈夫。

問題

上記のことを考えると、Rを使用して堅牢なコードを作成するのは非常に難しい場合があります。必要なものがすべてベースRにあるわけではありません。特定のプロジェクトでは、かなりの数の寄稿パッケージをロードすることになります。

IMHO、その点での最大の問題は、名前空間の概念をRで使用する方法です。Rでは、名前空間を明示的に要求することなく、特定の関数/メソッドの名前を簡単に記述できます(つまりfoonamespace::foo

簡単にするために、それは誰もがしていることです。しかし、そうすれば、名前の衝突、壊れたコード、コードを書き直したりリファクタリングしたりする必要性は時間の問題です(またはロードされたさまざまなパッケージの数の問題です)。

せいぜい、新しく追加されたパッケージによってどの既存の関数がマスク/オーバーロードされているかを知ることができます。最悪の場合、コードが壊れるまで手がかりはありません。

いくつかの例:

  • RMySQLRSQLiteを同時にロードしてみてください。うまくいきません。
  • また、 RMongoはRMySQLの特定の機能を上書きします
  • 予測は、ARIMA関連の機能に関して多くのものを覆い隠します
  • R.utilsbase::parseはルーチンをマスクします

(特にどの機能が問題を引き起こしていたのか思い出せませんが、興味があればもう一度調べてみてください)

驚いたことに、これは多くのプログラマーを悩ませているようには見えません。私はr-develで数回関心を高めようとしましたが、あまり役に立ちませんでした。

::演算子を使用することの欠点

  1. Dominick Samperiが指摘したように、演算子を使用する::と、特定のコンテキストで効率が大幅に低下する可能性があります。
  2. 独自のパッケージを開発する場合::、コードはまだ実際のパッケージではなく、名前空間もまだないため、独自のコード全体で演算子を使用することもできません。したがって、最初はfoo方法に固執し、ビルドし、テストしてから、すべてをに変更することに戻る必要がありnamespace::fooます。あまり。

これらの問題を回避するための可能な解決策

  1. 各パッケージの各関数を、特定の命名規則に従う変数に再割り当てnamespace..fooします。たとえば、関連する非効率性を回避するためです(ここnamespace::fooで一度概説しました)。長所:それは動作します。短所:不器用で、使用するメモリが2倍になります。
  2. パッケージを開発するときに名前空間をシミュレートします。AFAIU、これは実際には不可能です、少なくとも当時私はそう言われました
  3. の使用を必須にしますnamespace::foo。私見、それが最善の方法です。確かに、ある程度の単純さは失われますが、Rユニバースはもはや単純ではありません(少なくとも00年代初頭ほど単純ではありません)。

そして、(正式な)クラスはどうですか?

上記の側面とは別に、::wayは関数/メソッドに対して非常にうまく機能します。しかし、クラス定義はどうですか?

そのクラスでパッケージtimeDatetimeDateを取ります。クラスもある別のパッケージが付属しているとしましょうtimeDatetimeDate2つのパッケージのいずれかからクラスの新しいインスタンスが必要であることを明示的に示す方法がわかりません。

このようなものは機能しません:

new(timeDate::timeDate)
new("timeDate::timeDate")
new("timeDate", ns="timeDate")

ますます多くの人々がRパッケージをOOPスタイルに切り替え、多くのクラス定義につながるため、これは大きな問題になる可能性があります。クラス定義の名前空間を明示的にアドレス指定する方法があれば、ポインタをいただければ幸いです

結論

これは少し長かったですが、核となる問題/質問を指摘でき、ここでもっと意識を高めることができればと思います。

devtoolsmvbutilsには、広める価値のあるアプローチがいくつかあると思いますが、もっと言うことがあると確信しています。

4

2 に答える 2

34

素晴らしい質問です。

検証

堅牢で安定した、本番環境に対応したRコードを作成するのは困難です。あなたは、「驚くべきことに、これは多くのプログラマーを悩ませているようには見えません」と述べました。これは、ほとんどのRプログラマーが製品コードを作成していないためです。彼らは一回限りの学術/研究タスクを実行しています。私は、Rが本番環境に簡単に導入できると主張するコーダーのスキルセットに真剣に疑問を投げかけます。あなたがすでにリンクしている検索/検索メカニズムに関する私の投稿とは別に、私は警告の危険性についての投稿も書きました。提案は、本番コードの複雑さを軽減するのに役立ちます。

堅牢な/本番環境のRコードを作成するためのヒント

  1. Dependsを使用するパッケージを避け、Importsを使用するパッケージを優先します。依存関係がインポートのみに詰め込まれたパッケージは、完全に安全に使用できます。Dependsを使用するパッケージをどうしても使用する必要がある場合は、電話をかけた直後に作成者に電子メールを送信してくださいinstall.packages()

著者に伝える内容は次のとおりです。「著者の皆さん、私はXYZパッケージのファンです。リクエストを行いたいのですが、次のアップデートでABCとDEFをDependsからImportsに移動できますか?パッケージをに追加できません。これが発生するまで、自分のパッケージのインポート。R2.14ですべてのパッケージにNAMESPACEを適用すると、R Coreからの一般的なメッセージは、パッケージは「善良な市民」になるようにする必要があるというものです。Dependsパッケージをロードする必要がある場合、大きな負担がかかります。新しいパッケージに依存するたびに競合をチェックする必要があります。インポートを使用すると、パッケージに副作用がなくなります。これを行うと、他の人のパッケージが破損する可能性があることを理解しています。これは正しいことだと思います。輸入への取り組みを実証し、長期的には、人々がより堅牢なRコードを作成するのに役立ちます。」

  1. importFromを使用します。パッケージ全体をインポートに追加するのではなく、必要な特定の機能のみを追加してください。これは、Roxygen2関数のドキュメントと、NAMESPACEファイルを自動的に生成するroxygenize()を使用して実現します。このようにして、実際に使用する必要のある関数に競合がない場合に、競合のある2つのパッケージをインポートできます。これは退屈ですか?それが習慣になるまでだけ。利点:サードパーティのすべての依存関係をすばやく特定できます。それは助けになります...

  2. パッケージを盲目的にアップグレードしないでください。変更ログを1行ずつ読み、更新が独自のパッケージの安定性にどのように影響するかを検討します。ほとんどの場合、更新は実際に使用する機能には影響しません。

  3. S4クラスは避けてください。ここで手を振っています。S4は複雑で、Rの機能面での検索/検索メカニズムを処理するには十分な頭脳が必要です。これらのOO機能が本当に必要ですか?状態の管理=複雑さの管理-PythonまたはJavaの場合はそのままにします=)

  4. 単体テストを作成します。testthatパッケージを使用してください。

  5. R CMDでパッケージをビルド/テストするときはいつでも、出力を解析して、NOTE、INFO、WARNINGを探してください。また、自分の目で物理的にスキャンします。ビルドステップの一部に、競合を記録しているが、警告などを添付していない部分があります。

  6. サードパーティパッケージへの呼び出しの直後にアサーションと不変条件を追加します。言い換えれば、他の誰かがあなたに与えるものを完全に信頼しないでください。結果を少しstop()調べて、予期しない結果が生じた場合。気が狂う必要はありません-有効で信頼性の高い結果を意味する1つまたは2つのアサーションを選択してください。

もっとあると思いますが、これは今では筋肉の記憶になっています=)もっと来たら増強します。

于 2012-06-08T14:58:09.127 に答える
19

私の見解:

概要:柔軟性には代償が伴います。私はその代金を喜んで支払います。

1)そのような問題を引き起こすパッケージは使用していません。自分のパッケージでそのパッケージの関数が本当に必要な場合はimportFrom()NAMESPACEファイルでを使用します。いずれにせよ、パッケージに問題がある場合は、パッケージの作成者に連絡します。問題は彼らの側にあり、Rの側ではありません。

2)::自分のコード内で使用することはありません。パッケージのユーザーが必要とする関数のみをエクスポートすることで、競合が発生することなく、NAMESPACE内に自分の関数を保持できます。エクスポートされない関数も同じ名前の関数を非表示にしないので、それは二重の勝利です。

環境、名前空間などがどのように機能するかについての優れたガイドは、http: //blog.obeautifulcode.com/R/How-R-Searches-And-Finds-Stuff/にあります。

これは間違いなく、パッケージなどを書くすべての人にとって必読です。::これを読んだ後、パッケージコードで使用する必要がないことに気付くでしょう。

于 2012-06-08T11:14:35.273 に答える