Our coding conventions

 

I highly encourage you to write down here all our coding conventions. From now on nobody will be able to say "how could I know?".

Most of them are highly debatable so feel free to discuss them or even prove them wrong.

Also, the thing is that you have to know the rules to be able to break them. Proper order of coding something should look like this:

  1. You consider doing it according to this conventions, assuming you fully understand them.
  2. If your common sense tells you it's not right, it probably isn't - do it your way.
  3. But don't leave it like that, talk about it, or even better update this page.

Mes specific conventions

Model fields literals

Every time we add a new model field we should add it to the constants/PluginNameFields.java like this:

public class PluginNameFields {
 
  public final static String ORDER = "order";
}  

So we won't repeat those string literals over and over when accessing entities fields. We're gonna use:

entity.getBelongsToField(PluginNameFields.ORDER);

You should avoid static importing such constants or you loose their namespace and the probability to make mistake increase dramatically.
It is important especially for field names, which often has the same (or at least very similar) names.

 

Java enums

For every enum field of a model we create, we should create corresponding Java enum in constants package.

For ex.

BatchNumberUniquness.java
public enum BatchNumberUniqueness {
 
  GLOBALLY("01globally"), MANUFACTURER("02manufacturer");

  private final String stringValue;
 
  private BatchNumberUniqueness(final String stringValue) {
    this.stringValue = stringValue;
  }
  
  public String getStringValue() {
    return stringValue;
  }

  public static BatchNumberUniqueness parseString(final String string) {
    BatchNumberUniqueness parsedEnum = null;
      for (BatchNumberUniqueness value : BatchNumberUniqueness.values()) {
        if (value.getStringValue().equals(string)) {
          parsedEnum = value;
          break;
        }
      }
    Preconditions.checkArgument(parsedEnum != null, "Couldn't parse enum from string '" + string + "'");
    return parsedEnum;
  }

  @Override
  public String toString() {
    return stringValue;
  }

}

 

Naming conventions

Naming literals:

EDIT: look at the mes specific convention about model field literals.

If the same string literal occurs more than once we extract it to a field like this:

private static final String L_STRING_LITERAL = "stringLiteral"

I know it was STRING_LITERAL_L before, but that convention didn't work for magic numbers, also if you think about it, that L_ upfront tells you clearly what you deal with. That it's not a plugin specific constant nor enum.

Same thing holds for magic numbers:

private static final int L_15 = 15;

 

Naming classes/packages:

If plugin name is "mes-plugins-awesome-plugin" the basic package is: com.qcadoo.mes.awesomePlugin, we can create some additional packages (and it's very rare when we should create anything else):

  • constants - we hold here classes like AwesomePluginConstants.java and maybe some model enums that are plugin specific.
  • hooks - model and view hooks like: ViewNameHooks.java, ModelNameHooks.java. If the hook class is meant to extend (on a business level) an other plugin it should have plugin abbreviation for ex. ModelNameHooksAP.java
  • validators - model validators like: ModelNameValidators.java, SomeOtherModelNameValidators.java or ModelNameValidatorsAP.java (like with the hooks)
  • listeners - view listeners like: ViewNameListeners.java, ViewNameListenersAP.java (like with the hooks)
  • workPlansColumnExtensionhttp://wiki.qcadoo.org/display/QCDMESDOC/WorkPlans+column+extension

We add PluginName prefix only to classes that are meant to be used outside this plugin - things like: AwesomePluginConstants.java, AwesomePluginService.java.

Coding style conventions

Single line for or if statements:

Even if they are single commands, that you are sure won't grow bigger, we enclose it in { } brackets - always.

BAD

if (condition)
  doSomething(); 

GOOD

if (condition) {
  doSomething();
}  

 

We initiate objects, especially Lists (local - non field) upon creation:

Because if we won't we are in risk to letting them remain null.

BAD

String name;

if (condition) {
  name = "Michael";
}  
List<Entity> customers;

if (condition) {
   customers = loadCustomers();
}    

 

GOOD

String name = "Name not available";

if (condition) {
  name = "Michael";
}    
List<Entity> customers = new LinkedList<Entity>();

if (condition) {
  customers = loadCustomers();
}    

 

If we are dealing with 2 state enum kind of option we don't make the other option fall into simple else block.

Because number of states can change over time. The code where all different states fall into else block won't tell you anything, will just remain broken, silently.

This also applies to any options, not just model enums.

BAD

// state is either 01draft or 02accepted
 
if ("01draft".equals(state)) {
  doSomething();
} else {
  doSomethingDifferent();
}   

 

GOOD

// state is either 01draft or 02accepted

if ("01draft".equals(state)) {
  doSomething();
} else if ("02accepted".equals(state)) {
  doSomethingDifferent();
} else {
  throw new IllegalStateException("state is neither 01draft nor 02accepted");
}