Skip to content

mushanov | projectPantera#19

Open
mushanov wants to merge 1 commit into
demologin:mainfrom
mushanov:ushanov
Open

mushanov | projectPantera#19
mushanov wants to merge 1 commit into
demologin:mainfrom
mushanov:ushanov

Conversation

@mushanov
Copy link
Copy Markdown

No description provided.

Copy link
Copy Markdown
Owner

@demologin demologin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Общий вывод по проекту

Проект демонстрирует хорошее понимание архитектурных паттернов, таких как Front Controller и Command. Структура кода логична, а разделение на слои (entity, repository, service, controller) выполнено в соответствии с лучшими практиками. Однако стоит обратить внимание на потокобезопасность коллекций в многопоточной среде сервлетов и избегать «магических» чисел в тестах.

Разработчик следует принципам SOLID, использует современные возможности Java 21, организует код чистым образом.

Рекомендации:

  • Продолжить углубление знаний по паттернам проектирования
  • Изучить асинхронное программирование более глубоко
  • Уделить внимание документированию кода

Итоговая оценка: A

*/
@Getter
@Setter
public class GameSession {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Класс GameSession является изменяемым (mutable). Для хранения состояния сессии в многопоточной среде сервлетов следует обеспечить потокобезопасность или использовать неизменяемые структуры данных. [WARNING]

public class QuestRepository {

/** Все шаги квеста: ключ — id шага, значение — объект QuestStep */
private final Map<Integer, QuestStep> steps = new HashMap<>();
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Использование HashMap в многопоточной среде без внешней синхронизации может привести к неопределенному поведению. Рекомендуется заменить на ConcurrentHashMap. [ERROR]

* -> "Взять всех" => [8] WIN
* -> "Взять только капитана" => [9] LOSE
*/
private void initQuest() {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Метод initQuest() перегружен жестко закодированными данными. Рекомендуется вынести конфигурацию квеста во внешние файлы (JSON/YAML) для соблюдения принципа единственной ответственности. [WARNING]

* Получить шаг по id.
*/
public Optional<QuestStep> findById(int id) {
return Optional.ofNullable(steps.get(id));
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Метод findById возвращает Optional, что хорошо, но вызывающий код в тестах часто использует .orElseThrow() без аргументов, что может скрыть причину ошибки. [INFO]


private static final Logger log = LoggerFactory.getLogger(SessionService.class);

public static final String SESSION_KEY = "gameSession";
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ключ сессии 'gameSession' лучше вынести в общую константу или конфигурацию, чтобы избежать магических строк в разных частях приложения. [INFO]

Optional<QuestStep> optional = questRepository.findById(i);
if (optional.isPresent()) {
QuestStep step = optional.get();
if (step.isCompleted()) {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В цикле используется проверка 'step.isCompleted()', но сам тест называется finalStepsShouldHaveNoOptions. Проверка должна быть более явной относительно статусов WIN/LOSE. [INFO]


public int getNextStepId(int currentStepId, String chosenOption) {
QuestStep currentStep = getStep(currentStepId);
Integer nextStepId = currentStep.getOptions().get(chosenOption);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Возможен NullPointerException, если currentStep.getOptions() вернет null. Хотя Builder гарантирует инициализацию, явная проверка добавит надежности. [WARNING]

/**
* Кастомное исключение — бросается когда шаг квеста не найден.
*/
public class QuestStepNotFoundException extends RuntimeException {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Исключение является RuntimeException, что корректно. Однако стоит добавить serialVersionUID для соблюдения стандартов сериализации Java объектов. [INFO]

GameSession gameSession = sessionService.getSession(request.getSession());

// Если сессии нет — игрок не начинал игру, отправляем на старт
if (gameSession == null) {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Если сессия отсутствует, происходит редирект на '/'. Стоит убедиться, что StartPageCommand корректно обрабатывает такие случаи без бесконечных циклов. [INFO]


@BeforeEach
void setUp() {
questRepository = new QuestRepository();
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Инициализация репозитория в каждом тесте — это правильно для изоляции. Однако сам репозиторий заполняется данными в конструкторе, что замедляет тесты. [INFO]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants