How To Not Be A Noob [Resource for beginning developers]

#Socratic_Phoenix’s Ultimate Guide to Not Being A Noob Plugin Programmer

###Preface
As many of you know, the plugin development forums on bukkit and spigot were flooded with many questions along the lines of “here is stacktrace, give me code.” Since Sponge has attracted more attention from more experienced developers, I haven’t really seen too many of these posts, but I’d like to create a guide to:
a. Address common errors
b. Talk about when and when not to post a question
c. Convince people to learn Java before plugins

Hopefully, the following guide will help prevent the massive overflow of useless questions that sponge will undoubtedly experience as it grows.


###Note
If you have to ask “what is x” while reading this post, go learn Java. I’ve tried very hard to explain a huge amount of things that anyone who genuinely knows the language should know anyway, but if you don’t know what “OOP” stands for, or what a “namespace” is, your in trouble.

If you think I’ve genuinely mis-explained, or missed something, please notify me by posting a reply.


##Common Errors
This section addressing common errors having to do with practice and readability.


###Naming Conventions
This ‘error’ is probably the most common. Naming Conventions are a set of rules or guidelines, not enforced by the compiler, that dictate how you should name your Java files and variables. Packages should be all lowercase, and be reverse-domain (i.e. if I own example.com, my package name could be com.example. If you don’t own a domain, use your email, if your email is [email protected], the package could be com.example.someone)… You can than add as many sub-packages as you want, so if I owned example.com, I could have packages called com.example.sponge.plugin and com.example.api. The reasoning behind this package naming scheme is to ensure there are no duplicate class names spaces. Java class files should start with an uppercase letter, and camel-case for the rest (also known as TitleCase) (i.e. If I have a bank account class, it should be called BankAccount). Finally, variables and methods should start with a lowercase letter, and camel-case for the rest, static final variables and enum elements should be all uppercase. A more in-depth list can be found here (credit goes to JavaCodeGeeks and Steve Robinson), and the archived ‘official’ guidelines can be found here.


###Public, Static Plugin References
If, anywhere in your code, you have public static MyPlugin plugin; (where ‘MyPlugin’ is your plugin’s class-name), get rid of it. That code is not only insecure, but considered bad practice. (It’s insecure because someone can set a public variable to whatever they want, and it’s bad practice because OOP is about methods and encapsulation). I’d like to note that static is not bad practice in this context. Because a Sponge plugin is only initiated once per one, it is technically a singleton, and therefore there is nothing wrong with storing a static reference to it, but you should do it more like this:

@Plugin(...) //Actually have @Plugin filled out, shortened for sake of example
public class MyPlugin {
    private static MyPlugin instance;
    
    @Listener
    public void onServerStart(GamePreInitializationEvent ev) {
        MyPlugin.instance = this;
    }

    public static MyPlugin getPlugin() {
        return MyPlugin.instance;
    }
}

With the above setup, you no longer have the problem of insecurity or bad practice. The plugin is a singleton, so it’s fine to store it in a static variable, but the static variable is private, meaning other plugins can’t just access it willy-nilly, and we have a method that returns that instance, but there is no way to set the variable to something else. (Without reflection).


##To Ask or Not to Ask?
This section addresses questions about errors in your code, stacktraces potentially caused by your plugin, and whether or not you should post them on the forums here. If you’re going to ask a general question about how to use the API, you definitely should.


###Java or Sponge
A lot of errors can be caused by a more general java error, not an error related to Sponge. If it is a java error (see Stacktraces below), don’t post it on the Sponge forums. I’d suggest posting it on Stackoverflow (see Stackoverflow below).


###Stacktraces
Stacktraces are those big walls of text that output whenever there’s an error. I’m going to try and break them down into their separate pieces in this section. Stacktraces are Java’s way of saying, “here is an issue, this is where it happened, and this is what happened right before it.”

####Reading a Stacktrace
First, you need to understand a stack trace element. A stack trace is an exception, followed by a message, followed by a list of stack trace elements, optionally followed by the stack trace of a cause exception. A single stack trace element is of the form at [class].[method]([file]:[line]). For example, the stack trace element at Test.main(Test.java:28) refers to a line 28 of the Test.java file, which is in the Test.main method. The job of a stack trace element is to tell you specifically where the error occurred. A stack trace shows you where the root cause was, and what methods called the method where the root cause is located.

The first step when you see a stacktrace is to figure out where the problem occurred, and whether or not it’s in your code. For this, we have to find the root cause of the stack trace. The cause of the stack trace is the uppermost element in the bottom-most cause exception.
For example, in the following exception:

Exception in thread "main" java.lang.NullPointerException
        at com.example.myproject.Book.getTitle(Book.java:16) <-- Root
        at com.example.myproject.Author.getBookTitles(Author.java:25)
        at com.example.myproject.Bootstrap.main(Bootstrap.java:14)

the root cause is simply the uppermost element, because the exception has no causes. However, in the following exception:

Exception in thread "main" java.lang.IllegalStateException: A book has a null property
        at com.example.myproject.Author.getBookIds(Author.java:38)
        at com.example.myproject.Bootstrap.main(Bootstrap.java:14)
Caused by: java.lang.NullPointerException
        at com.example.myproject.Book.getId(Book.java:22) <-- Root
        at com.example.myproject.Author.getBookIds(Author.java:35)
        ... 1 more

the root cause is the first element of the last cause of the exception.

The above exceptions were taken from a stackoverflow answer here, the answer there is very detailed, and if you’re still confused about stacktraces, check it out.

After you’ve figured out the root cause, it could be potentially useful to see what methods called the method that caused the error. Each separate stacktrace is, chronologically, bottom to top, however the cause exceptions are chronologically top to bottom. This means that the method that called the method that caused an error is in the last cause stack trace, and is the second element. The method that called the method that caused an error is the third element in the last cause stack trace, etc.

####Using the Knowledge
Now that you know the root cause of the stack trace, go check out that line. If you have a NullPointerException, a variable or return value on that line is null. If you have an IndexOutOfBoundsException, an index is out of bounds. Most of the exception names are self explanatory, so make sure you take note of the bottom-most cause exception’s name.


###Is it You?
A lot of questions that have shown up in the plugin development section aren’t necessarily the plugin developer’s fault. If you post a question, be sure the error is coming from your code. Be sure to read the stacktrace, and find the root cause. Don’t assume it’s immediately Sponge either, but if you do post a question, just make sure you’ve already gone through and tried to fix it. If you come to the forums and say x happened in my plugin when I do y, I’ve tried a and b, then people will definitely be willing to help. Moreover, we can’t read your mind. If you have code that could, in any way, potentially be part of the error, post it. If it’s too long, put it in a gist or on pastebin.


###Is it Sponge?
A very common question I’ve seen brought up is what an AbstractMethodError means. An AbstractMethodError means that part of the Sponge API is not implemented in either Sponge Vanilla, Sponge Forge, or both. Furthermore, be sure to read the stacktrace - if your code is the root cause, it’s not sponge, if a sponge class is the root cause, it’s sponge. Finally, if you’ve definitively determined that Sponge is causing the issue, post the problem, with the stacktrace, on github.


###Stackoverflow
As aforementioned, a lot of errors are more associated with java than Sponge, and shouldn’t really be posted on the Sponge forums. If you think you have a problem with base java (and not Sponge), you could post the problem on stackoverflow. Stackoverflow is a great resource, run by stackexchange, that accepts a multitude of programming questions centered around bug fixing or specific questions about code. (High-level conceptual programming questions can be asked at programmers stack exchange).


##Java Before Sponge

###The Reason
The concepts of OOP and Java are not necessarily followed by outside APIs, although Sponge does fairly well, it is important to understand how the language works, and what the conventions are, before “polluting” it with an external API. I’m not saying Sponge is not a good API, it’s one of the best I’ve seen, but some of it’s wonderful methods aren’t necessarily traditional. I’d suggest starting with a small project (maybe a command line calculator?), and move to more advanced projects, with more complex architecture, before you begin using external APIs, such as Sponge. Furthermore, it is important to be able to determine what is an issue with your understanding of the Java language versus your understanding of the Sponge API.


###Tutorials
By far, the best place to start learning Java is the official tutorials. Not only are they always up to date, but they’re also very detailed and helpful. Try not to watch too many videos, because they quickly become outdated, and often don’t follow naming conventions or make some other error.


##Resources
Useful stuff for beginning developers (mostly already mentioned above, but here they are in a nice list)


##The End
If anyone thinks I’ve missed a particularly important issue, I’d be willing to add it in somewhere. If you found this guide helpful, than It’s served its purpose. Furthermore, if your answering a posted question that you think is answered in this thread, go ahead and just link the OP here and say “see section x”.

:slight_smile:

17 Likes

So detailed :open_mouth:

Nice resource! :grinning:

In the “Public, Static Plugin References” section, I do suggest changing the classname to MyPlugin and the static variable name to “instance”. That way there is no confusing with annotation, classname and the variable all having the same name.

This is alternatively known as TitleCase.

@Gamecube762 and @pie_flavor
Thanks for the input! I’ve edited the post.

Also, just a wee bit of a typo. The event is GamePreInitializationEvent, not PreInitializationEvent.

1 Like

Thanks, I’ll fix it