نمط رمز AOSP Java للمساهمين

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

الحفاظ على الاتّساق

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

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

قواعد لغة Java

يتبع Android اصطلاحات ترميز Java القياسية مع القواعد الإضافية الموضحة أدناه.

لا تتجاهل الاستثناءات

قد يكون من المغري كتابة تعليمات برمجية تتجاهل استثناءً، مثل:

  void setServerPort(String value) {
      try {
          serverPort = Integer.parseInt(value);
      } catch (NumberFormatException e) { }
  }

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

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

البدائل المقبولة (بترتيب التفضيل) هي:

  • وجّه الاستثناء إلى المتصل بطريقتك.
      void setServerPort(String value) throws NumberFormatException {
          serverPort = Integer.parseInt(value);
      }
    
  • ضع استثناءً جديدًا يتناسب مع مستوى التجريد لديك.
      void setServerPort(String value) throws ConfigurationException {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            throw new ConfigurationException("Port " + value + " is not valid.");
        }
      }
    
  • تعامل مع الخطأ بشكل رشيق واستبدل القيمة المناسبة في حظر "catch {}"
      /** Set port. If value is not a valid number, 80 is substituted. */
    
      void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            serverPort = 80;  // default port for server
        }
      }
    
  • اجمع الاستثناء واعرض مثيلاً جديدًا من RuntimeException. هذا أمر خطير، لذا لا تفعل ذلك إلا إذا كنت متأكدًا من أنه إذا حدوث خطأ معين، فإن الشيء المناسب الذي يجب القيام به هو التعطّل.
      /** Set port. If value is not a valid number, die. */
    
      void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            throw new RuntimeException("port " + value " is invalid, ", e);
        }
      }
    
  • كحل أخير، إذا كنت واثقًا من أن تجاهل الاستثناء مناسبًا فيمكنك تجاهله، ولكن يجب أيضًا التعليق على السبب سبب وجيه.
    /** If value is not a valid number, original port number is used. */
    
    void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            // Method is documented to just ignore invalid user input.
            // serverPort will just be unchanged.
        }
    }
    

عدم تصنيف الاستثناءات العامة

قد يكون من المغري أن تكون كسولًا عند اكتشاف الاستثناءات شيء مثل هذا:

  try {
      someComplicatedIOFunction();        // may throw IOException
      someComplicatedParsingFunction();   // may throw ParsingException
      someComplicatedSecurityFunction();  // may throw SecurityException
      // phew, made it all the way
  } catch (Exception e) {                 // I'll just catch all exceptions
      handleError();                      // with one generic handler!
  }

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

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

بدائل لرصد الاستثناءات العامة:

  • يمكنك رصد كل استثناء على حدة كجزء من مجموعة لقطات متعددة، على سبيل المثال:
    try {
        ...
    } catch (ClassNotFoundException | NoSuchMethodException e) {
        ...
    }
  • يمكنك إعادة ضبط الإعدادات المناسبة للرمز البرمجي لمعالجة الأخطاء بشكل أكثر دقة، من خلال عدة مرات للمحاولة. تقسيم طلب الإدراج (IO) من التحليل ومعالجة الأخطاء على حدة في كل حالة.
  • أعِد عرض الاستثناء. في كثير من الأحيان لا تكون بحاجة إلى فهم استثناء في هذا المستوى على أي حال، ما عليك سوى ترك الطريقة تطرحها.

الاستثناءات هي صديقك! عندما يشتكي المحول البرمجي من أنك لا ترصد أي استثناء، فلا تتجاهل. ابتسِم. قام المحول البرمجي للتو لاكتشاف مشكلات بيئة التشغيل في التعليمات البرمجية.

عدم استخدام الأدوات النهائية

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

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

عمليات استيراد مؤهَّلة بالكامل

عندما تريد استخدام الفئة Bar من الحزمة foo، هناك نوعان الطرق الممكنة لاستيراده:

  • import foo.*;

    من المحتمل أن تقلِّل بيانات الاستيراد من عدد عبارات الاستيراد.

  • import foo.Bar;

    يوضح الفئات المستخدمة والرمز البرمجي وسهل القراءة للمحافظين.

استخدِم import foo.Bar; لاستيراد جميع رموز Android. إنّ استثناء صريح لمكتبات Java القياسية (java.util.*، java.io.* وما إلى ذلك) ورمز اختبار الوحدة (junit.framework.*).

قواعد مكتبة Java

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

قواعد أنماط Java

استخدام تعليقات Javadoc العادية

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

/*
 * Copyright yyyy The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.foo;

import android.os.Blah;
import android.view.Yada;

import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * Does X and Y and provides an abstraction for Z.
 */

public class Foo {
    ...
}

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

أمثلة

/** Returns the correctly rounded positive square root of a double value. */

static double sqrt(double a) {
    ...
}

أو

/**
 * Constructs a new String by converting the specified array of
 * bytes using the platform's default character encoding.
 */
public String(byte[] bytes) {
    ...
}

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

كل طريقة تكتبها، سواء كانت عامة أو غيرها، ستستفيد من Javadoc. تعتبر الطرق العامة جزءًا من واجهة برمجة التطبيقات، وبالتالي تتطلب Javadoc. جهاز Android لا يفرض نمطًا معيّنًا لكتابة Javadoc التعليقات، ولكن عليك اتّباع التعليمات الواردة في كيفية كتابة تعليقات المستند لأداة Javadoc.

كتابة الطرق القصيرة

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

تحديد الحقول في الأماكن العادية

حدد الحقول إما في أعلى الملف أو قبل والطرق التي تستخدمها.

تحديد نطاق المتغيّر

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

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

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

// Instantiate class cl, which represents some sort of Set

Set s = null;
try {
    s = (Set) cl.newInstance();
} catch(IllegalAccessException e) {
    throw new IllegalArgumentException(cl + " not accessible");
} catch(InstantiationException e) {
    throw new IllegalArgumentException(cl + " not instantiable");
}

// Exercise the set
s.addAll(Arrays.asList(args));

ومع ذلك، يمكنك تجنب هذه الحالة عن طريق تغليف زر الجذب حظر في الطريقة:

Set createSet(Class cl) {
    // Instantiate class cl, which represents some sort of Set
    try {
        return (Set) cl.newInstance();
    } catch(IllegalAccessException e) {
        throw new IllegalArgumentException(cl + " not accessible");
    } catch(InstantiationException e) {
        throw new IllegalArgumentException(cl + " not instantiable");
    }
}

...

// Exercise the set
Set s = createSet(cl);
s.addAll(Arrays.asList(args));

تعريف متغيرات التكرار في عبارة for نفسها ما لم يكون هناك سبب مقنع للقيام بذلك بخلاف ذلك:

for (int i = 0; i < n; i++) {
    doSomething(i);
}

و

for (Iterator i = c.iterator(); i.hasNext(); ) {
    doSomethingElse(i.next());
}

بيانات استيراد الطلبات

يكون ترتيب عبارات الاستيراد هو:

  1. عمليات الاستيراد من Android
  2. الواردات من جهات خارجية (com وjunit و net، org)
  3. java وjavax

لمطابقة إعدادات IDE تمامًا، يجب أن تكون عمليات الاستيراد على النحو التالي:

  • الترتيب أبجديًا داخل كل مجموعة، مع كتابة أحرف كبيرة قبل الحرف اللاتيني أحرف الحالة (على سبيل المثال، Z قبل a)
  • مفصولة بسطر فارغ بين كل مجموعة رئيسية (android وcom وjunit net، org، java، javax)

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

اخترنا هذا النمط على النحو التالي:

  • إنّ الواردات التي يريد الناس الاطّلاع عليها أولاً تحظى بشعبية كبيرة (android).
  • إن الواردات التي يريد الناس البحث عنها تميل على الأقل إلى أن تكون في الأسفل (java).
  • يستطيع البشر متابعة الأسلوب بسهولة.
  • يمكن لبيئات IDE اتباع النمط.

ضع عمليات الاستيراد الثابتة فوق جميع عمليات الاستيراد الأخرى التي يتم طلبها بنفس طريقة واردات منتظمة.

استخدام المسافات كمسافة بادئة

نستخدم أربع (4) مسافات بادئة للكتل وعدم استخدام علامات التبويب مطلقًا. عندما تكون في شك، متسقة مع التعليمات البرمجية المحيطة.

نستخدم ثماني (8) مسافات بادئة لكل التفافات الأسطر، بما في ذلك استدعاءات الدوال والمهام.

إجراءات ننصح بها

Instrument i =
        someLongExpression(that, wouldNotFit, on, one, line);

صيغة غير محبَّذة

Instrument i =
    someLongExpression(that, wouldNotFit, on, one, line);

اتباع اصطلاحات تسمية الحقول

  • تبدأ أسماء الحقول غير العامة وغير الثابتة بـ m.
  • تبدأ أسماء الحقول الثابتة بـ s.
  • وتبدأ الحقول الأخرى بحرف صغير.
  • الحقول النهائية الثابتة (الثابت، غير قابلة للتغيير إلى حدٍ كبير) هي ALL_CAPS_WITH_UNDERSCORES.

مثلاً:

public class MyClass {
    public static final int SOME_CONSTANT = 42;
    public int publicField;
    private static MyClass sSingleton;
    int mPackagePrivate;
    private int mPrivate;
    protected int mProtected;
}

استخدام نمط الأقواس العادي

ضع الأقواس على نفس سطر التعليمة البرمجية قبلها، وليس على السطر الخاص بها:

class MyClass {
    int func() {
        if (something) {
            // ...
        } else if (somethingElse) {
            // ...
        } else {
            // ...
        }
    }
}

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

if (condition) {
    body();
}

ويكون هذا المحتوى مقبولاً:

if (condition) body();

ولكن هذا الإجراء غير مقبول:

if (condition)
    body();  // bad!

تحديد طول السطر

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

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

استخدام تعليقات Java التوضيحية القياسية

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

الممارسات القياسية في نظام Android للتعليقات التوضيحية الثلاثة المحددة مسبقًا في Java هي:

  • استخدام تعليق @Deprecated التوضيحي عند عدم تشجيع استخدام العنصر الذي به تعليقات توضيحية. في حال استخدام التعليق التوضيحي @Deprecated، يجب أن يكون لديك أيضًا @deprecated علامة Javadoc ويجب أن تسمي تنفيذًا بديلاً. بالإضافة إلى ذلك، تذكُّر أنّ طريقة @Deprecated لا تزال من المفترض أن تعمل. إذا ظهر لك رمز قديم يحتوي على علامة Javadoc @deprecated، أضِف تعليق توضيحي واحد (@Deprecated)
  • يمكنك استخدام التعليق التوضيحي @Override عندما تتجاوز الطريقة البيان أو التنفيذ من للغاية. على سبيل المثال، إذا كنت تستخدم علامة Javadoc @inheritdocs، المستمدة من فئة (وليس واجهة)، فيجب عليك أيضًا إضافة تعليق توضيحي فإن الطريقة تلغي طريقة الفئة الأصل.
  • استخدام تعليق @SuppressWarnings التوضيحي في ظروف يكون من المستحيل والتخلص من التحذير. إذا مرر التحذير هذا "المستحيل إزالة" يجب أن يكون تعليق @SuppressWarnings التوضيحي للتأكد من أن جميع التحذيرات تعكس مشكلات فعلية في الرمز.

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

    // TODO: The third-party class com.third.useful.Utility.rotate() needs generics
    @SuppressWarnings("generic-cast")
    List<String> blix = Utility.rotate(blax);
    

    عندما يكون التعليق التوضيحي @SuppressWarnings مطلوبًا، أعِد ضبط الرمز. لعزل عناصر البرنامج حيث يكون التعليق التوضيحي تنطبق.

التعامل مع الاختصارات ككلمات

تعامل مع الاختصارات والاختصارات ككلمات في تسمية المتغيرات والطرق وفئات لجعل الأسماء أكثر قابلية للقراءة:

جيدة سيئة
طلب XmlHttp طلب XMLHTTP
الحصول على رقم تعريف العميل الحصول على رقم تعريف العميل
HTML للفئة رمز HTML للصف
عنوان URL للسلسلة عنوان URL للسلسلة
المعرّف الطويل المعرّف الطويل

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

استخدام تعليقات TODO

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

// TODO: Remove this code after the UrlTable2 has been checked in.

و

// TODO: Change this to use a flag instead of a constant.

إذا كان TODO بالتنسيق "في تاريخ مستقبلي، تنفيذ إجراء" الحرص على حيث تُدرج تاريخًا محددًا ("حل المشكلة بحلول تشرين الثاني (نوفمبر) 2005") أو حدث محدّد ("يُرجى إزالة هذا الرمز بعد اختيار جميع أدوات مزج الإنتاج فهم البروتوكول V7).

التسجيل باعتدال

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

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

    يتم تسجيل هذا المستوى حتى في إصدارات الإصدار، وهو مطلوب تحيط بها مجموعة من if LOCAL_LOGD) أو if (LOCAL_LOG)، حيث يتم تحديد LOCAL_LOG[D] في الفئة أو المكون الفرعي، بحيث يكون هناك احتمال لإيقاف كل عمليات التسجيل هذه وبالتالي، يجب ألا يكون هناك منطق نشط في مربّع if (LOCAL_LOG) كل مبنى السلسلة يجب أيضًا وضع السجل داخل حظر "if (LOCAL_LOG)" عدم إعادة ضبط ترتيب طلب التسجيل استدعاء طريقة إذا كان ذلك سيؤدي إلى لإنشاء السلسلة يتم تنفيذها خارج حظر "if (LOCAL_LOG)"

    ما زال هناك رمز معيّن مفاده if (localLOGV). هذا النمط ويعتبر مقبولة أيضًا، على الرغم من أن الاسم غير قياسي.

  • VERBOSE: يُستخدم في أي مهام أخرى. هذا المستوى مخصص فقط التي تم تسجيلها على إصدارات تصحيح الأخطاء ويجب أن تحيط بها حظر if (LOCAL_LOGV) (أو ما يعادله) بحيث يمكن يتم تجميعها بشكل افتراضي. تتم إزالة أي مبنى سلسلة من بنيات الإصدار ويحتاج إلى الظهور داخل حظر "if (LOCAL_LOGV)"

ملاحظات

  • حدث خطأ ضمن وحدة معيّنة، غير مستوى VERBOSE يجب الإبلاغ عنه مرة واحدة فقط إن أمكن. في سلسلة واحدة من داخل وحدة ما، فيجب على الدالة الأعمق فقط عرض الخطأ، ويجب على المتصلين في نفس الوحدة فقط إضافة بعض التسجيل إذا كان ذلك يساعد بشكل كبير في عزل المشكلة.
  • في سلسلة من الوحدات، بخلاف مستوى VERBOSE، عندما الوحدة ذات المستوى الأدنى ترصد البيانات غير الصالحة الواردة من مستوى أعلى ، فإن الوحدة ذات المستوى الأدنى يجب أن تسجل هذا الموقف فقط لسجل DEBUG، وفقط إذا كان التسجيل يقدم معلومات غير متاحة للمتصل بطريقة أخرى. على وجه التحديد، ليست هناك حاجة إلى تسجيل حالات يتم فيها طرح استثناء (ينبغي أن يكون الاستثناء تحتوي على جميع المعلومات ذات الصلة) أو عند استخدام تسجيله مضمنة في رمز خطأ. يعد ذلك خاصةً أهمية في التفاعل بين إطار العمل والتطبيقات، والظروف التي تنشأ عن استخدام التطبيقات التابعة لجهات خارجية والتي التي تتم معالجتها بواسطة إطار العمل إلى تسجيل بيانات أعلى من مستوى DEBUG. الحالات الوحيدة التي يجب أن تبدأ تسجيل الدخول يتوفّر مستوى واحد (INFORMATIVE) أو مستوى أعلى عندما ترصد وحدة أو تطبيق. أي خطأ على مستواه أو من مستوى أدنى.
  • عندما يكون من المحتمل أن يكون هناك شرط يبرر عادةً بعض عمليات التسجيل عدة مرات، قد يكون من الجيد تنفيذ بعض آلية تقييد المعدل لمنع امتلاء السجلات بالعديد من نُسخ مكررة من المعلومات نفسها (أو معلومات مشابهة جدًا).
  • يُعد انقطاع الاتصال بالشبكة أمرًا شائعًا وعاديًا متوقعًا ولا ينبغي تسجيله دون مبرر. فقدان الشبكة الاتصال الذي له عواقب داخل التطبيق يجب تسجيله في المستوى DEBUG أو VERBOSE (بناءً على ما إذا كان العواقب خطيرة بدرجة كافية وغير متوقعة بما يكفي لتسجيل الدخول إلى إصدار ).
  • وجود نظام ملفات كامل على نظام ملفات يمكن الوصول إليه أو تشغيله بالنيابة عن التطبيقات التابعة لجهات خارجية على مستوى أعلى من المحتوى غير الملائم.
  • البيانات غير الصالحة الواردة من أي مصدر غير موثوق به (بما في ذلك أي ملف على أو مساحة التخزين المشتركة أو البيانات الواردة عبر الشبكة اتصال) تُعد متوقعة ويجب ألا تؤدي إلى تشغيل أي يتم تسجيل مستوى أعلى من DEBUG عند رصد ذلك غير صالح (وحتى في هذه الحالة يجب أن يكون التسجيل محدودًا قدر الإمكان).
  • عند استخدام عامل التشغيل + مع عناصر String، يشير ذلك ضمنًا إلى يتم إنشاء مثيل StringBuilder باستخدام الإعداد التلقائي حجم المخزن المؤقت (16 حرفًا) وString المؤقت الآخر المحتمل الأخرى. بالتالي، لن يكون إنشاء عناصر StringBuilder بشكل صريح أكثر أكثر تكلفة من الاعتماد على عامل التشغيل + التلقائي (وقد يكون مكلفًا أكثر كفاءة). ضع في اعتبارك أن التعليمة البرمجية التي تستدعي يتم تجميع Log.v() وتنفيذها على بُنى الإصدار، بما في ذلك إنشاء السلاسل، حتى إذا لم تتم قراءة السجلات.
  • أي تسجيل يهدف إلى قراءته من قبل الآخرين المتوفرة في إصدارات الإصدارات يجب أن تكون بسيطة دون الالتباس، ويجب أن يكون مفهومًا. يتضمن هذا جميع سجلات وصولاً إلى مستوى DEBUG.
  • عند الإمكان، يُرجى مواصلة التسجيل في سطر واحد. يصل طول الأسطر إلى 80 أو 100 حرف مقبول. تجنَّب استخدام أحرف تزيد عن 130 أو 160 حرفًا تقريبًا. (بما في ذلك طول العلامة) إن أمكن.
  • في حال نجاح تسجيل التقارير، لا تستخدمه أبدًا على مستويات أعلى من VERBOSE
  • إذا كنت تستخدم تسجيل الدخول المؤقت لتشخيص مشكلة يصعب إعادة إنتاجه، أو الإبقاء عليه على المستوى DEBUG أو VERBOSE قم بتضمينه إذا كانت القوالب التي تسمح بتعطيله في وقت التجميع.
  • يُرجى توخّي الحذر بشأن التسريبات الأمنية التي تتم من خلال السجلّ. تجنب التسجيل بخصوصية المعلومات. وعلى وجه الخصوص، تجنَّب تسجيل معلومات حول المحتوى المحمي. يعد ذلك مهمًا بشكل خاص عندما وكتابة رمز إطار العمل، لأنه ليس من السهل معرفة ما الذي ولن تكون ضمن المعلومات الخاصة أو المحتوى المحمي
  • عدم استخدام System.out.println() مطلقًا (أو printf() لمدة الرمز الأصلي). يحصل System.out وSystem.err على فتتم إعادة توجيههم إلى /dev/null، لذا لا تحتوي عبارتك المطبوعة التأثيرات المرئية. ومع ذلك، فإن كل إنشاء السلسلة الذي يحدث حتى يتم تنفيذ هذه المكالمات.
  • القاعدة الذهبية في التسجيل هي أن سجلاتك دفع السجلات الأخرى بدون داعٍ من المورد الاحتياطي، تمامًا كما يفعل الآخرون بدلاً من إثارة الرغبة في ذلك

قواعد الأنماط في Javatest

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

testMethod_specificCase1 testMethod_specificCase2

void testIsDistinguishable_protanopia() {
    ColorMatcher colorMatcher = new ColorMatcher(PROTANOPIA)
    assertFalse(colorMatcher.isDistinguishable(Color.RED, Color.BLACK))
    assertTrue(colorMatcher.isDistinguishable(Color.X, Color.Y))
}