C# Geeks (.NET)
413 subscribers
152 photos
4 videos
153 links
Download Telegram
#مهندس_فکر_کن
قسمت:1️⃣
🎯 سوال مصاحبه مهندسی نرم‌افزار

فرض کنید یک سرویس ASP.NET Core دارید که پیام‌ها را از Kafka دریافت می‌کند.
پیام دریافت می‌شود.Business Logic اجرا می‌شود.
داده در Database ذخیره می‌شود.
اما درست قبل از Commit Offset سرویس Crash می‌کند.
پس از Restart شدن سرویس، همان پیام دوباره پردازش می‌شود.
سؤال:
چگونه از ثبت دوباره اطلاعات جلوگیری می‌کنید؟
Forwarded from مسعود بیگی (مسعود بیگی)
چرا هر تیم نرم‌افزاری باید Runbook داشته باشه؟ سلام دوستان، تو دنیای امروز که سیستم‌ها ۲۴/۷ کار می‌کنن، Runbook دیگه لوکس نیست، یه ضرورت هست.Runbook چیه؟سند زنده‌ای که دقیقاً می‌گه:وقتی مشکلی پیش اومد چیکار کنیم؟ (Step-by-step)
وابستگی‌های سیستم چیا هستن؟
چک‌لیست‌های روزانه، هفتگی و ماهانه
راه‌حل‌های رایج خطاها و Incidentها
اطلاعات تماس افراد کلیدی و Escalation Path
حتی به تیم های مرتبط میگه endpoint هامون چین و ورودی خروجی های مورد انتظارش چیه


اهمیت Runbook برای تیم‌های نرم‌افزاری:کاهش چشمگیر زمان Downtime
وقتی Incident اتفاق می‌افته، دیگه کسی سردرگم نیست که "اول کجا رو چک کنیم؟" تیم تو کمتر از ۵ دقیقه وارد Action می‌شه.
کاهش وابستگی به افراد خاص
یکی از اعضای کلیدی تیم مرخصی باشه یا شرکت رو ترک کنه، دانش از دست نمی‌ره.
Onboarding خیلی سریع‌تر
developer یا SRE جدید تو همون هفته اول می‌تونه Incidentهای سطح متوسط رو هندل کنه.
Consistency در عملیات
همه اعضای تیم به یک روش استاندارد عمل می‌کنن، نه هر کسی به سلیقه خودش.
بهبود کیفیت و آرامش خاطر
وقتی بدونید همه چیز مستند شده، خواب راحت‌تری دارید!

تجربه واقعی:تیم‌هایی که Runbook خوب دارن، MTTR (Mean Time To Recovery) شون رو تا ۵۰-۷۰٪ کاهش دادن.پیشنهاد من:
همین امروز یه Runbook اولیه برای مهم‌ترین سرویس‌هاتون بسازید. حتی اگه ناقص باشه، بهتر از هیچی هست. بعد به مرور کاملش کنید.از ابزارهایی مثل Notion، Confluence، Markdown تو GitHub یا GitLab Wiki می‌تونید استفاده کنید.شما Runbook دارید؟
تو کامنت بگید تیم‌تون چقدر به مستندات عملیاتی اهمیت می‌ده؟ #DevOps #SRE #Runbook #SiteReliability #SoftwareEngineering #تیم_فنی
چند سال پیش از یکی از مدیران فنی سؤال کردم:
«چطور می‌فهمی یک تصمیم معماری خوب بوده یا نه؟»
فکر می‌کردم قرار است درباره Performance، Scalability یا Availability صحبت کند.
اما جوابش چیز دیگری بود.
گفت:
«ببین چند ماه بعد، تغییر دادن آن تصمیم چقدر درد دارد.»
آن زمان خیلی متوجه منظورش نشدم.
اما هرچه بیشتر روی سیستم‌های واقعی کار کردم، بیشتر به عمق این جمله پی بردم.
بیشتر تصمیم‌های معماری، روزی که گرفته می‌شوند عالی به نظر می‌رسند.
مشکل زمانی شروع می‌شود که نیازمندی‌ها تغییر می‌کنند.
کسب‌وکار مسیر جدیدی می‌رود.
تیم بزرگ‌تر می‌شود.
یا حجم کاربران چند برابر می‌شود.
اینجاست که کیفیت واقعی تصمیم‌ها مشخص می‌شود.
چون بعضی تصمیم‌ها فقط برای امروز بهینه هستند.
و بعضی دیگر، تغییرات آینده را هم در نظر گرفته‌اند.
جالب است که انعطاف‌پذیری یک سیستم را معمولاً از روی چیزهایی که می‌تواند انجام دهد نمی‌سنجند.
از روی چیزهایی می‌سنجند که می‌تواند تغییر دهد.
شاید به همین دلیل باشد که مهندسی نرم‌افزار کمتر درباره پیش‌بینی آینده است.
و بیشتر درباره آماده بودن برای آینده‌ای است که نمی‌توانی پیش‌بینی‌اش کنی.
در نهایت، ارزش یک طراحی خوب فقط در این نیست که امروز جواب می‌دهد.
در این است که فردا هم بتوانی با آن زندگی کنی.
#مهندس_فکر_کن
قسمت:2️⃣

🎯 مصاحبه‌کننده:
فرض کنید یک سیستم Microservice دارید.
سرویس A یک سفارش ثبت می‌کند.
سرویس B پرداخت را انجام می‌دهد.
سرویس C موجودی انبار را کم می‌کند.
سرویس D پیامک ارسال می‌کند.
در میانه کار، پرداخت موفق انجام می‌شود اما سرویس انبار از دسترس خارج می‌شود.

سؤال:
آیا باید یک Transaction سراسری تعریف کنیم تا اگر یکی از سرویس‌ها شکست خورد، همه چیز Rollback شود؟دلیل؟
Forwarded from .NET Internals
امروز تو شرکت داشتم با یکی از بچه ها درمورد نظریه پنجره شکسته صحبت میکردیم.

ChatGPT:

Broken Window Theory (نظریه پنجره شکسته)
در برنامه‌نویسی یعنی:

اگر یک مشکل کوچک، کد بد یا باگ جزئی را نادیده بگیریم، کم‌کم افراد بیشتری هم بی‌نظمی را عادی می‌بینند و کیفیت کل پروژه افت می‌کند.

مثال:

* یک فایل پر از کامنت‌های قدیمی و بی‌استفاده است.
* یک تابع اسم نامناسبی دارد.
* چند خط کد تکراری وجود دارد.

اگر این موارد اصلاح نشوند، برنامه‌نویس‌های بعدی هم با خیال راحت کدهای نامرتب بیشتری اضافه می‌کنند. بعد از مدتی پروژه پر از «بدهی فنی» (Technical Debt) می‌شود و نگهداری آن سخت خواهد شد.

🔹 اسم این نظریه از یک مثال شهری آمده: اگر پنجره یک ساختمان شکسته باشد و تعمیر نشود، افراد تصور می‌کنند کسی به آنجا اهمیت نمی‌دهد و خرابکاری‌های بیشتری رخ می‌دهد.

پیام اصلی برای برنامه‌نویس‌ها:

> مشکلات کوچک را زود برطرف کن؛ نگذار کد نامرتب و خراب به حالت عادی تبدیل شود.

به همین دلیل تیم‌های حرفه‌ای معمولاً:

* باگ‌های کوچک را سریع رفع می‌کنند.
* کد را مرتب و خوانا نگه می‌دارند.
* قبل از Merge شدن، Code Review انجام می‌دهند.
* تست‌ها را خراب رها نمی‌کنند.

خلاصه: یک «پنجره شکسته» در کد، اگر تعمیر نشود، می‌تواند کل پروژه را به‌تدریج به هم بریزد. 🚪🔧💻

---------------
کوتاهش اینه که باید حس مسولیت پذیری داشته باشید اگر میبینید کدی خرابه یا یه جایی درست نیست ازش رد نشید و بگید این کد رو من نزدم با لید خودتون درمیون بذارید و حلش کنید یا حداقل دلیلشو بپرسید.
در یکی از پروژه‌ها، یک توسعه‌دهنده جدید به تیم اضافه شده بود.
چند هفته بعد از شروع کارش، در یکی از جلسات گفت:
«چرا این بخش سیستم اینقدر پیچیده طراحی شده؟»
چند نفر از اعضای قدیمی تیم لبخند زدند.
یکی از آن‌ها گفت:
«چون تو هنوز داستانش رو نمی‌دونی.»
و واقعاً همین‌طور بود.پشت آن طراحی عجیب، چند سال تصمیم‌گیری، محدودیت، شکست، تغییر نیازمندی و تجربه پنهان شده بود.
اتفاق جالبی که بارها در پروژه‌ها دیده‌ام این است که ما معمولاً فقط نتیجه تصمیم‌ها را می‌بینیم.
نه شرایطی که آن تصمیم‌ها در آن گرفته شده‌اند.
برای همین گاهی قضاوت کردن خیلی آسان به نظر می‌رسد.
«من بودم اینطوری طراحی نمی‌کردم.»
«این معماری اشتباهه.»
«این کد باید از اول نوشته بشه.»
اما حقیقت این است که بیشتر سیستم‌ها در شرایط ایده‌آل ساخته نمی‌شوند.
در محدودیت زمان ساخته می‌شوند.
در محدودیت بودجه.
در فشار کسب‌وکار.
در شرایطی که اطلاعات کامل در دسترس نیست.
و شاید یکی از نشانه‌های بلوغ حرفه‌ای این باشد که قبل از قضاوت یک تصمیم، سعی کنیم زمینه شکل‌گیری آن را بفهمیم.
نه برای اینکه از هر تصمیمی دفاع کنیم.
برای اینکه بدانیم طراحی سیستم‌ها را فقط با نگاه کردن به کد نمی‌شود ارزیابی کرد.
باید داستان پشت آن کد را هم فهمید.
چون خیلی وقت‌ها چیزی که امروز اشتباه به نظر می‌رسد،
دیروز بهترین تصمیم ممکن بوده است.
Forwarded from tech-afternoon (Amin Mesbahi)
کوییز:

توی سیستم‌های توزیع‌شده، مخصوصا وقتی چند سرویس به واسطه پیام‌ها، eventها یا APIها با هم sync می‌شن، Reconciliation Job بیشتر برای چه کاری استفاده می‌شه؟
Final Results
13%
جایگزین کردن Message Broker با یک batch job
22%
تضمین exactly-once delivery بین همه سرویس‌ها
57%
مقایسه دوره‌ای وضعیت چند سیستم و پیدا کردن یا اصلاح مغایرت‌ها
5%
حذف نیاز به Outbox/Inbox Pattern
3%
افزایش سرعت response time در APIهای synchronous
Forwarded from .NET Fun
Media is too big
VIEW IN TELEGRAM
سال‌ها منتظرش بودیم؛ Union Types بالاخره به C# آمدند، اما...


@DotNetIsFun
🚀 یک Junior Developer باید ۵ الگوی معماری را بداند
⚙️ یک Middle Developer باید ۸ الگوی معماری را بداند
🏗 یک Senior Developer باید ۲۰ الگوی معماری را بداند

👉 Junior Developer 👨‍💻

در این مرحله، الگوها به شما کمک می‌کنند ساختار و جریان سیستم را درک کنید. 📚
1️⃣ Layered Architecture
🎨 UI → 🧠 Application → 📦 Domain → 🔧 Infrastructure
تفکیک شفاف مسئولیت‌ها.

2️⃣ Client–Server
🌐 Frontend در مقابل Backend
🔌 APIها به عنوان قرارداد
📨 درخواست‌های Stateless

3️⃣ Monolith
📦 یک واحد قابل استقرار
🛠 ساده برای توسعه، دیباگ و درک
بهترین انتخاب پیش‌فرض

4️⃣ Basic CRUD Architecture
Create
📖 Read
✏️ Update
Delete
پایه و اساس اکثر سیستم‌های کسب‌وکار.

5️⃣ Synchronous Request–Response
🔄 ارتباط ساده مبتنی بر HTTP
🔍 ردیابی و دیباگ آسان

👉 Middle Developer 👨‍💻

درک کنید که سیستم‌ها چگونه ساختاربندی و به یکدیگر متصل می‌شوند. 🏗

1️⃣ Modular Monolith
📦 مرزبندی شفاف درون یک Deployable
🧩 ماژول‌های مستقل بدون پیچیدگی سیستم‌های توزیع‌شده

2️⃣ API Gateway
🚪 نقطه ورود واحد برای کلاینت‌ها
🔀 Routing
🔐 Authentication
⏱️ Rate Limiting
📊 Aggregation
3️⃣ CQRS (Command Query Responsibility Segregation)
✍️ جداسازی مدل‌های خواندن و نوشتن
📈 بهبود Performance و Scalability در صورت نیاز واقعی

4️⃣ Event-Driven Architecture
📨 ارتباط ناهمگام (Asynchronous)
🔗 ءCoupling کمتر بین اجزا

5️⃣ Publish / Subscribe
📢 تولیدکننده‌ها مصرف‌کننده‌ها را نمی‌شناسند
📡 مناسب برای سناریوهای Fan-Out

6️⃣ Point-to-Point Async Integration
📬 صف‌ها بین سرویس‌ها
تحویل قابل اعتماد پیام‌ها

7️⃣ Outbox Pattern
📦 تضمین ارسال پیام همراه با سازگاری پایگاه داده
🚫 جلوگیری از مشکل Dual-Write

8️⃣ Replication Pattern
📖 ءRead Replica برای مقیاس‌پذیری خواندن
🟢 افزایش Availability

👉 Senior Developer 👨‍💻

در این سطح، سیستم‌هایی طراحی می‌کنید که در مقیاس بزرگ و تحت بار واقعی دوام بیاورند. 🚀
در اینجا معماری دیگر فقط درباره Patternها نیست؛
بلکه درباره Trade-offها و پیامدهای هر تصمیم است. ⚖️

1️⃣ Saga Pattern
🔄 مدیریت تراکنش‌های توزیع‌شده
🩹 جبران خطا (Compensation) به جای Rollback

2️⃣ Anti-Corruption Layer (ACL)
🛡 محافظت از Domain در برابر سیستم‌های خارجی
🚫 جلوگیری از آلودگی مدل دامنه

3️⃣ Strangler Fig Pattern
🌱 مدرن‌سازی تدریجی
🔄 جایگزینی امن سیستم‌های Legacy

4️⃣ Sidecar Pattern
📦 مدیریت Cross-Cutting Concernها خارج از Business Logic
📈 Observability
🔐 Security
🛡 Resilience
5️⃣ Service Discovery Pattern
📍 کشف پویا محل سرویس‌ها
⚙️ ضروری در مقیاس بزرگ

6️⃣ Sharding Pattern
🗂 تقسیم داده‌ها برای افزایش مقیاس‌پذیری نوشتن
⚠️ پیچیده اما قدرتمند

7️⃣ Replication + Sharding Trade-offs
⚖️ Consistency در برابر Availability
⚡️ Latency در برابر Correctness

8️⃣ چه زمانی نباید از یک Pattern استفاده کرد؟
Microservices خیلی زود
CQRS بدون نیاز واقعی
Eventها بدون Observability

9️⃣ مسیر تکامل سیستم‌ها
📦 Monolith
➡️ Modular Monolith
➡️ Microservices
🚀 تغییرات تدریجی، نه بازنویسی‌های بزرگ
💡 دانستن Patternها شما را Senior نمی‌کند.

ءSenior بودن یعنی بدانید:
چه زمانی از یک Pattern استفاده کنید.
چه زمانی از آن استفاده نکنید.
و هزینه هر تصمیم معماری را قبل از پرداختن آن بشناسید.
در یکی از پروژه‌ها یک تصمیم کوچک گرفتیم:
برای افزایش سرعت توسعه، Validationها را از سمت Backend به Frontend منتقل کنیم.
در لحظه همه چیز منطقی بود.UI سریع‌تر بازخورد می‌داد.API ساده‌تر شد.تیم Frontend هم راضی بود.
اما چند ماه بعد، همان تصمیم کوچک خودش را در جای دیگری نشان داد.
چند کلاینت مختلف وجود داشت.موبایل.وب.سرویس‌های داخلی.
و هرکدام بخشی از Validation را به شکل متفاوتی پیاده‌سازی کرده بودند.
نتیجه چه شد؟
یک منطق تجاری در چند جای مختلف تکرار شد.
و هیچ‌کدام ۱۰۰٪ با دیگری هماهنگ نبود.
باگ‌هایی ظاهر می‌شد که در یک کلاینت دیده می‌شد اما در دیگری نه.
و دیباگ کردن آن‌ها به مرور سخت‌تر شد.
نکته جالب این بود که تصمیم اولیه اشتباه نبود.
در آن مقطع حتی بهترین گزینه به نظر می‌رسید.
اما فرض اصلی آن تصمیم این بود:
«یک نقطه مرکزی برای اعمال منطق وجود ندارد.»
و همین فرض بعداً تغییر کرد.
در مهندسی نرم‌افزار، بسیاری از مشکلات از جایی شروع می‌شوند که یک تصمیم کوچک بدون توجه به پیامدهای توزیع‌شده گرفته می‌شود.
چون سیستم‌ها فقط یک کدبیس نیستند.
یک اکوسیستم از کلاینت‌ها، سرویس‌ها و رفتارهای همزمان هستند.
شاید به همین دلیل است که طراحی خوب فقط درباره محل قرار گرفتن منطق نیست.
درباره این است که آن منطق در چند جا باید زندگی کند،
و چطور باید با تغییرات آینده کنار بیاید.
🔐 چرا شرکت‌های بزرگ یک Identity Provider جداگانه می‌سازند؟

اوایل پروژه همه چیز ساده است.
کاربر لاگین می‌کند، JWT می‌گیرد و تمام.
اما وقتی تعداد سرویس‌ها بیشتر می‌شود، ناگهان هر سرویس شروع می‌کند به مدیریت کاربران، نقش‌ها، دسترسی‌ها، Refresh Tokenها و Social Loginها.
همین‌جاست که مفهوم Identity Provider (IdP) وارد می‌شود.
به جای اینکه هر سرویس خودش مسئول احراز هویت باشد، یک سرویس مرکزی فقط روی Authentication و Authorization تمرکز می‌کند.
🏗 معماری سنتی
User

Service A

Database

User

Service B

Database

هر سرویس منطق احراز هویت خودش را دارد.
🏗 معماری با Identity Provider
User

Identity Provider

Access Token


┌─────────┼─────────┐
↓ ↓ ↓
Service A Service B Service C

تمام سرویس‌ها فقط اعتبار Token را بررسی می‌کنند و دیگر درگیر فرآیند Login نیستند.
مزایا
1️⃣ Single Sign-On (SSO)

کاربر یک بار وارد می‌شود و به همه سیستم‌ها دسترسی پیدا می‌کند.
2️⃣ تمرکز روی امنیت

تمام منطق امنیتی در یک نقطه قرار می‌گیرد:
• Password Policy
• MFA
• OAuth
• OpenID Connect
• Account Lockout
• Device Management
3️⃣ کاهش کد تکراری

دیگر لازم نیست هر سرویس:
• Login Endpoint
• Refresh Token Logic
• Password Reset
• Email Verification
را جداگانه پیاده‌سازی کند.
4️⃣ توسعه‌پذیری بیشتر

اضافه کردن Google Login، GitHub Login یا Azure AD فقط در IdP انجام می‌شود.
تمام سرویس‌ها به صورت خودکار از آن بهره می‌برند.
5️⃣ مدیریت متمرکز دسترسی‌ها

ءRoleها، Permissionها و Claimها در یک نقطه نگهداری می‌شوند.

معایب
1️⃣ Single Point Of Failure

اگر IdP از دسترس خارج شود، ورود کاربران مختل می‌شود.
2️⃣ پیچیدگی بیشتر

دیگر با یک پروژه ساده طرف نیستید.OAuth2، OIDC، Token Exchange و Security Flowها وارد سیستم می‌شوند.
3️⃣ نیاز به مانیتورینگ قوی

ءIdentity Provider یکی از حساس‌ترین سرویس‌های سازمان خواهد شد.
4️⃣ چالش Revocation

حذف دسترسی کاربران در معماری JWT توزیع‌شده همیشه ساده نیست.
🚀 Flow اصولی پیاده‌سازی
مرحله 1️⃣
کاربر درخواست Login ارسال می‌کند.
POST /connect/token

مرحله 2️⃣
ءIdentity Provider اعتبار کاربر را بررسی می‌کند.
مرحله 3️⃣
ءAccess Token و Refresh Token صادر می‌شود.
Access Token
Refresh Token

مرحله 4️⃣
ءClient توکن را به سرویس‌ها ارسال می‌کند.
Authorization: Bearer xxx

مرحله 5️⃣
هر سرویس فقط Signature و Claims را اعتبارسنجی می‌کند.
مرحله 6️⃣
در صورت انقضای Access Token، از Refresh Token برای دریافت Token جدید استفاده می‌شود.

📋 نکاتی که حتماً باید رعایت شوند

🔸 ءAccess Token کوتاه‌عمر باشد
(۵ تا ۱۵ دقیقه)
🔸 ءRefresh Token قابلیت Rotation داشته باشد
🔸 ءJWT Secret یا Private Key به صورت امن نگهداری شود
🔸 ءMFA برای حساب‌های حساس فعال شود
🔸 ءRate Limiting روی Endpointهای Login اعمال شود
🔸 ءAudit Log تمام عملیات امنیتی ذخیره شود
🔸 از OAuth2 و OpenID Connect استاندارد استفاده شود

⭐️ برای بهتر شدن Identity Provider چه کارهایی انجام دهیم؟
Key Rotation خودکار
MFA و Passwordless Authentication
Device Tracking
Session Management
Distributed Cache برای Token Validation
Audit Logging و Monitoring
Revocation List برای ابطال Tokenها
High Availability و Replicaهای متعدد
استفاده از OpenIddict یا Keycloak به جای ساخت همه چیز از صفر

💡 مهم‌ترین نکته:
ءIdentity Provider فقط یک سرویس Login نیست.
در سیستم‌های بزرگ، IdP به قلب امنیت کل سازمان تبدیل می‌شود.
هرچه زودتر احراز هویت را از Business Domainها جدا کنید، توسعه سرویس‌ها ساده‌تر و امنیت سیستم قابل مدیریت‌تر خواهد شد.

🔖هشتگ‌ها:
#identityserver #oauth2 #jwt #security #microservices #modularmonolith #aspnetcore
#مهندس_فکر_کن
قسمت:3️⃣

🎯مصاحبه‌کننده:
فرض کنید یک سرویس دارید که روزانه میلیون‌ها درخواست را پردازش می‌کند.
ناگهان یکی از اعضای تیم متوجه می‌شود که در بعضی شرایط نادر، دو Thread همزمان وارد یک بخش حساس از کد می‌شوند و باعث ایجاد داده ناسازگار می‌شوند.
برای حل این مشکل چه مراحلی را باید طی کرد؟
Forwarded from thisisnabi.dev [Farsi]
4. Batch Processing

من این منابع برام جذاب بوده.
1. Designing Data-Intensive Applications E2
- Storage and Retrieval [4]
- Batch Processing [11]

2. Fundamentals of Data Engineering
- Designing Good Data Architecture [3]
- Storage [6]
- Ingestion [7]


Update 1:
تعطیلات سردتون نکنه، اگر چالش های قبلی رو نرسیدید بهترین وقته برای ریبیس شدن.

@thisisnabi_dev
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 اشتباه شروع شده است.
شاید به همین دلیل است که مهندسان باتجربه، معمولاً زودتر از بقیه راه‌ حل ارائه نمی‌دهند.
آن‌ها مدت بیشتری روی فهمیدن مسئله وقت می‌گذارند.
چون می‌دانند انتخاب بهترین راه‌ حل برای یک مسئله اشتباه،
هنوز هم یک اشتباه است.