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

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

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

Copilot Chat может помочь реорганизовать перекрёстные вопросы, предлагая внедрение практик Aspect-Oriented программирования (AOP) или используя декораторов и шаблоны промежуточного программного обеспечения для централизации этих вопросов модульно, поддерживаемым образом.

## Пример сценария

Представьте, что у вас есть Python-project, содержащий несколько сервисных файлов, в которых происходит логирование. Сведения, которые регистрируются, определяются в каждом из отдельных файлов службы. Если приложение изменено или расширено в будущем, это может привести к несоответствию содержимого и стиля записей журнала. Вы можете консолидировать и централизовать ведение логирования, чтобы избежать распространения этого по вашему project.

Вот три файла из нашего примера project: файл входной точки (`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 StudioCopilot контекст обо всём коде в вашем рабочем пространстве. Вы можете использовать `@workspace` , когда хотите Copilot рассмотреть структуру вашего проекта и то, как разные части вашего кода взаимодействуют. Если вы используете IDE JetBrains, используйте `@project` вместо `@workspace`.

## Пример ответа

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

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

> Для рефакторинга project использования Aspect-Oriented программирования (AOP) для ведения логирования как перекрёстной задачи, можно использовать библиотеку вроде `aspectlib`. Вот как это сделать:
>
> 1. Установите `aspectlib`:
>
>    `pip install aspectlib`
>
> 2. Создайте аспект для ведения журнала в новом файле:`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}")
>    ```
>
> 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
>    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
```

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

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

* [Инженерия подсказок для GitHub Copilot Chat](/ru/copilot/concepts/prompting/prompt-engineering)
* [Лучшие практики использования GitHub Copilot](/ru/copilot/get-started/best-practices)