Ошибки начинающих разработчиков майнкрафт плагинов и как их не допускать

Руководство Ошибки начинающих разработчиков майнкрафт плагинов и как их не допускать

*(и мне всё равно, что тут нет Markdown)*

# Мишань, всё херня, давай по-новой.

У статьи две проблемы: большой упор на производительность и очень неудачные примеры, которые реального новичка могут привести совсем не в ту сторону. По себе знаю, потому что программировать начинал именно с написания плагинов.

При этом советы из статьи не то, что бы плохие. Но подача очень хромает.

## 1. Некорректная работа с конфигурацией
### а) Код из примера не идентичен по функционалу
Переменная `message` из "правильного" кода будет взята единожды и переиспользоваться даже после выполнения перезагрузки конфига `plugin.reloadConfig()` - то есть игрок будет всё время видеть одно и то же сообщение. Если действительно хотим показать что-то правильное, нужно расширять скоуп. Что-нибудь вроде:
```java
public class MyClass {
private String message;

public MyClass(Plugin plugin) {
reload(plugin);
Bukkit.getScheduller().runTaskTimer(plugin, () -> {
Player player = Bukkit.getPlayer(nickname);
player.sendMessage(message);
}, 200L, 200L);
}

public void reload(Plugin plugin) {
this.message = plugin.getConfig().getString("message");
}
}
```
В следствии, при вызове `MyClass#reload` у нас наконец будет обновляться соответствующее сообщение.

Причём, далее есть примеры с переменными класса, но комментарии к ним дают совершенно другой контекст, внезапно заговаривая про рекорды. Будто бы тут больше подошёл поэтапный формат "проблема > решение > проблема решения > новое решение"

### б) Неэффективность преувеличена
Когда как для часто-вызываемых блоков кода рассказ про производительность имеет смысл, здесь его уже почти нет. Единоразовая перезагрузка конфига не может уронить ТПС сервера, если только происходит что-то совсем не так.

Тем не менее, использование секций - хорошая практика, и я бы заострил внимание именно на этом. Да даже просто из-за риска очепяток.

Единственный случай, когда здесь производительность может иметь какое-то значение - если какие-то данные активно подхватываются с конфигов. Какая-нибудь там валюта игрока. Однако даже в таком случае основной проблемой будет скорей работа с файловой системой (можно было бы плавно перейти к асинхрону), нежели какой-то просчёт хэша строк.

## 2. Страх перед локальными переменными/константами и прочим
Тут уже получше...
### Ситуация 1) ...но у новичка нет контекста, что должно быть константой
Например, есть потоко-зависимые классы, которые таковыми не кажутся. Пускай какой-нибудь `SimpleDateFormat` уже считается крайне устаревшим, но вот какой-нибудь `new DecimalFormat("#.##")` выглядит как хороший кандидат... а потом оказывается, что у него есть внутренний буфер, который может упороться при выполнении в потоках.

Также можно предположить, что при работе с SQL какой-нибудь `PreparedStatement` можно сохранить - ведь даже название на это будто намекает - но пойдёшь лесом на втором же прогоне.

Сложно придумать, как получше это всё уместить - возможно, просто написать популярные кейсы, и в остальном посоветовать обращаться к JavaDoc'ам и гуглить.

### Ситуация 2) ...но пример слишком конкретный
Как и в первом, рассматривается очень определённый кейс, из чего можно только подчеркнуть, что общие операция со строками следует делать сразу. По факту же, стоит расширить описание - мол, это касается всех подобных кейсов. Собственно, у таких значений даже название есть - инвариант цикла - т.е. то, что не меняется из итерации в итерацию. Тут же следует сделать оговорку про мутабельность:
```java
List<String> bestPeople = new ArrayList<>(getAdminNames());
for (Player player : Bukkit.getOnlinePlayers()) {
bestPeople.add(player.getName());
player.sendMessage("В список лучших людей на сервере входят: " + bestPeople); // С каждой итерацией будут добавляться новые игроки
}
```

## 3. Проблемы с коллекциями
Тоже неплохо...
### А) ...но стоит подправить пример
Тут чем-то похоже на проблему из самого первого пункта. Я *очень* часто видел, как люди создают новый `HashSet` прямо перед работой с ним. Следует помнить, что создание такого объекта, как `HashSet`, тоже небесплатно, и, по возможности, это следует делать заранее.
### Б) ...но стоит, по-моему, расширить
Хранение `Player` - далеко не единственная причина утечек. Одна из самых популярных у новичков - хранение мутабельных объектов в `HashSet` и в ключах `HashMap`. Коллекция запоминает старый хэш, а поиск/удаление идёт изменённому - объект становится недоступен, но остаётся в памяти. Такое часто видел с объектами типа `Location`.

Конечно, если всё делать аккуратно, как и в случае в `Player`, проблем можно избежать. Но лучше просто избегать таких ситуаций. Например, с локацией можно оформить свой рекорд:
```java
public record MyLocation(String world, int x, int y, int z) {
public MyLocation(Location loc) {
this(loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
}
}
```
### В) ...и всё
Могу лишь придраться, что для `ImmutableList`/`ImmutableSet` в ванильной джаве уже есть свои аналоги.

## 4. Асинхрон/конкурентность и что там должно и не должно быть
Очень странные примеры. Из них кажется, будто для работы с `ConcurrentHashMap` нужно обязательно работать в асинхроне - в реальности же, в однопоточном режиме производительность `CHM` сопоставима со стандартным `HashMap`. Лучше уж сделать по примеру про использование `HashMap` vs `CHM`, и по примеру для вызова долгих или тяжёлых операций, вроде обращения по сети, нормальная компутация, или работа с файловой системой.

## 5. Принцип DRY и ради бога - следуйте ему.
Ну тут правда. Хотелось бы только блоки логики побольше, чтоб реально показать разницу.

## 6. Мелкие придирки к бесящим вещам
Тут просто оставлю пару комментариев.
### А) Dependency Injection - круто
Единственное - про громоздкость можно поспорить. При правильной архитектуре и это решаемо, но это уже совсем другая история.
### Б) Хе-хе-хе, мой старый код
Наверно, один из лучших вариантов для баланса между производительностью и поддерживаемостью кода. Но примерно на том же уровне можно сделать всё и без регулярок, и одним методом.

# Моё заключение
1. Самое важное - нужны правки примеров (а ещё `getScheduler()` с одной `l`).
2. Некоторые темы плохо раскрыты.
3. Слишком большой упор на производительность - пишешь верно, но новичка так можно довести до того, что тот постоянно будет заниматься преждевременной ~~эяк~~оптимизацией.
4. Если реально заниматься оптимизацией - без тестов многое подтвердить просто невозможно, хорошо бы чего про проверки через JMH и spark тогда.
5. Как финальный совет, можно было бы попросить новичков забить на Spigot API и перейти на Paper API. Потихоньку оно будет становиться всё более несовместимым, а фич там намного больше.
отличная статья, для новичков - самое то. Единственный минус статьи - отсутствие котлина
Отличаня статья для новичков! Хоть я и сам знал все эти принципы, думаю, что тем кто только начал создавать плагины нужно выучить эти правила как молитву.
почему бы не 5 звезд, видно человек выделил время, постарался, респект
Мне понравилось, подробно и по фактам расписано все, для себя взял пару хороших привычек, будем привыкать XD. А так я думал все пишут так (правильно), а исходя из статьи странных кадров достаточно много :D
прикольно объяснил, пойду переписывать теперь свой rProfiles
Эммм нуууу крутооо пасибааа (надо 50 символов набрать просто), а если серьёзно, всё вполне качественно и хорошо написано.
я тоже тебе поставлю, че уж
(просто текст, чтобы набрать 50 символов)
Overwrite
Overwrite
легчайшая для величайшего
от величайшему равного
Хороший гайд для новичков в сфере разработки майнкрафт плагинов, таких гайдов сейчас мало)
Видно, автор постарался над данной статьёй и потратил больше количество времени, сил на его создание и оформление. Очень рад, что есть креативные люди на форуме. Да и плагины тоже интересные
Ну наконец то, нам начинающим вместо того чтоб критиковать объяснили! Спасибо вам дорогой Overwrite, от лица начинающих разработчиков говорю вам большое спасибо!
Топовая статья, как всегда, впрочем. Спасибо за такой полезный материал.
Имбуля, взял несколько идей на заметку. Надеюсь, русские разработчики хотя бы взглянут.
Наконец-то хоть кто-то поднял эту тему, ура! Жаль конечно что большинство "разработчиков" на неё даже не глянет, но расписано действительно очень классно
Overwrite
Overwrite
Давненько не был в эфире и все наверняка забыли, что только лишь Оверврайт остаётся на стиле!
Назад
Сверху Снизу