Preocupações paralelas são aspectos de um programa que afetam várias partes do sistema, como registro em log, segurança, validação de dados e tratamento de erros. Elas podem se espalhar por uma base de código, levando a desafios de duplicação e manutenção de código.
O Copilot Chat pode ajudar a refatorar preocupações paralelas sugerindo a implementação de práticas de AOP (programação orientada a aspectos) ou usando decoradores e padrões de middleware para centralizar essas preocupações de maneira modular e passível de manutenção.
Cenário de exemplo
Imagine que você tem um projeto de Python que contém vários arquivos de serviço nos quais ocorre o registro em log. As informações que são registradas são definidas em cada um dos arquivos de serviço individuais. Se o aplicativo for modificado ou estendido no futuro, esse design poderá levar a inconsistência no conteúdo e no estilo das entradas de log. Você pode consolidar e centralizar o comportamento do registro em log para evitar que isso seja distribuído em seu projeto.
Estes são três arquivos de nosso projeto de exemplo: o arquivo de ponto de entrada (main.py
), o arquivo de configuração da mensagem de log (logging_config.py
) e um dos arquivos de serviço (order_service.py
). O arquivo de serviço de exemplo mostra como as informações de log são definidas em conjunto com a lógica de negócios de uma parte específica do aplicativo.
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.")
Solicitação de exemplo
Abra o workspace do projeto no VS Code ou Visual Studio e insira o prompt a seguir na exibição Copilot Chat.
@workspace Refactor this project by using AOP to avoid logging that has cross-cutting concerns
Note
O participante do chat @workspace
no VS Code e Visual Studio fornece ao Copilot contexto sobre todo o código em seu workspace. Você pode usar o @workspace
quando quer que o Copilot considere a estrutura do projeto e como diferentes partes do código interagem.
Exemplo de resposta
O Copilot responde da seguinte maneira.
Note
A resposta a seguir é um exemplo. Respostas do Copilot Chat são não determinísticas, portanto, você pode obter uma resposta diferente da mostrada aqui.
Para refatorar esse projeto usando a AOP (programação orientada a aspectos) para lidar com o registro em log como uma preocupação paralela, você pode usar uma biblioteca como
aspectlib
. Veja como fazer isso:
Instale
aspectlib
:
pip install aspectlib
Crie um aspecto para registrar em log em um novo arquivo chamado
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}")
Aplique o aspecto aos métodos de serviço em
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()
O Copilot instrui você a remover o código de log de todas as classes de serviço e fornece o código para os arquivos revisados. Por exemplo, esta é a versão revisada de order_service.py
:
class OrderService:
def place_order(self, order):
# In here would be the business logic for placing an order
# ...
pass
Na versão refatorada do projeto, as mesmas operações de log são executadas, mas o código de log é centralizado em um só arquivo.