Beginner Programming Mistakes and Why You're Making Them

Discussion in 'Spigot Plugin Development' started by Choco, Oct 14, 2017.

  1. This post is really usefull, I will definitely come back here several more times. Until Im sure my plugins are not gonna be rejected for "beginner programming mistakes".
    • Friendly Friendly x 1
  2. Even utility methods? I see no reason to not use them
    • Agree Agree x 4
  3. It really depends of your method. In Scala and Kotlin, you can attach a new method to an existing class. Like "msg.kill".translate(Locale.EN_GB, "Il_totore", "MrMicky") → "Il_totore was killed by MrMicky"
    or "&b&lHey".toJsonFormatting → "{"text":"Hey","color":"aqua","bold":"true"}
  4. I know, but we're talking about Java here.
    • Agree Agree x 2
  5. No. We're talking about languages usable with Spigot. All the JVM languages are concerned. Some developpers write their plugins in Scala or Kotlin
  6. At that point, all languages are concerned. It's perfectly possible to use languages beyond JVM languages to make a Spigot plugin (e.g. JNI allows for interaction with native applications).

    As for the conversation before, utility methods can definitely be fine as outlined in the first post, but you must watch out that you're not making utility methods that shouldn't be utility methods. Utility methods are fine if the method does not belong to any specific class instance (or class). In that case you can provide it as a utility method, so you avoid having to pass around some kind of unnecessary class instance just to provide access to that method. The utility method, however, should avoid modifying any external state as to avoid making your code hard to reason about. I always found "hard to reason about" a bit confusing when I was learning about different design principles - after all, if you read the code you can clearly see that it's doing a mutation, so how is it hard to see this? Keep in mind, however, that not everyone will be reading your code and likely not even the documentation. Have you read the entire source code of Bukkit (in this case CraftBukkit, since that's where most of the implementation actually resides)? Even if for some reason you have, do you remember every line of it? I think it's safe to assume that most people haven't and then such a mutation can come out of nowhere and cause unexpected errors, since you think object A is in a certain state, but because you called a method it's suddenly in a different state you didn't expect it to be.
    A utility method should also only have one implementation. If you have methods that do the same thing, but in different ways, this is usually a place where actually defining a class comes in handy, because I can override that method that needs a different implementation. I can then also easily swap between implementations by just providing the classes that make use of the implementation a different class. This is easier then having to rip out places where you were using a utility method that suddenly has to be switched over to a different one, or replacing it with an if/else statement to decide on the spot which implementation is better to use. To go back to the classic example of the Math class: mathematics are clearly defined and there is for example no way that Math.abs(-4) would ever return anything but 4. While the implementation could of course be altered (any implementation can), the change would very likely not be meaningful.

    When and where a utility method is appropriate is definitely subjective, just like most of the design principles around here, but if you ask yourself: "Does this belong to a class?" and the answer is no, you're on the right track. As an extension of this, you can ask yourself: "Does this belong to any of my classes?" in case you don't have access to features like extension methods.

    While I definitely agree that utility methods can be used properly, you'd be surprised how long you can go without using them. It's very well possible to avoid the vast majority of cases where you could use a utility method without violating DRY.
  7. I never knew programmers were so snobbish.

    I don't think it matters at all, so long as the code actually works and does what it's supposed to do.
    • Funny Funny x 2
    • Optimistic Optimistic x 1
  8. It does matter, it could affect scalability, readability, productivity, performance etc. etc.
    • Agree Agree x 5
    • Informative Informative x 1
  9. This is a really interesting comment, because I believe you truly don't understand why these things matter. I encourage you to continue on your journey in software development so that you may one day discover for yourself why they do and in what contexts. As a fun exercise, take note of your own words here. When you have some more experience with software development in different constellations of contexts, domains, teams, etc., and you have felt the consequences of poor software design decisions, dig those words back up, so you can appreciate just how much you have learned and how far you have come :)

    This has nothing to do with snobbery and everything to do with experience. Some of these issues cause real problems that affect real people and real businesses. If the purpose of software was simply to "work and do what it's supposed to do", then it would not be software, it would be hardware. The soft part of software means something that can be easily changed. A fundamental goal of software is the capability of adapting to changing requirements and to deliver value faster than hardware can. If you are writing code that is hard to change, you are writing hardware, not software. Best practices exist to help people write better software. Just because you can't fathom the value of good software doesn't mean it has none. Writing good, reliable, readable, maintainable, flexible software - it turns out - actually requires a great deal of skill, insight, and experience.

    But perhaps you're right. Maybe I should call up the NBA and tell them that I'm ready to join a pro team. I have thrown a baseball into a hoop before. That's how you score points and win games, right? None of that other stuff like agility and precision matters. As long as I can throw a ball into a hoop.
    • Agree Agree x 1
    • Winner Winner x 1
  10. We just have different definitions for good software. Good software for me just means that the code works and does what it's supposed to do, and better would be if it did the task faster. I can guess you've never done any scientific computing.

    I am also no stranger to the allure of elegance, clarity and simplicity. If you can write a proof of A with all these things then great! If you can't, but your proof is still valid, then also great! You have successfully found ⊢A either way.

    Also, your analogy sucks. Obviously, you need to throw basketballs (not baseballs) into hoops. If you can throw a basketball into a hoop every time without fail, but you have to stand still at your end of the court, then you would definitely be considered one of the best players. However, you can never prove you can do as such (since scientific knowledge is acquired empirically), and we require evidence for this and statistical methods to analyze the results. Computer Science on the other hand, is a child of mathematics, hence knowledge is acquired a priori. In other words, if ⊢A in the formal system on which the study is based, then there is a proof for A in terms of validity and computability.
  11. In most cases, software isn't made to prove something. It is run on a runtime environment and is performing different tasks, handling requests etc. The faster you perform each action, the more actions you can perform in a certain range of time, which is extremely important when only a single thread is used (but not only in that case), for example in MC-Server.
    Moreover, badly written code is hard to maintain and add features to, which, again, is not that important when you have to scientifically prove something, (only once), however, is very important when you develop software that runs on a runtime, bascially, non-stop.
    • Like Like x 1
  12. Computer Science and Software Engineering are two different things. This thread is clearly more concerned about software engineering, since we're talking about writing (and maintaining) actual code. Software undergoes a lot of changes, so it makes sense to follow conventions to ensure that your code becomes less error prone and more easily readable (among other possible advantages). Computer Science is a scientific field that is mostly concerned with the theoretical side of computers. In this case a correct proof of something doesn't need to undergo (a large amount of) changes, since the proof is already correct. For computer science, the conventions applied within software engineering indeed don't make much sense, since your proof doesn't have the issues these principles were designed to overcome.
    • Winner Winner x 1
  13. drives_a_ford

    Junior Mod

    He might not have, but I certainly have.
    And while I know for a fact that most of that code is pretty much pure garbage when it comes to code quality, that doesn't mean that I haven't found myself wondering why I've not made the thing better maintainable.

    In my work, I've been working on a numerical method based on Haar wavelets. We've developed an improved version for the base method. This was obviously done in a mathematical sense before it was implemented in code.
    Now, in order to show that the method is an improvement, we tend to do some case studies by numerically solving a number of differential equations (ODEs, PDEs, linear, nonlinear) or eigenvalue problems and comparing the results to the base model and/or exact solution (for validity).
    However, since the code I've written for the task at hand (i.e for the very first case study) is of pretty awful quality, I've had to rewrite the thing over and over again.
    Of course, having been working on this for a couple of years now, I've developed a core that provides most of the functionality and which means I don't have to rewrite most of it anymore, but it was quite a hassle when I started off. Rewriting things can (and does!) create issues (i.e leaving the wrong initial or boundary conditions).

    My point is, even the scientific community would benefit from better coding standards. I know so from first hand experiences.

    I know my code quality when it comes to scientific work is poor. I wish it wasn't, but it is. So I suppose I'm saying "do as I say, not as I do".
    • Winner Winner x 2
  14. It's fine to say that you are content with software that does what you want it to do, but that doesn't mean it's "good software". It means it does what you want it to do right now, and that might be fine. I've done plenty of "scientific computing" in my time at uni, but none of what I accomplished then is even remotely close to software development. That's like saying the bird house you made in woodshop at school is reasonably comparable to the work of a carpenter. Computer science is not software development.

    EDIT: I don't mean to insinuate that scientific computing is "child's play" in any way. But code is written, read, evaluated, manipulated, and handled in wildly different ways, and software developers arguably need a lot more discipline in terms of their code than data scientists do to be effective at what they do.

    The wonderful thing about academia is that your results are all that matters. Your code almost never does, but when it does, it doesn't matter for your immediate work. It does, however, make for a great grad student project for someone who can meticulously wade through your oh-so-sophisticated specification to arrive at the fact that the theory is great and all, but it's not that great in practice.

    That's not to say academia is useless, but code written in academia is usually a one-off affair. It's hardly comparable to the field of software development, where software lives for weeks, months, years, decades, and goes through endless modifications in order to adapt to emerging and changing requirements. There is just absolutely no comparison.

    It bears repeating that computer science is not software development. Proof systems are great, but they are arguably useless for anything outside of academia. Don't get me wrong, I absolutely loved spending 3 weeks in Coq proving that 2x2 matrices can calculate Fibonacci numbers, but no one in their right mind would do something like that in software development. There's a relevant article about a guy who sat down and spent 4 months proving the correctness of 80 lines of assembly, and by the time he was done no one cared because it had already changed and thus his proof was irrelevant. I'm also gonna throw Rice's theorem at you to remind you that academia acknowledges how borderline useless the complete purity is.

    I'm glad you caught that about the baseballs, but I'm disappointed that you think it was a mistake. My point is that with an obviously limited knowledge of basketball, I still understand that "ball in hoop for the win". This doesn't make me a good basketball player, nor does my hypothetical 99.9% accuracy, simply because basketball is about more than just shooting for the hoop. Considering you're completely ignoring all the other aspects of basketball as if they don't matter, I'd say my analogy is actually pretty good, because you're doing the same about software development.
    #75 garbagemule, May 25, 2020
    Last edited: May 25, 2020
    • Winner Winner x 2
  15. Hey, I’m making a minigane plug-in, and I’ve been main class as a holder of all my different running games(worlds) and am also using static fairly often in UTIL classes... I don’t really care about premium resources, but I was just wondering if this seems like really bad java right off the bat...

    Btw when I was learning I did most of the java tutorials, and had a very experienced friend helping me s as long the way
  16. - You should replace your util classes by a more OO approach. Check about the decorator pattern ;)
    - You can use dependency injection instead of static. In my projects, I only use static for constants or for passing same instance trought multiple plugins. You can also try Scala as it doesn't have static keyword but only the object type. I think it can help you to code better, even for Java.
  17. To add onto the above reply, you're probably better of delegating your running games to a different class, something like a GameManager for example. That one can then keep track of your different running games and you can then use that one to retrieve different games (e.g. getting a game by an ID, by the player that's playing in that game, getting all running games, etc.).

    Using static in utility classes isn't necessarily bad, you just have to be wary that you're not substituting OO design for utility classes. In general, if a utility method doesn't belong to a specific class, then it's really a utility method. If it belongs to a specific class then you should put it in that class instead of turning it into a utility method. Determining whether a utility method belongs to a class or not can be pretty tricky, but as a starting point, you can take a look at the different parameters for a utility method. Check the parameters and wonder if the method shouldn't be part of that parameter's class instead. For example, take the following utility method:
    Code (Java):
    public class Game {
        //stuff related to a single running game

    //this in a utility class
    public static void joinGame(Game game, Player player) {
        //make the player join the game
    Notice the two parameters in the utility method: one is a Game and one is a Player. The Player is from Bukkit, you can't easily change anything about that, so you can ignore that one. This leaves us with one parameter Game. Would it be better if we moved this method into the Game class? In this case that would be a great place to put the method in. If we do that, then we end up with something like this:
    Code (Java):
    public class Game {
        //stuf related to a single game

        public void join(Player player) {
            //let the player join this game
    Now you can do game.join(player) instead of UtilityClass.joinGame(game, player). As a side note, look at how the method changes. First we remove the static keyword - while appropriate for utility methods, this is no longer a utility method and acts upon the instance of the class, which means that static is no longer appropriate. Secondly the Game parameter has been removed, since the game is now determined by the instance you call this method on - if you call it on game1 the player will join game1, if you call it on game2 the player will join game2. Lastly the name of the method was changed from joinGame to simply join, since the method is inside the Game class it's already clear that this is about joining a game and not something else (if we kept the same name, we would be doing game.joinGame(player) in which we specify "game" twice, generally this isn't super necessary and generally just bloats your code).

    So this conversion works, but there are of course also utility methods for which this doesn't work. Take for example a utility method as follows:
    Code (Java):
    public static String removeSpaces(String string) {
        //removes whitespaces from the string
    If we check the parameters again like we did the first time around, we notice that we only have String. This class is from Java itself and we can't change it, which leaves us with no other parameters left. In this case, this is a true utility method and doesn't need to be turned into a 'normal' method. (For languages with extension methods, you can of course turn this into an extension method on the String class.)

    While this procedure doesn't necessarily always give the intended effect, it's a good first step in seeing if something should be a utility method and if it shouldn't be one, where it should be put instead.
  18. Hey, thanks for the suggestions! I am basically doing what your talking about with a game manager, and it’s pretty OO, if you wanted to look at the GitHub project that would be cool!