based on coding standards by Oracle, Google, Twitter and Spring Framework
The objective of this article is to give you a quick summary of do and don?ts in other words prefer and avoid based on coding standards from tech giants such as Oracle, Google, Twitter, and Spring Framework.
You might or might not agree with some of the best practices presented here, and that?s absolutely fine as long as there is some coding standard in place.
Why coding standards in the first place? There are many good reasons if you Google it and I will leave you with the following illustration
Coding standards document can be lengthy and boring. This article cherry picks bits and pieces from coding conventions by Google, Oracle, Twitter and Spring and it?s objective is to provide you with an easy to follow and less boring set of practices to make your code easy to read and maintain.
Almost always you will join teams working on existing software and there is a pretty good chance that most of the authors have left or switched to different projects, leaving you stranded with portions of code that make you question humanity.
Let?s dive into best practices from various coding standards.
Java Source File
The following is considered as best practices when it comes to java source files:
- The source file length is lower than 2,000 lines of code
- The source file is organized with documentation comment, package declaration, followed by a class comment, imports grouped (static last), class/interface signature and so on as shown below
package com.example.model;/** * Implementation-free perspective to be read by developers * who might not necessarily have the source code at hand * * @author x,y,z * @date * @version * @copyright * */import com.example.util.FileUtil;/* * Optional class specific comment * */public class SomeClass { // Static variables in order of visibility public static final Integer PUBLIC_COUNT = 1; static final Integer PROTECTED_COUNT = 1; private static final Integer PRIVATE_COUNT = 1; // Instance variables in order of visibility public String name; String postalCode; private String address; // Constructor and overloaded in sequential order public SomeClass() {} public SomeClass(String name) { this.name = name; } // Methods public String doSomethingUseful() { return “Something useful”; } // getters, setters, equals, hashCode and toString at the end}
Naming
Class and interface names are CamelCase and it is recommended to use the whole word and avoid acronyms/abbreviations. For example class Raster or class ImageSprite
- Package ? names com.deepspace over com.deepSpace or com.deep_space
- File ? names are CamelCase and end with .java matching the class name. There is one public class per file with each top-level class in its file
- Method ? names should be verbs in mixed case with each internal word capitalized for example run(); or runFast();
- Constants ? should be uppercase with ?_? separating each words for example int MIN_WIDTH = 44; and int MAX_WIDTH = 99;
- Variable ? a name that tells the reader of the program what the variable represents i.e. if you are storing a test grade then pick grade vs var1 . Keep the variable names short avoid including metadata.
// Prefer (??) – variable names short and describe what it storesint schoolId;int filteredSchoolIds; int uniqueSchooldIds; Map<Integer, User> usersById;String value;//Avoid (x) – Too detailed variable namingint schoolIdentificationNumber; int userProvidedSchoolIds; int schoolIdsAfterRemovingDuplicates; Map<Integer, User> idToUserMap;String valueString;
Remember ? the variable name should be short and easily tell the reader what value it represents. Use your judgment.
Prefer & Avoid
Formatting and indentation are all about organizing your code to make it easy to read, and it includes spacing, line length, wraps and breaks and so on
- Indentation ? Use 2 or 4 spaces or tabs and stay consistent
- Line length ? Up to 70 to 120 characters depending on the effect on readability. It?s important to eliminate the need for horizontal scrolling and place line breaks after a comma and operator.
Methods ? Here are a listing of best practices
// Prefer (??) Line breaks are arbitrary and break after a comma. String downloadAnInternet(Internet internet, Tubes tubes, Blogosphere blogs, Amount<Long, Data> bandwidth) { tubes.download(internet);}// Avoid (x) Hard to diff method args to method bodyString downloadAnInternet(Internet internet, Tubes tubes, Blogosphere blogs, Amount<Long, Data> bandwidth) { tubes.download(internet);}// Prefer (??) Add 8 (double of 2 or 4) spaces for deep indentprivate static synchronized horkingLongMethodName(int anArg, Object anotherArg, String yetAnotherArg, Object andStillAnother) { …}// Prefer (??) Easy scanning and extra column space.public String downloadAnInternet( Internet internet, Tubes tubes, Blogosphere blogs, Amount<Long, Data> bandwidth) { tubes.download(internet); …}A unit test would have caught that ?
If-checks ? IMO writing well-formatted code makes it easy to spot typos and errors to the author and the code reviewers, see below:
// Avoid (x) Do not omit {}if (condition) statement;// Avoid (x) if (x < 0) negative(x);// Avoid (x)if (a == b && c == d) {…}// Prefer (??)if ((a == b) && (c == d)) {…}// Prefer (??)if (condition) { statements;} else if (condition) { statements;} else if (condition) { statements;}// Avoid (x)if ((condition1 && condition2) || (condition3 && condition4) ||!(condition5 && condition6)) { //BAD WRAPS doSomethingAboutIt(); //MAKE THIS LINE EASY TO MISS}// Prefer (??)if ((condition1 && condition2) || (condition3 && condition4) ||!(condition5 && condition6)) { doSomethingAboutIt();}
Ternary operator ? And below are recommended practices
alpha = (aLongBooleanExpression) ? beta : gamma;alpha = (aLongBooleanExpression) ? beta : gamma;alpha = (aLongBooleanExpression) ? beta : gamma;
Switch ? When it comes to switch it?s best practice to
- Always have a default case even without code
- Use /* falls through */ to indicate the control falls to the next case
switch (condition) { case ABC: statements; /* falls through */ case DEF: statements; break; default: statements; break;}
Exception messages ? When throwing an exception here are samples of good and poorly indented messages.
// Avoid (x) – Not easy to readthrow new IllegalStateException(“Failed to process request” + request.getId() + ” for user ” + user.getId() + ” query: ‘” + query.getText() + “‘”);// Prefer (??) – Fairly easier to readthrow new IllegalStateException(“Failed to process” + ” request ” + request.getId() + ” for user ” + user.getId() + ” query: ‘” + query.getText() + “‘”);
Iterators and Streams ? Streams are becoming more common and at times it can be very complex hence, it?s important to indent for easy to read.
// Avoid (x) – Not easy to readIterable<Module> modules = ImmutableList.<Module>builder().add(new LifecycleModule()) .add(new AppLauncherModule()).addAll(application.getModules()).build();// Prefer (??) – Fairly easier to readIterable<Module> modules = ImmutableList.<Module>builder() .add(new LifecycleModule()) .add(new AppLauncherModule()) .addAll(application.getModules()) .build();Just follow a coding standard ? any really
Declarations and Assignments? One declaration per line is recommended since it encourages comments as shown below.
// Prefer (??) int level; // indentation levelint sizeMeter; // size of table// Avoid (x) in favour of aboveint level, sizeMeter;// Prefer (??) – Include unit in variable name or typelong pollIntervalMs; int fileSizeGb;Amount<Integer, Data> fileSize;// Avoid (x) mixing typesint foo, fooarray; // Avoid (x) – Do not separate with commaFormat.print(System.out, ?error?), exit(1);// Avoid (x) multiple assignmentfooBar.fChar = barFoo.lchar = ‘c’; // Avoid (x) embedded assignments in attempt to increase performance // or save a line. I am guilty of doing this :(d = (a = b + c) + r;// Prefer (??) over above a = b + c;d = a + r;// Prefer (??) String args// Avoid (x)String args// Prefer (??) Long use “L” instead of “l” to avoid confusion with 1 long timeout = 3000000000L;// Avoid (x) – Hard to tell last letter is l and not 1 long timeout = 3000000000l;
Put declarations only at the beginning of blocks (A block is code surrounded by curly braces { and }). Do not wait to declare variables until their first use; it can confuse the unwary programmer and hamper code portability within the scope.
// Prefer (??) declare at the beginning of the block. public void doSomething() { int whatIRepresent; // beginning of method block if (condition) { int someFlag; // beginning of ?if? block ? }}
It?s also important to avoid local declarations that hide declarations of the higher-levels and is to avoid confusions as shown below
int count;…public void doSomething() { if (condition) { int count; // AVOID! … } …}
Spacing & line breaks ? Avoid the temptation of saving 1?2 lines of code at the expense of readability. Here are all the best practices when it comes to spacing and blank lines (A white space does make a difference)
- One (1) blank line between methods and Spring developers recommends two (2) blank lines after constructors, static block, fields and inner class
- Space pad operators i.e. Use int foo = a + b + 1; over int foo=a+b+1;
- Separate all binary operators except ?.? from operands using a space
- Open brace ?{? appears at the end of the same line as the declaration statement or method and closing brace ?}? starts a line by itself indented
// Prefer (??) – Space after “while” and before “(“while (true) { …}// Avoid (x) – Unlike above no spacewhile(true) { …}// Prefer (??) – No space between “doSomething” and “(“public void doSomething() { …}// Avoid (x) – Unlike above spacepublic void doSomething () { …}// Prefer (??) – Add a space after an argumentpublic void doSomething(int a, int b) { …}// Prefer (??) – Space between operand and operators (i.e. +, =)a += c + d;a = (a + b) / (c * d);while (d++ = s++) { n++;}
Documentation and Comments
It?s worth mentioning that almost all code goes changes throughout its lifetime and there will be times when you or someone is trying to figure out what a complex block of code, a method, or a class is intended to do unless clearly described. The reality is almost always as follow
There are times that the comment on a complex piece of code, method, class does not add any value or serve its purpose. This usually happens when commenting for the sake of it.
Comments should be used to give overviews of code and provide additional information that is not readily available in the code itself. Let?s get started. There are two types of comments
Implementation Comments ? are meant to comment out code or comment about a particular implementation of the code.
Documentation Comments ? are meant to describe the specification of the code from an implementation-free perspective to be read by developers who might not necessarily have the source code at hand.
The frequency of comments sometimes reflects poor quality of code. When you feel compelled to add a comment, consider rewriting the code to make it clearer.
Types of Implementation Comments
There are four (4) types of implementation comments as shown below
- Block comment ? see example below
- Single line comment ? when the comment is not longer than a line
- Trailing comments ? Very short comment moved to the right end
- End of line comment ? begins a comment that continues to the newline. It can comment out a complete line or only a partial line. It shouldn?t be used on consecutive multiple lines for text comments; however, it can be used in consecutive multiple lines for commenting out sections of code.
// Block comment/* * Usage: Provides description of files, methods, data structures * and algorithms. Can be used at the beginning of each file and * before each method. Used for long comments that do not fit a * single line. 1 Blank line to proceed after the block comment. */// Single line commentif (condition) { /* Handle the condition. */ …}// Trailing commentif (a == 2) { return TRUE; /* special case */} else { return isPrime(a); /* works only for odd a */}// End of line comment if (foo > 1) { // Do a double-flip. …} else { return false; // Explain why here.}//if (bar > 1) {//// // Do a triple-flip.// …//}//else// return false;
Documentation comments (i.e. Javadoc)
Javadoc is a tool that generates HTML documentation form your java code using the comments that begin with /** and end with */ ? see Wikipedia for more details on how Javadoc works or just read along.
Here is an example of Javadoc
/** * Returns an Image object that can then be painted on the screen. * The url argument must specify an absolute {@link URL}. The name * argument is a specifier that is relative to the url argument. * <p> * This method always returns immediately, whether or not the * image exists. When this applet attempts to draw the image on * the screen, the data will be loaded. The graphics primitives * that draw the image will incrementally paint on the screen. * * @param url an absolute URL giving the base location of the image * @param name the location of the image, relative to the url argument * @return the image at the specified URL * @see Image */ public Image getImage(URL url, String name) { try { return getImage(new URL(url, name)); } catch (MalformedURLException e) { return null; } }
And the above would result in an HTML as follow when javadoc is run against the code that has the above
See here for more
Here are some key tags that you can use to enhance the quality of the generated java documentation.
@author => @author Raf@code => {@code A<B>C} @deprecated => @deprecated deprecation-message @exception => @exception IOException thrown when @link => {@link package.class#member label} @param => @param parameter-name description @return => What the method returns@see => @see “string” OR @see <a …></a>@since => To indicate the version when a publicly accessible method is added
For a complete listing and more detailed description see here
Twitter?s coding standard advises against the use of @author tag
Code can change hands numerous times in its lifetime, and quite often the original author of a source file is irrelevant after several iterations. We find it?s better to trust commit history and OWNERS files to determine ownership of a body of code.
Following are examples of how you could write a documentation comment that is insightful as described in Twitter?s coding standard
// Bad.// – The doc tells nothing that the method declaration didn’t.// – This is the ‘filler doc’. It would pass style checks, but doesn’t help anybody./** * Splits a string. * * @param s A string. * @return A list of strings. */List<String> split(String s);// Better.// – We know what the method splits on.// – Still some undefined behavior./** * Splits a string on whitespace. * * @param s The string to split. An {@code null} string is treated as an empty string. * @return A list of the whitespace-delimited parts of the input. */List<String> split(String s);// Great.// – Covers yet another edge case./** * Splits a string on whitespace. Repeated whitespace characters * are collapsed. * * @param s The string to split. An {@code null} string is treated as an empty string. * @return A list of the whitespace-delimited parts of the input. */List<String> split(String s);
It?s important to be professional when it comes to writing comments
// Avoid (x)// I hate xml/soap so much, why can’t it do this for me!?try { userId = Integer.parseInt(xml.getField(“id”));} catch (NumberFormatException e) { …}// Prefer (??)// TODO(Jim): Tuck field validation away in a library.try { userId = Integer.parseInt(xml.getField(“id”));} catch (NumberFormatException e) { …}
And it is important to keep in mind not to document overrided method unless the implementation has changed.
And here are a few more points to keep in mind
- Avoid wildcard imports ? as described in Twitter?s coding standards it makes the source of class less clear. I work in a team with a mix of Eclipse and IntelliJ users and I found out that Eclipse removes wildcard imports and IntelliJ introduces them. There probably is an option to turn it off, just wanted to point out the default for the two.
- Always use @Override annotation when overriding
- Encourage use of @Nullable when a field or method returns null
- Make use of special comments for future work and do not forget to leave a reference to yourself so others know who to ask their Y question instead of guessing, removing it or checking git blame to find who added it. Some IDEs like Eclipse and IntelliJ also, help in listing these for easy access as well as a reminder.
//FIXME (Raf): An actionable message describe what needs to be done//TODO (Raf): An actionable message describe what needs to be done
The end game is to write code that makes the life of future authors and maintainers easy.
The end game
Conclusion
If you enjoyed this article, you might find my other articles useful.
The following article highlights what I wish I knew earlier as a developer and would have greatly helped me down the road. In other words, what would I tell to my student self?
Key habits and things I wish I knew earlier as a developer
A listing of key habits and skills that could help you become a better developer
codeburst.io
There are many benefits to contributing to Open-source and I have shared my experience and knowledge of contributing to Spring Boot, Spring Security, and Elasticsearch repositories.
How to contribute to open source
A guide on how to get started with open source contribution
medium.com
In the following article, I have listed 13 important points inspired by Google that any developer could apply to their code reviews
13 Code Review Standards Inspired by Google
How to excel at code reviews
medium.com
Load testing doesn?t have to be the job of a QA or tester or performance tester, anyone could with some effort load/performance test their piece of code. It?s a great skill to have.
How to Load Test: A developer?s guide to performance testing
How to design and run load tests using Apache JMeter & Taurus
medium.com
Please follow me on medium and check out my other articles https://medium.com/@rhamedy and feel free to connect with me on LinkedIn.
Other relevant reading materials
A listing of relevant articles that are relevant to writing code that is clean, well-structured, easy to read, and maintainable. If you wish to read more, definitely recommend the following