استكشف كيف مزجت سكالا لمارتن أودرْسكي أفكار البرمجة الدالية والشيئية على JVM، وأثر ذلك على تصميم الواجهات، الأدوات، ودروس تصميم اللغات الحديثة.

يشتهر مارتن أودرْسكي بكونه مبتكر سكالا، لكن تأثيره على برمجة JVM أوسع من لغة واحدة. لقد ساعد في تطبيع أسلوب هندسي يجمع بين شفافية التعبير، أنظمة أنواع قوية، والتوافق البراغماتي مع جافا.
حتى إذا لم تكتب سكالا يوميًا، فإن العديد من الأفكار التي أصبحت "عادية" الآن في فرق JVM—أنماط برمجة دالية أكثر، بيانات غير قابلة للتغيير أكثر، وتركيز أكبر على النمذجة—تسارعت بفضل نجاح سكالا.
الفكرة الجوهرية في سكالا بسيطة: احتفظ بنموذج البرمجة الموجهة للكائنات الذي جعل جافا قابلة للاستخدام على نطاق واسع (كلاسات، واجهات، تغليف)، وأضف أدوات البرمجة الدالية التي تجعل الكود أسهل للاختبار والفهم (دوال من الدرجة الأولى، افتراضات بعدم القابلية للتغيير، نمذجة بيانات على طراز جبري).
بدلًا من إجبار الفرق على اختيار جانب—OO صارم أو FP صارم—تسمح سكالا باستخدام كلاهما:
أهمية سكالا أنها أثبتت أن هذه الأفكار تعمل في بيئة الإنتاج على JVM، وليس فقط في الأوساط الأكاديمية. أثرت على كيفية بناء خدمات الخلفية (معالجة أخطاء أكثر صراحة، تدفقات بيانات غير قابلة للتغيير)، على تصميم المكتبات (واجهات توجه الاستخدام الصحيح)، وعلى تطور أطر معالجة البيانات (جذور Spark في سكالا مثال معروف).
وبنفس القدر من الأهمية، أجبرت سكالا على محادثات عملية لا تزال تشكل الفرق الحديثة: ما مدى التعقيد المقبول؟ متى يحسن نظام الأنواع القوي الوضوح، ومتى يجعل الكود أصعب قراءة؟ تلك المقايضات أصبحت الآن مركزية في تصميم اللغات والواجهات عبر JVM.
سنبدأ ببيئة JVM التي دخلت فيها سكالا، ثم نفكك التوتر بين FP وOO الذي واجهته. سننظر بعد ذلك في الميزات اليومية التي جعلت سكالا تبدو كـ "أفضل ما في العالمين" (traits, case classes, pattern matching)، قوة نظام الأنواع (وتكاليفه)، وتصميم الإمبليستس ونمط type class.
أخيرًا سنناقش التزامن، التوافق مع جافا، البصمة الحقيقية لسكالا في الصناعة، ما ضبطته سكالا 3، والدروس الدائمة التي يمكن لمصممي اللغات ومؤلفي المكتبات تطبيقها—سواء شحنوا سكالا، جافا، كوتلن، أو أي شيء آخر على JVM.
عندما ظهرت سكالا في أوائل العقد الأول من القرن الحادي والعشرين، كان JVM في الأساس "بيئة تشغيل جافا". جافا هيمنت على برمجيات المؤسسات لأسباب وجيهة: منصة مستقرة، دعم بائع قوي، ونظام بيئي هائل من المكتبات والأدوات.
لكن الفرق أيضًا شعرت بألم حقيقي عند بناء أنظمة كبيرة مع أدوات تجريد محدودة—لا سيما حول النماذج المليئة بالبُرنَة (boilerplate)، التعامل العُرضي مع null، وبدائيات التزامن السهلة الخطأ.
تصميم لغة جديدة لـ JVM لم يكن مثل البدء من الصفر. كان على سكالا أن تتلاءم مع:
حتى إن بدت اللغة أفضل على الورق، تتردد المؤسسات. يجب على لغة JVM جديدة تبرير تكاليف التدريب، تحديات التوظيف، وخطر أدوات أضعف أو آثار أقدام مكدسة مربكة. كما يجب عليها إثبات أنها لن تحجز الفرق داخل نظام بيئي ضيق.
تأثير سكالا لم يقتصر على الصياغة فقط. شجعت الابتكار "المبني حول المكتبات" (مجموعات أكثر تعبيرًا وأنماط دالية)، دفعت أدوات البناء وتدفقات التبعيات قُدمًا (إصدارات سكالا، البناء عبر الإصدارات، مكونات المترجم)، وطَبَّعَت تصاميم واجهات تفضل عدم القابلية للتغيير، قابلية التركيب، ونمذجة أكثر أمانًا—وكل ذلك مع البقاء داخل راحة عمليات JVM.
خلقت سكالا لوقف جدال مألوف كان يعيق التقدم: هل تعتمد فريق JVM على التصميم الموجه للكائنات، أم تعتمد أفكارًا دالية تقلل الأخطاء وتحسن إعادة الاستخدام؟
إجابة سكالا لم تكن "اختر واحدًا"، ولم تكن "اخلط كل شيء في كل مكان". الاقتراح كان أكثر عملية: دعم كلا الأسلوبين بأدوات متسقة وذات مرتبة أولى، وترك المهندسين يستخدمون كل منهما حيث يناسب.
في OO الكلاسيكي، تُنمذج النظام عبر كلاسات تجمع البيانات والسلوك. تُخفي التفاصيل عبر التغليف (الحفاظ على الحالة خاصة وكشف الطرق)، وتعيد استخدام الكود عبر الواجهات (أو الأنواع التجريدية) التي تحدد ما يمكن أن يفعله الكيان.
تتفوق OO عندما يكون لديك كيانات طويلة العمر مع مسؤوليات واضحة وحدود مستقرة—فكر في Order, User, أو PaymentProcessor.
تدفعك FP نحو عدم القابلية للتغيير (القيم لا تتغير بعد إنشائها)، الدوال ذات الرتبة العليا (دوال تأخذ أو تُرجع دوالًا)، والنقاء (مخرجات الدالة تعتمد فقط على مُدخلاتها دون آثار جانبية مخفية).
FP تتفوق عند تحويل البيانات، بناء خطوط أنابيب، أو الحاجة إلى سلوك متوقع تحت التزامن.
على JVM، يظهر الاحتكاك عادةً حول:
هدف سكالا كان جعل تقنيات FP تبدو أصلية دون التخلي عن OO. يمكنك متابعة نمذجة المجالات بكلاسات وواجهات، لكن يتم تشجيعك على الافتراض بعدم القابلية للتغيير والتركيب الدالي.
عمليًا، يمكن للفرق كتابة كود OO واضح حيثما يكون مناسبًا، ثم التحول إلى أنماط FP لمعالجة البيانات، التزامن، وقابلية الاختبار—دون مغادرة منظومة JVM.
سمعة سكالا كـ "أفضل ما في العالمين" ليست مجرد فلسفة—بل مجموعة أدوات يومية تتيح للفرق مزج التصميم الموجه للكائنات مع تدفقات عمل دالية دون طقوس مستمرة.
ثلاث ميزات شكلت مظهر كود سكالا في الممارسة: traits، case classes، و companion objects.
الـ traits هي إجابة سكالا العملية على "أريد سلوكًا قابلًا لإعادة الاستخدام دون شجرة وراثة هشة." يمكن للفئة أن تمتد من سوبركلاس واحد لكنها تمزج عدة traits، ما يجعل من الطبيعي نمذجة القدرات (التسجيل، التخزين المؤقت، التحقق) كقطع بناء صغيرة.
بالمصطلحات OO، تحافظ traits على تركيز أنواع المجال الأساسية مع السماح بتركيب السلوك. بالمصطلحات FP، غالبًا ما تحتوي traits على دوال مساعدة نقية أو واجهات صغيرة على طراز الجبر يمكن تنفيذها بطرق مختلفة.
تجعل case classes من السهل إنشاء أنواع "مركزة على البيانات"—سجلات مع افتراضات معقولة: معاملات المُنشِئ تصبح حقولًا، والمساواة تعمل كما يتوقع الناس (بالمقدار)، وتحصل على تمثيل مقروء للتصحيح.
تتزاوج أيضًا بسلاسة مع pattern matching، مما يدفع المطورين نحو معالجة أكثر أمانًا وصراحة لأشكال البيانات. بدلًا من تبعثر فحوصات null وinstanceof، تطابق على case class وتستخرج ما تحتاجه بالضبط.
أجسام المرافق (companion objects) في سكالا (object بنفس اسم class) فكرة صغيرة ذات تأثير كبير على تصميم الواجهات. تعطيك مكانًا للمصانع، الثوابت، والأساليب المساعدة—دون خلق كلاسات "Utils" منفصلة أو إجبار كل شيء إلى أساليب ثابتة.
هذا يحافظ على إنشاء بنمط OO مرتب، بينما يمكن لوحدات المساعدة على طراز FP (مثل apply للإنشاء الخفيف) أن تعيش بجانب النوع الذي تدعمه.
معًا، تشجع هذه الميزات على قاعدة كود حيث تكون كائنات المجال واضحة ومغلفة، وأنواع البيانات مريحة وآمنة للتحويل، والواجهات متماسكة—سواء كنت تفكر في مصطلحات الكائنات أو الدوال.
المطابقة النمطية في سكالا طريقة لكتابة منطق تفرع بناءً على شكل البيانات، وليس فقط على قيم منطقية أو سلاسل if/else. بدلًا من السؤال "هل العلم مضبوط؟" تسأل "أي نوع من الأشياء هذه؟"—ويقْرأ الكود كقائمة حالات مسماة.
بأبسط صورها، تحل المطابقة النمطية محل سلاسل الشرطيات بوصف "حالة بحالة":
sealed trait Result
case class Ok(value: Int) extends Result
case class Failed(reason: String) extends Result
def toMessage(r: Result): String = r match {
case Ok(v) => s"Success: $v"
case Failed(msg) => s"Error: $msg"
}
يجعل هذا الأسلوب النية واضحة: عالج كل شكل ممكن من Result في مكان واحد.
لا تُجبرك سكالا على وجود تسلسل وراثة واحد يناسب الجميع. مع sealed traits يمكنك تعريف مجموعة صغيرة ومغلقة من البدائل—غالبًا ما تُسمى نوع بيانات جبري (ADT).
"مغلقة" تعني أن كل البدائل المسموح بها يجب أن تُعرف معًا (عادة في نفس الملف)، بحيث يعرف المترجم القائمة الكاملة من الاحتمالات.
عند المطابقة على تسلسل مغلق، يمكن لسكالا تحذيرك إذا أغفلت حالة. هذه فائدة عملية كبيرة: عند إضافة case class Timeout(...) extends Result لاحقًا، يمكن للمترجم أن يُشير إلى كل المطابقات التي تحتاج الآن للتحديث.
هذا لا يُلغي الأخطاء—قد يظل المنطق خاطئًا—لكنّه يقلل فئة شائعة من أخطاء "الحالة غير المعالجة".
المطابقة النمطية مع ADTs المغلقة تشجع على واجهات تُنمذج الواقع صراحةً:
Ok/Failed بدلاً من null أو استثناءات غامضة.Loading/Ready/Empty/Crashed تمثل كبيانات، لا كأعلام مبعثرة.Create, Update, Delete) حتى تكون المعالجات مكتملة طبيعياً.النتيجة هي كود أسهل قراءة، أصعب سوء استخدامه، وأكثر وُدًّا لإعادة البناء بمرور الزمن.
نظام أنواع سكالا سبب رئيسي في شعور اللغة بالأناقة وبتحدٍ في آنٍ واحد. يقدم ميزات تجعل الواجهات معبرة وقابلة لإعادة الاستخدام، مع إبقاء الكود اليومي قابلاً للقراءة—على الأقل عند استخدام القوة بحكمة.
يُمكن للمترجم غالبًا استنتاج الأنواع التي لم تكتبها. بدلًا من تكرار نفسك، تسمّي النية وتمضي.
val ids = List(1, 2, 3) // inferred: List[Int]
val nameById = Map(1 -> "A") // inferred: Map[Int, String]
def inc(x: Int) = x + 1 // inferred return type: Int
هذا يقلل الضجيج في قواعد الكود المليئة بالتحويلات (شائعة في خطوط أنابيب على طراز FP). كما يجعل التركيب خفيفًا: يمكنك ربط خطوات بدون تعليق كل قيمة متوسطة.
###泛 الزيت: Generic و variance: مجموعات قابلة لإعادة الاستخدام وواجهات أكثر أمانًا
تميل مجموعات سكالا ومكتباتها إلى الاعتماد بشكل كبير على النوعيات العامة (مثال List[A], Option[A]). تُصف إشارات التفاوت (+A, -A) كيف يتصرف التوريث الفرعي لمعاملات النوع.
نموذج ذهني مفيد:
+A): "حاوية من Cats يمكن استخدامها حيثما يتوقع حاوية من Animals." (جيد للبُنى غير القابلة للتغيير والمقروءة مثل List).-A): شائع في "المستهلكين"، مثل مدخلات الدوال.التفاوت سبب في أن تصميم مكتبات سكالا يمكن أن يكون مرنًا وآمنًا: يساعدك على كتابة واجهات قابلة لإعادة الاستخدام دون تحويل كل شيء إلى Any.
الأنواع المتقدمة—أنواع عليا، أنواع معتمدة على المسار، تجريدات مدفوعة بالإمبليستس—تُمكّن مكتبات معبرة للغاية. الجانب السلبي هو أن المترجم يصبح لديه عمل أكثر، وعندما يفشل، قد تكون الرسائل مخيفة.
قد ترى أخطاء تذكر أنواعًا مستنتجة لم تكتبها أبدًا، أو سلاسل طويلة من القيود. ربما يكون الكود صحيحًا "بالمعنى"، لكن ليس بالشكل الدقيق الذي يحتاجه المترجم.
قاعدة عملية: دع الاستدلال يتعامل مع التفاصيل المحلية، لكن أضف تعليقات نوعية عند الحدود الهامة.
استخدم أنواعًا صريحة لـ:
هذا يحافظ على الكود مقروءًا للبشر، يسرع استكشاف أخطاء المترجم، ويحوّل الأنواع إلى توثيق—دون التخلي عن قدرة سكالا على إزالة البُرنَة حيث لا تضيف وضوحًا.
كانت الإمبليستس في سكالا إجابة جريئة على ألم شائع في JVM: كيف تضيف سلوكًا "تكفيه الحاجة" لأنواع موجودة—خصوصًا أنواع جافا—دون الوراثة، أو التغليف المتكرر، أو منادات أدوات فوضوية.
على مستوى عملي، تسمح الإمبليستس للمترجم بتزويد وسيطة لم تُمرَّر صراحة، طالما يوجد قيمة مناسبة في النطاق. مقترنةً بتحويلات ضمنية (لاحقًا أنماط طرق الامتداد الأكثر صراحة)، هذا وفّر طريقة نظيفة لـ "إلحاق" طرق جديدة بأنواع لا تتحكم بها.
هكذا تحصل على واجهات انسيابية: بدلًا من Syntax.toJson(user) يمكنك كتابة user.toJson، حيث تُؤمَّن toJson بواسطة فئة ضمنية مستوردة أو تحويل.
الأهم أن الإمبليستس جعلت type classes مريحة. type class طريقة للقول: "هذا النوع يدعم هذا السلوك" دون تعديل النوع نفسه. يمكن للمكتبات تعريف تجريدات مثل Show[A], Encoder[A], أو Monoid[A]، ثم توفير حالات عبر الإمبليستس.
تظل نداءات الاستدعاء بسيطة: تكتب كودًا عامًا، والمترجم يختار التنفيذ الصحيح بناءً على ما هو في النطاق.
الجانب السلبي للراحة نفسها: السلوك يمكن أن يتغير عندما تضيف أو تزيل استيرادًا. هذا "العمل على بعد" قد يجعل الكود مفاجئًا، يخلق أخطاء ضمنية غامضة، أو يختار حالة لم تكن تتوقعها بهدوء.
سكالا 3 تحتفظ بالقوة لكن توضح النموذج باستخدام given وusing. النية—"هذه القيمة تُقدم ضمنيًا"—أكثر وضوحًا في الصياغة، مما يجعل الكود أسهل قراءة وتعليمًا ومراجعة مع الحفاظ على تصميمات مدفوعة بنمط type-class.
التزامن هو المكان حيث يصبح مزيج سكالا "FP + OO" ميزة عملية. أصعب جزء في الكود المتوازي ليس تشغيل خيوط—إنما فهم ما يمكن أن يتغير، متى، ومن قد يراه.
تدفع سكالا الفرق نحو أنماط تقلل تلك المفاجآت.
تقلل القيم غير القابلة للتغيير من حالات السباق: جزآن من البرنامج يحدثان نفس البيانات في نفس الوقت فتحصل على نتائج يصعب إعادة إنتاجها.
تفضيل سكالا للقيم غير القابلة للتغيير (غالبًا مع case classes) يشجع على قاعدة بسيطة: بدلًا من تغيير كائن، أنشئ واحدًا جديدًا. قد يبدو ذلك "مُبذِّرًا" في البداية، لكنه غالبًا ما يعود بفائدة في عدد أخطاء أقل وتصحيح أسهل—خصوصًا تحت التحميل.
جعلت سكالا Future أداة مألوفة على JVM. الفكرة ليست "callbacks في كل مكان"، بل التركيب: يمكنك بدء عمل متوازي ثم دمج النتائج بطريقة مقروءة.
مع map, flatMap, وcomprehensions من نوع for يمكن كتابة كود غير متزامن بأسلوب يشبه منطقًا خطويًا عاديًا. هذا يسهل فهم التبعيات وقرار مكان التعامل مع الأخطاء.
شاعت سكالا أيضًا أفكار النمط المُمثل: عزل الحالة داخل مكوّن، التواصل عبر رسائل، وتجنب مشاركة الكائنات عبر الخيوط. لا تحتاج للالتزام بأي إطار محدد للاستفادة من هذا التفكير—تمرير الرسائل بطبيعته يحدد ما يمكن تغييره ومن يملك الحق في تغييره.
الفرق التي تتبنّى هذه الأنماط غالبًا ما ترى ملكية أوضح للحالة، افتراضات افتراضية أكثر أمانًا للتوازParallel، ومراجعات كود تركز أكثر على تدفق البيانات بدلاً من سلوك التأمين الخفي.
نجاح سكالا على JVM لا ينفصل عن رهان بسيط: لا يجب أن تضطر لإعادة كتابة العالم لاستخدام لغة أفضل.
"التوافق الجيد" ليس مجرد إمكانية استدعاء عبر الحدود—إنما توافق ممل متوقع: أداء متوقع، أدوات مألوفة، وإمكانية مزج سكالا وجافا في نفس المنتج دون هجرة بطولية.
من سكالا يمكنك استدعاء مكتبات جافا مباشرة، تنفيذ واجهات جافا، توسيع كلاسات جافا، وشحن بايتكود JVM عادي يعمل في أي مكان تعمل فيه جافا.
من جافا يمكنك استدعاء كود سكالا أيضًا—لكن "الجيد" عادةً يعني فتح نقاط دخول صديقة لجافا: طرق بسيطة، جينات عامة قليلة التعقيد، وتواقيع ثنائية مستقرة.
شجعت سكالا مؤلفي المكتبات على الحفاظ على "سطح" عملي: توفير مُنشئات/مصانع مباشرة، تجنب متطلبات ضمنية مفاجئة لطرق العمل الأساسية، وكشف أنواع تفهمها جافا.
نمط شائع هو تقديم واجهة سكالا أولًا مع واجهة جافا صغيرة (مثال: X.apply(...) في سكالا وX.create(...) لجافا). بهذا تبقى سكالا معبرة دون معاقبة مستدعيي جافا.
يظهر احتكاك التوافق في بعض الأماكن المتكررة:
null، بينما سكالا تفضل Option. قرِّر أين تُحوَّل الحدود.اجعل الحدود صريحة: حوّل null إلى Option عند الحافة، ركّز تحويلات المجموعات، ووثق سلوك الاستثناءات. إذا كنت تدخل سكالا في منتج قائم، ابدأ بوحدات طرفية (أدوات، تحويلات بيانات) ثم تقدم للداخل. وعند الشك، فضّل الوضوح على العبقرية—التوافق هو المكان الذي يدفع فيه "البساطة" عائدها يوميًا.
سكالا لا تزال مهمة لأنها أظهرت أن لغة على JVM يمكنها أن تجمع بين راحة البرمجة الدالية (قيم غير قابلة للتغيير، دوال من الدرجة الأولى، قابلية التركيب) والتكامل مع نموذج البرمجة الموجهة للكائنات (كلاسات، واجهات، نموذج وقت تنفيذ مألوف) والقدرة على العمل في بيئات الإنتاج.
حتى إن لم تكن تكتب سكالا اليوم، فإن نجاحها ساعد في تطبيع أنماط أصبحت الآن مألوفة لدى فرق JVM: نمذجة بيانات صريحة، تعامل أفضل مع الأخطاء، وواجهات مكتبات توجه المستخدم نحو الاستخدام الصحيح.
أثره أوسع من مجرد "مخترع سكالا": لقد قدم نموذجًا عمليًا مفاده دفع التعبيرية وسلامة الأنواع قُدُمًا دون التخلي عن قابلية التوافق مع جافا.
عمليًا يعني ذلك أن الفرق استطاعت تبني أفكار من FP (بيانات غير قابلة للتغيير، نمذجة أنظمة بقيم نوعية، التركيب) وفي الوقت نفسه الاستفادة من أدوات ونُهج ونشر منظومة جافا—مما خفف حاجز "إعادة بناء العالم" الذي يقتل معظم لغات جديدة.
مقاربة سكالا "المزج" تعني عمليًا إمكانية استخدام:
الفكرة ليست إجبار البرمجة الدالية في كل مكان—بل السماح للفرق باختيار النمط الأنسب لكل وحدة عمل أو تدفق دون مغادرة نفس اللغة ونفس وقت التشغيل.
بما أن سكالا كانت تُترجم إلى بايتكود JVM، وكانت هناك توقعات أداء مؤسسية واضحة، وضرورة التوافق مع مكتبات وأدوات جافا.
هذه القيود دفعت اللغة نحو البراغماتية: المزايا يجب أن تُترجم بشكل واضح إلى وقت التشغيل، وأن تتجنب سلوكًا تشغيليًا مفاجئًا، وأن تدعم أدوات البناء وIDE والتصحيح وإجراءات النشر الواقعية—خلاف ذلك فإن الاعتماد سيتوقف بغض النظر عن جودة اللغة.
تسمح الـ traits بخلط سلوكيات متعددة في فئة واحدة دون بناء شجرة وراثة هشة.
عمليًا تُستخدم لـ:
هي أداة لـ البرمجة الموجهة للكائنات المبنية على التركيب وتنسجم جيدًا مع طرق مساعدة دالية.
الكلاسات من نوع case هي أنواع مُركَّزة على البيانات مع افتراضات مفيدة: مساواة بقيمة الحقول، بناء مريح، وتمثيل مقروء للتصحيح.
تتفوق عندما:
كما أنها تتوافق طبيعيًا مع pattern matching، ما يشجع المعالجة الصريحة لأشكال البيانات.
المطابقة النمطية (pattern matching) تبرمج التفرع بناءً على شكل البيانات (أي أي متغير لديك)، بدلًا من شروط متباعدة أو فحوصات instanceof.
عند الجمع مع traits المعلمة بـ sealed (مجموعات بدائل مغلقة)، تحصل على إعادة تشكيل أكثر أمانًا:
لا يضمن ذلك صحة المنطق، لكنه يقلل كثيرًا من أخطاء "الحالة المنسية".
الاستدلال النمطي يُزيل الكثير من الحشو، لكن عادةً ما تُضاف تعليقات نوعية عند الحدود المهمة.
قواعد عملية شائعة:
هذا يحافظ على قابلية قراءة الكود للناس، ويسهل تتبع أخطاء المترجم، ويحوِّل الأنواع إلى توثيق دون فقدان إيجابية سكالا في تقليل الحشو.
الإمبليستس (implicits) تسمح للمترجم بتوفير وسيطات من النطاق تلقائيًا، مُمكنةً طرقًا لإضافة سلوك إلى أنواع لا تتحكم بها.
الفوائد:
Encoder[A], Show[A])المخاطر:
سكالا 3 تحافظ على أهداف سكالا الأساسية لكنها تهدف لتبسيط الاستخدام اليومي وتقليل غموض النموذج الضمني.
تغييرات بارزة:
given/using لتحل محل كثير من أنماط implicit، ما يجعل استخدام type classes وأنماط DI أوضحenum كميزة أولى لتبسيط أنماط sealed + case objects الشائعةعادةً ما تُستخدم الإمبليستس مع عادة عملية: إبقاؤها قابلة للاكتشاف (أسماء ووثائق جيدة)، محلية (استيراد صريح)، وغير مُفاجئة.
الترحيل عادةً ما يكون أقل عن إعادة كتابة المنطق و أكثر عن ضبط أدوات البناء، الإضافات، وحالات الحافة خاصةً في الكود الذي يستخدم الماكروز أو سلاسل ضمنية معقدة.