EduFlow

الوحدة 4 · الأدوات والتسليم

مسارات الـ Deprecation

18 دقراءة 4 درتّب الخطوات

الدرس في لمحة

احذف الـ tokens والـ props والمكوّنات دون كسر عمل الفرق، بإطلاق البديل أولًا، وإعلان الـ deprecation بوضوح في كل قناة، وأتمتة الانتقال بالـ codemods، والحذف في إصدار major فقط.

  1. 1مسار الـ deprecation
  2. 2أعلنه كما تعلن تغييرًا في منتج
  3. 3كم من الوقت يكفي؟

لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.

الحذف أصعب جزء في إدارة نظام التصميم. إضافة مكوّن تُسعد فريقًا واحدًا؛ أما حذف مكوّن فيجعل أربعين فريقًا يقومون بعمل لم يخطّطوا له. حذف أول إصدار major في Northwind أحد عشر prop وستة tokens دفعة واحدة، مع دليل انتقال نُشر في اليوم نفسه. وبعد تسعة أشهر كان فريقان ما زالا على الإصدار الـ major القديم، ينسخان الإصلاحات بصمت. عمليات الحذف نفسها كانت صحيحة. ما كان ينقص هو الطريق إليها.

مسار الـ deprecation

خط زمني من الإصدار 4.3 إلى 5.0 وما بعده: يُطلق 4.3 البديل ويعلن deprecation الـ API القديم؛ ومن 4.4 إلى 4.9 يجري الانتقال بالـ codemods وتتبّع الاستخدام؛ ويحذف 5.0 الـ API القديم؛ ويستمرّ 4.x في تلقّي الإصلاحات ستة أشهر. 4.3.0 من 4.4 إلى 4.9 5.0.0 البديل + deprecation Codemods، تتبّع الاستخدام الحذف إصلاحات لـ 4.x
الـ deprecation تمتدّ عبر إصدارات: بديل، فتحذير، فانتقال، فحذف

كل عملية حذف في Northwind تتبع اليوم الخطوات نفسها، موزّعة على عدّة إصدارات.

1. أطلق البديل أولًا. لا يمكنك أن تطلب من الفرق الانتقال إلى شيء غير موجود. أُطلق الـ prop المسمّى variant في Button ضمن الإصدار 4.3.0 كإضافة عادية، أي إصدار minor.

2. أعلن الـ deprecation في كل القنوات دفعة واحدة. في الإصدار نفسه يُعلَّم kind كـ deprecated في كل مكان قد يصادفه فيه الناس:

Button.tsx
type ButtonProps = {
  /** @deprecated Use `variant`. Removed in 5.0.0. */
  kind?: 'primary' | 'secondary' | 'danger';
  variant?: 'primary' | 'secondary' | 'danger';
  // …rest of the props
};

const warned = new Set<string>();
function warnOnce(key: string, message: string) {
  if (process.env.NODE_ENV === 'production' || warned.has(key)) return;
  warned.add(key);
  console.warn(`[Northwind UI] ${message}`);
}

export function Button({ kind, variant, ...rest }: ButtonProps) {
  if (kind) warnOnce('button-kind', 'Button `kind` is deprecated; use `variant`. Removed in 5.0.0.');
  const resolvedVariant = variant ?? kind ?? 'secondary';
  // …render as before, using resolvedVariant
}

وسم JSDoc المسمّى @deprecated يجعل المحرّرات تشطب الـ prop أثناء الكتابة. والتحذير يظهر مرة واحدة في كل جلسة، وفي نسخ التطوير وحدها؛ إذ تستبدل الـ bundlers قيمة process.env.NODE_ENV بثابت، فيسقط الفحص والرسالة من كود الإنتاج. وتحصل صفحة التوثيق على شارة «Deprecated»، وتُعاد تسمية خاصية المكوّن في Figma حتى يلاحظ المصمّمون أيضًا.

والـ tokens تُعامَل بالطريقة نفسها. يبقى الاسم القديم اسمًا مستعارًا للجديد، فلا ينكسر شيء، ويقول ملف الـ tokens ذلك صراحة:

JSON
{
  "color": {
    "text": {
      "light": {
        "$type": "color",
        "$value": "{color.text.subtle}",
        "$deprecated": "Use color.text.subtle. Removed in 5.0.0."
      }
    }
  }
}

3. أتمت الانتقال. الـ codemod سكربت يعيد كتابة الكود المصدري. ولـ prop أُعيدت تسميته، يكفي transform من بضعة أسطر في jscodeshift:

codemods/button-kind.js
export default function transformer(file, api) {
  const j = api.jscodeshift;
  return j(file.source)
    .find(j.JSXOpeningElement, { name: { name: 'Button' } })
    .find(j.JSXAttribute, { name: { name: 'kind' } })
    .forEach((path) => {
      path.node.name.name = 'variant';
    })
    .toSource();
}

تشغّله الفرق بالأمر npx jscodeshift --parser=tsx --extensions=tsx,ts -t codemods/button-kind.js src/ (فبدون هذين الخيارين لا يقرأ jscodeshift إلا ملفات .js بمحلّل Babel)، ثم تراجع الفروقات. ولأكبر خمسة مستخدمين، يفتح فريق النواة في Northwind pull requests الانتقال بنفسه. إعادة تسمية كانت ستكلّف كل فريق من الأربعين ظهيرة كاملة تصبح أربعين مراجعة سريعة.

للـ codemods حدود، ويجب أن يسمّيها دليل الانتقال. الـ transform أعلاه يعيد تسمية kind="danger" وkind={isUrgent ? 'danger' : 'primary'} بشكل صحيح، لأن كليهما سمة مكتوبة على <Button>. لكنه لا يرى kind المختبئ داخل props تُمرَّر بالـ spread، مثل <Button {...actionProps} /> حيث بُني actionProps في ملف آخر، ولا Button أُعيد تصديره باسم آخر. لهذا يبقى تحذير وقت التشغيل مهمًّا حتى بعد تشغيل الـ codemod: فهو يلتقط الحالات التي لا تصل إليها إعادة الكتابة الثابتة. ودليل Northwind لكل عملية حذف له الأجزاء الأربعة نفسها: كود قبل وبعد، وأمر الـ codemod، والحالات المعروفة التي يفوّتها الـ codemod، ورابط إلى موعد الساعات المكتبية حيث يساعد فريق النواة في الباقي.

4. قِس، ثم احذف. البحث في الكود عبر المستودعات يخبرك بعدد الاستخدامات المتبقّية؛ ويشرح القسم 5 كيف تجمع Northwind ذلك تلقائيًا. وحين يقارب الاستخدام الصفر، يدخل الحذف في الإصدار الـ major التالي، مجمّعًا مع عمليات الحذف المخطّطة الأخرى، فتواجه الفرق ترقية واحدة بدل عدّة ترقيات.

5. ادعم الإصدار الـ major السابق. بعد إطلاق 5.0.0 يظلّ 4.x يتلقّى إصلاحات الأخطاء والأمان ستة أشهر. الفرق التي لا تستطيع الترقية فورًا لا تُترك عالقة، ولا تنسخ النظام.

أعلنه كما تعلن تغييرًا في منتج

الـ deprecation خبر لأربعين فريقًا، فعامله كإعلان منتج لا كسطر في الـ changelog. تنشر Northwind كل deprecation في قناة نظام التصميم بثلاث جمل: ما الذي يتغيّر، ولماذا يستحقّ الجهد، ومتى يحدث الحذف. ويرتبط المنشور بدليل الانتقال ويبقى مثبّتًا حتى يُطلَق الـ major. ويتلقّى مديرو الهندسة ملخّصًا شهريًا بعمليات الحذف القادمة التي تمسّ فرقهم، لأنهم هم مَن يجدولون العمل.

كم من الوقت يكفي؟

تُبقي Northwind الـ API المُهمَل لإصدارين minor على الأقل أو ثلاثة أشهر، أيّهما أطول، قبل الـ major الذي يحذفه، وتنشر جدول الإصدارات الـ major قبل ربع سنة. أرقامك قد تختلف؛ المهمّ أن تكون مكتوبة ويمكن توقّعها، حتى تخطّط الفرق لعمليات الانتقال ضمن خرائط طريقها بدل أن تكتشفها في عملية بناء فاشلة.

في التمرين ترتّب مسار deprecation كاملًا. وبعدها تبني خط الإصدار الذي يلتقط التغييرات الكاسرة غير المقصودة قبل أن تُطلَق.

أهم النقاط

  • لا تعلن deprecation لشيء قبل أن يُطلَق بديله؛ فالـ deprecation بلا بديل مجرّد شكوى.
  • علّم الـ deprecation في كل مكان ينظر إليه الناس - الأنواع، والـ tokens، وتحذيرات الـ console في بيئة التطوير وحدها، والتوثيق، وFigma - وسمِّ دائمًا البديل وإصدار الحذف.
  • الـ codemods تحوّل الانتقال من مهمّة لأربعين فريقًا إلى مراجعة لأربعين فريقًا.
  • لا تحذف العناصر المُهمَلة إلا في إصدار major، بعد أن تقيس أن الاستخدام قارب الصفر، واستمرّ في إصلاح الإصدار الـ major السابق لمدّة معلنة.

قراءات إضافية

تحقّق من فهمك

3 أسئلة

السؤال 1 من 3

يريد فريق النواة إعلان deprecation لـ ShipmentCard لأن Card المركّب أفضل. لكن الـ slot الخاص بـ Footer في Card لم يُطلَق بعد. ما الذي يجب أن يحدث أولًا؟

السؤال 2 من 3

أين يجب أن يظهر تحذير «Button kind is deprecated» وقت التشغيل؟

السؤال 3 من 3

يُظهر البحث في الكود لدى Northwind 4 استخدامات متبقّية للـ prop المُهمَل kind عبر 40 مستودعًا، كلها في أداة إدارة قديمة لفريق واحد. إصدار 5.0 الأسبوع القادم. ما أفضل خطوة؟

تدريب

رتّب الخطوات

خطّط لإعادة تسمية الـ token من أولها إلى آخرها

تستبدل Northwind الـ token المسمّى --nw-color-text-light بـ --nw-color-text-subtle. هناك نحو 300 استخدام عبر 40 مستودعًا، والإصدار الحالي 4.6.0. رتّب خطوات مسار الـ deprecation.

استخدم أزرار الأسهم لإعادة الترتيب.

  1. 1إطلاق --nw-color-text-subtle في 4.7.0
  2. 2تتبّع الاستخدامات المتبقّية عبر المستودعات حتى تقارب الصفر
  3. 3الاستمرار في إطلاق إصلاحات الأخطاء على 4.x لستة أشهر
  4. 4حذف الـ token القديم في 5.0.0، مجمّعًا مع عمليات الحذف المخطّطة الأخرى
  5. 5نشر codemod وفتح pull requests الانتقال لأكبر المستخدمين
  6. 6إبقاء --nw-color-text-light اسمًا مستعارًا معلَّمًا بـ $deprecated، وإعلان إصدار الحذف في التوثيق والـ changelog