TG Telegram Group Link
Channel: کانال مکتب‌خانه DDD
Back to Bottom
💡 مقایسه‌ی پارادایم‌های برنامه‌نویسی — از Flow-Based تا State-Centric

در مسیر تحول برنامه‌نویسی، از تفکر flow-based با تکیه بر functionها، رفتیم به سمت ساختارهای state-centric و assignment-driven — و در این بین، شاید چیزی مهم مثل وضوح جریان داده رو از دست دادیم.

۱- Functional Programming (FP) — function-driven، flow-based

توابع هسته‌ی اصلی محاسبات هستن.
توابع به‌عنوان داده در نظر گرفته می‌شه؛ می‌تونه ترکیب بشه.
تمرکز روی جریان صریح داده بین functionهاست.
ساده، قابل پیش‌بینی، بدون state پنهان.
⚠️ مدل‌سازی سیستم‌های واقعی و stateful در این پارادایم محدودتره.

۲- Object-Oriented Programming (OOP) — state-centric، assignment-driven

توابع مرتبط به‌همراه state مشترک در قالب objectها قرار می‌گیرن.
باعث modularity و استفاده‌ی مجدد از کد می‌شه.
⚠️ ولی جریان هندل کردن یک سناریو implicit می‌شه — توی methodها و تغییرات داخلی state پنهانه.
⚠️ منطق حول assign و تغییر وضعیت- change state- می‌چرخه، نه حول جریان.

۳- Actor Model — agent-centric، message-driven

پارادایم OOP رو یه قدم جلوتر می‌بره: objectها به agentهای مستقل تبدیل می‌شن.
این agentها فقط با پیام‌های async با هم حرف می‌زنن.
برای سیستم‌های concurrent و توزیع‌شده عالیه.
⚠️ اما باز هم جریان داده پراکنده و پنهانه — در زنجیره‌های پیام و actorهای جدا.
--------------------------------------

👉 در این مسیر، از flow-based logic به سمت ساختار و مقیاس‌پذیری رفتیم — ولی اغلب با هزینه‌ی از دست دادن وضوح جریان داده.

🧭 آیا می‌تونیم دوباره بین این‌ها تعادل ایجاد کنیم؟
👍3
Loop vs Recursion.pdf
330.4 KB
🎯 درک عمیق control flow یکی از پایه‌های اصلی برنامه‌نویسیه. در این مقاله به بررسی تفاوت‌های بین loop و recursion پرداختم و نشون دادم که چرا این انتخاب‌ها فراتر از syntax ساده هستن و به mental models ما برمی‌گردن.

اگه شما هم تجربه‌ای در این زمینه دارید یا سوالی براتون پیش اومده، حتماً تو کامنت‌ها باهام به اشتراک بذارید. خوشحال میشم نظر شما رو هم بدونم .
معرفی کتاب ریاضی ارزشمند "How to Solve It" (چگونه مسئله را حل کنیم)

✍️ اثر ماندگار ریاضیدان برجسته، جورج پولیا

📖 این کتاب که در سال 1945 منتشر شد، فراتر از یک راهنمای حل مسائل ریاضی است و به یک مرجع بی‌نظیر در زمینه‌ی آموزش تفکر ساختاریافته و توسعه‌ی مهارت‌های حل مسئله در تمامی جوانب زندگی تبدیل شده است. پولیا در این اثر، با زبانی ساده و گیرا، یک چهارچوب عملی و فلسفی برای مواجهه با چالش‌ها و یافتن راه‌حل‌های مؤثر ارائه می‌دهد.

🔑 مفهوم اصلی "How to Solve It" بر پایه‌ی یک فرآیند چهار مرحله‌ای استوار است:

1️⃣ درک مسئله (Understanding the Problem):
ضروری است که مسئله به طور کامل درک شود. پولیا بر اهمیت پرسیدن سؤالات کلیدی تأکید می‌کند:

- مجهول چیست؟ (What is the unknown?)
- داده‌ها کدامند؟ (What are the data?)
- شرایط چیست؟ (What is the condition?)
- آیا امکان ترسیم شکل یا نمودار وجود دارد؟
- آیا مسئله مشابهی دیده‌اید؟
- آیا می‌توان مسئله را به بخش‌های -
کوچک‌تر تقسیم کرد؟
درک صحیح مسئله، نیمی از راه‌حل است.

2️⃣ طرح‌ریزی (Devising a Plan):یافتن ارتباط بین داده‌ها و مجهول و طرح‌ریزی استراتژی. پولیا "روش‌های مکاشفه‌ای" (heuristics) را معرفی می‌کند، مانند:

- حدس زدن و آزمایش کردن (Guessing and checking)
- جستجو برای الگو (Looking for a pattern)
- رسم شکل (Drawing a diagram)
- کار کردن به عقب (Working backward)
- استفاده از مسئله‌ی مشابه (Using a related problem)
- تجزیه و تحلیل (Breaking down the problem)
- ساده‌سازی (Simplifying the problem)
💡 طرح‌ریزی یک فرآیند اکتشافی است.

3️⃣ اجرا (Carrying out the Plan):اجرای دقیق و گام به گام طرح. صبر، دقت و توجه به جزئیات مهم است. هر گام باید منطقی و صحیح باشد و آمادگی برای مواجهه با مشکلات پیش‌بینی‌نشده وجود داشته باشد.

4️⃣ بازنگری (Looking Back):
بررسی و ارزیابی راه‌حل به دست آمده برای یادگیری و بهبود. سؤالاتی که باید پاسخ داده شوند:

- آیا راه‌حل صحیح است؟
- آیا روش دیگری برای حل وجود دارد؟
- آیا می‌توان از این روش برای مسائل مشابه استفاده کرد؟
- چه درس‌هایی آموختیم؟
🧐 بازنگری به بهبود عملکرد در آینده کمک می‌کند.

🌟 اهمیت و تأثیر "How to Solve It":
این کتاب با رویکرد عملی، زبان ساده و تأکید بر فرآیند تفکر، تأثیر عمیقی بر آموزش ریاضیات و مهارت‌های حل مسئله داشته است و در زندگی روزمره، علوم، مهندسی، مدیریت و سایر حوزه‌ها کاربرد دارد. پولیا با تأکید بر پرسش‌های درست، جستجو برای الگوها، استفاده از تجربیات و بازبینی، چارچوبی قدرتمند برای توسعه‌ی تفکر انتقادی و توانایی حل مسئله ارائه می‌دهد.

📚 "How to Solve It" همچنان یک منبع الهام‌بخش برای همگان است.



https://en.m.wikipedia.org/wiki/How_to_Solve_It
👍1
کانال مکتب‌خانه DDD
معرفی کتاب ریاضی ارزشمند "How to Solve It" (چگونه مسئله را حل کنیم) ✍️ اثر ماندگار ریاضیدان برجسته، جورج پولیا 📖 این کتاب که در سال 1945 منتشر شد، فراتر از یک راهنمای حل مسائل ریاضی است و به یک مرجع بی‌نظیر در زمینه‌ی آموزش تفکر ساختاریافته و توسعه‌ی مهارت‌های…
🎬 ویدئو: "ذهن درخشان پولیا: هنر تدریس و حل مسئله"

کاوشی در ذهن پولیا: چگونه عمیق‌تر فکر کنیم (ویژه توسعه‌دهندگان و مالکان محصول)

اگر به دنبال ارتقای سطح تفکر و توانایی حل مسائل پیچیده در کارتون هستید، پیشنهاد می‌کنم علاوه بر خواندن کتاب How To Solve It این ویدئو جالب و ارزشمند رو هم مشاهده کنید. این ویدئو، شما را به تماشای یک کلاس درس و کارگاه با جورج پولیا، نویسنده‌ی کتاب ارزشمند "How to Solve It"، دعوت می‌کند.

پولیا در این محتوا، نه فقط تکنیک‌های حل مسئله، بلکه نگرش عمیق خود به فرآیند یادگیری و مواجهه با چالش‌ها را به اشتراک می‌گذارد. او با تاکید بر این ایده محوری که "تدریس، فرصت دادن به دانش‌آموزان برای کشف بهتر چیزهاست"، یک اصل کلیدی در توسعه‌ی فردی و تیمی را برجسته می‌سازد.

چرا تماشای این ویدئو برای شما مفید است؟

👨‍💻 برای توسعه‌دهندگان: با مشاهده‌ی رویکرد پولیا به ساختاربندی مسائل و تشویق به تفکر مستقل برای یافتن راه‌حل، می‌توانید الگوهای ذهنی قدرتمندتری در مواجهه با مشکلات فنی ایجاد کنید. این ویدئو به تقویت تفکر تحلیلی و خلاقیت شما کمک می‌کند.

📦 برای مالکان محصول: درک فلسفه‌ی پولیا در مورد تسهیل فرآیند یادگیری و کشف، می‌تواند به شما در طراحی محصولاتی که کاربران را به تعامل عمیق و حل مسائل واقعی دعوت می‌کنند، الهام بخشد. این نگرش همچنین در رهبری تیم و اتخاذ تصمیمات استراتژیک مبتنی بر درک عمیق‌تر مسائل، مؤثر خواهد بود.

این ویدئو، یک آموزش سطحی نیست؛ بلکه فرصتی برای درک عمیق‌تر شیوه‌ی تفکر یک استاد برجسته است که می‌تونه نگرش شما به چالش‌ها و فرآیند یادگیری را متحول کنه.

🔗 لینک ویدئو: https://www.youtube.com/watch?v=h0gbw-Ur_do&t=928s

مکتب‌خانه DDD
@DomainDrivenDesign_ir
👍1
📌 ارتباط حل مسئله به روش جورج پولیا و EDD

چند وقت پیش، داشتم کتاب ارزشمند "چگونه مسئله را حل کنیم" اثر جورج پولیا را تورق می‌زدم. جورج پولیا توی این کتاب یه چارچوب ساده ولی قدرتمند برای حل مسئله ارائه می‌ده:
1️⃣ درک مسئله: قبل از هر اقدامی، مطمئن بشیم دقیقاً با چی طرفیم.
2️⃣ طراحی نقشه: یه استراتژی ما برای رسیدن به جواب.
3️⃣ اجرای نقشه: گام به گام پیش می‌ریم و برنامه‌مون رو عملی می‌کنیم.
4️⃣ بازبینی و تعمق: بعد از حل، یه نگاه بندازیم به مسیری که طی کردیم و درس‌هایی که گرفتیم.

یک همپوشانی جالب بین این توصیه‌ها و رویکرد Exploratory Domain Discovery وجود داره.
توی EDD، اولین قدم تیم برای طراحی یه سیستم اینه که بپرسه:

"هدف نهایی این سیستم چیه؟" خودمونی‌ترش اینه که: "تهش قراره به چی برسیم و جه مسئله‌ای رو حل کنیم؟". یا به قول پولیا، "صورت مسئله رو درست بفهمیم." .

1️⃣ درک مسئله: مثلاً، وقتی داریم سیستم حقوق و دستمزد طراحی می‌کنیم، "هدف نهایی" اینه که هر کارمند بعد از محاسبه دقیق حقوقش، یک فیش حقوقی عاری از خطا کنه. این میشه نقطه‌ی کانونی ما(Main Point).

2️⃣ طراحی نقشه: بعد، درست مثل نقشه‌ی پولیا، ما از اون هدف نهایی شروع می‌کنیم به عقبگرد و کشف عواملی که بهش منجر می‌شن: ثبت ساعات کاری دقیق، فرمول‌های محاسبه‌ی حقوق، انواع کسورات و... 🗺️ این دقیقاً همون مرحله‌ی "حرکت عقب‌گرد" یا "Backward Moving" در EDD هست.

3️⃣ اجرای نقشه:در مرحله‌ی بعد، با استفاده از ابزارهایی مثل کارت‌های مفهومی برای مدلسازی، برگزاری جلسات بحث و تبادل نظر با متخصصان دامنه و ایجاد نمونه‌های واقعی، سیستم رو می‌سازیم ("اجرای نقشه"). 🛠️

4️⃣ بازبینی و تعمق: و در نهایت، فرآیند EDD شامل چندین دور اکتشاف (Discovery)، تست مدل با مثال‌های واقعی، پرسیدن سوالات برای رفع ابهامات و بازبینی مستمر مدله. این همون "بازبینی و تعمق" پولیاست که به ما کمک می‌کنه مطمئن بشیم راه‌حل درستی رو پیدا کردیم و چیزهای جدیدی یاد گرفتیم. 🔄

------------------------

به نظر من، EDD در مواجهه با پیچیدگی‌های دنیای نرم‌افزار، همون منطق قدرتمندی رو دنبال می‌کنه که پولیا برای حل مسائل ریاضی پیشنهاد داده بود. فقط ابزارها متفاوت شدن: کارت‌های Domain Concept و ارتباطات بین این کارت‌ها به‌جای معادلات، و همکاری تیمی به‌جای کار انفرادی روی کاغذ. 🤝

اما سوال اساسی در هر دو رویکرد یکیه:

"ما واقعاً در تلاش برای حل چه مشکلی هستیم؟" 🤔


برای من EDD ادامه‌ی همون نگاه پولیاست؛ فقط این‌بار در دنیای پیچیده‌تر، مشارکتی‌تر و زنده‌ترِ طراحی نرم‌افزار.
نه معادله می‌نویسیم، نه تابع مشتق می‌گیریم. ولی همون منطق رو دنبال می‌کنیم.

یکی از شعارهای اساسی در EDD این است:
See the ending. Discover the meaning. Design with purpose



این ارتباط عمیق بین تفکر ریاضی و طراحی نرم‌افزار همیشه برام جذاب بوده.


🎯 برای اطلاعات بیشتر در مورد Exploratory Domain Discovery به لینک زیر مراجعه کنید:
https://exploratorydomaindiscovery.com/
1
Forwarded from Masoud Bahrami
Flow-State-Communication.pdf
290.9 KB
New Article

📖 Title:
Flow, State, and Communication: A Comparative Exploration of Functional Programming, Object-Oriented Programming, and the Actor Model


In this paper, I compare three of the most important programming approaches (FP, OOP, Actor Model). These paradigms have, in a way, evolved from one another.

💡 My main focus is on how each of them deals with data flow, system state, and communication between different parts.
I believe that while newer paradigms solve complexity issues better, understanding how data moves through the system has become more difficult.
1
چرا تخمین‌زدن سخت است، و به‌جای آن چه باید کرد

در توسعه محصول، اغلب تحت فشاریم که "حدس بزنیم" یک کار چقدر زمان می‌برد. سؤال رایجی مثل این:
«این تسک چند روز طول می‌کشه؟»
اما بیشتر وقت‌ها، این تخمین‌ها بیشتر از اینکه بر پایه درک واقعی باشن، روی امید و حدس بنا شدن. و وقتی کار طبق برنامه پیش نمی‌ره، که خیلی وقت‌ها هم همین‌طوره، تیم‌ها دچار استرس، عجله یا سرزنش می‌شن.

مشکل اینجاست: ما با کار کردن روی محصول مثل یه کار ساده و قابل‌پیش‌بینی برخورد می‌کنیم. درحالی‌که بیشتر کارهای محصول پیچیده هستن و این پیچیدگی تابعی است از فاکتورهای مختلف و بهم مرتبط. و پیچیدگی با برنامه زمانی دقیق پیش نمی‌ره.

کاری که واقعاً کمک می‌کنه، اینه که به‌جای زور زدن برای تخمین زودهنگام، اول سعی کنیم اصل مسئله رو بهتر بفهمیم.

به‌جای اینکه بپرسیم «چقدر طول می‌کشه؟»، می‌پرسیم:
«چقدر این کار رو می‌فهمیم؟»
و اینو از پنج زاویه اصلی بررسی می‌کنیم:

🌟 وضوح دامنه (Domain Clarity)
آیا دقیق می‌دونیم مشکل چیه و کسب‌وکار یا کاربر چی می‌خواد؟
🔄 مثال: پیاده‌سازی فرم لاگین = واضح. طراحی سیستم قیمت‌گذاری برای ۳ منطقه با قوانین در حال تغییر = مبهم.

🌟 وابستگی‌های فنی (Technical Dependencies)
چقدر این کار به سیستم‌های دیگه یا بخش‌های حساس و قدیمی بستگی داره؟
🔄 مثال: اضافه‌کردن یک تولتیپ ساده در UI = راحت. اتصال به API قدیمی یک سیستم ثالث = پیچیده و پرریسک.

🌟 وابستگی‌های بیرونی (External Dependencies)
آیا این تسک به ورودی یا تأیید تیم‌های دیگه، تأمین‌کننده‌ها یا بخش‌هایی مثل حقوقی وابسته‌ست؟
🔄 مثال: به‌روزرسانی مستندات داخلی = مستقل. راه‌اندازی فیچری که نیاز به تأیید حقوقی و هماهنگی با تأمین‌کننده داره = وابسته.

🌟 آشنایی تیم (Team Familiarity)
آیا تیم قبلاً این‌جور کارها رو با همین ابزارها انجام داده؟
🔄 مثال: رفع باگ در اپ اصلی = آشنا. ساخت سرویس جدید با زبانی که تیم بلد نیست = ناشناخته.

🌟 هماهنگی بین‌تیمی (Cross-Team Sync)
آیا این کار رو می‌تونیم کاملاً درون تیم انجام بدیم یا نیاز به هماهنگی و تأیید از جاهای دیگه داره؟
🔄 مثال: تغییر متن دکمه = مستقل. اضافه کردن فیچری که نیاز به تأیید حقوقی، دیزاین و دیتا داره = نیازمند هماهنگی بالا.

با امتیاز دادن به یک تسک بر اساس این ۵ عامل (از پیچیدگی کم تا زیاد)، درک خیلی دقیق‌تری از اونچه قراره انجام بشه به‌دست میاریم. این کمک می‌کنه بفهمیم آیا آماده اجراییم، یا باید اول کشف بیشتری انجام بدیم.

🔍 مثال واقعی:
فرض کن تیم قراره فیچری اضافه کنه به اسم «پشتیبانی از یک پلن جدید پرداخت».
در ظاهر ساده به‌نظر می‌رسه، ولی وقتی تیم از زاویه این ۵ عامل نگاه می‌کنه، متوجه می‌شه:

- منطق قیمت‌گذاری مشخص نیست → (وضوح دامنه پایین).
- باید به سیستم یک تأمین‌کننده خارجی وصل بشه → (وابستگی زیاد).
- تیم قبلاً با سیستم پرداخت کار نکرده → (آشنایی کم).
نتیجه:
این کار کوچیک نیست، و باید اول یک فاز کشف (Discovery) براش انجام بدن.
این روش کمک می‌کنه تیم‌ها هوشمندتر برنامه‌ریزی کنن، غافلگیر نشن، و از قبل در مورد ریسک‌ها صحبت کنن — نه وقتی خیلی دیر شده.


مکتب‌خانه DDD
@DomainDrivenDesign_ir
👍82
معرفی کوتاه الگوی طراحی State/Status Segregation Pattern

💡چرا مدل‌سازی سیستم‌ها گره می‌خورد؟ شفاف سازی Lifecycle در مقابل Context به منظور مدلسازی بهتر سیستم

تا حالا توی مکالمات کاری، مخصوصاً با مدیر محصول، به جمله‌هایی مثل این برخوردین؟
سفارش هنوز فعاله، ولی پیک تو ترافیکه، رستوران هم هنوز تأیید نکرده. تازه، کاربر زنگ زده بود آدرس رو عوض کنه."


یه جمله‌ی ساده، ولی پر از اطلاعات:
🔵 «سفارش فعال است» یه فاز اصلی از چرخه‌ی عمر
🟠 «پیک در ترافیکه، رستوران تأیید نکرده، تغییر آدرس» → شرایط موقت و همزمان.

اینجا همون جاییه که مدل‌سازی معمول ما (با یه enum تک‌بعدی، زمخت و پربار!) به مشکل می‌خوره:

enum OrderState {
Placed,
Preparing,
RiderDelayed,
RestaurantUnconfirmed,
AddressChangeRequested,
Delivered
}


این مدل به‌ظاهر ساده، مفاهیم غیرمرتبط رو با هم قاطی می‌کنه:
🔴 مقدار RiderDelayed یه وضعیت گذراست، نه فاز چرخه عمر
🔴 مقدار RestaurantUnconfirmed توی مرحله‌ی آماده‌سازی معنا داره، نه بعدش
🔴 مقدار AddressChangeRequested یه رخداد کاربره، نه حالت سفارش

📍 نتیجه؟‌ مدل به ظاهر ساده، ولی گول‌زننده، شکننده، مبهم و سخت تست‌پذیر!
———

راه‌حل غلبه بر چالش متداول بالا، تفکیک "State" و "Status"
برای حل این مسئله من الگوی State/Status Segregation Pattern یا به اختصار S3 رو معرفی کردم. S3 به بیان ساده:
یه اصل مدل‌سازی که به‌وضوح بین State (فاز انحصاری و پایدار چرخه عمر) و Status (شرایط موقت، خروجی و اکشن وابسته به آن State) تمایز قائل می‌شه.

🟡 در این مدل State (حالت) یعنی کجای فرآیندیم؟
کاملا Excusive هستند و چندین مقدار State با هم Mutually Excusive نیستند. اینها حالت پایدار هر موجودیت در طراحی رو مدل می‌کنند. مقادیرشون هم باعث تصمیم‌سازی در سیستم یا توسط کاربر می‌شود. (decision driver هستند). مثلا سفارشی که در وضعیت Draft است منتظر تسویه حساب شدن توسط کاربر میمونه.

enum OrderState { Draft, Paid, Issued, Cancelled }

• فقط یکی فعاله
• تعیین‌کننده‌ی منطق اصلی سیستم


🟠 و Status (وضعیت): چه اتفاقی افتاده؟ statusها مشخص کننده context یا outcome یک state هستند. همینطور observability سیستم رو توسط اینها مدل می‌کنیم. به ازای هر state ممکن است چندین status برای آن موجودیت وجود داشته باشد. بهمین خاطر exclusive نیستند. اینها بیشتر جنبه transient دارند.
enum OrderStatus {
RiderDelayed,
ConfirmationSMSSent,
AddressChangeRequested
}

• می‌تونه چندتا باشه
• فقط توصیف شرایط لحظه‌ایه، نه کنترل روند اصلی

الگوی S3 چطور کار می‌کنه؟
این الگو با تاکید بر جداسازی این دو مفهوم در طراحی و مدلسازی سعی می‌کنه به مدلی برسه که شفاف، قابل تست و قابل گسترش است.

نمونه واقعی:
{
"Order": {
"State": "OutForDelivery",
"Statuses": ["RiderDelayed", "AddressChangeRequested"]
},
"Settlement": {
"PaymentStatus": "Settled",
"LastAttempt": {
"Status": "Success",
"Time": "12:03"
}
}
}


🧠 الگوی S3 فقط یه روش نام‌گذاری نیست؛ یه زبان مشترک برای طراحی سیستمه.
این الگو بخشی از رویکرد مدل‌سازی و طراحی من در کتابی در دست نگارش با عنوان Language-Driven Design هست. الگوی S3 کمک می‌کنه مدل‌سازی‌مون شفاف، قابل تست و قابل گسترش بشه. با جدا کردن منطق چرخه عمر از وضعیت‌های contextی، هم ساختار کد تمیزتر می‌شه، هم APIها وضوح بیشتری پیدا می‌کنن. این الگو ما رو از enumهای زمخت، متورم، تک بعدی و درهم نجات می‌ده و کمک می‌کنه سیستم‌هایی بسازیم که هم قابل فهم‌ترن، هم راحت‌تر توسعه پیدا می‌کنن.

📎 لینک مقاله‌ 👇

https://masoudbahrami.medium.com/dont-confuse-state-with-status-when-modeling-domain-601bc91f326a


مکتب‌خانه DDD
@DomainDrivenDesign_ir
👏7👍1
S3Pattern.pdf
426.2 KB
📝 State/Status Segregation (S3) Pattern
Making Systems More Predictable by Separating Lifecycle from Context

🔍 In complex systems, mixing up state and status often leads to bloated models, fragile logic, and unpredictable behavior.

This paper, written by Masoud Bahrami, introduces the State/Status Segregation (S3) pattern, a modeling principle that cleanly separates lifecycle control (state) from contextual signals and side conditions (status).

❇️ By applying S3, you can design systems with clearer APIs, more predictable behavior, and codebases that are easier to test, evolve, and reason about.
1💯1
🎯معرفی کوتاه Behavior as Data Pattern

در جریان طراحی و توسعه دومین‌های نرم‌افزاری پیچیده، بارها و بارها با چالشی تکراری مواجه شدم:
فیلدی در مدل دامنه که ابتدا صرفاً یک مقدار داده‌ای (Data) به نظر می‌رسد، مثلاً Type، Category یا Status، اما به‌مرور زمان، همین فیلد ساده شروع می‌کند به تعیین رفتارسیستم. درظاهر هنوز با داده سروکار داریم، ولی در واقع داریم با «رفتار کد شده در دل داده»مواجه می‌شویم.

این مسئله را در دامنه‌های گوناگون تجربه کردم: از حسابداری گرفته تا فروش، از سیستم‌های پرداخت آنلاین تا رزرو آنلاین بلیت هواپیما. در هر مورد، ساختار اولیه‌ی سیستم به‌ظاهر ساده و قابل مدیریت بود، اما به‌مرور زمان شرط‌ها (if/switch) رشد می‌کردند، تست‌پذیری کاهش می‌یافت،و تغییرات جدید باعث ریسک شکستن بخش‌های قدیمی می‌شدند.

برای پاسخ به این چالش، به تدریج الگوی Behavior as Data را فرموله کردم، مدل ذهنی‌ای برای تشخیص زمان مناسب برای عبور از«داده» به «رفتار».

👁‍🗨 یک مثال واقعی ببینیم:
یک JournalEntry با فیلدی از جنس JournalEntryType که می‌تونست Sales، Purchase یاAdjustment باشه. در ابتدا با یک switch ساده در متد PostTo() کار راه می‌افتاد. اما به‌مرور زمان با افزوده شدن قوانین مالیاتی، تفاوت‌های بین انواع ثبت، و استثناهای تجاری متعدد، این فیلد تبدیل شد به گره‌ای بحرانی از منطق پراکنده، کدهای شرطی و دردسرهای تست‌پذیری و قص علی هذا.
enum JournalEntryType {
Sales,
Purchase,
Adjustment
}

class
JournalEntry {
JournalEntryType Type;
void PostTo(Ledger ledger) {

switch(Type) {

case Sales:
ledger.Credit(...); break;

case Purchase: ledger.Debit(...); break;

case Adjustment: ledger.Adjust(...); break;

}
}
}


این طراحی در ابتدا قابل قبول بود، اما هر تغییر دامنه‌ای باعث رشد شرط‌ها و شکنندگی کد می‌شد.

برای رفع این مشکل، به الگوی Behavior as Data رسیدم. در این الگو، وقتی می‌بینیم مقدار یک فیلد باعث تغییر در رفتار سیستم می‌شود، آن فیلد دیگر «داده» نیست، بلکه «نماینده‌ی رفتار» است


interface IPostingStrategy {
void PostTo(Ledger ledger);
}
class SalesEntry : IPostingStrategy { ... }
class
JournalEntry {
IPostingStrategy Strategy;
void PostTo(Ledger ledger) =>Strategy.PostTo(ledger);
}

نتیجه:
تست‌پذیری بهتر، حذف شرط‌ها، و گسترش‌پذیری بدون اثر جانبی.
----------------

🧠 معرفی Behavior as Data Pattern
الگوی
Behavior as Data یک الگوی ساختاری صرف نیست، بلکه یک بینش طراحی (modeling insight) است. الگوی Behavior as Data به ما می‌گوید:
اگر مقدار یک فیلد باعث تغییر در رفتار سیستم می‌شود، آنگاه آن فیلد دیگر صرفاً یک داده نیست، بلکه نماینده‌ی یک رفتار است و باید به یک مدل رفتاری (Behavioral Model) تبدیل شود.

به زبان ساده، هر زمان که سیستم به جای "تصمیم‌گیری با داده"، وارد فاز "تغییر رفتار بر اساس داده" می‌شود، زمان استفاده از این الگو فرارسیده است.
به عبارت دیگر:
💡اگر سیستم به جای آنکه با داده تصمیم بگیرد، بر اساس داده عمل متفاوتی انجام می‌دهد، زمان بازطراحی فرا رسیده.

مزایا و آثار این بازطراحی

حذف منطق شرطی تودرتو
تسهیل تست واحد برای هر رفتار
باز بودن مدل برای توسعه رفتارهای جدید بدون تغییر ساختار اصلی
بهبود شفافیت مدل دامنه برای ذینفعان (توسعه‌دهندگان، مدیران محصول و تحلیل‌گران)
----------------

چه زمانی باید از Behavior as Data استفاده کرد؟
برای تشخیص نیاز به این الگو، می‌توان از این هیوریستیک‌ها استفاده کرد:
🟠 مقدار فیلد منطق رفتار را تعیین می‌کند
آیا تغییر مقدار Type باعث تغییر در اجرای متدی مثل Submit() یا Process() می‌شود؟
🔵 وجود شرط‌های متعدد و در حال رشد بر اساس آن فیلد
آیا در نقاط مختلف سیستم شرط‌هایی مشابه if (type == ...) در حال تکرار است؟
🟣 نیاز به تست مستقل هر رفتار وجود دارد
آیا نمی‌توان به‌راحتی رفتار مرتبط با یک مقدار خاص را به‌صورت جداگانه تست کرد؟


چرا این الگو مهم است؟
در یک کلام باید بگم که بسیاری از مشکلات مزمن در طراحی سیستم‌ها (مثل پیچیدگی تدریجی، شرط‌های کلافه کننده، تست‌ناپذیری، و وابستگی‌هایشدید و شکننده) از همین بی‌توجهی به تمایز بین «داده» و «رفتار» ناشی می‌شود.

📘 این الگو بخشی از مجموعه الگوهای طراحی و مدلسازی من در کتاب «Language-Driven Design» که در حال نگارش آن هستم، است.


📎 مطالعه مقاله‌ی کامل الگو، با مثال‌های متنوع و تکنیک‌های بازطراحی:

https://medium.com/@masoudbahrami/introducing-behavior-as-data-pattern-1e4c82d1ede6
👌51
دوستان خوب و عزیزم

امیدوارم که همگی در کمال آرامش و سلامت به سر ببرید. در این ساعت‌های پرتنش همه‌مون بیش از هر زمان دیگه‌ای به آرامش و هوشیاری نیاز داریم. لطفا حواس‌تون به خودتون و عزیزاتون باشه

امیدواریم خیلی زود، دوباره روزهای آروم(تر) و بی‌دغدغه‌تر رو به همراه آرامش تجربه کنیم 🌿❤️
15
💡 Mixed Responsibility Smell

فرض کنید متدی دارید که پول را به حساب کاربر برمی‌گرداند و در همان لحظه مقدار جدید موجودی را هم برمی‌گرداند:
public Money Refund(Money amount)
{
Balance += amount;
return Balance;
}


چرا ممکن است این کار را بکنیم
شاید برای سادگی، یا چون می‌خواهیم بلافاصله بعد از عملیات، موجودی جدید را در تست‌ها Assert کنیم یا آن را به کاربر نمایش دهیم. این سناریوها کاملاً معقول به نظر می‌رسند!

اما سوال اینجاست:
آیا درسته که یک متد هم وضعیت را تغییر دهد و هم مقدار به‌روز شده رو برگرداند؟ در واقع سوال مهم در باره نحوه‌ی مدل کردن و پیاده‌سازی سناریوهایی که در بالا اشاره شد، است.

در جواب باید بگم:
این دقیقاً همون جاییه که با یک Code Smell به نام Mixed Responsibility Smell روبرو هستیم.

قطعاً ما نیاز به متد دیگری داریم که صرفاً موجودی را به ما بدهد. در واقع، نمی‌توانیم برای دریافت موجودی تنها به متد Refund تکیه کنیم؛ چرا که این امر ما را مجبور می‌کند برای هر بار خواندن موجودی، یک عملیات Refund انجام دهیم که نه منطقی است و نه قابل قبول. این یعنی عملاً ما هیچ‌گاه به یک موجودی ثابت و قابل اتکا دسترسی نداریم. علاوه بر بحث عدم قطعیت (indeterministic behavior) و موارد مشابه، این وضعیت یک Code Smell جدی محسوب می‌شود. حداقل پیامد آن این است که ما یک منطق یکسان (یعنی محاسبه موجودی) را در دو نقطه مختلف تکرار می‌کنیم: هم در متد Refund و هم در متدی مانند GetBalance، حتی اگر GetBalance تنها شامل return Balance; باشد.


سوال بعدی اینه که: چرا این مشکل‌ساز است
این «بوی بد» زمانی اتفاق می‌افته که یک متد یا کامپوننت بیش از یک مسئولیت یا وظیفه را بر عهده بگیره و باعث شود:

ابهام در نقش و وظیفه اصلی کد
پیچیدگی در فهم، تست و نگهداری کد
تکرار منطق مشابه در چند نقطه
مثل منطق محاسبه یا به‌روزرسانی موجودی که هم در متد Refund و هم در متد GetBalance تکرار می‌شود (حتی اگر در GetBalance صرفاً return Balance; باشد)
کاهش انعطاف‌پذیری و سختی توسعه کد
رفتار نامعین (Indeterministic Behavior): اگر برای گرفتن موجودی مجبور باشیم همیشه Refund را صدا بزنیم، هیچ‌وقت موجودی واقعی و پایدار در اختیار نخواهیم داشت، چون هر بار با گرفتن موجودی، وضعیت تغییر می‌کند!



مثال بهتر:
// command
public void Refund(Money amount)
{
Balance += amount;
}

// query
public Money GetBalance()
{
return Balance;
}


نتیجه اینکه:
هشدار مهمی که Mixed Responsibility Smell به ما میده اینه که:

یک متد یا کامپوننت باید تنها یک مسئولیت واضح و مشخص داشته باشد.
تفکیک درست مسئولیت‌ها باعث میشه که کد:
ساده‌تر و قابل فهم‌تر شود
راحت‌تر تست و نگهداری شود
توسعه و تغییرات آینده بدون دردسر انجام شود
👍72
کانال مکتب‌خانه DDD
Photo
📢 Introducing Goal-Oriented Architecture
By: Masoud Bahrami, from my upcoming book Language-Driven Design

We’ve been organizing software around layers, services, and controllers for decades.

Clean Architecture, Layered, Vertical Slicing… each gives us a way to structure HOW code is written. In all cases the organization is around(mostly): how we build it!

🤔 But what if we started with why the code exists

That's the core of Goal-Oriented Architecture. Instead of just focusing on structure, we make the Goal the primary building block.
It becomes a first-class citizen in your architecture.

A Goal is a concrete, high-level outcome your system must achieve, explicitly modeled right in your architecture.


🙋‍♂️What is Goal-Oriented Architecture about:

It isn't just about organizing code; it's about organizing intention.
It's about making your architecture a direct reflection of your business objectives, leading to clearer designs.



💸Example: TransferFunds

Imagine a TransferFunds Goal: it captures everything, preconditions, the transfer itself, and all side-effects like updating balances or sending notifications, all in one clear place. No more scattered logic!

This Goal declares:
🟥 Preconditions:

➡️ Both accounts are active
➡️ Sender has enough balance
➡️ Transfer limit isn’t exceeded

------
🟩 Goal:

➡️ Transfer funds between accounts

-----
🟨 Side-effects:

➡️ Update both balances
➡️ Log the transaction
➡️ Send notifications
➡️ Emit a FundsTransferred event


Everything related to this intent is captured in one place, the Goal, not scattered across services, handlers, and layers.

————-
🎯 The Benefits

Brings business purpose to the center of your design
Makes code easier to reason about, test, and trace
Treats side-effects as part of the architecture, not an afterthought
Encourages composable, declarative, intention-driven code
Fits naturally in event-driven, DDD, and workflow-based systems

Goal-Oriented Architecture brings business purpose to the forefront, making your code easier to reason about, test, and trace.

📝 Stay tuned
Goal Oriented Architecture is a key part of my upcoming book: Language-Driven Design, A practical philosophy for designing systems that reflect how we think, speak, and solve problems. I'll talk more about it...
1
میان تمام چارچوب‌ها، زبان‌ها و قراردادهای فکری، گاهی چیزی خام و ناهماهنگ از جایی دگر سر بر می‌آورد؛ نه برای تحلیل، نه برای آموزش، فقط به جهت یادآوری.

تصنیف «هستی چه بود؟» روایتی‌ست از اضطراب، فرسایش و ملالی که این روزها، حتی از دل منظمات! هم به بیرون نشت می‌کند.
شعر، ساده است. اجرا، قدیمی و آماتور. حس اما، صادقانه و آشناست:
«هستی چه بود؟ قصه‌ی پررنج و ملالی...»

مولانا جایی گفته بود:
«این جهان جنگ است چون کل بنگری»
شاید ما فقط قطعه‌هایی از این کل را مهندسی می‌کنیم، بی‌آن‌که میدان درگیر را ببینیم.

نظم هم گاهی نیاز به وقفه دارد. این، بخشی آن مکث است.


https://soundcloud.com/user-298641228/knnflitqzofw
4
"درک صحیح مسئله، نیمی از راه‌حل آن مسئله است."
- جورج پولیا

🧩 چگونه مسئله‌ای را به‌درستی حل کنیم؟
بر اساس روش کلاسیک جورج پولیا


1. درک مسئله
پیش از هر چیز، مسئله را واقعاً درک کنید.
• مسئله از شما چه می‌خواهد؟
• داده‌های در دسترس چیست؟
• شرایط چیست و آیا این شرایط برای رسیدن به پاسخ کافی است؟ یا ناقص، متناقض، یا زائد هستند؟
• آیا می‌توانید متغیرهای مسئله را مشخص کنید؟
• آیا می‌توانید نمودار، فلوچارت یا دیاگرامی از مسئله ترسیم کنید؟

✏️ بازنویسی دقیق مسئله، اولین گام برای حل آن است.


------------------------------------------
2. طراحی راه‌حل
پس از درک صحیح مسئله، به طراحی مسیر حل فکر کنید.
• آیا با چنین مسئله‌ای قبلاً مواجه شده‌اید؟
• آیا الگویی مشابه وجود دارد؟ الگوریتمی؟ راه‌حلی؟
• می‌توانید مسئله را به مسئله‌ای ساده‌تر یا آشناتر تبدیل کنید؟
• اگر اتصال مستقیمی میان داده و مجهول وجود ندارد، آیا یک مسئله‌ی فرعی یا موقت می‌تواند مفید باشد؟
• آیا امکان تغییر صورت مسئله برای قابل حل‌تر شدن آن وجود دارد؟

💡 مسائل آشنا، کلید حل مسائل ناآشنا هستند.


------------------------------------------
3. اجرای برنامه
راه‌حل طراحی‌شده را گام‌به‌گام اجرا کنید.
• آیا هر گام منطقی است و بر مبنای اطلاعات درست پیش می‌رود؟
• آیا می‌توانید صحت هر مرحله را توضیح یا اثبات کنید؟
• آیا اجرای این راه‌حل به نتیجه قابل اتکا می‌انجامد؟

⚙️ اجرای دقیق، همان اندازه اهمیت دارد که طراحی دقیق.


------------------------------------------
4 . بازنگری در نتیجه
پس از رسیدن به پاسخ، عقب برگردید و مسئله را دوباره مرور کنید.
• آیا پاسخ درست است؟
• آیا می‌توان آن را ساده‌تر یا واضح‌تر بیان کرد؟
• آیا می‌توان این روش را برای مسائل مشابه به‌کار گرفت؟
• آیا از تمام اطلاعات و شرایط استفاده شده؟

🔍 تحلیل راه‌حل، بخشی از حل مسئله است، نه مرحله‌ای اضافه.


------------------------------------------

🧠 در مجموع می‌توان گفت:
این ساختار کلاسیک، در عین سادگی، کاربردی‌ترین ابزار برای حل سیستماتیک مسائل در حوزه‌های مختلف توسعه نرم‌افزار، طراحی محصول، دیباگینگ، تحلیل داده، و تصمیم‌گیری است.
HTML Embed Code:
2025/07/14 15:24:36
Back to Top