diff options
Diffstat (limited to 'en/setup/code-style.html')
-rw-r--r-- | en/setup/code-style.html | 718 |
1 files changed, 718 insertions, 0 deletions
diff --git a/en/setup/code-style.html b/en/setup/code-style.html new file mode 100644 index 00000000..5367bd68 --- /dev/null +++ b/en/setup/code-style.html @@ -0,0 +1,718 @@ +<html devsite> + <head> + <title>AOSP Java Code Style for Contributors</title> + <meta name="project_path" value="/_project.yaml" /> + <meta name="book_path" value="/_book.yaml" /> + </head> + <body> + <!-- + Copyright 2017 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. + --> + + + +<p>The code styles below are strict rules for contributing Java code to the +Android Open Source Project (AOSP). Contributions to the Android platform that +do not adhere to these rules are generally <em>not accepted</em>. We recognize +that not all existing code follows these rules, but we expect all new code to +be compliant.</p> + +<p class="note"><strong>Note:</strong> These rules are intended for the Android +platform and are not required of Android app developers. App developers may +follow the standard of their choosing, such as the <a +href="https://google.github.io/styleguide/javaguide.html">Google Java Style +Guide</a>.</p> + +<h2 id="java-language-rules">Java Language Rules</h2> +<p>Android follows standard Java coding conventions with the additional rules +described below.</p> + +<h3 id="dont-ignore-exceptions">Don't Ignore Exceptions</h3> +<p>It can be tempting to write code that completely ignores an exception, such +as:</p> +<pre><code>void setServerPort(String value) { + try { + serverPort = Integer.parseInt(value); + } catch (NumberFormatException e) { } +} +</code></pre> +<p>Do not do this. While you may think your code will never encounter this error +condition or that it is not important to handle it, ignoring exceptions as above +creates mines in your code for someone else to trigger some day. You must handle +every Exception in your code in a principled way; the specific handling varies +depending on the case.</p> +<p><em>Anytime somebody has an empty catch clause they should have a +creepy feeling. There are definitely times when it is actually the correct +thing to do, but at least you have to think about it. In Java you can't escape +the creepy feeling.</em> -<a href="http://www.artima.com/intv/solid4.html">James Gosling</a></p> +<p>Acceptable alternatives (in order of preference) are:</p> +<ul> +<li>Throw the exception up to the caller of your method. +<pre><code>void setServerPort(String value) throws NumberFormatException { + serverPort = Integer.parseInt(value); +} +</code></pre> +</li> +<li>Throw a new exception that's appropriate to your level of abstraction. +<pre><code>void setServerPort(String value) throws ConfigurationException { + try { + serverPort = Integer.parseInt(value); + } catch (NumberFormatException e) { + throw new ConfigurationException("Port " + value + " is not valid."); + } +} +</code></pre> +</li> +<li>Handle the error gracefully and substitute an appropriate value in the +catch {} block. +<pre><code>/** 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 + } +} +</code></pre> +</li> +<li>Catch the Exception and throw a new <code>RuntimeException</code>. This is +dangerous, so do it only if you are positive that if this error occurs the +appropriate thing to do is crash. +<pre><code>/** 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); + } +} +</code></pre> +<p class="note"><strong>Note</strong> The original exception is passed to the +constructor for RuntimeException. If your code must compile under Java 1.3, you +must omit the exception that is the cause.</p> +</li> +<li>As a last resort, if you are confident that ignoring the exception is +appropriate then you may ignore it, but you must also comment why with a good +reason: +<pre><code>/** 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. + } +} +</code></pre> +</li> +</ul> + +<h3 id="dont-catch-generic-exception">Don't Catch Generic Exception</h3> +<p>It can also be tempting to be lazy when catching exceptions and do +something like this:</p> +<pre><code>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! +} +</code></pre> +<p>Do not do this. In almost all cases it is inappropriate to catch generic +Exception or Throwable (preferably not Throwable because it includes Error +exceptions). It is very dangerous because it means that Exceptions +you never expected (including RuntimeExceptions like ClassCastException) get +caught in application-level error handling. It obscures the failure handling +properties of your code, meaning if someone adds a new type of Exception in the +code you're calling, the compiler won't help you realize you need to handle the +error differently. In most cases you shouldn't be handling different types of +exception the same way.</p> +<p>The rare exception to this rule is test code and top-level code where you +want to catch all kinds of errors (to prevent them from showing up in a UI, or +to keep a batch job running). In these cases you may catch generic Exception +(or Throwable) and handle the error appropriately. Think very carefully before +doing this, though, and put in comments explaining why it is safe in this place.</p> +<p>Alternatives to catching generic Exception:</p> +<ul> +<li> +<p>Catch each exception separately as separate catch blocks after a single +try. This can be awkward but is still preferable to catching all Exceptions. +Beware repeating too much code in the catch blocks.</li></p> +</li> +<li> +<p>Refactor your code to have more fine-grained error handling, with multiple +try blocks. Split up the IO from the parsing, handle errors separately in each +case.</p> +</li> +<li> +<p>Rethrow the exception. Many times you don't need to catch the exception at +this level anyway, just let the method throw it.</p> +</li> +</ul> +<p>Remember: exceptions are your friend! When the compiler complains you're +not catching an exception, don't scowl. Smile: the compiler just made it +easier for you to catch runtime problems in your code.</p> +<h3 id="dont-use-finalizers">Don't Use Finalizers</h3> +<p>Finalizers are a way to have a chunk of code executed when an object is +garbage collected. While they can be handy for doing cleanup (particularly of +external resources), there are no guarantees as to when a finalizer will be +called (or even that it will be called at all).</p> +<p>Android doesn't use finalizers. In most cases, you can do what +you need from a finalizer with good exception handling. If you absolutely need +it, define a close() method (or the like) and document exactly when that +method needs to be called (see InputStream for an example). In this case it is +appropriate but not required to print a short log message from the finalizer, +as long as it is not expected to flood the logs.</p> + +<h3 id="fully-qualify-imports">Fully Qualify Imports</h3> +<p>When you want to use class Bar from package foo,there +are two possible ways to import it:</p> +<ul> +<li><code>import foo.*;</code> +<p>Potentially reduces the number of import statements.</p></li> +<li><code>import foo.Bar;</code> +<p>Makes it obvious what classes are actually used and the code is more readable +for maintainers.</p></li></ul> +<p>Use <code>import foo.Bar;</code> for importing all Android code. An explicit +exception is made for java standard libraries (<code>java.util.*</code>, +<code>java.io.*</code>, etc.) and unit test code +(<code>junit.framework.*</code>).</p> + +<h2 id="java-library-rules">Java Library Rules</h2> +<p>There are conventions for using Android's Java libraries and tools. In some +cases, the convention has changed in important ways and older code might use a +deprecated pattern or library. When working with such code, it's okay to +continue the existing style. When creating new components however, never use +deprecated libraries.</p> + +<h2 id="java-style-rules">Java Style Rules</h2> + +<h3 id="use-javadoc-standard-comments">Use Javadoc Standard Comments</h3> +<p>Every file should have a copyright statement at the top, followed by package +and import statements (each block separated by a blank line) and finally the +class or interface declaration. In the Javadoc comments, describe what the class +or interface does.</p> +<pre><code>/* + * Copyright (C) 2015 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 { + ... +} +</code></pre> +<p>Every class and nontrivial public method you write <em>must</em> contain a +Javadoc comment with at least one sentence describing what the class or method +does. This sentence should start with a third person descriptive verb.</p> +<p>Examples:</p> +<pre><code>/** Returns the correctly rounded positive square root of a double value. */ +static double sqrt(double a) { + ... +} +</code></pre> +<p>or</p> +<pre><code>/** + * Constructs a new String by converting the specified array of + * bytes using the platform's default character encoding. + */ +public String(byte[] bytes) { + ... +} +</code></pre> +<p>You do not need to write Javadoc for trivial get and set methods such as +<code>setFoo()</code> if all your Javadoc would say is "sets Foo". If the method +does something more complex (such as enforcing a constraint or has an important +side effect), then you must document it. If it's not obvious what the property +"Foo" means, you should document it. +<p>Every method you write, public or otherwise, would benefit from Javadoc. +Public methods are part of an API and therefore require Javadoc. Android does +not currently enforce a specific style for writing Javadoc comments, but you +should follow the instructions <a +href="http://www.oracle.com/technetwork/java/javase/documentation/index-137868.html">How +to Write Doc Comments for the Javadoc Tool</a>.</p> + +<h3 id="write-short-methods">Write Short Methods</h3> +<p>When feasible, keep methods small and focused. We recognize that long methods +are sometimes appropriate, so no hard limit is placed on method length. If a +method exceeds 40 lines or so, think about whether it can be broken up without +harming the structure of the program.</p> + +<h3 id="define-fields-in-standard-places">Define Fields in Standard Places</h3> +<p>Define fields either at the top of the file or immediately before the +methods that use them.</p> + +<h3 id="limit-variable-scope">Limit Variable Scope</h3> +<p>Keep the scope of local variables to a minimum. By doing so, you +increase the readability and maintainability of your code and reduce the +likelihood of error. Each variable should be declared in the innermost block +that encloses all uses of the variable.</p> +<p>Local variables should be declared at the point they are first used. Nearly +every local variable declaration should contain an initializer. If you don't +yet have enough information to initialize a variable sensibly, postpone the +declaration until you do.</p> +<p>The exception is try-catch statements. If a variable is initialized with the +return value of a method that throws a checked exception, it must be initialized +inside a try block. If the value must be used outside of the try block, then it +must be declared before the try block, where it cannot yet be sensibly +initialized:</p> +<pre><code>// 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)); +</code></pre> +<p>However, even this case can be avoided by encapsulating the try-catch block +in a method:</p> +<pre><code>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)); +</code></pre> +<p>Loop variables should be declared in the for statement itself unless there +is a compelling reason to do otherwise:</p> +<pre><code>for (int i = 0; i < n; i++) { + doSomething(i); +} +</code></pre> +<p>and</p> +<pre><code>for (Iterator i = c.iterator(); i.hasNext(); ) { + doSomethingElse(i.next()); +} +</code></pre> + +<h3 id="order-import-statements">Order Import Statements</h3> +<p>The ordering of import statements is:</p> +<ol> +<li> +<p>Android imports</p> +</li> +<li> +<p>Imports from third parties (<code>com</code>, <code>junit</code>, +<code>net</code>, <code>org</code>)</p> +</li> +<li> +<p><code>java</code> and <code>javax</code></p> +</li> +</ol> +<p>To exactly match the IDE settings, the imports should be:</p> +<ul> +<li> +<p>Alphabetical within each grouping, with capital letters before lower case +letters (e.g. Z before a).</p> +</li> +<li> +<p>Separated by a blank line between each major grouping (<code>android</code>, +<code>com</code>, <code>junit</code>, <code>net</code>, <code>org</code>, +<code>java</code>, <code>javax</code>).</p> +</li> +</ul> +<p>Originally, there was no style requirement on the ordering, meaning IDEs were +either always changing the ordering or IDE developers had to disable the +automatic import management features and manually maintain the imports. This was +deemed bad. When java-style was asked, the preferred styles varied wildly and it +came down to Android needing to simply "pick an ordering and be consistent." So +we chose a style, updated the style guide, and made the IDEs obey it. We expect +that as IDE users work on the code, imports in all packages will match this +pattern without extra engineering effort.</p> +<p>This style was chosen such that:</p> +<ul> +<li> +<p>The imports people want to look at first tend to be at the top +(<code>android</code>).</p> +</li> +<li> +<p>The imports people want to look at least tend to be at the bottom +(<code>java</code>).</p> +</li> +<li> +<p>Humans can easily follow the style.</p> +</li> +<li> +<p>IDEs can follow the style.</p> +</li> +</ul> +<p>The use and location of static imports have been mildly controversial +issues. Some people prefer static imports to be interspersed with the +remaining imports, while some prefer them to reside above or below all +other imports. Additionally, we have not yet determined how to make all IDEs use +the same ordering. Since many consider this a low priority issue, just use your +judgement and be consistent.</p> + +<h3 id="use-spaces-for-indentation">Use Spaces for Indentation</h3> +<p>We use four (4) space indents for blocks and never tabs. When in doubt, be +consistent with the surrounding code.</p> +<p>We use eight (8) space indents for line wraps, including function calls and +assignments. For example, this is correct:</p> +<pre><code>Instrument i = + someLongExpression(that, wouldNotFit, on, one, line); +</code></pre> +<p>and this is not correct:</p> +<pre><code>Instrument i = + someLongExpression(that, wouldNotFit, on, one, line); +</code></pre> + +<h3 id="follow-field-naming-conventions">Follow Field Naming Conventions</h3> +<ul> +<li> +<p>Non-public, non-static field names start with m.</p> +</li> +<li> +<p>Static field names start with s.</p> +</li> +<li> +<p>Other fields start with a lower case letter.</p> +</li> +<li> +<p>Public static final fields (constants) are ALL_CAPS_WITH_UNDERSCORES.</p> +</li> +</ul> +<p>For example:</p> +<pre><code>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; +} +</code></pre> +<h3 id="use-standard-brace-style">Use Standard Brace Style</h3> +<p>Braces do not go on their own line; they go on the same line as the code +before them:</p> +<pre><code>class MyClass { + int func() { + if (something) { + // ... + } else if (somethingElse) { + // ... + } else { + // ... + } + } +} +</code></pre> +<p>We require braces around the statements for a conditional. Exception: If the +entire conditional (the condition and the body) fit on one line, you may (but +are not obligated to) put it all on one line. For example, this is acceptable:</p> +<pre><code>if (condition) { + body(); +} +</code></pre> +<p>and this is acceptable:</p> +<pre><code>if (condition) body(); +</code></pre> +<p>but this is not acceptable:</p> +<pre><code>if (condition) + body(); // bad! +</code></pre> + +<h3 id="limit-line-length">Limit Line Length</h3> +<p>Each line of text in your code should be at most 100 characters long. While +much discussion has surrounded this rule, the decision remains that 100 +characters is the maximum <em>with the following exceptions</em>:</p> +<ul> +<li>If a comment line contains an example command or a literal URL +longer than 100 characters, that line may be longer than 100 characters for +ease of cut and paste.</li> +<li>Import lines can go over the limit because humans rarely see them (this also +simplifies tool writing).</li> +</ul> + +<h3 id="use-standard-java-annotations">Use Standard Java Annotations</h3> +<p>Annotations should precede other modifiers for the same language element. +Simple marker annotations (e.g. @Override) can be listed on the same line with +the language element. If there are multiple annotations, or parameterized +annotations, they should each be listed one-per-line in alphabetical +order.</p> +<p>Android standard practices for the three predefined annotations in Java are:</p> +<ul> +<li><code>@Deprecated</code>: The @Deprecated annotation must be used whenever +the use of the annotated element is discouraged. If you use the @Deprecated +annotation, you must also have a @deprecated Javadoc tag and it should name an +alternate implementation. In addition, remember that a @Deprecated method is +<em>still supposed to work</em>. If you see old code that has a @deprecated +Javadoc tag, please add the @Deprecated annotation. +</li> +<li><code>@Override</code>: The @Override annotation must be used whenever a +method overrides the declaration or implementation from a super-class. For +example, if you use the @inheritdocs Javadoc tag, and derive from a class (not +an interface), you must also annotate that the method @Overrides the parent +class's method.</li> +<li><code>@SuppressWarnings</code>: The @SuppressWarnings annotation should be +used only under circumstances where it is impossible to eliminate a warning. If +a warning passes this "impossible to eliminate" test, the @SuppressWarnings +annotation <em>must</em> be used, so as to ensure that all warnings reflect +actual problems in the code. +<p>When a @SuppressWarnings annotation is necessary, it must be prefixed with +a TODO comment that explains the "impossible to eliminate" condition. This +will normally identify an offending class that has an awkward interface. For +example:</p> +<pre><code>// TODO: The third-party class com.third.useful.Utility.rotate() needs generics +@SuppressWarnings("generic-cast") +List<String> blix = Utility.rotate(blax); +</code></pre> +<p>When a @SuppressWarnings annotation is required, the code should be +refactored to isolate the software elements where the annotation applies.</p> +</li> +</ul> + +<h3 id="treat-acronyms-as-words">Treat Acronyms as Words</h3> +<p>Treat acronyms and abbreviations as words in naming variables, methods, and +classes to make names more readable:</p> +<table> +<thead> +<tr> +<th>Good</th> +<th>Bad</th> +</tr> +</thead> +<tbody> +<tr> +<td>XmlHttpRequest</td> +<td>XMLHTTPRequest</td> +</tr> +<tr> +<td>getCustomerId</td> +<td>getCustomerID</td> +</tr> +<tr> +<td>class Html</td> +<td>class HTML</td> +</tr> +<tr> +<td>String url</td> +<td>String URL</td> +</tr> +<tr> +<td>long id</td> +<td>long ID</td> +</tr> +</tbody> +</table> +<p>As both the JDK and the Android code bases are very inconsistent around +acronyms, it is virtually impossible to be consistent with the surrounding +code. Therefore, always treat acronyms as words.</p> + +<h3 id="use-todo-comments">Use TODO Comments</h3> +<p>Use TODO comments for code that is temporary, a short-term solution, or +good-enough but not perfect. TODOs should include the string TODO in all caps, +followed by a colon:</p> +<pre><code>// TODO: Remove this code after the UrlTable2 has been checked in. +</code></pre> +<p>and</p> +<pre><code>// TODO: Change this to use a flag instead of a constant. +</code></pre> +<p>If your TODO is of the form "At a future date do something" make sure that +you either include a very specific date ("Fix by November 2005") or a very +specific event ("Remove this code after all production mixers understand +protocol V7.").</p> + +<h3 id="log-sparingly">Log Sparingly</h3> +<p>While logging is necessary, it has a significantly negative impact on +performance and quickly loses its usefulness if not kept reasonably +terse. The logging facilities provides five different levels of logging:</p> +<ul> +<li><code>ERROR</code>: +Use when something fatal has happened, i.e. something will have user-visible +consequences and won't be recoverable without explicitly deleting some data, +uninstalling applications, wiping the data partitions or reflashing the entire +device (or worse). This level is always logged. Issues that justify some logging +at the ERROR level are typically good candidates to be reported to a +statistics-gathering server.</li> +<li><code>WARNING</code>: +Use when something serious and unexpected happened, i.e. something that will +have user-visible consequences but is likely to be recoverable without data loss +by performing some explicit action, ranging from waiting or restarting an app +all the way to re-downloading a new version of an application or rebooting the +device. This level is always logged. Issues that justify some logging at the +WARNING level might also be considered for reporting to a statistics-gathering +server.</li> +<li><code>INFORMATIVE:</code> +Use to note that something interesting to most people happened, i.e. when a +situation is detected that is likely to have widespread impact, though isn't +necessarily an error. Such a condition should only be logged by a module that +reasonably believes that it is the most authoritative in that domain (to avoid +duplicate logging by non-authoritative components). This level is always logged. +</li> +<li><code>DEBUG</code>: +Use to further note what is happening on the device that could be relevant to +investigate and debug unexpected behaviors. You should log only what is needed +to gather enough information about what is going on about your component. If +your debug logs are dominating the log then you probably should be using verbose +logging. +<p>This level will be logged, even on release builds, and is required to be +surrounded by an <code>if (LOCAL_LOG)</code> or <code>if (LOCAL_LOGD)</code> +block, where <code>LOCAL_LOG[D]</code> is defined in your class or subcomponent, +so that there can exist a possibility to disable all such logging. There must +therefore be no active logic in an <code>if (LOCAL_LOG)</code> block. All the +string building for the log also needs to be placed inside the <code>if +(LOCAL_LOG)</code> block. The logging call should not be re-factored out into a +method call if it is going to cause the string building to take place outside +of the <code>if (LOCAL_LOG)</code> block.</p> +<p>There is some code that still says <code>if (localLOGV)</code>. This is +considered acceptable as well, although the name is nonstandard.</p> +</li> +<li><code>VERBOSE</code>: +Use for everything else. This level will only be logged on debug builds and +should be surrounded by an <code>if (LOCAL_LOGV)</code> block (or equivalent) so +it can be compiled out by default. Any string building will be stripped out of +release builds and needs to appear inside the <code>if (LOCAL_LOGV)</code> block. +</li> +</ul> +<p><em>Notes:</em> </p> +<ul> +<li>Within a given module, other than at the VERBOSE level, an +error should only be reported once if possible. Within a single chain of +function calls within a module, only the innermost function should return the +error, and callers in the same module should only add some logging if that +significantly helps to isolate the issue.</li> +<li>In a chain of modules, other than at the VERBOSE level, when a +lower-level module detects invalid data coming from a higher-level module, the +lower-level module should only log this situation to the DEBUG log, and only +if logging provides information that is not otherwise available to the caller. +Specifically, there is no need to log situations where an exception is thrown +(the exception should contain all the relevant information), or where the only +information being logged is contained in an error code. This is especially +important in the interaction between the framework and applications, and +conditions caused by third-party applications that are properly handled by the +framework should not trigger logging higher than the DEBUG level. The only +situations that should trigger logging at the INFORMATIVE level or higher is +when a module or application detects an error at its own level or coming from +a lower level.</li> +<li>When a condition that would normally justify some logging is +likely to occur many times, it can be a good idea to implement some +rate-limiting mechanism to prevent overflowing the logs with many duplicate +copies of the same (or very similar) information.</li> +<li>Losses of network connectivity are considered common, fully expected, and +should not be logged gratuitously. A loss of network connectivity +that has consequences within an app should be logged at the DEBUG or VERBOSE +level (depending on whether the consequences are serious enough and unexpected +enough to be logged in a release build).</li> +<li>Having a full filesystem on a filesystem that is accessible to or on +behalf of third-party applications should not be logged at a level higher than +INFORMATIVE.</li> +<li>Invalid data coming from any untrusted source (including any +file on shared storage, or data coming through just about any network +connection) is considered expected and should not trigger any logging at a +level higher than DEBUG when it's detected to be invalid (and even then +logging should be as limited as possible).</li> +<li>Keep in mind that the <code>+</code> operator, when used on Strings, +implicitly creates a <code>StringBuilder</code> with the default buffer size (16 +characters) and potentially other temporary String objects, i.e. +that explicitly creating StringBuilders isn't more expensive than relying on +the default '+' operator (and can be a lot more efficient in fact). Keep +in mind that code that calls <code>Log.v()</code> is compiled and executed on +release builds, including building the strings, even if the logs aren't being +read.</li> +<li>Any logging that is meant to be read by other people and to be +available in release builds should be terse without being cryptic, and should +be reasonably understandable. This includes all logging up to the DEBUG +level.</li> +<li>When possible, logging should be kept on a single line if it +makes sense. Line lengths up to 80 or 100 characters are perfectly acceptable, +while lengths longer than about 130 or 160 characters (including the length of +the tag) should be avoided if possible.</li> +<li>Logging that reports successes should never be used at levels +higher than VERBOSE.</li> +<li>Temporary logging used to diagnose an issue that is hard to reproduce should +be kept at the DEBUG or VERBOSE level and should be enclosed by if blocks that +allow for disabling it entirely at compile time.</li> +<li>Be careful about security leaks through the log. Private +information should be avoided. Information about protected content must +definitely be avoided. This is especially important when writing framework +code as it's not easy to know in advance what will and will not be private +information or protected content.</li> +<li><code>System.out.println()</code> (or <code>printf()</code> for native code) +should never be used. System.out and System.err get redirected to /dev/null, so +your print statements will have no visible effects. However, all the string +building that happens for these calls still gets executed.</li> +<li><em>The golden rule of logging is that your logs may not +unnecessarily push other logs out of the buffer, just as others may not push +out yours.</em></li> +</ul> + +<h3 id="be-consistent">Be Consistent</h3> +<p>Our parting thought: BE CONSISTENT. If you're editing code, take a few +minutes to look at the surrounding code and determine its style. If that code +uses spaces around the if clauses, you should too. If the code comments have +little boxes of stars around them, make your comments have little boxes of stars +around them too.</p> +<p>The point of having style guidelines is to have a common vocabulary of +coding, so people can concentrate on what you're saying, rather than on how +you're saying it. We present global style rules here so people know the +vocabulary, but local style is also important. If the code you add to a file +looks drastically different from the existing code around it, it throws +readers out of their rhythm when they go to read it. Try to avoid this.</p> + +<h2 id="javatests-style-rules">Javatests Style Rules</h2> +<p>Follow test method naming conventions and use an underscore to separate what +is being tested from the specific case being tested. This style makes it easier +to see exactly what cases are being tested. For example:</p> +<pre><code>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)) +} +</code></pre> + + </body> +</html> |