【公ド読】横断的関心事の処理

【公式ドキュメントを読もうシリーズ】横断的関心事の処理

## シリーズ概要

[https://qiita.com/yasu_programming/items/cec66f9e8d5d571e9ce3](https://qiita.com/yasu_programming/items/cec66f9e8d5d571e9ce3)

## URL

[https://docs.github.com/ja/copilot/copilot-chat-cookbook/refactoring-code/handling-cross-cutting-concerns](https://docs.github.com/ja/copilot/copilot-chat-cookbook/refactoring-code/handling-cross-cutting-concerns)

## 説明

アスペクト指向プログラミング (AOP)に沿ったリファクタリングをしてくれる。

下記のプロンプトで関心の分離をしてくれる。

> `@workspace Refactor this project by using AOP to avoid logging that has cross-cutting concerns`

## 所感

責務の分離ができているコードを見ると見やすいので、サクサク仕事が進むなあという感覚があるが、そういったリファクタリングをしてくれる。

アスペクト指向プログラミングという言葉を初めて知ったが、今までできていなかったので勉強になった。

ログ、セキュリティ、データ検証、エラー処理をそれぞれのビジネスロジック内に入れていたが、純粋なビジネスロジックだけを作成するという手法もあるんですね。

大規模開発とかだと使うのかもしれないですね。ロボットの組み立てっぽいというかパズルっぽい感じでプログラミングができそう。

AI君が出力した比較できるコードが下記の通りです。

### 従来のコード

```
def user_service():
    try:
        # ビジネスロジック
        result = process_user_data()
        return result
    except DatabaseError as e:
        logger.error(f"Database error: {e}")
        raise ServiceException("User processing failed")
    except ValidationError as e:
        logger.error(f"Validation error: {e}")
        raise ServiceException("Invalid user data")

def order_service():
    try:
        # ビジネスロジック
        result = process_order()
        return result
    except DatabaseError as e:
        logger.error(f"Database error: {e}")  # 重複コード
        raise ServiceException("Order processing failed")
    except ValidationError as e:
        logger.error(f"Validation error: {e}")  # 重複コード
        raise ServiceException("Invalid order data")
```

### AOPを使用したコード

```
import functools
import logging
from typing import Dict, Type, Callable

logger = logging.getLogger(__name__)

class ServiceException(Exception):
    pass

class DatabaseError(Exception):
    pass

class ValidationError(Exception):
    pass

# エラーハンドリングのアスペクト
def error_handler(error_mappings: Dict[Type[Exception], str]):
    """エラー処理のデコレータ（アスペクト）"""
    def decorator(func: Callable):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except Exception as e:
                # 共通のエラー処理ロジック
                error_type = type(e)
                if error_type in error_mappings:
                    logger.error(f"{error_type.__name__}: {e}")
                    raise ServiceException(error_mappings[error_type])
                else:
                    logger.error(f"Unexpected error: {e}")
                    raise ServiceException("An unexpected error occurred")
        return wrapper
    return decorator

# ビジネスロジックからエラー処理を分離
@error_handler({
    DatabaseError: "User processing failed",
    ValidationError: "Invalid user data"
})
def user_service():
    # 純粋なビジネスロジックのみ
    return process_user_data()

@error_handler({
    DatabaseError: "Order processing failed", 
    ValidationError: "Invalid order data"
})
def order_service():
    # 純粋なビジネスロジックのみ
    return process_order()

def process_user_data():
    # 実際の処理
    pass

def process_order():
    # 実際の処理
    pass
```

単純なコード生成だけではなく、アーキテクチャの提案などもしてくれるので、初心者だけではなく、概念の具体化なども出来て良いなあと思いました。