Pull to refresh
44
0.1
Валерий Вырва @valery1707

Java backend

Send message

Да, верно в этом случае default можно не указывать - я забыл об этом при копировании примеров из статьи.

Эта статья сосредоточена на аспекте тестирования в CI/CD ...

Только всё описано на столько общими словами что статья фактически ничего не описывает вообще.

Потому что favicon принято размещать по тому же URL, где лежит index.html. Поэтому ссылкой на эту картинку будет url ссылки (его доменная часть) с добавлением ‘/favicon.ico’.

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

На сайтах в разделе Сертификаты обычно есть письма от Макиты с именным подтверждением. месяц назад купил так перфоратор.

А как проверить что эти письма на каком-то левом сайте действительно от Макиты, а не подделка?

Я так понимаю что наличие информации о всех наследниках в родителе это не побочная проблема, а одна из целей функционала.
А ещё такая зависимость есть в enum-ах, причём даже более жёсткая: родительский класс не только знает все его реализации, но они ещё и объявлены должны быть строго в пределах родительского класса.
Тогда как наследники sealed-класса могут быть объявлены где угодно (но в пределах видимости родительского - так как в нём необходимо указать потомка). Ну и с учётом возможности дать возможность расширять иерархию классов через non-sealed потомка это вообще не выглядит не преодолимой проблемой.
Другое дело что не все классы имеет смысл объявлять sealed.

Интересно что структура sealed классов не обязана быть полностью закрытой так как один из разрешённых вариантов может иметь модификатор non-sealed и от него можно будет наследоваться.
Может быть полезным для библиотек и прочих мест где нужно всё же дать возможность неконтролируемо расширять иерархию классов.

public sealed interface Demo permits Demo.Sealed1, Demo.Sealed2, Demo.Open {
    // Эти классы входят в закрытую часть структуры
    final class Sealed1 implements Demo {}
    final class Sealed2 implements Demo {}
    non-sealed class Open implements Demo {}

    // Это пример структуры, которая уже не контролируется ограничениями по `sealed`
    class External extends Open {}
}

Многослойные Docker-образы умеет генерировать GoogleContainerTools/jib:

  1. Внешние релизные зависимости.

  2. Снапшотные зависимости.

  3. Модули внутри проекта.

  4. Ресурсы собираемого модуля.

  5. Классы собираемого модуля.

  6. Дополнительные настроенные директории.

В результате основной объём оседает в первом слое внешних завимостейи меняется очень редко, чаще меняется слой внутренних модулей и слои с содержимым собираемого модуля.
Причём jib подключается и Maven и к Gradle проектам буквально в пару кликов.

Да, Lombok это часто удобно, но реализовать UIState удобнее на рекордах:

public sealed interface UIState permits UIState.Loading, UIState.Error, UIState.Idle, UIState.Success {
    record Loading(boolean isLoading) implements UIState {}
    record Error(String message) implements UIState {}
    record Success(Object data) implements UIState {}
    enum Idle implements UIState {INSTANCE}
}

и вот пример работы с ним:

public void processUIState(UIState uiState) {
    switch (uiState) {
        case UIState.Loading loading -> System.out.println("loading: " + loading.isLoading());
        case UIState.Error error -> System.out.println("error: " + error.message());
        case UIState.Success success -> System.out.println("success: " + success.data());
        case UIState.Idle __ -> System.out.println("idle");
        default -> throw new IllegalStateException("Unexpected value: " + uiState);
    }
}

Даже с типизированным Maybe фактически нет проблем, причём за счёт использования enum создать ещё один инстанс Nothing даже через рефлексию будет проблематично.

public sealed interface Maybe<T> permits Maybe.Just, Maybe.Nothing {

    @Nonnull
    @SuppressWarnings("unchecked")
    static <T> Maybe<T> maybe(@Nullable T value) {
        return value == null ? (Maybe<T>) Nothing.INSTANCE : new Just<>(value);
    }

    record Just<T>(T value) implements Maybe<T> {}
    enum Nothing implements Maybe<Object> {INSTANCE}

}

Я может что-то не понимаю, но как эта новость связана с хабами $mol, *nix, .NET, и 1С-Битрикс?
@moderator

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

В Java 17 можно и так:

public Double convert(Object value) {
    if (null == value) {
        return null;
    } else if (value instanceof Double v) {
        return v;
    } else if (value instanceof String v) {
        return (v.trim().isEmpty()) ? null : Double.parseDouble(v);
    } else if (value instanceof Number v) {
        return v.doubleValue();
    }
    throw new AdvImportException("Can't convert value " + value + " to double");
}

А вариант Java 21 просто делает код более выразительным выделяя паттерны из кучи if в один switch:

public Double convert(Object value) {
    return switch (value) {
        case null -> null;
        case Double v -> v;
        case String v -> v.trim().isBlank() ? null : Double.parseDouble(v);
        case Number v -> v.doubleValue();
        default -> throw new IllegalArgumentException("Can't convert value" + value + " to double");
    };
}

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

Сейчас и у Wildberries есть аналогичная скидка для "кошелька WB"

А не рассматривали вынести логику из консюмера и продюсера в сервисы не завязанные на Kafka в принципе?
Чтобы тестировать логику в отрыве от транспорта:

  • Метод в консюмере просто транслирует полученный объект в сервис - однострочник консюмера можно не тестировать вовсе, а тестируемый сервис не зависит от кафки и на вход просто принимает объекты

  • От множества продюсеров можно отказаться вовсе, заменив их универсальным, который на вход принимает отправляемый объект и возможно имя очереди, а там где раньше шла прямая отправка инжектить такой сервис , который в тестах будет мокаться.

В результате тестируется именно бизнес-логика, а не завязки на транспорт, поднимать ничего не нужно, выключать ничего не нужно.
Сплошные плюсы.

Пример кода

То есть вместо ```java @Slf4j @Service @RequiredArgsConstructor public class UserConsumer {

private final UserService userService;
private final NotUserService notUserService;
private final UserHandler userHandler;
private final UserMapper userMapper;
private final List<String> userCodes;

@KafkaListener(groupId = "userConsumerGroupId",
        clientIdPrefix = "UserConsumer",
        topics = {"user-topic"},
        containerFactory = "kafkaListenerContainerFactory")
public void consume(UserInfoRecord userInfoRecord) {
    log.info("Тут разнообразная логика обработки");
    log.info("Cохранение в бд?");
    log.info("Работа с внешними сервисами?");
    log.info("Вызов мапперов?");
    log.info("Отправка информации в Kafka?");
}

}

@Slf4j
@Service
@RequiredArgsConstructor
public class UserProducer {

private final UserService userService;
/** Если у нас какой-то персистинг сообщений перед отправкой или обработка ошибок отправки */
private final KafkaMessageService kafkaMessageService;
/** Если мы просто отправляем - используем KafkaProducer, например, у нас по бОльшей части используетс AVRO */
private final KafkaProducer<String, SpecificRecordBase> kafkaProducer;
/** Но есть места, где используется JSON вместо AVRO */
private final KafkaProducer<String, String> kafkaJsonProducer;
private final ApplicationProperties applicationProperties;

public void sendUserInfoMessage(User user, Set<Integer> managerIds) {
  log.info("Тут логика отправки");
  log.info("Обычно сначала идет сборка модели для отправки.")
  log.info("Но может быть и какая-то более сложная логика.");
  var record = UserInfoRecord.newBuilder().build();
  log.info("Тут может быть как непосредственно отправка в Kafka");
  log.info("Так и реализация outbox-паттерна.");
  kafkaMessageService.persistMessageToSend(applicationProperties.userTopic(), record);
}

}

сделать так:
```java
@Slf4j
@Service
@RequiredArgsConstructor
public class UserConsumer {

    private final UserConsumerService service;

    @KafkaListener(groupId = "userConsumerGroupId",
            clientIdPrefix = "UserConsumer",
            topics = {"user-topic"},
            containerFactory = "kafkaListenerContainerFactory")
    public void consume(UserInfoRecord userInfoRecord) {
	    service.consume(userInfoRecord);
    }
}

@Slf4j
@Service
@RequiredArgsConstructor
public class UserConsumerService {
    private final UserService userService;
    private final NotUserService notUserService;
    private final UserHandler userHandler;
    private final UserMapper userMapper;
    private final List<String> userCodes;

    public void consume(UserInfoRecord userInfoRecord) {
        log.info("Тут разнообразная логика обработки");
        log.info("Cохранение в бд?");
        log.info("Работа с внешними сервисами?");
        log.info("Вызов мапперов?");
        log.info("Отправка информации в Kafka?");
    }
}

@Slf4j
@Service
@RequiredArgsConstructor
public class UserProducerService {

    private final KafkaSender sender;

    public void sendUserInfoMessage(User user, Set<Integer> managerIds) {
      log.info("Обычно сначала идет сборка модели для отправки.")
      log.info("Но может быть и какая-то более сложная логика.");
      var record = UserInfoRecord.newBuilder().build();
      sender.sendUserInfoMessage(record);
    }
}

@Slf4j
@Service
@RequiredArgsConstructor
public class KafkaSender {

    private final UserService userService;
    /** Если у нас какой-то персистинг сообщений перед отправкой или обработка ошибок отправки */
    private final KafkaMessageService kafkaMessageService;
    /** Если мы просто отправляем - используем KafkaProducer, например, у нас по бОльшей части используетс AVRO */
    private final KafkaProducer<String, SpecificRecordBase> kafkaProducer;
    /** Но есть места, где используется JSON вместо AVRO */
    private final KafkaProducer<String, String> kafkaJsonProducer;
    private final ApplicationProperties applicationProperties;

    public void sendUserInfoMessage(UserInfoRecord record) {
      log.info("Тут логика отправки");
      log.info("Тут может быть как непосредственно отправка в Kafka");
      log.info("Так и реализация outbox-паттерна.");
      kafkaMessageService.persistMessageToSend(applicationProperties.userTopic(), record);
    }
}

Странно что не упомянуто основное ограничение хеш-индексов: они могут помогать только в случае простых проверках на равенство.
То есть при поиске x = 500 он поможет, а при поиске x >= 500 уже нет.

и у них не было стандартов и документации?

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

Я пробовал смотреть прохождения, что просто на YouTube, что онлайн на стримах - постоянно ощущаю внутренее сопротивление вида "я бы сделал по другому" и очень быстро уровень расхода нервов становится сильно выше чем если бы играл сам.
Да, можно поискать игрока подходящего мне "по духу", но это же нужно искать, да и никто не гарантирует что он не убежут играть во что-то другое из-за того что там больше денег.

Я начал погружаться в компьютерные RPG с Might and Magic VI: The Mandate of Heaven (1998) и там был открытый мир - персонаж мог идти куда угодно и его ничего не останавливало.
Даже море было препятствием только первое время и только игро-механически - персонаж банально тонул из-за чего терял HP и мог умереть, но потом получал "хождение по воде" или "полёт" и море уже не было проблемой.
В разных областях монстры были разной сложности - не справляешься в прямом столкновении - можно пробовать стелсом, можно набегами, можно отвлекать на себя по несколько противников, а если противник один, но сильный, то переход в пошаговый режим позволял выполнить больше шагов чем противник и этим нанести больше урона.
Да, можно было свернуть в сторону и раскачаться так что вернувшись оказаться "перекачанным", но это был мой выбор как игрока: я мог идти равномерно и получить равномерный рост сложности, и я же мог прыгнуть в область "не по рангу", пробежать там зайчиком получить кучку квестов и прочих зацепок на будущее, и вернуться в "плановое" место с лучшим шмотом или заклинаниями и банально уровнем, за счёт чего упростить собственную жизнь.
И это, на мой взгляд, нормально - да, где-то сложнее, а где-то проще.

Я из Казахстана (был, пока не переехал в РФ) и там вполне в ходу выражение "в СНГ"

Information

Rating
3,719-th
Location
Воронеж, Воронежская обл., Россия
Date of birth
Registered
Activity