횡단 관심사는 로깅, 보안, 데이터 유효성 검사, 오류 처리와 같은 시스템의 여러 부분에 영향을 주는 프로그램의 애스팩트입니다. 코드베이스 전체에 분산되어 코드 중복과 유지 관리 문제가 발생할 수 있습니다.
Copilot Chat는 AOP(측면 지향 프로그래밍) 구현을 제안하거나 데코레이터와 미들웨어 패턴을 사용하여 이러한 문제를 모듈식으로 유지 관리 가능한 방식으로 중앙 집중화하여 교차 절단 문제를 리팩터링하는 데 도움이 될 수 있습니다.
예제 시나리오
로깅이 발생하는 여러 서비스 파일이 포함된 Python 프로젝트가 있다고 상상해 보세요. 기록되는 정보는 개별 서비스 파일 내에서 정의됩니다. 나중에 애플리케이션을 수정하거나 확장하면 이 디자인으로 인해 로그 항목의 콘텐츠와 스타일이 일치하지 않을 수 있습니다. 로깅 동작을 통합하고 중앙 집중화하여 프로젝트 전체에 분산되지 않도록 할 수 있습니다.
다음은 예제 프로젝트의 세 가지 파일인 진입점 파일(main.py
), 로그 메시지 구성 파일(logging_config.py
) 및 서비스 파일(order_service.py
) 중 하나입니다. 예제 서비스 파일은 애플리케이션의 특정 부분에 대한 비즈니스 논리와 함께 로그 정보가 정의되는 방법을 보여줍니다.
main.py
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
import logging
def setup_logging():
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
order_service.py
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 보기에 다음 프롬프트를 입력합니다.
@workspace Refactor this project by using AOP to avoid logging that has cross-cutting concerns
Note
VS Code 및 Visual Studio의 채팅 참가자는 @workspace
Copilot에게 작업 영역의 모든 코드에 대한 컨텍스트를 제공합니다. Copilot가 프로젝트의 구조, 코드의 여러 부분이 상호 작용을 하는 방식을 고려하도록 하려면 @workspace
를 사용하세요.
예제 응답
Copilot는 다음과 같이 응답합니다.
Note
다음 응답이 예제입니다. Copilot Chat 응답은 비결정적이므로 여기에 표시된 응답과 다른 응답을 얻을 수 있습니다.
AOP(관점 지향 프로그래밍)를 사용하여 이 프로젝트를 리팩터링하여 횡단 관심사로 로깅을 처리하려면
aspectlib
와 같은 라이브러리를 사용할 수 있습니다. 수행할 방법은 다음과 같습니다.
aspectlib
설치:
pip install aspectlib
logging_aspect.py
라는 새 파일에 로깅하기 위한 애스팩트를 만듭니다.
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}")
main.py
의 서비스 메서드에 해당 애스팩트를 적용합니다.
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
의 수정된 버전은 다음과 같습니다.
class OrderService:
def place_order(self, order):
# In here would be the business logic for placing an order
# ...
pass
프로젝트의 리팩터링된 버전에서 동일한 로깅 작업이 수행되지만, 로깅 코드는 단일 파일에서 중앙 집중화됩니다.