Skip to content

General Principles

  • Write clean and readable code.
  • Prefer clarity over cleverness.
  • Keep methods and classes small and focused.
  • Avoid unnecessary complexity.

Code should always be understandable for other developers working on the project.


Naming Conventions

Use clear and descriptive names.

Classes

Classes should use PascalCase.

Example:

PinataManager.class
PlotService.class
PlayerDataRepository.class

Methods and Variables

Use camelCase.

Example:

spawnPinata()
calculateJobReward()

PlayerData playerData;
int plotOwnerId;

Avoid Repeated Method Chains

Avoid calling the same method chains multiple times within a method.\ Instead, store frequently used objects in local variables.

Repeated calls reduce readability and make the code harder to maintain.

Avoid:

getPlugin().getKitManager().getKit(name).getDisplayName();
getPlugin().getKitManager().getKit(name).getOrderId();

Prefer:

KitManager kitManager = getPlugin().getKitManager();
KnockbackFFAKit kit = kitManager.getKit(name);
kit.getDisplayName();
kit.getOrderId();

This improves:

  • readability
  • maintainability
  • debugging

and prevents long and repetitive method chains


Constants

Constants (static final) should use UPPER_CASE.

Example:

public static final MAX_PINATAS_PER_PLAYER = 12;
public static final DEFAULT_PLOT_SIZE = 4;

Prefer Early Returns over Nested if / else

Avoid deeply nested if / else if / else structures.\ Instead, use early returns (guard clauses) to handle edge cases first and keep the main logic readable.

Deep nesting quickly makes code harder to read and maintain.

Avoid:

if (args.length >= 1) {
  KitManager kitManager = getPlugin().getKitManager();
  KnockbackFFAKit kit = kitManager.getKit(args[0]);
if (kit != null) {
  if (args.length == 1) {
    getPlugin().getManager().openKitEditMenu(player, kit);
  } else {
    String action = args[1];
    kitManager.editKit(player, kit, args, action);}
  } else {
    player.sendMessage(DisplayData.KIT_DOESNT_EXIST);
  }
}

Prefer:

if (args.length < 1) return;

KitManager kitManager = getPlugin().getKitManager();
KnockbackFFAKit kit = kitManager.getKit(args[0]);

if (kit == null) {
  player.sendMessage(DisplayData.KIT_DOESNT_EXIST);
  return;
}

if (args.length == 1) {
  getPlugin().getManager().openKitEditMenu(player, kit);
  return;
}

String action = args[1];
kitManager.editKit(player, kit, args, action);

Benefits:

  • reduces indentation
  • improves readability
  • makes error cases explicit
  • keeps the main logic easier to follow

Logging

Use proper logging instead of printing to console.

Avoid:

System.out.println("Debug");

Use:

plugin.getLogger().info("System started");

Null Safety

Always check for possible null values where applicable.

Example:

if (player == null) {
  return;
}

Avoid assumptions that may cause NullPointerExceptions.


JetBrains Annotations

Use JetBrains annotations to make nullability explicit:

  • @NotNull
  • @Nullable

They help to:

  • improve readability
  • prevent null-related bugs
  • define clear method contracts

Example:

public void sendMessage(@NotNull Player player, @Nullable Component message) {
  if (message == null) return;
  player.sendMessage(message);
}

Avoid Static Abuse

Avoid excessive use of static fields or global access patterns such as singleton-style getInstance() methods.

Static access creates strong coupling between classes and makes code harder to maintain, test, and refactor.

Avoid:

KitManager.getInstance().getKit("archer");

or long global chains:

Main.getInstance().getKitManager().getKit("archer");

Prefer passing dependencies through constructors or storing them in fields.

Prefer:

public class KitHolder {

  private final KitManager kitManager;

  public KitHolder(KitManager kitManager) {
    this.kitManager = kitManager;
  }

  public void giveKit(BukkitPixelPlayer player {
    kitManager.getKit("archer").applyTo(player);
  }

}

Benefits:

  • clearer dependencies
  • easier testing
  • better maintainability
  • reduced global state

Static fields should only be used where they are truly appropriate, such as:

  • constants
  • utility classes without state

Avoid using static access as a shortcut to reach managers or plugin instances.


Comments

Use comments when code is not immediately obvious.

Avoid obvious comments:

// increase i
i++;

Prefer explaining why, not what.

Example:

// Prevent players from claiming the plot again while it is already being claimed
if (plotManager.isClaiming(player)) return;

Performance

Avoid expensive operations in frequently called methods such as:

  • event listeners
  • tick tasks
  • loops over large collections

Cache values where appropriate.

Never execute SQL or Redis operations on the main thread!

Minecraft runs primarily on a single main thread, and blocking operations such as database or Redis calls will cause server lag or tick delays. Even Redis operations can introduce small blocking delays.

All database and external service operations must therefore be executed asynchronously (off-thread).


Testing

Before submitting a merge request:

  • test your feature on the [[Dev Server|Development/Dev-Server]]
  • verify that it does not break existing systems