این مقاله از راکت برای کسانی مفید است که هرنوع کد backend مینویسند و ربطی به میزان تجربه آنها در این زمینه ندارد، حتی برای برنامهنویس fully backend و یا fullstack و یا حتی برای برنامهنویس frontend که گاهی برنامهنویسی backend انجام میدهند هم مفید است و اینکه از کدام پلتفرم (Node.js، PHP، Python، Ruby،Java ، .NET، Golang و ...) استفاده میکنند هم چندان اهمیتی ندارد.
در اینجا با ده تا از اشتباهات رایج و فهرستی از 16 اشتباه دیگر که توسعهدهندگان backend مرتکب میشوند، آشنا میشوید. پس از خواندن این مقاله، متوجه میشوید که چگونه از وقوع این اشتباهات جلوگیری کنید، با عواقب آنها و نحوه برخورد با آنها درصورت وقوع آشنا میشوید.
۱. استفاده بیشازحد از فناوری یا مهندسی بیشازحد یا بهینهسازی بیشازحد
مشکل:
من در لیست اشتباهات، این اشتباه را در جایگاه اول قرار دادم چون اشتباه رایجی است و اگر بهموقع حل نشود، رفع آن در آینده دشوار میشود و گاهی ممکن است لازم باشد بخش زیادی از یک پروژه دوباره نوشته شود.
استفاده زیاد از فناوری یعنی استفاده از موارد نامناسب مانند رعایت نکردن قوانین SOLID و DRY، توابع یا روشهای طولانی، تعداد زیادی سطوح تورفتگی، حذف تست (در قسمت بعدی توضیح داده میشود)، حذف مستندسازی، نامگذاری ضعیف متغیرها، نامگذاری ضعیف پیغامهای commit، توجه ناکافی به عملکرد و سایر موارد.
همچنین میتواند به معنای یک معماری نامناسب هم باشد. اگر کد فقط ظاهر نامناسبی داشته باشد میتوان آن را فایل به فایل و یا میکروسرویس به میکروسرویس، اصلاح کرد اما اگر کل سیستم بهصورت نامناسب طراحی شده باشد، اصلاح آن بسیار دشوار میشود.
مهندسی بیشازحد زمانی اتفاق میاُفتد که توسعهدهنده backend از یک الگوی بسیار پیچیده استفاده میکند آنهم درحالیکه یک راهحل سادهتر وجود دارد و با این کار قوانین KISS یا YAGNI را نقض میکند.
بهینهسازی بیشازحد بهمعنای توجه بیشازحد به عملکرد درجایی است که نیاز چندانی به این کار نیست مثل کوتاه کردن یک بازه زمانی از 0.1 ثانیه به 0.01 ثانیه آنهم درحالیکه روش دیگر حدود 15 ثانیه طول میکشد.
عواقب:
در طولانیمدت هرکدام از این مشکلات فرعی باعث اتلاف وقت زیادی میشود که درنهایت توسعه هر ویژگی جدید سختتر و غیرممکن میشود. درموارد حادتر، زمان اجرای هر ویژگی بهصورت تصاعدی افزایش مییابد چون باید تمام مسیرهای ممکن تست شود یا تمام شروط موجود بروزرسانی شوند و ویژگیهای قدیمی با ویژگیهای جدید ترکیب شوند.
هم روشهای فنی بیشازحد و هم مهندسی بیشازحد، پشتیبانی از کد را دشوار میسازند. بهینهسازی بیشازحد هم اگر همراه با مهندسی بیشازحد همراه باشد که در اغلب موارد هم هست، ممکن است این نتیجه را داشته باشد.
روند جلوگیری:
توسعه دهندگان backend باید زمان توسعه هر ویژگی جدیدی به این مسئله توجه کنند که ویژگیهای دیگری هم در آینده به کد اضافه خواهد شد؛ بنابراین باید بسنجند که ارزش بهینهسازی و یا مهندسی بیشازحد را دارد یا نه.
محدوده عمر عملکردی (تا چه مدتزمانی این ویژگی برای این محصول کاربرد دارد) و محدوده عمر فنی (تا چه مدتزمانی این ویژگی با فناوریهای موجود مطابقت دارد) هم باید درنظر گرفته شوند. تمام ویژگیها باید مجدداً مرور شوند و ایرادات احتمالی باید رفع شوند.
روش برخورد:
وقتیکه متوجه میشویم که موارد فنی زیاد یا مهندسی بیشازحد در کد ما اتفاق افتاده است و پشتیبانی از آن را دشوار ساخته است باید تا جاییکه امکان دارد کد را سادهسازی کنیم.
اگرچه تا زمانیکه بهینهسازی بیشازحد با مهندسی بیشازحد همراه نشده باشد، برای ما مفید است چون اجرای کد سریعتر انجام میشود؛ البته زمان زیادی را قبلاً بهخاطر انجام بهینهسازی بیشازحد تلف کردهایم ولی زمان را نمیتوان به عقب برگرداند.
۲. حذف تست یا تست نکردن سطوح هرم
مشکل:
حذف تست یعنی فرایندی را تست نکنید و یا حتی کلاً هیچ تستی برای ویژگیهای جدید انجام ندهید. تست نکردن هر سطح هرم به این معنی است که حداقل در یکی از سطوح آن تستی انجام نشده باشد.
عواقب:
این کار باعث میشود که پشتیبانی از کد برای توسعه دهندگان backend دشوار شود چون میترسند هر قسمتی را تجزیه کنند و این باعث افزایش نواقص میشود. همواره به یاد داشته باشید که تست کلی غیرممکن است.
روند جلوگیری:
نوشتن تمام تستها در هر سطح با هم با یک ویژگی جدید و انجام تستها با هم با یک ایراد رفعشده میتواند کمککننده باشد. تستها باید بهصورت روتین روزانه انجام شوند. این روند ممکن است توسط هر توسعهدهنده backend بهصورت جداگانه و با استفاده از (TDD (test-driven development و تحلیلهای کد استاتیکی و بررسی پوشش کد انجام شود.
رویکرد دیگری که چندان رایج نیست، نوشتن تست در یک گروه است به اینصورت که یک نفر کد را مینویسد و یک توسعهدهنده دیگر آن را بررسی میکند یا اینکه گاهی از برنامهنویسی مشترک استفاده شود.
ممکن است گاهی شخصی با نوشتن تست مخالفت کند. این شخص ممکن است یک توسعهدهنده backend تازهکار باشد که هیچ تجربهای در نوشتن تست ندارد و یا مالک محصولی باشد که میخواهد در سریعترین زمان ممکن محصولش آماده شود؛ بنابراین این موضوع خیلی اهمیت دارد که برای آنها توضیح دهید چرا تستها اینقدر مهم هستند.
دلایل اصلی عبارتاند از: عملکرد بالای برنامه در بلندمدت، گاهی حتی عملکرد بالای آن در کوتاهمدت اگر ویژگی موردنظر پیچیده باشد، نواقص کمتر و درنهایت طراحی یک معماری بهتر. برای توضیحاتی با جزئیات بیشتر میتوانید عبارت «چرا باید تست بنویسم؟» را در گوگل، Quora و یا یوتیوب جستجو کنید.
نحوه برخورد:
بهطورکلی انجام موارد پیشگیرانه از بروز یک سری ایرادات جلوگیری میکند، اما باید تحلیل کنید که کدام ویژگیها برای انجام تست از اولویت بالاتری برخور دارند.
۳. حذف بررسی و مرور کد
مشکل:
حذف بررسی و مرور کد به این معنی است که کد برای عرضه آماده شود بدون اینکه لااقل یک توسعهدهنده backend دیگر بهجز خود نویسنده آن را بررسی کند.
حذف تحلیل استاتیکی کد یعنی آمادهسازی کد برای عرضه بدون تحلیل آن بهوسیله یک ابزار مثل ESLint برای جاوااسکریپت یا TSLint برای TypeScript.
عواقب:
عواقب احتمالی آن عبارتاند از کارکرد نامناسب و یا کارکرد کد متناقض که باعث میشوند پشتیبانی از کد دشوار شود و کد آسیبپذیر شود و مدیریت سایر موارد دشوار شود.
روند جلوگیری:
برای جلوگیری از وقوع این اتفاق، هر (PR (Problem Reports یا (MR (Maintenance Release را قبل از ادغام کردن (و البته قبل از اینکه هر قسمتی از کدتان را در GitHub یا Gitlab قرار دهید)، بررسی کنید و بعد از انجام هر commit از ادغام پیوسته برای اجرای تحلیل استاتیکی کد استفاده کنید.
نحوه برخورد:
نحوه برخورد با این اشتباه این است که باید اقداماتی را مانند بررسی کد، سازماندهی تجزیهوتحلیل استاتیکی کد و مرور کدی که در قسمت دیفالت وجود دارد اما بررسی نشده است، انجام دهیم.
گاهی اوقات مشکلاتی برای بررسی کد بهوجود میآید که برای رفع آنها موارد زیر را به شما توصیه میکنم:
- تیم منفرد توسعهدهنده backend: یک توسعهدهنده frontend از یک پروژه مشابه یا یک توسعهدهنده backend از یک پروژه دیگر یا حتی هردوی آنها باید کد شما را بررسی کنند!
- توسعه دهندگان backend در بازههای زمانی مختلفی کار میکنند: تقسیم تیم backend به تیمهای فرعی از منظر بازه زمانی یا حتی کارکردن همکاران در بازه زمانی یکسان.
- قراردادن تصادفی در یک شاخه دیفالت یا ادغام کد بدون بررسی آن: GitHub یا Gitlab را طوری تنظیم کنید که از انجام چنین اشتباهاتی جلوگیری کند.
- CTO یا شخصی در جایگاه بالا که بدون بررسی کد آن را عرضه میکند: بااحترام از آنها بخواهید که PR/MR را باز کنند و حتی اگر یک کار فوری پیش آمده است، مدتی صبر کند تا کسی کد را برای جلوگیری از بروز مشکلات اساسی بررسی کند. رفع ایرادات بدون بررسی کد گاهی موجب آسیب بیشتر میشود.
۴. استفاده زیاد از فناوریها، کتابخانهها یا رویکردهای اینچنینی
مشکل:
بهطورکلی، توسعه دهندگان backend باید از فناوری مشابه (زبان برنامهنویسی یا فریمورک یا کتابخانه یا DBMS یا یک API خارجی) و الگوی مشابه برای حل یک مسئله استفاده کنند. برای مثال برای برنامهنویسی با سطح عملکردی بالا از جاوااسکریپت.
البته میتوان بهجای جاوااسکریپت از پایتون، بهجای Moment.js از Day.js، بهجای MongoDB از Couch DB یا یک کلاس بهجای توابع استفاده کرد اما شما خودتان باید تصمیم بگیرید که از کدام روش میخواهید در پروژهتان استفاده کنید. در موارد استثنا میتوانید یک فناوری جدید را بهکار ببرید اما بعداً باید از این فناوری در کل پروژهتان استفاده کنید و یا اینکه آن را معرفی کنید.
عواقب:
بااستفاده از فناوریهای متناقض یا رویکردهایی که پشتیبانی را دشوار میسازد، به دلیل اینکه به دانش زیادی نیاز دارد، ریسک بهوجود آمدن ایرادات زیاد و آسیبپذیری زیاد بهخاطر تعداد زیاد مشتقات و نصب کندتر بهخاطر زیاد بودن آنها، بیشتر است.
روند جلوگیری:
استفاده از فناوریها و الگوهای مشابه برای یک مسئله و بررسی کد.
نحوه برخورد:
ما باید تصمیم بگیریم که کدام فناوری یا رویکرد برای پروژهمان مناسب است و باقی کد را مدام اصلاح کنیم تا همیشه از همان فناوری یا رویکرد استفاده شود.
۵. حذف نسخه پشتیبانگیری خودکار از پایگاه داده محصول
مشکل:
ممکن است قسمتهایی از پایگاه داده محصول یا کل آن حذف شود و یا دادههای بیارزشی وارد آن شود که منجر به ایراداتی شود. دادههای محصول معمولاً حتی ارزشمندتر از کد ما هستند زیرا کد نتیجه کار چندین توسعهدهنده backend است اما دادههای محصول نتیجه کار هزاران یا حتی چندین میلیون کاربر برنامه هستند.
علاوه بر این، کد ما میتواند با برنامههای کاربردی دیگری جایگزین شود؛ درحالیکه پایگاه داده محصول ممکن است بدون داشتن نسخه پشتیبان بازیابی نشود.
عواقب:
کاربران سیستم ما ممکن است نتیجه کارشان را از دست بدهند. برخلاف سایر موارد، درصورت ازبین رفتن دادههای محصول احتمالاً باید خسارت پرداخت شود.
روند جلوگیری:
تنظیم نسخه پشتیبانگیری خودکار مثل MongoDB Atlas که نسخه پشتیبان خودکار بهصورت دورهای ارائه میکند.
نحوه برخورد:
نسخه پشتیبانگیری خودکار ASAP را تنظیم کنید. اگر پایگاه داده بدون نسخه پشتیبان پاک شده باشد، انجام این کار خیلی دیر شده است اما اگر خوششانس باشیم ممکن است بتوانیم بخشی از دادهها را از logs بازیابی کنیم یا از همتیمیهایمان بپرسیم که بهصورت دستی نسخه پشتیبان تهیه کردهاند یا نه.
۶. حذف توسعه میکروسرویسهای محصول و هشداردهی
مشکل:
محصول باید همیشه دردسترس باشد، بنابراین اگر میکروسرویسها چندین ساعت از کار بیافتند مشکلات زیادی بهوجود میآید. باید تمام میکروسرویسها پایش شوند و اگر یکی از آنها از کار افتاد، باید سریعاً آنرا راهاندازی کنیم.
این، یک مشکل DevOps است اما در کنار کار DevOps، توسعه دهندگان backend نیز باید گوش به زنگ باشند.
عواقب:
منجر به ایرادات اساسی میشود که ناشی از کارکرد نادرست میکروسرویس یا کل سیستم وقتیکه میکروسرویسهای اصلی از کار میافتند.
روند جلوگیری:
برای میکروسرویس هر محصول باید یک سیستم پایش درنظر گرفته شود؛ بهعنوان یکی از اولین کارهایی که پس از ساخت محیط محصول باید انجام شود.
نحوه برخورد:
باید مانیتورهای حذفشده را تنظیم کنیم و تمام میکروسرویسهای از کار افتاده را مجدداً راهاندازی کنیم.
۷. ایجاد یک مدل بدون یک برنامه مناسب
مشکل:
model یک قسمت مهم از معماری سیستم است بنابراین اگر بهدرستی طراحی نشده باشد، باعث بروز مشکلاتی میشود.
عواقب:
منجر به داده نامعتبر میشود، تحلیل داده یا پشتیبانی از آن دشوار میشود و جستجوی داده بسیار کند میشود.
روند جلوگیری:
مدل باید بادقت طراحی شود، اگر تیم توسعه کوچکی دارید، با کل تیم توسعه backend درمورد آن صحبت کنید (تیمی با تقریباً 10 نفر عضو). درمورد تیمهای بزرگتر باید با تیمهای فرعی پاسخگو درمورد منطق مدل و متخصصان دادههای تخصصی یا متخصصان یک داده خاص مثل DBMS صحبت کنیم.
نحوه برخورد:
اگر تاکنون هیچ مدل نامناسبی برای محصول استفاده نشده باشد، میتوان مدل را بروزرسانی کرد و تمام دادههای نامعتبر موجود در محیطهای پایینتر را حذف کرد. اگر یک مدل نامناسب در محصول بهکار رفته باشد، در کنار بروزرسانی مدل، باید یک migration برای اصلاح داده معتبر بنویسیم.
متأسفانه در برخی موقعیتها، داده نامعتبر محصول میتواند کاملاً اصلاح شود. این اتفاق درصورتی میافتد که دادههای مبهمی را ذخیره کرده باشیم مثل نام یک شهر بهجای ID آن شهر چون ممکن است شهرهای زیادی با آن نام وجود داشته باشند.
مشکل:
این اشتباهی است که بیشتر توسط توسعه دهندگان backend تازهکار انجام میشود اما گاهی افراد باتجربه هم این اشتباه را مرتکب میشوند. Injection SQL ممکن است باعث شود که کاربر یک جستجویی را تایپ کند که بهدلیل ماهیت رشتهای در پایگاه داده اجرا شود.
بههرحال، این یک عبارت کلی است چون میتواند تزریقی از یک زبان جستجوی دیگر مثل AQL (زبان جستجوی ArangoDB) و GraphQL و سایر موارد باشد.
عواقب:
کاربر (هکر) اطلاعاتی را دریافت میکند که نباید قادر به خواندن و بدتر از آن بروزرسانی، وارد کردن یا حذف آنها باشد.
روند جلوگیری:
برای جلوگیری از این اتفاق باید پارامترها را برای هر جستجویی بررسی کنیم بهجای آنکه آنها را به هم متصل کنیم، بررسی دقیقی روی کد انجام دهیم، از رشتههای اتصال کمتری استفاده کنیم، مطمئن شویم که هر قسمت، رشتهای معتبر است و باعث بهوجود آمدن جستجوی خطرناک نمیشود، از پایگاه دادهها و پایگاه داده کاربران زیادی استفاده کنیم بنابراین حتی اگر یک کاربر بخواهد از چیزی سوءاستفاده کند، توان او محدود است و نسخه پشتیبانگیری خودکار میتواند دادههای حذفشده یا آسیبدیده را بازیابی کند.
نحوه برخورد:
موارد محدودیت را اضافه کنید و از آنها برای حفاظت از محصول استفاده کنید.
۹. عدم استفاده از log
مشکل:
Log گرفتن برای گزارش مشکلات و جمعآوری آمار درمورد استفاده از سیستم بسیار مهم است.
عواقب:
اصلاح ایرادات موجود بسیار دشوار و گاهی غیرممکن میشود.
روند جلوگیری:
باید به تمام خطاهای سرور را برای محیط محصول شامل مسیر stack، بازه زمانی، درخواست بدنه/مسیر/عنوان دسترسی داشته باشیم و درصورت امکان نام کاربری و آدرس IP مربوط به client را رمزگذاری کنیم.
علاوه بر این برای محیط dev میتوان به هر درخواستی با یک پاسخ کامل دسترسی داشت. همچنین باید اعتبارنامهها را قبل از ورود تنظیم کنیم تا از حذف آنها جلوگیری شود.
دسترسی به اطلاعات اساسی هر درخواست محصول مثل بازه زمانی، مسیر درخواست، رمزگذاری نام کاربری و IP مربوط به client هم برای جمعآوری آماری که میزان استفاده از یک endpoint را در تاریخ/زمان هفتهای که ترافیک بالایی دارد نشان بدهد، خوب است.
نحوه برخورد:
اجرای اتصال ASAP.
۱۰. ازبین رفتن جزئیات خطاهای client یا اعلام جزئیات خطاهای سرور در API
مشکل:
هر درخواست خطایی که مربوط به client است (یک کد وضعیت که با 4 شروع میشود) باید شامل جزئیاتی باشد که کاربران (مخصوصاً توسعه دهندگان frontend یا سایر توسعهدهندگان وب) بتوانند بهراحتی ایرادات را رفع کنند.
بههرحال پیغامهای خطای سرور (یک کد وضعیت که با 5 شروع میشود) هیچ جزئیاتی را بیان نمیکند چون آنها میتوانند بهصورت بالقوه برای بهرهبرداری سیستم مورداستفاده قرار بگیرند.
عواقب:
ازبین رفتن جزئیات خطای client باعث میشود که استفاده از endpoint موردنظر دشوارتر شود و جزئیات خطای سرور میتواند موجب سوءاستفاده از سیستم شود.
روند جلوگیری:
اجرای هر endpoint براساس قوانینی که تعریف شده است و بررسی کد مناسب.
تستهای endpoint شامل حالات مختلف مثل خطاهای client (بهطورکلی قادر به پیشبینی خطاهای سرور نیستیم) است.
نحوه برخورد:
تشخیص هر دو موقعیت و اصلاح آنها.
علاوه بر ده اشتباهی که نام بردیم، اشتباهات دیگری هم هستند که باید از وقوع آنها جلوگیری کرد (اهمیت این اشتباهات از سایر اشتباهات کمتر است):
- عدم استفاده از سیستم کنترل نسخه (VCS)
- ایجاد یکپارچه برای یک سیستم بزرگ
- ایجاد نانوسرویسهای زیاد
- انجام همزمان کارهایی که میتوانند در زمانهای مختلف انجام شوند
- شروع یک پروژه جدید با یک فناوری منسوخ شده
- درنظر نگرفتن موارد حاشیهای
- ازبین رفتن مستندات API
- بروزرسانی نکردن مشتقات
- عدم بهاشتراک گذاری دانش خود با سایر مهندسین backend
کلام آخر
مهم نیست که چه مقدار تجربه درزمینهٔ توسعه backend دارید، امیدوارم که مطالب این مقاله را یادگرفته باشید و بتوانید از وقوع اشتباهات رایج جلوگیری کنید و جزئیات بیشتری درمورد این اشتباهات و عواقب و روشهای برخورد و جلوگیری از آنها کسب کرده باشید.
دیدگاه و پرسش
در حال دریافت نظرات از سرور، لطفا منتظر بمانید
در حال دریافت نظرات از سرور، لطفا منتظر بمانید