C# Geeks (.NET)
413 subscribers
152 photos
4 videos
152 links
Download Telegram
Forwarded from thisisnabi.dev [Farsi]
This media is not supported in your browser
VIEW IN TELEGRAM
احتمالا همه تون این پست هایی مصاحبه کننده سوال میکند فلان رو دیده باشید‌
سوالات خیلی سطحی و یک خطی که احتمالا در جای درست و حسابی هم از شما پرسیده نمیشه.

جدای از اینکه خوب هست یا بد، نگاه من اینه که در مصاحبه جزئیات رو از سوال کننده بخواید، خیلی از تصمیم ها بخاطر یک جزئیات کوچک می توانند رد بشن.

در کنار این پرداختن به جزییات سطح آگاهی شما رو به تصویر میکشه.

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

@thisisnabi_dev
یکی از اشتباه‌ ترین تصور هایی که اوایل مسیر داشتم این بود که فکر می‌کردم هر مسئله‌ای باید یک راه‌ حل درست داشته باشد.
یک جواب.
یک تصمیم صحیح.
یک انتخاب واضح.
اما هرچه بیشتر در پروژه‌ های واقعی کار کردم، بیشتر فهمیدم که بسیاری از تصمیم‌ های مهندسی این‌ گونه نیستند.
مثلاً:
آیا باید Monolith بمانیم یا به سمت Microservice برویم؟
آیا باید Cache اضافه کنیم؟
آیا باید سیستم را Rewrite کنیم؟
آیا باید این Feature را Generic طراحی کنیم؟

جالب است که برای همه این سوال‌ ها می‌توان مثال‌ هایی پیدا کرد که پاسخ «بله» درست باشد.
و مثال‌ هایی که پاسخ «خیر» درست باشد.
همان‌ جا بود که فهمیدم بخش بزرگی از مهندسی نرم‌ افزار، پیدا کردن پاسخ درست نیست.فهمیدن سوال درست است.
چون خیلی وقت‌ ها قبل از اینکه راه‌ حل اشتباهی انتخاب کنیم،
در حال حل کردن مسئله اشتباهی هستیم.
ساعت‌ ها روی Performance کار می‌کنیم، در حالی که گلوگاه اصلی جای دیگری است.
معماری را پیچیده می‌کنیم، در حالی که مشکل واقعی فرآیند های تیم است.
سیستم را Scale می‌کنیم، در حالی که مسئله از یک Query اشتباه شروع شده است.
شاید به همین دلیل است که مهندسان باتجربه، معمولاً زودتر از بقیه راه‌ حل ارائه نمی‌دهند.
آن‌ها مدت بیشتری روی فهمیدن مسئله وقت می‌گذارند.
چون می‌دانند انتخاب بهترین راه‌ حل برای یک مسئله اشتباه،
هنوز هم یک اشتباه است.
The best abstraction is the one you don't have to write. 😉☕️
یکی از اشتباهاتی که در بسیاری از پروژه‌های NET. دیده می‌شود، استفاده از "throw" برای خطاهای قابل انتظار (Expected Errors) است.

فرض کنید کاربر می‌خواهد سفارشی ثبت کند، اما موجودی کالا کافی نیست.

این یک Exception نیست:
throw new OutOfStockException();

این یک نتیجه‌ی قابل انتظار از منطق کسب‌وکار است:
return Result.Failure(Errors.Product.OutOfStock);

چرا؟
🔹 ساختن Exception شامل ایجاد Stack Trace است که هزینه‌ی CPU و حافظه دارد.
🔹 پرتاب و Catch کردن Exception مسیر اجرای برنامه را کندتر می‌کند.
🔹 درواقع Exception برای اتفاقات غیرمنتظره طراحی شده است، نه اعتبارسنجی قوانین کسب‌وکار.

قاعده‌ای که همیشه از آن استفاده می‌کنیم:
Expected Error → "Result"


• موجودی کافی نیست.
• کاربر پیدا نشد.
• اعتبارسنجی ناموفق بود.
• سفارش قبلاً پرداخت شده است.

Unexpected Error → "throw"


• قطع شدن Database
• خطای شبکه
• باگ برنامه
• شرایطی که هرگز نباید رخ دهند

به این ترتیب:
✔️ کد خواناتر می‌شود.
✔️ جریان اجرای برنامه شفاف‌تر است.
✔️ از هزینه‌ی غیرضروری Exceptionها جلوگیری می‌شود.
✔️ و Performance در سناریوهای پرتکرار بهتر خواهد بود.

پس Result برای کنترل جریان عادی برنامه است و Exception برای شرایط استثنایی.
نرم‌افزار هیچ‌وقت «تمام‌شده» نیست. و دقیقاً به همین دلیل است که باید در مسیر، موفقیت‌های کوچک را جشن گرفت.

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

من دیده‌ام افرادی که اجازه داده‌اند یک یا دو سال از زندگی کاری‌شان در یک حالت کاریِ بی‌وقفه و فرسایشی محو شود و آن را «طبیعی» بنامند. خودم هم این را تجربه کرده‌ام. یک روز نگاه می‌کنی و می‌بینی بخش بزرگی از مسیر شغلی‌ات گذشته، بدون اینکه حتی لحظه‌ای توقف کرده باشی تا احساس خوبی نسبت به آن داشته باشی.

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

کار قرار نیست متوقف شود تا به تو تبریک بگوید. پس این کار را باید خودت برای خودت بسازی.
🚫 چه زمانی نباید از Design Patternها استفاده کنیم؟

یکی از بزرگ‌ترین اشتباهات برنامه‌نویس‌ها این است که فکر می‌کنند هر مسئله‌ای باید با یک Design Pattern حل شود.
در حالی که بسیاری از Patternها برای حل مشکلات پیچیده طراحی شده‌اند، نه برای پیچیده‌تر کردن کدهای ساده.
گاهی یک متد ساده یا یک if دقیقاً همان چیزی است که نیاز دارید. 👇
1️⃣ Adapter

زیاده‌روی است وقتی:
فقط قرار است یک یا دو نوع داده را تبدیل (Map) کنید.
به‌جای آن:
یک Mapper ساده یا Helper Method بنویسید.

2️⃣ Decorator

زیاده‌روی است وقتی:
فقط می‌خواهید یک Validation یا Log ساده اضافه کنید.
به‌جای آن:
از Pipeline، Middleware یا حتی منطق مستقیم استفاده کنید.

3️⃣ Facade

زیاده‌روی است وقتی:
زیرسیستم شما API واضح و ساده‌ای دارد.
به‌جای آن:
مستقیماً همان Service را فراخوانی کنید.

4️⃣ Abstract Factory

زیاده‌روی است وقتی:
فقط یک یا دو نوع شیء می‌سازید.
به‌جای آن:
از Constructor یا Factory Method ساده استفاده کنید.

5️⃣ Strategy

زیاده‌روی است وقتی:
رفتار فقط چند حالت ساده دارد.
به‌جای آن:
یک if/else یا switch کاملاً کافی است.

6️⃣ Builder

زیاده‌روی است وقتی:
شیء فقط چند Property اختیاری دارد.
به‌جای آن:
از Object Initializer یا پارامترهای Optional استفاده کنید.

7️⃣ Factory Method

زیاده‌روی است وقتی:
منطق ساخت شیء بسیار ساده است.
به‌جای آن:
از new یا یک Helper استفاده کنید.

8️⃣ Chain of Responsibility

زیاده‌روی است وقتی:
جریان اجرای شما کوتاه و ثابت است.
به‌جای آن:
یک Pipeline ساده از متدها بسازید.

9️⃣ Template Method

زیاده‌روی است وقتی:
فقط بخش کوچکی از الگوریتم تغییر می‌کند.
به‌جای آن:
از Delegate یا یک متد مشترک استفاده کنید.

🔟 Bridge

زیاده‌روی است وقتی:
فقط یک بُعد تغییر در سیستم دارید.
به‌جای آن:
ءComposition یا یک Interface ساده کافی است.

1️⃣1️⃣ Command

زیاده‌روی است وقتی:
عملیات ساده هستند و نیازی به Queue، Undo یا Retry ندارند.
به‌جای آن:
مستقیماً متد موردنظر را صدا بزنید.

1️⃣2️⃣ State

زیاده‌روی است وقتی:
فقط چند State ساده دارید.
به‌جای آن:
یک enum همراه با switch استفاده کنید.

1️⃣3️⃣ Proxy

زیاده‌روی است وقتی:
فقط یک Wrapper کوچک نیاز دارید.
به‌جای آن:
یک Helper یا Wrapper ساده بنویسید.

1️⃣4️⃣ Observer

زیاده‌روی است وقتی:
فقط یک یا دو Receiver دارید.
به‌جای آن:
از Callback یا فراخوانی مستقیم متد استفاده کنید.

1️⃣5️⃣ Composite

زیاده‌روی است وقتی:
قرار نیست با Itemها و Groupها رفتار یکسانی داشته باشید.
به‌جای آن:
منطق List و Item را جدا نگه دارید.

1️⃣6️⃣ Visitor

زیاده‌روی است وقتی:
مدل دائماً تغییر می‌کند و تعداد عملیات کم است.
به‌جای آن:
ءPattern Matching یا switch انتخاب بهتری است.

1️⃣7️⃣ Prototype

زیاده‌روی است وقتی:
کپی گرفتن از اشیاء ساده است.
به‌جای آن:
از Copy Constructor یا Mapper استفاده کنید.

1️⃣8️⃣ Flyweight

زیاده‌روی است وقتی:
مصرف حافظه مشکل اصلی سیستم نیست.
به‌جای آن:
از Objectهای معمولی و Cache هدفمند استفاده کنید.

1️⃣9️⃣ Interpreter

زیاده‌روی است وقتی:
قوانین سیستم کم و ثابت هستند.
به‌جای آن:
از Parser ساده یا Configuration Table استفاده کنید.

2️⃣0️⃣ Singleton

زیاده‌روی است وقتی:
فقط یک سرویس مشترک می‌خواهید.
به‌جای آن:
آن را به‌صورت Singleton در DI Container ثبت کنید، نه اینکه الگوی Singleton را پیاده‌سازی کنید.

2️⃣1️⃣ Mediator

زیاده‌روی است وقتی:
فقط چند سرویس محدود با هم تعامل دارند.
به‌جای آن:
از فراخوانی مستقیم Service به Service استفاده کنید.

🎯 جمع بندی

ءDesign Patternها ابزار هستند، نه هدف.
بهترین معماری، معماری‌ای نیست که بیشترین Pattern را داشته باشد؛ بلکه معماری‌ای است که ساده‌ترین راه‌حل ممکن را برای مسئله‌ی واقعی انتخاب کند.
همان‌طور که Martin Fowler می‌گوید:
"Any fool can write code that a computer can understand. Good programmers write code that humans can understand." 💡
گاهی بهترین Pattern، استفاده نکردن از Pattern است. 😉
تا حالا دقت کرده‌ای چرا بعضی کتابخانه‌ها این‌قدر آرام هستند؟
نه به خاطر اینکه کسی آنجا کتاب نمی‌خواند.
به خاطر اینکه هر کتاب، جای مشخصی دارد.
اگر دنبال کتابی باشی، لازم نیست از ده نفر سؤال بپرسی.
لازم نیست حدس بزنی کدام قفسه مناسب است.
همه چیز بر اساس یک نظم مشخص پیدا می‌شود.
حالا یک پروژه نرم‌افزاری را تصور کن که بعد از چند سال توسعه، هر کلاس می‌تواند هر چیزی را صدا بزند.
هر ماژول به هر ماژول دیگری وابسته است.
برای تغییر یک قابلیت ساده، باید پنج بخش مختلف را بررسی کنی.
پروژه هنوز کار می‌کند.
اما دیگر شبیه کتابخانه نیست.
بیشتر شبیه انباری است.
انباری که همه چیز داخل آن هست.
اما پیدا کردن هر چیزی، زمان می‌برد.
جالب اینجاست که هیچ پروژه‌ای از روز اول انباری نبوده است.
فقط هر بار یک وابستگی کوچک اضافه شده.
یک میانبر دیگر.
یک دسترسی مستقیم دیگر.
تا جایی که مرزها از بین رفته‌اند.
در مهندسی نرم‌افزار،معماری فقط برای این نیست که سیستم امروز کار کند.
برای این است که شش ماه بعد،هنوز بدانی هر چیز دقیقاً باید کجا باشد.
#مهندس_فکر_کن
قسمت:4️⃣

🎯مصاحبه‌کننده:
ءCache Stampede چیست؟
فرض کن یک کلید در Cache داری:
Product:123

و TTL آن 5 دقیقه است.
در لحظه‌ای که این کلید منقضی می‌شود، همزمان 5000 درخواست برای همان محصول می‌آید.
اتفاقی که می‌افتد:
Client 1 ----\
Client 2 -----\
Client 3 -------> Cache Miss
Client 4 -----/
Client 5 ----/
...
5000 Requests

همه همزمان Cache Miss می‌خورند.
سپس همه به Database می‌روند.
5000 Query

Database

در نتیجه Database Overload، افزایش شدید Latency ،احتمال Down شدن سرویس.
به این حالت Cache Stampede می‌گویند.

حالا بگو ببینم برای حل این مشکل چه راهکار هایی میدی؟🤔
"صرفا فقط برای اینکه لیبل خارج خورده روش"😑
Forwarded from Learning With M
This media is not supported in your browser
VIEW IN TELEGRAM
دستور مصرف: هر صبح، حداقل یک بار بلافاصله بعد از بیدار شدن از خواب

پ.ن: الان تو کدوم ظرف برنجیم؟
یا شاید ظرف ها؟
Forwarded from thisisnabi.dev [Farsi]
کتاب خوب بخونیم.

این کتابه کمی گم هست و کم دیدم در موردش صحبت کنن، ولی واقعا کتاب خوبی هست. دیشب توی میت های 10x developer معرفیش کردم، گفتم اینجا هم برای شما هم بذارمش شاید کسی علاقه داشت بخوندش.

کلا این سری کتاب های pragmatic خیلی ارزش خوندن دارن و نگاه آدم رو نسبت به موضوعی که قرار هست مطرح کنن، تغییر می دن.

@thisisnabi_dev
گاهی فکر می‌کنیم دلیل اینکه یک توسعه‌دهنده بعد از چند سال بهتر می‌شود، این است که تکنولوژی‌های بیشتری یاد گرفته است.
اما همیشه این‌طور نیست.یک اتفاق مهم‌تر هم می‌افتد.
کم‌کم یاد می‌گیرد به هر مشکلی جواب ندهد.
اوایل مسیر، وقتی یک مشکل می‌بینی، اولین واکنش این است:
«باید سریع یک راه‌حل پیدا کنم.»
اما بعد از چند سال، واکنش تغییر می‌کند.
اول می‌پرسی:
«اصلاً مطمئنیم این همان مسئله‌ای است که باید حل شود؟»
جالب است که در خیلی از پروژه‌ها، ساعت‌ها صرف حل کردن مسئله‌ای می‌شود که از ابتدا، مسئله اصلی نبوده است.
ءQuery را بهینه می‌کنیم.بعد می‌فهمیم گلوگاه، شبکه بوده است.
ءCaching اضافه می‌کنیم.بعد مشخص می‌شود مشکل از طراحی درخواست‌ها بوده است.
ءService جدید می‌نویسیم.بعد می‌بینیم با حذف یک وابستگی، کل مسئله حل می‌شد.
به مرور متوجه می‌شوی ارزش یک مهندس، فقط به تعداد راه‌حل‌هایی که بلد است نیست.
به تعداد مسئله‌هایی است که قبل از شروع، درست تشخیص می‌دهد. چون در مهندسی نرم‌افزار،اشتباه‌ترین جواب، جواب اشتباه به یک سؤال درست نیست.
جواب کاملاً درست به یک سؤال اشتباه است.
کانال یک برنامه نویس تنبل

🔥لینوکس
🔥برنامه نویسی فرانت‌اند
🔥برنامه نویسی بک‌اند
🔥اخبار تکنولوژی و...

@TheRaymondDev
در یکی از پروژه‌ ها، قرار بود یک قابلیت جدید به سیستم اضافه کنیم.
یکی از اعضای تیم گفت:
«اگر از همین الان این بخش را Generic طراحی کنیم، بعدا برای چند سناریوی دیگر هم قابل استفاده است.»
پیشنهاد جذابی بود. شروع کردیم به طراحی. Interface اضافه شد. چند لایه Abstraction ایجاد شد. تنظیمات مختلف اضافه شدند.
قابلیتی که قرار بود در دو روز آماده شود، نزدیک دو هفته زمان برد.
چند ماه بعد، برگشتیم و نگاهی به آن بخش انداختیم.
از تمام سناریو هایی که برای آینده پیش‌ بینی کرده بودیم، فقط همان سناریوی اول استفاده شده بود.
بقیه هیچ‌ وقت اتفاق نیفتادند.آن روز یک درس مهم گرفتم.
بزرگ‌ ترین خطر در طراحی نرم‌ افزار، همیشه «طراحی ضعیف» نیست.
گاهی «طراحی برای آینده‌ ای است که هنوز وجود ندارد.»
از آن به بعد، هر وقت وسوسه میشوم چیزی را بیش از نیاز امروز Generalize کنم، از خودم یک سوال میپرسم:
«اگر این نیاز هیچ‌ وقت به وجود نیاید، آیا باز هم حاضر بودم هزینه امروز را پرداخت کنم؟»
خیلی وقت‌ها جواب، «نه» است.
و همان «نه»، باعث میشود سیستم ساده‌ تر بماند.
چون تجربه به من یاد داد که آینده، همیشه آن‌طور که ما طراحی میکنیم پیش نمیرود.
اما پیچیدگی‌ ای که امروز وارد سیستم میکنیم، همین امروز شروع به گرفتن هزینه میکند.
📚 مسیر یادگیری یک برنامه‌نویس NET. در هر سطح

بیشتر توسعه‌دهنده‌ها نمی‌دانند در هر مرحله از مسیر حرفه‌ای خود باید روی چه موضوعاتی تمرکز کنند. به همین دلیل ممکن است سال‌ها تجربه داشته باشند، اما هنوز برای موقعیت‌های Senior یا Architect آماده نباشند.

اگر بخواهم مسیر یادگیری یک برنامه‌نویس NET. را به چهار مرحله تقسیم کنم، این نقشه راه را پیشنهاد می‌دهم:
1️⃣ Junior Developer

در این مرحله هدف، یادگیری اصول برنامه‌نویسی و ساخت پروژه‌های واقعی است.

C# Syntax, Types & OOP
Collections & Basic LINQ
Async/Await Basics
Exception Handling
Building Basic APIs with Controllers & EF Core
Configuration with appsettings.json
Git Basics & IDE Debugging

2️⃣ Middle Developer

در این مرحله دیگر فقط کدنویسی مهم نیست؛ باید یاد بگیرید چرا یک راه‌حل از راه‌حل دیگر بهتر است.

Advanced LINQ, IQueryable vs IEnumerable
Async/Await, CancellationToken & Deadlocks
EF Core Migrations, Relationships & Query Performance
SOLID Principles & Common Design Patterns
Clean Architecture & Layered Architecture
Authentication & Authorization
Middleware, Filters & Model Binding
Validation, Mapping & Dependency Injection
Scheduling & Caching
Structured Logging
Integration Testing
Docker & Containerization

3️⃣ Senior Developer

در این سطح تمرکز روی طراحی سیستم‌های قابل اعتماد، مقیاس‌پذیر و قابل نگهداری است.

Performance, Memory & Allocation Profiling
Concurrency, Threading & Thread Safety
Distributed Systems Fundamentals
RabbitMQ, Kafka & Azure Service Bus
Resilience with Polly (Retry & Circuit Breaker)
OpenTelemetry (Metrics, Tracing & Observability)
CQRS & Event-Driven Architecture
Database Transactions & Concurrency Control
Security Best Practices (OWASP & Secret Management)
CI/CD Pipelines & Cloud Deployment
Domain Modeling & DDD Tactical Patterns
Code Review & Mentoring
Trade-off Analysis & Technology Selection
Modular Monolith & Service Boundaries

4️⃣ Software Architect

در این مرحله دیگر مسئله فقط نوشتن کد نیست؛ بلکه طراحی سیستم‌هایی است که سال‌ها قابل توسعه و نگهداری باشند.
System Design (Scalability, Availability & Reliability)
Monolith vs Modular Monolith vs Microservices vs Serverless
Strategic DDD (Bounded Context & Context Mapping)
Consistency, Idempotency & Saga Pattern
Data Architecture, Event Sourcing & Polyglot Persistence
CAP Theorem & PACELC Trade-offs
Zero Trust Security & Identity
Non-Functional Requirements (NFRs) & Quality Attributes
ADRs (Architecture Decision Records) & C4 Model
Migration & Modernization Strategy
Standards, Guardrails & Governance
Business-Driven Architecture
Conway's Law & Team Topologies
Stakeholder Communication & Trade-off Analysis
Cloud Cost Optimization
Platform Engineering & Developer Experience (DevEx)
Disaster Recovery & Business Continuity
Multi-Tenancy & Data Isolation Patterns

🎯 نکته مهم

این مسیر یک نردبان نیست که بعد از رسیدن به مرحله بعدی، مطالب قبلی را کنار بگذارید.
هرچه جلوتر می‌روید، عمق دانشتان در موضوعات قبلی بیشتر می‌شود و مفاهیم جدیدی به آن اضافه می‌کنید.
یک Architect خوب، هنوز هم #C را عمیق می‌شناسد؛ فقط نگاهش از «نوشتن کد» به «طراحی سیستم» تغییر کرده است.