<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>نوشته های زهرا بهرامیان</title><link>https://virgool.ir/feed/@m_84385734</link><description></description><language>fa</language><pubDate>2026-11-11 20:21:45</pubDate><image><url>https://virgool.ir/images/default-avatar.jpg</url><title>زهرا بهرامیان</title><link>https://virgool.ir/@m_84385734</link></image><item><title>DDD در Django</title><link>https://virgool.ir/@m_84385734/ddd-در-django-zwjsfvqu6wzi</link><description>راهنمای سبک اعمال Domain-Driven Design در Django مقدمه: معماری فعلی DjangoDjango به طور پیشفرض از معماری Model-View-Template (MVT) پیروی میکند که شباهت زیادی به الگویModel-View-Controller (MVC)  دارد.در این معماری:- Model  : لایه دسترسی به داده و منطق کسب وکار- View  : لایه منطق برنامه و واسط بین Model و Template-  : Template لایه نمایشی و رابط کاربریدر پروژه های کوچک، این معماری ساده و کارآمد است. اما با بزرگ شدن پروژه، مشکلاتی ظاهر میشوند:1. مدل ها و ویو ها به سرعت پیچیده و حجیم میشوند.2. منطق کسب وکار در سراسر پروژه پراکنده میشود.3. تست پذیری کاهش می یابد.4. وابستگی بین کامپوننت ها افزایش می یابد.5. تغییر در یک بخش ممکن است اثرات ناخواسته در بخشهای دیگر ایجاد کند.مشکلات معماری پیشفرض Djangoمعماری پیشفرض Django برای پروژه های بزرگ چند مشکل اساسی دارد:1. عدم جداسازی مناسب لایه ها: منطق کسب وکار (Business Logic  ) اغلب در مدل ها یا ویو ها قرار میگیرد که باعث میشود تغییرات در یک حوزه  (Domain) بر حوزه های دیگر تأثیر بگذارد.2. وابستگی متقابل: در پروژه های بزرگ، مدل ها و ویو ها به شدت به یکدیگر وابسته میشوند که نگهداری را سخت میکند.3. عدم تمرکز  بر Domain : معماری پیش فرض ، توسعه دهندگان را تشویق میکند بیشتر به جنبه های فنی (مانند مدل های دیتابیس) توجه کنند تا منطق کسب وکار.4. مشکل در تست پذیری: به دلیل ترکیب منطق کسب وکار با لایه های دیگر، نوشتن تست های واحد مستقل دشوار میشود.پس این راهنمای سبک با معرفی اصول Domain-Driven Design (DDD) سعی دارد این مشکلات را حل کند. پیشینه Domain-Driven DesignDDD یک رویکرد توسعه نرم افزار است که تمرکز اصلی آن بر روی مدل سازی دقیق دامنه (Domain) کسب وکار است. اریک اوانز در کتاب خود به نامDomain-Driven Design: Tackling Complexity in the Heart of Software&#34; &#34;این مفاهیم را معرفی کرد.مفاهیم کلیدی DDD از دیدگاه فاولر:الف) Domain Modelمدل دامنه نمایش انتزاعی از دانش و فعالیت های مربوط به یک حوزه خاص کسب وکار است. این مدل باید:- مفاهیم و روابط کلیدی حوزه را منعکس کند.- به زبان کسب وکار (نه زبان فنی) بیان شود.- به صورت اشیاء و عملیات پیاده سازی شود.در این راهنمای سبک، مدل دامنه به جای اینکه فقط در مدلهای Django قرار گیرد، در لایه های خاص خود سازماندهی میشود. مثال از منبع:class Order:       def init (self, items, user):            self.items = items     # Domain logic here            self.user = userب) ) Ubiquitous Language زبان همه جا حاضر(یک زبان مشترک بین توسعه دهندگان و متخصصان حوزه که در تمام مراحل توسعه استفاده میشود. این زبان باید:- در کد، اسناد و گفتگوها یکسان باشد.- از اصطلاحات فنی غیرضروری پرهیز کند.- مفاهیم حوزه را دقیقاً همانطور که متخصصان حوزه می فهمند بیان کند.در این راهنمای سبک، نام کلاسها، متدها و ماژول ها باید از این زبان پیروی کنند.    استفاده از اصطلاحات کسب وکار در نام گذاری:     مثال:   Order.is_eligible_for_discount() به جای Order.check_discount().ج) Multiple Canonical modelsدر سیستم های بزرگ، یک مدل واحد برای کل سیستم ممکن است بسیار پیچیده شود. DDD پیشنهاد میکند از چندین مدل متعارف استفاده شود که هر کدام بخش خاصی از سیستم را با دیدگاه خاصی مدل سازی میکنند.در این راهنمای سبک، این مفهوم با تقسیم سیستم به حوزه های مستقل (Bounded Contexts) پیاده سازی میشود.   مثال: مدل User در حوزه orders ممکن است با مدل User در حوزه payments متفاوت باشد.د)  Bounded Context (حوزه محدود)مرز مشخصی که در آن یک مدل دامنه خاص معنا پیدا میکند و تعاریف دقیق دارد. ویژگی های کلیدی:- هر حوزه محدود مسئولیت های مشخصی دارد.- مدل های مختلف می توانند در حوزه های محدود مختلف تعاریف متفاوتی داشته باشند.- ارتباط بین حوزه ها باید به دقت مدیریت شود.در این راهنمای سبک، هر حوزه محدود به عنوان یک اپلیکیشن Django جداگانه پیاده سازی میشود.درک و اعمال راهنمای سبکاین راهنمای سبک پیشنهاد میکند پروژه های Django را بر اساس اصول DDD سازماندهی کنیم.  اصول کلیدی در پیاده سازی:1. جداسازی حوزه ها: هر حوزه کسب وکار (مانند سفارشات، محصولات) باید در ماژول خود قرار گیرد و وابستگی حداقلی به دیگر حوزه ها داشته باشد.2. تمرکز بر : Domain Logic منطق کسب وکار باید در سرویس ها و مدل های دامنه قرار گیرد، نه در ویوها یا کنترلرها.3. استفاده از الگویRepository  : برای جداسازی لایه دسترسی به داده از لایه منطق کسب وکار.4. تعریف واضح مرزها: ارتباط بین حوزه ها باید از طریق واسط های تعریف شده و واضح انجام شود.5. تست پذیری: با جداسازی مناسب لایه ها، نوشتن تست های واحد آسان تر میشود. مدلسازی معماری با نمودار های UML  نمودار کامپوننت برای معماری پیشنهادی@startumlpackage &#34;Core&#34; {    [Common Utilities]    [Shared Kernel]}package &#34;Order Domain&#34; as orders {    [Order Model]    [Order Service]    [Order Repository]}package &#34;Product Domain&#34; as products {    [Product Model]    [Product Service]    [Product Repository]}package &#34;Interfaces&#34; {    [API Controllers]    [Web Views]}[API Controllers] --&gt; [Order Service] : uses[API Controllers] --&gt; [Product Service] : uses[Web Views] --&gt; [Order Service] : uses[Web Views] --&gt; [Product Service] : uses [Order Service] --&gt; [Order Repository] : depends on[Order Repository] --&gt; [Order Model] : manages[Order Service] --&gt; [Order Model] : operates on [Product Service] --&gt; [Product Repository] : depends on[Product Repository] --&gt; [Product Model] : manages[Product Service] --&gt; [Product Model] : operates on [Order Service] --&gt; [Shared Kernel] : uses[Product Service] --&gt; [Shared Kernel] : uses @endumlتوضیح نمودار:1. اینترفیس ها: شامل کنترلرهای API و ویوهای وب که به عنوان نقطه ورود سیستم عمل میکنند.2. سرویس های حوزه: حاوی منطق کسب وکار و از طریق واسط های تعریف شده با لایه های دیگر ارتباط برقرار میکنند.3. Repositoryها : مسئول دسترسی به داده ها و جداسازی لایه ذخیره سازی از منطق کسب وکار.4. مدل ها: نمایش مفاهیم حوزه با استفاده از Ubiquitous Language.5. هسته مشترک ( Shared Kernel  ) : شامل قابلیت های مشترک بین چندین حوزه.مدل  Order:from dataclasses import dataclassfrom datetime import datetimefrom typing import List @dataclassclass OrderItem:    product_id: str    quantity: int    price: float @dataclassclass Order:    id: str    user_id: str    items: List[OrderItem]    status: str = &#34;pending&#34;    created_at: datetime = datetime.now()     def total_price(self):        return sum(item.price * item.quantity  for  item in self.items)     def mark_as_paid(self):        if self.status != &#34;pending&#34;:            raise ValueError(&#34;Order must be pending&#34;)        self.status = &#34;paid&#34;سرویس Order با تزریق وابستگی:class OrderService:    def init(self, order_repo, payment_gateway):        self.order_repo = order_repo        self.payment_gateway = payment_gateway     def place_order(self, user_id, items):        order = Order(str(uuid4()), user_id, items)        self.order_repo.save(order)        return order     def process_payment(self, order_id, payment_details):        order = self.order_repo.get(order_id)        self.payment_gateway.charge(order.total_price(), payment_details)        order.mark_as_paid()        self.order_repo.save(order)تست پذیری سرویس Order :from unittest.mock import Mockdef test_order_payment():    mock_repo = Mock()    mock_gateway = Mock()    service = OrderService(mock_repo, mock_gateway)       order = service.place_order(&#34;user1&#34;, [{&#34;product_id&#34;: &#34;1&#34;, &#34;quantity&#34;: 2, &#34;price&#34;: 10}])    service.process_payment(order.id, {&#34;card&#34;: &#34;1234&#34;})       assert mock_gateway.charge.called    assert order.status == &#34;paid&#34;نمودار توالی پرداخت:@startumlactor Customerparticipant &#34;Order API&#34; as apiparticipant &#34;Order Service&#34; as serviceparticipant &#34;Payment Gateway&#34; as gatewayparticipant &#34;Order Repository&#34; as repo Customer -&gt; api: POST /ordersapi -&gt; service: place_order()service -&gt; repo: save()api -&gt; Customer: 201 Created Customer -&gt; api: POST /paymentsapi -&gt; service: process_payment()service -&gt; gateway: charge()service -&gt; repo: save()api -&gt; Customer: 200 OK@endumlنمودار UML بهینه شده (مطابق اصول طراحی نرم افزار)@startumlcomponent &#34;Order API&#34; as api {    [OrderViewSet]}component &#34;Order Domain&#34; as domain {    [OrderService]    [OrderRepository]    [OrderModel]}component &#34;Product Domain&#34; as product {    [ProductService]}api --&gt; domain : usesdomain --&gt; product : depends (via interface) note right of domain  Bounded Context:  - OrderModel encapsulates  domain logic  - Repository handles DBend note@enduml مزایای این معماری:1. قابلیت نگهداری: تغییر در یک حوزه تأثیر کمی بر حوزه های دیگر دارد.2. قابلیت تست: هر جزء را میتوان به صورت مستقل تست کرد.3. انعطاف پذیری: میتوان تکنولوژی های مختلف را برای حوزه های مختلف انتخاب کرد.4. مقیاس پذیری: هر حوزه را می توان به صورت مستقل مقیاس داد.5. شفافیت: ساختار کد منعکس کننده ساختار کسب وکار است. مثال واقعی: سیستم فروشگاه آنلاین با معماری DDD در Djangoدر این مثال، یک سیستم فروشگاه آنلاین را با معماری DDD پیاده‌سازی می‌کنیم. حوزه‌های اصلی عبارتند از: - سفارشات (Order) - محصولات (Product) - کاربران (User)   گام ۱: ساختار پروژه (Project Structure)ساختار پیشنهادی مبتنی بر Bounded Contexts:my_shop/├── core/ # Shared Kernel│ ├── exceptions.py│ └── utils.py├── domains/│ ├── orders/ # Bounded Context: Order│ │ ├── models.py # Domain Models│ │ ├── services.py # Domain Services│ │ ├── repositories.py # Repositories│ │ └── events.py # Domain Events│ ├── products/ # Bounded Context: Product│ │ ├── models.py│ │ └── services.py│ └── users/ # Bounded Context: User│ └── models.py├── interfaces/│ ├── api/ # API Layer│ │ └── orders/│ │ └── views.py│ └── web/ # Web Layer (Optional)└── infrastructure/├── db/ # Database Adaptors│ └── django_orm.py└── event_handlers/ # Event Handlersگام ۲: پیاده‌سازی مدل دامنه (Domain Models) ۱. مدل Order (در domains/orders/models.py)from dataclasses import dataclassfrom datetime import datetimefrom typing import Listfrom domains.users.models import Userfrom domains.products.models import Product @dataclassclass OrderItem:    product: Product    quantity: int    price: float @dataclassclass Order:    id: str    user: User    items: List[OrderItem]    created_at: datetime = datetime.now()     def total_price(self) -&gt; float:        return sum(item.price * item.quantity for item in self.items)     def add_item(self, product: Product, quantity: int, price: float):        self.items.append(OrderItem(product, quantity, price)) ۲. مدل Product  (در domains/products/models.py)@dataclassclass Product:    id: str    name: str    price: float    stock: int     def reduce_stock(self, quantity: int):        if self.stock &lt; quantity:            raise ValueError(&#34;Insufficient stock&#34;)        self.stock -= quantityگام ۳: پیاده‌سازی سرویس دامنه (Domain Services) vices   ۱. OrderService  (درdomains/orders/services.py )from domains.orders.models import Orderfrom domains.orders.repositories import OrderRepositoryfrom domains.products.services import ProductService class OrderService:    def init(self, order_repository: OrderRepository, product_service: ProductService):        self.order_repository = order_repository        self.product_service = product_service     def place_order(self, user, items: List[dict]) -&gt; Order:          for item in items:            self.product_service.reduce_stock(item[&#34;product_id&#34;], item[&#34;quantity&#34;])                   order = Order.create(user, items)                    self.order_repository.save(order)           from domains.orders.events import OrderPlacedEven               OrderPlacedEvent(order.id).publish            return order2.  ProductService (در domains/products/services.py)from domains.products.repositories import ProductRepository class ProductService:    def init(self, product_repository: ProductRepository):        self.repository = product_repository     def reduce_stock(self, product_id: str, quantity: int):        product = self.repository.get_by_id(product_id)        product.reduce_stock(quantity)        self.repository.save(product) گام ۴: پیاده‌سازی Repository  (دسترسی به داده) ۱. OrderRepository (در domains/orders/repositories.py)from domains.orders.models import Orderfrom infrastructure.db.django_orm import DjangoOrderModel class OrderRepository:    def save(self, order: Order):        django_order = DjangoOrderModel.from_domain(order)        django_order.save()def get_by_id(self, order_id: str) -&gt; Order:        django_order = DjangoOrderModel.objects.get(id=order_id)        return django_order.to_domain() ۲.  DjangoOrderModel  (در  infrastructure/db/django_orm.py )from django.db import models class DjangoOrderModel(models.Model):    id = models.UUIDField(primary_key=True)    user_id = models.UUIDField()    total = models.DecimalField(max_digits=10, decimal_places=2)    created_at = models.DateTimeField()     @classmethod    def from_domain(cls, order):        return cls)            id=order.id,            user_id=order.user.id,            total=order.total_price(),            created_at=order.created_at        (     def to_domain(self):        from domains.orders.models import Order        return Order)            id=self.id,            user=User(id=self.user_id),            items=[],  # Load items separately            created_at=self.created_at گام ۵: پیاده‌سازی API (Interface Layer) ۱.  OrderViewSet (در interfaces/api/orders/views.py )from rest_framework import viewsetsfrom domains.orders.services import OrderServicefrom domains.orders.repositories import OrderRepositoryfrom domains.products.services import ProductService class OrderViewSet(viewsets.ViewSet):    def create(self, request):        user = request.user        items = request.data.get(&#34;items&#34;, [])         order_service = OrderServic)            OrderRepository(),            ProductService(ProductRepository())        (         order = order_service.place_order(user, items)        return Response({&#34;order_id&#34;: order.id}, status=201) گام ۶: مدیریت رویدادهای دامنه (Domain Events) ۱. تعریف رویداد (در domains/orders/events.py )from core.events import DomainEvent class OrderPlacedEvent(DomainEvent):    def init(self, order_id: str):        self.order_id = order_id     def handle(self):        print(f&#34;Order {self.order_id} placed!&#34;) گام ۷: تست‌ها (Testability) ۱. تست  OrderService (در tests/orders/test_services.py )from unittest.mock import Mockfrom domains.orders.services import OrderService def test_place_order():    repo = Mock()    product_service = Mock()    service = OrderService(repo, product_service)     service.place_order(user=None, items=[{&#34;product_id&#34;: &#34;1&#34;, &#34;quantity&#34;: 2}])       assert repo.save.called    assert product_service.red  نتیجه گیریاعمال اصول DDDدر Djangoنیاز به تغییر در شیوه سنتی توسعه دارد، اما مزایای آن در پروژه های متوسط و بزرگ کاملاً محسوس است. این راهنمای سبک با معرفی ساختار مبتنی بر حوزه های محدود، جداسازی مسئولیت ها و تعریف واسط های واضح ، به ایجاد سیستم های قابل نگهداری، انعطاف پذیر و متناسب با نیازهای کسب وکار کمک میکند. مدل سازی مناسب با  ) UML مانند نمودارهای کامپوننت(به درک بهتر روابط بین اجزا و طراحی دقیق تر معماری کمک میکند.</description><category>زهرا بهرامیان</category><author>زهرا بهرامیان</author><pubDate>Mon, 30 Jun 2025 10:43:54 +0330</pubDate></item></channel></rss>