توسعهدهنده Back Endپاسخهای مصاحبه
سوالات متداول مصاحبه
من اصول REST را دنبال میکنم: منابع باید اسم باشند (نه فعل)، آدرسهای URI بهصورت سلسلهمراتبی باشند و روابط منابع را نشان دهند، و متدهای HTTP بهصورت معنایی استفاده شوند (GET خواندن، POST ایجاد، PUT/PATCH بهروزرسانی، DELETE حذف). از ابتدا نسخهبندی API را اعمال میکنم (/v1/) تا امکان توسعه بدون شکست بودن فراهم شود. قالبهای پاسخ، کدهای خطا و الگوهای صفحهبندی را یکنواخت طراحی میکنم. مستندسازی را با OpenAPI/Swagger انجام میدهم. هنگام طراحی نیازهای کلاینت را در نظر میگیرم — یک API که از نظر فنی درست است اما استفاده از آن سخت است، API بدی است. همچنین محدودیت نرخ، احراز هویت و اعتبارسنجی ورودیها را بهعنوان مسائل سطحاول API مد نظر قرار میدهم.
من اسکیمای پایگاهداده را بر اساس الگوهای دسترسی طراحی میکنم — بهطور پیشفرض نرمالسازی میکنم و زمانی که عملکرد پرسوجوها ایجاب کند، دینرمالسازی انجام میدهم. از ایندکسها بهصورت استراتژیک استفاده میکنم: هر پرسوجوی کند یک EXPLAIN plan میگیرد و ایندکسها بر اساس سلکتویتی و تکرار پرسوجو اضافه میشوند. از پرسوجوهای N+1 جلوگیری میکنم با طراحی بارگذاری پیشبارگذاری (eager loading) در لایه داده. مهاجرتها (migrations) را با احتیاط مینویسم — در صورت امکان تغییرات سازگار با نسخههای قبلی انجام میدهم و برای تغییرات شکافزا استراتژیهای استقرار blue-green را بهکار میبرم. همچنین برای تمامیت داده طراحی میکنم: قیدهای foreign key، قیدهای not-null و check constraints یکپارچگی را در سطح پایگاهداده برقرار میکنند.
از ابتدا سرویسهای بدونحالت (stateless) طراحی میکنم — حالت در دیتابیس یا کش نگهداری میشود، نه در حافظه اپلیکیشن. برای عملیاتهایی که نیازی به همزمانی ندارند از پردازش غیرهمزمان استفاده میکنم (صفهای پیام: RabbitMQ، Kafka، SQS). در لایه مناسب بهطور هجومی کش میکنم: نتایج پرسوجوی پایگاهداده (Redis)، تجمعهای محاسبهشده و منابع ایستا. APIها را طوری طراحی میکنم که بهصورت افقی مقیاسپذیر باشند و سرویسهای مدیریتشده را ترجیح میدهم (RDS، ElasticCache) که بهصورت مستقل مقیاس مییابند. همچنین محدودسازی نرخ و مدیریت پسفشار را طراحی میکنم — سرویسها باید تحت بار بهصورت تدریجی دگرگون شوند.
احراز هویت: OAuth 2.0 / OIDC برای احراز هویت کاربران، کلیدهای API یا JWT برای سرویسبهسرویس. همه ورودیها را اعتبارسنجی و پاکسازی میکنم — هیچ ساختار SQL مستقیمی از ورودی کاربر ساخته نمیشود. برای جلوگیری از سوءاستفاده محدودیت نرخ و throttling را پیادهسازی میکنم. از HTTPS/TLS در همهجا استفاده میکنم و اعتبارسنجی گواهی را الزام میکنم. اصل کمترین امتیاز (least-privilege) را اعمال میکنم: هر سرویس و کاربر حداقل مجوزهای لازم را دارد. استفاده از امتیازات را ممیزی میکنم. وابستگیها را برای آسیبپذیریها در CI اسکن میکنم (OWASP Dependency-Check، Snyk). و رویدادهای امنیتی — احراز هویتهای ناموفق، ارتقاء امتیازات — را بهصورت مرکزی برای مانیتورینگ لاگ میگیرم.
اصول من این است که خطاها باید لاگ شوند، دستهبندی شوند و معنادار بازگردانده شوند. از لاگنویسی ساختاریافته (JSON) با سطح مناسب استفاده میکنم تا لاگها قابل جستجو باشند. ردیابی توزیعشده را پیادهسازی میکنم (OpenTelemetry) تا درخواستها در سراسر سرویسها قابل دنبالکردن باشند. کدهای خطا را بهصورت یکسان در سراسر API تعریف و مستندسازی میکنم. هشداردهی را بر روی آنومالیهای نرخ خطا تنظیم میکنم، نه صرفاً شاخصهای فنی مانند CPU. در معماریهای میکروسرویس از مدارشکنها (Resilience4j، Hystrix) برای جلوگیری از شکستهای آبشاری هنگام بدعملی یک وابستگی استفاده میکنم.
من هر دو را ساخته و نگهداری کردهام. مونولیتها دستکم گرفته شدهاند: سادهتر برای توسعه، تست و استقرار هستند و بیشتر تیمها تا زمانی که به محدودیتهای مقیاس یا هماهنگی تیمی برخورد نکنند، نیازی به میکروسرویسها ندارند. وقتی به میکروسرویس مهاجرت کردهام، از الگوی Strangler Fig استفاده کردهام — استخراج سرویسها بهصورت تدریجی از یک مونولیت فعال بهجای تجزیهی یکباره (big-bang decomposition). میکروسرویسها پیچیدگی عملیاتی قابلتوجهی وارد میکنند (service discovery، ردیابی توزیعشده، حالات شکست شبکه، سازگاری داده بین سرویسها) — من تنها وقتی آن پیچیدگی را میپذیرم که مزایا بهوضوح بر آن غالب باشند.
برای من، تست واحد برای منطق تجاری بهصورت ایزوله (با موککردن دیتابیس و وابستگیهای خارجی) نوشته میشود. تستهای یکپارچهای مینویسم که سرویس را در برابر یک پایگاهدادهٔ واقعی (تستی) بررسی میکنند — اینها چرخهٔ کامل درخواست-پاسخ را تست میکنند و خطاهای SQL، مشکلات عملکرد پرسوجو و نگاشت داده را که تستهای واحد نمیبینند، میگیرند. از تست قرارداد (Pact) جایی که سرویسها API منتشرشدهشان را توسط تیمهای مصرفکننده دارند، استفاده میکنم. همچنین برای نقطههای پایان حساس به عملکرد تستهای بار مینویسم (k6، Locust). پوشش تست تنها زمانی معنادار است که تستها قادر به کشف خطاهای واقعی باشند.
من سیستمهای رویدادمحور را با استفاده از RabbitMQ و Apache Kafka طراحی کردهام. با مصالحهها آشنا هستم: تحویل حداقل-یکبار (at-least-once) در مقابل دقیقاً-یکبار (exactly-once)، الگوهای گروه مصرفکننده، صفهای نامههای مرده (dead letter queues)، و تضمینهای ترتیب پیام. اسکیمای پیام را با دقت طراحی میکنم — تکامل اسکیما که با نسخههای قبلی سازگار باشد در تولید ضروری است. مصرفکنندههای ایدمپوتنت را پیادهسازی میکنم تا پیامهای تکراری باعث فساد داده نشوند. عمق صف و تأخیر مصرفکننده (consumer lag) را بهعنوان شاخصهای عملیاتی کلیدی مانیتور میکنم. معماریهای رویدادمحور مقیاسپذیری و جداسازی عالی فراهم میکنند، اما نیازمند مدیریت دقیق اسکیما و هندلینگ خطا هستند.
دریافت پاسخهای مصاحبه شخصیسازیشده برای درخواست شغلی خاص شما
رزومه و/یا شرح شغلی را بارگذاری کنید