Уймин - про разработку
188 subscribers
3 photos
1 file
40 links
Авторский канал про backend-разработку. Подробнее - в закрепллённом сообщении.

Личиный аккаунт: @maksimuimin
Download Telegram
Чтение кода > написание кода

Чем на работе занимается профессиональный программист? “Пишет код!” - ответит любой студент или новичок в профессии. “А ещё?” - спрошу я его 😉

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

👀 Первый раз я услышал этот тезис на 2-ом курсе универа, когда поступал в Технопарк Mail.ru (сейчас ОЦ VK в МГТУ. им. Н.Э. Баумана). Я тогда тоже думал, что программисты “Пишут код!”, поэтому для меня было настоящим шоком увидеть на вступительных задачу на чтение кода. Мне тогда предложили прочитать вот эту функцию из утилиты strings и рассказать, что она делает. Читая её вдоль, поперёк и по диагонали за 20 минут я так и не смог выдавить из себя чего-то внятного 🤡

❗️ Профессиональный программист читает код чаще, чем пишет. Этот навык не менее важен, чем навык кодирования. Его можно и нужно развивать. Единственный способ прокачать чтение кода - практика, например:

1️⃣ Проводить код ревью, особенно более опытных коллег. Да, джунам полезно ревьюить работу сеньоров. При этом важно не просто просмотреть код по формальным критериям типа кодстайла, а найти ответы на следующие вопросы:
- Какую задачу решал автор патча?
- Каким образом он её решал, как работает этот код?
- Решена ли задача, будет ли этот код работать?
В общем, главная цель код ревью - это поиск багов. У меня на ревью одного патча в среднем уходит где-то 1 час. Если вы тратите на первую итерацию ревью меньше 30-40 минут, то, скорее всего, вы избегаете действительно важных вопросов 🙅‍♂️

2️⃣ Нет возможности читать код коллег - читайте код из OpenSource. Задача с утилитой strings как раз относится к этому упражнению 🙂 Разобраться в проекте - не то же самое, что разобраться в патче. Не получится прочитать весь проект, слишком много информации. Вместо этого, нужно посмотреть на него более высокоуровнево:
- Зачем нужен проект, какую задачу он решает?
- Какое API предоставляет проект?
- Какие в проекте есть модули, как они взаимодействуют между собой?
- Какие в проекте ключевые сущности (классы, структуры данных, таблицы БД)?

3️⃣ Ищите ответы на вопросы в своём софте - не в головах коллег. При выполнении задач в проектах, написанных другими разработчиками, часто появляются вопросы типа “как работает вон та штука?”. В этот момент появляется соблазн пойти к старшему коллеге, задать вопрос в лоб, получить ответ и пойти дальше код писать. Я считаю такой подход безответственным и непрофессиональным. Вместо этого, первое, что разработчику следует сделать - выполнить поиск по кодовой базе проекта, например так:
fgrep -re "some interesting stuff" ./src | fgrep -v "filtering out boring stuff, like third_party"

👆 Это мощнейший драйвер роста твоих навыков! Даже если ты в итоге не найдёшь то, что ищешь, ты придёшь к коллегам уже с другим вопросом:
Я решаю задачу X, для этого мне нужно знать Y. Я поискал в проекте запросами A и B, но ничего не нашёл. Что я упускаю?

☝️ Так ты найдёшь не только ответ, но и навыки поиска прокачаешь, и с проектом по-ближе познакомишься. Профит x3 🔥

🧐 Многие недооценивают навык чтения кода, и это большая ошибка - его можно и нужно тренировать.

🕹 Интерактив: у моей компании есть вот такой код в на гитхабе: https://github.com/mailru/tntlua/blob/master/spammerdb.lua

Дано: Там есть 2 функции get_value и set_value, они работают со структурой данных, которая называется flags. Известно, что переменная stype может принимать только 4 разных значения: 0, 1, 2 или 3

Вопрос: что такое flags, какой тип данных там хранится?

Ответ: `flags` - это число размером в 1 байт. Там хранится массив из 4-ёх элементов размером 2 бита каждый. Каждый элемент - это `stype`, так что `flags` - это массив из 4-ёх `stype`’ов.

Ставьте , если читаете код каждый день 🔥

#hardskills #codereading #selflearning
🔥5
Паттерн early exit

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

📍 В чём суть: когда в вашем алгоритме появляется оператор ветвления (if, switch и т.п.), короткую ветвь вычислений надо обработать перед длинной ветвью.

ℹ️ Пример:
- Без early exit
if user.isAuthorized() {
// Do
// some
// business
// logic
} else {
return errors.New("403 Anauthorized")
}

- То же самое, но с early exit:
if !user.isAuthorized() {
return errors.New("403 Anauthorized")
}
// Do
// some
// business
// logic


У early exit подхода есть ряд преимуществ:

1️⃣ Снижается вложенность операторов - это упрощает чтение кода.

2️⃣ Повышается фокус на основной путь выполнения функции - часто, когда дочитываешь длинную (вероятно, главную) ветвь выполнения кода, уже забываешь, зачем выше было ветвление и в чём смысл короткой ветви. Early exit позволяет быстро прочитать короткую ветвь и забыть о ней, сфокусировавшись на длинной ветви. В итоге, программисту нужно меньше “оперативной памяти” чтобы прочитать код 😊

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

4️⃣ Если в вашем языке нет defer'ов и сборки мусора, разновидность early exit упрощает корректную деаллокацию ресурсов. Пример:
void foo() {
void *a = malloc(1024);
if (!a)
goto out_a;

void *b = malloc(1024);
if (!b)
goto out_b;

void *c = malloc(1024);
if (!c)
goto out_c;

/*
* Метки позволяют деаллоцировать только те ресурсы,
* которые были успешно аллоцированы
*/

free(c);

out_c:
free(b);

out_b:
free(a);

out_a:
return;
}

^ такой подход особенно популярен в ядре Linux: раз, два, три. Думаю, авторы этого кода что-то знают о программировании 😉

💡 Итого: при использовании операторов ветвления короткие ветви алгоритма следует обрабатывать перед длинными. Этот подход называется early exit. Он позволяет писать более простой и корректный код.

Ставь огонёк, если используешь early exit в своей работе 🔥

#hardskills #coding #pattern #bestpractice #codereading
🔥5
Главный источник знаний в проекте

Этот маленький засранец знает ответы на самые сложные вопросы:
- Сколько тредов запускает приложение?
- На каких серверах запущен nginx?
- Какие сервисы ходят в эту БД?

Вот он, святой грааль разработчика:
 fgrep -rie "pthread_create" ./src


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

Grep - это семейство утилит для текстового поиска. Я чаще всего пользуюсь такими вариантами грепа, как:
- fgrep - простой текстовый поиск, никакие символы в поисковом запросе не имеют специального значения
- grep - текстовый поиск по регулярным выражениям
- zgrep / zfgrep - всё то же самое, но позволяет искать по сжатым gzip-файлам без необходимости полной декомпрессии. Используется редко, но бывает полезно для поиска по историческим логам.

Самые важные флаги grep-утилит (одинаковые для всех вариантов):
- -r - рекурсивный поиск по директории, именно этот флаг позволяет искать “по всему проекту” или “по какой-то части проекта”.
- -i - включает case-insensitive поиск (это когда заглавные и строчные буквы интерпретируются одинаково, т.е. между “А” и “а” нет никакой разницы).
- -e - включает extended regexp syntax, я уже привык к этому синтаксису, поэтому включаю этот флаг всегда по привычке. Для fgrep он ничего не делает.
- -v - исключающий поиск, это когда мы ищем “всё, кроме <поисковый запрос>”

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

0️⃣ Начинаем с вопроса: что мы хотим найти? Например, “кто ходит в сервис А” или “сколько соединений открывает сервис Б”. Далее, выбираем область поиска. Если твой вопрос по внутреннему устройству какого-то софта, ищем по его исходному коду. Если твой вопрос про конфигурацию (взаимодействие между сервисами или продакшен-настройки), ищем по IaC репозиторию, если у твоей компании он есть. Например, мы используем Puppet и Kubernetes, многие пользуются Ansible. Не стесняйтесь отсекать директории, в которых точно нет ничего полезного. Например, искать по ./src вместо ., чтобы не заходить в ./third_party, ./vendor или ./node_modules - это сильно ускоряет процесс.

1️⃣ Дальше выполняем рекурсивный поиск. Я убеждён, что самое главное в этом вопросе - контроль фокуса. Мы не хотим найти слишком много результатов, глаз будет замыливаться и можно пропустить что-то важное. Поэтому начинаем с самого простого fgrep -re

2️⃣ Если ничего не нашли, можем расширять поисковый запрос. Добавить флаг -i или перейти на grep и поиск по регулярке.

3️⃣ Скорее всего, после расширения запроса в поисковую выдачу попадёт что-то лишнее. Не стесняемся добавлять | grep -v в конец запроса и отсекать ненужные варианты.

4️⃣ В конце концов, ты либо найдёшь, что ищешь, либо сдашься и пойдёшь спрашивать помощи у коллег. Второй вариант на самом деле неплохой, но тут тоже есть один трюк. Скорее всего, коллега, который ответит тебе на вопрос, тоже этот ответ как-то найдёт. Невозможно запомнить все нюансы и тонкости в большой системе, но возможно научиться находить эту информацию. И трюк тут в том, чтобы после ответа на свой вопрос спросить: “А как ты это нашёл?” Это гораздо важнее, чем сам ответ, потому что позволит развить навыки поиска информации и, в конченом итоге, повысить самостоятельность.

Этот простой алгоритм, когда я был джуном, стал мощным драйвером роста моих навыков, и я им пользуюсь до сих пор. В следующий раз, когда у тебя возникнет вопрос по проекту, не спеши обращаться к коллегам, попробуй найти ответ сам! Ну и grep в помощь, куда же без него 🔥

#hardskills #codereading #selflearning #Linux #tools
3🔥2
Комментарии для сверхразумов

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


Мой код в то время часто выглядел так:
// Это функция main. С неё начинается выполнение программы.
int main() {
}


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

Когда стоит писать комментарии?
 В начале программы или модуля: какую задачу выполняет.
 Перед математикой: формулы и алгоритмы сложны для восприятия и требуют пояснений.
⚠️ При объявлении функции: что она делает, какие у неё аргументы и возвращаемые значения. Почему функция написана именно так и в каких ситуациях её предполагается использовать.
⚠️ При объявлении структуры: жизненный цикл объекта и смысл полей. Специфичные свойства, например иммутабельность.
 Код выглядит сложно без комментариев: лучше сразу перепишите код.
 Если позвать функцию <вот так>, то всё сломается: эта проверка должна быть в коде.

Комментарии нужны для управления фокусом при чтении кода. Они должны подсвечивать важное и игнорировать незначительное. Только в этом случае от комментов есть польза 🔥

#hardskills #codereading #coding #antipattern
🔥6💯1