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:
Instale
aspectlib
:
pip install aspectlib
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}")
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.