Часть 3. Критикал проблемы. 🧯
Критикал проблем тут несколько:
- Вызов транзакционного метода из метода внутри класса - это не сработает.
- Проблема потенциально большого количества пользователей на входе и их поштучное создание.
- Влияние сохранения одних пользователей на других: при ошибке сохранения одного не запишется весь пакет (откат всей транзакции).
- Вызов regionService поштучно для каждого пользователя - потенциально дорогая и неэффективная операция.
- Нет гарантии выполнения обновления region для каждого пользователя, а также сбой при обновлении повлияет на остальных.
Начинать обсуждение можно с любой из этих проблем, поскольку они так или иначе взаимосвязаны. Нужно предложить рефакторинг, который позволит их решить.
Глубина разбора этих проблем позволяет оценить реальный опыт. Далее обсудим варианты того, как это можно исправить. 💡
Критикал проблем тут несколько:
- Вызов транзакционного метода из метода внутри класса - это не сработает.
- Проблема потенциально большого количества пользователей на входе и их поштучное создание.
- Влияние сохранения одних пользователей на других: при ошибке сохранения одного не запишется весь пакет (откат всей транзакции).
- Вызов regionService поштучно для каждого пользователя - потенциально дорогая и неэффективная операция.
- Нет гарантии выполнения обновления region для каждого пользователя, а также сбой при обновлении повлияет на остальных.
Начинать обсуждение можно с любой из этих проблем, поскольку они так или иначе взаимосвязаны. Нужно предложить рефакторинг, который позволит их решить.
Глубина разбора этих проблем позволяет оценить реальный опыт. Далее обсудим варианты того, как это можно исправить. 💡
🔥2
Часть 4. Возможное Решение 🧠
Главный поинт в том, что не нужно решать ВСЕ проблемы, но нужно дать хорошую проработку хотя бы одной-двух.
Лучше акцентировать внимание на проблеме, которую ты сможешь лучше всего раскрыть.
Вопрос вызова транзакционного метода банальный, это отработает не так как ожидается, поскольку Spring использует прокси для реализации транзакций, можно предложить изменить структуру вызовов или self-injection для решения проблемы атомарного создания всего батча юзеров.
Но лучше пойти дальше и посмотреть на проблему производительности и надежности. На этом этапе можно дособрать требования по задаче. Есть ли потребность в батчевой обработке юзеров?
Если потребность есть - нужно копать в сторону батчевой вставки и конфигурировать hibernate. Если нагрузка очень большая - то подумать о том чтобы клеить всё в один INSERT (с отказом от hibernate здесь).
Если же нагрузка ожидается небольшая и равномерная - то в идеале нужно разделить обработку пользователей так, чтобы атомарно происходило сохранение юзера и обновление ссылки на регион (особенно если там под капотом rest интеграция). Здесь можно подумать об асинхронном способе обновления линка. Например через брокер сообщений и outbox.
При этом стоит добавить что код должен содержать обработку ошибок и логгер, который даст нам наблюдаемость и поможет разбирать ошибки. (ненавязчиво еще раз подчеркиваем свой опыт)
Обычно такой ответ уже удовлетворителен и на этом секция заканчивается.
С вами был Артем. Спасибо за внимание.
#Java #ревью #собеседование
Главный поинт в том, что не нужно решать ВСЕ проблемы, но нужно дать хорошую проработку хотя бы одной-двух.
Лучше акцентировать внимание на проблеме, которую ты сможешь лучше всего раскрыть.
Вопрос вызова транзакционного метода банальный, это отработает не так как ожидается, поскольку Spring использует прокси для реализации транзакций, можно предложить изменить структуру вызовов или self-injection для решения проблемы атомарного создания всего батча юзеров.
Но лучше пойти дальше и посмотреть на проблему производительности и надежности. На этом этапе можно дособрать требования по задаче. Есть ли потребность в батчевой обработке юзеров?
Если потребность есть - нужно копать в сторону батчевой вставки и конфигурировать hibernate. Если нагрузка очень большая - то подумать о том чтобы клеить всё в один INSERT (с отказом от hibernate здесь).
Если же нагрузка ожидается небольшая и равномерная - то в идеале нужно разделить обработку пользователей так, чтобы атомарно происходило сохранение юзера и обновление ссылки на регион (особенно если там под капотом rest интеграция). Здесь можно подумать об асинхронном способе обновления линка. Например через брокер сообщений и outbox.
При этом стоит добавить что код должен содержать обработку ошибок и логгер, который даст нам наблюдаемость и поможет разбирать ошибки. (ненавязчиво еще раз подчеркиваем свой опыт)
Обычно такой ответ уже удовлетворителен и на этом секция заканчивается.
С вами был Артем. Спасибо за внимание.
#Java #ревью #собеседование
🔥2
Предыдущая задача, которую разбирали, закрывает большую часть бинго. Но мне интересно было подобрать пример с if/else цепочками. Без спринга и прочего сахара.
На связи тот же "один зеленый банк", немного адаптированная задачка на рефакторинг.
Первым предложением будет конечно поменять if/else на switch. Но основную проблему это не решает.
Если посмотреть детальнее - то CodeProcessor начинает брать на себя ответственность сразу за обработку всех типов кодов. Это нарушает SRP (и здравый смысл).
Даже протестировать подобный код будет очень проблематично, поскольку велика вероятность высокой связности между ветками кода.
На связи тот же "один зеленый банк", немного адаптированная задачка на рефакторинг.
class CodeProcessor {
public void process(CodeType codeType) {
if (codeType == CodeType.ONE) {
sout("Handling ONE"); // и еще какая то сложная логика
} else if // череда else-if
...
else {
sout("Handling Default Case"); // тут тоже
}
}
}
enum CodeType {
ONE, TWO, THREE, OTHER
}
public class CodeProcessingApp {
public static void main(String[] args) {
var processor = new CodeProcessor();
processor.process(CodeType.ONE);
}
}Первым предложением будет конечно поменять if/else на switch. Но основную проблему это не решает.
Если посмотреть детальнее - то CodeProcessor начинает брать на себя ответственность сразу за обработку всех типов кодов. Это нарушает SRP (и здравый смысл).
Даже протестировать подобный код будет очень проблематично, поскольку велика вероятность высокой связности между ветками кода.
Обычно в такой ситуации стоит вспомнить отцов-основателей (банда четырех), и спросить себя, а что бы сделали они?
Одним из вариантов ответов будет полиморфизм. Процессор может продолжать обрабатывать коды, но детали реализации каждого типа должны быть инкапуслированы в собственные классы.
На мой взгляд, это можно упаковать в вариацию паттерна Стратегия, который позволяет выбирать алгоритмы на лету. В нашем случае, мы выбираем обработчик в зависимости от типа кода.
Хороший разбор паттернов очень простым языком можно найти вот тут:
https://refactoring.guru/ru/design-patterns/strategy
Ну а мы посмотрим на код:
Что мы здесь видим? Теперь CodeProcessor не знает ничего о деталях обработки каждого типа кода. Он просто делегирует эту работу соответствующему обработчику.
Это делает код модульным, тестируемым и расширяемым. При этом соблюдается принцип единственной ответственности, так как каждый класс отвечает только за свою часть логики.
И хотя такой вариант реализации конечно выглядит немного сложнее, но уже на 30 строчках кода обработчика такая организация начинает приносить свои плоды.
И намного красивее это начинает смотреться как только в проекте появляется DI контейнер, который может автоматически инжектить зависимости и регистрировать обработчики.
Фух, наконец-то паттерны пригодились. На этом всё, если есть вопросы - всегда можно задать их в личке или в комментариях.
Одним из вариантов ответов будет полиморфизм. Процессор может продолжать обрабатывать коды, но детали реализации каждого типа должны быть инкапуслированы в собственные классы.
На мой взгляд, это можно упаковать в вариацию паттерна Стратегия, который позволяет выбирать алгоритмы на лету. В нашем случае, мы выбираем обработчик в зависимости от типа кода.
Хороший разбор паттернов очень простым языком можно найти вот тут:
https://refactoring.guru/ru/design-patterns/strategy
Ну а мы посмотрим на код:
interface Handler {
void handle();
}
class OneHandler implements Handler {
@Override public void handle() {
sout("Handling ONE"); // и еще какая то сложная логика
}
}
class DefaultHandler implements Handler {
@Override public void handle() {
sout("Handling Default Case"); // и еще сложная логика
}
}
class CodeProcessor {
private final Map<CodeType, Handler> handlers = new EnumMap<>(CodeType.class);
private final Handler defaultHandler = new DefaultHandler();
public CodeProcessor() {
handlers.put(CodeType.ONE, new OneHandler());
// регистрируем обработчики здесь
}
public void process(CodeType codeType) {
handlers.getOrDefault(codeType, defaultHandler).handle();
}
}Что мы здесь видим? Теперь CodeProcessor не знает ничего о деталях обработки каждого типа кода. Он просто делегирует эту работу соответствующему обработчику.
Это делает код модульным, тестируемым и расширяемым. При этом соблюдается принцип единственной ответственности, так как каждый класс отвечает только за свою часть логики.
И хотя такой вариант реализации конечно выглядит немного сложнее, но уже на 30 строчках кода обработчика такая организация начинает приносить свои плоды.
И намного красивее это начинает смотреться как только в проекте появляется DI контейнер, который может автоматически инжектить зависимости и регистрировать обработчики.
Фух, наконец-то паттерны пригодились. На этом всё, если есть вопросы - всегда можно задать их в личке или в комментариях.
refactoring.guru
Стратегия
Стратегия — это поведенческий паттерн проектирования, который определяет семейство схожих алгоритмов и помещает каждый из них в собственный класс, после чего алгоритмы можно взаимозаменять прямо во время исполнения программы.
Пока все вайбкодят новые тасктрекеры, предлагаю поговорить о том, с чем вайбкод не справляется совсем 🌚
Mainteinability - это одна из важнейших вех в разработке.
И как связаны "поддерживаемость" с собеседованиями?
А это самая важная часть интервью, которая напрямую влияет на оценку. Практически любой интервьювер имеет в запасе пару таких вопросов.
Опытный кандидат на вопрос про инциденты на проекте с удовольствием расскажет о том, как на их проекте устроен мониторинг, какие основные метрики позволяют понять что произошел сбой. Как они дежурят, и что происходит после того как сбой устранен.
Поэтому из плоскости теории джава мы плавно переходим в область практики - почему качество кода менее важно чем качество процессов.
И какие открытые вопросы в первую очередь стоит прорабатывать перед собеседованием. 😇
Mainteinability - это одна из важнейших вех в разработке.
И как связаны "поддерживаемость" с собеседованиями?
А это самая важная часть интервью, которая напрямую влияет на оценку. Практически любой интервьювер имеет в запасе пару таких вопросов.
Опытный кандидат на вопрос про инциденты на проекте с удовольствием расскажет о том, как на их проекте устроен мониторинг, какие основные метрики позволяют понять что произошел сбой. Как они дежурят, и что происходит после того как сбой устранен.
Поэтому из плоскости теории джава мы плавно переходим в область практики - почему качество кода менее важно чем качество процессов.
И какие открытые вопросы в первую очередь стоит прорабатывать перед собеседованием. 😇
С чего начинается maintanability? 💬
1. Шаг номер один. Статический анализ. На любом проекте больше чем тыща строк кода возникает потребность в контроле стиля и формата. Сюда же относятся более продвинутые инструменты типа sonarqube. Весь этот хоровод называется словом quality gate.
Чуть детальнее по ссылке:
https://t.me/java_interview_tips/40
2. Тестовый контур и процессы тестирования. Сюда входит понимание пирамиды тестирования, опыт развертывания и поддержки тестовой инфраструктуры на проекте, метрик качества. Слова для поиска - testcontainers, jacoco, junit, mockito, wiremock, allure.
3. Здоровье сервиса. Отвечает на вопрос - как понять что сервис жив и выполняет свои функции. Ключевики - Actuator, Prometheus, Micrometer. Grafana для визуализации.
4. Логирование и трассировка, ELK - обычных разработчиков касается по касательной, достаточно общего представления.
5. Документация - автодоки, причесаный сваггер, gitlab pages.
6. CI, простая поставка ценности, пайплайны.
1. Шаг номер один. Статический анализ. На любом проекте больше чем тыща строк кода возникает потребность в контроле стиля и формата. Сюда же относятся более продвинутые инструменты типа sonarqube. Весь этот хоровод называется словом quality gate.
Чуть детальнее по ссылке:
https://t.me/java_interview_tips/40
2. Тестовый контур и процессы тестирования. Сюда входит понимание пирамиды тестирования, опыт развертывания и поддержки тестовой инфраструктуры на проекте, метрик качества. Слова для поиска - testcontainers, jacoco, junit, mockito, wiremock, allure.
3. Здоровье сервиса. Отвечает на вопрос - как понять что сервис жив и выполняет свои функции. Ключевики - Actuator, Prometheus, Micrometer. Grafana для визуализации.
4. Логирование и трассировка, ELK - обычных разработчиков касается по касательной, достаточно общего представления.
5. Документация - автодоки, причесаный сваггер, gitlab pages.
6. CI, простая поставка ценности, пайплайны.
Telegram
Артем | Java Интервью | Подготовка | Инсайды
Code smells не пройдут! Как вы следите за качеством кода?
Кодстайл решает очень важную проблему - он экономит массу времени разработчиков на ревью
Вместо споров как лучше - правила фиксируются один раз и позволяют фокусироваться только на логике
Обычно…
Кодстайл решает очень важную проблему - он экономит массу времени разработчиков на ревью
Вместо споров как лучше - правила фиксируются один раз и позволяют фокусироваться только на логике
Обычно…
Пункт номер один. Code smells не пройдут! Как вы следите за качеством кода?
Для чего на проекте, в котором больше чем один разработчик - нужен кодстайл, какие-то правила, quality gate и прочие сложные процессы?
Эти процессы позволяют решить две проблемы:
1) Споры между разработчиками "как лучше и как правильно"
2) Сделать качество кода хотя бы немного "измеримым"
При этом наличие жесткого код-стайла в команде существенно экономит общее время на ревью.
Вместо споров как лучше - правила фиксируются один раз и позволяют фокусироваться только на логике
Обычно для реализации используется checkstyle или detekt с набором ваших правил
Пример таких правил - максимальный размер строки или метода, или количество return
На собеседованиях это обычно встречается под соусом вопросов "а как вы следите за качеством вашего кода? А кроме ревью?"
Для чего на проекте, в котором больше чем один разработчик - нужен кодстайл, какие-то правила, quality gate и прочие сложные процессы?
Эти процессы позволяют решить две проблемы:
1) Споры между разработчиками "как лучше и как правильно"
2) Сделать качество кода хотя бы немного "измеримым"
При этом наличие жесткого код-стайла в команде существенно экономит общее время на ревью.
Вместо споров как лучше - правила фиксируются один раз и позволяют фокусироваться только на логике
Обычно для реализации используется checkstyle или detekt с набором ваших правил
Пример таких правил - максимальный размер строки или метода, или количество return
На собеседованиях это обычно встречается под соусом вопросов "а как вы следите за качеством вашего кода? А кроме ревью?"
Пункт номер 2. Любимая всеми нами пирамида Хеопса. Но на моем проекте отвалился нос с юнитами.
Что же хотят услышать коварные люди, когда спрашивают "как ты относишься к юнитам"?
Ответ что ты их терпеть не можешь - это отличный ответ умного человека. Особенно если потом объяснить, где проходит граница применимости и что покрытие юнитами в 80% это ужас ужасный - такой код проще сжечь чем отрефакторить.
Еще пример комплексных вопросов:
1) Приведи пример реализации всех слоев тестирования из твоего проекта, что, зачем, почему? (ожидается детальный рассказ)
2) Как дружите тестирование и CI, сколько занимает прогон тестов, и почему интеграционники бывают такими долгими? Как с этим боретесь?
3) Почему интеграционники с моками это нечестные тесты? Что тестируете руками?
И как видно - в вопросах мало намеков на конкретные технологии. Все они на глубину понимания проблем. Ожидается что разраб ти-шейпится и сам может поднять инфу автотестов, нагрузочных тестов, напишет базовые сценарии и даже не почешется.
Что же хотят услышать коварные люди, когда спрашивают "как ты относишься к юнитам"?
Ответ что ты их терпеть не можешь - это отличный ответ умного человека. Особенно если потом объяснить, где проходит граница применимости и что покрытие юнитами в 80% это ужас ужасный - такой код проще сжечь чем отрефакторить.
Еще пример комплексных вопросов:
1) Приведи пример реализации всех слоев тестирования из твоего проекта, что, зачем, почему? (ожидается детальный рассказ)
2) Как дружите тестирование и CI, сколько занимает прогон тестов, и почему интеграционники бывают такими долгими? Как с этим боретесь?
3) Почему интеграционники с моками это нечестные тесты? Что тестируете руками?
И как видно - в вопросах мало намеков на конкретные технологии. Все они на глубину понимания проблем. Ожидается что разраб ти-шейпится и сам может поднять инфу автотестов, нагрузочных тестов, напишет базовые сценарии и даже не почешется.
Завершающий пост на тему тестирования 👀
Я считаю, что профессия обычного (да и auto) qa уходит в прошлое, все больше компаний не дают в команду вакансию qa, или дают всего одного стажера.
В этих условиях у разработчика всего 3 союзника - он сам, llm и тесты.
Для того, чтобы тесты были надежными, самому приходится вникать во все процессы, связанные с качеством, считать покрытие, настраивать контур для интеграционного тестирования, проверять happy path e2e руками.
Именно поэтому сейчас в компаниях все более высокие требования к понимаю процессов qa для разработчиков. Экономия на qa приводит к тому, что за это отвечаем теперь тоже мы.
Поэтому если на текущем проекте еще нет автоматических интеграционных тестов - самое время подумать о том, чтобы с помощью llm их прикрутить, и заодно разобраться с основным инструментарием, пощупать поближе проблемы, которые возникают, когда пытаешься написать надежные но при этом устойчивые тесты.
Тестируй свой код прежде чем пушить в прод, аве! 🙏
Я считаю, что профессия обычного (да и auto) qa уходит в прошлое, все больше компаний не дают в команду вакансию qa, или дают всего одного стажера.
В этих условиях у разработчика всего 3 союзника - он сам, llm и тесты.
Для того, чтобы тесты были надежными, самому приходится вникать во все процессы, связанные с качеством, считать покрытие, настраивать контур для интеграционного тестирования, проверять happy path e2e руками.
Именно поэтому сейчас в компаниях все более высокие требования к понимаю процессов qa для разработчиков. Экономия на qa приводит к тому, что за это отвечаем теперь тоже мы.
Поэтому если на текущем проекте еще нет автоматических интеграционных тестов - самое время подумать о том, чтобы с помощью llm их прикрутить, и заодно разобраться с основным инструментарием, пощупать поближе проблемы, которые возникают, когда пытаешься написать надежные но при этом устойчивые тесты.
Тестируй свой код прежде чем пушить в прод, аве! 🙏
😁1
Фундамент комфорта и лучшая сегодня галка в резюме - observability на проекте 🎯
Что обычно понимают под этим словом?
Простыми словами - это процессы, которые позволяют легко и быстро понять, что на проекте что-то идет не так. Для этого команде нужен работающий 24/7 мониторинг ее услуг.
Как это касается разработчиков?
Именно разработчик обычно принимает решение, что нужно собирать метрики, и какие. Именно разработчик пушит внедрение инструментов трассировки в проект. И автоматизирует работу алертов.
И если разработчик этого не делает - то очень скоро команда проводит в разборах инцидентов времени больше, чем тратится на разработку бизнес фич.
Когда эти вещи внедряются сверху - то они делаются для галочки и ничего не мониторят.
Поэтому кандидатов часто спрашивают один простой но глубокий вопрос - как именно на текущем проекте у вас устроен observability?
Симулировать хороший ответ на него сложно. И даже для мидла уже важно самому принимать решение, а что же именно мониторить? И главное - как?
Что обычно понимают под этим словом?
Простыми словами - это процессы, которые позволяют легко и быстро понять, что на проекте что-то идет не так. Для этого команде нужен работающий 24/7 мониторинг ее услуг.
Как это касается разработчиков?
Именно разработчик обычно принимает решение, что нужно собирать метрики, и какие. Именно разработчик пушит внедрение инструментов трассировки в проект. И автоматизирует работу алертов.
И если разработчик этого не делает - то очень скоро команда проводит в разборах инцидентов времени больше, чем тратится на разработку бизнес фич.
Когда эти вещи внедряются сверху - то они делаются для галочки и ничего не мониторят.
Поэтому кандидатов часто спрашивают один простой но глубокий вопрос - как именно на текущем проекте у вас устроен observability?
Симулировать хороший ответ на него сложно. И даже для мидла уже важно самому принимать решение, а что же именно мониторить? И главное - как?
Шпаргалка по секции алгоритмов (без сложных задач):
Алгоритмическая сложность:
- Оценивается по времени и по памяти
- Оценки сложности (О обозначает оценку худшего возможного случая):
О(1) - константная - например, обращение по индексу в массиве
O(log n) - логарифмическая - бинарный поиск
О(n) - линейная - проход по массиву
O(n log n) - линейно-логарифмическая - быстрая сортировка, сортировка слиянием
O(n²) - квадратичная - вложенные циклы, наивные сортировки
Обычно все что ниже квадратичной - хорошо
- Основные способы решения алгоритмических задач:
1) Перебор - стартовый толчек для рассуждений, обычно неоптимален, нужно обьяснить почему и перейти к другим вариантам решения
2) Два указателя
https://leetcode.com/problems/valid-palindrome
https://leetcode.com/problems/reverse-string
https://leetcode.com/problems/linked-list-cycle (на алгоритм Флойда)
https://leetcode.com/problems/move-zeroes
https://leetcode.com/problems/merge-sorted-array
3) Плавающее окно
https://leetcode.com/problems/maximum-average-subarray-i
https://leetcode.com/problems/maximum-number-of-vowels-in-a-substring-of-given-length
4) Бинарный поиск
https://leetcode.com/problems/binary-search
5) Рекурсия и динамическое программирование
https://leetcode.com/problems/fibonacci-number
https://leetcode.com/problems/climbing-stairs
https://leetcode.com/problems/power-of-two
6) Жадные алгоритмы
https://leetcode.com/problems/assign-cookies
https://leetcode.com/problems/lemonade-change
https://leetcode.com/problems/best-time-to-buy-and-sell-stock
7) Обход графов в ширину (BFS) и высоту (DFS)
https://leetcode.com/problems/number-of-islands
https://leetcode.com/problems/network-delay-time (на алгоритм Дейкстры - для взвешенных графов)
8) Хэш-таблицы
https://leetcode.com/problems/single-number
https://leetcode.com/problems/two-sum
Алгоритмическая сложность:
- Оценивается по времени и по памяти
- Оценки сложности (О обозначает оценку худшего возможного случая):
О(1) - константная - например, обращение по индексу в массиве
O(log n) - логарифмическая - бинарный поиск
О(n) - линейная - проход по массиву
O(n log n) - линейно-логарифмическая - быстрая сортировка, сортировка слиянием
O(n²) - квадратичная - вложенные циклы, наивные сортировки
Обычно все что ниже квадратичной - хорошо
- Основные способы решения алгоритмических задач:
1) Перебор - стартовый толчек для рассуждений, обычно неоптимален, нужно обьяснить почему и перейти к другим вариантам решения
2) Два указателя
https://leetcode.com/problems/valid-palindrome
https://leetcode.com/problems/reverse-string
https://leetcode.com/problems/linked-list-cycle (на алгоритм Флойда)
https://leetcode.com/problems/move-zeroes
https://leetcode.com/problems/merge-sorted-array
3) Плавающее окно
https://leetcode.com/problems/maximum-average-subarray-i
https://leetcode.com/problems/maximum-number-of-vowels-in-a-substring-of-given-length
4) Бинарный поиск
https://leetcode.com/problems/binary-search
5) Рекурсия и динамическое программирование
https://leetcode.com/problems/fibonacci-number
https://leetcode.com/problems/climbing-stairs
https://leetcode.com/problems/power-of-two
6) Жадные алгоритмы
https://leetcode.com/problems/assign-cookies
https://leetcode.com/problems/lemonade-change
https://leetcode.com/problems/best-time-to-buy-and-sell-stock
7) Обход графов в ширину (BFS) и высоту (DFS)
https://leetcode.com/problems/number-of-islands
https://leetcode.com/problems/network-delay-time (на алгоритм Дейкстры - для взвешенных графов)
8) Хэш-таблицы
https://leetcode.com/problems/single-number
https://leetcode.com/problems/two-sum
👍2🔥2
На следующей неделе иду на алгоритмы в яндекс, они никогда не были моей сильной стороной, поэтому продолжаю усиленно вспоминать что там и как.
Накидал еще немного задачек yandex-like, всеми любимый разворот односвязного списка тоже в деле)
📌 Разворот списка, слов в строке:
https://leetcode.com/problems/reverse-linked-list
https://leetcode.com/problems/reverse-words-in-a-string-iii
📌 И подборка из 6 задачек, которые рекомендует сам яндекс (уже который год):
https://coderun.yandex.ru/selections/yandex-interview
Эти задачки они вынесли в контест и предлагают решить примерно за 3 часа.
📌 Отдельно из этих 6 выделил *Задачу со скобками*, которая ломает мне мозг:
https://leetcode.com/problems/valid-parentheses
Потому что в конце 25 мне попалась именно она ☠️
Накидал еще немного задачек yandex-like, всеми любимый разворот односвязного списка тоже в деле)
📌 Разворот списка, слов в строке:
https://leetcode.com/problems/reverse-linked-list
https://leetcode.com/problems/reverse-words-in-a-string-iii
📌 И подборка из 6 задачек, которые рекомендует сам яндекс (уже который год):
https://coderun.yandex.ru/selections/yandex-interview
Эти задачки они вынесли в контест и предлагают решить примерно за 3 часа.
📌 Отдельно из этих 6 выделил *Задачу со скобками*, которая ломает мне мозг:
https://leetcode.com/problems/valid-parentheses
Потому что в конце 25 мне попалась именно она ☠️
LeetCode
Reverse Linked List - LeetCode
Can you solve this real interview question? Reverse Linked List - Given the head of a singly linked list, reverse the list, and return the reversed list.
Example 1:
[https://assets.leetcode.com/uploads/2021/02/19/rev1ex1.jpg]
Input: head = [1,2,3,4…
Example 1:
[https://assets.leetcode.com/uploads/2021/02/19/rev1ex1.jpg]
Input: head = [1,2,3,4…
👍2🔥2
Перерывчик в алгоритмах, maintanability для самых маленьких, часть 3. Здоровье сервиса
Как объективно оценить, что сервис не только запущен, но и исправно выполняет свои функции?
Простой периодической проверки доступности пингом или отслеживания работающего процесса недостаточно. Сервис может принимать соединения, но при этом работать медленно, терять данные или не взаимодействовать с критическими зависимостями (базой данных, очередями сообщений, внешними API). Для реальной оценки состояния необходимы метрики, отражающие внутреннее поведение системы.
📌 Базовое решение - это подключить к приложению micrometer (библиотека для сбора метрик) и actuator, который предоставляет методы оценки здоровья приложения. С их помощью можно собрать ключевые метрики и хелсчеки: состояние сервиса, количество запросов в секунду, долю ошибок, время ответа, загрузку памяти и состояние подключений к внешним ресурсам.
📌 Для автоматического сбора и хранения метрик используется prometheus. Он регулярно опрашивает приложение, забирает числовые показатели и сохраняет их на таймлайне. Например. Для обычного java-приложения собирается более 20 различных метрик - это метрики по утилизации ресурсов, метрики скорости обработки запросов, метрики количества соединений с БД, и еще миллион их - включая кастомные бизнесовые метрики приложения.
📌 На основании этих данных строится мониторинг - данные визуализируются в Grafana, формируются целевые значения метрик, при выходе за пределы которых срабатывают алерты. Ну и в любой момент можно зайти и глянуть историю значений - это отличное подспорье в разборе инцидентов.
Как объективно оценить, что сервис не только запущен, но и исправно выполняет свои функции?
Простой периодической проверки доступности пингом или отслеживания работающего процесса недостаточно. Сервис может принимать соединения, но при этом работать медленно, терять данные или не взаимодействовать с критическими зависимостями (базой данных, очередями сообщений, внешними API). Для реальной оценки состояния необходимы метрики, отражающие внутреннее поведение системы.
📌 Базовое решение - это подключить к приложению micrometer (библиотека для сбора метрик) и actuator, который предоставляет методы оценки здоровья приложения. С их помощью можно собрать ключевые метрики и хелсчеки: состояние сервиса, количество запросов в секунду, долю ошибок, время ответа, загрузку памяти и состояние подключений к внешним ресурсам.
📌 Для автоматического сбора и хранения метрик используется prometheus. Он регулярно опрашивает приложение, забирает числовые показатели и сохраняет их на таймлайне. Например. Для обычного java-приложения собирается более 20 различных метрик - это метрики по утилизации ресурсов, метрики скорости обработки запросов, метрики количества соединений с БД, и еще миллион их - включая кастомные бизнесовые метрики приложения.
📌 На основании этих данных строится мониторинг - данные визуализируются в Grafana, формируются целевые значения метрик, при выходе за пределы которых срабатывают алерты. Ну и в любой момент можно зайти и глянуть историю значений - это отличное подспорье в разборе инцидентов.
❤1
Подслушал специфичную, но интересную тему. 🧠
Могут ли потеряться данные, если получено подтверждение от Postgres о том, что транзакция завершилась успешно?
На первый взгляд, кажется что нет - Postgres очень надежная штука. Но дело не всегда только в ней.
Давайте посмотрим несколько сценариев, когда данные таки могут потеряться.
1) Асинхронная репликация
Что такое репликация? Это дублирование данных на другую машину для надежности хранения и отказоустойчивости - при выходе из строя главной машины её роль на себя берет реплика.
Допустим, у вас есть главный сервер БД и одна или несколько реплик. Если нет ни одной синхронной реплики - главный сервер подтверждает коммит, как только записал данные к себе. Он не ждёт, пока реплика их получит. Если в этот момент главный сервер упал и вы переключились на реплику - последние изменения могут потеряться. Реплика просто не успела их сохранить к себе.
Для важных данных включайте синхронную репликацию, но готовьтесь к тому что будет работать медленнее.
2) Сбой дискового контроллера - энергозависимый кэш
Сначала немного инфы.
WAL (Write-Ahead Log) - это журнал, куда postgres сначала пишет всё, что собирается сделать. Коммит считается успешным, когда запись о нём попала в WAL и надёжно сохранилась.
После записи в WAL postgres вызывает fsync - специальный вызов к операционной системе: "запиши все данные на диск немедленно"
И тут в дело вступает железо.
Многие RAID-контроллеры имеют энергозависимый кэш. Данные попадают в этот быстрый кэш, контроллер сигнализирует что всё записано, а на самом деле до дисков они не дошли. Если пропадает питание, а у контроллера нет исправной резервной батарейки - кэш очищается, и данные теряются. Postgres честно вызвал fsync, думал, что всё на диске, а по факту данные жили только в быстрой памяти контроллера.
Фикс: либо батарейка на контроллере, либо отключение кэша записи, либо использование специальных дисков
3) Физическое повреждение WAL на диске
А что, если диск уже после успешного fsync физически повредил тот самый кусочек журнала, где лежит ваш коммит?
Например: неисправный дисковый контроллер, ошибка записи, сбой на уровне сектора, или просто SSD, который незаметно сломал данные.
Вы получили COMMIT OK, но через секунду сектор с WAL превратился в тыкву.
С большой вероятностью база вообще откажется запускаться с ошибкой PANIC: could not read from WAL. Тогда только ручное восстановление и потеря данных.
Это крайне редкий сценарий в нормальной enterprise-среде, но на дешёвых SSD или контроллерах - возможен.
4) Выключен fsync в настройках - да, надо быть экстремалом :d
Чтобы ускорить вставку миллионов строк, иногда временно выключают fsync. В таком режиме postgres не ждёт подтверждений от диска, а полагается на кэш операционной системы. Это даёт прирост скорости
Но при внезапном отключении питания, падении ОС или сбое сервера - все незаписанные данные теряются, а база данных может прийти в неконсистентное состояние и не запуститься. В боевой среде так делать не стоит.
Короткий итог:
Postgres - надёжный, но если железо врет про fsync, реплика асинхронная или вы сами отключили защиту - данные могут потеряться даже после успешного коммита. Храните бекапы, используйте синхронные реплики, RAID и надежные диски, иногда лучше медленнее и без кеша. 😅
Могут ли потеряться данные, если получено подтверждение от Postgres о том, что транзакция завершилась успешно?
На первый взгляд, кажется что нет - Postgres очень надежная штука. Но дело не всегда только в ней.
Давайте посмотрим несколько сценариев, когда данные таки могут потеряться.
1) Асинхронная репликация
Что такое репликация? Это дублирование данных на другую машину для надежности хранения и отказоустойчивости - при выходе из строя главной машины её роль на себя берет реплика.
Допустим, у вас есть главный сервер БД и одна или несколько реплик. Если нет ни одной синхронной реплики - главный сервер подтверждает коммит, как только записал данные к себе. Он не ждёт, пока реплика их получит. Если в этот момент главный сервер упал и вы переключились на реплику - последние изменения могут потеряться. Реплика просто не успела их сохранить к себе.
Для важных данных включайте синхронную репликацию, но готовьтесь к тому что будет работать медленнее.
2) Сбой дискового контроллера - энергозависимый кэш
Сначала немного инфы.
WAL (Write-Ahead Log) - это журнал, куда postgres сначала пишет всё, что собирается сделать. Коммит считается успешным, когда запись о нём попала в WAL и надёжно сохранилась.
После записи в WAL postgres вызывает fsync - специальный вызов к операционной системе: "запиши все данные на диск немедленно"
И тут в дело вступает железо.
Многие RAID-контроллеры имеют энергозависимый кэш. Данные попадают в этот быстрый кэш, контроллер сигнализирует что всё записано, а на самом деле до дисков они не дошли. Если пропадает питание, а у контроллера нет исправной резервной батарейки - кэш очищается, и данные теряются. Postgres честно вызвал fsync, думал, что всё на диске, а по факту данные жили только в быстрой памяти контроллера.
Фикс: либо батарейка на контроллере, либо отключение кэша записи, либо использование специальных дисков
3) Физическое повреждение WAL на диске
А что, если диск уже после успешного fsync физически повредил тот самый кусочек журнала, где лежит ваш коммит?
Например: неисправный дисковый контроллер, ошибка записи, сбой на уровне сектора, или просто SSD, который незаметно сломал данные.
Вы получили COMMIT OK, но через секунду сектор с WAL превратился в тыкву.
С большой вероятностью база вообще откажется запускаться с ошибкой PANIC: could not read from WAL. Тогда только ручное восстановление и потеря данных.
Это крайне редкий сценарий в нормальной enterprise-среде, но на дешёвых SSD или контроллерах - возможен.
4) Выключен fsync в настройках - да, надо быть экстремалом :d
Чтобы ускорить вставку миллионов строк, иногда временно выключают fsync. В таком режиме postgres не ждёт подтверждений от диска, а полагается на кэш операционной системы. Это даёт прирост скорости
Но при внезапном отключении питания, падении ОС или сбое сервера - все незаписанные данные теряются, а база данных может прийти в неконсистентное состояние и не запуститься. В боевой среде так делать не стоит.
Короткий итог:
Postgres - надёжный, но если железо врет про fsync, реплика асинхронная или вы сами отключили защиту - данные могут потеряться даже после успешного коммита. Храните бекапы, используйте синхронные реплики, RAID и надежные диски, иногда лучше медленнее и без кеша. 😅
❤2👍2
Итак, сходить на лайв алгоритмы в яндекс - отличный способ подпитывать внутреннего самозванца 😁
С задачкой и повезло и неповезло одновременно.
С чем повезло - попался хороший интервьювер и дал первую easy задачу такого формата, которую хотя бы *можно решить* если ты ее до этого не решал.
Неповезло с тем, что эту задачу я таки не решал, поэтому решение пришлось думать на ходу.
Как проходит интервью (если кто-то еще не был):
0) Время на интервью как обычно, 1 час и ни минутой более, две задачи, ко второй идем когда пройдем первую
Код пишем "на листочке" - без автоподстановок, IDE, гугла и прочего
1) Дали входящие условия - обязательно проговорить решение, сложность, граничные кейсы прежде чем браться решать - примерно 5-7 минут
2) Потратил на написание кода около 30 минут, что очень долго для первой задачи, и еще примерно 15 минут на прогон тестовых сценариев на готовом коде "в слух". По итогу вылизали код до почти "компилящегося"
3) Код получился объективно длинным и сложным - я не увидел путь проще и пошел сложным путем со state, с пачкой if, но по сложности O(1) по памяти и O(N) по времени
За вторую задачу браться не стал, решили с интервьювером еще немного поштормить первую, он тоже решил "скомпилировать" мой алгоритмический шиткод в голове 😁 Этим занимались до конца интервью
В какой то момент на прогонке кейса просто словил ступор. В общем, нужно больше практики "компилировать код в голове"
Задачку приложу чуть позже, как чуть отойду 🙈
С задачкой и повезло и неповезло одновременно.
С чем повезло - попался хороший интервьювер и дал первую easy задачу такого формата, которую хотя бы *можно решить* если ты ее до этого не решал.
Неповезло с тем, что эту задачу я таки не решал, поэтому решение пришлось думать на ходу.
Как проходит интервью (если кто-то еще не был):
0) Время на интервью как обычно, 1 час и ни минутой более, две задачи, ко второй идем когда пройдем первую
Код пишем "на листочке" - без автоподстановок, IDE, гугла и прочего
1) Дали входящие условия - обязательно проговорить решение, сложность, граничные кейсы прежде чем браться решать - примерно 5-7 минут
2) Потратил на написание кода около 30 минут, что очень долго для первой задачи, и еще примерно 15 минут на прогон тестовых сценариев на готовом коде "в слух". По итогу вылизали код до почти "компилящегося"
3) Код получился объективно длинным и сложным - я не увидел путь проще и пошел сложным путем со state, с пачкой if, но по сложности O(1) по памяти и O(N) по времени
За вторую задачу браться не стал, решили с интервьювером еще немного поштормить первую, он тоже решил "скомпилировать" мой алгоритмический шиткод в голове 😁 Этим занимались до конца интервью
В какой то момент на прогонке кейса просто словил ступор. В общем, нужно больше практики "компилировать код в голове"
Задачку приложу чуть позже, как чуть отойду 🙈
💯3
Сама задачка:
Дан массив чисел.
Необходимо найти строгую монотонную убывающую или возрастающую последовательность максимальной длины. Вернуть в ответе индекс начала и конца последовательности.
Примеры:
[1, 4, 3, 3, 3] -> (0, 1) - возрастающая
[10, 8, 6, 4, 2] -> (0, 4) - убывающая
fun findLongestMonotonicSubarray(nums: Array<Int>): Pair<Int, Int> {
...
}
Сколько обычно занимает поиск работы в айтишке (бекенд) до оффера по опыту знакомых, коллег и интернета?
В связи с ситуацией на рынке (соотношение вакансий к соискателям) обычное среднее время поиска работы, которое составляло 2-3 месяца с момента публикации резюме до выхода на работу - выросло до 4-5 месяцев.
Какие этапы и сколько занимают?
1) Отклики - вырос в основном он - до двух месяцев для поиска подходящей вакансии (при условии что резюме впорядке)
2) Технические интервью - с учетом лага между секциями до двух недель и большого количества этапов - может занимать 2 месяца (личный опыт)
3) Фиты - подбор команды, "смотрины" либо бенч - еще до двух месяцев
4) Переход с одной работы на другую - до месяца (подготовка смены, передача проектов, etc)
Таким образом перед сменой работы нужно иметь подушку более чем на полгода поисков. Поскольку даже согласованный оффер не дает гарантий выхода на проект - и может все переиграться. Се-ля-ви.
В связи с ситуацией на рынке (соотношение вакансий к соискателям) обычное среднее время поиска работы, которое составляло 2-3 месяца с момента публикации резюме до выхода на работу - выросло до 4-5 месяцев.
Какие этапы и сколько занимают?
1) Отклики - вырос в основном он - до двух месяцев для поиска подходящей вакансии (при условии что резюме впорядке)
2) Технические интервью - с учетом лага между секциями до двух недель и большого количества этапов - может занимать 2 месяца (личный опыт)
3) Фиты - подбор команды, "смотрины" либо бенч - еще до двух месяцев
4) Переход с одной работы на другую - до месяца (подготовка смены, передача проектов, etc)
Таким образом перед сменой работы нужно иметь подушку более чем на полгода поисков. Поскольку даже согласованный оффер не дает гарантий выхода на проект - и может все переиграться. Се-ля-ви.
😢3❤2💯1
Лето не способствует продуктивности и написанию постов, но я подсобрал немного открытых вопросов по теме "тестирование для разработчиков, interview edition" 🥸
Начнем с архитектуры тестов:
1) Как на текущем проекте устроена стратегия тестирования? Какое соотношение между юнит, интеграционными и e2e тестами вы считаете оптимальным и почему?
2) В какой ситуации приходилось применять параметризованные тесты? Приведите пример из проекта
3) С какими проблемами вы сталкивались при использовании моков? Бывало ли в тестах слишком много моков, почему это происходило и как это решалось?
4) Как вы подходите к тестированию методов с побочными эффектами (например, отправка событий в очередь) или асинхронного кода?
Интеграционный слой:
1) Используете ли Testcontainers? Какие у них есть недостатки? (например, могут замедлять сборку на CI/CD) Какие практики вы используете, чтобы оптимизировать скорость работы тестов с контейнерами?
2) Как вы организуете тестирование интеграций с внешними сервисами? (тут можно поболтать про wiremock)? Есть ли проверка сценариев отказоустойчивости (таймауты, 500)?
Общие вопросы:
1) Есть ли на проекте флакающие тесты? Какие основные причины нестабильности тестов вы знаете?
2) Как вы проверяете, что тесты действительно проверяют бизнес сценарии, а не просто "для покрытия" в отчете?
Вопрос со звездочкой (блистаем):
Вспомните случай из вашей практики, когда написанный вами тест, вовремя внедренный инструмент автоматизации или другая доработка тестового слоя спасли продакшен от критичной проблемы? Что это был за сценарий?
Надо понимать, что "правильного" на эти вопросы нет, они все из практики и копают в глубину, поэтому стоит в голове покрутить их и подумать, а как бы вы решали подобную задачу?
Начнем с архитектуры тестов:
1) Как на текущем проекте устроена стратегия тестирования? Какое соотношение между юнит, интеграционными и e2e тестами вы считаете оптимальным и почему?
2) В какой ситуации приходилось применять параметризованные тесты? Приведите пример из проекта
3) С какими проблемами вы сталкивались при использовании моков? Бывало ли в тестах слишком много моков, почему это происходило и как это решалось?
4) Как вы подходите к тестированию методов с побочными эффектами (например, отправка событий в очередь) или асинхронного кода?
Интеграционный слой:
1) Используете ли Testcontainers? Какие у них есть недостатки? (например, могут замедлять сборку на CI/CD) Какие практики вы используете, чтобы оптимизировать скорость работы тестов с контейнерами?
2) Как вы организуете тестирование интеграций с внешними сервисами? (тут можно поболтать про wiremock)? Есть ли проверка сценариев отказоустойчивости (таймауты, 500)?
Общие вопросы:
1) Есть ли на проекте флакающие тесты? Какие основные причины нестабильности тестов вы знаете?
2) Как вы проверяете, что тесты действительно проверяют бизнес сценарии, а не просто "для покрытия" в отчете?
Вопрос со звездочкой (блистаем):
Вспомните случай из вашей практики, когда написанный вами тест, вовремя внедренный инструмент автоматизации или другая доработка тестового слоя спасли продакшен от критичной проблемы? Что это был за сценарий?
Надо понимать, что "правильного" на эти вопросы нет, они все из практики и копают в глубину, поэтому стоит в голове покрутить их и подумать, а как бы вы решали подобную задачу?
👍2💯1
Готовь сани Летом? 🥸
Агенты для кодинга пролезли уже даже в финтех, а это повод подумать, как новый тренд повлияет на отборы
Периодически звучат предложения добавить секцию AI кодинга, или же заменить лайвкодинг на нее. Слишком радикально, но это звоночек, уже очень скоро в том или ином виде секция AI появится в требованиях к кандидатам, а потом и на интервью.
Давайте попробуем подумать над потенциальным форматом. По моему личному ощущению, очень скоро будет пару новых минорных апдейтов:
1) на секции лайводинга будут добавлять задачи для решения с помощью агентов, чтобы оценить навыки - здесь стоит посмотреть в сторону claude, codex, opencode (вообще бесплатный) и любых подобных агентов, тысячи их.
Важнее конкретной модели понять суть агентского цикла - постановка задачи, планирование, имплементация, ревью. Нужно руками потрогать, попробовать настроить под себя агентский флоу, написать скилл, что-то автоматизировать
2) добавятся вопросы по практике использования агентов. Например, базовые:
- разрешения агента - как пользовать безопасно?
- MCP - руки агента - чем пользуетесь и для решения каких проблем?
- навыки агента, субагенты (эдакий мультитрединг)
- контроль потребления токенов, контекст агента
Дисклеймер - клод это не панацея, и не отменяет навыки программирования. Но совсем игнорировать тренды глупо.
Чтобы не вылететь за борт, стоит хотя бы краем глаза просмотреть эти штуки, если все продолжаешь копировать код из chatgpt руками 🧠
Агенты для кодинга пролезли уже даже в финтех, а это повод подумать, как новый тренд повлияет на отборы
Периодически звучат предложения добавить секцию AI кодинга, или же заменить лайвкодинг на нее. Слишком радикально, но это звоночек, уже очень скоро в том или ином виде секция AI появится в требованиях к кандидатам, а потом и на интервью.
Давайте попробуем подумать над потенциальным форматом. По моему личному ощущению, очень скоро будет пару новых минорных апдейтов:
1) на секции лайводинга будут добавлять задачи для решения с помощью агентов, чтобы оценить навыки - здесь стоит посмотреть в сторону claude, codex, opencode (вообще бесплатный) и любых подобных агентов, тысячи их.
Важнее конкретной модели понять суть агентского цикла - постановка задачи, планирование, имплементация, ревью. Нужно руками потрогать, попробовать настроить под себя агентский флоу, написать скилл, что-то автоматизировать
2) добавятся вопросы по практике использования агентов. Например, базовые:
- разрешения агента - как пользовать безопасно?
- MCP - руки агента - чем пользуетесь и для решения каких проблем?
- навыки агента, субагенты (эдакий мультитрединг)
- контроль потребления токенов, контекст агента
Дисклеймер - клод это не панацея, и не отменяет навыки программирования. Но совсем игнорировать тренды глупо.
Чтобы не вылететь за борт, стоит хотя бы краем глаза просмотреть эти штуки, если все продолжаешь копировать код из chatgpt руками 🧠
❤2🔥2💯2