Les problèmes transversaux sont des aspects d’un programme qui affectent plusieurs parties du système, tels que la journalisation, la sécurité, la validation des données et le traitement des erreurs. Ils peuvent être dispersés dans une base de code, ce qui entraîne une duplication du code et des problèmes de maintenance.
Copilot Chat peut aider à remanier les problèmes transversaux en suggérant la mise en œuvre de pratiques de programmation orientée aspects (AOP) ou en utilisant des décorateurs et des modèles d’intergiciels pour centraliser ces problèmes d’une manière modulaire et maintenable.
Exemple de scénario
Imaginez que vous ayez un projet Python qui contient plusieurs fichiers de service dans lesquels la journalisation se produit. Les informations qui sont journalisées sont définies dans chacun des fichiers de service individuels. Si l’application est modifiée ou étendue à l’avenir, cette conception pourrait entraîner des incohérences dans le contenu et le style des entrées de journal. Vous pouvez consolider et centraliser le comportement de journalisation afin d’éviter qu’il ne soit distribué à travers votre projet.
Voici trois fichiers de notre projet d’exemple : le fichier du point d’entrée (main.py
), le fichier de configuration des messages de journalisation (logging_config.py
) et l’un des fichiers de service (order_service.py
). Le fichier de service de l’exemple montre comment les informations de journalisation sont définies parallèlement à la logique commerciale d’une partie particulière de l’application.
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.")
Exemples d’invite
Ouvrez l’espace de travail du projet dans VS Code ou Visual Studio et entrez le prompt suivant dans l’affichage Copilot Chat.
@workspace Refactor this project by using AOP to avoid logging that has cross-cutting concerns
Note
Le participant au chat @workspace
dans VS Code et Visual Studio fournit à Copilot le contexte de tout le code de votre espace de travail. Vous pouvez utiliser @workspace
lorsque vous souhaitez que Copilot prenne en compte la structure de votre projet et la manière dont les différentes parties de votre code interagissent.
Exemple de réponse
Copilot répond comme suit.
Note
La réponse suivante est un exemple. Copilot Chat Les réponses ne sont pas déterministes, il est donc possible que vous obteniez une réponse différente de celle présentée ici.
Pour refactoriser ce projet à l’aide de la programmation orientée aspects (AOP) afin de gérer la journalisation comme un problème transversal, vous pouvez utiliser une bibliothèque telle que
aspectlib
. Voici comment procéder :
Installez
aspectlib
:
pip install aspectlib
Créer un aspect pour la journalisation dans un nouveau fichier appelé
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}")
Appliquer l’aspect aux méthodes de service dans
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 vous indique ensuite de supprimer le code de journalisation de toutes les classes de service et vous donne le code des fichiers révisés. Par exemple, voici la version révisée de order_service.py
:
class OrderService:
def place_order(self, order):
# In here would be the business logic for placing an order
# ...
pass
Dans la version refactorisée du projet, les mêmes opérations de journalisation sont effectuées, mais le code de journalisation est centralisé dans un seul fichier.