وقتی یک Component در Design System مشکل دارد، واکنش طبیعی معمولاً این است که آن را بهتر کنیم.API را اصلاح میکنیم، Variant جدید اضافه میکنیم، Documentation را کاملتر میکنیم، Accessibility را بهبود میدهیم یا Component را با نیازهای جدید محصولات هماهنگ میکنیم.اما قبل از تمام این کارها شاید یک سؤال مهمتر وجود داشته باشد:آیا این Component اصلاً هنوز باید بخشی از Design System باشد؟Design Systemها معمولاً برای اضافهکردن چیزهای جدید فرایند مشخصی دارند. Proposal نوشته میشود، Use Caseها بررسی میشوند، Component طراحی و توسعه پیدا میکند و بعد از Review وارد Library میشود.اما مسیر خروج معمولاً به همین اندازه واضح نیست.نتیجه این است که سیستم در اضافهکردن خوب عمل میکند، اما در حذفکردن نه.درحالیکه Maintenance فقط به معنی سالم نگه داشتن چیزهایی که داریم نیست؛ گاهی یعنی تصمیم بگیریم دیگر چیزی را نگه نداریم.
هر Component یک هزینه پنهان دارد
فرض کنید Componentی سه سال پیش وارد Design System شده است. امروز فقط دو محصول از آن استفاده میکنند و برای Use Case اصلی آن هم راهحل مناسبتری در سیستم وجود دارد.Component هنوز کار میکند. Bug جدی ندارد و حذف فوری آن هم ضروری نیست.پس چرا باید درباره Retirement آن فکر کنیم؟چون وجود یک Component رایگان نیست.تا زمانی که Component بخشی از Design System است، تیم عملاً تعهدی نسبت به آن دارد: باید با تغییر Tokenها سازگار بماند، Accessibility آن بررسی شود، تغییرات Framework را تحمل کند، Documentation آن بهروز شود، Bugهایش بررسی شوند و Breaking Changeهایش مدیریت شوند.Carbon در Checklist مربوط به Componentهای پایدار، Stability، Developer Experience، Accessibility، Documentation و Migration Experience را بخشی از مسئولیت یک Component پایدار میداند. [1]بنابراین سؤال Maintenance فقط این نیست:«آیا این Component هنوز کار میکند؟»سؤال دقیقتر این است:«آیا ارزشی که این Component ایجاد میکند هنوز هزینه نگهداری آن را توجیه میکند؟»این تفاوت کوچک، Maintenance را از Bug Fixing به Portfolio Management نزدیک میکند.
استفاده شدن الزاماً دلیل کافی برای باقی ماندن نیست
یکی از سختترین دلایل برای حذف نکردن یک Component این است:«هنوز چند تیم از آن استفاده میکنند.»این اطلاعات مهم است، اما بهتنهایی تصمیم را مشخص نمیکند.فرض کنید Component قدیمی LegacyTable هنوز در هشت محصول استفاده میشود، اما Design System دو سال است DataTable جدیدی دارد که Accessibility بهتر، API پایدارتر و Documentation کاملتری ارائه میدهد.بالا بودن Usage در این شرایط ممکن است نشاندهنده ارزش Component قدیمی نباشد؛ ممکن است فقط نشان دهد Migration اتفاق نیفتاده است.بنابراین Usage باید همراه با سؤالهای دیگری خوانده شود:آیا پروژههای جدید هم این Component را انتخاب میکنند؟آیا برای آن Alternative بهتری وجود دارد؟آیا Usage آن در حال افزایش است یا کاهش؟آیا تیمها به دلیل مناسب بودن Component از آن استفاده میکنند یا فقط چون Migration پرهزینه است؟اگر فقط تعداد Instanceها را ببینیم، ممکن است Legacy را با Value اشتباه بگیریم.
Maintenance باید درباره آینده تصمیم بگیرد، نه فقط گذشته
فرض کنید Componentی داریم که امروز بدون مشکل کار میکند، اما Architecture آن با جهت آینده سیستم سازگار نیست.برای مثال، ممکن است Styling آن هنوز به Token Architecture قدیمی وابسته باشد، API آن با Componentهای جدید همراستا نباشد یا برای Frameworkی طراحی شده باشد که سازمان در حال فاصله گرفتن از آن است.در این شرایط دو انتخاب داریم.میتوانیم Component را بازنویسی کنیم تا با معماری جدید سازگار شود.یا میتوانیم بپرسیم:آیا ارزش این Component آنقدر بالاست که Migration خود Component را توجیه کند؟این سؤال مهم است، چون گاهی تیمها برای جلوگیری از Breaking Change، ماهها روی زنده نگه داشتن چیزی سرمایهگذاری میکنند که اگر امروز قرار بود درباره ورودش به Design System تصمیم بگیرند، احتمالاً اصلاً پذیرفته نمیشد.پس میتوانیم یک Stress Test ساده داشته باشیم:اگر این Component امروز در Design System وجود نداشت، آیا با دانشی که الان داریم دوباره آن را وارد سیستم میکردیم؟اگر پاسخ «نه» باشد، شاید مسئله دیگر Improvement نیست؛ مسئله Retirement است.
Deprecated کردن با حذف کردن فرق دارد
اینجا یکی از مشکلات رایج Maintenance ظاهر میشود.یک Component را Deprecated میکنیم، روی Documentation یک Warning قرار میدهیم و فکر میکنیم مسئله حل شده است.اما Component همچنان در Package وجود دارد، تیمها همچنان از آن استفاده میکنند و گاهی حتی پروژههای جدید هم آن را Import میکنند.در این شرایط Deprecation تبدیل به یک وضعیت دائمی شده است.درحالیکه سیستمهایی مثل USWDS میان Deprecated و Retired تفاوت مشخصی قائل میشوند. در Lifecycle این سیستم، Component در مرحله Deprecated از Active Support خارج میشود اما هنوز در Codebase وجود دارد؛ مرحله Retired زمانی است که Component واقعاً از Codebase حذف شده و Lifecycle آن پایان پیدا میکند. [2]Atlassian هم Deprecation را یک فرایند انتقال میبیند، نه صرفاً یک Label. در Release Phases آنها، Feature منسوخشده دیگر Supported نیست، Alternative پیشنهادی دارد و بعد از پایان Deprecation Period حذف خواهد شد. [3]پس Deprecation بهتر است وضعیت موقت در مسیر خروج باشد، نه قبرستان Componentهایی که هیچکس حاضر نیست حذفشان کند.
قبل از حذف، باید بفهمیم چرا هنوز استفاده میشود
اگر Componentی را Deprecated کردهایم اما یک سال بعد Usage آن تقریباً تغییری نکرده، اولین نتیجه نباید این باشد که «تیمها Migration را جدی نگرفتهاند.»شاید Migration Path مشکل دارد.ممکن است Alternative جدید تمام Use Caseهای Component قبلی را پوشش ندهد. شاید Documentation انتقال کافی نیست. شاید Migration هزینه فنی زیادی دارد یا تیمها حتی نمیدانند Component قدیمی Deprecated شده است.به همین دلیل Maintenance فقط تصمیم درباره خود Component نیست؛ بخشی از آن طراحی مسیر خروج Component است.Carbon در راهنمای Deprecation خودش برای Packageهای قدیمی فقط اعلام نمیکند که چیزی Deprecated شده؛ مشخص میکند چه چیزی باید جایگزین آن شود و برای Migration به نسخه جدید راهنما ارائه میدهد. [4]در Atlassian هم ابزارهای توسعه میتوانند استفاده از Tokenهای Deprecated را شناسایی کنند و هنگام توسعه Warning بدهند. یعنی Migration فقط یک پیام داخل Documentation نیست؛ میتواند وارد Workflow روزمره توسعهدهنده شود. [5]این نگاه مهم است:اگر میخواهیم چیزی را از سیستم حذف کنیم، باید حذف شدن آن را هم Design کنیم.
همه Componentهای ضعیف نباید حذف شوند
از طرف دیگر، پایین بودن Usage هم بهتنهایی دلیل Retirement نیست.ممکن است Componentی کماستفاده باشد اما مسئلهای بسیار مهم را حل کند. مثلاً Pattern خاصی برای Accessibility یا یک Workflow حساس ممکن است فقط در چند نقطه استفاده شود، اما جایگزین کردن آن برای هر Product هزینه زیادی داشته باشد.پس نه Usage بالا الزاماً به معنی Keep است و نه Usage پایین الزاماً به معنی Remove.برای همین شاید بهتر باشد تصمیم Maintenance را براساس چند Signal همزمان بگیریم.
یک مدل ساده برای تصمیم Keep / Improve / Deprecate / Remove
برای بررسی هر Component میتوانیم چهار سؤال بپرسیم:1. Value : هنوز چه ارزشی ایجاد میکند؟چند Product واقعاً به آن نیاز دارند؟ آیا مسئلهای System-level حل میکند؟ آیا تیمهای جدید هم آن را انتخاب میکنند یا فقط Legacy Usage باقی مانده است؟2. Fitness : هنوز راهحل مناسبی برای آن مسئله است؟آیا Accessibility، API، UX و Architecture آن با استاندارد فعلی سیستم هماهنگ است؟ آیا Alternative بهتری داریم؟3. Cost : نگهداری آن چه هزینهای دارد؟چند Bug و Support Request ایجاد میکند؟ تغییر Foundations چه مقدار Rework برای آن ایجاد میکند؟ آیا وجودش Complexity سیستم را افزایش داده است؟4. Exit Cost : حذف آن چقدر هزینه دارد؟چند Product باید Migration انجام دهند؟ آیا Replacement آماده است؟ آیا میتوان Migration را Automate کرد؟ Breaking Change آن چقدر گسترده است؟از ترکیب این چهار Signal میتوانیم به چهار تصمیم برسیم:Keep زمانی که Value بالاست و Component همچنان Fit است.Improve زمانی که Value بالاست اما Fitness کاهش پیدا کرده است.Deprecate زمانی که Value یا Fitness کاهش پیدا کرده و Alternative مشخصی وجود دارد، اما Migration هنوز باید انجام شود.Remove زمانی که Migration Path طی شده و ادامه حضور Component دیگر ارزش قابل دفاعی ایجاد نمیکند.این Framework استاندارد رسمی Design System نیست؛ یک مدل پیشنهادی برای تبدیل Maintenance از مجموعهای از Fixهای پراکنده به تصمیمگیری درباره Lifecycle سیستم است.
گاهی حذف نکردن، خودش Debt تولید میکند
نگه داشتن Component قدیمی فقط هزینه Maintenance ندارد؛ روی تصمیمهای آینده هم اثر میگذارد.فرض کنید Library دو Date Picker، سه نوع Modal و دو روش مختلف برای Navigation دارد. حتی اگر همه آنها Document شده باشند، هر گزینه اضافی سؤال دیگری برای مصرفکننده ایجاد میکند:کدام یکی را باید استفاده کنم؟کدام نسخه جدیدتر است؟آیا نسخه قدیمی هنوز Supported است؟چرا این دو Component تقریباً یک کار انجام میدهند؟در این نقطه Legacy فقط Code Debt نیست؛ Decision Debt هم ایجاد کرده است.هر چیزی که در Library باقی میماند، بخشی از Surface Area سیستم است که مصرفکنندگان باید آن را بفهمند.به همین دلیل حذف میتواند خودش یک قابلیت Design System باشد.سیستمی که بتواند Component جدید اضافه کند اما نتواند Component قدیمی را بازنشسته کند، بهمرور فقط بزرگتر میشود؛ نه الزاماً بهتر.
Retirement هم باید بخشی از Lifecycle باشد
USWDS برای Componentها Lifecycle مشخصی از Proposal تا Development، Stable، Deprecated و در نهایت Retired تعریف کرده است. حتی یک Component پایدار هم وضعیت دائمی ندارد؛ اگر دیگر Requirements را برآورده نکند یا نیازی به آن نباشد، میتواند وارد مسیر خروج شود. [2]این نگاه یک پیام مهم دارد:Stable به معنی Permanent نیست.ممکن است تصمیمی که سه سال پیش برای سیستم درست بوده، امروز دیگر بهترین تصمیم نباشد.نیاز کاربران تغییر میکند، Technology تغییر میکند، Accessibility Research بهتر میشود و خود Design System هم بالغتر میشود.برای نمونه، USWDS اخیراً اعلام کرده Component مربوط به Validation به دلیل مشکلات مهم Usability و Accessibility که در Testing و Research مشخص شده، برای حذف در نسخههای آینده در نظر گرفته شده است. [6]یعنی وجود قبلی Component در سیستم، دلیل کافی برای ادامه وجودش نیست.Evidence جدید میتواند تصمیم قدیمی را تغییر دهد.
Maintenance یعنی مدیریت تعهدات سیستم
شاید بهتر باشد Maintenance را فقط بهعنوان «نگهداری Componentها» نبینیم.هر Component، Token، Pattern یا API که وارد Design System میکنیم، یک تعهد ایجاد میکند. تیمهای محصول روی آن Build میکنند و انتظار دارند سیستم تغییراتش را مسئولانه مدیریت کند.بنابراین اضافهکردن یک Component فقط اضافهکردن یک Asset نیست؛ پذیرفتن یک Maintenance Commitment است.همین موضوع باعث میشود تصمیم حذف هم حساس باشد. نمیتوانیم چیزی را فقط چون دیگر دوستش نداریم از Library حذف کنیم. باید Alternative، Migration Path، Communication و زمان کافی برای انتقال وجود داشته باشد.Carbon در Guidelineهای API خودش روی همین نکته تأکید میکند: قبل از Removal باید Deprecation انجام شود، زمان کافی برای Deprecation در نظر گرفته شود و Migration Experience توسعهدهندگان بخشی از تصمیم باشد. [1]پس یک سیستم سالم باید در هر دو جهت Discipline داشته باشد:ورود به سیستم باید سختتر از ساختن یک Component باشد و خروج از سیستم هم باید مسئولانهتر از زدن یک Deprecated Badge باشد.
جمعبندی
Maintenance فقط این نیست که Componentهای موجود را Update کنیم، Bugهایشان را ببندیم و Documentationشان را بهروز نگه داریم.گاهی مهمترین تصمیم Maintenance این است که دیگر روی چیزی سرمایهگذاری نکنیم.برای همین قبل از اینکه Component قدیمی را Redesign کنیم، Variantهایش را اصلاح کنیم یا API آن را دوباره بنویسیم، شاید ارزش داشته باشد چهار چیز را بررسی کنیم:Value × Fitness × Maintenance Cost × Exit Costو بعد تصمیم بگیریم:Keep / Improve / Deprecate / Removeچون Design System سالم فقط سیستمی نیست که بتواند چیزهای جدید را بهخوبی وارد کند.باید بتواند چیزهایی را که دیگر به آنها نیاز ندارد هم با اطمینان و بدون آسیب به مصرفکنندگان، از سیستم خارج کند.شاید یکی از نشانههای بلوغ Maintenance همین باشد:قبل از اینکه بپرسیم «چطور این Component را بهتر کنیم؟»، بپرسیم «اگر امروز این Component وجود نداشت، آیا دوباره آن را میساختیم؟»
کامنتها
…