Skip to content

Instantly share code, notes, and snippets.

@antrix190
Last active April 12, 2018 19:16
Show Gist options
  • Save antrix190/7e3a64a35cb78a92ea0cc57577204fcb to your computer and use it in GitHub Desktop.
Save antrix190/7e3a64a35cb78a92ea0cc57577204fcb to your computer and use it in GitHub Desktop.
Java Best Practises
General Idea
The main goal of the recommendation is to improve readability and thereby the understanding and the maintainability and general quality of the code.
Naming Convention
There's no "one" correct answer here. Naming is quite subjective but what matters the most is that it should be consistent throughout the code base.
Hence few of the recommendations are mentioned below:
Variables
Use whole words and must avoid acronyms and abbreviations.
One-character variable names should be avoided except loop index.
Every variable declaration (field or local) declares only one variable: declarations such as int a, b; are not used.
Local variables are declared close to the point they are first used (within reason), to minimize their scope.
Constant names use CONSTANT_CASE while non-constant field names (static or otherwise) are written in lowerCamelCase.
Class variables should never be declared public,one exception to this rule is when the class is essentially a data structure, with no behavior. In this case it is appropriate to make the class' instance variables public.
Loop variables should be initialized immediately before the loop.
Numbers other than 0 and 1can be considered declared as named constants instead.
private static final int TEAM_SIZE = 11;
Player[] players = new Player[TEAM_SIZE]; // NOT: Player[] players = new Player[11];
Methods
Function names should be descriptive,name a function after the action it performs and it should follow lower camel case eg : getReceiptByTransactionId.
Functions that return a bool should be phrased as a question. e.g. isReady(), doesThingExist(), hasThing().
Package
Package name are all small.
Package should follow the below mentioned pattern :
com.sonetel.app.package
Package name should start by com.sonetel, which is the reverse of our domain.
app is name of the application, eg : common-api, telephony etc.
package is the name given to the functional unit such as config, entity,web,dao etc.
File Naming Convention
Service and Implementation Classes
The prefix hurts readability.
Impl sounds ugly and looks noisy. Do not use it. Do not use prefixes or other suffixes either. Use whole words. Remember the basics: classes are objects, so an Apple is an apple, not an App. Moreover, Impl does not convey anything about the implementation (aka business logic.)
eg:
Interface User { }
class DefaultUser implements User { }
class AnotherClassOfUser implements User { }
Package name for service could be : com.sonetel.appName.service while for implementations could be : com.sonetel.appName.service.impl or com.sonetel.appName.impl, what is imp worth noting here is that it should be consistent throughout the project.
Entity
Package name could be com.sonetel.appName.entity or com.sonetel.appName.model.
Since model classes describe 'real-life' entities it's better to call them by name.
Configuration Classes
Class name of files containing configuration should have a suffix such as Config or configuration. It is again important to be consistent with the naming convention throughout the project. eg: MonitoringConfig.java, SwaggerConfig.java, RedisConfig.java etc.
Controllers(?)
Package name should be com.sonetel.appName.web or com.sonetel.appName.web.controllers when the entities are with package name : com.sonetel.appName.web.model.
Controller follows Spring's convention of controller naming. Furthermore it lets the programmer understand immediately what the class does.
One type one controller form.
Repository and DAO
Repository or a DAO should be one per type persisted.
Hence it could follow pattern such as, {type}{repository} or {type}{DAO}
eg : UserRepository, AccountDAO etc.
Exception and Exception Handlers
Util
Constant And Enum
Logging
1.Use {} substitution feature instead of use of string concatenation.
2.Use DEBUG to report results to yourself and other developers
3.Use INFO to report results to Administrators and Users
4.Use TRACE for very detailed information, intended only for development. You might keep trace messages for a short period of time after deployment on production environment, but treat these log statements as temporary, that should or might be turned-off eventually.
5.Each logging statement should contain both data and description.
6.Log method arguments and return values,every method that: accesses external system (including database), blocks, waits, etc. should be considered
eg:
public String printDocument(Document doc, Mode mode) {
log.debug("Entering printDocument(doc={}, mode={})", doc, mode);
String id = //Lengthy printing operation
log.debug("Leaving printDocument(): {}", id);
return id;
}
7. If you communicate with an external system, consider logging every piece of data that comes out from your application and gets in.
8. Write logging messages in such a way, that they could be understood both by humans and computers, e.g. avoid formatting of numbers, use patterns that can be easily recognized by regular expressions, etc.
Max lines of code in a file /reusability
Rule 1
One class per file (in C++: one class -> one header and one implementation file).
Rule 2
Seven is considered the number of items that our brain can observe at the same time without getting confused. Above 7 we find it difficult to keep an overview of what we see. Therefore: each class should not have more than 7-10 methods. A class that has more than 10 method is probably too complex and you should try to split it. Splitting is a very effective method because every time you split a class you reduce the complexity of each individual class at least by a factor of 2.
Rule 3
A method body that does not fit in one or two screens is too big (I assume that a screen / editor window is about 50 lines). Ideally, you can see the whole method in one window. If this is not the case, you only need to scroll up and down a bit, without forgetting the part of the method that gets hidden. So, if you have to scroll more than one screen up or down to read the whole method body, your method is probably too big and you can easily lose the overview.
Again, splitting methods using private help methods can reduce method complexity very fast (at every split the complexity is at least halved). If you introduce too many private help methods you can consider creating a separate class to collect them (if you have more private methods than public ones, maybe a second class is hiding inside your main class).
Putting together these very rough estimates:
At most one class per source file.
At most 10 public method per class.
At most 10 private method per class.
At most 100 lines per method.
So a source file that is more than 2000 lines is probably too large and starting to be too messy.
Comments
The most important point to remember is to explain WHY you are doing something not What you are doing.
Avoid obvious comments.
Include JIRA ID and description if you're making modifications to already existing code.
Formatting
Braces to be used where optional.
Block indentation +4 spaces.
Column limit : 100 (detail Line wrapping rules)
Horizontal whitespace:
Separating any reserved word, such as if, for or catch, from an open parenthesis (() that follows it on that line eg catch () rather than catch()
Separating any reserved word, such as else or catch, from a closing curly brace (}) that precedes it on that line
Before any open curly brace ({), with two exceptions:
@SomeAnnotation({a, b}) (no space is used)
String[][] x = {{"foo"}}; (no space is required between {{)
On both sides of any binary or ternary operator.
After ,:; or the closing parenthesis ()) of a cast
Class and member modifiers, when present, appear in the order recommended by the Java Language Specification:
public protected private
abstract default static
final transient volatile synchronized native strictfp
Logical units within a block should be separated by one blank line.
eg :
// Create a new identity matrix
Matrix4x4 matrix = new Matrix4x4();
// Precompute angles for efficiency
double cosAngle = Math.cos(angle);
double sinAngle = Math.sin(angle);
Exception Handling
Never return null in catch block instead of handling or re-throwing the exception.
Declare the specific checked exception that your method can throw.
e.g.
public void foo() throws Exception { //Not Recommended
}
public void foo() throws NumberFormatException,IOException { //Recommended
}
Always correctly the wrap the exceptions in custom exceptions so that stack trace is not lost.
e.g.
catch(NoSuchMethodErrorException e) {
throw new MyServiceException("Some information: " + e.getMessage()); //Not Recommended
}
catch(NoSuchMethodErrorException e) {
throw new MyServiceException("Some information: " + e); //Recommended way
}
Don't catch any exception just for the sake of catching it.Catch any exception only if you want to handle it or , you want to provide additional contextual information in that exception.If you can't handle it in catch block, the best advice is just don't catch it only to re-throw it.
Use finally blocks instead of catch blocks if you are not going to handle exception.
If you are using resources like database connections or network connections, make sure you clean them up.
Always validate user input in very early stage, even before it reached to actual controller.
Pass all relevant information to exceptions to make them informative as much as possible.
Always terminate the thread which it is interrupted.
Prefer throwing runtime exceptions instead of checked exceptions from service layer.
Use @ControllerAdvice to catch controller exceptions and handle custom messages.
Package name for custom exceptions or exception handlers
com.sonetel.app.exception
Spring Configuration
Always externalise configuration.
Use annotations as much as possible.
Use Java configuration as much as possible.
Maintain separate profiles for separate environments(Dev/Sanity/Staging/Prod).
@Lazy for expensive bean initialisation.
Use component-scanning to find application beans and @Configuration for framework specific configuration that deviates from Spring Boot’s default auto-configuration.
Package name for configuration file should be
com.sonetel.app.config
Versioning
Given a version number MAJOR.MINOR.PATCH, increment the:
MAJOR version when you make incompatible API changes,
MINOR version when you add functionality in a backwards-compatible manner, and
PATCH version when you make backwards-compatible bug fixes.
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
Eg : 1.0.0-beta , 2.0.1-rc2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment