Some checks failed
CD - Build & Deploy / build-and-push (push) Has been cancelled
CD - Build & Deploy / package-helm (push) Has been cancelled
CD - Build & Deploy / deploy-staging (push) Has been cancelled
CD - Build & Deploy / deploy-production (push) Has been cancelled
CD - Build & Deploy / release (push) Has been cancelled
CI / test (3.11) (push) Has been cancelled
CI / test (3.12) (push) Has been cancelled
CI / security (push) Has been cancelled
- Implemented Clean Architecture with Domain, Application, Infrastructure, Presentation layers - Added comprehensive project structure following SOLID principles - Created Kubernetes deployment with Helm charts (HPA, PDB, NetworkPolicy) - Configured ArgoCD for automated deployment (production + staging) - Implemented CI/CD pipeline with GitHub Actions - Added comprehensive documentation (handbook, architecture, coding standards) - Configured PostgreSQL, Redis, Celery for backend services - Created modern landing page with Persian fonts (Vazirmatn) - Added Docker multi-stage build for production - Configured development tools (pytest, black, flake8, mypy, isort) - Added pre-commit hooks for code quality - Implemented Makefile for common operations
7.7 KiB
7.7 KiB
استانداردهای کدنویسی
اصول کلی
1. کد تمیز (Clean Code)
کد باید:
- خوانا باشد
- ساده باشد
- قابل فهم باشد
- قابل نگهداری باشد
2. PEP 8 Compliance
الزامی: تمام کدها باید با PEP 8 مطابقت داشته باشند.
استفاده از ابزارها:
black src/ # Auto-formatting
flake8 src/ # Linting
isort src/ # Import sorting
قوانین Naming
Classes
# ✅ GOOD: PascalCase
class UserService:
pass
class PaymentGateway:
pass
class DatabaseConnection:
pass
# ❌ BAD
class user_service: # Wrong case
class payment_gateway_service: # Too long
class UServ: # Unclear abbreviation
Functions & Methods
# ✅ GOOD: snake_case, descriptive
def calculate_total_price(items: List[Item]) -> Decimal:
pass
def send_welcome_email(user: User) -> bool:
pass
# ❌ BAD
def calcTotPrice(): # Mixed case
def cp(): # Not descriptive
def calculate(): # Too vague
Variables
# ✅ GOOD
user_email = "test@example.com"
total_amount = Decimal("100.00")
is_active = True
MAX_ATTEMPTS = 3 # Constant
# ❌ BAD
e = "test@example.com" # Too short
userEmail = "test@example.com" # camelCase
TOTAL = 100 # Constant style for variable
Type Hints
الزامی: همه function signatures باید type hints داشته باشند.
from typing import Optional, List, Dict, Any
from decimal import Decimal
# ✅ GOOD
def get_user(user_id: int) -> Optional[User]:
pass
def create_invoice(
user_id: int,
amount: Decimal,
items: List[InvoiceItem]
) -> Invoice:
pass
# ❌ BAD
def get_user(user_id): # No types
pass
def create_invoice(user_id, amount, items): # No types
pass
Docstrings
الزامی: همه public functions, classes, و methods باید docstring داشته باشند.
Google Style (استاندارد پروژه)
def create_user(
email: str,
password: str,
full_name: str
) -> User:
"""Create a new user account.
Args:
email: User's email address
password: Plain text password
full_name: User's full name
Returns:
User: Created user object
Raises:
EmailAlreadyExistsException: If email exists
WeakPasswordException: If password is weak
Example:
>>> user = create_user(
... email="test@example.com",
... password="SecurePass123!",
... full_name="John Doe"
... )
"""
pass
Error Handling
Use Specific Exceptions
# ✅ GOOD
try:
user = user_repository.get_by_id(user_id)
if not user:
raise UserNotFoundException(f"User {user_id} not found")
except DatabaseException as e:
logger.error("database_error", error=str(e))
raise
except Exception as e:
logger.critical("unexpected_error", error=str(e))
raise
# ❌ BAD
try:
user = get_user(user_id)
except: # Never use bare except!
pass
try:
user = get_user(user_id)
except Exception: # Too broad
pass
Custom Exception Hierarchy
class PeikarbandException(Exception):
"""Base exception."""
pass
class DomainException(PeikarbandException):
"""Domain layer exceptions."""
pass
class UserNotFoundException(DomainException):
"""User not found."""
pass
Code Organization
Imports
# 1. Standard library
import os
import sys
from typing import Optional, List
from decimal import Decimal
# 2. Third-party
import redis
from sqlalchemy import Column, Integer
from pydantic import BaseModel
# 3. Local
from src.config.settings import settings
from src.core.domain.entities.user import User
Function Length
Max 50 lines per function (توصیه: 20-30 lines)
# ✅ GOOD: Short and focused
def calculate_discount(amount: Decimal, user: User) -> Decimal:
"""Calculate user discount."""
if user.is_premium:
return amount * Decimal("0.10")
return Decimal("0.00")
# ❌ BAD: Too long (100+ lines)
def process_order(order_data):
# 100+ lines of code
pass
Class Length
Max 300 lines per class (توصیه: 100-200 lines)
اگر class بزرگ شد، به چند class کوچکتر تقسیم کنید.
Comments
When to Comment
# ✅ GOOD: Explain WHY, not WHAT
def calculate_tax(amount: Decimal) -> Decimal:
# Iranian tax rate is 9% as of 2024
TAX_RATE = Decimal("0.09")
return amount * TAX_RATE
# ❌ BAD: States the obvious
def add(a, b):
# Add two numbers
return a + b
TODO Comments
# TODO(username): Description of what needs to be done
# TODO(john): Implement caching for this query
# FIXME(jane): This breaks when amount is negative
# HACK(bob): Temporary workaround until API is fixed
Best Practices
1. Single Responsibility
# ✅ GOOD
class UserRepository:
def save(self, user: User) -> User:
pass
class EmailService:
def send_email(self, to: str, subject: str) -> bool:
pass
# ❌ BAD
class UserManager:
def save_user(self, user):
pass
def send_email(self, user):
pass
def log_activity(self, user):
pass
2. DRY (Don't Repeat Yourself)
# ❌ BAD
def get_user_name(user_id):
db = connect_db()
user = db.query(User).filter_by(id=user_id).first()
db.close()
return user.name
def get_user_email(user_id):
db = connect_db()
user = db.query(User).filter_by(id=user_id).first()
db.close()
return user.email
# ✅ GOOD
def get_user(user_id: int) -> Optional[User]:
with get_db_context() as db:
return db.query(User).filter_by(id=user_id).first()
def get_user_name(user_id: int) -> Optional[str]:
user = get_user(user_id)
return user.name if user else None
3. Early Return
# ✅ GOOD: Early return
def process_payment(amount: Decimal) -> bool:
if amount <= 0:
return False
if not user.has_sufficient_balance(amount):
return False
# Process payment
return True
# ❌ BAD: Nested conditions
def process_payment(amount):
if amount > 0:
if user.has_sufficient_balance(amount):
# Process payment
return True
return False
4. Use Constants
# ✅ GOOD
MAX_LOGIN_ATTEMPTS = 3
PASSWORD_MIN_LENGTH = 8
SESSION_TIMEOUT_MINUTES = 30
if attempts >= MAX_LOGIN_ATTEMPTS:
lock_account()
# ❌ BAD: Magic numbers
if attempts >= 3: # What's 3?
lock_account()
5. Avoid Deep Nesting
# ✅ GOOD: Max 2-3 levels
def process_order(order: Order) -> bool:
if not order.is_valid():
return False
if not user.can_order():
return False
return save_order(order)
# ❌ BAD: Too nested
def process_order(order):
if order:
if order.is_valid():
if user:
if user.can_order():
if save_order(order):
return True
return False
Code Review Checklist
قبل از ارسال PR، این موارد را بررسی کنید:
- همه تستها pass میشوند
- Code coverage کافی است (>80%)
- تمام functions دارای type hints هستند
- تمام public functions دارای docstring هستند
- black, flake8, mypy بدون error
- هیچ TODO/FIXME جدید بدون توضیح نیست
- تغییرات در CHANGELOG.md ثبت شده
- مستندات بهروز شده
الزامات: این استانداردها الزامی هستند و در code review بررسی میشوند.