Are there general principles that should work for every project? I think so..
Code conventions should follow market conventions
Picking up code conventions that are widely known and used greatly increases chance of hiring right people who can touch the ground running when joining the project. Usually most of the cost of software is associated to its maintenance and hardly any software is maintained for its whole life by the original creator. Widely used conventions improve the readability of the software, allowing engineers to understand new code more quickly and thoroughly.
Some of the widely used conventions to follow in Java would be
Another useful one to decide upfront is to prefer 4 spaces or tabs. The choice of tabs versus spaces is arbitrary and in the absence of opinion 4 spaces look more common.
Self Documenting Code
Code comments do not form part of the compilation process and nor are they statically typed/linked. As such comments are ignored by the compilation process and more importantly by the testing processes. There is nothing to assert that the comments reflect what the code does or should do. It is therefore unreasonable to assume that, as the code organically grows, the comments will stay in line with the code that they narrate. What was once a salient point will, over time, become irrelevant or downright misleading. As such code should be expressive and document its behavior in preference to code comments.
You aren’t going to need it. The principle here states that you should not write any code until you actually need it. This is the heart of simplicity. Write as little as you can to satisfy the requirement you are building. Examples where this is breached could be:
- creating a factory when it only builds one thing
- adding in getters and setters when no external usage of them
- abstract classes when there is only one derived class
One of the easiest ways to not build stuff that is not needed is introduction of TDD. It forces you to satisfy the immediate test requirements, everything that doesn’t serve this goal should not be added.
Interfaces and classes should be well named, reflecting their purpose
Interfaces should always describe the behavior they represent. As such they should form more of a description of the implementing classes behaviour. Below two are an important help when defining interfaces.
Class names should describe the way that they implement a function or a behaviour.
If you introduce interfaces intentionally – and not as a general rule, you will considerably reduce the number of files. Your code becomes easier to understand and so maintain. An interface will become an artifact to hide multiple implementations and not a general plumbing.
Some examples where the above is very often breached:
- interfaces that are prefixed with ‘I’. The fact that the prefix is needed tells us that the name does not comply with the above.
- classes that are postfixed with ‘Impl’. The fact that the postfix has been used suggests that either the interface is too closely aligned to the way that it implements the behaviour, or it’s just badly named.
En excellent article on interfaces in modern Java by Adam Bien:
A perfect example of this is java.util.List is not java.util.IList.
Import Using Wildcards
In order to avoid long import lists, it is sometimes wise to say that after 4 imports one should introduce wild cards in import list. This is also default of IntelliJ Idea.