Tech Standards
This page covers coding standards and best practices used in the tech department.
Always Test
Always test your code before you ask for feedback or say that you are done. When you just finished coding a feature you should assume it’s broken and buggy. You should always launch your local Minecraft server and test all aspects of the feature. You will almost always find something to correct.
The reason we bring this up is because new tech staff members usually don’t test their code enough.
Code Style
Follow the MassiveCraft code style. It’s described below by example.
You will also have to configure your IDE.
- Download the MassiveCraft Code Style for IntelliJ and add it at File → Settings → Editor→ Code Style.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
// We use an Allman inspired indent style. // This means curly brackets have their own line (with some exceptions). // Indentation is done with tabs. public class Example { // -------------------------------------------- // // FIELDS // -------------------------------------------- // // For simple getters and setters we do everything on one line. protected boolean awesome = true; public boolean isAwesome() { return this.awesome; } public void setAwesome(boolean awesome) { this.awesome = awesome; } // -------------------------------------------- // // CONSTRUCT // -------------------------------------------- // public Example() { } public Example(boolean awesome) { this.awesome = awesome; } // -------------------------------------------- // // METHODS // -------------------------------------------- // public boolean someMethod(Collection players) { // Oneliners like this are awesome! if (this.isAwesome()) return true; // We use space between most operators and funny characters. // Note the "for (" as opposed to "for(". // Note the "player : players" as opposed to "player:players". for (Player player : players) { // Note the "!player.isOnline()" as opposed to " ! player.isOnline()". if (!player.isOnline()) return false; } return true; } } // Every file ends with an empty line. |
Name Positively
Double negations are harder to understand than no negations at all. With that in mind booleans should have positive names and not negative ones.
Right:
1 2 3 4 5 |
protected boolean featureEnabled = false; public boolean isFeatureEnabled() { return this.featureEnabled; } protected boolean synchronous = false; public boolean isSynchronous() { return this.synchronous; } |
Wrong:
1 2 3 4 5 |
protected boolean featureDisabled = true; public boolean isFeatureDisabled() { return this.featureDisabled; } protected boolean asynchronous = true; public boolean isAsynchronous() { return this.asynchronous; } |
Name Backwards
When coding it’s often good to name things backwards. It will allow for better readability and string based sorting. Explain the the core nature first in the name rather than in the end.
This is best proven by example. Assume you have three different comparators. They compare players, awesomeness, and files. In human speech you would say that the comparator comparing players is a “Player Comparator”. But the backwards “Comparator Player” will work much better. Please note how grouping up the common words to the left improves readability, even if it mean naming backwards in some cases:
Right:
- ComparatorPlayer
- ComparatorAwesomeness
- ComparatorFile
Right:
1 2 3 4 |
public volatile long millisBetweenPollLocal = 1000; public volatile long millisBetweenPollLocalColl = 100; public volatile long millisBetweenPollRemote = 1000; public volatile long millisBetweenPollRemoteColl = 100; |
Wrong:
- PlayerComparator
- AwesomenessComparator
- FileComparator
Wrong:
1 2 3 4 |
public volatile long millisBetweenLocalPoll = 1000; public volatile long millisBetweenLocalCollPoll = 100; public volatile long millisBetweenRemotePoll = 1000; public volatile long millisBetweenRemoteCollPoll = 100; |
Beware Player NPCs
Just because something seems to be a player does not mean it actually is. It can be a player NPC. Use the method in MUtil to test this.
1 2 3 4 5 6 7 8 9 |
@EventHandler(priority = EventPriority.NORMAL) public void onPlayerTeleport(PlayerTeleportEvent event) { // If a player teleports ... Player player = event.getPlayer(); if (MUtil.isntPlayer(player)) return; ... } |
Continue and Return to Avoid Indentation
The more indentation the harder the source code is to read. To avoid indentation you should use the continue statement in loops and the return statement in methods.
Right:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@EventHandler(priority = EventPriority.MONITOR) public void onPlayerJoin(PlayerJoinEvent event) { // If a player joins the server ... Player player = event.getPlayer(); if (MUtil.isntPlayer(player)) return; // ... and this player never played before ... if (player.getFirstPlayed() != 0) return; // ... enourage all other players to say hi. for (Player other : MUtil.getOnlinePlayers()) { if (other.equals(player)) continue; other.sendMessage("Say hello to " + player.getDisplayName() + "!"); } } |
Wrong:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
@EventHandler(priority = EventPriority.MONITOR) public void onPlayerJoin(PlayerJoinEvent event) { // If a player joins the server ... Player player = event.getPlayer(); if (MUtil.isPlayer(player)) { // ... and this player never played before ... if (player.getFirstPlayed() == 0) { // ... enourage all other players to say hi. for (Player other : MUtil.getOnlinePlayers()) { if (!other.equals(player)) { other.sendMessage("Say hello to " + player.getDisplayName() + "!"); } } } } } |
Use Singletons
Use singletons when you can rather than creating new instances of the class over and over again.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public class ComparatorDerp implements Comparator { // -------------------------------------------- // // INSTANCE & CONSTRUCT // -------------------------------------------- // private static final ComparatorDerp i = new ComparatorDerp(); public static ComparatorDerp get() { return i; } // -------------------------------------------- // // OVERRIDE: COMPARATOR // -------------------------------------------- // @Override public int compare(Derp derp1, Derp derp2) { ... } } |