프로그래밍을 시작하면서 흥미로운 패턴을 발견했습니다. 즉, 대부분의 애플리케이션이 템플릿으로 구성되어 있다는 것입니다. 예, 그것은 순수한 사실입니다! 이 글의 시작 부분에서 바로 멈추고 여러분이 개발한 모든 프로젝트에 대해 생각해 보세요.
그들의 공통점이 무엇입니까? 자세히 살펴보면 여러 프로젝트에서 많은 핵심 기능이 재사용되는 것을 볼 수 있습니다. 이러한 핵심 기능에는 사용자 인증, 결제 처리, 사용자 관리 등이 포함되는 경우가 많습니다.
이 글에서는 이러한 패턴이 모두 과거 프로그래머에 의해 이미 만들어졌다는 점을 강조하고 싶습니다. 실제로 우리가 지금 사용하고 있는 거의 모든 것이 이미 구현되었습니다. 특정 프로젝트에 따라 일부 기능을 수정합니다.
Python의 백엔드 개발 관점에서 예제를 소개하겠지만 이는 모든 프로그래밍 언어나 소프트웨어 엔지니어링 영역의 모든 분야에 적용될 수 있습니다.
그렇다면 모든 백엔드 애플리케이션의 공통점은 무엇일까요? 한 번 보자!
참고 : OOP(객체 지향 프로그래밍)에 익숙하다면 템플릿 모듈을 가장 높은 수준의 추상화이지만 응용 프로그램 수준 으로 간주하여 이 원칙에 따라 작성해야 합니다.
각 추가 섹션을 거의 모든 백엔드 애플리케이션에 적용할 수 있는 기본 구성 요소로 분류하고 싶습니다.
기본 구성 요소
2.1 사용자 모델
우리는 특정 사용자에게 적용될 수 있는 속성을 사용하여 가장 일반적인 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)
2.2 토큰 관리
토큰 기반 인증에 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
2.3 데코레이터
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
과 같은 결제 게이트웨이와 연결
3.1 결제 게이트웨이 통합
이는 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
이는 결제 게이트웨이의 가장 일반적인 예이며 필요에 따라 특정 구현에 집중할 수 있습니다.
3.2 결제 모델
결제 정보를 저장할 모델을 정의합니다. 이 예제는 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 = []
모든 지불금을 데이터베이스에 저장하고 3.3 섹션에 대한 거래 처리를 위한 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
와 같은 이메일 서비스와 연결합니다.
4.1 이메일 서비스 통합
EmailService
클래스 내에서 이메일을 보내기 위한 SendGrid
의 기본 논리를 정의합니다.
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)
지불 게이트웨이와 마찬가지로 시장에 나와 있는 특정 유틸리티나 제품에 집중할 필요가 없습니다. 이는 모든 프로젝트에 대해 어떻게 일반화하고 템플릿화할 수 있는지 보여주는 예일 뿐입니다.
4.2 이메일 템플릿
이와 같은 시스템에서 제가 가장 좋아하는 패턴은 핸들러 패턴입니다. 이메일 유형으로 사전에 점점 더 많은 키를 추가하고 콘텐츠가 포함된 파일 경로를 추가하기만 하면 됩니다.
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
을 정의하는 것이 좋을 수 있습니다.
4.3 이메일 보내기
마법이 일어나게 하려면 함수가 필요합니다! 다음을 작성해 보겠습니다.
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 구현에 약간 엄격하지만 앞서 언급했듯이 다른 언어나 분야에서도 동일한 작업을 수행할 수 있습니다.
또한 가장 높은 수준의 추상화에서 템플릿을 작성하고 애플리케이션의 좋은 구조를 유지하는 것이 중요합니다.
마이크로서비스 아키텍처에 대한 패키지 또는 추가로 다른 프로젝트에 재사용됩니다.
모든 것이 템플릿화될 수 있습니다!
여기에 제공된 예제는 시작에 불과합니다. 이러한 패턴은 프로젝트가 발전함에 따라 더 복잡한 시나리오를 포괄하도록 확장되고 개선될 수 있습니다. caching
설정 k8s
, docker
, Devops
인프라, CI/CD
및 파이프라인을 추가할 수 있습니다.
한 가지 간단한 말을 기억하십시오. 일을 제대로 수행한 후에는 다른 일을 완료하는 동안 동일한 일을 사용할 수 있습니다.
목표는 다양한 애플리케이션에서 프로젝트, 인프라, 구성 요소 및 서비스를 재사용할 수 있도록 만드는 것입니다!
잠시 시간을 내어 애플리케이션의 어떤 부분을 다른 앱에서 재사용할 수 있는지 생각해 보세요. 일부 코드 부분만 조정하여 유사한 서비스를 만들고 작업을 자동화해 보세요!
읽어주셔서 감사합니다. 즐거운 템플릿 만드세요!