فرانكنشتاين في البرمجة هو كود مجمع من أجزاء غير متوافقة من تقنيات وأنماط وبنى مختلفة. وفقًا لبحث ThoughtWorks Technology Radar (2024)، 28% من المشاريع الكبيرة تظهر علامات متلازمة فرانكنشتاين — الانتقائية المعمارية الناتجة عن عدم وجود رؤية تقنية موحدة. قياسًا لرواية ماري شيلي، هذا الكود يعمل، لكن صيانته تتحول إلى كابوس.
النقاط الرئيسية
فرانكنشتاين (كود فرانكنشتاين، نمط فرانكنشتاين) هو نمط مضاد يتم فيه تجميع نظام برمجي من أجزاء غير مصممة للعمل معًا. مثل وحش فرانكنشتاين، يمكن لهذا الكود أن يعمل، لكنه قبيح وغير قابل للتنبؤ وخطير عند أدنى تغيير.
يأتي المصطلح من الأدب: في رواية ماري شيلي «فرانكنشتاين، أو بروميثيوس الحديث» (1818)، خلق عالم كائنًا حيًا من شظايا أجساد أشخاص مختلفين موتى. في البرمجة، التشبيه دقيق — يأخذ المطورون قطعًا من أطر عمل مختلفة ومكتبات ولغات ويلصقونها معًا «على الهواء»، للحصول على نتيجة عاملة لكنها وحشية.
الفرق بين فرانكنشتاين وكود السباغيتي هو في النطاق والطبيعة. كود السباغيتي هو هيكل متشابك ضمن حزمة تقنية واحدة. فرانكنشتاين هو انتقائية على مستوى البنية: تقنيات مختلفة، نماذج غير متوافقة، أساليب متعارضة ضمن نفس النظام.
بنية الخدمات المصغرة تسمح باستخدام تقنيات مختلفة لخدمات مختلفة، ولكن بشرط حدود واضحة وبروتوكولات تفاعل قياسية. فرانكنشتاين هو خلط فوضوي بلا حدود: REST و GraphQL في نفس وحدة التحكم، وORMان في نفس الوحدة، وSQL و NoSQL لكيان واحد.
غياب قائد تقني أو مهندس معماري هو السبب الجذري. عندما لا يكون هناك شخص مسؤول عن سلامة البنية، يختار كل مطور أدوات «لنفسه». واحد يحب Spring، وآخر Guice، وثالث يستخدم DI مخصص. النتيجة — خليط معماري.
دمج المشاريع هو السبب الثاني الشائع. طور فريقان وحداتهم بشكل مستقل، باستخدام حزم تقنية مختلفة. عندما يجب دمج الوحدات في تطبيق واحد، يتم «لصقها» ببساطة بمحولات وطبقات وسيطة. النتيجة هي فرانكنشتاين.
الاستحواذات المؤسسية هي السيناريو الثالث. اشترت الشركة أ الشركة ب وتريد دمج منتجها في منتجها. بدلاً من إعادة الكتابة — اللصق عبر APIs، وقواعد بيانات مشتركة، وحلول مؤقتة. بعد عام، يتحول النظام إلى وحش لا يفهمه أحد.
| السبب | الوصف | النتيجة النموذجية |
|---|---|---|
| لا مهندس معماري | كل مطور يختار حزمته الخاصة | 3 عملاء HTTP مختلفين في وحدة واحدة |
| دمج المشاريع | منتجان يُلصقان في واحد | ORMان، طريقتان للتسجيل |
| الاستحواذات | شراء شركة مع منتجها | هجين من بنى وأنماط مختلفة |
| التجارب | إدخال تقنيات جديدة بدون استراتيجية | ميزات Java 8 + Java 21 في ملف واحد |
| قرارات سياسية | فرض تقنية من الأعلى بدون سياق | إطار مؤسسي لسكريبت بسيط |
المطورون ذوو الخبرة الذين يريدون تجربة تقنيات جديدة في الإنتاج غالبًا ما يصبحون مصدر فرانكنشتاين. بدلاً من حصر التجارب في وحدة معزولة، يقومون بإدخال كود تجريبي في أجزاء حرجة من النظام.
مثال كلاسيكي — استخدام ORMs متعددة في تطبيق واحد. بعض الوحدات تستخدم Hibernate، وبعضها MyBatis، وبعضها استعلامات JDBC مباشرة. تصبح المعاملات غير قابلة للإدارة، وذاكرة التخزين المؤقت غير متسقة، والمطور الجديد لا يعرف أي نهج يختار لميزة جديدة.
مثال ثانٍ — خلط الأنماط المعمارية. في وحدة تحكم REST API، تجد استدعاءات لخدمات SOAP، واستعلامات SQL مباشرة، والوصول إلى نظام الملفات، وتوليد HTML. مثل هذا التطبيق من المستحيل اختباره أو توسيعه أو توثيقه.
مثال ثالث — حزمة تقنية حيث يُستخدم Python للخلفية، Node.js لخدمة مصغرة، C# لعميل سطح المكتب، و Java لتطبيق Android، بينما كل منطق الأعمال موزع بينهم دون فصل واضح للمسؤوليات.
// فرانكنشتاين — أنماط وتقنيات مختلطة
// استدعاءات و Promises و async/await مجتمعة
// استدعاءات
db.query("SELECT * FROM users", function(err, rows) {
if (err) handleError(err);
// Promise داخل استدعاء
fetch("/api/data").then(function(data) {
// async/await داخل then
(async () => {
const result = await processData(data);
sendResponse(result);
})();
});
});
// كود نظيف — أسلوب async/await موحد
async function getUserData(userId) {
const user = await db.query("SELECT * FROM users WHERE id = ?", [userId]);
const data = await fetch("/api/data/" + userId);
return await processData(user, data);
}
قاعدة بيانات واحدة تُستخدم في وقت واحد كـ SQL علائقية (مع التطبيع) و NoScript موجهة للمستندات (مع أعمدة JSON). بعض الاستعلامات تذهب عبر ORM، وبعضها عبر الإجراءات المخزنة، وبعضها عبر SQL مباشر من الكود. مخطط قاعدة البيانات غير موثق، الترحيلات تتعارض.
تعقيد الانضمام هو العاقبة الأولى. يجب على المطور الجديد معرفة 5 لغات و 3 أطر عمل ونمطين معماريين لفهم كيفية عمل النظام. يستغرق الانضمام أسابيع إلى شهور. وفقًا لـ LinkedIn (2023)، المشاريع ذات الانتقائية التقنية تفقد الموظفين الجدد مرتين أكثر.
عدم قابلية التنبؤ بالسلوك هي العاقبة الثانية. تغيير في الخدمة المصغرة Python يمكن أن يكسر بشكل غير متوقع وحدة Java لأنهما يشتركان في قاعدة بيانات دون عقود واضحة. تصحيح مثل هذه المشكلات يتطلب معرفة متزامنة بجميع التقنيات في الحزمة.
الأمان هو العاقبة الثالثة. كل تقنية في الحزمة تتطلب تكوين أمان خاص بها، وتصحيحاتها الخاصة، ومراقبتها الخاصة. الحفاظ على الأمان عند مستوى مقبول لـ 5-6 تقنيات غير متجانسة أمر مستحيل عمليًا. واحدة منها ستكون حتمًا عرضة للخطر.
SonarQube يمكنه قياس الدين التقني، لكنه لا يمكنه قياس «الدين المعماري» — عدم توافق المكونات. يظهر هذا الدين ليس في تحذيرات المدقق، بل في استحالة إضافة ميزة جديدة دون تعديل ثلاث وحدات مختلفة مكتوبة بتقنيات مختلفة.
الخطوة الأولى والأساسية — تعيين مهندس معماري أو قائد تقني مسؤول عن سلامة حزمة التقنيات. هذا الشخص لديه حق النقض على إدخال تقنيات جديدة دون مراجعة معمارية. ليس ديمقراطية، بل قرار فردي مسؤول بشأن التقنيات الرئيسية.
الخطوة الثانية — تطبيق عملية Architecture Decision Record (ADR). أي قرار معماري مهم (اختيار قاعدة بيانات، إطار عمل، بروتوكول) يُوثق كنص قصير: السياق، البدائل المدروسة، القرار المتخذ، العواقب. يتم تخزين ADRs في المستودع وتكون متاحة للفريق بأكمله.
الخطوة الثالثة — وضع مبدأ «مهمة واحدة — أداة واحدة». لطلبات HTTP — عميل واحد. لـ ORM — مكتبة واحدة. للتسجيل — إطار عمل واحد. الاستثناءات مسموحة فقط عبر ADR مع تبرير. إذا كان المشروع لديه بالفعل Axios — لا تضف fetch، إذا كان لديه SLF4J — لا تكتب عبر System.out.
التجارب مسموحة، لكن في بيئة معزولة. خصص وحدة أو خدمة يمكن إعادة كتابتها بتقنية جديدة دون التأثير على باقي النظام. إذا نجحت التجربة — قم بتوحيدها عبر ADR. إذا لم تنجح — أزلها دون عواقب.
الجرد — الخطوة الأولى. أنشئ خريطة كاملة لحزمة التقنيات: ما هي أطر العمل والمكتبات واللغات والبروتوكولات المستخدمة، في أي وحدات ولأي مهام. سترى حجم المشكلة: ازدواجية الأدوات، تقنيات متعارضة، تبعيات غير مستخدمة.
التوحيد — الخطوة الثانية. اختر أداة واحدة لكل مهمة. على سبيل المثال: Hibernate فقط لـ ORM، SLF4J + Logback فقط للتسجيل، REST فقط لـ API. وثق المعيار في ADR. ابدأ الاستبدال من الوحدات حيث تسبب الانتقائية أكبر مشاكل.
استراتيجية Parallel Run — الخطوة الثالثة. تعمل الأدوات القديمة والجديدة بالتوازي حتى تثبت الجديدة موثوقيتها. على سبيل المثال، عميل HTTP القديم والجديد يعملان معًا، لكن الجديد يتعامل مع جزء فقط من الطلبات. بعد فترة استقرار، يُزال القديم.
// فرانكنشتاين — ثلاث مناهج HTTP في مشروع واحد
// الوحدة A: OkHttp
OkHttpClient client = new OkHttpClient().newCall(request);
// الوحدة B: RestTemplate (Spring)
restTemplate.getForObject(url, String.class);
// الوحدة C: java.net.HttpURLConnection
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
// نهج موحد: RestTemplate للتزامن، WebClient للتفاعلي
@Autowired
private RestTemplate restTemplate;
public String callApi(String url) {
return restTemplate.getForObject(url, String.class);
}
القائد التقني هو الأداة الرئيسية لمكافحة فرانكنشتاين. ليس مديرًا، ولا مهندسًا معماريًا في برج عاجي، بل مطورًا ممارسًا يكتب الكود ويراجع PRs ويتخذ القرارات المعمارية. بدون مثل هذا الشخص، ينزلق المشروع حتمًا إلى الانتقائية التقنية.
RFC (Request for Comments) هو عملية مستعارة من مجتمعات المصدر المفتوح. قبل إدخال أي تقنية مهمة، يكتب المؤلف RFC: المشكلة، الحل المقترح، البدائل، خطة التنفيذ. يناقش الفريق، يصوت، يقبل أو يرفض. RFC يخلق الشفافية ويمنع القرارات المعمارية «الصامتة».
الرادار التقني (ThoughtWorks Technology Radar) هو أداة تصنيف: Adopt، Trial، Assess، Hold. يراجع الفريق الرادار بانتظام ويحدث الحالات. يساعد هذا في تمييز «الموضة» عن «المفيد» وتجنب إدخال تقنيات غير مثبتة في الكود الحرج.
أهم صفة في البنية هي التناسق (consistency). حتى الأداة غير المثالية المستخدمة في المشروع بأكمله أفضل من أفضل أداة مستخدمة فقط في وحدة واحدة. التناسق يقلل العبء المعرفي، ويبسط الانضمام، ويجعل الكود قابلًا للتنبؤ.
الأسئلة الشائعة
Polyglot persistence هو الاستخدام الواعي لقواعد بيانات مختلفة لمهام مختلفة (PostgreSQL للمعاملات، Redis للتخزين المؤقت، Elasticsearch للبحث). فرانكنشتاين هو خلط فوضوي بدون استراتيجية. الفرق في وجود قرار معماري: polyglot هو خطة، فرانكنشتاين هو غيابها.
نعم، وهذه مشكلة شائعة. عندما تستخدم كل خدمة مصغرة لغتها الخاصة وقاعدة بياناتها الخاصة وبروتوكولها الخاص ونهجها الخاص في النشر دون معايير مركزية — تحصل على فرانكنشتاين موزع. للخدمات المصغرة، المعايير المشتركة مهمة: بروتوكول موحد (REST/gRPC)، تنسيق سجل مشترك، مراقبة مركزية.
لا تمنع — وجه. اقترح على المؤلف كتابة RFC: وصف لماذا الحل الحالي غير مناسب، وما البدائل التي تم النظر فيها، وكيف سيتم الترحيل. غالبًا في عملية كتابة RFC، يدرك المطور نفسه أن التقنية الجديدة غير ضرورية. إذا كان RFC مقنعًا — نفذه، لكن مع خطة وقيود.
أولًا الجرد، ثم التوحيد. لا تحاول إعادة كتابة كل شيء دفعة واحدة. اختر طبقة واحدة (مثل عملاء HTTP أو التسجيل)، واختر أداة واحدة، واكتب ADR، ورحّل تدريجيًا. نمط Strangler Fig — استبدل المكونات القديمة بأخرى جديدة واحدة تلو الأخرى دون إيقاف التطبيق.
كلما قل، كان أفضل. مثاليًا — لغة واحدة، إطار عمل واحد، قاعدة بيانات واحدة، طريقة تسجيل واحدة. واقعيًا — 2-3 لغات (مع فصل واضح)، 1-2 قاعدة بيانات، 1-2 إطار عمل. كل تقنية إضافية تزيد العبء المعرفي للفريق وتكلفة الصيانة.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.