هو إعادة بيع ديون طريق تجميع الأخطاء سيئة ؟

StackOverflow https://stackoverflow.com/questions/404717

  •  03-07-2019
  •  | 
  •  

سؤال

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

هل كانت مفيدة؟

المحلول

هذه تقنية شائعة ومفيدة للغات المترجمة بشكل ثابت. يمكن ذكر النسخة العامة لما تفعله على النحو التالي:

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

هناك مجموعة متنوعة من الكحيلات:

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

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

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

ما تفعله حقًا هو استخدام المترجم لمساعدتك في فحص جميع الأماكن في الكود الذي قد تحتاج إلى تغييره.

نصائح أخرى

لا أعتمد أبدًا على التجميع البسيط عند إعادة التجديد ، يمكن أن يتم تجميع الكود ولكن قد تم تقديم الأخطاء.

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

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

لا أرى أي مشكلة في ذلك. إنه آمن ، وطالما أنك لا ترتكب تغييرات قبل التجميع ، فليس له تأثير طويل الأجل. أيضًا ، لدى Resharper و VS أدوات تجعل العملية أسهل قليلاً بالنسبة لك.

يمكنك استخدام عملية مماثلة في الاتجاه الآخر في TDD - تكتب رمزًا قد لا يتم تحديد الطرق المحددة ، مما يؤدي إلى عدم تجميعها ، ثم تكتب رمزًا كافيًا لتجميعه (ثم اجتياز الاختبارات ، وما إلى ذلك ...)

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

يتحدث عن تحديد خصائص الكود التي تعمل قبل إجراء تغيير وتفعل ما يسميه إعادة إعادة تصميم Scratch. هذا هو المقاطع لإيجاد خصائص الكود ثم رمي النتائج بعيدا.

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

النظر في هذا

class myClass {
     void megaMethod() 
     {
         int x,y,z;
         //lots of lines of code
         z = mysideEffect(x)+y;
         //lots more lines of code 
         a = b + c;
     }
}

هل يمكن أن تخرج الإضافة

class myClass {
     void megaMethod() 
     {
         int a,b,c,x,y,z;
         //lots of lines of code
         z = addition(x,y);
         //lots more lines of code
         a = addition(b,c);  
     }

     int addition(int a, b)
     {
          return mysideaffect(a)+b;
     }
}

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

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

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

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

أود فقط أن أضيف إلى كل الحكمة هنا أن هناك حالة أخرى قد لا تكون فيها هذه الآمنة. انعكاس. هذا يؤثر على بيئات مثل .NET و Java (وغيرها أيضًا ، بالطبع). سيتم تجميع الكود الخاص بك ، ولكن لا يزال هناك أخطاء في وقت التشغيل عندما يحاول الانعكاس الوصول إلى متغيرات غير موجودة. على سبيل المثال ، قد يكون هذا أمرًا شائعًا جدًا إذا كنت تستخدم ORM مثل Hibernate وتنسى تحديث ملفات XML الخاصة بك.

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

لا أعتقد أن هناك طريقة مضمونة بنسبة 100 ٪ ، بصرف النظر عن جميع الكود يدويًا.

أعتقد أنها طريقة شائعة جدًا ، حيث تجد جميع الإشارات إلى هذا الشيء المحدد. ومع ذلك ، فإن IDEs الحديثة مثل Visual Studio قد وجدت جميع ميزة المراجع التي تجعل هذا غير ضروري.

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

إنها طريقة ولا يمكن أن يكون هناك أي بيان محدد حول ما إذا كان آمنًا أو غير آمن دون معرفة الشكل الذي تبدو عليه الكود الذي تقوم به إعادة تهيئته والخيارات التي تقوم بها.

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

http://www.refactoring.com/

خيار آخر يمكن أن تنظر إذا كنت تستخدم واحدة من dotnet lanuages هو العلم "القديمة" الأسلوب مع عفا عليها الزمن السمة التي سوف أعرض كل مترجم التحذيرات ولكن لا تزال تترك رمز للاستدعاء يجب أن يكون هناك قانون بعدها يمكنك التحكم (إذا كنت تكتب API أو إذا كنت لا تستخدم الخيار صارمة في VB.Net على سبيل المثال).يمكنك من بمرح ريفاكتور ، وجود النسخة القديمة الدعوة الجديدة ؛ كمثال:

    public string Username
    {
        get
        {
            return this.userField;
        }
        set
        {
            this.userField = value;
        }
    }

    public int Login()
    {
        /* do stuff */
    }

يصبح:

    [ObsoleteAttribute()]
    public string Username
    {
        get
        {
            return this.userField;
        }
        set
        {
            this.userField = value;
        }
    }

    [ObsoleteAttribute("Replaced by Login(username, password)")]
    public int Login()
    {
        Login(Username, Pasword);
    }

    public int Login(string username, string password)
    {
        /* do stuff */
    }

هكذا كنت تميل إلى أن تفعل ذلك على أي حال...

هذا نهج شائع ، ولكن قد تختلف النتائج اعتمادًا على ما إذا كانت لغتك ثابتة أم ديناميكية.

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

لدي انطباع بأنك تعمل بلغة ثابتة مثل C# أو Java ، لذا استمر في هذا النهج حتى تواجه نوعًا من القضايا الرئيسية التي تقول إنه يجب عليك القيام بخلاف ذلك.

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

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

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

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

بالمناسبة ، يجعل Eclipse هذه الطريقة "فشل ، كعب ، كتابة" سهلة السهلة في Java: يتم وضع علامة على كل كائن غير موجود لك ، ويخبر Ctrl-1 بالإضافة إلى اختيار القائمة Eclipse لكتابة كعب (قابل للتجميع) لك! سأكون مهتمًا بمعرفة ما إذا كانت اللغات والمعاصف الأخرى تقدم دعمًا مماثلًا.

من "الآمن" بمعنى أنه في لغة تم تجميعها بشكل كافٍ ، فهي تجبرك على تحديث جميع الإشارات المباشرة إلى الشيء الذي قمت بتغييره.

لا يزال من الممكن أن يحدث خطأ إذا كان لديك رمز مبلل ، على سبيل المثال إذا كنت قد استخدمت المعالج المسبق C/C ++. لذا تأكد من إعادة البناء في جميع التكوينات الممكنة وعلى جميع المنصات ، إن أمكن.

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

void foo(int a, int b);

إلى

void foo(int a);

ثم قم بتغيير المكالمة من:

foo(1,2);

إلى:

foo(2);

هذا يجمع بشكل جيد ، لكنه خطأ.

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top