paint-brush
Modelagem no desenvolvimento de software: uma análise mais aprofundadapor@pro1code1hack
381 leituras
381 leituras

Modelagem no desenvolvimento de software: uma análise mais aprofundada

por Yehor Dremliuha8m2024/07/16
Read on Terminal Reader

Muito longo; Para ler

Muitas funcionalidades principais são reutilizadas em diferentes projetos. Essas funcionalidades incluem autenticação de usuário, processamento de pagamentos, gerenciamento de usuários e muito mais. Neste artigo gostaria de salientar que todos esses padrões já foram criados por programadores do passado. Quase tudo que estamos usando agora já foi implementado. Apenas modificamos algumas funcionalidades com base no projeto específico.
featured image - Modelagem no desenvolvimento de software: uma análise mais aprofundada
Yehor Dremliuha HackerNoon profile picture
0-item
1-item

1. Introdução

Desde que comecei minha jornada com programação, percebi um padrão interessante: a maioria das aplicações são templates. Sim, é um fato puro! Pare aqui mesmo, no início deste artigo, e comece a pensar em todos os projetos que você desenvolveu.


O que eles têm em comum? Se você olhar com atenção, verá que muitas funcionalidades principais são reutilizadas em diferentes projetos. Essas funcionalidades principais geralmente incluem autenticação de usuário, processamento de pagamentos, gerenciamento de usuários e muito mais.


Neste artigo, gostaria de salientar que todos esses padrões já foram criados por programadores do passado. Na verdade, quase tudo que estamos usando agora já foi implementado. Apenas modificamos algumas funcionalidades com base no projeto específico.


Apresentarei exemplos da perspectiva de desenvolvimento de back-end em Python, mas isso pode ser aplicado a qualquer linguagem de programação ou qualquer campo da engenharia de software.


Então, o que todos os aplicativos de back-end têm em comum? Vamos dar uma olhada!


Nota : Se você estiver familiarizado com OOP (Programação Orientada a Objetos), considere seus módulos de modelo como o nível mais alto de abstração, mas no nível do aplicativo , para que sejam escritos de acordo com este princípio.

2. Autenticação e Autorização

Gostaria de dividir cada seção adicional em componentes básicos, que podem ser aplicados a quase qualquer aplicativo de back-end.


Componentes básicos

  1. Modelo de usuário: uma representação do usuário que inclui atributos como nome de usuário, senha, email, funções, etc.
  2. Gerenciamento de senhas: Funções para hash e verificação de senhas.
  3. Geração de Token: Mecanismo para gerar e verificar tokens (JWT, OAuth2, etc.).
  4. Middleware/Decorator: Proteja rotas/endpoints que requerem autenticação.
  5. Gerenciamento de funções: atribua e verifique funções e permissões de usuário.


2.1 Modelo de usuário

Estamos definindo a classe mais genérica do User com atributos que podem ser aplicados a qualquer usuário específico.

 from werkzeug.security import generate_password_hash, check_password_hash class User: def __init__(self, username, password, email): self.username = username self.password_hash = generate_password_hash(password) self.email = email self.roles = [] def set_password(self, password): self.password_hash = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password_hash, password)


2.2 Gerenciamento de Tokens

Usar JWT para autenticação baseada em token é uma boa escolha em termos de segurança cibernética e práticas recomendadas no desenvolvimento de back-end.

 def generate_token(user): payload = { 'username': user.username, 'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1) } return jwt.encode(payload, SECRET_KEY, algorithm='HS256') def verify_token(token): try: payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256']) return payload['username'] except jwt.ExpiredSignatureError: return None except jwt.InvalidTokenError: return None


2.3 Decoradores

  • Decorador para verificar se o usuário tem permissão para acessar a página.
 from functools import wraps from flask import request, jsonify, session def is_authenticated(func): @wraps(func) def decorated_function(*args, **kwargs): if 'user' not in session: return jsonify({"error": "User not authenticated"}), 401 return func(*args, **kwargs) return decorated_function


  • Decorador para verificar a função do usuário.
 def roles_required(*roles): def decorator(func): @wraps(func) def decorated_function(*args, **kwargs): user_roles = session.get('roles', []) if not any(role in user_roles for role in roles): return jsonify({"error": "User does not have the required role"}), 403 return func(*args, **kwargs) return decorated_function return decorator


E basicamente é isso! Você pode usar esta funcionalidade predefinida para autenticação em todos os projetos!

3. Pagamentos e cobrança

Quase todos os aplicativos lidam com transações financeiras. Quer se trate de um açougue local ou de uma grande empresa gigante, você precisará usar um sistema eficaz para receber pagamentos.


Componentes básicos

  1. Integração com gateway de pagamento: conexão com gateways de pagamento como Stripe ou PayPal
  2. Modelos de Pagamento: Definição de modelos para lidar com dados de pagamento.
  3. Processamento de pagamento: Lidar com o ciclo de vida do pagamento (iniciar, confirmar, etc.).


3.1 Integração do Gateway de Pagamento

Isto pode ser usado como base para integração de diferentes gateways de pagamento, com uma implementação concreta para Stripe. Geralmente, minha preferência pessoal é usar StripeAPI para pagamentos, pois já está no mercado há muito tempo e é muito fácil de integrar em qualquer projeto.


 class PaymentGateway(ABC): @abstractmethod def create_payment_intent(self, amount, currency='gbp'): pass @abstractmethod def confirm_payment(self, payment_id): pass @abstractmethod def handle_webhook(self, payload, sig_header): pass

Este é o exemplo mais genérico de gateway de pagamento, e você pode focar na implementação específica de acordo com suas necessidades.


3.2 Modelos de Pagamento

Defina modelos para armazenar informações de pagamento. Este exemplo pode ser adaptado para uso com ORM. Você pode criar uma hierarquia de classes mais complexa, se necessário, mas para este exemplo, o trecho a seguir deve ser suficiente.

 class Payment: def __init__(self, user_id, amount, currency): self.id = uuid.uuid4() self.user_id = user_id self.amount = amount self.currency = currency self.status = status payments = []


Salve todos os pagamentos no banco de dados e configure uma tarefa Celery para processamento de transações, para a seção 3.3. Os registros do banco de dados devem ser parecidos com os seguintes:

 id | user_id | amount | currency | status --------------------------------------+-----------------------------------+--------+----------+---------- e532d653-7c8b-453a-8cd4-3ab956863d72 | 1ff9efb3-d5e8-4e53-854f-4246ba9ff638 | 100.00 | USD | Failed 35985d41-5d54-4021-bed6-82d7233cc353 | a0984002-bace-478e-b6f9-6e4459e1b5ba | 250.50 | EUR | Pending 1ff9efb3-d5e8-4e53-854f-4246ba9ff638 | 9f896874-dc43-4592-8289-d0f7f8b8583a | 99.99 | GBP | Completed


Agora criamos um sistema complexo que pode ser integrado a qualquer projeto. Você ainda segue o padrão? Isso pode ser usado em qualquer lugar!


Afinal, você pode definir outra aplicação para visualização desses dados. Você entendeu o que quero dizer sobre modelos! 😉

4. Serviços de e-mail e notificação

Email e notificações mantêm os usuários informados e envolvidos na vida do seu aplicativo. Seja para verificação de conta, redefinição de senha ou comunicações de marketing, um serviço de e-mail confiável é essencial para qualquer tipo de projeto.

  1. Integração de serviços de e-mail: conexão com serviços de e-mail como SendGrid ou Amazon SES .
  2. Modelos de email: definição de modelos para vários tipos de email.
  3. Envio de Emails: Funções para envio de emails através do serviço integrado.


4.1 Integração de serviços de e-mail

Defina a lógica principal do SendGrid para envio de emails dentro da classe EmailService .

 import sendgrid from sendgrid.helpers.mail import Mail class EmailService: def __init__(self, api_key): self.sg = sendgrid.SendGridAPIClient(api_key) def send_email(self, from_email, to_email, subject, html_content): email = Mail( from_email=from_email, to_emails=to_email, subject=subject, html_content=html_content ) try: response = self.sg.send(email) return response.status_code except Exception as e: return str(e)


Tal como acontece com o gateway de pagamento, você não precisa se concentrar em nenhum utilitário ou produto específico do mercado. Este é apenas um exemplo de como pode ser generalizado e modelado para qualquer projeto.


4.2 Modelos de e-mail

Meu padrão favorito para sistemas como esse é o padrão manipuladores; você apenas adiciona mais e mais chaves ao dicionário como um tipo de e-mail e o caminho para o arquivo com conteúdo.


 email_templates = { 'welcome': “welcome.html”, 'reset_password': "<h1>Reset Your Password</h1><p>Click <a href='{link}'>here</a> to reset your password.</p>" }


Caso contrário, seria bom definir um Enum para os mesmos fins.


4.3 Envio de e-mails

Precisamos de uma função para fazer a mágica acontecer! Vamos escrever o seguinte:

 def send_email(email_service, from_email, to_email, subject, template_name, **template_vars): """ Send an email using the specified email service. """ html_content = get_email_template(template_name, **template_vars) return email_service.send_email(from_email, to_email, subject, html_content)


Outro ponto importante seria adicionar vários arquivos a todos os projetos backend, como README .env config.py , pyproject.toml, .pre-commit.yml e criar a estrutura base dos arquivos dentro do projeto.


Embora a estrutura sugerida seja um pouco restrita à implementação do Python, como mencionei antes, você pode fazer o mesmo para qualquer outra linguagem ou campo.


Também é importante notar que a modelagem no mais alto nível de abstração e a manutenção de uma boa estrutura da aplicação podem ser

reutilizado para outros projetos como um pacote ou um acréscimo à arquitetura de microsserviços.



Figura 1 – Exemplo de arquitetura de microsserviços

5. Conclusão

TUDO PODE SER MODELO!


Os exemplos fornecidos aqui são apenas o começo: esses padrões podem ser estendidos e refinados para cobrir cenários mais complexos à medida que seus projetos evoluem. Você pode adicionar caching para estabelecer k8s , docker , infraestrutura Devops , CI/CD e pipelines.


Lembre-se de uma afirmação simples: depois de realizar seu trabalho corretamente, você poderá usar o mesmo trabalho enquanto conclui outro.


O objetivo é tornar o projeto, a infraestrutura, os componentes e os serviços reutilizáveis em diferentes aplicações!


Prepare uma xícara de chá e pense em quais partes de seus aplicativos podem ser reutilizadas em diferentes aplicativos. Tente criar serviços semelhantes e automatizar seu trabalho, ajustando apenas alguns trechos de código!


Obrigado pela leitura e bons modelos!