paint-brush
Plantillas en el desarrollo de software: una mirada más profundapor@pro1code1hack
377 lecturas
377 lecturas

Plantillas en el desarrollo de software: una mirada más profunda

por Yehor Dremliuha8m2024/07/16
Read on Terminal Reader

Demasiado Largo; Para Leer

Muchas funcionalidades principales se reutilizan en diferentes proyectos. Estas funcionalidades incluyen autenticación de usuarios, procesamiento de pagos, gestión de usuarios y más. En este artículo me gustaría señalar que todos estos patrones ya fueron creados por programadores del pasado. Casi todo lo que estamos usando ahora ya fue implementado. Simplemente modificamos algunas funciones según el proyecto específico.
featured image - Plantillas en el desarrollo de software: una mirada más profunda
Yehor Dremliuha HackerNoon profile picture
0-item
1-item

1. Introducción

Desde que comencé mi viaje con la programación, noté un patrón interesante: la mayoría de las aplicaciones están basadas en plantillas. ¡Sí, es un hecho puro! Simplemente deténte aquí, al comienzo de este artículo, y comienza a pensar en todos los proyectos que has desarrollado.


¿Qué tienen en común? Si observa detenidamente, verá que muchas funcionalidades principales se reutilizan en diferentes proyectos. Estas funcionalidades principales suelen incluir autenticación de usuarios, procesamiento de pagos, gestión de usuarios y más.


En este artículo, me gustaría señalar que todos estos patrones ya fueron creados por programadores del pasado. Realmente, casi todo lo que estamos usando ahora mismo ya estaba implementado. Simplemente modificamos algunas funciones según el proyecto específico.


Le presentaré ejemplos desde la perspectiva del desarrollo backend en Python, pero esto se puede aplicar a cualquier lenguaje de programación o cualquier campo en el ámbito de la ingeniería de software.


Entonces, ¿qué tienen en común todas las aplicaciones backend? ¡Vamos a ver!


Nota : Si está familiarizado con la programación orientada a objetos (OOP), considere sus módulos con plantilla como el nivel más alto de abstracción pero en el nivel de aplicación, por lo que debe escribirse de acuerdo con este principio.

2. Autenticación y Autorización

Me gustaría dividir cada sección adicional en los componentes básicos, que se pueden aplicar a casi cualquier aplicación backend.


Componentes básicos

  1. Modelo de usuario: una representación del usuario que incluye atributos como nombre de usuario, contraseña, correo electrónico, roles, etc.
  2. Gestión de contraseñas: funciones para codificar y verificar contraseñas.
  3. Generación de Tokens: Mecanismo para generar y verificar tokens (JWT, OAuth2, etc.).
  4. Middleware/Decorator: protege rutas/puntos finales que requieren autenticación.
  5. Gestión de roles: asigne y verifique roles y permisos de usuarios.


2.1 Modelo de usuario

Estamos definiendo la clase más genérica de User con atributos que se pueden aplicar a cualquier usuario 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 Gestión de tokens

Usar JWT para la autenticación basada en tokens es una buena opción en términos de ciberseguridad y mejores prácticas en el desarrollo backend.

 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 comprobar si el usuario tiene permiso para acceder a la 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 comprobar el rol del usuario.
 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


Y básicamente, ¡eso es todo! ¡Puede utilizar esta funcionalidad predefinida para la autenticación en todos los proyectos!

3. Pagos y facturación

Casi cualquier aplicación maneja transacciones financieras. Ya sea una carnicería local o una gran empresa gigante, necesitará utilizar un sistema eficaz para cobrar los pagos.


Componentes básicos

  1. Integración de pasarela de pago: conexión con pasarelas de pago como Stripe o PayPal
  2. Modelos de Pago: Definición de modelos para manejar datos de pago.
  3. Procesamiento de pagos: Manejo del ciclo de vida del pago (iniciar, confirmar, etc.).


3.1 Integración de pasarela de pago

Esto se puede utilizar como base para integrar diferentes pasarelas de pago, con una implementación concreta para Stripe. Generalmente, mi preferencia personal es usar StripeAPI para pagos, ya que lleva mucho tiempo en el mercado y es realmente fácil de integrar en cualquier proyecto.


 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 es el ejemplo más genérico de pasarela de pago y usted puede centrarse en una implementación específica según sus necesidades.


3.2 Modelos de pago

Definir modelos para almacenar información de pago. Este ejemplo se puede adaptar para su uso con ORM. Puede crear una jerarquía de clases más compleja si es necesario, pero para este ejemplo, el siguiente fragmento debería 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 = []


Guarde todos los pagos en la base de datos y configure una tarea Celery para procesar transacciones, para la sección 3.3. Los registros de la base de datos deberían verse como los siguientes:

 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


Ahora hemos creado un sistema complejo que se puede integrar en cualquier proyecto. ¿Sigues siguiendo el patrón? ¡Esto se puede usar EN TODAS PARTES!


Después de todo, puedes definir otra aplicación para visualizar estos datos. ¡Tienes razón sobre las plantillas! 😉

4. Servicios de notificación y correo electrónico

El correo electrónico y las notificaciones mantienen a los usuarios informados y comprometidos con la vida de su aplicación. Ya sea para verificación de cuenta, restablecimiento de contraseña o comunicaciones de marketing, un servicio de correo electrónico confiable es esencial para cualquier tipo de proyecto.

  1. Integración de servicios de correo electrónico: conexión con servicios de correo electrónico como SendGrid o Amazon SES .
  2. Plantillas de correo electrónico: definición de plantillas para varios tipos de correo electrónico.
  3. Envío de correos electrónicos: Funciones para enviar correos electrónicos utilizando el servicio integrado.


4.1 Integración del servicio de correo electrónico

Defina la lógica principal de SendGrid para enviar correos electrónicos dentro de la clase 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)


Al igual que con la pasarela de pago, no es necesario centrarse en ninguna utilidad o producto específico del mercado. Este es solo un ejemplo de cómo se puede generalizar y crear plantillas para cualquier proyecto.


4.2 Plantillas de correo electrónico

Mi patrón favorito para sistemas como este es el patrón de controladores; simplemente agrega más y más claves al diccionario como un tipo de correo electrónico y la ruta al archivo con un contenido.


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


De lo contrario, sería bueno definir una Enum para los mismos propósitos.


4.3 Envío de correos electrónicos

¡Necesitamos una función para que la magia suceda! Escribamos lo siguiente:

 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)


Otro punto importante sería agregar varios archivos a todos los proyectos backend, como README .env config.py , pyproject.toml, .pre-commit.yml y crear la estructura base de los archivos dentro del proyecto.


Aunque la estructura sugerida se ajusta un poco a la implementación de Python, como mencioné antes, puedes hacer lo mismo con cualquier otro lenguaje o campo.


También es importante tener en cuenta que crear plantillas en el nivel más alto de abstracción y mantener una buena estructura de la aplicación puede ser

reutilizado para otros proyectos como un paquete o una adición a la arquitectura de microservicio.



Figura 1: Ejemplo de arquitectura de microservicio

5. Conclusión

¡TODO SE PUEDE PLANTAR!


Los ejemplos proporcionados aquí son solo el comienzo: estos patrones se pueden ampliar y perfeccionar para cubrir escenarios más complejos a medida que evolucionan sus proyectos. Puede agregar caching establecer k8s , docker , infraestructura Devops , CI/CD y canalizaciones.


Recuerde una afirmación simple: una vez que haya hecho su trabajo correctamente, puede utilizar el mismo trabajo mientras realiza otro.


¡El objetivo es hacer que el proyecto, la infraestructura, los componentes y los servicios sean reutilizables en diferentes aplicaciones!


Prepárate una taza de té y piensa qué partes de tus aplicaciones se pueden reutilizar en diferentes aplicaciones. ¡Intenta crear servicios similares y automatiza tu trabajo, ajustando solo algunas partes del código!


¡Gracias por leer y felices plantillas!