Новиков > путь в Big Tech – Telegram
Новиков > путь в Big Tech
184 subscribers
94 photos
192 links
От зеро-кодинга на стройке до написания высоконагруженных сервисов в Big Tech. 

Пишет SWE в Avito.ru (backend), в прошлом: .NET developer и сертифицированный специалист по использованию BIM.

Написать автору: @nvkv_ai

Книги: https://boosty.to/time2code
Download Telegram
Что делать, когда прямой путь не работает

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

Простой плагин, который раскрашивает brief-файлы (корпоративный стандарт для описания контрактов по типу protobuf, подробнее почитать здесь), подкинул очередную задачку.

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

К плагину прилагалась простая инструкция:


1. Скачать `vsix` файл: wget http://<extension-directory>.vsix

2. Добавить его в VSCode: Extensions -> ... -> Install from VSIX -> <extension-directory>.vsix

3. Либо через терминал: code --install-extension <extension-directory>.vsix


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

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

Далее рассудил так: если у меня есть репозиторий, куда активно контрибьютят, но нет самого vsix-файла (не важно, что я про такие файлы впервые слышу), который могу поставить как расширение, то что мне мешает собрать исходный код в такой файл?

Порадовавшись этой нехитрой мысли я переключился с проблемы "отсутствует файл", на задачу "как собрать файл". Через секунду я прочитал, что существует vsce - VS Code Extension Manager, с помощью которого я могу собрать нужный мне vsix. Ставим его:


npm install -g vsce


Далее переходим в директорию с исходником расширения (где живет наш плагин) и упаковываем в нужный vsix:


vsce package


Теперь нужно установить расширение в IDE. Используем следующую команду:


code --install-extension <extension-directory>.vsix


И, если с vsce все было просто, то следующим вызовом для меня как относительно нового пользователя VS Code стала команда code --instal-extension, так как просто в консоли она не выполнялась. Но спустя пару минут, разобравшись, что это CLI, уже устанавливал и ее.

В пределах 5-10 минут мне удалось: разобраться в проблеме, узнать как собирать vsix-файлы с помощью менеджера расширений vsce, устанавливать их через CLI и бонусом, пока все устанавливалось, подробно почитал про проект GNU Wget (небольшой тизер: Wget2 на подходе).

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

Рекомендую, когда прямолинейный подход не сработал, остановиться, записать вопрос и найти альтернативное решение, спустившись на уровень ниже. Так вы не только расширите свою экспертизу, но очередной раз потренируетесь в системном подходе решения задач.
👍4
Привычка, которая поможет расти в Big Tech

Одной из важнейших компетенций, на которую смотрят при возможном пересмотре грейда, является "инженерная культура".

В Авито на уровень E5 (синьор) ее признаки обозначаются как:

- Улучшает общие инженерные инструменты компании.
- Тестирует сложные корнер-кейсы.
- Проектирует тестопригодные системы и исправляет те, которые сложно тестировать.
- Ищет неэффективные места в коде/архитектуре/тестовых моделях. Пополняет технический бэклог команды.
- Устанавливает и тестирует нефункциональные требования или привлекает для этого экспертов.
- Знает и использует безопасные подходы к реализации функциональности.


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

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

На днях подключал к новому сервису библиотеку для работы с АБ-экспериментами. Была понятная дока с примерами, а еще были интересные нюансы:

1. Либу можно было использовать несколькими способами. Один из них - подключение как мидлвара (middleware).

Когда сделал все в соответствии с документацией, то ничего не заработало. Я долго не понимал почему, перечитывал доку и комментарии к функциями, все было правильно, но не работало.

Перечитывая очереденой раз документацию, глаз зацепился за комментарий, окруженный восклицательными знаками - он указывал на определенный порядок вызова мидлвар; я заодно перепроверил свой - все было корректно.

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

Как итог, все заработало.

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

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

2. При использовании либы, как мидлвары, оказалось, что ее нельзя адекватно протестировать юнит-тестами.

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

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

В юнитах - мы с мидлварой не работаем непосредственно, а прямое обогащение контекста предусмотрено не было.

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

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

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

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

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

@time2code
👍72👏1
Лучше маленький шаг, чем грандиозный план. Создаем красивый блог за 10 минут.

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

Шло время, но ничего не двигалось, так как я понимал, что нужны ресурсы на это: время и деньги для инфраструктуры.

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

Был даже план по написанию своего блога:

1. Стать фулстек-разработчиком, пройдя несколько курсов, изучая архитектуру фронтенда и JS
2. Мигрировать на стабильный VPS-сервер
3. Купить домен (тот, который нравится, стоит 10к в год)
4. Разработать блог

Близится конец года, а из намеченного плана есть только VPS-сервер, который самостоятельно стал стабильнее, так как провайдер переехал в более надежное место. Пункт 2 автоматически выполнился, без моего участия (такое мы любим).

И вот в один прокрастинирующий вторник (вчера) я решил, что откладывать больше нельзя.

У многих профессиональных разработчиков на сайтах или блогах я видел приписки "powered by ..." - и все в этом духе. Это означает, что они используют какое-то внешнее решение для своего сайта/блога.

И тут я подумал: чем я хуже?

Сперва планировал использовать bear blog, так как нравился по стилю. Но то ли я не разобрался из-за вечерней усталости, то ли еще что, увидев необходимость регистрироваться на платформе, решил, что мне это не подходит.

На втором месте у меня в закладках был Hugo - часто видел его у других авторов.

Круто, что проект написан на Go, open source и полностью бесплатный, а это значит, что при сильном желании, сможем что-нибудь законтрибьютить, а при необходимости - сделать свой форк и двигаться независимо.

Решил попробовать, тем более у проекта - отличная документация.

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

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

Сперва подумал, что смогу задеплоить на своем VPS-сервере, но сообразил, что быстро и легко не смогу это сделать...

Меня выручил github.pages, где у меня уже жила страничка с CV. А Hugo даже предоставляет простую инструкцию, как задеплоить туда.

Настроив Github Actions, чтобы проект автоматически разворачивался при пуше в мастер, и залив первую версию, с удивлением обнаружил, что все завелось с первой попытки!

Честно говоря, был счастлив, что, наконец, сделал серьезный шаг в сторону создания своего блога.

Конечно, Hugo уже оброс приличным функционалом и потребуется время, чтобы научиться пользоваться фреймворком, но самое важное, что начало положено и дальше будет проще.

Результат здесь (пока там только интро из гитхаба).

В планах перенести туда профессиональный блог с избранными постами из телеграма + начать активно его развивать с постингом в LinkedIn.

Конечно, есть и критика у подобных генераторов сайтов, но я считаю, что тут нужно отталкиваться от своих целей. Важно действовать по принципу "необходимое и достаточное".

На текущий момент кажется, что Hugo идеально подходит, но не исключаю, что через год перееду на полноценное standalone решение, если столкнусь с ограничениями.

Таким образом, фактически я создал свой новый сайт меньше чем за 10 минут + 30-60 минут потратил на чтение документации.

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

Интересно был ли у вас похожий опыт с блогами и на каком решении остановились в итоге?

@time2code
4👍3
Можем ли мы писать код без ошибок?

Мой ответ: нет.

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

Последний месяц занимался важной для нашей команды функциональностью. При этом разрабатывался только бэкенд, а фронтенд - отставал.

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

Но все равно случилось интересное. В конце прошлого спринта мы, наконец, смогли начать интеграционно тестировать фичу.

На бэкенде было найдено 3 бага:

1. Приходил цвет в странной кодировке.
2. Пустой массив не возвращался в ответе.
3. Лимит на количество элементов в ответе применялся в неправильном поле.

Что их объединяет? Все они были сделаны сознательно:

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

У каждого бага есть своя предыстория, свой контекст и тип.

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

Задача каждого инженера - создавать понятную и точную спецификацию, от которой будет сложно отойти и наделать ошибок, но, к сожалению, это утопия.

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

Самое важное - делать правильные выводы, обсуждать все проблемы на ретро и формировать такие договоренности внутри команды, чтобы в будущем качество своего продукта держать на стабильно высоком уровне.

@time2code
👍5
Два года в Big Tech. Стоило того?

Вчера было ровно 2 года с момента, как я работаю в Авито.

За это время мне удалось качественно вырасти как специалист.

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

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

Если меня спрашивают куда лучше идти работать, часто призываю стремиться именно в крупные компании. Особенно актуально для молодых специалистов, так как здесь можно получить отличную базу «как делать правильно».

Попробую проанализировать плюсы и минусы, которые заметил за это время.

👍 Несколько причин стремиться в компании уровня Авито:

Причины указаны в произвольном порядке. Каждая жизненно важна и без одной теряют сразу ценность другие.

1. Инженерная культура

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

2. Зрелые процессы

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

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

3. Компенсация и коммьюнити

Сюда попадает то, что связано с гигиеническими факторами: зарплата, мед. страховка, дружелюбная среда и прочее.

По внутренним ощущениям и отзывам коллег - тут все отлично.

4. Привязанность к продукту

Еще важным критерием в пользу той или иной компании может стать личная привязанность к продукту.

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

Меня это очень сильно заряжает и дает по-настоящему большое удовлетворение от того, что делаю.

👎 Несколько причин избегать компании уровня Авито:

1. Медленный рост грейда

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

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

2. Прозрачность решений топ-менеджмента

Иногда менеджеры принимают непопулярные решения, которые сложно понять рядовому сотруднику, а коммуникация может быть несвоевременной или вообще отсутствовать.

3. Потеря гибкости

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

4. Маленькие задачи

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

И если в стартапе есть возможность с нуля построить MVP продукта, поработав сразу над множеством задач разной сложности, то в Биг Техе тебя легко могут посадить “красить кнопку” или “перекладывать json”.

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

@time2code
👍12
Сентябрь 2024:

развитие

✔️ Завершил курс «Основы функционального программирования».
✔️ На примере GORM (ORM для Go) рассмотрел, как можно увеличить производительность на 20% при работе с базой данных.
✔️ Прошел отбор на внутренний курс по "Инженерной культуре", который предполагает интенсивное погружение в такие темы, как "проектное управление", "системное мышление" и др.
✔️ Приступил к реализации нового сервиса, по которому в прошлом месяце утвердил TDR: подготовил инфраструктуру и начинаю разработку бизнес-логики.
✔️ Провел сессию по управлению рисками (+моделирование угроз) для важной функциональности в текущем квартале.
✔️ Обнаружил 3 бага в функциональности соседних команд: 1 в продукте и 2 в инфраструктуре. Один из них - коллеги уже исправили, а оставшиеся - запланировали на ближайшие спринты.

прочее

✔️ Пробежал первый полумарафон (21.1км) с результатом 1:50:54 (5:15/км).
✔️ Поставил личный рекорд на 10км - 47.28 (4:50/км).
✔️ Сходил на неделю в отпуск. Хайкинг в горах отлично помогает отвлечься от работы.

посты

🔖 Простой язык программирования - иллюзия, которая продается (читать)
🔖 Что делать, когда прямой путь не работает (читать)
🔖 Привычка, которая поможет расти в Big Tech (читать)
🔖 Лучше маленький шаг, чем грандиозный план. Создаем красивый блог за 10 минут (читать)
🔖 Можем ли мы писать код без ошибок? (читать)
🔖 Два года в Big Tech. Стоило того? (читать)

#результаты
🔥7👍2🫡2
Почему мозг избегает сложных задач. Как его заставить работать?

Мозг - самая энергозатратная часть нашего организма. Нередко он нас обманывает, но зачем?

Ответ банален: чтобы спасти нас, сберегая ресурсы для своей сложной работы.

Очевидно, нас это не устраивает, так как разработка ПО - сложная и творческая задача, требующая от всех максимального включения в работу.

Уверен, многие знакомы с концепцией: задавания вопросов. Есть поговорка: «хорошо заданный вопрос - половина ответа».

Но почему это работает и работает ли?

Зачем задавать вопросы и как это помогает решать задачи?

Сейчас прохожу курс по системному мышлению (СМ) и получаю множество инсайтов.

Кратко: СМ - учит двум вещам:
1. Видеть границы своей компетенции.
2. Видеть проблемы на большем масштабе.

Есть еще понятие "модель" для решения той или иной задачи. Но в рамках текущего поста мы будем оперировать понятием "контекст".

Пока обозначим контекст как окружение, в рамках которого существует та или иная проблема.

Теперь самое интересное: решение проблемы может существовать либо в одном контексте, который вы уже рассматриваете, либо в другом.

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

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

Запомнить: через правильные вопросы мы помещаем свой мозг в нужные для решения задачи рамки.

Со мной происходит такое постоянно, но случалось ли с вами, что появился вопрос, который хотите задать коллегам, но пока вы его формулировали, то ответ находился самостоятельно?

@time2code
👍41
Блог готов! С чем пришлось справиться на старте?

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

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

Какая работа была проделана:
- Изучил большинство Hugo-тем, которые предлагаются для ведения блога. Остановился на PaperMod как самой приятной, хорошо работающей и активно поддерживаемой (это важно).
- Принял решение, что буду блог вести на двух языках (от этого зависела структура проекта).
- Так как решил вести блог на двух языках, то сразу выстрелил себе в ногу пришлось изучать множество нюансов, связанных с локализацией. На это потратил большую часть времени: тут и некорректное отображение даты на русском, странные заголовки, которые не хотели убираться из коробки, а также такие простые вещи, как скрытие текста и добавление плейсхолдера "Читать полностью...".

Финальным результатом я очень доволен. Особенно приятно, что создание блога было одной из моих целей на этот год.

Предлагаю ознакомиться 👈

В блоге доступны все свежие посты, начиная с сентября.

В планах (скорее всего, уйдет на 2025 год) добавить:
- Раздел с CV, где по одному клику HR смогут получить PDF.
- Теги, чтобы было удобнее группировать посты (+ облако тегов на главную или другой удобный инструмент для навигации).
- Поисковую строку (опционально, так как видел, что может не стабильно работать).
- Удобную пагинацию при большом количестве постов.

Телеграм останется моим основным инструментом для всех постов и коммуникации, а в блог будут публиковаться избранные материалы + возможно в будущем добавятся лонгриды, которые здесь пока не прижились.

Если раздумываете о своем блоге, но еще не начали, то пишите что останавливает (возможно, мой опыт может помочь). А если уже активно ведете, то делитесь им в треде для вдохновения и обсуждения опыта ;)

@time2code
👍11
Балансируя с производительностью. Можно ли жить без ORM?

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

Когда я писал на C#, то использовал Entity Framework Core - ORM для платформы .NET. А так как это был мой первый язык, то мне казалось это вполне естественным и об альтернативах я вообще не задумывался (возможно, на .NET тогда их и не было, не знаю есть ли сейчас).

В Go есть стандартная библиотека database/sql, представляющая собой общий интерфейс для работы с SQL-подобными базами. Если нужна максимальная производительность, то это ваш выбор.

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

Когда стандартного инструмента уже недостаточно, на помощь приходит sqlx, расширяя возможности, при сохранении производительности.

В прошлом месяце перед нашей командой стоял вопрос о том, как удобнее работать с базой, так как в прошлом немного настрадались с голым sqlx. Решили серьезно рассмотреть использование ORM, которых в языке хватает.

Когда только начал изучать Go, одно из первых, что запомнил - ORM для языка очень плохая практика. С этой мыслью и жил, пока вопрос удобства не встал более острым, чем вопрос производительности.

Подискутировав с командой и не найдя единого решения, я дошел до внутреннего Go-коммьюнити за советом. Коллеги единогласно разгромили ORM, и мы обсудили альтернативы 🤓

Из интересного мне приглянулась библиотека по генерации SQL-запросов - squirrel. И я решил сразу ее попробовать в бою.

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

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

Тут и пригодился squirrel, который при помощи различных билдеров мог составлять сложные запросы.

Инициируем такой билдер, наполняя данными.

Важно не забыть выбрать плейсхолдер для переменных в зависимости от драйвера бд! Для Постгреса это доллар.


builder := squirrel.Insert("element").Columns("noscript", "price")

for _, element := range elements {
builder = builder.Values(
element.Title, element.Price)
}

query, args, err := builder.PlaceholderFormat(squirrel.Dollar).ToSql()
if err != nil {
return fmt.Errorf("failed to build query: %w", err)
}

_, err = tx.Exec(query, args...)
if err != nil {
return fmt.Errorf("failed to execute query: %w", err)
}


По итогу получаем нужный запрос:


INSERT INTO element (noscript, price) VALUES ($1, $2), ($3, $4)


Конечно, интересно еще посмотреть на различные тесты производительности кода с этой либой и без (возможно, сделаю в будущем бенчмарки), но пока выглядит отличным инструментом, когда вы переросли sqlx, а в полноценную ORM идти пока не хотите.

@time2code
👍3🔥2
Такой Fizz Buzz вы точно не видели!

Надеюсь, все знакомы с этой задачей, но если нет, то можно прочитать статью для контекста и попробовать себя на литкоде (задача уровня easy).

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

Цель была простая - собирать нетривиальные решения Fizz Buzz на Go.

Например, вот несколько моих решений без единого if'а:


func (fb *FizzBuzzer) FizzBuzz() []string {
result := make([]string, 0, fb.n)

f := []string{"Fizz", "", ""}
b := []string{"Buzz", "", "", "", ""}

for i := 1; i < fb.n; i++ {
t := f[i%3] + b[i%5]
opts := []interface{}{i, t, t, t, t, t, t, t, t}
printed := fmt.Sprintf("%v", opts[len(t)])

result = append(result, printed)
}

return result
}


А вот еще одно:


func (fb *FizzBuzzer) FizzBuzz() []string {
result := make([]string, fb.n)

for i := 0; i < fb.n; i++ {
result[i] = strconv.Itoa(i + 1)
}

for i := 2; i < fb.n; i += 3 {
result[i] = "Fizz"
}

for i := 4; i < fb.n; i += 5 {
result[i] = "Buzz"
}

for i := 14; i < fb.n; i += 15 {
result[i] = "FizzBuzz"
}

return result
}


Очевидно, что на собеседовании лучше обойтись классическим вариантом, чтобы не пугать интервьюера (ведь ему это еще проверять).

* * *

Шло время, а новых решений с момента создания репозитория так и не появилось. И вот спустя 8 месяцев на почту получаю уведомление, что в fizz-buzz-world прилетел первый пул-реквест!

Так неожиданно я стал опен-сорс разработчиком.

Хочу выразить признательность автору: ПР был отлично оформлен и задокументирован, а предлагаемое решение крайне неочевидное и очень интересное. Подробнее читайте в ридми от него.

В основе новой реализации лежит "счастливое число", которое подсчитано для данной задачи, и в Go версии 1.23.2 оно равно: 176064004.

Зная такое число, решение выглядит следующим образом:


func (fb *FizzBuzzer) FizzBuzz() []string {
result := make([]string, 0, fb.n)

predefined := []string{"", "Fizz", "Buzz", "FizzBuzz"}
var r *rand.Rand
for i := 1; i < fb.n; i++ {
if i%15 == 1 {
r = rand.New(rand.NewSource(LUCKY))
}
index := r.Int63() % 4
if index == 0 {
result = append(result, strconv.Itoa(i))
} else {
result = append(result, predefined[index])
}
}

return result
}


Честно признаюсь, что мне потребовалось время, чтобы понять решение. Поэтому если интересно разобраться в этой магии, пишите комментарии или оставляйте реакции - сделаю разбор!

А еще, если у вас есть интересные идеи как можно решить Fizz Buzz, то предлагаю контрибьютить.

Если вы пишите на других языках, но знаете оригинальный метод решения, то пишите в личку, тред или создавайте issue - будем переводить ваше решение на Go и собирать самые безумные решения этой задачи вместе ;)

@time2code
4🔥2
Секрет счастливого числа в решении FizzBuzz.

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

На помощь приходит random seed, который обозначает число, на основании которого генератор всегда производит одну и ту же пвсевдослучайную последовательность.

В Go есть функция rand.NewSource. С ней мы можем задать нужный нам "seed". Это число и будет нашим "счастливым числом" (не путать с теорией чисел).

Основной задачей становится поиск такого числа. Полная реализация доступна здесь, мы лишь рассмотрим одну функцию, из которой станет понятна идея дальнейшего решения:


func izLucky() bool {
yep := []int{0, 0, 1, 0, 2, 1, 0, 0, 1, 2, 0, 1, 0, 0, 3}
for i := 0; i < 15; i++ {
r := int(r.Int63() % 4)
if yep[i] != r {
return false
}
}
return true
}


"yep" - массив, который содержит правильные индексы ответов первых 15 итераций. Если по указанному индексу выбрать строку из массива возможных вариантов: {"", Fizz, Buzz, FizzBuzz}, то мы получим корректное значение на выбранном шаге, а именно:


// ["", "", "Fizz", "", "Buzz", "Fizz", "", "", "Fizz", "Buzz", "", "Fizz", "", "", "FizzBuzz"]


То есть нам нужно подобрать такое число, при котором на каждой итерации для первых 15 элементов мы "случайно" будем получать правильный ответ, а вернее индекс, по которому сможет найти ответ.

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

Реинициализируем рандомайзер с заданным сидом каждые 15 итераций (внимание на "if i%15 == 1"):


func (fb *FizzBuzzer) FizzBuzz() []string {
// ...
var r *rand.Rand
for i := 1; i < fb.n; i++ {
if i%15 == 1 {
r = rand.New(rand.NewSource(176064004)) // <- lucky number
}
index := r.Int63() % 4
// ...
}

// ...
}


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

@time2code
1🔥1
Всегда ли автоматизация оправдана?

Когда был рядовым инженером в строительной компании, приходилось каждые 2 недели делать отчет на 150+ страниц в Power Point.

На это уходило много времени, и мне хотелось это автоматизировать.

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

Но шло время и мне так и не удавалось автоматизировать презентацию, потому что это выглядело так:
1. Изучить программирование.
2. Написать скрипт для презентации.

И я все время выбирал ручной труд, так как затраты на автоматизацию в этом случае превосходили мои возможности.

Спустя год компания наняла PHP-программиста, который автоматизировал презентацию, но он не писал плагин на Power Point, а создал полноценное решение, из которого автоматически получался PDF-файл.

Это было круто и, конечно, мне захотелось также уметь ...

В информационной безопасности есть правило: затраты на защиту не должны превышать ценность защищаемого объекта.

Как не нужно на велосипед стоимостью 3 тысячи рублей вешать замок за 12, так и не стоит автоматизировать процесс, который руками выполняется за 2 часа при стоимости разработки автоматики в несколько месяцев.

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

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

Когда завел блог, то решил обязательно сделать удобный инструмент для добавления новых постов.

Первый месяц, пока занимался настройкой, то мне приходилось их создавать вручную, а так как я решил блог вести на двух языках, то добавление нового поста сводилось к следующему:
1. Найти правильную директорию (решил все хранить по принципу: год-месяц-статья). Если нет, например, нужного месяца, то создаем и уже туда помещаем файл для будущей статьи.
2. Вставить в шапку файла шаблон с метаинформацией.
3. Задать slug, который будет являться URL-путем.
4. Добавить содержание.
5. Повторить пункты 1-4 для английской статьи.

В какой-то момент я устал это делать и решил автоматизировать. Я знал, что hugo предлагает удобный способ создания нового поста на основе шаблона (что автоматически могло избавить меня от пункта 2).

Завел нужный шаблон архетипов, заодно организовав его таким образом, чтобы slug подставлялся из названия поста и теперь мои действия стали такими:
1. Команда в терминале:

hugo new 2024/september/mypost.md --kind post

2. Добавить содержание.
3. Повторить пункты 1-2 для английской статьи.

Это быстрее, чем было, но все равно медленно. И тут я вспоминаю про Makefile.

Бегу создавать его в корневой директории со следующим содержимым:


SLUG ?= "default-slug"
YEAR ?= $(shell date +"%Y")
MONTH ?= $(shell date +"%B" | tr '[:upper:]' '[:lower:]')

post:
hugo new posts/$(YEAR)/$(MONTH)/$(SLUG).md --kind post_en && \
hugo new ../ru/posts/$(YEAR)/$(MONTH)/$(SLUG).md --kind post_ru


Год и месяц автоматически проставляются shell-командой, слаг берется из названия статьи, и одновременно заводится сразу 2 нужных поста в правильных директориях.

После чего изначальный труд свелся к следующим действиям:
1. Команда в терминале:

make post SLUG="mypost"

2. Добавить содержание.
3. Повторить пункт 2 для английской статьи.

Очевидно, можно и дальше продолжить.

План-капкан - создавать новую статью, например, через телеграм бота, который будет получать содержание, переводить на английский и самостоятельно деплоить на сервер :)

Но это уже другая история и текущая автоматизация меня полностью всем устраивает.

@time2code
👍4
В поисках первопричины. Как найти точку отказа?

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

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


Пролог

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

Например, если говорят, что SLA = 4 часа, то это означает, что в течение четырех часов с момента обращения на ваш запрос должны отреагировать.

У нас в вертикальной команде тоже есть SLA и дежурства. Мы должны оперативно реагировать на все возникающие проблемы у пользователей.

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

Как это всегда бывает, сперва пытаемся установить зону ответственности (кто сломал), чтобы передать "горячую картошку" дальше и продолжить заниматься своими задачами.

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

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

Продолжение следует...

@time2code
👍1
В поисках первопричины. Как найти точку отказа?

Ранее:
- Пролог

Часть I - Обращения продолжают поступать

1. Первым делом иду в историю коммитов сервиса, горизонтально отвечающего за данный сценарий. Вижу много релизов и начинаю проверять каждый, начиная от момента, когда появилось первое обращение о проблеме. Пролистав порядка 10 релизов и не найдя ничего подозрительного в истории изменений, двигаюсь дальше.
2. Иду смотреть дашборды сервиса. Смотрю технические и продуктовые метрики по разным сценариям в надежде увидеть какие-то отклонения от нормального состояния, но тщетно.
3. Следующая остановка Sentry и Kibana. В обилии логов и ошибок нахожу подходящую под мой случай. Текст ошибки указывает на проблему в другом горизонтальном сервисе.
4. Обсуждаем эту историю с QA и находим название "проблемного сервиса".
5. Повторяются пункты 1-3 для найденного сервиса. По коммитам последних релизов снова проблема неочевидна, но вот на дашбордах можно заметить интересное: нужная RPC-ручка время от времени не справляется с нагрузкой и начинает отдавать ошибки.
6. Обрадовавшись, что проблема найдена, идем в чат поддержки данного сервиса и указываем на проблему.
7. Спустя какое-то время нам подтверждают, что о ситуации известно: виноват Redis, а в следующем спринте запланирована починка.
8. В этот момент хотелось расслабиться и ждать, пока ребята все наладят, но обращения по проблеме от пользователей не прекращают поступать, и вот мы уже повышаем приоритет бага до "серьезного". Чинить нужно срочно, нет времени ждать следующего спринта.

Продолжение следует...

@time2code
👍1
В поисках первопричины. Как найти точку отказа?

Ранее:
- Пролог
- Часть I - Обращения продолжают поступать

Часть II - Удивительное совпадение

9. Решив еще раз сравнить графики ошибок двух сервисов, я вижу несоответствие. Проблемный сервис действительно работает с перебоями, но почему-то моменты его отказа не полностью коррелируют с фоном ошибок у вызывающего сервиса, а значит, что должно быть что-то еще, что оказывает негативное влияние.
10. Иду к ребятам из горизонтальной команды, чтобы помогли установить причину, погрузившись своей экспертизой.
11. Локализовав проблему, коллеги подсказывают, что не формируется диплинк, который должен отдавать уже третий сервис и, если они его не получают, то может происходить похожее поведение. У меня появляется серьезная надежда, что первопричина найдена.
12. Узнав какой сервис формирует диплинк, иду по классической схеме из п.1-3 и вижу... Накануне дня, когда начались проблемы, был совершен коммит, задевающий логику по формированию нужного нам диплинка и при этом авторы - коллеги из моей вертикали, что как будто сигнализирует о том, что вот она разгадка.
13. Иду к ребятам и прошу посмотреть нашу ситуацию и спроецировать на свой код: могли ли они что-то задеть?
14. После некоторого анализа и череды сообщений в разных тредах, к моему удивлению, это оказалось удивительным совпадением. Функционал задели не они...

Продолжение следует...

@time2code
👍1
В поисках первопричины. Как найти точку отказа?

Ранее:
- Пролог
- Часть I - Обращения продолжают поступать
- Часть II - Удивительное совпадение

Часть III - Пятничный деплой

15. На этом этапе уже отчаявшись, я поднимаю 3+ сервиса локально и начинаю детальный дебаг с проблемным запросом, который мне любезно подготовил QA (спасибо ему большое, одному было бы гораздо дольше с этим разбираться). Я решил идти построчно по коду, начиная с самого первого сервиса.
16. Спустя некоторое время, неожиданно наблюдаю, что запрос, пройдя множество сервисов и вернувшись в первый, прерывается в странном месте. В конструкции switch-case ни один case не срабатывает, запрос уходит в default, из-за чего и возвращается непонятная ошибка.
17. Показав это поведение ответственному за горизонтальный сервис, он сразу подтвердил, что вот он корень проблемы, должна быть другая логика.
18. Пытаюсь понять как исправить. Быстрый анализ конструкции показывает, что сравнивались различные типы ошибок и в зависимости от этого выполнялась дальнейшая обработка. В нашем случае тип ошибки перестал определяться, из-за чего сервис не понимал как ее обрабатывать. Но почему так начало происходить?
19. Начинаю искать, где формируется ошибка, и вижу: добавился враппер, который обернул нашу ошибку и добавил дополнительный контекст... А так как в Go работа с ошибками построена максимально примитивно, то легко можно ошибиться - это здесь и произошло.
20. Готовлю "быстрый" фикс, QA тестирует и подтверждает, что проблема, с которой пришли пользователи, ушла!
21. Классический пятничный деплой в конце спринта и томительное ожидание за просмотром метрик, где раньше наблюдались ошибки...
22. Фон ошибок резко падает. На графиках видно, как нормализуются ситуация. Наконец, можно выдохнуть. Проблема решена, я спокойно ухожу на выходные, а пользователи получают возможность завершить свой обычный сценарий.

Эпилог следует...

@time2code
👍2
В поисках первопричины. Как найти точку отказа?

Ранее:
- Пролог
- Часть I - Обращения продолжают поступать
- Часть II - Удивительное совпадение
- Часть III - Пятничный деплой

Эпилог

1. Просматривая историю коммитов, подвергайте сомнению каждый. В самом начале я обратил внимание, что в первом сервисе провели рефакторинг некоторых ошибок: поменяли нейминг, где-то добавили логирование, однако проблема не была сразу очевидна. Оказалось, я просто искал ответ на другом уровне абстракции.
2. Потратить 10-30 минут на внимательный дебаг может быть полезнее, чем многочасовой просмотр и поиск нужных дашбордов. Код покажет, как система действительно работает в отличие от того, как она "работает" на графиках.
3. Подвергайте сомнению любые предположения коллег о работе сервиса: они могут заблуждаться, не осознавая этого. Здравый скептицизм полезен.
4. Если пишете на "простом" языке, как Go, то разберитесь, как работать с ошибками. Не просто так на Stepik существуют курсы за 500$, посвященные работе с ними.
5. И, конечно, после таких инцидентов всегда заводите Action Item. В данном случае заведен - о поиске такого дашборда, который четко указывает на существование проблемы (к слову сказать: вчера с коллегами все-таки нашли такой). И второй немаловажный момент - добавление алерта на данный сценарий. Вы всегда должны узнавать о проблеме быстрее, чем это заметит пользователь, и тем более чем он сам вам об этом сообщит.

@time2code
👍4
Октябрь 2024:

развитие

✔️ Запустил свой блог на Hugo, в котором можно найти более 10 расширенных постов из телеграма на двух языках.
✔️ Добавил в блог несколько своих фишек, которых не схватило из коробки и даже поделился опытом в "Обсуждениях" официального репозитория PaperMod.
✔️ Попрактиковался в ФП на Python.
✔️ Завершил курс из 4-х занятий по проектному управлению (PMF).
✔️ Завершил курс из 4-х занятий по системному мышлению.
✔️ В рамках обучения инженерной культуре продолжаю участвовать в занятиях по паттернам проектирования.
✔️ Научился удобно генерировать различные типы файлов на основе шаблонов text/template в Go.
✔️ Начал использовать AI-ассистент из VS Code на основе Continue.

прочее

✔️ Познакомился с Haskell и написал свою первую программу.
✔️ Написал 4 поста в LinkedIn, экспериментируя с форматами.
✔️ Поставил личный рекорд на 21.1км - 1:48:37 (5:09/км).
✔️ Поставил личный рекорд на 10км - 47.21 (4:44/км).

посты

🔖 Почему мозг избегает сложных задач. Как его заставить работать? (читать)
🔖 Блог готов! С чем пришлось справиться на старте? (читать)
🔖
Балансируя с производительностью. Можно ли жить без ORM? (читать)
🔖 Такой Fizz Buzz вы точно не видели! (читать)
🔖 Секрет счастливого числа в решении FizzBuzz. (читать)
🔖
Всегда ли автоматизация оправдана? (читать)
🔖 В поисках первопричины. Как найти точку отказа? - Серия из 5 постов (читать)

#результаты
👍32🔥1
Возможно ли сохранить отношения после код-ревью?

Все мы слышали про "запах" кода (code smell). Так называют явные проблемы в исходном коде, которые обязательно приведут к трудностям при дальнейшей поддержке и эксплуатации.

Но все ли знают, что "пахнуть" может не только код?

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

Ситуация

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

Возвращаясь после обеда, чтобы посмотреть как поживает ваш открытый ПР, обнаруживаете: десятки комментариев. Вы не сможете быстро это исправить. Необходимо садиться и защищать свой код...

Начинаете разбираться с каждым комментарием построчно, читаете первый: "Здесь написана неправда.". Читаете другие: "Это плохо, так делать не нужно", "Почему решили так делать?", "Я не пропущу это в прод!".

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

В такой ситуации проигрывают все.

Нас это не устраивает, поэтому давайте посмотрим как можно прийти к win-win.

Что делать? (вы ревьюер)

1. Не допускайте высокомерных и токсичных комментариев на код-ревью. Пишите по делу. Знаете как сделать лучше? - Предложите свой вариант. Попробуйте уточнить, почему автор решил пойти в такое решение, а не использовать лучшие практики принятые в компании.

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

Не понравился продукт? - Не сдерживаясь выскажите все, что вы про него думаете. Главное - донести мысль, что это не то и вам не нравится. Пусть автор все переделает и попробует догадаться сам как исправить ситуацию => Не нужно так!

2. Каждому, кто оценивает других, рекомендую прочитать основы или пройти курс по тому, как давать обратную связь. По теме рекомендовал полезную ссылку в апрельском посте. Это необходимый навык в современной работе и не только в IT.

3. Будьте полезным - пытайтесь предугадать возможный ответ автора на ваш комментарий и пишите с его учетом. Так сэкономите время себе и другим.

Что делать? (вы автор ПР)

1. Запомните: оценивают не вас лично, а ваш код. Не принимайте на свой счет и попробуйте понять мотивацию подобного комментария. Возможно, ревьюер неявно решил прокричать про свою боль, с которой он недавно столкнулся, и которой хочет избежать в будущем.

2. Задавайте вопросы. Увидели комментарий из разряда: "Это плохо, мне не нравится" - не спешите сразу бросаться исправлять, попробуйте уточнить, что конкретно не понравилось? Если понимаете проблему, то можно сразу в вопрос подложить решение и уточнить будет ли такой подход лучше?

3. Предлагайте компромисс. Если понимаете, что исправить все комментарии - это очень дорого, заведите новую задачу, куда приложите все возникшие вопросы. Предложите сейчас "покатиться" так, а в новой задаче вы уже все доделаете как нужно.

4. Очень опасная, но эффективная техника. Использовать осторожно и в крайней ситуации!

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

Попадали ли вы в неприятные ситуации на ревью и как из них выходили? А может быть у вас скопился богатый опыт как следует проводить ревью коллегам и у вас есть мнение на этот счет?

@time2code
7
Готовимся к фичефризу и закрываем цели, сохраняя рассудок

До 31-го декабря осталось ровно семь недель. 7 недель, чтобы успеть сдержать все обещания, данные в начале года и достичь всех целей, которые не были достигнуты. В этом году я решил попробовать систему целеполагания по ОКР и позже поделюсь, что у меня из этого вышло (спойлер: работы впереди еще очень много, чтобы показать результат).

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

Остается 6 недель - 3 спринта (не считая текущей недели, при условии, что у вас спринт длится 2 недели), чтобы успеть сделать максимум для закрытия своих ОКРов, подготовить очередной мобильный релиз и задеплоить изменения, которые запланированы в этом году.

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

Чувствуется усталость, но нужно потерпеть. Пора переходить в режим тупого автопилота: меньше думать, больше делать, стараясь не терять в качестве.

Конечно, иногда скучаешь по спокойным инженерным временам, когда не было никакой спешки, спринтов, стремления к низкому TTM и прочих болей современного IT. Таковы издержки разработки.

Как можно себе помочь?

И если на фиксированные даты мы повлиять не можем, как и не можем повлиять на рабочие задачи, которые должны быть сделаны, то влиять на свои достижения в 2024, а также планы на 2025 - еще как можем.

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

2. Начинайте анализировать. Вероятно, не все, что вы запланировали в начале года релевантно для вас сейчас и будет таким в будущем. Если понимаете, что при планировании просчитались - ничего страшного - просто явно зафиксируйте это, чтобы была возможность к этому потом вернуться. Таким образом, вы избавитесь от навязчивой мысли, что чего-то не успеваете, и уменьшите нервное напряжение от этого.

Например, у меня из крупных целей на год осталось:
- Серьезно развить свои компетенции во Frontend-разработке
- Сделать 1 ПР в опенсорс проект
- Написать 5-ый пост в Linkedin
- Прочитать 4 книги

К некоторым я точно не успею подступиться и явно это фиксирую, чтобы про это больше не думать. При этом попробую по каждой сделать небольшой ресерч, чтобы понимать переедет ли цель в следующий год и, если да, то в каком виде.

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

3. Устройте себе неделю недель (авторская терминология). Попробуйте на каждой из 7 недель сделать всего лишь одно запланированное дело из тех, которые у вас были на год. А потом посмотрите на результат.

Предлагаю попробовать вместе. В треде отпишусь о своем небольшом деле на эту неделю. Если готовы - присоединяйтесь!

@time2code
👍2🫡1
Как не уронить свою пирамиду тестирования?

Когда в проекте сотни микросервисов, настроен CI-CD, при котором во время очередного билда не только происходит билд проекта, запуск линтеров, но еще и запускается десяток различных е2е-тестов, то небольшая проблема с инфраструктурой или в отдельно взятом сервисе может стать серьезной головной болью.

Представьте ситуацию: вносите изменения в сервис, делаете коммит, а тесты падают. Вы пытаетесь понять: могли ли стать причиной падения или проблема в другом?

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

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

Причем, если ответственные за тесты не указаны, то следуете алгоритму:

1. Ищешь возможную проблему в связанных сервисах (кто-то мог сообщить об этом).

2. Если проблема не найдена (а так обычно бывает в 99% случаев), то идешь в канал для обсуждения общих проблем при разработке, задаешь вопрос и ждешь.

3. Если повезет, оперативно могут подсказать ответственных за сервис и ты идешь уже к ним.

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

4. Запрашиваем помощи ответственных за тест - обычно апрув, чтобы была возможность пропустить упавшие тесты и задеплоить свои изменения.

Пример выше - отличная иллюстрация того, почему пирамида тестирования должна выглядеть таким образом, каким ее рисуют в учебниках: широкое основание с дешевыми юнит-тестами и небольшая вершина с e2e. Они очень дороги в поддержке и сильно увеличивают TTM, если у вас случился перекос в пирамиде или имеют место случаи, описанные в посте.

Выводы:

1. Особенно, если вы QA, следите за пирамидой. Не допускайте в своем проекте антипаттерна "рожок мороженого" и следите, чтобы e2e было адекватное количество и они относительно стабильно работали или была четкая документация на случай проблем.
2. Если часто становитесь борцом с такими тестами, как я, то старайтесь выработать универсальный навык траблшутинга и поиска ответственных.

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

@time2code