Новиков > путь в 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
Cross-Site Request Forgery (CSRF)

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

🕵️‍♂️ Веб-приложение уязвимо к CSRF-атакам, если обнаружено:

1. Отсутствие или ненадежная реализация CSRF-токена.
2. Наличие повторяющихся запросов на изменение данных без дополнительной проверки подлинности.
3. Автоматическое выполнение действий без подтверждения со стороны пользователя.

🔧 Обеспечить безопасность вашего приложения помогут:

1. Внедрение CSRF-токен в формы и проверка их на сервере перед выполнением действия.
2. Использование сессионных токенов для подтверждения подлинности пользователя.
3. Ограничение привилегий доступа к функциями изменения данных.

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

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

Подробнее о данном виде атак и методах защиты можно найти в шпаргалке OWASP.

Применяя данные советы, вы добавите еще один слой защиты к своим приложениям.

#безопасность
Март 2024:

навыки
✔️ Завершил практикум по безопасной разработке. Со всеми задачами можно познакомиться здесь. Планирую еще выпустить несколько постов по темам: IDOR, Path Traversal и SQL Injection.
✔️ Поучаствовал в оффлайн митапе Go-сообщества. Послушал про фаззинг и альтернативу buf.
✔️ Приступил к книге Head First Design Patterns, изучил 2 паттерна и реализовал их на Go
✔️ Продолжаю изучать ООП. Нравится, что эта парадигма заставляет думать иначе, нежели чем функциональный подход, однако, общие принципы к проектированию программы схожи.
✔️ Поделился рефлексией о том, как писать комментарии к своему коду.
✔️ Рефлексия о важности атомарных изменений. Частые коммиты лучше, чем редкие и большие.

карьера
✔️ Обсудил с тим-лидом возможности роста и будущий проект, который позволит перейти на следующий уровень экспертизы. Написал пост о важности коммуникации со своим руководителем.

прочее
✔️ Не открывал прошлую IDE (Goland) более месяца. Отлично справляюсь с VS Code. Можно сказать, что переход прошел легко.

#результаты
🔥3
Как хорошо вы знаете свой язык программирования? [1/2]

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

Сможете правильно сказать что выведет код представленный ниже?

Выберите свой ЯП и, не раздумывая, попробуйте ответить. Затем проверьте себя.


var sum = 90 + 010;
System.Console.WriteLine(sum);



func main() {
sum := 90 + 010
fmt.Println(sum)
}



sum = 90 + 010
print(sum)



public class Main
{
public static void main(String[] args) {
var sum = 90 + 010;
System.out.println(sum);
}
}



var sum = 90 + 010
console.log(sum)



fun main() {
var sum = 90 + 010
println(sum)
}



<?php
$sum = 90 + 010;
echo $sum;



sum = 90 + 010
print(sum)



var sum = 90 + 010
print(sum)


Ответы:

C#, Julia, Swift: 100
Go, Java, Javanoscript, PHP: 98
Kotlin, Python: ERROR!
🔥3
Как хорошо вы знаете свой язык программирования? [2/2]

"SyntaxError: leading zeros in decimal integer literals are not permitted; use an 0o prefix for octal integers". - С такой ошибкой ругнется интерпретатор Python, если выполните код, предложенный выше.

Из 9 представленных языков синтаксис также не устроит и компилятор Kotlin. А остальные? :)

Ответ 100 кажется интуитивный, поэтому к C#, Julia и Swift вопросов нет, но почему другие допускают такую вольность или это чем-то обусловлено?

98 мы получаем, когда появляются ведущие нули перед числом и (!) оно представлено в восьмеричной системе счисления (все цифры меньше 8), то есть на 090 + 010 нормальный язык уже заругается, что, конечно, разумно.

Извини JavaScript, но когда вижу, что console.log(090 + 010) все также выведет 98 , мой мир логики рушится. Очень уважаю людей, кто не путается со всеми подобными особенностями JS.

Go солидарен с Python, но при этом допускает оба написания:
90 + 010 <=> 90 + 0o10

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

Кстати говоря, Go также позволяет следующие префиксы: 0b, 0o, 0x - подробнее их описывал здесь.

Для чего вообще такой трюк с восьмеричной системой нужен? Например, для задания прав доступа в Unix при работе с файлами: 0777 (но лучше, конечно, 0o777).

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

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

Присмотритесь к книгам издательства Manning. У них есть серия 100 {Language} Mistakes and How To Avoid Them. Я сейчас дочитываю "100 Go Mistakes and How to Avoid Them" и это must have для всех, кто изучает Go, в связке с какой-нибудь базовой книгой или гайда, как, например, A Tour of Go.

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

Тренироваться.

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

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

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

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

. . .

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

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

Настал день интервью, где в течение 1.5 часов мы общались про Go, базы данных и немного про брокеров сообщений (в частности Kafka). Хочется отдать компании должное: собеседование на 90% состояло из практических задач, а я, к своей неудачи, всю прошлую неделю готовился к теории...

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

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

. . .

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

0️⃣ Когда работаешь в крупной компании, то в какой-то момент начинает казаться, что все по плечу и ты с легкостью найдешь работу. Такие ситуации тебя приземляют и ты вспоминаешь, что нужно тренироваться, чтобы проходить технические секции. 1 неделя для тренировки - очень мало, комфортный темп 2-4 недели (зависит от класса компании, в FAANG могут уйти месяцы).

1️⃣ Даже легкое волнение влияет на внимательность. Пример с собеседования: инициализация слайса make([]int, 4) дает cap=4, len=4, но я почему-то воспринял это как cap=4, len=0, прочитав make([]int, 0, 4), несмотря на то, что я проговорил правило вслух. Такие вещи должны тренироваться до автоматизма, чтобы не совершать глупых ошибок.

2️⃣ Я понял, что сильно погружен в продуктовую / бизнес разработку, из-за чего отлично разбираюсь в продуктовых контекстах, запусках и сетапах AB-экспериментов, но могу быть неуверенным при работе с транзакциями, написании SQL-запросов или траблшутингом сервисов, так как работаю с этим мало.

3️⃣ За время, что я готовился к собеседованию, значительно увеличил свои знания в Go и Kafka, изучая лучшие практики и особенности работы.

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

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

P.S.: Если будет интерес, то обязательно разберу задачи с собеседования, они довольно легкие, но по-своему полезные.
🔥6
Разбираем задачи с технической секции (платформа Go)

Решил остановиться на 3-х задачах, так как они довольно показательные, несмотря на простоту. Интервью еще включало задание на код-ревью готового пул-реквеста, написание SQL-запросов и сопутствующие вопросы про БД, транзакции и Kafka.

Так как стандартных средств форматирования для такого лонгрида мне не хватило, то тестирую telegraph.
С чего начинать код-ревью? [1/2]

ℹ️ Дисклеймер. Как именно давать обратную связь мы не затронем, но это очень важная тема, про которую нельзя забывать. Рекомендую материал по теме.

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

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


package domain

import (
"database/sql"
"fmt"
"time"
)

type UserStatusHistoryStore struct {
db *sql.DB
}

func New() UserStatusHistoryStore {
db, err := sql.Open("mysql", "username:password@tcp(127.0.0.1:3306)/jazzrecords")
if err != nil {
panic(err)
}

return UserStatusHistoryStore{
db: db,
}
}

func (s *UserStatusHistoryStore) Save(userID, partition, status string) {
query := fmt.Sprintf("insert into userstatushistory (user_id, status, inserted_at) values (%v, %v, %v, %v)", userID, partition, status, time.Now())
s.db.Exec(query)
}


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

Алгоритм (1/2):

0️⃣ Погружаюсь в контекст. Для этого достаточно прочитать описание задачи, по которой выполнен данный пул-реквест (далее ПР). Хорошая практика - линковать к ПР номер таски Джиры или другой системы учета тасок. В Авито, например, название git-ветки начинается с номера Jira issue (иначе линтер не пропустит), а Bitbucket это распознает и делает кликабельную ссылку, поэтому легко можно навигироваться к задаче. 

1️⃣ В первом приближении сравниваю описание задачи с фактической реализацией: смотрю в какой сервис или библиотеку сделан ПР, пытаюсь сопоставить критерии приемки с кодом, если они написаны и это вообще применимо. Часто бывает так, что по описанию задачи можно ничего не понять о том, что должно быть сделано, если, например, это задача другой команды или незнакомого домена. 

2️⃣ Если после п.1 вопросов не возникло, то ревью начинаем с первой измененной строчки, в нашем случае с обозначения пакета, обращаем внимание на нейминг. Очевидно, что название domain никак не характеризует свое содержание, поэтому первым предложением может стать переименование пакета в соответствии с назначением добавляемого функционала: storage - лучше. 

3️⃣ Далее импорты. Часто проблемой может быть их сортировка. Хотя настроенный CI/CD, конечно, не пропустит здесь вольность, но, если он вдруг не настроен и мы видим, что разработчик устроил беспорядок, то лучше ему порекомендовать исправить: например, использовать goimports или другие инструменты для форматирования, чтобы соблюсти код-стайл. 

4️⃣ Пока далеко не ушли, то следует обратить внимание на нейминг. Некорректный алиас в импортах хоть и не является блокером, но лучше также соблюдать стиль языка (рекомендации); спойлер - стараться делать кратко, используя одно существительное, если говорим про Go.

5️⃣ И снова про нейминг. Важно обращать внимание на именование переменных, функций и пр. Применительно к нашему примеру, если мы пакет рекомендовали переименовать в storage, то большинство названий можно упростить:
UserStatusHistoryStore -> UserStatusHistory и т.д. 

6️⃣ Лучшие практики. Тут многое еще зависит от специфики проекта, но применительно к нашему случаю можно предположить, что напрямую использовать db sql.DB - не очень хорошо, а лучше работать с соединениями или их пуллом, который будет инициироваться при старте приложения.

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

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

В следующем посте обсудим основные блокеры, без исправления которых ваш код не пропустят в прод 🚫
👍2
С чего начинать код-ревью? [2/2]

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

Алгоритм (2/2):

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

8️⃣ Общая архитектура (в т.ч. организация директорий в проекте). Свое ли место занимает код, правильно лил организован в пакетах, доступен ли для расширения другими командами и пр. Тема очень обширная. В чужом сервисе иногда сложно понять общую концепцию, посмотрев всего несколько файлов, но при наличии опыта плохую архитектуру видно сразу.

9️⃣ Принципиальным моментом может стать сигнатура функции. Важно обращать внимание на то, что мы передаем (и как) и что возвращаем. В нашем примере можно заметить 2 вещи: 1) Мы работаем с базой данных, но не передаем контекст (ctx.Context) а значит теряем гибкость и другие полезные возможности; 2) Передаем партицию БД в функцию, чего мы делать явно не должны на этом уровне (c партициями работаем снаружи).

1️⃣0️⃣ Нагрузка. Если у вас высоконагруженное приложение, то крайне важно обратить внимание на создаваемую вашими изменениями нагрузку. Согласована ли она с оунерами сервиса и готовы ли мы к ней? Отсюда вытекают всевозможные оптимизации, такие как использование горутин (если возможно делать несколько действий асинхроонно) и работа с ними. Частая ошибка - пересоздавать какой-нибудь объект в цикле в то время, когда он не меняется при итерациях и есть удобная возможность объявить его до.

1️⃣1️⃣ Работа с секретами. Обращайте внимание на то, как организована работа с переменными среды и различными секретами. Очевидно, что:
sql.Open("mysql", "username:password@tcp(127.0.0.1:3306)/jazzrecords") - недопустимо. Чувствительную информацию нужно получать из окружения или защищенного хранилища.

1️⃣2️⃣ Наличие уязвимостей. Так как мы работаем с БД, то важно проверить код на наличие инъекции. Подобный запрос уязвим:
query := fmt.Sprintf("insert into userstatushistory (user_id, status, inserted_at) values (?, ?, ?, ?)", userID, partition, status, time.Now())

Пользовательский ввод важно валидировать. Можно использовать различные средства предоставляемые библиотеками:

rows, err := db.Query("insert into userstatushistory (user_id, status, inserted_at) values (%v, %v, %v, %v)", user_id, status_ inserted_at)


После всех исправлений финальный код может выглядеть так:


// package domain
package storage

import (
"context"
"database/sql"
"fmt"
"os"
"time"
)

// type UserStatusHistoryStore struct {
type UserStatusHistory struct {
db *sql.DB
}

// func New() UserStatusHistoryStore {
func New() UserStatusHistory {
// db, err := sql.Open("mysql", "username:password@tcp(127.0.0.1:3306)/jazzrecords")
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/jazzrecords", os.Getenv("user"), os.Getenv("password"), os.Getenv("ip")))
if err != nil {
panic(err)
}

// return UserStatusHistoryStore{
return UserStatusHistory{
db: db,
}
}

// func (s *UserStatusHistoryStore) Save(userID, partition, status string) {
func (s *UserStatusHistory) Save(ctx context.Context, userID, status string) error {
// query := fmt.Sprintf("insert into userstatushistory (user_id, status, inserted_at) values (%v, %v, %v, %v)", userID, partition, status, time.Now())
// s.db.Exec(query)
_, err := s.db.Query("insert into userstatushistory (user_id, status, inserted_at) values (%v, %v, %v)", userID, status, time.Now())
if err != nil {
return err
}

// ...

return nil
}


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

Если вы учли все вышеописанное, то с большой долей вероятности пройдете очередное код-ревью.
👍2
👤 Делаем CV с ATS >80%

Пару недель назад вдохновился постом Jerry Lee, который опубликовал "продающее" резюме.

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

F-формат

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

XYZ

В блоке со своей карьерой соблюдайте формулу: XYZ (см. статью). Надеюсь, со временем тоже приведу к ней все полностью.

LLM считает ATS

Llama3 высоко оценила мое резюме, обозначив цифру в 84%, преимущественно снизив оценку из-за нерелевантного опыта в строительстве. Учитывайте это, подаваясь на конкретную вакансию.

Мое обновленное резюме доступно здесь. А самая первая версия выглядела так.
👍2
Апрель 2024:

навыки
✔️ Завершил курс по объектно-ориентированному программированию. Основные моменты разбирал здесь.
✔️ В рамках подготовки к собеседованию прочитал книгу “100 Go Mistakes and How to Avoid Them” и довольно подробно изучил Kafka, с которой раньше непосредственно работать не приходилось.
✔️ Написал первый пост, используя telegraph, где рассмотрел задачи с реального интервью.
✔️ Рассказал в 2-х частях как проводить код-ревью.
✔️ Завел репозиторий, где планирую выкладывать реализации основных паттернов проектирования на Go (уже выложены: observer и strategy).

карьера
✔️ Впервые за полтора года поучаствовал в техническом интервью по Go, БД и брокерам сообщений. Рефлексия здесь.
✔️ Обновил верстку своего резюме на github pages.
✔️ Обсудил с руководителем возможности для финансового роста, так как стало казаться, что моя квалификация стала опережать текущую компенсацию.
✔️ Взял на себя ответственность за онбординг нового бэкендера в команду (одна из компетенций инженера уровня senior).

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

#результаты
🔥6👍2
В конце января обозначил ОКР'ы на этот год.

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

Фокусируемся .

1. Книги: Design Patterns и System Design

📌 Закончить до 31 мая

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

-

2. Новые роли в команде: Чемпион по безопасности и эксперт подачи в своей вертикали.

📌 До 24 мая

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

-

3. Менторство: Онбординг.

📌 Ближайшие 6 месяцев продолжаю активно погружать в разработку нового бэкендера.

И, конечно, же планирую ментально разгрузиться на Праздниках (повышаем эффективность). Чего и вам желаю!
👍3
Как все успевать?

Никак. Но есть альтернатива.

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

В какой-то момент я задался вопросом: «Как все успевать, когда столько всего важного и срочного вокруг?».

Ответ меня поразил. Прозвучало: «Может быть тебе не нужно успевать все?».

* * *

У каждого человека есть ежедневная емкость (capacity) для задач, которые он может сделать с заданным качеством (определяется его опытом).

Если емкость превышена, то начинается суета, стресс, снижается эффективность и в конечном счете страдает результат. Появляется синдром «как успеть все».

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

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

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

🧾 Фреймворк

1) Выписываем все срочные и/или важные задачи на ближайшую неделю.
2) Отбираем N задач, которые хотим сделать за 1 день (число для каждого индивидуальное, у меня, например, 5-6).
3) Распределяем задачи по 3-м зонам:

🟥 - зона фокуса (делаем в первую очередь, фактически цель дня, обязательно нужно выполнить)

🟨 - зона буфера (делаем по ходу дня, сюда попадают задачи, не требующие больших трудозатрат, но которые желательно выполнить за день без привязки ко времени)

🟩 - зона резерва (делаем, если разобрались с задачами из первых двух зон, невыполнение таких задач не ведет ни к каким последствиям)

4) Все, что не успели за день, отправляется в общий список на неделю (на следующий день автоматически не переносим!).

5) Для очередного дня применяем п.2.

6) По завершении недели оставшиеся задачи оцениваем: что перестало быть актуальным, а что лучше все-таки сделать. «Полезный остаток» отправляется в общий пул задач, из которого затем формируется п.1.

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

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

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

P.S.: Какую бы систему для планирование вы ни использовали, это гораздо лучше полного отсутствия системы.
👍101🥴1
{:permitted_use_established=>

Такой строчкой нас встречает официальный документ из Росреестра, заверенный ЭЦП.

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

В чем сложность покрыть формирование PDF-файла юнит-тестами? Форма стандартная, поля фиксированные. Полагаю, что изменение структуры случается крайне редко, но даже если нет, то добавить/удалить юниты ничего не стоит.

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

Вывод один: пишите тесты, увеличивайте code coverage. Поверьте, лучше написать тесты, а потом удалить, чем так и не написать.
💯31👍1
Не шутите с индексами, не верьте гарантиям и пишите надежный код

Работа с индексами массива сопряжена со множеством проблем. Тут и классическое "IndexOutOfRange", и, конечно же, получение неверного элемента из запрашиваемой позиции.

Возьмем простой код на Go. Нужно реализовать функцию getTag, которая ожидает в качестве аргумента массив и возвращает тэг нашей фичи. У нас также есть информация о том, что этот тип аргумента - "неизменный" легаси и у нас всегда приходит массив ровно с одним элементом. Разве может что-то плохое случиться, если получать значение прямо по индексу? Это выглядит быстро и удобно.

Абстрактный Петя так и решил, подготовил пул-реквест, отправил на код-ревью. Коллеги-синьоры, конечно, одобрили, так как все выглядело логично и лаконично.

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

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


package main

func main() {
tag := getTag([]string{"feature"})
if enableFeatureByTag(tag) {
print("OK")
return
}
print("FAILED")
}

func enableFeatureByTag(tag string) bool {
return tag == "feature"
}

func getTag(values []string) string {
if len(values) == 0 {
return ""
}
return values[0]
}


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

Оказалось, что в код попало то, чего не должно там быть в принципе. Гарантия, что массив состоит из одного значения, была нарушена, соседняя команда решила добавить еще одно значение ("json"), очевидно, не слышав ни про какие договоренности. Это же массив, почему бы его так и не использовать?

* * *

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


package main

func main() {
tag := getTag([]string{"json", "feature"})
if enableFeatureByTag(tag) {
print("OK")
return
}
print("FAILED")
}

func enableFeatureByTag(tag string) bool {
return tag == "feature"
}

func getTag(values []string) string {
for _, v := range values {
if v == "feature" {
return v
}
}
return ""
}


Герои вымешлены, все совпадения случайны :)

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

1. Забудьте про явную завязку на любые индексы, используйте безопасные конструкции (например, итерация по значениям массива). Заворачивайте коллекции в обертки с безопасным доступом к значениям и т.д.
2. Не верьте договоренностям, особенно словесным. Верьте написанному коду и тому, что может произойти в нем, исходя из общей логики и передаваемых аргументов (если код ответственный, то используйте фаззинг).
3. Лучше надежный и читаемый код, чем хрупкий, но сверхоптимизированный.
4. Помните, что код пишут люди, а им свойственно ошибаться.
🤔2
Как сделать продакшн среду стабильнее?

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

В Авито это называется Live Site Review (LSR) и хорошо описано в playbook. Очевидно, идея не нова, а берет свое начало из лучших SRE практик.

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

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

1. На инцидент заводится задача, которая затем станет основным артефактом о произошедшем.
2. Опустим подробности процесса починки, который сопряжен с большим количеством "веселья" (особенно, когда начинается цепочка с призывом ответственных в канал по решению проблемы). После исправления - фиксируем все, что может помочь в дальнейшем разборе, в задаче из п.1 (обязательно должна быть ссылка на тред(ы), где обсуждалась и решалась проблема).
3. Как правило, в больших компаниях есть человек, который фасилитирует данный процесс - инцидент-менеджер. Такой человек следит за всем: от появления первого сообщения о проблеме до момента, когда работы направленные на исправление первопричин произведены и все задокументировано. Одной из обязанностей менеджера является организация встречи со всеми причастными, где будут выясняться причины произошедшего и формироваться экшн-айтемы.
4. Итак, инцидент-менеджер создал встречу и пригласил всех. Теперь необходимо вместе пробежаться по чек-листу (как правило, задача из п.1 имеет унифицированный шаблон для разбора инцидентов), собрать фактуру и зафиксировать всю информацию. Для лучшего понимания предлагаю посмотреть "список типовых вопросов, которые стоит обсудить при разборе LSR".
5. Финальным аккордом должны стать экшн-айтемы с назначенными ответственными и обозначенными сроками выполнения. Очевидно, что такие задачи имеют приоритет при взятии в работу.

За 2 года в компании меня дважды приглашали на разбор инцидента, и это всегда очень интересно. По сути, вся встреча - это мозговой штурм с ответами на вопросы: "Можно ли быстрее было среагировать на проблему?", "Почему это допустили?", "Чего не хватило при тестировании?" и пр.

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

Часто это последовательность неудачного стечения обстоятельств. Как эффект бабочки или домино: один неосторожный if'чик или взятие элемента по индексу поломало отлично работающую фичу; метрики просели, но алерты не сработали, так как были некорректно настроены; дежурный не придал значение одному из многих упавших тестов синтетического мониторинга, так как после фича-фриза все немного штормило и случалось много ложных срабатываний; в конечном итоге оперативно пофикшенный баг не мог сутки доехать до прода из-за не работающей инфраструктуры… Продолжать такую цепочку можно до бесконечности, но нужно ли? :)

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

Напишите в комментариях как в вашей компании организована практика по разбору инцидентов и насколько считаете такой процесс полезным ⤵️
👍1
Май 2024:

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

Главное, чтобы черные лебеди не выбивали вас из колеи. Взбодрились, наладили расписание и пошли дальше.

навыки

✔️ Завершил курс Быстрая прокачка в ООП (Object Calisthenics - очень интересная штука, хочется порефлексировать в отдельном посте).
✔️ Рассмотрел простые правила проектного дизайна.
✔️ Потренировался в приведении своего очень старого кода в соответствие с SRP: раз, два, три.

карьера

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

прочее

✔️ В какой-то момент у меня отвалилась фича по генерации изображений у шахматного бота, который публикует задачки в рабочий канал. Пришлось фиксить ASAP и выпускать версию v1.0.6, так как 3 раза в неделю коллеги ожидают очередную задачку :)
✔️ Ввел в свои привычки ранний подъем и спорт - эти ребята хорошо помогают оставаться эффективным целый день.

#результаты
👍3🔥3
Новиков > путь в Big Tech
В ближайшие месяцы планирую взять на себя роль Security Champion нашей продуктовой команды. Это поможет улучшить свои знания в кибер-безопасности, а также усилить свою команду экспертизой в этом направлении. Если совсем кратко, то секьюрити чемпион предупреждает…
Моделирование угроз

В начале недели перенял роль SC. Теперь являюсь амбассадором безопасности в нашей фича команде.

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

Основные этапы

1️⃣ Перед моделированием угроз сперва необходимо декомпозировать фичу, нарисовать верхнеуровневую архитектуру, описать как будут использоваться, перемещаться, обрабатываться и храниться данные в системе. Это поможет впоследствии определить узкие места и сразу обозначить возможные пути решения (необходимо будет учесть при разработке).

2️⃣ Теперь важно найти опасные угрозы. Пробуем ответить на вопрос: "Что может пойти не так?". Здесь могут работать подходы:
a) Берем библиотеку атак (крупные компании обычно организуют свою основанную на опыте), но для начала можно начать с тех, которые обозначил OWASP, и задаемся вопросами о возможных последствиях для нашей системы и ее пользователях при попытке осуществления каждой из атак.
b) Используем методику STRIDE, которую активно применяет у себя Microsoft. Такой подход подразделяет угрозы на 6 основных категорий (спуфинг, незаконное изменение, отказ в обслуживании и другие). С данной моделью работаем также, как и с библиотекой атак, задавая, например, такой вопрос применительно к незаконному изменению: "Как злоумышленник может изменить наши данные или повлиять на них?"

3️⃣ Когда угрозы обозначены, приоритизируем их:
a) Учесть сразу - решаем как обработать, заводим задачу и выполняем вместе с разрабатываемой фичой
b) Отложить на будущее - заводим задачу и кладем в бэклог (можно закрывать в рамках тех. долга)
c) Принимаем риск - если вероятность возникновения минимальная, а трудоемкость закрытия уязвимости существенная, то фиксируем данный момент в задаче или документации (если такой риск все-таки случится, то останутся артефакты о том, что мы сознательно пошли на такое решение)

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

Самые полезные материалы, чтобы провести моделирование угроз правильно:
- Шпаргалка от OWASP
- Интерактианый курс от Microsoft и его подмодуль, который позволяет за 15 минут познакомиться с темой.

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

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

Ответьте себе: стоит ли туда идти прямо сейчас с текущим опытом? И с какой целью?

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

Зачастую собеседования на такой грейд сопровождаются классическим system-design interview, где вас попросят спроектировать твиттер, ютуб или другую популярную систему.

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

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

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

Потребность в навыках system design на разных этапах:

1. Представим ситуацию, что человек имеет небольшой опыт (до 2-х лет) и занимает позицию junior/middle- разработчик. В таком случае (на мой взгляд) углубляться в проектирование может оказаться даже вредным, так как легко закопаться в обилии материала, потерять мотивацию и основной рабочий фокус.

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

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

Так как первые пункты по своей сути тривиальны, то стоит внимательнее рассмотреть №3, о чем дальше и пойдет речь.

У меня в закладках давно живут:
- дизайн праймер
- дорожная карта

И еще немало крутого материала, который стараюсь время от времени почитывать 🤓

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

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

В моем фокусе сейчас оказалось 2 проекта:
- курс по анализу систем (АС)
- курс по объектно-ориентированному анализу и проектированию (ООАП)

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

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

⚡️ Уже сейчас крупным открытием из курса по АС для меня было узнать про воркшоп Event Storming. Поставил себе цель - провести его в своей команде. Это действительно захватывающий подход к проектированию, и я про него расскажу отдельно.

Так как же все-таки научиться проектировать системы, если решили, что хотите в этом разобраться?

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

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

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

В конечном итоге, вы сделаете ощутимый скачок в своем развитии.
👍4🔥32
Секрет хорошего дизайна, о котором знают все гиганты в IT [1/2]

Рассмотрим упрощенную модель "зрелости" по реализации проектных решений разбитую на 5 уровней:

Уровень 1
- Пишем код

Уровень 2
- Пишем код -> Согласовываем

Уровень 3
- Согласовываем -> Пишем код

Уровень 4
- Согласовываем -> Пишем код -> Документируем решение

Уровень 5
- Документируем решение -> Согласовываем -> Пишем код

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

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

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

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

"Документирование решений" и "Согласования" в совокупности образуют процесс под названием "Дизайн ревью" (Design Review), который стал стандартом для разработки любых решений в Биг Техе.

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

Авито тоже не стоит на месте и постоянно оптимизирует свои процессы. Так в компании на смену дорогих архитектурных комитетов пришел Tech Design Review или просто TDR.

Как с ним работать, чтобы создавать надежные системы, поговорим во второй части.
🔥4👍1
Секрет хорошего дизайна, о котором знают все гиганты в IT [2/2]

Итак, Tech Design Review. Что за ним скрывается?

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

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

В TDR механика абсолютно такая же, а весь процесс состоит из следующих этапов:

0️⃣ Обозначаем проблему

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

1️⃣ Находим решение

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

2️⃣ Собираем вместе

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

проблема <=> описание решения <=> схема зависимостей <=> компромиссы <=> альтернативы <=> FAQ <=> нагрузка и расчеты <=> ресурсы <=> структура баз данных <=> метрики

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

Фактически общая формула такая:
проблема -> решение -> обоснование

3️⃣ Отдаем в ревью

На этом этапе у нас есть оформленная версия документа (v1.0). Выбираем экспертов, в домене которых будет происходить новая разработка. Чтобы найти экспертов можно задать 2 вопроса: "Кто владелец сервиса, на которое будет оказано влияние?" и "Кому потенциально наше решение облегчит или затруднит жизнь?".

Эксперты выбраны. Отправляем на согласование и ждем.

4️⃣ Ревью

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

🟢 - вопросов нет
🟡 - есть неблокирующие вопросы, можно начинать разработку
🔴 - такое решение нельзя запускать в прод

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

5️⃣ Завершение

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

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

Если будете углубляться в тему, то можете столкнуться с ADR (Architecture decision record) - это тоже важный документ, но представляет собой другой процесс и лучше мы рассмотрим его отдельно.

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

Но это позже, а пока продолжаем работать.
👍3
Июнь 2024:

навыки

✔️ Завершил больше половины курса по анализу систем, выполнил 4/5 всех заданий курса. Улучшил экспертизу в областях: работа с требованиями и внешними ограничениями, выделение основных частей системы при помощи Event Storming, выбор архитектурного стиля в зависимости от характеристик и пр. Ход мыслей и выполнение заданий можно посмотреть здесь.
✔️ Прошел тренинг по управлению рисками. Запомнить: важно развивать вероятностное мышление, прорабатывать возможные сценарии и помнить, что наступление любого события всегда меньше единицы.
✔️ Зарефакторил старый проект. Полезная мысль: при рефакторинге и код-ревью в первую очередь обращаем внимание на то, как код влияет на остальную часть проекта, как с ним взаимодействует.
✔️ Продолжаю практиковаться в ООАП. Переосмыслил разницу между классами анализа и дизайна (отличный мог бы выйти пост в будущем, а кому интересно копнуть уже сейчас, может начать со статьи).

карьера

✔️ Перенял роль платформенного эксперта в своей вертикали (за несколько лет накопилось немало экспертизы в одном домене, которой могу делиться с коллегами и разгружать горизонтальную команду).
✔️ Написал свой первый TDR в компании. Утвержденный документ + последующая успешная реализация проекта = хорошая основа для будущего промо на следующий грейд, но, конечно, это не гарантия, а лишь один из кирпичиков.
✔️ Подготовился к перф-ревью, собрав все артефакты за полгода работы. По окончании июльского ревью подробнее поговорим о процессе и как к нему лучше готовиться, чтобы он прошел без боли.

посты

✔️ Как сделать продакшн стабильнее и что такое LSR (читать)
✔️ Моделирование угроз - инструмент для обеспечения безопасности ваших фичей (читать)
✔️ Кому нужно изучать проектирование систем и как к этому подступиться (читать)
✔️ Секрет хорошего дизайна и при чем здесь TDR и ADR (читать)

прочее

✔️ Поучаствовал в 2-х массовых забегах: на 7.195 км и 10 км. Кажется бег начинает входить в привычку. Важно к интеллектуальной активности добавлять любую физическую - они хорошо дружат, а вы сможете делать больше.

#результаты
🔥2👍1