# 횡단 관심사 처리

Copilot Chat 는 코드가 있는 메서드 또는 함수의 핵심 관심사가 아닌 우려 사항과 관련된 코드를 방지하는 데 도움이 될 수 있습니다.

횡단 관심사는 로깅, 보안, 데이터 유효성 검사, 오류 처리와 같은 시스템의 여러 부분에 영향을 주는 프로그램의 애스팩트입니다. 코드베이스 전체에 분산되어 코드 중복과 유지 관리 문제가 발생할 수 있습니다.

Copilot Chat 는 AOP(Aspect-Oriented 프로그래밍) 사례의 구현을 제안하거나 데코레이터 및 미들웨어 패턴을 사용하여 이러한 문제를 모듈식으로 유지 관리 가능한 방식으로 중앙 집중화하여 교차 절단 문제를 리팩터링하는 데 도움이 될 수 있습니다.

## 예제 시나리오

로깅이 발생하는 여러 서비스 파일이 포함된 Python 프로젝트가 있다고 상상해 보세요. 기록되는 정보는 개별 서비스 파일 내에서 정의됩니다. 나중에 애플리케이션을 수정하거나 확장하면 이 디자인으로 인해 로그 항목의 콘텐츠와 스타일이 일치하지 않을 수 있습니다. 로깅 동작을 통합하고 중앙 집중화하여 프로젝트 전체에 분산되지 않도록 할 수 있습니다.

다음은 예제 프로젝트의 세 가지 파일인 진입점 파일(`main.py`), 로그 메시지 구성 파일(`logging_config.py`) 및 서비스 파일(`order_service.py`) 중 하나입니다. 예제 서비스 파일은 애플리케이션의 특정 부분에 대한 비즈니스 논리와 함께 로그 정보가 정의되는 방법을 보여줍니다.

### 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
```

프로젝트의 리팩터링된 버전에서 동일한 로깅 작업이 수행되지만, 로깅 코드는 단일 파일에서 중앙 집중화됩니다.

## 추가 읽기

* [GitHub Copilot 채팅에 대한 프롬프트 엔지니어링](/ko/copilot/concepts/prompting/prompt-engineering)
* [GitHub 부필로트 사용에 대한 모범 사례](/ko/copilot/get-started/best-practices)