در چشمانداز رقابتی توسعه نرمافزار، سازمانها به دنبال بهینهسازی چرخه عمر توسعه نرمافزار (SDLC) برای افزایش سرعت، بهبود کیفیت و کاهش اصطکاک هستند. با توجه به اینکه سرویسهای Workleap از صدها پروژه #C و چندین راهحل داتنت تشکیل شدهاند، تیم مهندسی پلتفرم این شرکت الگوهای تکراری و مشکلسازی را در مخازن کد (code repositories) شناسایی کرد. از جمله این مشکلات میتوان به ناسازگاری در سبک کدنویسی، کیفیت و عملکرد بین پروژههای مختلف اشاره کرد که ناشی از کپی کردن کدهای اولیه (boilerplate) توسط توسعهدهندگان بود.
تحلیل صدها درخواست بازنگری (pull requests) نشان داد که بخش قابل توجهی از نظرات مربوط به مسائل سبک کدنویسی است. این موضوع باعث کاهش بهرهوری و افزایش زمان چرخه توسعه (cycle time) میشد، زیرا گفتگوهای طولانی بر سر مسائل جزئی میتوانست فرآیند ادغام کد را به تعویق بیندازد. علاوه بر این، مشکلات مهمی مانند مسائل مربوط به عملکرد، کیفیت و امنیت نیز در این درخواستها نادیده گرفته میشدند. این مسائل به عوامل مختلفی نسبت داده میشد، از جمله تعداد زیاد نظرات جزئی که تمرکز بازبینها را از مسائل مهمتر منحرف میکرد. همچنین، هشدارهای (warnings) مختلفی در زمان ساخت (build time) ظاهر میشدند که جلوی ادغام کد مربوطه را نمیگرفتند.
این یافتهها به کشف مشکلات دیگری در خصوص ویژگیهای MSBuild منجر شد، مانند غیرفعال بودن پیشفرض انواع مرجع Nullable (Nullable reference types) در برخی نقاط، تنظیم بودن سطح تحلیل Roslyn (Roslyn analysis level) روی حداقل مقدار پیشفرض، عدم اعمال اجباری سبک کدنویسی در زمان ساخت و فعال نبودن حسابرسی بستههای NuGet. برای حل این مشکلات، Workleap به دنبال راهحلی مقیاسپذیر بود که هم استانداردهای کدنویسی را اعمال کند و هم به راحتی در پروژههای موجود ادغام شود.
ساخت استانداردهای کدنویسی قابل استفاده مجدد داتنت
تیم Workleap تصمیم گرفت به جای اتکا به StyleCop، از ابزارهای تحلیلگر (analyzers) و اصلاح کد (code fixes) مبتنی بر Roslyn استفاده کند. نتیجه این تلاش، بیش از ۲۰۰ خط پیکربندی بود که به دقت برای نیازهای اکثریت پروژهها تنظیم شد. این پیکربندی شامل جزئیاتی بسیار ریز، از جمله محل قرارگیری نقطه، ویرگول، پرانتز، فاصلهگذاری، ترتیب اصلاحکنندههای دید (visibility modifiers) و نامگذاری متغیرها و انواع است.
پس از تعریف سبک کدنویسی، بیش از ۸۰۰ قانون تحلیلگر Roslyn برای کیفیت، عملکرد و امنیت پیکربندی شد. از جمله مثالهای برجسته میتوان به جلوگیری از شمارش چندگانه IEnumerable، ارسال پارامترهای CancellationToken به متدها، استفاده از throw برای حفظ جزئیات پشته (stack details)، عدم استفاده از توابع مشتقگیری کلید منسوخ یا ضعیف و انتظار (awaiting) برای Taskها به جای استفاده از .Result اشاره کرد. این کار به گونهای انجام شد که سربار قابل توجهی بر زمان ساخت اضافه نشود و در کمال تعجب، زمان ساخت پروژهها در همان سطح قبلی یا حتی کمی بهتر باقی ماند.
پیکربندی ویژگیهای MSBuild و ابزارهای تحلیلگر
به موازات پیکربندی قوانین Roslyn، ویژگیهای MSBuild نیز بهینهسازی شدند تا ساختهای ثابت (consistent)، قطعی (deterministic) و با عملکرد بالا را تضمین کنند. این تنظیمات به گونهای اعمال شدند که تنها در صورت عدم وجود مقدار قبلی در پروژه، مقداردهی شوند. ویژگیهای مهمی که پیکربندی شدند عبارتند از:
- AnalysisLevel: این ویژگی روی
latest-all تنظیم شد تا تمامی جدیدترین ویژگیهای تحلیل Roslyn فعال شوند. - TreatWarningsAsErrors: این ویژگی در محیطهای ادغام مداوم (CI) یا پیکربندی Release روی
true قرار گرفت تا هیچ هشداری در کد تولیدی نادیده گرفته نشود. - EnforceCodeStyleInBuild: این ویژگی روی
true تنظیم شد تا سبک کدنویسی در زمان ساخت اجباری شود و از ادغام کدهای غیرمنطبق جلوگیری کند. - NuGetAudit: این قابلیت به همراه چندین ویژگی مرتبط دیگر فعال شد تا تمام بستههای NuGet از نظر آسیبپذیریها بررسی شوند.
- AccelerateBuildsInVisualStudio و RestoreUseStaticGraphEvaluation: این ویژگیها برای بهبود عملکرد ساخت در سناریوهای خاص فعال شدند.
علاوه بر این، وابستگی به Microsoft.CodeAnalysis.BannedApiAnalyzers نیز اضافه شد تا استفاده از برخی APIهای شناختهشده و مشکلساز داتنت، مانند DateTime.Now یا Newtonsoft.Json به جای System.Text.Json داخلی، مسدود شود. اگرچه انواع مرجع Nullable به صورت پیشفرض فعال نشدند، اما در الگوهای پروژههای جدید، ویژگی Nullable فعال است تا استفاده از این قابلیت توصیه شود.
بسته NuGet، راهحل نهایی
تمام این تلاشها بدون یک راهکار توزیع ساده و کارآمد بیفایده بود. کپی کردن صدها خط پیکربندی در هر پروژه یک کابوس نگهداری بود. خوشبختانه، با استفاده از قابلیتهای .NET SDK، تمام این پیکربندیها در یک بسته NuGet واحد قرار داده شدند. این بسته شامل فایلهای .editorconfig و سایر ویژگیهای MSBuild است که به طور خودکار در پروژههایی که بسته را نصب میکنند، اعمال میشوند. این قابلیت، به توسعهدهندگان اجازه میدهد تنها با اضافه کردن یک بسته، تمامی استانداردهای کدنویسی را فعال کنند.
استقبال و نتایج حاصل از استانداردها
برای تشویق توسعهدهندگان به پذیرش این ابزار، Workleap از رویکرد «شرمساری مثبت» (positive shaming) استفاده کرد. با اعمال استانداردها روی پروژههای کلیدی شرکت و ارائه مستندی که مزایا را توضیح میداد، هزاران نمونه از کدهای غیرمنطبق نشان داده شد تا تمایل به اصلاح آنها ایجاد شود. این رویکرد با موفقیت همراه بود و به سرعت به مهاجرت بیش از ۸۰٪ پروژهها به استانداردهای جدید منجر شد.
مزایای حاصل از این استانداردسازی شامل موارد زیر است:
- کاهش زمان بررسی کد: مسائل مربوط به سبک کدنویسی اکنون به طور خودکار یا توسط بررسیهای CI (Continuous Integration) حل میشوند.
- بهبود کیفیت، عملکرد و امنیت کد: فعالسازی قوانین تحلیل Roslyn به صورت پیشفرض، به شناسایی زودهنگام بسیاری از مشکلات کمک کرده است.
- افزایش دانش توسعهدهندگان: قرار گرفتن در معرض قوانین و پیشنهادهای جدید در محیطهای توسعه یکپارچه (IDE)، باعث یادگیری بهترین شیوهها و تبدیل شدن توسعهدهندگان به متخصصان C# بهتر میشود.
- کاهش کدهای اولیه تکراری: فایلهای
.editorconfig بزرگ و فایلهای .csproj سادهسازی شدند و پیکربندیها به صورت متمرکز در یک مکان قرار گرفتند. - یکنواختی در بین پروژهها: توسعهدهندگان میتوانند انتظار سبک کدنویسی یکسانی را در تمام پروژهها داشته باشند، که اصطکاک هنگام جابهجایی بین آنها را کاهش میدهد.
- ساخت سریعتر: برخی از راهحلهای بزرگ، تا ۲۰٪ کاهش زمان ساخت را تجربه کردند که به دلیل حذف قوانین غیرضروری StyleCop و استفاده از قوانین داخلی و پرفورمنسمحور داتنت بود.
Workleap خاطرنشان میکند که استانداردهای کدنویسی، سلیقهای هستند و این قوانین برای آنها به بهترین نحو عمل کرده است. با این حال، توسعهدهندگان میتوانند به راحتی
مخزن (repository) را فورک (fork) کرده و قوانین را مطابق با ترجیحات خود تغییر دهند.