# 横断的関心事の処理

Copilot Chat は、コードが配置されているメソッドまたは関数の主要な懸念事項以外の懸念事項に関連するコードを回避するのに役立ちます。

横断的関心事は、ログ、セキュリティ、データ検証、エラー処理など、システムの複数の部分に影響を与えるプログラムの側面です。 それらは、コードベース全体にちらばっていて、コードの重複やメンテナンスの課題の原因になる可能性があります。

Copilot Chat は、Aspect-Oriented プログラミング (AOP) プラクティスの実装を提案するか、デコレーターとミドルウェア パターンを使用してモジュール式の保守可能な方法でこれらの懸念を一元化することで、横断的な懸念をリファクタリングするのに役立ちます。

## サンプル シナリオ

ログが行われる複数のサービス ファイルを含む Python プロジェクトがあるとします。 ログされる情報は、個々のサービス ファイル内で定義されています。 将来、アプリケーションが変更または拡張される場合、この設計のため、ログ エントリの内容とスタイルに不整合が生じる可能性があります。 ログの動作を統合して一元化し、これがプロジェクト全体に広がるのを防ぐことができます。

このプロジェクト例には、エントリ ポイント ファイル (`main.py`)、ログ メッセージ構成ファイル (`logging_config.py`)、サービス ファイル (`order_service.py`) という 3 つのファイルがあります。 サービス ファイルの例では、ログ情報の定義方法と、アプリケーションの特定の部分のビジネス ロジックが示されています。

### main.py

```python
import logging
from logging_config import setup_logging
from payment_service import PaymentService
from order_service import OrderService
from shipping_service import ShippingService
from inventory_service import InventoryService
from notification_service import NotificationService

def main():
    setup_logging()
    payment_service = PaymentService()
    order_service = OrderService()
    shipping_service = ShippingService()
    inventory_service = InventoryService()
    notification_service = NotificationService()

    # Example usage
    payment_service.process_payment({"amount": 100, "currency": "USD"})
    order_service.place_order({"item": "Book", "quantity": 1})
    shipping_service.ship_order({"item": "Book", "quantity": 1})
    inventory_service.update_inventory("Book", -1)
    notification_service.send_notification("Order has been placed and shipped.")

if __name__ == "__main__":
    main()
```

### logging\_config.py

```python
import logging

def setup_logging():
    logging.basicConfig(level=logging.INFO,
                  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
```

### order\_service.py

```python
import logging

class OrderService:
    def __init__(self):
        self.logger = logging.getLogger(__name__)

    def place_order(self, order):
        self.logger.info("Entering place_order method.")
        try:
            # In here would be the business logic for placing an order
            # ...
            self.logger.info("Order placed successfully.")
        except Exception as e:
            self.logger.error(f"Error in place_order method: {e}")
            raise
        finally:
            self.logger.info("Exiting place_order method.")
```

## プロンプトの例

VS CodeまたはVisual Studioでプロジェクト ワークスペースを開き、Copilot Chat ビューに次のプロンプトを入力します。

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

> \[!NOTE]
> `@workspace`とVS CodeのVisual Studio チャット参加者は、ワークスペース内のすべてのコードに関するコンテキストをCopilotに提供します。 `@workspace`は、プロジェクトの構造やコードのさまざまな部分の相互作用を考慮したいときにCopilotを使用できます。 JetBrains IDE を使っている場合は、`@project` ではなく `@workspace` を使ってください。

## 応答の例

Copilot は次のように応答します。

> \[!NOTE] 次の応答は例です。 Copilot Chat の応答は非決定的であるため、ここで示したものとは異なる応答が返される可能性があります。

> アスペクト指向プログラミング (AOP) を使ってこのプロジェクトをリファクタリングし、ログを横断的関心事として処理するには、`aspectlib` などのライブラリを使用できます。 これを行う方法を次に示します。
>
> 1.

`aspectlib` をインストールします。

> `pip install aspectlib`
>
> 1.

`logging_aspect.py` という名前の新しいファイルでログのアスペクトを作成します。

> ```python
> import aspectlib
> import logging
>
> @aspectlib.Aspect(bind=True)
> def log_method_call(cutpoint, *args, **kwargs):
>     logger = logging.getLogger()
>     method_name = cutpoint.__name__
>     logger.info(f"Entering method: {method_name}")
>     try:
>         result = yield aspectlib.Proceed
>         logger.info(f"Method {method_name} executed successfully.")
>         return result
>     except Exception as e:
>         logger.error(f"Error in method {method_name}: {e}")
>         raise
>     finally:
>         logger.info(f"Exiting method: {method_name}")
> ```
>
> 1.

`main.py` のサービス メソッドにそのアスペクトを適用します。

> ```python
> import logging
> from logging_config import setup_logging
> from payment_service import PaymentService
> from order_service import OrderService
> from shipping_service import ShippingService
> from inventory_service import InventoryService
> from notification_service import NotificationService
> from logging_aspect import log_method_call
> import aspectlib
>
> def main():
>     setup_logging()
>
>     # Apply logging aspect to service methods
>     aspectlib.weave(PaymentService.process_payment, log_method_call)
>     aspectlib.weave(OrderService.place_order, log_method_call)
>     aspectlib.weave(ShippingService.ship_order, log_method_call)
>     aspectlib.weave(InventoryService.update_inventory, log_method_call)
>     aspectlib.weave(NotificationService.send_notification, log_method_call)
>
>     payment_service = PaymentService()
>     order_service = OrderService()
>     shipping_service = ShippingService()
>     inventory_service = InventoryService()
>     notification_service = NotificationService()
>
>     # Example usage
>     payment_service.process_payment({"amount": 100, "currency": "USD"})
>     order_service.place_order({"item": "Book", "quantity": 1})
>     shipping_service.ship_order({"item": "Book", "quantity": 1})
>     inventory_service.update_inventory("Book", -1)
>     notification_service.send_notification("Order has been placed and shipped.")
>
> if __name__ == "__main__":
>     main()
> ```

Copilot 次に、すべてのサービス クラスからログ コードを削除するように指示し、変更されたファイルのコードを提供します。 たとえば、次に示すのは `order_service.py` の改訂版です。

```python
class OrderService:
    def place_order(self, order):
        # In here would be the business logic for placing an order
        # ...
        pass
```

リファクタリング後のバージョンのプロジェクトでは、同じログ操作が実行されますが、ログのコードは 1 つのファイルに一元化されています。

## 詳細については、次を参照してください。

* [GitHub Copilot Chat のプロンプト エンジニアリング](/ja/enterprise-cloud@latest/copilot/concepts/prompting/prompt-engineering)
* [GitHub Copilot の使用に関するベスト プラクティス](/ja/enterprise-cloud@latest/copilot/get-started/best-practices)