سبک کد جاوا AOSP برای مشارکت کنندگان

سبک های کد موجود در این صفحه قوانین سختگیرانه ای برای مشارکت کد جاوا در پروژه متن باز اندروید (AOSP) هستند. مشارکت در پلتفرم Android که از این قوانین پیروی نمی کند معمولاً پذیرفته نمی شود. می‌دانیم که همه کدهای موجود از این قوانین پیروی نمی‌کنند، اما انتظار داریم همه کدهای جدید مطابقت داشته باشند. برای مثال‌هایی از اصطلاحات برای استفاده و اجتناب از اکوسیستم فراگیرتر به کدنویسی با احترام مراجعه کنید.

مقاوم باش

یکی از ساده ترین قوانین، سازگاری است. اگر در حال ویرایش کد هستید، چند دقیقه به کد اطراف نگاه کنید و سبک آن را تعیین کنید. اگر آن کد از فضاهای دور بند if استفاده می کند، شما نیز باید این کار را انجام دهید. اگر کامنت‌های کد جعبه‌های کوچکی از ستاره‌ها در اطراف خود دارند، کاری کنید که نظرات شما نیز جعبه‌های کوچکی از ستاره‌ها در اطراف خود داشته باشند.

هدف از داشتن دستورالعمل‌های سبک، داشتن واژگان مشترک کدنویسی است، بنابراین خوانندگان می‌توانند بر آنچه می‌گویید تمرکز کنند، نه اینکه چگونه آن را بیان می‌کنید. ما قوانین سبک جهانی را در اینجا ارائه می دهیم تا واژگان را بدانید، اما سبک محلی نیز مهم است. اگر کدی که به یک فایل اضافه می کنید به شدت با کد موجود در اطراف آن متفاوت به نظر می رسد، خوانندگان را هنگام خواندن آن از ریتم خارج می کند. سعی کنید از این کار اجتناب کنید.

قوانین زبان جاوا

اندروید از قوانین کدنویسی استاندارد جاوا با قوانین اضافی که در زیر توضیح داده شده است پیروی می کند.

استثناها را نادیده نگیرید

نوشتن کدی که استثنایی را نادیده می گیرد، می تواند وسوسه انگیز باشد، مانند:

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

این کار را نکن در حالی که ممکن است فکر کنید کد شما هرگز با این شرایط خطا مواجه نمی‌شود یا رسیدگی به آن مهم نیست، نادیده گرفتن این نوع استثنا باعث ایجاد مین‌هایی در کد شما می‌شود تا شخص دیگری روزی فعال شود. شما باید هر استثنا در کد خود را به روشی اصولی مدیریت کنید. رسیدگی خاص بسته به مورد متفاوت است.

" هر وقت کسی یک بند خالی داشته باشد باید احساس ترسناکی داشته باشد. قطعاً مواقعی وجود دارد که واقعاً کار درستی است، اما حداقل باید به آن فکر کنید. در جاوا نمی توانید از احساس وحشتناک فرار کنید. " - جیمز گاسلینگ

گزینه های قابل قبول (به ترتیب اولویت) عبارتند از:

  • استثنا را به تماس گیرنده روش خود بیاندازید.
      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 را از تجزیه جدا کنید و خطاها را در هر مورد جداگانه مدیریت کنید.
  • استثنا را دوباره برگردانید. در بسیاری از مواقع نیازی به گرفتن استثنا در این سطح ندارید، فقط اجازه دهید روش آن را پرتاب کند.

به یاد داشته باشید که استثناها دوست شما هستند! هنگامی که کامپایلر شکایت می کند که شما استثنا نمی کنید، اخم نکنید. لبخند! کامپایلر به راحتی می‌تواند مشکلات زمان اجرا را در کدتان تشخیص دهد.

از نهایی کننده ها استفاده نکنید

Finalizers راهی برای اجرای یک تکه کد در هنگام جمع آوری یک شیء زباله است. در حالی که نهایی کننده ها می توانند برای پاکسازی مفید باشند (به ویژه منابع خارجی)، هیچ تضمینی در مورد زمان فراخوانی نهایی کننده (یا حتی فراخوانی آن) وجود ندارد.

اندروید از نهایی کننده ها استفاده نمی کند. در بیشتر موارد، می توانید به جای آن از مدیریت استثنایی خوب استفاده کنید. اگر کاملاً به یک نهایی کننده نیاز دارید، یک متد ( close() یا مشابه) تعریف کنید و دقیقاً زمانی که آن متد باید فراخوانی شود مستند کنید (به عنوان مثال به InputStream مراجعه کنید). در این مورد، چاپ یک پیام گزارش کوتاه از نهایی کننده مناسب است، اما لازم نیست، تا زمانی که انتظار نمی رود که سیاهه ها را پر کند.

واردات کاملا واجد شرایط

هنگامی که می خواهید از class Bar از بسته foo استفاده کنید، دو راه ممکن برای وارد کردن آن وجود دارد:

  • import foo.*;

    به طور بالقوه تعداد اظهارنامه های واردات را کاهش می دهد.

  • import foo.Bar;

    مشخص می کند که چه کلاس هایی استفاده می شوند و کد برای نگهدارنده ها خواناتر است.

از import foo.Bar; برای وارد کردن تمام کدهای اندروید یک استثنا صریح برای کتابخانه‌های استاندارد جاوا ( java.util.* ، java.io.* ، و غیره) و کد تست واحد ( junit.framework.* ) ایجاد شده است.

قوانین کتابخانه جاوا

کنوانسیون هایی برای استفاده از کتابخانه ها و ابزارهای جاوا اندروید وجود دارد. در برخی موارد، این قرارداد به روش‌های مهمی تغییر کرده است و ممکن است کدهای قدیمی‌تر از یک الگو یا کتابخانه منسوخ استفاده کنند. هنگام کار با چنین کدی، ادامه دادن سبک موجود اشکالی ندارد. با این حال، هنگام ایجاد اجزای جدید، هرگز از کتابخانه های منسوخ استفاده نکنید.

قوانین سبک جاوا

از نظرات استاندارد Javadoc استفاده کنید

هر فایل باید یک عبارت کپی رایت در بالا داشته باشد، به دنبال آن دستورات بسته و واردات (هر بلوک با یک خط خالی از هم جدا شده است)، و در نهایت اعلان کلاس یا رابط. در نظرات Javadoc توضیح دهید که کلاس یا رابط چه کاری انجام می دهد.

/*
 * Copyright 2022 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) {
    ...
}

اگر همه جاوادوک شما می گوید "sets Foo" است، نیازی به نوشتن Javadoc برای متدهای بی اهمیت دریافت و تنظیم مانند setFoo() ندارید. اگر روش کار پیچیده‌تری انجام می‌دهد (مانند اعمال یک محدودیت یا یک عارضه جانبی مهم)، پس باید آن را مستند کنید. اگر مشخص نیست که ویژگی "فو" به چه معناست، باید آن را مستند کنید.

هر روشی که بنویسید، چه عمومی و چه در غیر این صورت، از Javadoc سود می برد. متدهای عمومی بخشی از یک API هستند و بنابراین به Javadoc نیاز دارند. Android سبک خاصی را برای نوشتن نظرات Javadoc اعمال نمی کند، اما باید دستورالعمل های نحوه نوشتن نظرات سند برای ابزار Javadoc را دنبال کنید.

روش های کوتاه را بنویسید

در صورت امکان، روش ها را کوچک و متمرکز نگه دارید. ما تشخیص می‌دهیم که روش‌های طولانی گاهی مناسب هستند، بنابراین هیچ محدودیت سختی برای طول روش اعمال نمی‌شود. اگر روشی بیش از 40 خط یا بیشتر است، به این فکر کنید که آیا می توان آن را بدون آسیب رساندن به ساختار برنامه شکست.

فیلدها را در مکان های استاندارد تعریف کنید

فیلدهایی را در بالای فایل یا بلافاصله قبل از روش هایی که از آنها استفاده می کنند تعریف کنید.

محدوده متغیر را محدود کنید

دامنه متغیرهای محلی را به حداقل برسانید. این امر خوانایی و قابلیت نگهداری کد شما را افزایش می دهد و احتمال خطا را کاهش می دهد. هر متغیر را در درونی ترین بلوک که تمام کاربردهای متغیر را در بر می گیرد، اعلان کنید.

متغیرهای محلی را در نقطه ای که برای اولین بار استفاده می شود، اعلام کنید. تقریباً هر اعلان متغیر محلی باید حاوی مقداردهی اولیه باشد. اگر هنوز اطلاعات کافی برای مقداردهی اولیه متغیر را ندارید، اعلان را تا زمانی که انجام دهید به تعویق بیندازید.

استثنا عبارت‌های try-catch هستند. اگر متغیری با مقدار برگشتی روشی که یک استثنای علامت زده را ایجاد می کند مقداردهی اولیه شود، باید در داخل یک بلوک try مقداردهی اولیه شود. اگر مقدار باید خارج از بلوک try استفاده شود، باید قبل از بلوک try اعلام شود، جایی که هنوز نمی توان به طور معقولی مقداردهی اولیه کرد:

// 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));

با این حال، حتی می توانید با کپسوله کردن بلوک try-catch در یک روش از این مورد جلوگیری کنید:

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. واردات اندروید
  2. واردات از اشخاص ثالث ( com , junit , net , org )
  3. java و javax

برای مطابقت دقیق با تنظیمات IDE، واردات باید به صورت زیر باشد:

  • حروف الفبا در هر گروه، با حروف بزرگ قبل از حروف کوچک (به عنوان مثال، Z قبل از a)
  • با یک خط خالی بین هر گروه اصلی ( android ، com ، junit ، net ، org ، java ، javax ) جدا شده است.

در اصل، هیچ نیازی به سبک در سفارش وجود نداشت، به این معنی که IDE ها یا همیشه سفارش را تغییر می دادند یا توسعه دهندگان IDE باید ویژگی های مدیریت واردات خودکار را غیرفعال می کردند و به صورت دستی واردات را حفظ می کردند. این بد تلقی شد. هنگامی که از سبک جاوا پرسیده شد، سبک‌های ترجیحی بسیار متفاوت بودند و این به آن رسید که اندروید به سادگی «انتخاب یک سفارش و سازگاری» داشت. بنابراین ما یک سبک را انتخاب کردیم، راهنمای سبک را به روز کردیم، و 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 کاراکتر بیشتر باشد.
  • خطوط واردات ممکن است از حد مجاز فراتر رود زیرا انسان به ندرت آنها را می بیند (این کار نوشتن ابزار را نیز ساده می کند).

از حاشیه نویسی های استاندارد جاوا استفاده کنید

حاشیه نویسی باید قبل از سایر اصلاح کننده ها برای عنصر زبان مشابه باشد. حاشیه نویسی نشانگر ساده (به عنوان مثال، @Override ) را می توان در همان خط با عنصر زبان فهرست کرد. اگر چندین حاشیه نویسی یا حاشیه نویسی پارامتری وجود دارد، آنها را به ترتیب حروف الفبا در هر خط فهرست کنید.

روش های استاندارد اندروید برای سه حاشیه نویسی از پیش تعریف شده در جاوا عبارتند از:

  • هر زمان که استفاده از عنصر حاشیه نویسی ممنوع شد، از حاشیه نویسی @Deprecated استفاده کنید. اگر از حاشیه‌نویسی @Deprecated @ استفاده می‌کنید، باید یک برچسب @deprecated @deprecated نیز داشته باشید و باید یک پیاده‌سازی جایگزین نام‌گذاری کند. علاوه بر این، به یاد داشته باشید که یک روش @Deprecated همچنان باید کار کند . اگر کد قدیمی را مشاهده کردید که دارای برچسب @deprecated @deprecated است، حاشیه نویسی @Deprecated @ را اضافه کنید.
  • هر زمان که روشی اعلان یا پیاده سازی یک سوپرکلاس را لغو می کند، از حاشیه نویسی @Override استفاده کنید. برای مثال، اگر از تگ @inheritdocs Javadoc استفاده می‌کنید و از یک کلاس (نه یک رابط) مشتق می‌شوید، باید توضیح دهید که متد متد کلاس والد را لغو می‌کند.
  • از حاشیه نویسی @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 مورد نیاز است، کد را مجدداً تغییر دهید تا عناصر نرم افزاری که در آن حاشیه نویسی اعمال می شود جدا شوند.

کلمات اختصاری را به عنوان کلمات در نظر بگیرید

در نامگذاری متغیرها، متدها و کلاسها، کلمات اختصاری و اختصاری را به عنوان کلماتی در نظر بگیرید تا نامها خواناتر شوند:

خوب بد
XmlHttpRequest XMLHTTPrequest
getCustomerId getCustomerID
کلاس 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_LOG) یا if LOCAL_LOGD) شود، جایی که 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 شود (بسته به اینکه آیا پیامدها به اندازه کافی جدی و غیرمنتظره هستند که در نسخه منتشر شده ثبت شوند).
  • داشتن یک فایل سیستم کامل در یک سیستم فایل که برای برنامه های شخص ثالث قابل دسترسی است یا از طرف آنها قابل دسترسی است، نباید در سطحی بالاتر از INFORMATIVE ثبت شود.
  • داده‌های نامعتبر که از هر منبع غیرقابل اعتمادی (از جمله هر فایلی در فضای ذخیره‌سازی مشترک یا داده‌هایی که از طریق اتصال شبکه می‌آیند) به دست می‌آیند، مورد انتظار تلقی می‌شوند و در صورت تشخیص نامعتبر بودن (و حتی پس از آن) نباید هیچ گزارشی را در سطحی بالاتر از 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 هدایت می شوند، بنابراین عبارات چاپی شما هیچ اثر قابل مشاهده ای ندارند. با این حال، تمام ساختن رشته‌ای که برای این فراخوان‌ها اتفاق می‌افتد همچنان اجرا می‌شود.
  • قانون طلایی ورود به سیستم این است که لاگ های شما ممکن است بی جهت دیگر لاگ ها را از بافر خارج نکنند، همانطور که دیگران ممکن است لاگ های شما را بیرون نبرند.

قوانین سبک Javatests

قوانین نامگذاری روش آزمایش را دنبال کنید و از یک خط زیر برای جدا کردن موارد مورد آزمایش از مورد خاص استفاده کنید. این سبک دیدن مواردی که در حال آزمایش هستند را آسان تر می کند. مثلا:

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))
}