DevGang
Авторизоваться

Шаблоны в разработке программного обеспечения: более глубокий взгляд

С тех пор как я начал свой путь в программировании, я заметил интересную закономерность: большинство приложений шаблонны. Да это чистый факт! Просто остановитесь прямо здесь, в начале этой статьи, и начните думать обо всех проектах, которые вы разработали.

Что они имеют общего? Если вы присмотритесь, вы увидите, что многие основные функции повторно используются в разных проектах. Эти основные функции часто включают аутентификацию пользователей, обработку платежей, управление пользователями и многое другое.

В этой статье я хотел бы подчеркнуть, что все эти шаблоны уже были созданы программистами прошлого. Действительно, почти все, что мы используем сейчас, уже реализовано. Мы просто модифицируем некоторый функционал исходя из конкретного проекта.

Я познакомлю вас с примерами серверной разработки на Python, но это можно применить к любому языку программирования или любой области разработки программного обеспечения.

Итак, что общего у всех серверных приложений? Давайте взглянем!

Примечание. Если вы знакомы с ООП (объектно-ориентированным программированием), рассматривайте свои шаблонные модули как высший уровень абстракции, но на уровне приложения, поэтому их следует писать в соответствии с этим принципом.

Аутентификация и авторизация

Я хотел бы разбить каждый следующий раздел на базовые компоненты, которые можно применить практически к любому серверному приложению.

Основные компоненты

  • Модель пользователя: представление пользователя, включающее такие атрибуты, как имя пользователя, пароль, адрес электронной почты, роли и т. д.
  • Управление паролями: функции для хэширования и проверки паролей.
  • Генерация токенов: механизм генерации и проверки токенов (JWT, OAuth2 и т. д.).
  • Промежуточное программное обеспечение/декоратор: защищает маршруты/конечные точки, требующие аутентификации.
  • Управление ролями: назначение и проверка ролей и разрешений пользователей.

Модель пользователя

Мы определяем наиболее общий класс user с атрибутами, которые можно применить к любому конкретному пользователю.

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)

Управление токенами

Использование JWT для аутентификации на основе токенов — хороший выбор с точки зрения кибербезопасности и лучших практик серверной разработки.

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

Декораторы

Декоратор, проверяющий, разрешен ли пользователю доступ к странице.

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

Декоратор для проверки роли пользователя.

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

И в принципе, вот и все! Вы можете использовать эту предопределенную функцию для аутентификации во всех проектах!

Платежи и выставление счетов

Практически любое приложение обрабатывает финансовые транзакции. Будь то местная мясная лавка или крупный гигант, вам потребуется использовать эффективную систему сбора платежей.

Основные компоненты

  • Интеграция платежных шлюзов: подключение к платежным шлюзам, таким как Stripe или PayPal.
  • Модели оплаты: определение моделей для обработки платежных данных.
  • Обработка платежей: обработка жизненного цикла платежа (инициирование, подтверждение и т. д.).

Интеграция платежного шлюза

Это можно использовать в качестве основы для интеграции различных платежных шлюзов с конкретной реализацией Stripe. В целом, я лично предпочитаю использовать StripeAPI для платежей, поскольку он уже давно присутствует на рынке и действительно легко интегрируется в любой проект.

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

Это наиболее общий пример платежного шлюза, и вы можете сосредоточиться на конкретной реализации в соответствии с вашими потребностями.

Модели оплаты

Определите модели для хранения платежной информации. Этот пример можно адаптировать для использования с ORM. При необходимости вы можете создать более сложную иерархию классов, но для этого примера следующего фрагмента будет вполне достаточно.

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 = []

Cохраните все платежи в базу данных и настройте задачу Celery для обработки транзакций. Записи базы данных должны выглядеть следующим образом:

                  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

Теперь мы создали сложную систему, которую можно интегрировать в любой проект. Вы все еще следуете шаблону? Это можно использовать ВЕЗДЕ!

Ведь вы можете определить другое приложение для визуализации этих данных. Вы поняли суть шаблонов! 😉

Службы электронной почты и уведомлений

Электронная почта и уведомления позволяют пользователям быть в курсе событий и участвовать в жизни вашего приложения. Будь то проверка учетной записи, сброс пароля или маркетинговые коммуникации, надежная служба электронной почты необходима для любого типа проекта.

  • Интеграция службы электронной почты: подключение к службам электронной почты, таким как SendGrid или Amazon SES.
  • Шаблоны электронной почты: определение шаблонов для различных типов электронной почты.
  • Отправка электронных писем: функции для отправки электронных писем с помощью интегрированной службы.

Интеграция службы электронной почты

Определите основную логику SendGrid для отправки электронных писем внутри класса 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)

Как и в случае с платежным шлюзом, вам не нужно сосредотачиваться на каких-либо конкретных утилитах или продуктах на рынке. Это всего лишь пример того, как это можно обобщить и шаблонизировать для любого проекта.

Шаблоны электронных писем

Мой любимый шаблон для подобных систем — шаблон обработчиков; вы просто добавляете в словарь все больше и больше ключей как типа письма, так и пути к файлу с содержимым.

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

В противном случае было бы неплохо определить Enum для тех же целей.

Отправка электронных писем

Нам нужна функция, чтобы творить волшебство! Напишем следующее:

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)

Еще одним важным моментом будет добавление нескольких файлов во все серверные проекты, таких как README .env config.py, pyproject.toml, .pre-commit.yml, и создание базовой структуры файлов внутри проекта.

Хотя предложенная структура немного ограничена реализацией Python, как я уже упоминал ранее, вы можете сделать то же самое для любого другого языка или области.

Также важно отметить, что создание шаблонов на самом высоком уровне абстракции и поддержание хорошей структуры приложения могут быть эффективными.

Повторно использоваться в других проектах в качестве пакета или дополнения к микросервисной архитектуре.

Вывод

ВСЕ МОЖНО СДЕЛАТЬ ПО ШАБЛОНУ!

Приведенные здесь примеры — это только начало: эти шаблоны можно расширять и уточнять, чтобы охватить более сложные сценарии по мере развития ваших проектов. Вы можете добавить кэширование, установить k8, докер, инфраструктуру Devops, CI/CD и конвейеры.

Запомните одно простое утверждение: как только вы выполнили свою работу должным образом, вы можете использовать ту же работу при выполнении другой.

Цель состоит в том, чтобы сделать проект, инфраструктуру, компоненты и сервисы повторно используемыми в различных приложениях!

Заварите себе чашку чая и подумайте, какие части ваших приложений можно повторно использовать в других приложениях. Попробуйте создать подобные сервисы и автоматизировать свою работу, корректируя лишь некоторые участки кода!

Спасибо за прочтение и удачного создания шаблонов!

Источник

#Python
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу