کانال مکتب‌خانه DDD
654 subscribers
81 photos
1 video
4 files
154 links
کانال مکتب‌خانه DDD

اطلاع‌رسانی کارگاه‌ها، دوره‌ها و وبینارهای آموزشی
ارائه منابع و مطالب آموزشی

http://DomainDrivenDesign.ir

#Youtube Channel:
https://www.youtube.com/@Masoud.Bahrami

#Public Group:
https://t.me/DomainDrivenDesignGroup

#DDD
Download Telegram
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...
2
میان تمام چارچوب‌ها، زبان‌ها و قراردادهای فکری، گاهی چیزی خام و ناهماهنگ از جایی دگر سر بر می‌آورد؛ نه برای تحلیل، نه برای آموزش، فقط به جهت یادآوری.

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

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

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


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

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


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

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


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

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


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

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


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

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


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

🧠 در مجموع می‌توان گفت:
این ساختار کلاسیک، در عین سادگی، کاربردی‌ترین ابزار برای حل سیستماتیک مسائل در حوزه‌های مختلف توسعه نرم‌افزار، طراحی محصول، دیباگینگ، تحلیل داده، و تصمیم‌گیری است.
3
سلام دوستان عزیز 🍃
امیدوارم آخر هفته خوبی داشته باشید 🌿

وب‌سایت شخصی من راه‌اندازی شده:

https://MasoudBahrami.com

جایی برای ثبت و به اشتراک‌گذاری ایده‌ها، تجربیات عملی و تأملاتم درباره یافتن راه‌هایی بهتر برای توسعه نرم‌افزار بهتر.

امیدوارم مطالب سایت برای شما مفید و الهام‌بخش باشد

نظرات و پیشنهادات شما برای من بسیار ارزشمند است و خوشحال می‌شوم آن‌ها را بشنوم 💬🙏
👍43
Forwarded from Masoud Bahrami
New Article: Introducing Goal-Oriented Software Architecture!

Ever feel like your software gets lost in technical details instead of focusing on what your business needs? In my new article, I introduce Goal-Oriented Architecture, a new architectural style developed to address challenges often seen in common approaches like Clean, Onion, Ports and Adapters, and Vertical Slicing architectures.

It's a fresh way to build software that puts your real business objectives, your "goals", right at the core.

Discover how it makes systems clearer, more effective, and perfectly aligned with your business vision 👇:
https://masoudbahrami.com/article/introducing-goal-oriented-software-architecture/
2
Forwarded from Masoud Bahrami
Have you ever been tasked with building software for a complex business process and felt like you're staring at a tangled ball of yarn?
What if you could start with the finished masterpiece and unravel it backward?

That's the aim of Exploratory Domain Discovery (EDD), a collaborative tool introduced by Masoud Bahrami.


Imagine you need to automate hotel room pricing

The Desired End: The customer sees the correct final price.

🤔 Work Backward: What steps led to that price? (Discounts applied, base rate set, availability checked.)

🔄 Find Cycles: "Pricing periods" and "daily availability" are clear repeating patterns here!


By starting at the desired end result and working backward, using simple examples, EDD helps teams understand complex problems clearly. It's all about finding the main point and its surrounding details to build smarter solutions.
1
Forwarded from Masoud Bahrami
Math: Discovered or invented? And Why It Matters to Dev Guys

There's a fundamental question that has puzzled thinkers
for centuries: Is mathematics discovered, or is it invented? This long-standing debate within the philosophy of mathematics isn't just an academic exercise.

For us in software development, as designers, modelers, architects, and developers, understanding this dichotomy, and its nuances, directly impacts how we approach complex problems and build robust systems.

--------------------
The "Discovered" View:
From the perspective that mathematical truths exist independently of human thought, software professionals often find themselves acting as explorers. When I delved into domains like accounting or payroll, I encountered deeply embedded principles and seemingly immutable rules.

The precise logic of financial transactions, the established principles of double-entry bookkeeping, the complex yet consistent calculations for tax liabilities or social contributions, these feel-like inherent truths governing how money and compensation work.
A big confession:
I simply discover that I'm not(and must not!) invent the principle that a debit equals a credit, or that gross pay minus deductions equals net pay.


We are accurately modeling fundamental relationships that exist independently, uncovering the mathematical structure of the real world within that domain.

--------------------
The "Invented" View:
Aligned with the view that mathematics is a human-constructed system of symbols and rules we create, much of what we do in software involves invention. While the core accounting principles might be discovered, the way we implement them within a digital system is a creative act of invention. We invent abstract data structures to represent ledgers, design custom algorithms to handle intricate tax rules across different jurisdictions, or devise new abstract models for payroll processing that ensure scalability, auditability, and performance.

Example:
Consider the solution we invent for managing a large-scale accounting ledger. While debits and credits are discovered principles, the invented part is how we represent, store, and process millions of transactions efficiently in software. This involves devising custom data structures for journal entries, creating indexing strategies for rapid querying, and designing algorithms for real-time balance calculations. These aren't just paper-to-digital translations; they're new mathematical constructs and rules invented to harness computational power, ensuring consistency and performance in complex digital environments.

--------------------
The Nuance of the Dichotomy:
Some philosophers, like George Lakoff, argue that this dichotomy is too simplistic, suggesting mathematics emerges from our embodied human experience. From a software professional's perspective, this nuanced view resonates strongly. We are constantly observing and discovering the underlying mathematical nature of the problem space, recognizing the inherent patterns and constraints. Simultaneously, we are inventing abstract tools, languages, and systems, from low-level algorithms to high-level architectural patterns, to articulate, solve, and extend those problems.

🧐For Example:
The recognition of recurring problems in software led to the discovery of design patterns as effective solutions. However, the formalization and naming of these patterns, along with the rules for their application, were distinct acts of invention that codified and communicated this discovered knowledge in a reusable, mathematical way.

Our work is a continuous cycle of recognizing existing mathematical structures and then creatively constructing the digital scaffolding around them.

--------------------
Understanding this dynamic, knowing when we are accurately reflecting a discovered truth versus when we are inventing a new paradigm, is crucial for making sound design decisions, ensuring system integrity, fostering innovation, and ultimately, building effective software solutions.

- Masoud Bahrami
Forwarded from Masoud Bahrami
For a long time, I struggled with complex domains like accounting and payroll. My initial mistake🙋‍♂️? Thinking I had to invent a better double-entry bookkeeping system or a new way to handle credit/debit equality.

But DDD revealed two profound truths:

🟣 Deep Understanding is Key: The more effort I invested in truly understanding the problem domain the more clearly the right solution emerged.

🟣 Needs vs. Wants: What customers or domain experts express are often just wants. My role shifted to using these wants as clues to uncover the real underlying needs.

I realized my job wasn't to reinvent established accounting principles. Instead it was to discover their true essence and the profound ideas behind them.

At the same, for modeling and designing concepts like ledge, my primary goal was to invent the best solution for them.

A financial ledger, for instance, is far more than just a simple database table separated by year; it's a rich, living concept that demands careful, accurate representation.
3
🎯اطلاع رسانی پیش‌ثبت‌نام ورکشاپ دو‌ روزه معماری

📌‌ عنوان کارگاه: Designing Goal-Oriented Architecture
🧠‌ با تمرکز بر حل چالش‌های پیشرفته DDD Plus
📅 مدت: دو روز — ۱۶ ساعت آموزشی
👥 مناسب برای: برنامه‌نویسان، معماران نرم‌افزار، مدیران محصول و CTOها
📍 به‌صورت حضوری / ظرفیت محدود: حداکثر ۱۵ نفر

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

👇‌ اطلاعات بیشتر و ‌ثبت‌نام:
http://domaindrivendesign.ir/product/%d9%88%d8%b1%da%a9%d8%b4%d8%a7%d9%be-designing-goal-oriented-architecture-with-ddd-plus-challenges/

👇لینک مستقیم فرم پیش ثبت‌نام:
کلیک کنید
کانال مکتب‌خانه DDD
🎯‌ اطلاع رسانی پیش‌ثبت‌نام ورکشاپ دو‌ روزه معماری 📌‌ عنوان کارگاه: Designing Goal-Oriented Architecture 🧠‌ با تمرکز بر حل چالش‌های پیشرفته DDD Plus 📅 مدت: دو روز — ۱۶ ساعت آموزشی 👥 مناسب برای: برنامه‌نویسان، معماران نرم‌افزار، مدیران محصول و CTOها 📍 به‌صورت…
صبح همگی عزیزان بخیر🌱

ظرفیت پیش‌ثبت‌نام کارگاه Designing Goal-Oriented Architecture در کمتر از یک روز تکمیل شد! از استقبال شما سپاسگزاریم.❤️ 🙏

به زودی با عزیزانی که موفق به ثبت‌نام شدن تماس می‌گیریم تا مرحله بعدی رو تکمیل کنیم.

برای دوستانی هم که جا موندن: داریم بررسی می‌کنیم که بتونیم ظرفیت رو یه کوچولو بیشتر کنیم! اگه شد، همین‌جا اطلاع می‌دیم 💬👀
Forwarded from Masoud Bahrami
🚀 Need advanced date/time manipulation in .NET?

I'm excited to announce the release of Quantum.Tempo v1.0.0, a powerful, calendar-agnostic date/time framework for .NET!

🔹 Intuitive string-based API for dates, times, intervals, and durations
🔹 Supports multiple calendars: Gregorian, Persian (Shamsi), Hijri, and custom
🔹 Recurrence rules (RRULE), interval algebra, fuzzy date parsing, and timezone support
🔹 Comes with a handy REPL CLI for interactive exploration
🔹 Fully ISO-compliant and localization-ready


Check it out on NuGet:
👉 https://www.nuget.org/packages/Quantum.Tempo/

🌟 Try it, contribute, and let's make date/time handling in .NET simpler and smarter!