Skip to main content

Обработка перекрестных проблем

Copilot Chat помогает избежать кода, связанного с проблемой, отличной от основной проблемы метода или функции, в которой находится код.

Перекрестные проблемы — это аспекты программы, влияющие на несколько частей системы, таких как ведение журнала, безопасность, проверка данных и обработка ошибок. Они могут быть разбросаны по базе кода, что приводит к дублированию кода и проблемам обслуживания.

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

Участник @workspace чата в VS Code и Visual Studio предоставляет Copilot контекстом обо всем коде в рабочей области. Вы можете использовать @workspace , если требуется Copilot для рассмотрения структуры проекта и способа взаимодействия различных частей кода.

Пример отклика

Copilot отвечает следующим образом.

Note

Следующий ответ является примером. Ответы Copilot Chat являются недетерминированными, поэтому вы можете получить другой ответ, показанный здесь.

Для рефакторинга этого проекта с помощью программирования на основе аспектов (AOP) для обработки ведения журнала в качестве перекрестной проблемы можно использовать библиотеку, например aspectlib. Вот как это сделать:

  1. Установите aspectlib:

    pip install aspectlib

  2. Создайте аспект для ведения журнала в новом файле: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}")
    
  3. Применение аспекта к методам службы в 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

В рефакторинговой версии проекта выполняются те же операции ведения журнала, но код ведения журнала централизованный в одном файле.

Дополнительные материалы