Help us understand the problem. What is going on with this article?

.NET で独自の AOP を導入したら不便になってしまった話

More than 1 year has passed since last update.

ロギングのコードを毎度書かなくてよいって素晴らしいじゃないですか?
それではアスペクト指向プログラミング (AOP) を開発に取り入れよう。と思い、AOP をプロジェクトに導入してしたら不便になってしまった話をします。

AOP の実装方法

.NET で AOP を実装する方法をいくつかご紹介します。

  • RealProxy クラスを使用して、独自に実装する方法
  • Unity Container (Unity) ライブラリを使用する方法
  • PostSharp ライブラリを使用する方法(商用)

可能な限りライブラリに依存しない方法で進めていくプロジェクトだったので、今回は RealProxy クラスを使って実装することにしました。
参考にした URL を記載しておきます。

.NETにおいてAOPを実現する透過プロキシ - マイクロソフト系技術情報 Wiki

アスペクト指向プログラミング - RealProxy クラスによるアスペクト指向プログラミング

UnityでAOPをしよう in C# for Visual Studio 2012

C#のAOPライブラリ(PostSharp) - Status Code 303 - See Other

出来上がったコードたち

載せるコードを短くしたかったので簡略化しています。実際に使用していたときはメソッドのパラメーターや戻り値などをログファイルに出力したり、ロギング以外のプロキシも復数実装していました。

ロギングプロキシ

public class LogProxy<T> : RealProxy
{
    private readonly T _decorated;
    private LogProxy(T decorated) : base(typeof(T))
    {
        _decorated = decorated;
    }

    public static T Create(T instanse)
    {
        return (T)new LogProxy<T>(instanse).GetTransparentProxy();
    }

    public override IMessage Invoke(IMessage msg)
    {
        var methodCall = msg as IMethodCallMessage;
        var methodInfo = methodCall.MethodBase as MethodInfo;

        Console.WriteLine($"Before executing '{methodCall.MethodName}'");
        var result = methodInfo.Invoke(_decorated, methodCall.InArgs);
        Console.WriteLine($"After executing '{methodCall.MethodName}' ");

        return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall);
    }
}

プロキシを使用可能にするクラス

public class TestModel : MarshalByRefObject
{
    public string MethodA(string param)
    {
        Console.WriteLine($"Testing {param}!");
        return "MethodA OK!";
    }

    public string MethodB(string param)
    {
        Console.WriteLine($"Testing {param}!");
        return "MethodB OK!";
    }
}

実際に使用しているクラス

static void Main(string[] args)
{
    var test = LogProxy<TestModel>.Create(new TestModel());
    test.MethodA("123");
    test.MethodB("ABC");
}

出力結果

https://gyazo.com/9bf2d4463c8baf179f85ae007ed00e51

開発が進むにつれて邪魔になってきた AOP

出来上がったコードだけを見ると自動でログを書いてくれてとても便利です。他にも便利なプロキシクラスをたくさん増やしていきました。
しかし、便利なものが増えていくにつれて問題が発生していきます。その中でも特に厄介だったのがこの部分になります。

デバッグがしづらくなってきた

デバッグ時にステップインしているとプロキシクラスに飛ばされてしまいます。
メソッド等に対してステップインするときは、そのメソッドの処理に入りたいはずです。プロキシに飛ばされるのは凄くストレスです。

https://gyazo.com/e21e8bb53666922c520e429005636e4c

ウォッチウィンドウなどでクラスの状態を見ようとしても、呼び出し元から中身を見ることができません。

https://gyazo.com/fd54ee7445e9a06498c4b5da6f4ed31b

完成したアプリケーション

コード上から AOP はほぼ消えました。そしてロギングは必要な時にそれぞれのクラスで実装するようになりました。残っているのは邪魔になってくる前にテストが完了してリリースしてしまった部分になります。残念ながら技術的負債になってしまいました。

どうすればよかったのか

まとめです。独自に作成した場合と、ライブラリを使用した場合の二つに分けました。上手く開発に成功していれば「こうするべき」というのを書きたかったのですが、今回は上手くいかなかったので気をつけるべき点だけ記載します。

RealProxy クラスを使用する場合

デバッグがしづらくなることを前提に開発を進めてください。それと MarshalByRefObject を使用しているため、パフォーマンスへの影響も考慮してください。
そういった色々な部分も考えながら開発を進めるのは面倒なので、個人的にはもう使いたくありません。

ライブラリを使用する場合

AOP のライブラリに限らず、ライブラリを使用する場合のメリット/デメリットを考慮した上で導入してください。RealProxy クラスがあまりにも微妙だったため、どちらかと言えばライブラリを使用する方法のほうが好きです。

headwaters
常に新しい技術を取り込み、ありとあらゆる技術を駆使してビジネスを仕掛けるエンジニア集団です。技術力をベースに世の中の課題を解決しつつ、クライアントの強みを生かしたスタートアップインテグレーターとして共に事業も展開しています。「AI企画開発​」「マルチAIプラットフォーム(SyncLect)」「ロボットアプリ企画開発​」「React Native/Monaca/PWAアプリ開発」...etc他多数
http://www.headwaters.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした