Skip to main content

Gestión de problemas transversales

Chat de Copiloto puede ayudarle a evitar el código relacionado con una preocupación distinta de la preocupación principal del método o la función en la que se encuentra el 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.

Chat de Copiloto puede ayudar a refactorizar aspectos transversales sugiriendo 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 aspectos de forma modular y mantenible.

Escenario de ejemplo

Imagínese que tiene un proyecto de Python que contiene varios archivos de servicio en los que se realiza el registro de eventos. 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.")

Mensaje de ejemplo

Abra el área de trabajo del proyecto en VS Code o Visual Studio y escriba la siguiente instrucción en la vista Chat de Copiloto.

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

Nota:

El @workspace participante del chat en VS Code y Visual Studio ofrece Copilot información contextual sobre todo el código en tu área de trabajo. Puede usar @workspace cuando desee Copilot tener en cuenta la estructura del proyecto y cómo interactúan diferentes partes del código. Si usas un IDE de JetBrains, utiliza @project en lugar de @workspace.

Respuesta de ejemplo

Copilot responde de la siguiente manera.

Nota:

La respuesta siguiente es un ejemplo. Las respuestas de Chat de Copiloto 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 a continuación, le indica que quite el código de registro de todas las clases de servicio y le proporcione 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 refactorizada del proyecto, se realizan las mismas operaciones de registro, pero el código de registro se centraliza en un archivo único.

Lectura adicional