Обновить
29

Пользователь

0,2
Рейтинг
2
Подписчики
Отправить сообщение

Да, немного по-другому названо просто.

Хороший комп за полторашку при нынешних ценах на оперативу и видяхи не соберёшь :).

Чтобы баланс сходился, нужно использовать специальное бухгалтерское округление. Но этим редко кто заморачивается.

В какой-то степени, так и случилось. :)

Деньги считают не только в банках.

Например, ситуация 15 летней давности. Сейчас, возможно, что-то изменилось. Сбытовая компания закупает на свободном рынке электроэнергию в МВт, а перепродаёт её потребителям уже в кВт. Так вот для потребителя тариф получался простым делением на 1000. Т.о. для потребителя тариф на электроэнергию по свободной цене был с точностью до 5 знаков.

СНИЛС говорят не меняется

Не меняется, но их может стать несколько. Да, это неправильно, и остаться должен только один, но важен сам факт: теоретически номер СНИЛСа может измениться.

Разрешите поинтересоваться в целях повышения образования. (ц)

А можно пример несуррогатного ключа, который на дистанции хотя бы в 10-20 лет 146% не изменится?

TL/DR Soft delete - хрень.

После появления встроенной функции uuidv7() в PostgreSQL не осталось ни одного разумного аргумента в пользу UUIDv4.

Есть такой аргумент. Функция появилась в последней версии слоника, а миграция, во-первых, не всегда возможна в принципе, во-вторых, не всегда возможна в адекватные сроки. В-третьих, работает - не трогай.

Т.ч. не всё так однозначно.

Предпочитайте мягкое удаление для критичных бизнес-данных

Я просто оставлю это здесь.

Возможно, вы правы.

буду закрывать этот "технический долг"

Действительно, зачем делать сразу нормально? А так можно ещё пару недель на рефакторинг списать. Код крутится, лавеха мутится.

свой фильтр дает больше прозрачности и гибкости

А зачем тогда нужен весь Spring Security?

TL/DR. Новички, не делайте так никогда. Автор, мягко говоря, некомпетентен в вопросах, о которых рассуждает.

class JwtConfig

@ConfigurationProperties.

Использование COALESCE в запросе позволяет нам безопасно проверять статус токена: если записи нет в базе - мы по умолчанию считаем такую сессию отозванной.

Вы бы, прежде, чем делать подобные заявления хоть попробовали запросы повыполнять в БД. COALESCE конкретно в данном запросе - ненужная хрень, т.к. поле nullable = false. Если записи, удовлетворяющей условию отбора нет, то будет возвращён пустой набор.

Как в этом случае поведёт себя spring-data-репозиторий, я, честно, не помню, но по JPA специфицикации getSingleResult() при отсутствующей записи бросит NoResultException. Spring-data, скорее всего, как-то обрабатывает этот момент, но вряд ли на пустом наборе он вернёт что-либо, отличающееся от значения по умолчанию для результирующего типа. В данном случае, boolean, а, стало быть, по умолчанию вернётся false, т.о. метод isTokenRevoked() вернёт абсолютно противоположное ожидаемому значение.

JwtAuthenticationFilter extends OncePerRequestFilter ... извлекает токен из заголовка Authorization и "представляется" системе Spring Security

Раз уж затащил этого ~монстра~ Spring Security, то, емнип, там уже всё "из коробки" готово для работы jwt, надо только законфигурить, без какого-либо написания своих компонентов вообще.

И начните уже писать тесты.

При переводе в заказа в CANCELLED в bank-service отправляется отмена платежа, а сервис уже смотрит провёл он его реально и надо ли отменять.

на стороне order-service процесс никогда не перейдёт ни в APPROVED, ни в CANCELLED

Чтобы это исправить достаточно раз в t1 с/м/ч/etc. запускать фоновую задачу, которая просто переводит все PENDING в CANCELLED, если со времени создания прошло t2. Лучше, чтобы t1 < t2.

Выбор localDateTime обусловлен тем, что на старте разработки важнее наглядность данных в БД

Как одно связано с другим? В БД тип колонки что для LocalDateTime, что для Instant будет одинаковым.

упрощение отладки логики, завязанной на локальное время.

У java.time.Instant вполне задокументированный человекочитаемый toString(). Т.ч. что в sout, что в лог, что просто под дебагером понять какая там именно дата можно без проблем.

Наличие конструкторов по умолчанию и сеттеров это необходимый компромисс

Это не компромисс, а вполне себе требование стандарта JPA. Который, кстати, хибер вполне себе допускает нарушать.

Проектирование это всегда баланс между академической чистотой и прагматизмом.

Как раз с точки зрения прогматизма equals() и hashCode() вообще не надо реализовывать, пока не упёрся в проблему, решить которую без реализации этих методов вообще не получается. У вас же буквально первая сущность UserEntity уже имеет натуральный идентификатор (unique = true) и вот как раз с точки зрения бизнес-логики равенство должно бы проверяться по этому значению.

ведет к оверинжинирингу

Это именно то, что мы наблюдаем на описываемом проекте. Берём простую задачу: найти NicknameOldEntity по идентификатору. Казалось бы, чего проще, и проблем быть не должно, но вместо тупейшего select * from nickname_old where id = ? у нас появится монстр с двумя join-ами на ровном месте.

Какая разработка высоконагруженной системы? Вам бы для начала "How to..." прочесть, посмотреть на аналогичные решения, доступные в сети, обдумать используемые там решения, а потом уже, если останется желание, можно и статью на Хабр написать, которая будет реально полезной.

AbstractEntityUuid#equals, AbstractEntityUuid#hashCode

Уж сколько раз эта тема обсасывалась со всех сторон. В том числе и на Хабре. Сущность мутабельна, согласно спецификации должна иметь конструктор по умолчанию, соответственно, её можно создать в неконсистентном состояннии. Её внутренней состояние может измениться в течение жизни.

Определять equals()/hashCode() в 145% случаев не требуется. А где требуется надо быть очень осторожным и завязывать реализацию этих методов только на идентификатор неправильно. А уж ваша реализация equals() вообще неправильная, т.к. не учитывает прокси.

private LocalDateTime createdAt;

Время создания - это точка на временной оси, какой-то конкретный момент, при чём тут локальное время? А если учесть, что это время меняется одним параметром запуска jvm, то это вообще полный звиздец. Для таких полей надо использовать java.time.Instant.

А куда делся главный?

Не будешь же ты всегда таскать калькулятор с собой. (ц) Учитель математики

А развести потоки никак? Это ж классика: клиент принимает данные и складывает их в буфер, а паралллельный поток этот буфер читает и что-то с прочитанным делает.

Информация

В рейтинге
3 599-й
Откуда
Омск, Омская обл., Россия
Зарегистрирован
Активность