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

The following response is an example. Copilot Chat responses are non-deterministic, so you may get a different response from the one shown here.

Для рефакторинга этого проекта с помощью программирования на основе аспектов (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

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

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