Skip to main content

Gestión de problemas transversales

Copilot Chat puede ayudarte a evitar código que se relacione con un problema distinto al problema principal del método o función en la que se encuentra dicho código.

Los problemas transversales son aspectos de un programa que afectan a varias partes del sistema, como el registro, la seguridad, la validación de datos y el control de errores. Pueden dispersarse por toda la base de código, lo que genera duplicación de código y problemas de mantenimiento.

Copilot Chat puede ayudar a refactorizar problemas transversales al sugerir la implementación de prácticas de programación orientada a aspectos (AOP) o el uso de decoradores y patrones de middleware para centralizar estos problemas de una manera modular y fácil de mantener.

Escenario de ejemplo

Imagina que tienes un proyecto de Python que contiene varios archivos de servicio en los que se produce el registro. La información que se registra se define dentro de cada uno de los archivos de servicio individuales. Si la aplicación se modifica o amplía en el futuro, este diseño podría provocar incoherencias en el contenido y el estilo de las entradas de registro. Puedes consolidar y centralizar el comportamiento de registro para evitar que se distribuya en el proyecto.

Estos son tres archivos del proyecto de ejemplo: el archivo de punto de entrada (main.py), el archivo de configuración de mensajes de registro (logging_config.py) y uno de los archivos de servicio (order_service.py). El archivo de servicio de ejemplo muestra cómo se define la información de registro junto con la lógica de negocios de una parte determinada de la aplicación.

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.")

Ejemplos de indicaciones

Abre el área de trabajo del proyecto en VS Code o Visual Studio y escribe el siguiente mensaje en la vista Copilot Chat.

@workspace Refactor this project by using AOP to avoid logging that has cross-cutting concerns

Note

El participante del chat @workspace en VS Code y Visual Studio proporciona Copilot con contexto sobre todo el código del área de trabajo. Puedes usar @workspace cuando quieras que Copilot tenga en cuenta la estructura del proyecto y, cómo interactúan las distintas partes del código.

Respuesta de ejemplo

Copilot responde de la manera siguiente.

Note

La respuesta siguiente es un ejemplo. Las respuestas de Copilot Chat no son deterministas, por lo que puedes obtener una respuesta diferente a la aquí mostrada.

Para refactorizar este proyecto mediante la programación orientada a aspectos (AOP) para controlar el registro como un problema transversal, puedes usar una biblioteca como aspectlib. Así es cómo se puede hacer:

  1. Instale aspectlib:

    pip install aspectlib

  2. Crea un aspecto para registrarlo en un nuevo archivo llamado 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. Aplica el aspecto a los métodos de servicio en 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 te indica que quites el código de registro de todas las clases de servicio y te proporciona el código para los archivos revisados. Por ejemplo, esta es la versión revisada de order_service.py:

class OrderService:
    def place_order(self, order):
        # In here would be the business logic for placing an order
        # ...
        pass

En la versión refactorizado del proyecto, se realizan las mismas operaciones de registro, pero el código de registro se centraliza en un único archivo.

Información adicional