Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

 

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?".

...

  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:

Code Block
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:

Code Block
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.

Code Block
titleBatchNumberUniquness.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:

...

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.

...

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 rarely rare when we should create anything else):

  • constants - we hold here classes like AwesomePluginConstants AwesomePluginConstants.java and maybe some model enums that are plugin specific.
  • hooks - model and view hooks like: ViewNameViewHooks ViewNameHooks.java, ModelNameHooks 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 ModelNameValidators.java, SomeOtherModelNameValidators SomeOtherModelNameValidators.java or ModelNameValidatorsAP.java (like with the hooks)
  • listeners - view listeners like: ViewNameListeners ViewNameListeners.java, ViewNameListenersAP.java (like with the hooks)
  • workPlansColumnExtensionhttp://wiki.qcadoo.org/display/QCDMESDOC/WorkPlans+column+extension

We add PluginName suffix 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

Code Block
if (condition)
  doSomething(); 

GOOD

Code Block
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

Code Block
String name;

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

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

 

GOOD

Code Block
String name = "Name not available";

if (condition) {
  name = "Michael";
}    
Code Block
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

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

 

GOOD

Code Block
// 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");
}