Ir para o conteúdo

Boas práticas no desenvolvimento de automações em Python

Agora que discutimos a legibilidade e manutenibilidade de código, o guia de estilo de código, o uso efetivo de comentários e documentação, a tipagem (typing), a validação de dados de entrada e a importância dos testes automatizados, podemos aplicar esses conceitos a um contexto prático muito comum com Python RPA que é a modularização e criação de pacotes escaláveis.

Por que criar pacotes Python para usar em automações escaláveis?

Ao desenvolver automações, frequentemente temos funções que se repetem entre diferentes robôs, como:

  • Ler arquivos CSV

  • Conectar em bancos de dados

  • Ler ou enviar e-mails

Empacotar essas funções em um pacote Python reutilizável permite:

  • Reusabilidade / Reuso: Módulos podem ser usados em diferentes processos, projetos ou robôs, sem necessidade de reescrever código.

  • Manutenibilidade / Manutenção: Alterações ou correções podem ser feitas em um único lugar, sem impactar outros módulos.

  • Escalabilidade: À medida que o número de processos aumenta, é fácil adicionar novos módulos e funcionalidades.

  • Facilidade de Testes: Testar módulos individualmente simplifica a identificação e resolução de problemas.

  • Padronização: Mantém consistência entre diferentes projetos e equipes.

  • Colaboração via PR: Permite revisar mudanças, manter a estabilidade da branch principal (main) e melhorar a qualidade do código.

Agora que entendemos a importância de criar pacotes reutilizáveis, podemos aplicar conceitos de legibilidade, manutenibilidade, tipagem e validação no contexto prático de modularização e criação de pacotes escaláveis para Python e automações inteligentes.

Modularização e Criação de Pacotes

A modularização é muito importante em projetos de automação, onde diversas ações, como interação com APIs, leitura de bancos de dados ou envio de e-mails, podem ser reutilizadas na mesma ou em diferentes automações.

Como Modularizar um projeto Python?

1 - Identificar Componentes Reutilizáveis

Primeiro, divida o fluxo do seu processo de automação em partes funcionais que podem ser modularizadas. Abaixo alguns exemplos comuns de componentes que podem ser modularizados:

  • Conexões com sistemas: Como interação com bancos de dados, APIs e ERP.
  • Ações repetitivas: Como logins, navegação em aplicativos e interações com interfaces de usuário.
  • Processamento de dados: Leitura, transformação e armazenamento de dados.
  • Geração de relatórios e notificações: Geração de logs, e-mails e alertas.

2 - Criar Módulos Reutilizáveis

Agora que você identificou os componentes reutilizáveis, crie módulos Python que encapsulam essas funcionalidades. Aqui estão alguns exemplos:

Módulo de Conexão com Banco de Dados:

# first_py/db_functions.py

import psycopg2
from typing import Optional

def conectar_db(host: str, usuario: str, senha: str, banco: str) -> Optional[psycopg2.extensions.connection]:
    """
    Função para conectar a um banco de dados PostgreSQL.

    Args:
        host (str): Endereço do servidor do banco de dados.
        usuario (str): Nome de usuário do banco de dados.
        senha (str): Senha do banco de dados.
        banco (str): Nome do banco de dados.

    Returns:
        Optional[psycopg2.extensions.connection]: Conexão com o banco de dados ou None em caso de erro.
    """    
    try:
        conexao = psycopg2.connect(host=host, user=usuario, password=senha, database=banco)
        return conexao
    except Exception as e:
        print(f"Erro ao conectar ao banco de dados: {e}")
        return None

Módulo de leitura CSV:

# first_py/csv_functions.py

import csv
import os

def ler_csv(arquivo: str) -> list:
    """
    Função para ler um arquivo CSV e retornar o conteúdo como uma lista de dicionários.

    Args:
        arquivo (str): Caminho do arquivo CSV.

    Returns:
        list: Lista de dicionários com o conteúdo do CSV.
    """
    dados = []

    if not os.path.exists(arquivo):
        raise FileNotFoundError(f"O arquivo {arquivo} não foi encontrado.")
    with open(arquivo, mode='r', newline='', encoding='utf-8') as file:
        leitor = csv.DictReader(file)
        for linha in leitor:
            dados.append(linha)

    return dados

Módulo que procura e lê e-mails:

# first_py/email_functions.py

from botcity.plugins.email import BotEmailPlugin

def ler_email(usuario: str, senha: str, assunto: str) -> list:
    """
    Função para ler e-mails de uma conta do Gmail com base em um assunto.
    Args:
        usuario (str): Endereço de e-mail do usuário.
        senha (str): Senha do e-mail do usuário.
        assunto (str): Assunto a ser procurado.
    Returns:
        list: Lista de e-mails encontrados.
    """

    email = BotEmailPlugin.config_email(MailServers.GMAIL, usuario, senha)

    messages = email.search(f'SUBJECT "{assunto}"')

    emails_info = []

    for msg in messages:
        email_data = {
            "Date": msg.date_str,
            "From": msg.from_,
            "Message": msg.text
        }
        emails_info.append(email_data)

    return emails_info

Importante

No exemplo estamos lidando com módulos de funções seguindo a programação funcional que foca em funções independentes que executam tarefas específicas. Mas, para projetos mais complexos a utilização de POO pode ser utilizada também, abaixo alguns motivos para seguir com a programação orientada a objetos:

  • Quando a automação envolve entidades complexas, como robôs, usuários, tarefas ou sistemas.

  • Quando a automação envolve interações complexas com múltiplas APIs, fluxos de trabalho e estados.

  • Quando você precisa de herança (por exemplo, diferentes tipos de robôs com comportamentos distintos, mas compartilhando algumas funcionalidades).

Veja a etapa de empacotamento detalhada no Lab seguinte.