MPS 2019.1ヘルプ

生成コードからのソースの削除

MPSはデフォルトでソースを生成モデルにバンドルします。モデルのユーザーは、自分のコードで使用している概念の定義にナビゲートすることができます。たとえば、呼び出しているメソッドやインスタンス化しているクラスの実装を確認するには、1回のControlキーを押しながらクリックするだけです。彼らは単に実装側を覗くことによって言語/ライブラリーの作者のアイデアの多くを把握することができるため、これはユーザーにとって非常に便利です。
ただし、実装を隠すことが望ましい場合があるかもしれません。特にクローズドソースプロジェクトでは、実装に含まれる知的財産を慎重に保護する必要があります。ユーザーはまだコードを呼び出すことができるはずですが、Control + Bを押すと、クラスとメソッドのシグネチャーを見ることしかできなくなります。

obfuscated1

難読化されたクラスファイルと、リバースエンジニアリングによる他の人へのチャンスとを組み合わせると、ハードワークの成果はかなり低くなります。これを行う方法を見つけるために参照してください。

BaseLanguageコードからソースを削除する

BuildLanguageは、特定のアーティファクトからソースを削除する必要があることを示すためのストリップ実装フラグを提供します。

obf2

いずれかのビルドレイアウトコマンド( modulesources ofplugin )でこのフラグをtrueに設定すると、生成されたアーティファクトから実装のソースを削除するようにビルドプロセスに指示します。このフラグは、BaseLanguageメソッドの本体が空のStatementListに置き換えられ、クラスの静的およびインスタンス初期化子が削除されるようにします。言語の実装を隠したい場合は、このフラグによって、振る舞いメソッドの本体も空のStatementListに置き換えられます。

まとめると、MPSはそのまま使用できます。

  • BaseLanguageで書かれたあなたの実装を隠す

  • 言語定義の側面を隠す

必要なソリューションまたは言語に合わせて、ビルドスクリプトでstrip実装フラグを設定するだけです。

いくつかの便利なメモ

  1. MPSでキャッシュの破棄を使用する機能は、ストリップされたバージョンとされていないバージョンの言語を含むプロジェクトを切り替えるときに便利です。

  2. ビルドスクリプトが生成された成果物の変更を反映するように、言語に手動で変更を加える必要がある場合があります。

独自の言語のための実装ストリッピングのカスタマイズ

BaseLanguageコードが実装の隠蔽を許可するのと同じように、あなたの言語も実装の隠蔽を許可することができます。

MPSは実装ストリッピングに関してあなたの言語の概念の意図されたふるまいを区別するためにあなたに3つのマーカーインターフェースを与えます:

  • InterfacePart - 生成されたモデルに完全に表示される概念ユーザーは自分のところに移動して自分のコード内でそれらの参照を保持することができます。

  • ImplementationPart - 生成されたモデルから削除される概念ユーザーは自分のコードに移動したり、自分の参照を自分のコードで保持したりできなくなります。

  • ImplementationWithStubPart - 空のスタブに置き換えられる概念。コード内のノードを表すためにスタブ置換が使用される点を除いて、ImplementationPartのように動作します。たとえば、空のメソッド本体を表す/* compiled code */マークを考えてください。

ロボットカヤサンプル

たとえば、Robot Kajaのサンプル言語(MPSにバンドルされている)を使用してその実装を隠すことができるようにしたい場合は、いくつかの手順で実現できます。次のシナリオを想定しましょう。

  1. エンドユーザーがロボットカヤ言語でSampleRobotScriptsプロジェクトの一部としてスクリプトを書いています。彼はロボットルーチン(MPSソリューション)と呼ばれるロボットルーチンのライブラリーをダウンロードして再利用したいと考えています。

  2. ロボットルーチンの作者は彼女のライブラリーの実装を隠したいと思います。

  3. ロボットルーチンの実装を隠すことをサポートするために、ロボットカヤ言語を修正する必要があります。それは、その概念のうちどれがその言語で書かれたアプリケーション/ライブラリーのパブリックインターフェース(契約)を形成し、どれがその実装を保持するかを宣言する必要があります。単純な言語を選んだため、3つの概念だけを本当にインターフェースの一部にする必要があることを識別するのはかなり簡単です。他の人たちはパッケージングの間に彼らの源を取り除かれることができます。
    1. スクリプト
    2. ライブラリー
    3. ルーチン定義

初期の状況

Robot Kaja言語では、ライブラリーのルーチンを作成できます。ライブラリーは根本的な概念であり、コレクションまたはルーチン定義を保持します。ロボットカヤ言語を使用するロボットルーチンライブラリーは、いくつかのライブラリールートノードを作成し、それらにいくつかの便利なルーチンを実装することができます。

obf6

SampleRobotScriptsコードで使用すると、開発者はいつでも定義に移動してロボットルーチンライブラリーの完全な実装を見ることができます。

obf3
obf4b

ゴール

ロボットルーチンなどのライブラリーの作者に実装を隠す機能を提供したいです。一度正しく実装されると、SampleRobotScriptsの開発者はルーチンのシグネチャーとそれらの空の本体しか見ることができません。

obf4a

Robot Kaja言語への変更

ロボットカヤ言語では、スクリプトライブラリー、およびルーチン定義の概念をInterfacePartインターフェースでマークする必要があります。これは、ユーザーコードで参照できるためです。

obf7
obf8

ルーチンの実装を隠すには、それらの本体を隠す必要があります。ルーチン本体はCommandListの概念です。それを隠すには、ImplementationPartインターフェースまたはImplementationWithStubPartインターフェースのいずれかでそれをマークする必要があります。どちらも実装を隠すことになりますが、後者では削除された実装の代わりに挿入される置換「スタブ」の概念を提供できます。スタブは、削除された実装でコードの見栄えをよくする機会を提供します。エンドユーザーに時折見られるような隠れた実装については常に考慮する必要があります。

obf9

スタブ作成

ImplementationPartに対するImplementationWithStubPartのオーバーヘッドは、スタブの概念を作成することにあります。私たちのCommandListのためにStubCommandList概念を必要とし、それをIDontSubstituteByDefaultIStubForAnotherConceptでマークします。StubCommandListCommandListからImplementationWithStubPartインターフェースを継承するため、IStubForAnotherConceptが必要です。MPSは、StubCommandListがスタブ自体であり、さらに別のスタブによってスタブされる必要がないことを明示的に伝える必要があります。

stubx2

StubCommandListCommandListの代わりにAbstractCommandを拡張していた場合、AbstractCommandImplementationWithStubPartではないため、IStubForAnotherConceptとしてマークする必要はありません。

stubx3

スタブエディターは、実装が削除されており、ここでは表示されないことを読者に丁寧に明らかにする必要があります。

obf11

再構築してパッケージ化すると、言語はロボットルーチンの作者が彼女のライブラリーの実装を隠すのを手助けする準備ができています。

ライブラリー作家のためのスクリプトを作成する

ロボットカヤ言語が実装の削除をサポートするようになると、ロボットルーチンライブラリーの作者は自分のビルドスクリプトでstripの実装フラグを設定し、生成されたプラグインから自分のライブラリーの実装のソースを削除することができます。

obf5

一般的なガイドラインと追加の注意事項

  1. マーカーインターフェースは、スーパーコンセプトとスーパーコンセプトインターフェースから伝統的な方法で継承されます。複数のマーカーインターフェースが概念に適用可能な場合(直接または継承を通じて)、InterfacePartが他のものに勝ち、ImplementationWithStubPartImplementationPartに勝ちます。

  2. どのマーカーインターフェースも指定されていない場合、概念はInterfacePartが設定されているかのように動作します: InterfacePartで概念をマークすることは2つの目的に役立ちます:
    • 概念があなたの言語の必要な公的要素であるという事実を文書化する

    • たとえば、概念が他のフラグのいずれかを継承している場合に、その概念が誤って実装の一部としてマークされるのを防ぎます。

  3. ImplementationPartインターフェースを使用して、クライアントコードから参照する必要がない、または必須(基数1および1..n)リンクを介してInterfacePartの概念から直接アクセスする必要がない言語の概念をマークします。これらの概念のソースはビルド中にソリューションから削除されるため、ユーザーはコンセプト宣言へを使用するなどして定義を確認することはできません。

  4. ImplementationPartと同様に削除すべき概念をマークするためにImplementationWithStubPartインターフェースを使用しますが、ユーザーは概念の定義の一部として見ることができるため、単純にソースから削除する代わりにプレースホルダーに置き換える必要があります: InterfacePartのコンセプト

  5. ImplementationWithStubPartは、InterfacePartの概念から指し示す基数1および1..nの子または参照の参照先を表す概念には通常必要です。なぜなら、含むリンクは空のままにできず、検証エラーを報告するからです。

  6. 0..1および0..nの基数を持つ参照の子およびターゲットは、安全にImplementationPartとしてマークできます。含まれているリンクは空のままになります。

  7. スタブは命名規則置き換えられる概念のスタブ+名前に従い、置き換えられた概念を持つ同じパッケージ内に配置されなければなりません。

  8. スタブの概念は、それらの子ノードから型システムエラーが報告されるのを避けるためにISuppressErrorsを実装することができます。

  9. スタブは、それらがコード補完メニューで提供されないようにIDontSubstituteByDefaultも実装するべきです。

  10. 概念がInterfacePart実装(WithStub)パートの両方である場合、MPSは警告を報告します。

  11. 概念がImplementationWithStubPartインターフェースを宣言または継承し、同じ仮想パッケージ内に適切なスタブ概念が見つからない場合、MPSはエラーを報告します。

  12. ImplementationWithStubPartインターフェースを継承するスタブは、おそらくスタブ化された概念を拡張することによって、それらがスタブであることを示すためにIStubForAnotherConceptを実装する必要があるため、自分でスタブする必要はありません。すべてのスタブにIStubForAnotherConceptインターフェースを実装させるのは良い戦略です。

  13. スタブは抽象的なスーパーコンセプトを置き換えるように定義することはできません。彼らは常にImplementationWithStubPartを実装する1つの具体的な概念のために1つのスタブとして、すべての具体的な概念を個別に置き換える必要があります。

  14. 明確なメッセージを表示するようにスタブの概念のエディターを再定義します。別名「コンパイル済みコード」は、実装が削除されたことを読者に明確に示すためのものです。

  15. 削除された言語のユーザーがスタブ化された概念で見られるモデル検証エラーを回避するために、すべての子の「特殊化」およびそれらのスーパー概念からスタブ概念に継承された「少なくとも1」カーディナリティの参照を検討してください。

これは、次のような概念に必要です。modelAccessorの子はカーディナリティ1を持つため、スタブ化された概念では必須です。

Hid1

スタブの概念は、スタブをスタブの概念の名前の前に付けるという命名規則に従う必要があります。スタブ化された概念を拡張する必要があるかもしれませんし、そうでないかもしれません - これは元の概念が他の言語からどのように参照されているかに依存します。スタブの概念がスタブの概念を拡張する必要がある場合は、子参照が空のままにならないように、何らかの理由で必須の子を処理する必要もあります。

推奨される方法は、子または参照関係を特殊化し、ターゲットの概念をBaseConceptに変更することです。

Stubx1

コンストラクターの動作の側面では、IntegerConstantなどのダミーノードを指すように参照を設定します。これにより、リンクが空のままにならないようになりますが、スタブ化された概念で元のmodelAccessorリンクを完全に満たすノードを作成する必要がなくなります。

Hid3
最終更新日: 2019年6月7日