سألت روح المدير الفني: أنت بارع في العديد من التقنيات ، لماذا لا يمكنك القيام بمشروع؟

المؤلف | Li Yingquan

المصدر | Si Yuanwai (المعرف: si-yuanwai)

إن كتابة التعليمات البرمجية عالية الجودة والقابلة للصيانة ليست فقط الإنجاز الأساسي للمبرمجين ، ولكنها أيضًا عامل رئيسي يمكن أن يحدد نجاح أو فشل المشروع.حاول هذه المقالة تلخيص المشاكل الشائعة الشائعة لمشكلة المشاريع وتقديم الحلول المقابلة.

مصير المبرمجين؟

سيواجه المبرمجون حتمًا مشاريع سيئة في حياتهم المهنية ، فبعض المشاريع تتعفن عند الانضمام ، وبعضها مشاريع فاسدة صنعتها بنفسك من الصفر ، وبعضها فاسد من الداخل إلى الخارج ، والبعض الآخر لامع وينتظر منك التعمق أكثر. عندما دخلت ، وجدت أنها كانت "حفرة قطران" ، وبعضهم لم يكن فاسدًا في هذا الوقت ولكن كانت هناك علامات على وجود مشاكل وكانوا يسيرون على طريق العفن.

هذا هو الحال بشكل أساسي في الصين. لا أعرف الكثير عن الوضع في الخارج. ومع ذلك ، من منظور مستوى الشكاوى من الأجانب في المجتمع الإنجليزي ووسائل الإعلام التقنية ، يجب أن تكون متشابهة. على الرغم من أن الجودة العامة قد تكون أعلى ، لقد تراكمت أيضًا بسبب طول المعلوماتية. المزيد من الأسئلة. بعد كل شيء ، لم يتم اختراع المصطلحات المستوردة "حفرة القطران ، Shit_Mountain" بدون سبب.

على أي حال ، ربما يكون هذا هو مصير صناعتنا - إما تغيير المهن ، أو البقاء في مشاريع سيئة ورموز سيئة. تمامًا مثل "قانون زيادة إنتروبيا" الكون:

تتطور جميع العمليات التلقائية لنظام منعزل في اتجاه جعل حالته أكثر اضطرابًا ، ومن المستحيل إعادة النظام إلى نظامه الأصلي ما لم يعمل العالم الخارجي عليه.

في مواجهة ظل القدر ، أصبح بعض الناس مخدرين لمصيرهم ، وفقدوا تدريجياً حماسهم لهذه الصناعة.

أولئك الذين لم يقبلوا بمصيرهم قاتلوا ضده ، لكن لم يكن هناك طريق على الأرض ، ولم تتبدد سحابة أزمة البرمجيات حقًا. لا تزال أسطورة الإنسان والشهر أسطورة ، لذلك أصدر الناس أحكامًا ومحاولات مختلفة:

  • اقلب الطاولة وابدأ من جديد :
    • ألقى الكثير من الناس باللوم على المشروع الضعيف على الفشل في وضع أساس جيد في المرحلة الأولى من المشروع ، والمتطلبات غير المستقرة والترميم على طول الطريق ، والفوضى التي خلفها المهندسين المعماريين والمبرمجين السابقين والتي كان من الصعب تنظيفها.
    • إما أنهم لا يملكون الثقة لتنظيف الفوضى ، أو أنهم يشعرون أنه جهد لا يحمد الله عليهم ويتخلون عن المشروع على أمل الحصول على فرصة للبدء من جديد.
    • لكنهم غير متأكدين أو يفكرون بعمق في كيفية تجنب تكرار نفس الأخطاء والقيام بمشروع آخر سيئ ، فهم متفائلون بشكل أعمى بأنهم أفضل من سابقيهم.
  • المصلحين الراديكاليين :
    • يلقي هذا الفصيل باللوم على المشاريع السيئة لعدم استخدام لغة البرمجة الصحيحة ، أو أحدث وأكبر مجموعة أو أدوات تقنية في المقام الأول.
    • يفكر البعض منهم أيضًا في فرصة البدء من جديد واستخدام أكثر حزم التكنولوجيا شيوعًا وسخونة (Spring Boot و Spring Cloud و Redis و NoSql و Docker و Vue).
    • أو حتى إذا لم تبدأ من جديد ، فأنت تعتقد أن مجموعة التكنولوجيا الحالية قديمة جدًا ولا يمكن تحملها (في الواقع ، قد لا تكون قديمة) ، وهي غير مقبولة بدون الخدمات الدقيقة والتوزيع ، لذا فإن تقديم مكدسات تقنية جديدة بشكل جذري ، بتهور القيام بعمليات كبرى في المشروع.
    • هذا النوع من اتباع الاتجاه الأعمى للتكنولوجيات الشائعة وغير الناضجة واختيار التكنولوجيا اللامبالية أمر شائع جدًا.مجموعة التكنولوجيا التي عفا عليها الزمن في أعينهم اليوم هي في الواقع مجرد اتجاه لمجموعة أخرى من الناس قبل بضع سنوات.
    • أنا لست ضد السعي وراء التكنولوجيا الجديدة ، ولكن مرة أخرى ، المشكلة هنا هي: أنهم ليسوا متأكدين من مخاطر وآثار جانبية لعملية جراحية كبرى ، وكيفية تجنب تكرار نفس الأخطاء والقيام بمشروع آخر سيئ باستخدام تقنية جديدة. الهندسة المعمارية. مجرد متفائل أعمى بأن التكنولوجيا الجديدة يمكن أن تحقق النجاح.
    • لا أحد يستطيع إيقاف الاتجاه المتهور لاختيار التكنولوجيا المدفوعة بالسيرة الذاتية. بعد كل شيء ، يتم إنفاق موارد الشركة ، ويتم استخدام أشياء جديدة لإظهار أنك طموح للغاية. لن يؤثر الفشل على تجميل سيرتك الذاتية. سوف تضيف فقط استئناف مشروع واستئناف لسيرتك الذاتية. العديد من المهارات المتقنة ، لن تذكر أنك قد أنجزت مشروعًا سيئًا مرة أخرى ، وستكتسب الشهرة والثروة دون خسارة المال.
  • المصلحون المحافظون :
    • هناك أيضًا مجموعة من الأشخاص الذين يترددون في التخلي عن هذا المشروع الإشكالي الذي لا يزال يحقق فوائد ، لأنهم يرون أن المشروع لا يزال له قيمة في الصيانة ، ويرون أيضًا صعوبة البدء من جديد (كل شيء صعب في البداية ، في الواقع ، هناك العديد من العوامل الخارجية في البداية الباردة للمشروع. القيود) ، وتكلفة الجراحة الكبرى التي تؤثر على العمل ، وصعوبة ومخاطر ترحيل النظام.
    • في الوقت نفسه ، حاولوا تحسين جودة المشروع تدريجيًا بطريقة لطيفة وتدريجية ، واعتمدوا سلسلة من الممارسات الهندسية (بما في ذلك إعادة بناء الكود الساخن ، واستكمال الاختبارات الآلية ، وتكملة الوثائق) لإزالة "الديون التقنية" "والقضاء على الاختناقات التي تحد من كفاءة تطوير المشروع وجودة التسليم..

إذا تمت مقارنة مشروع مشكلة بمريض مصاب بمرض عضال ، فإن هذه الأساليب الثلاثة تعادل التخلي عن العلاج ، والبتر ، والعلاج التقليدي.

تأملات مبرمج يبلغ من العمر 35 عامًا

عندما كنت صغيرًا ، كنت أيضًا من المعجبين بفصيل الطاولة والفصيل المتطرف. تم فتح وإغلاق المشروع الجديد والإطار الجديد. وعلى طول الطريق ، ارتفعت قيمة الخبرة والمهارة بشكل مطرد ، وكانت يسعدني تغيير الوظائف ورفع الأجور.

لكن في السنوات الأخيرة ، مع تقدم العمر ، من ناحية ، أصبح من المستحيل تعلم أشياء جديدة ، ومن ناحية أخرى ، تغير مفهوم التفكير في المشاريع التي تم تجربتها تدريجياً.

أحد أكثر الأشياء التي أثرت فيّ هو المشروع الذي بدأته من الصفر في أوائل عام 2016 ، وبحلول الوقت الذي غادرت فيه في نهاية عام 2018 (فقط من منظور جودة الكود) تركني ذلك غير راضٍ للغاية. فقط ، هذه المرة ليس هناك عذر:

  • من الاختيار الفني إلى التصميم المعماري إلى مواصفات الكود ، قمت بذلك بنفسي ، والفريق ليس كبيرًا ، وقمت بتشكيله وأخرجته بنفسي ؛
  • تقدم النصف الأول من العام بشكل سلس للغاية. لقد ركضت على طول الطريق مع التكنولوجيا والأدوات التي أمتلكها أكثر من غيرها ، واستبدلت المنتج غير المرغوب فيه الذي اشتريته قبل نهاية العام (نعم ، إنها أيضًا ميزة رائعة أن يكون لدي كمرجع في مجال الأعمال.
  • في عملية القيام بذلك ، يمكنني بذل قصارى جهدي واستخدام ما تعلمته في حياتي - قيمة خبرة السنوات الـ 13 السابقة من العمل ، والتحولات والدروس المستفادة ، بحيث تستخدم الشركة 20 فقط من موارد مشاريع مماثلة لشركات أخرى مماثلة لبناء المنصة ؛
  • إذا قيل إن السرعة والجودة والاقتصاد هي أعلى حالة ، فقد تمكنت في ذلك الوقت من تحقيق المزيد وأسرع وأكثر اقتصادا - الوظائف التي تم تسليمها غنية جدًا وقريبة من احتياجات العمل ، وتيرة التطوير سريعة ، وموارد تطوير الشركة اقتصادية للغاية ؛
  • ولكن يبدو الآن أن "الجيد" بعيد المنال. في منتصف المشروع ، تم الانتهاء من المتطلبات البسيطة وذات الأولوية العالية ، وظهرت تحديات جديدة في أعمال الشركة - الاتصال بنظام أساسي آخر ومنصات خارجية ، هنا يأتي الاختبار الحقيقي.
  • مشروع التجديد له تأثير كبير نسبيًا ويحتاج إلى إجراء تعديلات واسعة النطاق على نظامنا. الشيء الأكثر إزعاجًا هو أن هذا يعني أنه قد تغير من نظام واحد بسيط إلى نظام موزع ، وأن العمل ينطوي على معاملات رأس المال والموثوقية المتطلبات العليا أكثر صعوبة.
  • لذلك بدأ السؤال في الظهور: لم تعد مزايا بنيتي السابقة - البساطة والمباشرة - ميزة في هذا الوقت. يمكن تنفيذ الهندسة البسيطة والمباشرة بسرعة واقتصاديًا عندما تكون بيئة الأعمال والبيئة التقنية بسيطة ، ولكن عندما عندما تصبح بيئة العمل والبيئة الفنية معقدة فجأة ، فإنها لن تعمل ؛
  • الأداء المحدد هو: يصبح هيكل العمارة ومستوى الكود سريعًا معقدًا وفوضويًا - تزيد الإنتروبيا بشكل حاد ؛
  • الشيء التالي خارج عن السيطرة: تزداد صعوبة تغيير الكود ، وهناك المزيد من مشكلات الاختبار ، وبيئة الإنتاج بها المزيد من الإخفاقات والمشكلات ، وبالتالي تزداد الطاقة المستهلكة في استكشاف مشكلات الاختبار وإصلاحها ومشاكل الإنتاج وإصلاح البيانات بحدة ، وتحدث دائرة مفرغة.
  • في هذه الحالة حتى لو كان المشروع فاسدا! فشل بدأت من الصفر بلا أعذار!

لذلك أدركت حقيقة بسيطة للغاية: وجود لفافة صورة فارغة ، وفرشاة رسم من أعلى الخطوط ، واستوديو احترافي لا يضمن أنه يمكنك رسم لفافة صورة جميلة. إذا لم تكن جيدًا في الرسم ، فكل شيء خيال وفحش.

ثم أصبحت "مصلحًا محافظًا" ، لأنني أدركت أن قلب الطاولة والإصلاحات الجذرية أمر غير مسؤول ، وأن أقول ذلك بشكل سيئ هو في الواقع إخفاء الأجراس والهرب من الصعوبات. لا يمكن للناس الهروب مدى الحياة ، عليك دائمًا مواجهتها.

حتى إذا قمت بقلب الطاولة وبدء موقد جديد ، فلا تزال بحاجة إلى إيجاد طريقة لحرق هذا الموقد الجديد ، لأنه مع تطوير المشروع ، ستظل المشاكل القديمة تظهر واحدة تلو الأخرى ، وما زلت بحاجة إلى مواجهة الواقع ، لا تهرب ، وتجد طريقة.

لن تساعدك مواجهة المشكلة على أداء مشروعك الحالي بشكل جيد فحسب ، بل ستساعدك أيضًا على اغتنام الفرص بشكل أفضل عند ظهور مشاريع جديدة في المستقبل.

بغض النظر عن العمر الوظيفي أو العمر الطبيعي ، يبدأ الناس في الرغبة في المراجعة والتلخيص في هذه المرحلة ، ويصبحون أكثر قلقًا بشأن نجاح الأعمال أو فشل المشاريع والمنتجات وحتى الشركات أكثر من ذي قبل.

كنشاط تجاري ، يجب الحكم على نجاح أو فشل تطوير البرمجيات على أساس ما إذا كان بإمكانه تقديم منتجات تلبي احتياجات السوق الوظيفية للأعمال بتكلفة مقبولة ، وإيقاع زمني يمكن التنبؤ به ، ومستوى جودة ثابت.

في الواقع ، هناك أربعة عناصر لإدارة المشروع - التكلفة والجدول الزمني والنطاق والجودة. وتعتقد نظرية إدارة المشروع التقليدية أن هذه العناصر الأربعة مقيدة بشكل متبادل ويصعب تحقيقها في وقت واحد. يكمن فن إدارة المشروع في توازن العناصر الأربعة عناصر.

لقد نضجت العديد من النظريات والكتب حول هندسة البرمجيات وإدارة المشاريع. وهنا أقترح وجهة نظر جديدة من منظور المبرمج - لا يمكن المساومة على الجودة:

  • عامل الجودة ليس عاملاً يمكن التضحية به والتنازل عنه - فالتضحية بالجودة سيضر بالعوامل الثلاثة ، وعلى العكس من ذلك ، فإن السعي وراء الجودة سيفيدك في جميع الجوانب الثلاثة.
  • على فرضية الحفاظ على مستوى الجودة ، فإن العناصر الثلاثة للتكلفة والجدول الزمني والنطاق هي بالفعل مقيدة بشكل متبادل - عادةً ، التضحية بالتكلفة (العمل الإضافي) لتسريع الجدول الزمني لتقديم الوظائف التي تشتد الحاجة إليها.
  • كما يوحي "تأثير النافذة المكسورة" الشهير: إن وجود أي نوع من الظواهر غير المرغوب فيها ينقل رسالة تؤدي إلى التوسع اللامتناهي للظواهر غير المرغوب فيها ، ويجب على المرء أن يكون في حالة تأهب شديد لتلك "العيوب" العرضية والفردية والثانوية التي ، إذا تم التجاهل ، أو التجاهل ، أو عدم الاستجابة ، أو التصحيح السيئ ، فسيؤدي ذلك إلى التغاضي عن المزيد من الأشخاص "لتحطيم المزيد من زجاج النوافذ" ، وعلى الأرجح أنها تطورت إلى النتيجة الشريرة "لسد ألف ميل ، انهار في عش النمل" - فقير رمز الجودة للمشروع ، تمامًا مثل النافذة المكسورة للمبنى ، وعش النمل في السد.
  • والخبر السار هو أنه طالما أنك تضع الجودة في المشروع ، فسوف تكون تدريجيًا على مسار صحي ، وستتحسن المجالات الثلاثة الأخرى أيضًا. اعتني بالجودة ، ويمكنك التحكم إلى حد كبير في العناصر الأساسية لنجاح مشروعك أو فشله.
  • النبأ السيئ هو أن جودة المشاريع يمكن أن تخرج عن نطاق السيطرة بسهولة. في الواقع ، تكثر المشاريع ذات الجودة الرديئة والمتضخمة والمشتتة ، وحالات تحسين الجودة الأفضل والأفضل لم يسمع بها الناس لدرجة أن الناس يعتقدون أنها شيء في الفيزياء. قانون زيادة الانتروبيا هو نفس القانون الحتمي.
  • بالطبع كل شيء به درجة من المشكلة ، فعندما تكون الجودة أقل من مستوى معين ، ستتلف العناصر الثلاثة الأخرى في نفس الوقت. على العكس من ذلك ، عندما تصل الجودة إلى مستوى معين ، فإن الاستمرار في السعي وراء الجودة لن يؤدي إلى أي فوائد واضحة فحسب ، بل سيؤدي أيضًا إلى إتلاف العناصر الثلاثة الأخرى - قانون تناقص المنفعة الحدية.
  • تتطلب هذه الدرجة تقييمك وقياسه بنفسك ، وإذا كان المستوى الحالي للجودة بينهما ، فعليك التركيز على تحسين جودة البرنامج. بالطبع ، من النادر رؤية مشروع في العالم الواقعي بجودة لا تحتاج إلى أن يؤخذ على محمل الجد.

السبب الأكثر شيوعًا لفشل المشروع هو جودة الكود الرديئة

إن تراجع المشروع يشبه تدهور صحة الشخص ، وبالطبع قد يكون هناك مجموعة متنوعة من الأسباب - مثل خروج الطلب عن السيطرة ، وتعديل الأعمال ، ودوران تغييرات الموظفين. ولكن بصفتنا الفنيين لدينا ، إذا تمكنا من القيام بعملنا بشكل جيد - كتابة كود قابل للصيانة ، وخفض تكلفة الفائدة على الديون التقنية ، وتقديم بنية تطبيق قوية ومرنة ، فهي بالتأكيد فضيلة.

في حين أنه من الصعب تقدير عدد المشاريع التي يمكن أن ينقذها هذا ، فقد رأيت عشرات المشاريع في مسيرتي المهنية التي استمرت عشر سنوات ، وشاهدت الكثير منها يفشل بسبب رداءة جودة الكود. وفي الوقت نفسه ، وجدت أيضًا أن العديد من المشكلات يمكن أن يُعزى جوهر المشاريع الفاشلة بالفعل إلى الارتباك وانخفاض جودة رمز المشروع ، مثل الحلقة المفرغة الشائعة لانحلال المشروع: فوضى التعليمات البرمجية > الكثير من البق > يستغرق استكشاف الأخطاء وإصلاحها وقتًا > إعادة استخدام منخفضة > متأخر , بعد فوات الوقت > معنويات منخفضة .......

ما يسمى ب "جسر الألف ميل دمره عش النمل" ، مشكلة الكود هي عش النمل.

بعد ذلك ، دعنا نتعمق من تركيز إدارة المشروع إلى المنطقة الصغيرة نسبيًا لجودة كود المشروع. كتابة كود عالي الجودة وقابل للصيانة هو الإنجاز الأساسي للمبرمجين. تحاول هذه المقالة العثور على جوهر بعض المشاريع الفاشلة على مستوى الكود.في نفس الوقت ، تلخص بعض أنماط التصميم بناءً على خبرة التطوير الشخصي لأكثر من عشر سنوات يتم تقاسمها كوصفات طبية.

من الصعب في الواقع شرح موضوع جودة الكود من خلال مقال ، بل إنه يتطلب طول الكتاب.هناك علاقات معقدة ودقيقة بين العديد من الاهتمامات المفاهيمية المتضمنة.

أوصي بالفصل الثاني من "جمال أنماط التصميم" ، "ما البعد للحكم على جودة الكود؟ كيف يكون لديك القدرة على كتابة كود عالي الجودة؟ ، الأطروحة الأكثر ذكاءً ونظرةً التي رأيتها حول موضوع جودة الكود.

استعادة مشروع فاشل

أولاً ، انشر بضع لقطات من الكود لإلقاء نظرة على آفات وأعراض هذا المشروع الذي يعاني من مرض خطير:

  • هذه واحدة من الفئات الأساسية والأكثر تعقيدًا والأكثر تغييرًا في المشروع ، مع 4881 سطرًا من التعليمات البرمجية ؛
  • والنتيجة هي قائمة API مطولة (تحتاج القائمة إلى تمرير 4 شاشات حتى النهاية ، وهناك 180 واجهة برمجة تطبيقات عامة وخاصة) ؛
  • لا تزال هذه الفئة ، يمتد الاستيراد في الرأس إلى 139 سطرًا ، ويتم إزالة السطر الأول من إعلان الحزمة وبعض الأسطر الفارغة لاستيراد إجمالي 130 فئة!
  • لا يزال هذا المكون الغبي .. من السطر 156 إلى السطر 235 ، تم الإعلان عن 40 مكونًا لحقن التبعية الربيعية!

لن أقوم بتحليل هذا النوع من المشاكل هنا ، لكنني سأظهر فقط في البداية شدة المرض.

أعتقد أن هذا لا ينبغي أن يكون وضعًا سيئًا بشكل خاص ، فهناك مشاريع أكثر جدية من هذا ، ولكن يجب أن يكون ذلك كافياً لفضح المشكلة وتحليل السبب.

جوهر 1: التفصيل المفرط للمكونات وانتشار واجهات برمجة التطبيقات

لطالما كان مفهوم الطبقات متجذرًا بعمق في قلوب الناس ، وخاصة استقلالية طبقة منطق الأعمال ، والتي تقضي تمامًا على مشاكل خلط منطق العمل مع منطق العرض ومنطق المثابرة في السابق (العصر غير متعدد الطبقات).

لكن الأوقات الجيدة لا تدوم طويلاً. مع تعقيد وتغيرات الأعمال ، ازداد أيضًا تعقيد طبقة منطق العمل بشكل حاد ، والذي أصبح عنق زجاجة جديد لكفاءة التنمية. تكمن المشكلة في طريقة تقسيم مكونات منطق العمل - تقسيم الأعمال وفقًا لنموذج المجال. مكونات المنطق:

  • لا توجد معايير وأفضل الممارسات في الصناعة حول كيفية تصميم طبقة منطق الأعمال. في معظم المشاريع (المشاريع التي جربتها بنفسي والمشاريع التي أتيحت لي الفرصة لفهمها بعمق) ، يعتبر الجميع أمرًا مفروغًا منه يعتمد التصميم على كائنات مجال الأعمال ؛
  • على سبيل المثال: تتضمن كائنات كيان المجال الحساب والأمر والتسليم والحملة. لذلك فإن طبقة منطق العمل تصمم AccountService و OrderService و DeliveryService و CampaignService
  • هذا النهج لا يمثل مشكلة عندما يكون المشروع بسيطًا ، في الواقع ، عندما يكون المشروع بسيطًا ، يمكنك تصميم ما تريد.
  • ولكن عندما يصبح المشروع كبيرًا ومعقدًا ، تظهر المشكلات:
    • المكونات المتضخمة: عدد مكونات الخدمة هو في الأساس نفس عدد كائنات كيان المجال ، مما سيؤدي حتمًا إلى تضخم مكونات الخدمة الفردية - هناك العديد من واجهات برمجة التطبيقات ، ويصل عدد أسطر الكود إلى عدة آلاف من السطور ؛
    • المسؤوليات غير الواضحة: غالبًا ما يمتد منطق الأعمال إلى كيانات مجال متعددة ، بغض النظر عن الخدمة التي يتم تقديمها فيها ، فهو غير مناسب.وبالمثل ، من المستحيل تحديد الخدمة التي تتطلب الخدمة للعثور على منطق تنفيذ الوظيفة ؛
    • معضلة تكرار الكود أو التشابك المنطقي: عند مواجهة منطق عمل ، تم تنفيذ ارتباط معين منه في واجهة برمجة تطبيقات منطقية عمل أخرى ، ثم إذا كنت لا ترغب في تحمل التنفيذ المتكرر والرمز ، فيمكنك استدعاء واجهة برمجة التطبيقات هذه فقط. ومع ذلك ، ينتج عن هذا الاقتران والتبعية بين مكونات منطق الأعمال ، والتي ستنتشر قريبًا - ستعتمد واجهات برمجة التطبيقات الجديدة على منطق الأعمال الأخرى ، وفي النهاية تشكل تبعيات معقدة مثل شبكات العنكبوت أو حتى التبعيات الدائرية ؛
    • إن إعادة استخدام الكود وتقليل الازدواجية أمر جيد ، لكن تبعيات الاقتران المعقدة هي أيضًا ضارة جدًا - فدفع الذئب بعيدًا يجذب النمر. كأسان من النبيذ السام لتختار!

مكون المشكلة ContractService في لقطة الشاشة السابقة هو حالة نموذجية. غالبًا ما تكون هذه المكونات عنق الزجاجة للشفرة الساخنة وكفاءة تطوير المشروع بأكمله.

الوصفة 1: هيكل هرمي معكوس - مكونات منطق الأعمال لها مسؤولية واحدة وتحظر التبعيات داخل الطبقة

إن عكس جذر المشكلة يخفي الحل فعليًا ، فهو يتطلب منا فقط تغيير عاداتنا بوعي واتباع أسلوب تصميم جديد ، بدلاً من التصميم بشكل حدسي:

  • يجب تصميم طبقة منطق الأعمال كمكونات صغيرة ذات وظائف مفردة جدًا ، ويشير ما يسمى بالطبقة الصغيرة إلى عدد صغير من واجهات برمجة التطبيقات وعدد صغير من أسطر التعليمات البرمجية ؛
  • نظرًا للمسؤولية الفردية ، يجب أن يكون هناك عدد كبير من المكونات ، وكل مكون يتوافق مع نقطة وظيفة عمل محددة للغاية (أو عدة عناصر مماثلة) ؛
  • يجب أن تحدث إعادة الاستخدام (الاستدعاء ، التبعية) فقط بين طبقتين متجاورتين - تستدعي الطبقة العليا API للطبقة السفلية لإعادة استخدام وظائف الطبقة السفلية ؛
  • لذلك ، تقدم بنية النظام بشكل طبيعي شكل هرمي مقلوب: كلما اقتربنا من الطبقة العليا ، زاد عدد مكونات مشهد العمل ، وزادت قابلية إعادة استخدام الطبقة السفلية ، وقل عدد المكونات.

جوهر 2: تماسك منخفض ، اقتران عالي

تخبرنا النظرية الكلاسيكية الموجهة للكائن أن بنية الشفرة الجيدة يجب أن تكون "تماسكًا عاليًا ، واقترانًا منخفضًا":

  • تماسك عالٍ: يجب أن يحتوي المكون نفسه قدر الإمكان على جميع المعلومات والتفاصيل المهمة للوظيفة التي ينفذها ، بحيث لا يضطر القائمون على الصيانة إلى القفز إلى أماكن أخرى متعددة لتعلم المعرفة الضرورية.
  • اقتران منخفض: تحتوي المكونات على أقل قدر ممكن من الاعتماد المتبادل والفهم بحيث لا تتأثر المكونات الأخرى عندما يحتاج أحد المكونات إلى التغيير.

في الواقع ، هذان وجهان من نفس الجسم. إذا تم تحقيق تماسك عالٍ ، يتم تحقيق اقتران منخفض بشكل أساسي. على العكس ، إذا كانت درجة التماسك منخفضة جدًا ، فلا بد أن يكون هناك عدد كبير من المكونات ذات اقتران.

لقد لاحظت أن العديد من المشاريع تعاني من مشاكل التماسك المنخفض والاقتران العالي. السبب الأساسي هو أن العديد من المبرمجين ، وحتى العديد من المبرمجين ذوي الخبرة ، يفتقرون إلى الوعي في هذا الصدد - فهم ليسوا واضحين تمامًا بشأن مفهوم "التماسك" ، ولا يدركون الضرر الناجم عن تدمير التماسك ، بل إنهم أكثر وعيًا بكيفية تجنب ذلك. لا شيء للحديث عنه.

يكتب العديد من الأشخاص برامج عن طريق الحدس من البداية. وبعد الحصول على تجربة معينة ، يمكنهم بشكل عام التعرف على خطر تكرار التعليمات البرمجية ولديهم فهم قوي لقابلية إعادة الاستخدام ، لذلك سوف يقعون في فخ - السعي الأعمى لإعادة الاستخدام ، والنتيجة تدمر تماسك.

  • يوجد سوء فهم في فهم الصناعة لـ "إعادة الاستخدام" - يُعتقد أن المكونات على أي مستوى ، بما في ذلك مكونات منطق الأعمال ، يجب أن تسعى إلى أقصى حد من إعادة الاستخدام ؛
  • بالطبع ، إعادة الاستخدام أمر جيد ، ولكن يجب أن يكون هناك شرط مسبق: إعادة الاستخدام دون زيادة تعقيد النظام أمر جيد.
  • أي نوع من إعادة الاستخدام سيزيد من تعقيد النظام وهل هو سيء؟ كما ذكرنا سابقًا ، تتم إعادة استخدام واجهة برمجة تطبيقات منطقية عمل واحدة بواسطة واجهة برمجة تطبيقات أخرى لمنطق العمل - إنها ليست جيدة:
    • يدمر الاستقرار: لأن منطق العمل نفسه مرتبط بأعمال العالم الحقيقي ، وسوف يتغير العمل ؛ عندما تعيد استخدام واجهة برمجة التطبيقات التي ستتغير ، فهذا يعادل بناء مبنى شاهق على الرمال - الأساس فضفاض ؛
    • زيادة التعقيد: تقلل مثل هذه التبعيات أيضًا من قابلية قراءة الكود - في كود منطق الأعمال المعقد بالفعل ، بما في ذلك الاستدعاءات لمنطق عمل معقد آخر ، سيزداد التعقيد بشكل كبير ، وسيستمر في التدفق والنقل ؛
    • تم تدمير التماسك: نظرًا لتشتت منطق الأعمال في طرق المكونات المتعددة ، فإنه يصبح مجزأًا ، ولا يمكن رؤية المنطق الكلي وخطوات التنفيذ في مكان واحد - فقد تم تدمير التماسك ، مما يعني أيضًا أن هناك اقترانًا كبيرًا بين جميع المكونات المتضمنة في سلسلة الاستدعاء.

الوصفة 2: وضعان صحيحان لإعادة الاستخدام - قم ببناء lib وإطار العمل الخاصين بك

هناك شيئان في هندسة البرمجيات لتحقيق إعادة الاستخدام - lib و framework ،

  • مكتبة lib مخصصة لك (التطبيق) للاتصال بها ، فهي تساعدك على تنفيذ إمكانيات محددة (مثل التسجيل ، وإدارة قاعدة البيانات ، وتسلسل json ، وحساب التاريخ ، وطلب http).
  • إطار العمل مخصص لك للتوسيع ، فهو نصف تطبيق بحد ذاته. بعد تحديد تقسيم المكون وآلية التفاعل ، تحتاج إلى تمديد تطبيق معين وفقًا لقواعده وربطه ودمجه لإكمال التطبيق.
  • lib هو إعادة استخدام التوليفة ، وإطار العمل هو إعادة استخدام الوراثة. تمتد كلمة Java الأساسية الموروثة ، لذا فهي في الأساس امتداد.
  • في الماضي كان هناك قول مأثور: "التكوين خير من الميراث ، حاول ألا ترث المشاكل التي يمكن حلها بالتكوين". أنا لا أتفق مع هذا البيان ، فمن السهل تضليل المبتدئين في التفكير في أن التكوين أفضل من الميراث. في الواقع ، الميراث هو أقوى جزء من الميراث. بالطبع لا يمكن استخدام أي شيء بشكل عشوائي.
  • الاستخدام العشوائي النموذجي للوراثة هو وراثة واجهة برمجة تطبيقات معينة للفئة الأصلية. يجب أن يكون الوراثة للتمديد ، وليس للحصول على قدرة مباشرة. للحصول على قدرة ، يجب عليك استدعاء lib ، ويجب ألا تنفذ الفئة الأصلية وظائف محددة ، وهو ما يجب أن يفعله الليب. الأشياء التي يجب القيام بها.
  • ولا يجب أن ترث Class من lib من أجل استخدام lib. يتم استخدام lib ليتم استدعاؤه عن طريق الجمع ، ويتم استخدام إطار العمل ليتم توريثه وتوسيعه.
  • قم بتوسيعه مرة أخرى: يمكن أن يكون lib إما طرفًا ثالثًا (Log4j أو HttpClient أو FastJSON) أو مشروعك الخاص (مثل طبقة الثبات Dao والمرافق الخاصة بك) ؛
  • وبنفس الطريقة ، يمكن أن يكون إطار العمل إما طرفًا ثالثًا (SpringMVC ، JPA ، SpringSecurity) أو مجال عمل معين مُغلف في مشروعك (مثل التقرير ، تصدير Excel ، الترحيل أو أي عملية خوارزمية قابلة لإعادة الاستخدام).
  • بهذا المعنى ، يوجد في الواقع ثلاثة أنواع فقط من التعليمات البرمجية في المشروع: فئات lib المخصصة ، والفئات ذات الصلة بإطار العمل المخصص ، وفئات المكونات التي تعمل على توسيع الأطر الخارجية أو الأطر المخصصة.
  • للتوسع مرة أخرى: مقارنة بالماضي ، لدينا الآن ما يكفي من libs وأطر العمل التابعة لجهات خارجية لإعادة استخدامها لمساعدة المشروع على توفير الكثير من التعليمات البرمجية ، ويبدو أن أعمال التطوير أصبحت مملة وغير تقنية CRUD. ولكن بالنسبة للمشروعات ذات الأعمال المعقدة للغاية ، هناك حاجة إلى الأشخاص ذوي الخبرة والتفكير المجرد وفهم أنماط التصميم لتصميم أطر عمل موجهة للأعمال و libs موجهة للأعمال. وبهذه الطريقة فقط يمكن توفير برامج قابلة للصيانة وقابلة للتطوير وقابلة لإعادة الاستخدام. الهندسة المعمارية - بنية عالية الجودة تساعد المشروع أو المنتج على النجاح.

Crux 3: التجريد غير الكافي والتشابك المنطقي - منطق الأعمال عالي المستوى والتشابك المنطقي المنخفض المستوى

ما الذي نتحدث عنه بالضبط عندما نقول "منطق الأعمال الوارد في الكود"؟ لا يوجد معيار في الصناعة .. إضافة CRUD والحذف والتعديل والاستعلام الذي يتحدث عنه الجميع ينتمي في الواقع إلى منطق الوصول إلى البيانات ذي المستوى الأدنى.

وجهة نظري هي: ما يسمى بمنطق العمل في الكود يشير إلى جميع قواعد الإدخال والإخراج والخوارزميات والسلوكيات التي تظهر في هذا الرمز ، والتي يمكن تقسيمها عادةً إلى الفئات الخمس التالية:

  • التحقق من صحة المدخلات
  • التحقق من قاعدة العمل: عادةً ، مثل التحقق من حالة سجل المعاملة ، والمبلغ ، والحد الزمني ، والسلطة ، وما إلى ذلك ، وعادةً ما يتضمن قاعدة البيانات أو استعلام الواجهة الخارجية كمرجع ؛
  • سلوك استمرارية البيانات: أي شكل من أشكال سلوك كتابة البيانات مثل قاعدة البيانات وذاكرة التخزين المؤقت والملف والسجل وما إلى ذلك ؛
  • سلوك استدعاء الواجهة الخارجية ؛
  • إعداد قيمة الإخراج / العائد.

بالطبع ، خاصة بمثيل المكون ، قد لا تتضمن جميع الأنواع الخمسة المذكورة أعلاه من منطق الأعمال ، ولكن قد يكون هناك أنواع متعددة من منطق الأعمال.

بالنظر إلى الأمر بهذه الطريقة ، قد لا تعتقد أنه معقد بشكل خاص ، ولكن في الواقع ، يحتوي كل نوع من الأنواع الخمسة المذكورة أعلاه من منطق الأعمال عادةً أيضًا على واحد أو أكثر من منطق التنفيذ منخفض المستوى ، مثل منطق الوصول إلى بيانات CRUD أو الطرف الثالث مكالمات API.

على سبيل المثال ، للتحقق من صحة الإدخال ، من الضروري عادةً التحقق مما إذا كان السجل المقابل موجودًا. قبل استدعاء الواجهة الخارجية ، من الضروري عادةً الاستعلام عن السجلات ذات الصلة للحصول على المعلمات التي تتطلبها واجهة الاستدعاء. بعد الاتصال الواجهة ، من الضروري تحديث حالة السجل ذات الصلة وفقًا للنتيجة.

من الواضح أن هناك مستويين من المنطق هنا - منطق المستوى العالي الذي يتوافق مع متطلبات العمل ويرتبط ارتباطًا وثيقًا ، ومنطق التنفيذ للمستوى المنخفض.

إذا كان منطق المستويين غير مميز ومختلط ، فسوف تتضرر جودة الكود بشكل خطير على الفور:

  • تصبح قابلية القراءة أسوأ: يتم خلط تعقيد البعدين - تعقيد الأعمال والتعقيد التقني للتنفيذ الأساسي - معًا ، والتعقيد هو 1 + 1 > 2 يزيد بشكل حاد ، مما يضيف الكثير من العبء على الآخرين لقراءة الكود ؛
  • قابلية الصيانة السيئة: تشير قابلية الصيانة عادةً إلى تكلفة استكشاف الأخطاء وإصلاحها وحل المشكلات. عندما يتشابك مستويان من المنطق ، فإن ذلك سيجعل استكشاف الأخطاء وإصلاحها أكثر صعوبة ويسهل إصلاح الأخطاء.
  • من المستحيل الحديث عن قابلية التوسع: تشير قابلية التوسع عادةً إلى تكلفة إضافة ميزة إلى النظام. وكلما ارتفعت التكلفة ، زادت قابلية التوسع ؛ على غرار استكشاف الأخطاء وإصلاحها وإصلاح المشكلات ، من الواضح أن التشابك المنطقي سيجعل من الصعب إضافة ميزات جديدة. يؤدي بطريق الخطأ إلى تدمير الوظائف الحالية.

الكود التالي هو حالة نموذجية - التدفق المنطقي للمستوى العالي (اكتساب المعلمة ، إلغاء التسلسل ، التحقق من المعلمة ، كتابة ذاكرة التخزين المؤقت ، استمرار قاعدة البيانات ، تحديث سجلات المعاملات ذات الصلة) مغمور تمامًا في منطق التنفيذ للمستوى المنخفض (مقارنة السلسلة ، إلغاء تسلسل Json ، وعمليات redis ، وعمليات dao ، والعديد من إعداد المعلمات التافهة ومعالجة قيمة الإرجاع قبل وبعد). في القسم التالي ، سأقدم خطة إعادة هيكلة لرمز المشكلة هذا.

OverridepublicvoidupdateFromMQ (Stringcompress) {try {JSONObjectobject = JSON.parseObject (compress)؛ if (StringUtils.isBlank (object.getString ("type")) || StringUtils.isBlank (object.getString ("mobile")) || StringUtils .isBlank (object.getString ("data"))) {thrownewAppException ("استثناء معلمة إرجاع MQ") ؛} logger.info (object.getString ("mobile") + " < < < < < < < < < احصل على بيانات التفويض من MQ > > > > > > > > > "+ object.getString (" type ")) ؛ Mapmap = newHashMap () ؛ map.put (" type "، CrawlingTaskType.get (object.getInteger (" type "))) ؛ map.put (" mobile "، كائن .getString ("mobile")) ؛ قائمة < مهمة الزحف > list = baseDAO.find ("fromcrtcwherec.phoneNumber =: mobileandc.taskType =: type"، map) ؛ redisClientTemplate.set (object.getString ("mobile") + "_" + object.getString ("type") ، CompressUtil .compress (object.getString ("data"))) ؛ redisClientTemplate.expire (object.getString ("mobile") + "_" + object.getString ("type")، 2 * 24 * 60 * 60) ؛ / / حفظ تم تخزينه بنجاح في redis لمدة 48 ساعة CrawlingTaskcrawlingTask = null؛ // providType: (0: Xinyan، 1XX Alipay، 2: ZZ Taobao، 3: TT Taobao) if (CollectionUtils.isNotEmpty (list)) {crawlingTask = list. get (0)؛ crawlingTask.setJsonStr (object.getString ("data"))؛} else {// Add crawlingTask = newCrawlingTask (UUID.randomUUID (). toString ()، object.getString ("data")، object .getString ("mobile") ، CrawlingTaskType.get (object.getInteger ("type"))) ؛ crawlingTask.setNeedUpdate (صحيح) ؛} baseDAO.saveOrUpdate (crawlingTask) ؛ // حفظ نقاط السمسم في xyzif ("3". equals ( object.getString ("type"))) {Stringdata = object.getString ("data") ؛ Integerzmf = JSON.parseObject (data) .getJSONObject ("taobao_user_info"). getInteger ("zm_score") ؛ Mapparam = newHashMap () ؛ param.put ("phoneNumber"، object.getString ("mobile")) ؛ قائمة < دبرسون > list1 = personBaseDaoI.find ("fromxyzwherephoneNumber =: phoneNumber"، param)؛ if (list1! = null) {for (Dpersondperson: list1) {dperson.setZmScore (zmf)؛ personBaseDaoI.saveOrUpdate (dperson)؛ AppFlowUtil.updateApp .getToken () ، null ، null ، zmf) ؛ // الاستعلام عن مصادقة جدول متعدد المستأجرين ، اضبط مصادقة Taobao على 0 وضبطها على 1}}}} catch (Exceptione) {logger.error ("Failed to update myMQ Authorization information "، e)؛ thrownewAppException (e.getMessage ()، e)؛}}

الوصفة 3: التحكم في الفصل المنطقي - نمط قالب الأعمال لقالب الأعمال المتداخلة

مفتاح حل "التشابك المنطقي" هو إيجاد آلية عزل تفصل بين منطق المستويين - فصل منطق التحكم. فوائد الفصل عديدة:

  • وفقًا للتجربة ، عندما نبدأ في الاحتفاظ بجزء من التعليمات البرمجية ، يجب علينا أولاً أن نفهم عمليتها الشاملة وخوارزمية وسلوكها ، بدلاً من دراسة تفاصيلها في البداية ؛
  • بعد فصل منطق التحكم ، ما عليك سوى قراءة قسم المستوى العالي لفهم المحتوى أعلاه ، ويتم تقليل عبء قراءة الكود إلى حد كبير ، وتحسين قابلية قراءة الكود بشكل كبير ؛
  • فهم الكود هو أساس كل أعمال الصيانة وإعادة البناء اللاحقة ، وعدد المرات التي تتم فيها قراءة جزء من الكود أعلى بكثير من عدد المرات التي يتم فيها تعديله (ترتيب من حيث الحجم أعلى) ، وبالتالي فإن قابلية قراءة الكود للبشر لا يمكن التأكيد عليها ، ومع ذلك ، فإن تحسين قابلية القراءة يمكن أن يحسن بشكل كبير من قابلية صيانة النظام وهو أيضًا الهدف الرئيسي لإعادة البناء.
  • في الوقت نفسه ، وفقًا لتجربتي ، غالبًا ما تكون التغييرات في منطق العمل عالي المستوى أكثر تكرارًا من تلك الخاصة بمنطق تنفيذ المستوى المنخفض. بالطبع ، يختلف وضع الأنواع المختلفة من المشاريع ، وغالبًا ما تكون النقاط الزمنية لتغييراتها مختلفة ؛
  • في هذا السياق ، تكون فوائد فصل منطق التحكم أكثر وضوحًا: في كل مرة تحتاج صيانة وتوسيع وظائف النظام فقط إلى تغيير رمز Levle ، والمستوى الآخر لا يتأثر أو يكون له تأثير ضئيل ، مما سيقلل بشكل كبير من التكلفة ومخاطر التعديل.

بعد تلخيص الدروس والخبرات الخاصة بمشاريع متعددة في الماضي ، انتهيت من أفضل الممارسات أو نمط التصميم - نمط قالب الأعمال لـ NestedBusinessTemplat ، والذي يمكنه فصل نوعين من المنطق بشكل بسيط وفعال للغاية. دعنا نلقي نظرة على الكود أولاً:

publicclassXyzService {abstractclassAbsUpdateFromMQ {publicfinalvoiddoProcess (StringjsonStr) {try {JSONObjectjson = doParseAndValidate (jsonStr)؛ cache2Redis (json)؛ saveJsonStr2CrawingTask (json4}} " ,e);thrownewAppException(e.getMessage(),e);}}protectedabstractvoidupdateZmScore4Dperson(JSONObjectjson);protectedabstractvoidsaveJsonStr2CrawingTask(JSONObjectjson);protectedabstractvoidcache2Redis(JSONObjectjson);protectedabstractJSONObjectdoParseAndValidate(Stringjson)throwsAppException;}@SuppressWarnings({"unchecked","rawtypes "}) publicvoidprocessAuthResultDataCallback (Stringcompress) {newAbsUpdateFromMQ () {@ OverrideprotectedvoidupdateZmScore4Dperson (JSONObjectjson) {// حفظ نقاط السمسم في xyzif (" 3 ".equals (json.getString) ({" typeget) data ")؛ Integerzmf = JSON.parseObject (data) .getJSONObject (" taobao_user_info "). getInteger (" zm_score ")؛ Mapparam = newHashMap ()؛ param.put (" phoneNumber "، json.getString (" mobile ")) ؛ قائمة < دبرسون > list1 = personBaseDaoI.find ("fromxyzwherephoneNumber =: phoneNumber"، param)؛ if (list1! = null) {for (Dpersondperson: list1) {dperson.setZmScore (zmf)؛ personBaseDaoI.saveOrUpdate (dperson)؛ AppFlowUtil.updateApp .getToken ()، null، null، zmf)؛}}}} @ OverrideprotectedvoidsaveJsonStr2CrawingTask (JSONObjectjson) {Mapmap = newHashMap ()؛ map.put ("type"، CrawlingTaskType.get (json.getInteger ("type"))) ؛ map.put ("mobile"، json.getString ("mobile"))؛ قائمة < مهمة الزحف > list = baseDAO.find ("fromcrtcwherec.phoneNumber =: mobileandc.taskType =: type"، map)؛ CrawlingTaskcrawlingTask = null؛ // provideType: (0: xx، 1yy Alipay، 2: zz Taobao، 3: tt Taobao) إذا (CollectionUtils.isNotEmpty (list)) {crawlingTask = list.get (0)؛ crawlingTask.setJsonStr (json.getString ("data"))؛} else {// Add crawlingTask = newCrawlingTask (UUID.randomUUID (). toString ( )، json.getString ("data")، json.getString ("mobile")، CrawlingTaskType.get (json.getInteger ("type")))؛ crawlingTask.setNeedUpdate (true)؛} baseDAO.saveOrUpdate (crawlingTask)؛ } @ Overrideprotectedvoidcache2Redis (JSONObjectjson) {redisClientTemplate.set (json.getString ("mobile") + "_" + json.getString ("type")، CompressUtil.compress (json.getString ("data"))) ؛ redisClientTemplate. expire (json.getString ("mobile") + "_" + json.getString ("type")، 2 * 24 * 60 * 60)؛} @ OverrideprotectedJSONObjectdoParseAndValidate (Stringjson) throwsAppException {JSONObjectobject = JSON.parseObject (json)؛ إذا (StringUtils.isBlank (object.getString ("type")) || StringUtils.isBlank (object.getString ("mobile")) || StringUtils.isBlank (كائن .getString ("data"))) {thrownewAppException ("استثناء معلمة إرجاع MQ") ؛} logger.info (object.getString ("mobile") + " < < < < < < < < < احصل على بيانات التفويض من MQ > > > > > > > > > "+ object.getString (" type ")) ؛ returnobject ؛}}. doProcess (compress) ؛}

إذا كنت معتادًا على أنماط تصميم GOF23 الكلاسيكية ، فمن السهل أن تجد أن مثال الكود أعلاه هو في الواقع تطبيق لنمط تصميم أسلوب القوالب ، ولا شيء جديد.

هذا صحيح ، لم أقترح أو ابتكر أي شيء جديد في هذا الحل. لقد عثرت للتو على نمط تصميم أسلوب القوالب في الممارسة العملية. إنه مناسب حقًا لحل مشكلات التشابك المنطقي المنتشرة ، ووجدت أيضًا أن عددًا قليلاً من المبرمجين يمكنهم استخدام هذا بفاعلية التصميم.نمط ؛ جزء من السبب قد يكون عدم وجود الكثير من الناس على دراية بمشكلة "التشابك المنطقي" ، ولا يوجد الكثير من الأشخاص على دراية بنمط التصميم هذا ويمكنهم استخدامه بحرية ، والتقاطع بين الاثنين أمر مثير للشفقة بطبيعة الحال ؛ ومهما كان السبب ، فإن النتيجة هي أن هذه المشكلة منتشرة وأصبحت مشكلة شائعة.

أرى بعض المبرمجين المهتمين بجودة الكود. حلهم يكون من خلال "البرمجة المهيكلة" و "البرمجة المعيارية":

  • استخراج منطق المستوى المنخفض إلى وظيفة خاصة ، والتي يتم استدعاؤها مباشرة بواسطة الوظيفة حيث يوجد رمز المستوى العالي ؛
    • المشكلة 1: الاتصال الصعب ليس مرنًا: أولاً وقبل كل شيء ، على الرغم من أن هذا له تأثير عزل معين ، فإن المستويين ثابتان ومتصلان بشدة ، ولا يمكن استبدال المستوى المنخفض ببساطة. لا يزال البديل بحاجة إلى التعديل والتأثير على المستوى العالي جزء المستوى
    • المشكلة 2 تؤدي الرؤية في المكون إلى حدوث ارتباك: تكون الوظيفة الخاصة المستخرجة مرئية بشكل عام في المكون الحالي - وهي مرئية أيضًا لوظائف المستوى العالي الأخرى غير ذات الصلة ، ولا يزال هناك تشابك منطقي بين الوحدات النمطية المختلفة. هذا شائع جدًا في الكود الساخن في العديد من المشاريع ، والمشكلة أيضًا بارزة جدًا: تخيل مكونًا يحتوي على عشرات من واجهات برمجة التطبيقات ، كل وظيفة API لها وظيفة أو وظيفتان خاصتان مرتبطتان ، ثم درجة الارتباك والصيانة داخل هذا المكون الصعوبة لا يطاق.
  • استخرج منطق المستوى المنخفض إلى مكونات جديدة للمكونات حيث يوجد رمز المستوى العالي للاعتماد والاستدعاء ؛ قد يضيف المبرمجون الأكثر خبرة طبقة من الواجهات ويستخدمون حقن تبعية Spring ؛
    • مشكلة 1 فيضان واجهة برمجة التطبيقات (API): يبدو أن استخراج المكونات الجديدة يؤدي إلى تجنب قيود "البرمجة المهيكلة" ، ولكنه يجلب مشكلات جديدة - إغراق واجهة برمجة التطبيقات (API): نظرًا لأن المكالمات بين المكونات يمكن أن تمر فقط من خلال الطرق العامة ، ولا توجد العديد من فرص إعادة الاستخدام ضرورية لإعلان أعلى مستوى من الرؤية للجمهور.
    • المشكلة الثانية: اعتماد المكونات على نفس المستوى خارج عن السيطرة: بعد تكاثر المكونات وواجهات برمجة التطبيقات ، سيؤدي ذلك حتماً إلى الاعتماد المتبادل بين المكونات. وبعد أن يخرج عن السيطرة ببطء ، سيصبح في النهاية أن جميع المكونات تعتمد على معظم تحدث المكونات الأخرى ، وحتى التبعيات الدائرية ؛ على سبيل المثال ، المكون الذي يحتوي على 130 ContractService لاستيراد واحد و 40 مكونًا تابعًا للربيع.

فيما يلي مقدمة لاستخدام نمط تصميم أسلوب النموذج ، والذي يتم تلخيصه بإيجاز على النحو التالي:

  • يتم تغليف المنطق عالي المستوى في وظيفة نهائية للفئة الأصلية المجردة AbsUpdateFromMQ لتشكيل قالب منطق الأعمال ؛
  • تضمن الوظيفة النهائية أن المنطق الموجود فيه لن يتضرر من خلال العبث المتعمد أو غير المتعمد بالفئات الفرعية ، لذلك يجب أن تغلف الأشياء الثابتة نسبيًا في منطق الأعمال. بالنسبة لتلك الأجزاء المتغيرة والأجزاء غير المؤكدة مؤقتًا ، فإن نقاط الامتداد الاحتياطية في شكل وظيفة محمية مجردة ؛
  • تشبه الفئة الفرعية (فئة داخلية مجهولة) "ملء الفراغات" ، وملء القالب لتنفيذ منطق المستوى المنخفض - تنفيذ نقاط امتداد الوظيفة المحمية ؛ نظرًا لأن نقاط الامتداد مجردة في الفئة الأصلية ، سيقوم المترجم بتذكير الفئة الفرعية من ماذا يجب أن يوسع المبرمج.

إذن كيف تتجنب القيود الأربعة للحلين المذكورين أعلاه:

  • عندما يحتاج المستوى المنخفض إلى التعديل أو الاستبدال ، فإنه يحتاج فقط إلى تمديد فئة فرعية جديدة من الفئة الأصلية ، ولا يحتاج الفصل الأصلي إلى أي تغييرات على الإطلاق ؛
  • سواء كانت الفئة الأصل أو الفئة الفرعية ، فإن الوظيفة الموجودة فيها غير مرئية لمكون XyzService الخارجي ، حتى الوظيفة العامة في الفئة الأصلية غير مرئية ، لأن كائن المثيل الذي يحتفظ بالفئة فقط يمكنه الوصول إلى الوظيفة ؛
  • سواء كانت فئة أصل أو فئة فرعية ، فجميعها موجودة كفئة داخلية من XyzService ، ولن تتم إضافة ملفات فئة جافا جديدة ، ولن تتم إضافة عدد كبير من واجهات برمجة التطبيقات التي لا معنى لها (يمكن إعادة استخدام واجهات برمجة التطبيقات داخل المشروع فقط أو إصدارها للاستخدام الخارجي. من المنطقي استخدامه فقط ، فقط واجهة برمجة تطبيقات المتصل فقط ليست ضرورية) ؛
  • بالطبع ، لا توجد مشكلة خروج تبعيات المكونات عن نطاق السيطرة.

في الواقع ، تم استخدام نمط تصميم أسلوب القوالب على نطاق واسع في المشاريع مفتوحة المصدر القائمة على إطار العمل مثل SpringFramework. يجب أن يجلب هذا الإلهام والشرح لنا لمبرمجي تطوير التطبيقات ، ولكن من المؤسف أن الصناعة لم تلاحظها وتستخدمها بالكامل القيمة.

وضع NestedBusinessTemplat هو تطبيقه الكامل والنشط. إن الوضعين الصحيحين لإعادة الاستخدام المذكورين في القسم السابق هما إنشاء lib وإطار العمل الخاصين بك. في الواقع ، NestedBusinessTemplat هو إطار عمل المشروع نفسه.

المشكلة 4: الصدفية في كل مكان إذا كان آخر

بغض النظر عن لغة البرمجة الخاصة بك ، فإن أول بيان تحكم منطقي تتعلمه يجب أن يكون إذا كان آخر ، ولكن للأسف ستصبح عادة سيئة تضر بجودة المشروع بعد أن تبدأ عمل برمجة حقيقي.

تواجه جميع المشاريع تقريبًا مشكلة إذا كان هناك فيضان آخر ، لكنها لم تولي اهتمامًا كافيًا لليقظة ، بل إنها اعتبرت طبيعية من قبل العديد من المبرمجين.

بادئ ذي بدء ، اسمحوا لي أن أشرح لماذا إذا كان هذا الشيء الذي يبدو غير ضار ضارًا ويحتاج إلى مراقبة صارمة:

  • إذا كان وإلا ...
  • تكمن مشكلة الترميز الثابت في أنه عندما تتغير المتطلبات ، يجب تعديلها في كل مكان ، وهو أمر يسهل تفويته وارتكاب الأخطاء ؛
  • خذ جزءًا من التعليمات البرمجية كمثال لتحليل محدد:
  • if ("3" .equals (object.getString ("type"))) {String data = object.getString ("data")؛ Integer zmf = JSON.parseObject (data) .getJSONObject ("taobao_user_info"). getInteger ( "zm_score")؛ Map param = new HashMap ()؛ param.put ("phoneNumber"، object.getString ("mobile"))؛ قائمة < دبرسون > list1 = personBaseDaoI.find ("from xyz where phoneNumber =: phoneNumber"، param)؛ if (list1! = null) {for (Dperson dperson: list1) {dperson.setZmScore (zmf)؛ personBaseDaoI.saveOrUpdate (dperson)؛ AppFlowUtil .updateAppUserInfo (dperson.getToken ()، null، null، zmf)؛}}}
  • if ("3" .equals (object.getString ("type")))
    • من الواضح أن "3" هنا رقم سحري ، لا أحد يعرف ما تعنيه 3 ، فقط تخمين ؛
    • لكن مجرد إعادة هيكلة "3" إلى ABC_XYZ الثابت لا يتحسن كثيرًا ، لأنه إذا كان (ABC_XYZ.equals (object.getString ("type")) لا يزال أسلوب برمجة موجهًا إجرائيًا ولا يمكن تمديده ؛
    • الثابت ABC_XYZ المشار إليه في كل مكان ليس أفضل بكثير من الرقم السحري المشفر في كل مكان ، إنه له معنى فقط ؛
    • ليس من الأفضل ترقية الثوابت إلى أنواع تعداد التعداد. عند إضافة الأنواع التي يجب الحكم عليها أو تغيير قواعد الحكم ، لا تزال بحاجة إلى التعديل في كل مكان - جراحة البندقية (تعديل البندقية)
  • ليس كل شيء إذا كانت الآخرين ضارة ، مثل إذا كانت (list1! = null) {في المثال أعلاه غير ضارة ، فلا داعي للقضاء عليها ، ولا يمكن إزالتها. أساس تحديد ما إذا كان ضارًا:
    • إذا كانت الحالة المتغيرة للحكم لها احتمالان فقط (مثل منطقية ، مثل الحكم الباطل) ، فهي غير ضارة ؛
    • على العكس من ذلك ، إذا كان المتغير يحكم عليه ما إذا كان يحتوي على حالات متعددة ، ويمكن إضافة حالات جديدة في المستقبل ، فهذه مشكلة ؛
    • بيان التبديل ضار بلا شك ، لأنه غالبًا ما يكون هناك العديد من الحالات التي يتم فيها استخدام المفتاح.

الوصفة 4: نوع تعداد فرط الدم - نوع العد الغني

كما يوضح التحليل السابق ، بالنسبة للحالة والنوع إذا كانت الأحكام الشرطية موجودة على نطاق واسع في الكود ، فإن إعادة بناء القيم المقارنة إلى أنواع التعداد الثابت أو التعداد لا تتحسن كثيرًا - لا يزال المستخدم يعتمد بشكل مباشر على قيمة التعداد المحددة أو ثابتًا بدلاً من الاعتماد على فكرة مجردة.

لذلك ظهر الحل بشكل طبيعي: مزيد من التغليف التجريدي بناءً على نوع التعداد للحصول على ما يسمى بنوع التعداد "المزدحم" ، يتحدث الكود:

  • تنفيذ مجموعة متنوعة من آليات إعلام النظام ، الأسلوب التقليدي:
  • تعداد NOTIFY_TYPE {email، sms، wechat؛} // أولاً عرّف التعداد - نوع تعداد "ضعيف" يحدد فقط القيم التي لا تحتوي على أي سلوك if (type == NOTIFY_TYPE.email) {// إذا حكم على النوع واستدع تنفيذ آليات الإعلام المختلفة . . . } else if (type = NOTIFY_TYPE.sms) { . . . }آخر{ . . . }
  • تنفيذ مجموعة متنوعة من طرق إعلام النظام ، نوع تعداد الازدحام - وضع Rich Enum Type:
  • تعداد NOTIFY_TYPE {// 1 ، حدد نوع التعداد الذي يحتوي على "ازدحام" آلية تنفيذ الإعلام البريد الإلكتروني ("Mail" ، NotifyMechanismInterface.byEmail ()) ، sms ("SMS" ، NotifyMechanismInterface.bySms ()) ، wechat ("WeChat" ، NotifyMechanismInterface.byWechat ()) ؛ مذكرة سلسلة NotifyMechanismInterface notifyMechanism ؛ NOTIFY_TYPE خاص (مذكرة سلسلة ، NotifyMechanismInterface notifyMechanism) {// 2 ، مُنشئ خاص ، يُستخدم لتهيئة قيم التعداد this.memo = مذكرة ؛ this.notifyMechanism = notifyMechanism ؛ } // حاصل ... } الواجهة العامة NotifyMechanismInterface {// 3. تحديد الواجهة أو فئة الأصل المجردة لآلية الإعلام منطقية عامة doNotify (سلسلة الرسائل) ؛ public static NotifyMechanismInterface byEmail () {// 3.1 إرجاع تنفيذ السياسة التي تحدد آلية إعلام البريد الإلكتروني - مثيل فئة داخلية مجهول إرجاع NotifyMechanismInterface الجديد () { doNotify المنطقي العام (رسالة سلسلة) { ...... } } ؛ } العامة الثابتة NotifyMechanismInterface bySms () {// 3.2 تحديد استراتيجية تنفيذ آلية إعلام الرسائل القصيرة إرجاع NotifyMechanismInterface الجديد () { doNotify المنطقي العام (رسالة سلسلة) { ...... } } ؛ } NotifyMechanismInterface العام بواسطةWechat () {// 3.3 تحديد استراتيجية تنفيذ آلية إعلام WeChat إرجاع NotifyMechanismInterface الجديد () { doNotify المنطقي العام (رسالة سلسلة) { ...... } } ؛ } } // 4 ، استخدم المشهد NOTIFY_TYPE.valueof (type) .getNotifyMechanism (). doNotify (msg)؛
  • نوع تعداد فرط الدم - مزايا نمط نوع العد الغني:
    • ليس من الصعب أن تجد أن هذا هو في الواقع مزيج ذكي من نوع التعداد ونمط الإستراتيجية ؛
    • عند الحاجة إلى إضافة طريقة إعلام جديدة ، ما عليك سوى إضافة قيمة إلى فئة التعداد NOTIFY_TYPE ، وفي نفس الوقت إضافة طريقة by إلى واجهة السياسة NotifyMechanismInterface لإرجاع تنفيذ السياسة المقابل ؛
    • عندما تحتاج إلى تعديل تفاصيل تنفيذ آلية الإعلام ، ما عليك سوى تعديل تنفيذ السياسة المطابق في NotifyMechanismInterface ؛
    • بغض النظر عما إذا تمت إضافة آلية الإعلام أو تعديلها ، فإن المتصل لا يتأثر على الإطلاق ، فهي لا تزال NOTIFY_TYPE.valueof (type) .getNotifyMechanism (). doNotify (msg)؛
  • مقارنة بنمط إستراتيجية نموذج الإستراتيجية التقليدي: يمكن لنمط الإستراتيجية الشائعة أيضًا القضاء على حكم "if else" ، ولكنه أكثر صعوبة في التنفيذ ، وهناك حاجة إلى تطوير المزيد من الفئات والكود:
    • يحتاج تنفيذ كل استراتيجية إلى تعريفه بشكل منفصل كفئة ؛
    • تحتاج أيضًا إلى فئة سياق للتهيئة - استخدم الخريطة لتعيين النوع وتنفيذ الإستراتيجية المقابلة ؛
    • احصل على الإستراتيجية المحددة من السياق عند استخدام ؛
  • مزيد من الازدحام في نوع التعداد الغني:
    • يحتوي نوع التعداد في المثال أعلاه على سلوك ، لذلك يتم احتسابه بالفعل كنموذج احتقان ، ولكن يمكن أن يكون احتقانًا إضافيًا ؛
    • على سبيل المثال ، في بعض السيناريوهات ، من الضروري فقط إجراء عملية حسابية بسيطة على قيمة التعداد للحصول على علامة معينة ، ثم ليست هناك حاجة لتلخيص منطق الحساب في واجهة مثل NotifyMechanismInterface ، وهي خدعة لقتل الدجاج ؛
    • في هذا الوقت ، يمكنك إضافة دالة ثابتة إلى نوع التعداد لتغليف منطق الحساب البسيط ؛
  • مزيد من التجريد من تنفيذ السياسة:
    • عندما يكون لكل تنفيذ إستراتيجية (byEmail bySms byWechat) أجزاء مشتركة ومنطق متكرر ، يمكن استخراجه في فئة أصل مجردة ؛
    • ثم تمامًا مثل الفصل السابق - نموذج قالب الأعمال الخاص بقالب الأعمال المتداخلة ، حقق فصلًا منطقيًا أنيقًا وأعد الاستخدام بين الفئات الفرعية.

استطلاع الحريق قبل إعادة البناء:

قم بتجميع دليل / فهرس قاعدة بيانات لمشروعك - CODEX

ما سبق هو 4 مشاكل جودة التعليمات البرمجية الأكثر شيوعًا والأكثر تأثيرًا وحلولها التي لخصتها:

  • مكونات طبقة منطق الأعمال بمسؤولية فردية ، ودقة صغيرة ، وتماسك عالي ، وإقران منخفض - هيكل هرمي مقلوب ؛
  • بناء طبقة lib وإطار عمل المشروع نفسه - وضع إعادة الاستخدام الصحيح ؛
  • نمط قالب الأعمال لـ NestedBusinessTemplate - فصل منطق التحكم ؛
  • نوع التعداد المزدحم نوع التعداد الغني - التخلص من الأحكام الشرطية المشفرة إذا كان الأمر كذلك ؛

الخطوة التالية هي كيفية إعادة تشكيل هذه الجوانب الأربعة ، لكن الأمور ليست بهذه البساطة.

على الرغم من أن كل المحتوى أعلاه يأتي من الخبرة العملية ، لتطبيقه على مشروعك المحدد ، فإنك لا تزال بحاجة إلى خطوة - استطلاع النيران - لمعرفة السياق المنطقي والخوارزمية وحتى تفاصيل تنفيذ الوحدة التي تريد إعادة تشكيلها ، وإلا فإنك سوف تفعل ذلك بتسرع. فمن السهل أن تفوتك التفاصيل الأساسية وتسبب مخاطر ، ويصعب ضمان كفاءة إعادة البناء ، وأنت عالق في موقف محرج.

في عام 2019 ، مررت بثلاثة مشاريع برمز شديد الفوضى. وكان أكبر مكسب هو العثور على أفضل ممارسة لفرز الشفرة السيئة - المخطوطة:

  • في عملية قراءة الكود ، أضف تعليقات منظمة في المناصب الرئيسية ، مثل: // CODEX ProjectA 1 عملية موعد الفحص المادي 1 إدخال واجهة برمجة تطبيقات خدمة المواعيد

  • ما يسمى التعليق التوضيحي المنظم هو عكس العناصر والوحدات النمطية وخطوات العملية والمعلومات الأخرى في محتوى التعليق التوضيحي من خلال بادئة الرقم والفاصل وما إلى ذلك من التسمية القياسية ، على غرار العنوان 1 ، 2 ، 3 في تحرير النص ؛
  • ثم قم بتعيين أدوات IDE للتعرف على هذا التعليق الخاص للعرض المنظم. تأثير عرض مهام Eclipse مشابه للشكل التالي ؛

  • هذا العرض المهيكل هو في الأساس فهرس ودليل قاعدة الكود. يختلف عن مستند جافادوك ، يتمتع المخطوطة بمستوى منطقي أكثر وضوحًا وسهولة أكبر في البحث عن الكود.
  • تتم مشاركة هذه التعليقات المنظمة مع الفريق بعد إرسالها مع الكود ؛
  • مثل هذا الفهرس الدقيق والمشترك والحي لشفرة المصدر سيساعد بلا شك بشكل كبير في تطوير الفريق بأكمله وصيانته ؛
  • علاوة على ذلك ، إذا أضفت الكلمة الأساسية Markdown في CODEX ، فيمكنك ببساطة معالجة CODEX التي تم تصديرها وتحويلها إلى مخطط تسلسل لمنطق الأعمال ، كما هو موضح أدناه.

ملاحظات ختامية - لا ترقى إلى أفضل عصر للمبرمجين

ليس هناك شك في أن هذا هو أفضل عصر للمبرمجين ، فقد اجتاحت موجة الإنترنت كل ركن من أركان العالم ، وتعتمد جميع مناحي الحياة بشكل متزايد على تكنولوجيا المعلومات. في الماضي ، كانت شركات البرمجيات وشركات الإنترنت والصناعة المصرفية فقط هي التي توظف المبرمجين. ومع انتشار الحوسبة السحابية ، وظهور الإنترنت الصناعي والإنترنت + ، بدأت المزيد والمزيد من الشركات التقليدية في توظيف المبرمجين لبناء أنظمة تكنولوجيا المعلومات لدعم الأعمال عمليات.

أدى الطلب القوي على تكنولوجيا المعلومات التي يروج لها رأس المال إلى جعل المبرمجين من المواهب النادرة ، وفي منصات التوظيف الرئيسية ، كان عدد المناصب ومستويات رواتب المبرمجين من بين الأفضل منذ فترة طويلة.

ولكن كيف هو الأداء العام لمجموعتنا ، اسأل نفسك ، أجد أنه غير مرض ، وقليل من المشاريع التي جربتها ولاحظتها عن قرب يمكن وصفها بأنها ناجحة. النجاح هنا ليس نجاحًا تجاريًا ، فهو يقتصر على كونه مشروعًا برمجيًا ويمكن تسليم المشروع باستمرار على مدار فترة زمنية طويلة بتكلفة وجودة مقبولة.

غالبًا لا يرتبط نجاح الأعمال قصير المدى بالضرورة بنجاح المشروع ، فالمشروع الناجح تجاريًا قد لا يعمل بشكل جيد في الهندسة ، ولكنه نجاح مؤقت فقط من خلال استثمار موارد رأسمالية ضخمة. هذا كل شيء.

في نهاية المطاف ، نحن ، مجتمع المبرمجين ، مسؤولون عن سمعتنا ، وعلى المدى الطويل ، سوف نستفيد من سمعتنا أو ندمرها على المدى الطويل.

أعتقد أن أعظم سمعة وأهم جودة مهنية للمبرمج هي مساعدة الفريق والشركة والمنظمة على خلق قيمة وزيادة فرص النجاح من خلال كتابة كود عالي الجودة والقيام بعمل جيد في كل مشروع ومنتج.

آمل أن تكون التجربة والأساليب التي تمت مشاركتها في هذه المقالة مفيدة في هذا الأمر!

هذا المقال صديق مديري الفني: لقد أمضى الأخ كوان نصف شهر في كتابة مقال عن الضمير ، أوصي به بشدة للجميع ، فالمقال طويل جدًا وصعب وقيِّم ، يمكنك جمعه وقراءته عدة مرات. آمل أن تتمكن من إعادة توجيهها وقراءتها بعد قراءتها ، ويجب أن يرى المزيد من الأشخاص المقالات الجيدة.

حوسبة غير متجانسة العصر الذهبي الذي تغير السوبر غير متجانسة الحوسبة الخادم FP5468G2 تحقيق؟

مكافحة الوباء، شي جين بينغ هذه الكلمات الرنانة

UAV الدعاية دورية، والتحقيق الوباء، تسليم المخدرات التطهير، والكفاح ضد السارس معركة الروبوت تجسد جنود الصلب

الجانب حرب "الطاعون" | البيانات الكبيرة، 5G، والذكاء الاصطناعي ..... سر تشجيانغ الرقمية مكافحة السارس "سلاح"

أفعل المطورين المستقلين من السنة الثانية

قوانغدونغ الفريق الطبي "مقدما" قوة جينغتشو هونغهو لكسر جديد الوقاية تاج الالتهاب الرئوي والسيطرة معضلة

الترتيب تنغ جيثب TOP العجاف والمطورين الصينيين في العمل

وجدت البرازيل فيروس غامض، و 90 لا يمكن التعرف على الجينات والعلماء كلمات مثيرة للقلق

عدوى "كا" في الحب |! 'أو اسمحوا لي أن "اللعب السلطة تونجكسيانج بعد 90 أعضاء الحزب يونغ

الحرب مصورة "الطاعون": Wucheng "12 ساعة"

الخطوة هانغتشو! كلتا يديه، أن الفوز في مباراتين

قسم الحب إلى النهر! شكرا لك تصمد "مظلة الحماية" للحرب "الطاعون"