paint-brush
Tạo khuôn mẫu trong phát triển phần mềm: Nhìn sâu hơntừ tác giả@pro1code1hack
377 lượt đọc
377 lượt đọc

Tạo khuôn mẫu trong phát triển phần mềm: Nhìn sâu hơn

từ tác giả Yehor Dremliuha8m2024/07/16
Read on Terminal Reader

dài quá đọc không nổi

Nhiều chức năng cốt lõi được tái sử dụng trên các dự án khác nhau. Các chức năng này bao gồm xác thực người dùng, xử lý thanh toán, quản lý người dùng, v.v. Trong bài viết này tôi muốn nêu lên quan điểm rằng tất cả các mẫu này đều đã được tạo ra bởi các lập trình viên từ xưa. Hầu hết mọi thứ chúng tôi đang sử dụng hiện nay đều đã được triển khai. Chúng tôi chỉ sửa đổi một số chức năng dựa trên dự án cụ thể.
featured image - Tạo khuôn mẫu trong phát triển phần mềm: Nhìn sâu hơn
Yehor Dremliuha HackerNoon profile picture
0-item
1-item

1. Giới thiệu

Kể từ khi bắt đầu hành trình lập trình, tôi nhận thấy một mô hình thú vị: phần lớn các ứng dụng đều được tạo khuôn mẫu. Vâng, đó là một sự thật thuần túy! Chỉ cần dừng lại ở đây, ở phần đầu của bài viết này và bắt đầu nghĩ về tất cả các dự án bạn đã phát triển.


Họ có đặc điểm gì chung? Nếu quan sát kỹ, bạn sẽ thấy nhiều chức năng cốt lõi được sử dụng lại trong các dự án khác nhau. Các chức năng cốt lõi này thường bao gồm xác thực người dùng, xử lý thanh toán, quản lý người dùng, v.v.


Trong bài viết này, tôi muốn nêu quan điểm rằng tất cả các mẫu này đều đã được các lập trình viên từ xưa tạo ra. Thực sự, hầu hết mọi thứ chúng tôi đang sử dụng hiện nay đều đã được triển khai. Chúng tôi chỉ sửa đổi một số chức năng dựa trên dự án cụ thể.


Tôi sẽ giới thiệu cho bạn các ví dụ từ góc độ phát triển phụ trợ trong Python, nhưng điều này có thể được áp dụng cho bất kỳ ngôn ngữ lập trình hoặc bất kỳ lĩnh vực nào trong lĩnh vực công nghệ phần mềm.


Vậy tất cả các ứng dụng phụ trợ có điểm gì chung? Chúng ta hãy xem xét!


Lưu ý : Nếu bạn đã quen thuộc với OOP (Lập trình hướng đối tượng), hãy coi các mô-đun tạo khuôn mẫu của bạn là mức trừu tượng cao nhất nhưng ở cấp độ ứng dụng để mô-đun này phải được viết theo nguyên tắc này.

2. Xác thực và ủy quyền

Tôi muốn chia nhỏ từng phần tiếp theo thành các thành phần cơ bản, hầu hết có thể áp dụng cho bất kỳ ứng dụng phụ trợ nào.


Thành phần cơ bản

  1. Mô hình người dùng: Đại diện cho người dùng bao gồm các thuộc tính như tên người dùng, mật khẩu, email, vai trò, v.v.
  2. Quản lý mật khẩu: Chức năng băm và xác minh mật khẩu.
  3. Tạo mã thông báo: Cơ chế tạo và xác minh mã thông báo (JWT, OAuth2, v.v.).
  4. Middleware/Decorator: Bảo vệ các tuyến/điểm cuối yêu cầu xác thực.
  5. Quản lý vai trò: Chỉ định và xác minh vai trò và quyền của người dùng.


2.1 Mô hình người dùng

Chúng tôi đang xác định lớp User chung nhất với các thuộc tính có thể áp dụng cho bất kỳ người dùng cụ thể nào.

 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 Quản lý mã thông báo

Sử dụng JWT để xác thực dựa trên mã thông báo là một lựa chọn tốt về mặt an ninh mạng và các phương pháp hay nhất trong phát triển phụ trợ.

 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 Trang trí

  • Trình trang trí để kiểm tra xem người dùng có được phép truy cập trang hay không.
 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


  • Decorator để kiểm tra vai trò của người dùng.
 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


Và về cơ bản, thế là xong! Bạn có thể sử dụng chức năng được xác định trước này để xác thực trên tất cả các dự án!

3. Thanh toán và lập hóa đơn

Hầu như bất kỳ ứng dụng nào cũng xử lý các giao dịch tài chính. Cho dù đó là một cửa hàng bán thịt ở địa phương hay một doanh nghiệp lớn, bạn sẽ cần sử dụng một hệ thống hiệu quả để thu các khoản thanh toán.


Thành phần cơ bản

  1. Tích hợp cổng thanh toán: Kết nối với các cổng thanh toán như Stripe hoặc PayPal
  2. Mô hình thanh toán: Xác định mô hình để xử lý dữ liệu thanh toán.
  3. Xử lý thanh toán: Xử lý vòng đời thanh toán (bắt đầu, xác nhận, v.v.).


3.1 Tích hợp cổng thanh toán

Điều này có thể được sử dụng làm cơ sở để tích hợp các cổng thanh toán khác nhau, với việc triển khai cụ thể cho Stripe. Nói chung, sở thích cá nhân của tôi là sử dụng StripeAPI để thanh toán vì nó đã có mặt từ lâu trên thị trường và thực sự rất dễ tích hợp vào bất kỳ dự án nào.


 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

Đây là ví dụ chung nhất về cổng thanh toán và bạn có thể tập trung vào việc triển khai cụ thể theo nhu cầu của mình.


3.2 Mô hình thanh toán

Xác định các mô hình để lưu trữ thông tin thanh toán. Ví dụ này có thể được điều chỉnh để sử dụng với ORM. Bạn có thể tạo một hệ thống phân cấp lớp phức tạp hơn nếu cần, nhưng đối với ví dụ này, đoạn mã sau là khá đủ.

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


Lưu tất cả các khoản thanh toán vào cơ sở dữ liệu và thiết lập tác vụ Celery để xử lý các giao dịch, cho phần 3.3. Các bản ghi cơ sở dữ liệu sẽ trông giống như sau:

 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


Bây giờ, chúng tôi đã tạo ra một hệ thống phức tạp có thể được tích hợp vào bất kỳ dự án nào. Bạn vẫn đang theo mô hình này phải không? Điều này có thể được sử dụng MỌI NƠI!


Rốt cuộc, bạn có thể xác định một ứng dụng khác để trực quan hóa dữ liệu này. Bạn đã có quan điểm về việc tạo khuôn mẫu! 😉

4. Dịch vụ email và thông báo

Email và thông báo giúp người dùng luôn được cập nhật và tham gia vào hoạt động của ứng dụng của bạn. Cho dù đó là để xác minh tài khoản, đặt lại mật khẩu hay liên lạc tiếp thị thì dịch vụ email đáng tin cậy đều cần thiết cho bất kỳ loại dự án nào.

  1. Tích hợp dịch vụ email: Kết nối với các dịch vụ email như SendGrid hoặc Amazon SES .
  2. Mẫu email: Xác định mẫu cho các loại email khác nhau.
  3. Sending Emails: Chức năng gửi email sử dụng dịch vụ tích hợp.


4.1 Tích hợp dịch vụ email

Xác định logic chính của SendGrid để gửi email bên trong lớp 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)


Cũng như cổng thanh toán, bạn không cần tập trung vào bất kỳ tiện ích hoặc sản phẩm cụ thể nào trên thị trường. Đây chỉ là một ví dụ về cách nó có thể được khái quát hóa và tạo khuôn mẫu cho bất kỳ dự án nào.


4.2 Mẫu email

Mẫu yêu thích của tôi cho các hệ thống như thế này là mẫu trình xử lý; bạn chỉ cần thêm ngày càng nhiều khóa vào từ điển dưới dạng một loại email và đường dẫn đến tệp có nội dung.


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


Mặt khác, có thể tốt hơn nếu xác định Enum cho cùng mục đích.


4.3 Gửi email

Chúng ta cần một chức năng để biến điều kỳ diệu thành hiện thực! Hãy viết như sau:

 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)


Một điểm quan trọng khác là thêm một số tệp vào tất cả các dự án phụ trợ, chẳng hạn như README .env config.py , pyproject.toml, .pre-commit.ymlđưa ra cấu trúc cơ sở của các tệp bên trong dự án.


Mặc dù cấu trúc được đề xuất hơi chặt chẽ hơn một chút đối với việc triển khai Python, nhưng như tôi đã đề cập trước đó, bạn có thể thực hiện tương tự với bất kỳ ngôn ngữ hoặc lĩnh vực nào khác.


Cũng cần lưu ý rằng việc tạo khuôn mẫu ở mức trừu tượng cao nhất và duy trì cấu trúc tốt của ứng dụng có thể

được sử dụng lại cho các dự án khác dưới dạng gói hoặc phần bổ sung cho kiến trúc microservice.



Hình 1 - Ví dụ về kiến trúc microservice

5. Kết luận

MỌI THỨ CÓ THỂ ĐƯỢC TẠM THỜI!


Các ví dụ được cung cấp ở đây chỉ là bước khởi đầu—những mẫu này có thể được mở rộng và cải tiến để bao gồm các tình huống phức tạp hơn khi dự án của bạn phát triển. Bạn có thể thêm caching thiết lập k8s , docker , cơ sở hạ tầng Devops , CI/CD và đường ống.


Hãy nhớ một câu nói đơn giản: Khi bạn đã hoàn thành tốt công việc của mình, bạn có thể sử dụng công việc tương tự trong khi hoàn thành công việc khác.


Mục tiêu là làm cho dự án, cơ sở hạ tầng, thành phần và dịch vụ có thể tái sử dụng được trên các ứng dụng khác nhau!


Hãy pha cho mình một tách trà và suy nghĩ xem phần nào trong ứng dụng của bạn có thể được sử dụng lại trong các ứng dụng khác nhau. Hãy thử tạo các dịch vụ tương tự và tự động hóa công việc của bạn, chỉ điều chỉnh một số đoạn mã!


Cảm ơn bạn đã đọc và chúc bạn tạo mẫu vui vẻ!