Pull to refresh
34
0.2
Валерий Вырва @valery1707

Java backend

Send message

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

Обязательно упомянуть, что это лучшее решение с его точки зрения.

Наиболее производительное на данный момент. Более чем в два раза чем "простой" и вариант@igolikov.

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

Производительность почти всегда важна, но не в ущерб читаемости и поддерживаемости.
Ваше же решение получилось хоть и производительным, но, на мой взгляд, практически не поддерживаемым - любое минимальное изменение параметров из задания будет требовать картинальной переработки всего кода.
И чаще всего такой write only код на проекте, в действительности, не нужен.

Нету их ? Странно, что это за фирма такая...

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

Только вот результат получаем разный, на несколько порядков.

Как и их стоимость. Особенно с учётом этой ветки.

Впрочем, VPS за пару баксов/мес. справится с туннелированием.

А вот и велосипеды подъехали.

Что вы на нём собирать будете, и как долго? Как быстро упрётесь в ООМ?

Ну мало у кого занят сборочный сервер в режиме 24/7. Да и сам проект часто не требует много RAM для сборки. Причём в рамках рассмотренного решения никто не мешает заупскать сервер с большим количеством RAM, CPU и GPU - и это всё ещё будет иметь ценник подъёмный даже одиночному разработчику.

И только не надо рассказывать как надёжны облака. Например, чем они рискуют, случайно уничтожив все ваши данные? Дадут $5 скидку на следующий заказ?

И разве своё железо надёжнее "само по себе"? Сдохнет диск - кто-нибудь даст "хотя бы" скидку? Вынесут через окно? Уборщица "протрёт"? Тем более если брать б/у - оно может умереть даже без помощи извне.
Возникают вопросы дублирования, бэкапов, активной поддержки.

Естественно я понимаю что "облака" это просто "чужие сервера", но в них входит не "просто железо", а так же его поддержка, сопровождение, замена, обновление (включая софт) а так же возможность гибко управлять выделяемыми ресурсами (RAM, CPU, HDD/SSD, GPU).

Вопрос переезда на bare-metal нужно решать тогда когда он реально себя проявляет, а не на начальном этапе организации компании - в этот момент ещё нет ни понимания требований к железу ни, собствено, средств которые можно "заморозить" в железе.
Естественно крупная фирма существующая продолжительное время и имеющая план на ближашие несколько лет скорее всего получит профит от перехода на bare metal и self-hosted ПО.

Напомню что статья рассказывает про решение для "создания публикаций в социальных сетях", используемом в неком "профсоюзе".
И они получили требуемый им функционал за ~250 р./мес. что в год будет около 3к руб. Плюс время на ресёч и реализацию.
Вы же предлагаете им сразу использовать bare metal за 100к, причём б/у, без дублирования, гарантий, поддержки, с необходимостью оплачивать Интернет и электричество для него, плюс сервер для реализации точки доступа в его сеть, плюс место для организации "серверной", плюс администрирование всего этого "счастья".
И всё это - в ультимативной форме.
Да, bare metal будет производительнее, но будет ли такое решение лучше удовлетворять изначальным требованиям?

Да, именно - внешний доступ в сеть с таким сервером тоже нужно будет как-то обеспечивать, так же как и максимальный аптайм электричества и интернета вкупе с фиксированным IP для точки входа (или через dyn-dns привязывать его к домену) что превращается в кучу головняка с велосипедами, которые в итоге становятся не проще и не дешевле решения "с облаком".

Сервер в "локальной сети" удобен, когда все разработчики тоже находятся в этой "локальной сети".

Мой вариант решал конкретную задачу.

Исходная постановка звучит примерно так: Решите задачу X с помощью опрятного и поддерживаемого кода. По результирующему коду будет оцениваться то как будет писаться код для боевых задач.

Решая конкретную задачу, разумно использовать знания об этой задаче.

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

  1. А причём тут "методы работы со String"? Вычисление "суммы цифр" числа через преобразование числа в строку и получение потока символов используется только у вас и у @DenisPantushev тогда как есть более "алгоритмический" вариант без, так сказать "зубрения".

  2. Из-за проверки String.valueOf(i).length() > 1 ваш код упускает часть корректных значений.

  3. Вместо String.valueOf(i).chars().mapToObj(c -> Integer.valueOf(""+(char)c)).reduce(0, Integer::sum) можно использовать гораздо более короткий, понятный и эффективный вариант: String.valueOf(i).chars().map(Character::getNumericValue).sum().

  4. А зачем IntStream боксируется в Stream<Integer>?

Всё это у вас бы спросили на собесе.

Я накидал бенчмарк по вариантам предложенным в комментариях (плюс мои) и получил вот такие данные:

| Benchmark | Mode  | Cnt | Score ± Error        | Units | vs `naive` | vs `simple` |
|-----------|-------|-----|----------------------|-------|------------|-------------|
| naive     | thrpt | 10  | 53348,090 ± 4429,824 | ops/s | -------    | -27.110%    |
| simple    | thrpt | 10  | 73190,139 ± 5990,700 | ops/s | +37.19%    | -------     |
| pin2t     | thrpt | 10  | 77951,880 ± 6964,085 | ops/s | +46.12%    | +06.51%     |
| igolikov  | thrpt | 10  | 79527,875 ± 5324,465 | ops/s | +49.07%    | +08.66%     |
| rombell   | thrpt | 10  | 83608,345 ± 3828,489 | ops/s | +56.72%    | +14.23%     |

Что интерпретировать можно так:

  • ваш, @rombell, вариант самый быстрый, но корректно работает строго в диапазоне до 1000 (так как проверяет только 3 знака) и при сумме цифр именно 10

  • потом идёт вариант от @igolikov, за счёт отсутствия проверки делимости на 3 и внесения проверки лимита суммы цифр в цикл подсчёта этой суммы

  • потом идёт вариант от @pin2t, за счёт проверки суммы только трёх знаков (из-за чего и работает корректно только на диапазоне до 1000)

  • и потом мой вариант

Плюс 14% это весьма хороший показатель.
А вот с учётом поддерживаемости, расширяемости и тестируемости побеждает вариант от @igolikov - он и работает на любых диапазонах и делает это довольно быстро (ваш быстрее всего на 5%) и доступен для понимания.

Вариант с i+3 уже предложили.
А по остальным предложениям: напишите код, а не мысли вслух - давайте рассмотрим.

Вы придумали несуществующие требования

Выдержка из постановки к задаче 1:

Работодателю здесь важно понять, как соискатель владеет основами синтаксиса языка и может ли писать код сразу чисто.
С помощью задач такого типа мы проверяем уровень соискателя: как много он писал код сам, а также косвенно — сталкивался ли с «грязным» кодом и рефакторил ли его. По такому заданию можно косвенно увидеть, как быстро и «чисто» (понятно и поддерживаемо) специалист будет писать собственный код.

Из этого следует что код должен быть достаточно "опрятным" и "поддерживаемым".
Да, Sonar тут не будет прогоняться и код, действительно, будет "выброшен", но именно по этому коду идёт оценка того что кандидат будет "творить" в дальнейшем - можно писать "лишь бы работало", но это явно не покажет кандидата с лучшей стороны.

Да и вы сами пишете:

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

, хотя проверка суммы цифр явно таковой не является даже в текущем варианте (суммирующем всего 3 позиции) и только ухудшится при изменении условий (что часто происходит с таким кодом на собесах - типа "а что будет если диапазон будет не до 1000, а до 20000?" - см. упоминание рефакторинга).

Решение работает для конкретного заданного случая и заданного диапазона, естественно не является универсальным

Вычисление суммы цифр легко превращается в функцию, которая

  1. работает для любых значений

  2. повышает читаемость и поддерживаемость

  3. не снижает производительности

  4. повышает тестируемость и модульность

Если в БД существует нормальный FK, то в e.department_id не будет ерунды, в том числе нуля и других значений которых нет в таблице department.
Если же FK нет (что как раз и позволяет хранить в e.department_id значения навроде 0) тогда JOIN будет верятно всё же более адекватным вариантом чем проверки на уровне записей.

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

P.S.
И это тоже обсуждалось.

  1. Проверка e.id not in (select id from department) не просто "сомнительна" она в принципе не корректна, так как select id from department выберет идентификаторы департаментов, тогда как e.id это идентификаторы сотрудников и они не связаны между собой и в том числе могут и пересекаться

  2. В комментариях уже предложили решение: e.department_id is null. Правда оно рассчитано на то что структура БД корректна и e.department_id имеет FK на таблицу department

Данное решение

  • в дальнейшем нужно будет поддерживать

  • Sonar всё равно возмутится хардкоду значений в коде - и нужно будет выносить константы

  • развёрнутое вычисление суммы цифр это быстро, но работает только для 1000 - если максимум увеличится в размере всего на пару цифр, то развёрнутая формула вычисления суммы станет совсем не читаемой

  • 1000 не делится на 3 и должно отсутствовать в выводе, а оно присутствует

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

Спасибо за вопрос (жаль только я увидел его только сейчас, хотя он задан был ещё в день публикации).
При создании строк в Java можно указывать значения сиволов юникода:

"\u0020".isBlank(); // пробел ~> true
"\u00A0".isBlank(); // неразрывный пробел ~> false

P.S.
На Kotlin код, выглядящий точно также, в обоих случаях будет возвращать true так как там вызывается кастомный CharSequence::isBlank, вызывающий кастомный Char::isWhitespace, добавлящий проверку на все пробельные символы.

Вопрос 6. Почему для var всегда нужен инициализатор в правой части?
Тип переменной вычисляется на основе инициализатора.
Это означает, что var можно использовать только при наличии инициализатора.

Начиная с Java 11 (вышла 4 года назад) ключевое слово var можно использовать и не только при наличии инициализатора, а например и у аргументов в лямбдах:

Function<String, String> append = (@NotNull var string) -> string + " ";

токсичная аудитория с "силой" продолжит минусовать старые комменты и карму даже спустя года

Так ведь же за комменты старее месяца голосовать уже нельзя - какие тут "года"?
На карму это не распространяется, конечно.

Например, в одной и тем четко и ясно разъяснил свою позицию для автора, заминусовали ...

Я не минусовал там и не минусовал тут, но поддерживаю желание поставить минус и по этому хотел бы раскрыть свою причину этого желания.
В комментарии "там" я не вижу "чёткого и ясного разъяснения позиции" я вижу только вот это:

Это не тоже самое и X. Повторю общеизвестную информацию. Тут был хак "на маршруте пула" и мы решили что это не честно. Я повторяю что "это не тоже самое что и X или Y". Управляющие _ решили так как решили.

Я вот не вижу тут ни "чёткости" ни "разъяснения" - просто "мы решили как решили и чужое мнение нас не волнует". И за что мне плюсовать этот коммент?

И ровно таже ситуация в текущем комменте: вы пришли, показали "совершенно корректно заминусованный с моей точки зрения коммент" считая при этом что вас "не заслуженно минусуют" и уже этот коммент опять заминусовали. А за что его плюсовать?
Я вот не вижу тут конструктивного начала, а вижу только "я хороший, а все плохие, и из-за них я тут завожу новые аккаунты".

И ещё приходит @myhambr и называет всех "токсиками, затыкающими рот". И тоже получает минусы.

P.S.
Посмотрю сбудутся ли прогнозы @Moskus относительно диалога с вами.

В первом сезоне юмор был как-то по-лучше

Запросить пачку из нескольких десятков ключей, проверить парочку, а остальные продать.

Information

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