مرکز مقایسه
تفاوتهای واقعی دو فناوری، کنار هم و بدون حاشیه — تا انتخاب درست را بشناسی.
Vertical Slice Architecture در مقابل Layered (N-Tier) Architecture
در Vertical Slice Architecture کد بر اساس هر قابلیت (Feature) سازماندهی میشود و همه چیز مربوط به آن قابلیت (Controller، منطق، دسترسی به داده) در یک پوشه کنار هم قرار میگیرد، در حالی که در معماری لایهای سنتی کد بر اساس نوع فنی (Controllers، Services، Repositories) در پوشههای جداگانه سازماندهی میشود و هر قابلیت در چند لایه پخش است.
Single Responsibility Principle (SRP) در مقابل Open/Closed Principle (OCP)
SRP میگوید هر کلاس باید فقط یک دلیل برای تغییر داشته باشد، یعنی فقط یک مسئولیت مشخص را بر عهده بگیرد؛ OCP میگوید کلاسها باید برای توسعه باز و برای تغییر بسته باشند، یعنی بتوان رفتار جدید اضافه کرد بدون اینکه کد موجود و تستشده را تغییر داد.
Onion Architecture در مقابل Clean Architecture
Onion Architecture (معرفیشده توسط Jeffrey Palermo) لایهها را بهصورت حلقههای متحدالمرکز با هسته دامنه در مرکز توصیف میکند و تأکید زیادی روی Domain Services دارد، در حالی که Clean Architecture (معرفیشده توسط Robert C. Martin) نامگذاری دقیقتری برای لایه Use Cases دارد؛ در عمل هر دو بر یک اصل مشترک استوارند: وابستگیها همیشه باید به سمت مرکز (هسته دامنه) جهتگیری کنند، نه برعکس.
Modular Monolith در مقابل Microservices
Modular Monolith یک برنامه واحد است که بهصورت داخلی به ماژولهای مستقل و کاملاً مرزبندیشده تقسیم میشود اما همچنان در یک پروسه و یک Deploy واحد اجرا میشود، در حالی که Microservices این ماژولها را به سرویسهای کاملاً جدا، با پروسه، دیتابیس و Deploy مستقل از هم تبدیل میکند.
Database per Service در مقابل Shared Database
در الگوی Database per Service هر میکروسرویس دیتابیس اختصاصی خودش را دارد و هیچ سرویس دیگری مستقیماً به آن دسترسی ندارد که استقلال کامل میدهد، در حالی که در Shared Database چند سرویس از یک دیتابیس مشترک استفاده میکنند که سادهتر است اما استقلال و مرزبندی واقعی بین سرویسها را از بین میبرد.
IRequest در مقابل INotification
IRequest در MediatR یک پیام است که دقیقاً یک Handler مشخص آن را پردازش میکند و میتواند یک نتیجه هم برگرداند (مثل Command یا Query)، در حالی که INotification یک رویداد است که میتواند توسط صفر یا چند Handler مستقل و بدون بازگشت مقدار مشخص، همزمان پردازش شود.
Primary/Driving Adapters در مقابل Secondary/Driven Adapters
Primary Adapter (یا Driving Adapter) نقطهای است که از بیرون هسته برنامه را فرا میخواند، مثل یک Controller وب یا یک دستور CLI، در حالی که Secondary Adapter (یا Driven Adapter) پیادهسازی چیزی است که خود هسته برنامه به آن نیاز دارد و آن را فرا میخواند، مثل یک Repository که به دیتابیس متصل میشود.
Validate() (همزمان) در مقابل ValidateAsync() (ناهمزمان)
Validate() تمام قوانین را بهصورت همزمان و مسدودکننده اجرا میکند و برای قوانینی که فقط روی داده در حافظه کار میکنند (مثل طول رشته) مناسب است، در حالی که ValidateAsync() از قوانینی پشتیبانی میکند که نیاز به عملیات ناهمزمان دارند، مثل MustAsync() برای چک کردن یکتا بودن ایمیل در دیتابیس.
Choreography (رقص هماهنگ) در مقابل Orchestration (ارکستراسیون)
در Choreography هیچ کنترلکننده مرکزی وجود ندارد و هر سرویس با گوشدادن به رویدادهای سرویسهای دیگر تصمیم میگیرد چه کاری انجام دهد، در حالی که در Orchestration یک هماهنگکننده مرکزی (Orchestrator) وجود دارد که بهصراحت به هر سرویس میگوید چه زمانی چه کاری انجام دهد.
Factory Method در مقابل Abstract Factory
Factory Method یک متد است که در کلاسهای فرزند Override میشود تا نحوه ساخت یک نوع محصول خاص را تعیین کند، در حالی که Abstract Factory یک Interface کامل است که خانوادهای از محصولات مرتبط را بدون مشخص کردن کلاس دقیق آنها تولید میکند و معمولاً از چند Factory Method در کنار هم تشکیل شده است.
Entity در مقابل Value Object
Entity در DDD یک هویت مشخص و پایدار دارد (معمولاً یک شناسه Id) که حتی اگر همه فیلدهایش تغییر کنند همچنان همان شیء محسوب میشود، در حالی که Value Object هیچ هویت مستقلی ندارد و کاملاً بر اساس مقدار فیلدهایش شناخته میشود؛ دو Value Object با مقادیر یکسان کاملاً معادل هم هستند و معمولاً غیرقابل تغییر (Immutable) طراحی میشوند.
Command در مقابل Query
Command در الگوی CQRS عملیاتی است که وضعیت سیستم را تغییر میدهد (مثل ایجاد یا حذف) و معمولاً مقدار قابل توجهی برنمیگرداند، در حالی که Query عملیاتی است که فقط داده میخواند و هیچ تغییری در وضعیت سیستم ایجاد نمیکند؛ جدا کردن این دو مسیر اجازه میدهد هرکدام مستقل بهینهسازی و مقیاسدهی شوند.
Entities (هسته دامنه) در مقابل Use Cases (لایه Application)
Entities در Clean Architecture در مرکزیترین لایه قرار دارند و قوانین کسبوکار کاملاً مستقل از هر برنامه خاص را در خود دارند (مثل قانون «سفارش زیر ۱۰۰ هزار تومان هزینه ارسال دارد»)، در حالی که Use Cases (لایه Application) قوانین مخصوص یک عملیات خاص برنامه را هماهنگ میکنند و از Entities برای انجام یک سناریوی مشخص (مثل «ثبت سفارش جدید») استفاده میکنند.
ProjectTo() در مقابل Map()
ProjectTo() مستقیماً روی یک IQueryable عمل میکند و Expression نگاشت را به کوئری SQL ترجمه میکند تا فقط ستونهای لازم از دیتابیس خوانده شوند، در حالی که Map() روی اشیاء موجود در حافظه (In-Memory) کار میکند و ابتدا باید کل موجودیت از دیتابیس خوانده شده باشد.
Coupling (وابستگی/جفتشدگی) در مقابل Cohesion (انسجام)
Coupling میزان وابستگی یک ماژول به جزئیات داخلی ماژولهای دیگر را نشان میدهد که هرچه کمتر باشد بهتر است، در حالی که Cohesion میزان مرتبط و همهدف بودن اعضای داخل یک ماژول را نشان میدهد که هرچه بیشتر باشد بهتر است؛ هدف اصلی معماری خوب رسیدن به Coupling کم و Cohesion بالا بهطور همزمان است.
پایگاهداده برداری اختصاصی (مثل Pinecone/Qdrant) در مقابل افزونه برداری روی دیتابیس موجود (مثل pgvector)
پایگاهداده برداری اختصاصی از ابتدا برای جستجوی برداری در مقیاس بسیار بزرگ بهینهسازی شده و امکاناتی مثل ایندکسهای پیشرفته HNSW و مقیاسپذیری افقی آماده دارد، در حالی که افزونهای مثل pgvector قابلیت جستجوی برداری را مستقیماً به یک پایگاهداده رابطهای موجود (مثل PostgreSQL) اضافه میکند تا داده برداری و رابطهای در یک سیستم واحد بمانند.
Plugins در مقابل Planners
Plugin در Semantic Kernel یک مجموعه از توابع مشخص (کد C#/Python یا پرامپت) است که مدل میتواند مستقیماً فراخوانی کند، در حالی که Planner جزئی از Kernel است که بر اساس یک هدف کلی، خودش تصمیم میگیرد چه ترتیبی از Plugin ها را برای رسیدن به آن هدف فراخوانی کند.
RAG با جستجوی برداری (Vector Search) در مقابل RAG با جستجوی کلیدواژهای (Keyword Search)
در RAG مبتنی بر جستجوی برداری، اسناد بر اساس شباهت معنایی Embedding بازیابی میشوند و میتوانند مفاهیم مشابه با کلمات متفاوت را پیدا کنند، در حالی که RAG مبتنی بر جستجوی کلیدواژهای (مثل BM25) اسناد را بر اساس تطابق دقیق کلمات کوئری با متن سند بازیابی میکند.
Zero-shot Prompting در مقابل Few-shot Prompting
در Zero-shot Prompting فقط دستورالعمل کار را بدون هیچ مثالی به مدل میدهید و به دانش از پیش آموختهشده آن تکیه میکنید، در حالی که در Few-shot Prompting چند نمونه ورودی-خروجی درست در خود پرامپت قرار میدهید تا مدل الگوی دقیق پاسخ مورد نظرتان را بهتر یاد بگیرد.
Chat Completions API در مقابل Assistants API
Chat Completions API یک API بدونحالت (Stateless) است که در هر فراخوانی باید کل تاریخچه مکالمه را خودتان ارسال کنید و کنترل کامل روی همهچیز دارید، در حالی که Assistants API حالتدار (Stateful) است و مدیریت تاریخچه مکالمه (Threads)، فایلها و ابزارهایی مثل تفسیر کد را خودش روی سرور OpenAI نگه میدارد.
Microsoft.Extensions.AI در مقابل Semantic Kernel
Microsoft.Extensions.AI یک لایه انتزاعی سبک و استاندارد در اکوسیستم .NET است که فقط یک رابط یکسان برای فراخوانی مدلهای مختلف زبانی فراهم میکند، در حالی که Semantic Kernel یک فریمورک کامل Orchestration است که علاوه بر فراخوانی مدل، امکاناتی مثل Plugin، Planner، Memory و مدیریت مکالمه پیچیده را هم ارائه میدهد.
MCP Tools در مقابل MCP Resources
در پروتکل MCP، Tools قابلیتهای قابل فراخوانی هستند که مدل زبانی میتواند با پارامتر مشخص اجرا کند تا کاری انجام دهد یا دادهای پردازش کند (مثل ارسال ایمیل یا اجرای کوئری)، در حالی که Resources منابع دادهای فقطخواندنی هستند که مدل یا کلاینت میتواند برای گرفتن زمینه (Context) بدون اجرای عملیات جانبی، آنها را بخواند.
Chains (زنجیره ثابت) در مقابل Agents (عامل پویا)
Chain در LangChain یک توالی از پیش تعیینشده و ثابت از مراحل است (مثلاً پرامپت -> مدل -> پارس خروجی) که همیشه به همان ترتیب اجرا میشود، در حالی که Agent در هر مرحله خودش با کمک مدل تصمیم میگیرد کدام ابزار را فراخوانی کند و ترتیب اجرا از قبل ثابت نیست بلکه بهصورت پویا در Runtime تعیین میشود.
Embedding متراکم (Dense) در مقابل Embedding پراکنده (Sparse)
Embedding متراکم بردارهایی با صدها یا هزاران بُعد اما بدون صفر زیاد تولید میکند که معنای مفهومی متن را در فضای پیوسته نشان میدهد (تولیدشده توسط مدلهای عصبی)، در حالی که Embedding پراکنده (مثل TF-IDF یا BM25) بردارهایی بسیار بزرگ اما عمدتاً صفر دارد که مستقیماً بر اساس فراوانی کلمات کار میکند و برای تطابق دقیق کلمه کلیدی قویتر است.
Azure AI Search در مقابل Azure OpenAI Service
Azure AI Search سرویس جستجو و بازیابی اطلاعات است که با ایندکسگذاری متن و بردار (Vector) امکان جستجوی معنایی سریع در حجم زیاد داده را فراهم میکند، در حالی که Azure OpenAI Service دسترسی به مدلهای زبانی بزرگ OpenAI (مثل GPT-4o) را با تضمینهای امنیتی و انطباق سازمانی مایکروسافت ارائه میدهد؛ این دو معمولاً در کنار هم برای ساخت سیستمهای RAG استفاده میشوند.
ML.NET (مدل محلی سفارشی) در مقابل فراخوانی API مدل زبانی بزرگ
ML.NET به توسعهدهنده .NET اجازه میدهد یک مدل یادگیری ماشین کوچک و اختصاصی را روی داده خودش آموزش داده و بهصورت محلی و بدون وابستگی به اینترنت اجرا کند، در حالی که فراخوانی API مدل زبانی بزرگ (مثل OpenAI یا Azure OpenAI) یک مدل عظیم و از پیش آموزشدیده را از طریق شبکه فراخوانی میکند بدون نیاز به آموزش مدل توسط خود شما.
چتبات مبتنی بر قانون (Rule-based) در مقابل چتبات مبتنی بر LLM
چتبات مبتنی بر قانون با درخت تصمیم و الگوهای از پیش تعریفشده (Intent/Entity) کار میکند و فقط به سناریوهای پیشبینیشده پاسخ میدهد، در حالی که چتبات مبتنی بر مدل زبانی بزرگ میتواند سؤالات باز و پیشبینینشده را با درک زبان طبیعی واقعی پاسخ دهد.
سیستم تکایجنت (Single-Agent) در مقابل سیستم چندایجنت (Multi-Agent)
در سیستم تکایجنت، یک AI Agent با مجموعهای از ابزارها تمام مراحل یک وظیفه را خودش انجام میدهد، در حالی که در سیستم چندایجنت، چند Agent تخصصی (مثلاً یکی برای تحقیق، یکی برای نوشتن، یکی برای بازبینی) با هم همکاری میکنند و هرکدام مسئولیت بخشی از کار را بر عهده دارند.
یادگیری ماشین سنتی (Machine Learning) در مقابل هوش مصنوعی مولد (Generative AI)
یادگیری ماشین سنتی روی داده برچسبدار یا الگوهای عددی آموزش میبیند و معمولاً یک خروجی مشخص (دستهبندی، عدد، پیشبینی) تولید میکند، در حالی که هوش مصنوعی مولد (مثل مدلهای زبانی بزرگ) محتوای جدید مثل متن، تصویر یا کد تولید میکند که قبلاً به همان شکل وجود نداشته است.
Options API در مقابل Composition API
Options API کد کامپوننت را در بخشهای از پیش تعیینشده (data، methods، computed) سازماندهی میکند که برای مبتدیان خواناتر است، در حالی که Composition API با تابع setup() و توابعی مثل ref و reactive اجازه میدهد منطق مرتبط با هم را کنار هم بنویسید و آن را در قالب Composable بین کامپوننتها به اشتراک بگذارید.
MUI (Material UI) در مقابل Ant Design
MUI پیادهسازی رسمی زبان طراحی Material Design گوگل برای React است و شخصیسازی عمیق ظاهر آن نیازمند تنظیم Theme دقیق است، در حالی که Ant Design یک کتابخانه سازمانی با کامپوننتهای آماده و پرجزئیات (مثل جداول پیشرفته و فرمهای پیچیده) است که برای پنلهای مدیریتی و Dashboard های سازمانی بسیار محبوب است.
interface در مقابل type (Type Alias)
interface عمدتاً برای توصیف شکل یک شیء یا کلاس بهکار میرود و قابلیت خاصی به نام Declaration Merging دارد (چند interface همنام با هم ادغام میشوند)، در حالی که type انعطاف بیشتری دارد و میتواند اتحاد (Union)، تقاطع (Intersection) یا نوعهای اولیه و Tuple را هم تعریف کند، اما Declaration Merging ندارد.
کلاسهای Utility مستقیم در مقابل دایرکتیو @apply
در روش معمول Tailwind، کلاسهای Utility مستقیماً در HTML/JSX نوشته میشوند و همه استایل در همان مارکآپ قابل مشاهده است، در حالی که @apply این امکان را میدهد چند کلاس Utility را در یک کلاس CSS سفارشی جدید ترکیب کنید تا از تکرار مکرر یک ترکیب طولانی از کلاسها در چند جای مختلف جلوگیری شود.
useState در مقابل useReducer
useState یک مقدار وضعیت ساده را نگه میدارد و بهطور مستقیم با یک تابع Setter بهروزرسانی میشود، در حالی که useReducer وضعیت را از طریق یک تابع Reducer و ارسال Action ها مدیریت میکند و برای وضعیتهای پیچیده با چند فیلد مرتبط و منطق تغییر پیچیدهتر مناسبتر است.
استراتژی Cache-First در مقابل استراتژی Network-First
در استراتژی Cache-First، Service Worker ابتدا نسخه ذخیرهشده در Cache را برمیگرداند و فقط در نبود آن به شبکه مراجعه میکند، در حالی که در Network-First ابتدا تلاش میکند از شبکه پاسخ تازه بگیرد و فقط در صورت شکست اتصال به نسخه Cache شده برمیگردد.
Static Site Generation (SSG) در مقابل Incremental Static Regeneration (ISR)
در SSG صفحات فقط یکبار در زمان Build ساخته میشوند و تا Deploy بعدی ثابت میمانند، در حالی که ISR اجازه میدهد صفحات استاتیک بعد از Build هم با یک بازه زمانی مشخص (revalidate) در پسزمینه بهروزرسانی شوند بدون نیاز به Build کامل دوباره کل سایت.
برابری ضعیف (==) در مقابل برابری دقیق (===)
عملگر == قبل از مقایسه، مقادیر را بهصورت خودکار به یک نوع مشترک تبدیل میکند (Type Coercion) که میتواند نتایج غیرمنتظره بدهد، در حالی که === بدون هیچ تبدیل نوعی، هم مقدار و هم نوع داده را دقیقاً مقایسه میکند.
HTML معنایی (Semantic) در مقابل استفاده افراطی از div (Div Soup)
HTML معنایی از تگهایی مثل header، nav، main، article و footer استفاده میکند که معنای ساختاری صفحه را هم برای مرورگر و هم برای ابزارهای کمکی مشخص میکند، در حالی که Div Soup یعنی استفاده از div برای همهچیز بدون هیچ معنای ساختاری، که خواندن کد و دسترسیپذیری (Accessibility) را دشوار میکند.
CSS Flexbox در مقابل CSS Grid
Flexbox یکبعدی است و برای چیدمان عناصر در یک ردیف یا یک ستون طراحی شده، در حالی که CSS Grid دوبعدی است و امکان کنترل همزمان ردیفها و ستونها را در یک سیستم چیدمان کامل فراهم میکند.
Bootstrap 4 در مقابل Bootstrap 5
Bootstrap 4 برای برخی کامپوننتها (مثل Modal و Dropdown) به jQuery وابسته است و از کلاسهای sr-only و مقادیر Sass قدیمیتری استفاده میکند، در حالی که Bootstrap 5 کاملاً وابستگی به jQuery را حذف کرده، از جاوااسکریپت خالص استفاده میکند و کلاسهای Utility API قدرتمندتری برای سفارشیسازی دارد.
Blazor Server در مقابل Blazor WebAssembly
Blazor Server کد C# را روی سرور اجرا میکند و تغییرات UI را از طریق یک اتصال SignalR دائمی به مرورگر میفرستد، در حالی که Blazor WebAssembly کل برنامه را بهصورت باینری .NET در خود مرورگر دانلود و اجرا میکند و بعد از بارگذاری اولیه هیچ وابستگی دائمی به سرور ندارد.
Reactive Forms در مقابل Template-driven Forms
Reactive Forms ساختار فرم را بهطور کامل در کد TypeScript با FormGroup و FormControl تعریف میکند و کنترل و تستپذیری بالایی دارد، در حالی که Template-driven Forms عمدتاً در HTML با دایرکتیوهایی مثل ngModel تعریف میشود و برای فرمهای ساده سریعتر نوشته میشود.
رندر سمت کلاینت (CSR) در مقابل رندر سمت سرور (SSR)
در CSR مرورگر یک فایل HTML تقریباً خالی دریافت میکند و جاوااسکریپت کل رابط کاربری را در خود مرورگر میسازد، در حالی که در SSR سرور HTML کامل و آماده هر صفحه را از قبل رندر کرده و به مرورگر میفرستد و جاوااسکریپت بعداً برای تعاملیشدن صفحه (Hydration) بارگذاری میشود.
XSS ذخیرهشده (Stored) در مقابل XSS بازتابی (Reflected)
در XSS ذخیرهشده، اسکریپت مخرب در دیتابیس یا فایل سرور ذخیره میشود (مثلاً در یک کامنت) و برای هر کاربری که آن صفحه را ببیند اجرا میشود، در حالی که در XSS بازتابی، اسکریپت مخرب فقط در همان درخواست (معمولاً در پارامتر URL) قرار دارد و بلافاصله در پاسخ همان درخواست بازتاب داده و اجرا میشود بدون اینکه جایی ذخیره شود.
TLS 1.2 در مقابل TLS 1.3
TLS 1.2 برای برقراری اتصال به یک Handshake دو رفتوبرگشتی نیاز دارد و از الگوریتمهای رمزنگاری قدیمیتر (بعضاً ناامن) هم پشتیبانی میکند، در حالی که TLS 1.3 با کاهش Handshake به یک رفتوبرگشت سریعتر است، الگوریتمهای ضعیف و قدیمی را کاملاً حذف کرده و بهصورت پیشفرض امنتر است.
SQL Injection کلاسیک (In-band) در مقابل SQL Injection کور (Blind)
در SQL Injection کلاسیک، مهاجم نتیجه کوئری مخرب یا پیام خطای دیتابیس را مستقیماً در پاسخ صفحه میبیند، در حالی که در نوع کور (Blind) هیچ داده یا خطایی مستقیماً نمایش داده نمیشود و مهاجم باید از طریق تغییرات رفتاری غیرمستقیم (مثل تفاوت زمان پاسخ یا صحت/خطای بولی صفحه) اطلاعات را حدس بزند.
کنترل دسترسی مبتنی بر نقش (RBAC) در مقابل کنترل دسترسی مبتنی بر ویژگی (ABAC)
RBAC دسترسی را بر اساس نقش ثابت کاربر (مثل Admin، Editor) تعیین میکند و ساده و قابل فهم است، در حالی که ABAC دسترسی را بر اساس ترکیبی از ویژگیهای پویا (کاربر، منبع، محیط، زمان) با قوانین منطقی تصمیم میگیرد و انعطافپذیری بسیار بیشتری دارد.
احراز هویت تکعامله (Single-Factor) در مقابل احراز هویت چندعامله (MFA)
احراز هویت تکعامله فقط با یک چیز (معمولاً رمز عبور) هویت را تأیید میکند، در حالی که احراز هویت چندعامله حداقل دو دسته مستقل از عوامل را ترکیب میکند: چیزی که میدانید (رمز عبور)، چیزی که دارید (گوشی/توکن) یا چیزی که هستید (اثر انگشت).
اعتبارسنجی سمت کلاینت در مقابل اعتبارسنجی سمت سرور
اعتبارسنجی سمت کلاینت در مرورگر یا اپلیکیشن اجرا میشود و برای تجربه کاربری سریع و بازخورد فوری مفید است، اما چون کاملاً تحت کنترل کاربر است هیچ تضمین امنیتی نمیدهد؛ اعتبارسنجی سمت سرور در محیطی است که مهاجم کنترلی روی آن ندارد و تنها منبع قابلاعتماد برای اطمینان از صحت و امنیت داده ورودی است.
تست نفوذ خارجی (External Pentest) در مقابل تست نفوذ داخلی (Internal Pentest)
تست نفوذ خارجی از دید یک مهاجم اینترنتی انجام میشود و روی سطوح در معرض دید عموم مثل وبسایت، API عمومی و فایروال تمرکز دارد؛ تست نفوذ داخلی فرض میکند مهاجم از قبل به شبکه داخلی سازمان (مثلاً از طریق یک کارمند آلوده یا Wi-Fi داخلی) دسترسی پیدا کرده و بررسی میکند تا کجا میتواند در شبکه داخلی پیش برود.
HSTS (HTTP Strict Transport Security) در مقابل ریدایرکت ۳۰۱ به HTTPS
ریدایرکت ۳۰۱ روشی است که سرور درخواست HTTP اولیه را میگیرد و کاربر را به نسخه HTTPS هدایت میکند، اما همان درخواست اول هنوز رمزنگارینشده و در معرض حمله Man-in-the-Middle است؛ HSTS یک هدر است که به مرورگر میگوید برای مدت مشخصی حتی درخواستهای بعدی را هم مستقیماً و بدون تلاش اولیه HTTP به HTTPS بفرستد.
Broken Access Control در مقابل Security Misconfiguration
Broken Access Control (رتبه اول OWASP Top 10 2021) به معنی نبود یا نقص در منطق برنامه برای کنترل دسترسی کاربران به منابعی است که نباید ببینند، در حالی که Security Misconfiguration به تنظیمات نادرست زیرساخت یا فریمورک (مثل باز ماندن پنل مدیریتی، هدرهای امنیتی غایب یا پیام خطای افشاگر) اشاره دارد که ربطی به منطق کد ندارد.
CSRF Token (Synchronizer Token) در مقابل کوکی SameSite
CSRF Token یک مقدار تصادفی و غیرقابلحدس است که سرور در فرم یا هدر قرار میدهد و در هر درخواست تغییردهنده باید همراه با آن ارسال شود تا سرور مطمئن شود درخواست از صفحه واقعی سایت آمده، در حالی که ویژگی SameSite کوکی به مرورگر میگوید کوکی را فقط در درخواستهایی که از همان سایت شروع شدهاند ارسال کند و درخواستهای Cross-Site را از اول مسدود میکند.
درخواست ساده (Simple Request) در مقابل درخواست Preflight (OPTIONS)
درخواست ساده در CORS شرایط محدودی دارد (متد GET/POST/HEAD، هدرهای استاندارد) و مرورگر مستقیماً آن را ارسال میکند، در حالی که اگر درخواست از متدهایی مثل PUT/DELETE یا هدرهای سفارشی (مثل Authorization یا Content-Type: application/json) استفاده کند، مرورگر ابتدا یک درخواست OPTIONS به نام Preflight میفرستد تا از سرور اجازه بگیرد.
API Key در مقابل OAuth 2.0 Access Token
API Key یک رشته ثابت و ساده است که یک برنامه یا سرویس را شناسایی میکند اما معمولاً هویت یک کاربر نهایی خاص یا محدوده دسترسی دقیق را مشخص نمیکند، در حالی که Access Token در OAuth 2.0 معمولاً کوتاهمدت، دارای Scope مشخص و قابل نگاشت به یک کاربر واقعی است و از طریق یک فرآیند تأیید هویت استاندارد صادر میشود.
رمزنگاری متقارن (Symmetric) در مقابل رمزنگاری نامتقارن (Asymmetric)
رمزنگاری متقارن از یک کلید مشترک برای رمزگذاری و رمزگشایی استفاده میکند و بسیار سریع است اما توزیع امن کلید بین طرفین چالشبرانگیز است، در حالی که رمزنگاری نامتقارن از یک جفت کلید عمومی/خصوصی استفاده میکند که مشکل توزیع کلید را حل میکند اما بهمراتب کندتر است.
[Fact] در مقابل [Theory]
[Fact] یک تست ساده و بدون پارامتر است که همیشه با همان شرایط ثابت اجرا میشود، در حالی که [Theory] یک تست پارامتری است که همراه با [InlineData]، [MemberData] یا [ClassData] یک بار برای هر مجموعه داده اجرا میشود و به شما اجازه میدهد یک منطق تست را با چند ورودی مختلف بررسی کنید.
الگوی AAA (Arrange-Act-Assert) در مقابل الگوی Given-When-Then (BDD)
الگوی AAA یک تست واحد را به سه بخش آمادهسازی، اجرا و بررسی نتیجه تقسیم میکند و زبان فنی و مستقیم دارد؛ الگوی Given-When-Then از دنیای BDD میآید، ساختار مشابهی دارد اما با زبانی نزدیکتر به توصیف رفتار کسبوکار نوشته میشود و اغلب در ابزارهایی مثل SpecFlow بهکار میرود.
Testcontainers (دیتابیس واقعی در Docker) در مقابل دیتابیس In-Memory جعلی (مثل SQLite In-Memory)
Testcontainers یک نمونه واقعی از دیتابیس (مثل SQL Server یا PostgreSQL) را در یک کانتینر Docker موقت برای تست بالا میآورد که رفتار دقیقاً مثل Production است؛ دیتابیس In-Memory جعلی سریعتر است اما موتور متفاوتی دارد و ممکن است برخی رفتارها (مثل قیدهای خاص یا نحوه Query) را دقیق شبیهسازی نکند.
[TestCase] در مقابل [TestCaseSource]
[TestCase] مقادیر ورودی و خروجی مورد انتظار را مستقیماً و بهصورت ثابت روی خود Attribute مینویسد و برای سناریوهای ساده و کمتعداد کافی است، در حالی که [TestCaseSource] لیست موارد تست را از یک متد، Property یا کلاس جداگانه میخواند و برای دادههای پیچیده، پویا یا قابل استفاده مجدد بین چند تست مناسبتر است.
[DataRow] در مقابل [DynamicData]
[DataRow] مقادیر تست پارامتری را مستقیماً و بهصورت ثابت (Compile-time) روی خود Attribute مینویسد و برای تعداد کم داده ساده مناسب است، در حالی که [DynamicData] دادهها را در Runtime از یک متد یا Property جداگانه (که میتواند شامل انواع پیچیده یا منابع خارجی باشد) میخواند.
Mock (تأیید رفتار) در مقابل Stub (پاسخ ثابت)
در Moq، وقتی از Verify() برای اطمینان از فراخوانی یک متد با آرگومانهای خاص استفاده میکنید، شیء را بهعنوان Mock بهکار بردهاید که رفتار (تعامل) را تست میکند؛ وقتی فقط از Setup() برای بازگرداندن یک مقدار ثابت بدون Verify کردن فراخوانی استفاده میکنید، همان شیء نقش Stub یعنی تأمینکننده داده ساختگی را دارد.
تست یکپارچگی درونپروسهای (In-Process) در مقابل تست یکپارچگی برونپروسهای (Out-of-Process)
تست درونپروسهای با ابزاری مثل WebApplicationFactory برنامه را در حافظه همان پروسه تست میزبانی میکند و درخواستهای HTTP را بدون شبکه واقعی شبیهسازی میکند، در حالی که تست برونپروسهای یک نمونه واقعی از برنامه را (مثلاً روی یک پورت واقعی یا در Docker) اجرا کرده و با HttpClient واقعی از بیرون به آن درخواست میزند.
تست عملکردی دستی (Manual) در مقابل تست عملکردی خودکار (Automated)
در تست عملکردی دستی یک تستر انسانی طبق سناریوهای از پیش نوشتهشده با برنامه کار میکند و نتیجه را با انتظار مقایسه میکند، در حالی که تست عملکردی خودکار همان سناریوها را با اسکریپت و ابزار (مثل Playwright یا Postman) بدون دخالت انسان و بهصورت تکرارپذیر اجرا میکند.
Should().Be() در مقابل Should().BeEquivalentTo()
Should().Be() برابری دقیق (معمولاً Reference Equality برای Object یا Value Equality برای انواع ساده) را چک میکند، در حالی که Should().BeEquivalentTo() دو شیء را با مقایسه عمیق و بازگشتی همه Property ها با هم مقایسه میکند، بدون توجه به اینکه دو نمونه متفاوت از حافظه باشند.
Playwright در مقابل Selenium
Playwright ابزار جدیدتری است که مستقیماً با پروتکلهای مرورگر ارتباط برقرار میکند، منتظرماندن هوشمند (Auto-waiting) دارد و بهصورت پیشفرض پایدارتر و سریعتر است، در حالی که Selenium ابزار قدیمیتر و بالغتری است که از WebDriver استاندارد استفاده میکند و پشتیبانی گستردهتری از زبانها و مرورگرهای قدیمی دارد.
Job.Dry (اجرای سریع آزمایشی) در مقابل Job.Default (اجرای کامل آماری)
Job.Dry فقط یک بار Warmup و یک بار اجرای واقعی را انجام میدهد تا سریع مطمئن شوید بنچمارک خطا ندارد، در حالی که Job.Default طبق روش آماری کامل BenchmarkDotNet چندین Iteration گرمکردن و اجرای واقعی انجام میدهد تا نتیجهای دقیق و قابل اعتماد آماری تولید کند.
تست جعبه سیاه (Black-box) در مقابل تست جعبه سفید (White-box)
در تست جعبه سیاه، تستر بدون اطلاع از کد داخلی، فقط ورودی میدهد و خروجی را با انتظار مقایسه میکند، در حالی که در تست جعبه سفید، تستر به ساختار داخلی کد دسترسی دارد و مسیرهای اجرا (Branch ها)، شرطها و منطق داخلی را هدف قرار میدهد.
Ubuntu LTS در مقابل Ubuntu نسخه میاندورهای (Interim)
نسخههای LTS (مثل 22.04، 24.04) هر دو سال منتشر میشوند و ۵ سال پشتیبانی رسمی (قابل تمدید تا ۱۰ سال) دارند، در حالی که نسخههای میاندورهای هر ۶ ماه منتشر میشوند، جدیدترین نرمافزارها و کرنل را دارند اما فقط ۹ ماه پشتیبانی میشوند.
Service Unit در مقابل Timer Unit
Service Unit (فایل .service) نحوه اجرای یک پروسه یا سرویس را تعریف میکند، مثل اینکه چه دستوری اجرا شود و چگونه Restart شود، در حالی که Timer Unit (فایل .timer) یک زمانبند است که مشخص میکند یک Service Unit در چه زمانی فعال شود، مشابه جایگزین مدرنتر برای cron.
اجرا در Subshell (./script.sh) در مقابل Source کردن اسکریپت (source یا .)
اجرای اسکریپت با ./script.sh یک پروسه فرزند (Subshell) جدید میسازد که متغیرها و cd های داخل آن بعد از پایان اسکریپت از بین میروند، در حالی که source script.sh یا . script.sh اسکریپت را در همان شل فعلی اجرا میکند و هر تغییری در متغیرها، alias یا دایرکتوری جاری در شل فعلی باقی میماند.
Nginx بهعنوان Web Server در مقابل Nginx بهعنوان Reverse Proxy
در حالت Web Server، Nginx مستقیماً فایلهای استاتیک (HTML، CSS، عکس) را از دیسک میخواند و پاسخ میدهد، در حالی که در حالت Reverse Proxy، Nginx درخواست را دریافت کرده و به یک سرور برنامه در پشت خودش (مثل Node.js یا Kestrel روی پورت دیگر) forward میکند و پاسخ را برمیگرداند.
TCP در مقابل UDP
TCP یک پروتکل اتصالگرا (Connection-oriented) است که با Handshake سهمرحلهای، تضمین تحویل، ترتیب بستهها و کنترل ازدحام کار میکند، در حالی که UDP بدون اتصال و بدون تضمین است و بستهها را با کمترین سربار و سریعترین حالت ممکن ارسال میکند بدون تأیید دریافت.
لینک سخت (Hard Link) در مقابل لینک نمادین (Symbolic Link)
لینک سخت اشارهگر دیگری به همان inode روی دیسک است و عملاً دو نام برای یک فایل واقعی محسوب میشود، در حالی که لینک نمادین (Symlink) یک فایل کوچک جداگانه است که فقط مسیر فایل مقصد را نگه میدارد و میتواند به دایرکتوری یا فایل روی پارتیشن دیگر اشاره کند.
Crontab کاربری (crontab -e) در مقابل Cron سیستمی (/etc/cron.d و /etc/crontab)
Crontab کاربری با دستور crontab -e ویرایش میشود و همیشه با دسترسی همان کاربر اجرا میشود، در حالی که فایلهای /etc/crontab و /etc/cron.d/* سطح سیستم هستند، ستون اضافه برای مشخص کردن کاربر اجراکننده دارند و معمولاً توسط پکیجها یا مدیر سیستم برای وظایف سراسری استفاده میشوند.
CentOS Stream در مقابل CentOS Linux (سنتی)
CentOS Linux سنتی یک بازسازی باینری دقیق از RHEL بود که پس از انتشار پایدار RHEL منتشر میشد، اما از سال ۲۰۲۰ منسوخ شد؛ CentOS Stream نسخهای است که جلوتر از RHEL قرار میگیرد و بهعنوان شاخه توسعه Upstream برای نسخه بعدی RHEL عمل میکند.
Apache Prefork MPM در مقابل Apache Event MPM
Prefork MPM برای هر درخواست یک پروسه کاملاً جدا ایجاد میکند که پایدار ولی سنگین است و اغلب برای ماژولهای non-thread-safe مثل mod_php کلاسیک لازم است، در حالی که Event MPM از رشتهها (Thread) و مدل رویدادمحور برای مدیریت هزاران اتصال همزمان با مصرف حافظه بسیار کمتر استفاده میکند.
کروشه تکی [ ] در مقابل کروشه دوتایی [[ ]]
[ ] همان دستور test است و یک ابزار POSIX استاندارد برای شرطگذاری است که در تمام شلها کار میکند، در حالی که [[ ]] یک کلمه کلیدی خاص Bash است که امکاناتی مثل مقایسه رشته با الگو (pattern matching)، عملگرهای && و || داخلی و جلوگیری از Word Splitting را اضافه میکند.
توزیعهای مبتنی بر Debian (APT) در مقابل توزیعهای مبتنی بر Red Hat (RPM/YUM/DNF)
توزیعهای خانواده Debian مانند Ubuntu از فرمت بسته .deb و ابزار مدیریت بسته apt استفاده میکنند، در حالی که توزیعهای خانواده Red Hat مانند CentOS و Fedora از فرمت .rpm و ابزارهایی مثل yum یا dnf بهره میبرند؛ این تفاوت روی نام دستورات، مسیر فایلهای پیکربندی و چرخه انتشار اثر میگذارد.
مقیاسپذیری افقی (Horizontal Scaling) در مقابل مقیاسپذیری عمودی (Vertical Scaling)
مقیاسپذیری افقی یعنی افزودن سرورهای بیشتر و توزیع بار بین آنها (Scale Out)، در حالی که مقیاسپذیری عمودی یعنی افزایش منابع یک سرور واحد مانند CPU و RAM (Scale Up) بدون تغییر در تعداد سرورها.
ارتباط کلامی (Verbal) در مقابل ارتباط نوشتاری (Written)
ارتباط کلامی شامل جلسات، تماسهای صوتی/تصویری و گفتگوهای حضوری است که برای بحث سریع و حل ابهام مناسب است، در حالی که ارتباط نوشتاری (پیام، مستندات، تیکت) دائمی، قابل جستجو و مناسب تیمهای توزیعشده و ناهمزمان است.
نقشه راه عمومی (Generalist) در مقابل نقشه راه تخصصی (Specialist)
نقشه راه عمومی روی یادگیری گسترده چند حوزه (فرانتاند، بکاند، دیتابیس، DevOps) تمرکز دارد تا فرد بتواند در نقشهای Full-Stack کار کند، در حالی که نقشه راه تخصصی روی عمیق شدن در یک حوزه خاص (مثلاً فقط React یا فقط پایگاهداده) متمرکز است.
رزومه زمانی (Chronological) در مقابل رزومه مهارتمحور (Skills-based)
رزومه زمانی سابقه کاری را به ترتیب معکوس تاریخ (جدیدترین اول) فهرست میکند و مسیر رشد شغلی را واضح نشان میدهد، در حالی که رزومه مهارتمحور روی دستهبندی مهارتها و پروژهها تمرکز دارد و برای پوشاندن وقفههای شغلی یا تغییر مسیر شغلی مناسبتر است.
پیچیدگی زمانی (Time Complexity) در مقابل پیچیدگی حافظه (Space Complexity)
پیچیدگی زمانی با نماد O بزرگ نشان میدهد چقدر زمان اجرای الگوریتم با افزایش اندازه ورودی رشد میکند، در حالی که پیچیدگی حافظه نشان میدهد الگوریتم چقدر حافظه اضافی نسبت به ورودی نیاز دارد؛ بهینهسازی یکی گاهی باعث بدتر شدن دیگری میشود.
نگهدارنده (Maintainer) در مقابل مشارکتکننده (Contributor)
نگهدارنده مسئولیت کامل یک پروژه متنباز از جمله بازبینی و ادغام Pull Request ها، انتشار نسخهها و تعیین جهتگیری پروژه را بر عهده دارد، در حالی که مشارکتکننده فردی است که بهصورت داوطلبانه و معمولاً موردی، کد، مستندات یا رفع باگ ارسال میکند.
پست (Post) در مقابل مقاله (Article)
پست یک محتوای کوتاه در فید اصلی است که سریع دیده و اسکرول میشود و الگوریتم لینکدین آن را به شبکه گستردهتری نشان میدهد، در حالی که مقاله محتوای بلندتر و ساختاریافتهتری است که در پروفایل باقی میماند و بیشتر برای عمق و مرجع بودن مناسب است.
مصاحبه فنی (Technical Interview) در مقابل مصاحبه رفتاری (Behavioral Interview)
مصاحبه فنی مهارتهای عملی مانند حل الگوریتم، طراحی سیستم یا دیباگ کد را میسنجد، در حالی که مصاحبه رفتاری با پرسیدن درباره تجربههای گذشته، نحوه کار تیمی و واکنش به چالشها، تناسب فرهنگی و مهارتهای نرم فرد را ارزیابی میکند.
بازبینی همزمان (Pair/Live Review) در مقابل بازبینی Pull Request (ناهمزمان)
بازبینی همزمان یعنی دو نفر کنار هم (حضوری یا با اشتراک صفحه) کد را همان لحظه با هم میبینند و بحث میکنند، در حالی که بازبینی Pull Request یعنی نویسنده کد را ثبت میکند و بازبینها هر زمان که فرصت داشتند، با کامنتهای نوشتاری آن را بررسی میکنند.
قیمت ثابت (Fixed-Price) در مقابل کار ساعتی (Hourly)
در قرارداد قیمت ثابت، فریلنسر برای کل پروژه یک مبلغ مشخص توافق میکند و ریسک زمان بیشتر روی خودش است، در حالی که در کار ساعتی بر اساس ساعات واقعی کار مزد پرداخت میشود و ریسک طولانی شدن پروژه روی کارفرماست.
مسیر فنی تخصصی (IC Track) در مقابل مسیر مدیریتی (Management Track)
مسیر IC (Individual Contributor) یعنی پیشرفت شغلی از طریق عمیقتر شدن در مهارتهای فنی و رسیدن به سطوحی مثل Staff یا Principal Engineer، در حالی که مسیر مدیریتی یعنی حرکت به سمت رهبری تیم، برنامهریزی و مسئولیت افراد بهجای نوشتن روزانه کد.
VS Code Remote - SSH در مقابل VS Code Dev Containers
افزونه Remote-SSH به VS Code اجازه میدهد مستقیماً به یک سرور یا ماشین لینوکسی راه دور وصل شده و در محیط همان سرور کد بزنید، در حالی که Dev Containers کد را داخل یک کانتینر Docker تعریفشده با فایل پیکربندی محلی اجرا و ویرایش میکند.
Visual Studio Community در مقابل Visual Studio Professional/Enterprise
نسخه Community رایگان است اما فقط برای استفاده شخصی، آموزشی یا در تیمهای خیلی کوچک/سازمانهای غیرانتفاعی مجاز است؛ نسخههای Professional و Enterprise دارای مجوز تجاری کامل، ابزارهای تیمی پیشرفته (مثل CodeLens مشترک و تست بار) و پشتیبانی رسمی هستند.
SQL Server Management Studio در مقابل sqlcmd
SSMS محیطی گرافیکی کامل برای نوشتن کوئری، مدیریت اشیاء دیتابیس و دیباگ بصری است، در حالی که sqlcmd ابزاری سبک و خطفرمانی است که همان دستورات T-SQL را از ترمینال یا داخل اسکریپتهای Deployment اجرا میکند.
Postman در مقابل cURL
Postman یک ابزار گرافیکی برای ساخت، سازماندهی و اجرای درخواستهای API با قابلیتهایی مثل Collection، Environment و تست خودکار است، در حالی که cURL یک دستور خط فرمان ساده برای ارسال سریع یک درخواست HTTP از ترمینال یا اسکریپت است.
Docker Desktop (رابط گرافیکی) در مقابل Docker CLI (خط فرمان)
Docker Desktop یک اپلیکیشن گرافیکی روی ویندوز/مک است که موتور Docker را همراه Dashboard برای مشاهده کانتینرها، ایمیجها و لاگها نصب میکند؛ Docker CLI همان دستورات خط فرمان (docker run، docker ps و غیره) است که مستقیماً با Docker Engine صحبت میکند و روی سرورهای لینوکسی بدون رابط گرافیکی هم کار میکند.
Azure Data Studio در مقابل SQL Server Management Studio
Azure Data Studio ابزاری سبک، چندسکویی (ویندوز، مک، لینوکس) و مبتنی بر Notebook برای کار با SQL Server و Azure SQL است؛ در حالی که SSMS ابزاری سنگینتر و فقط ویندوزی است که مدیریت کامل و گرافیکی سرور را با تمام جزئیات فراهم میکند.
ویرایشگر کد (Code Editor) در مقابل محیط توسعه یکپارچه (IDE)
ویرایشگر کد ابزاری سبک برای نوشتن و ویرایش متن کد است که با نصب افزونه قابلیتهای بیشتری میگیرد، در حالی که IDE از ابتدا کامپایلر، دیباگر، تحلیلگر کد و ابزارهای رفکتور را یکجا و بدون نیاز به تنظیم اضافه در خود دارد.
Personal Project در مقابل Client/Freelance Project
Personal Project پروژهای است که خودتان ایده، محدوده و زمانبندی آن را تعیین میکنید و آزادی کامل خلاقانه دارید؛ Client/Freelance Project پروژهای است که برای یک مشتری واقعی با نیازمندیهای مشخص، بودجه، ددلاین و انتظارات کسبوکاری او انجام میشود و نیازمند مهارت ارتباطی و مدیریت انتظارات نیز هست.
Message Queue در مقابل Pub/Sub
Message Queue (مثل Azure Queue یا RabbitMQ Queue) یک پیام را فقط به یک مصرفکننده تحویل میدهد و پس از پردازش از صف حذف میشود، مناسب برای توزیع کار بین چند worker؛ Pub/Sub (مثل Azure Service Bus Topics) یک پیام را به همه مشترکین علاقهمند بهطور همزمان تحویل میدهد.
Structured Logging در مقابل Plain Text Logging
Structured Logging لاگها را بهصورت دادههای ساختیافته (معمولاً JSON) با فیلدهای مجزا ثبت میکند که بهراحتی قابل جستجو و تحلیل در ابزارهایی مثل Seq یا ELK هستند؛ Plain Text Logging پیامها را بهصورت رشته متنی ساده مینویسد که خواندن سریع آن برای انسان راحت است اما جستجو و تحلیل برنامهای آن دشوار و شکننده است.
