Битмап / словарь разработчика
510 subscribers
71 photos
1 video
71 links
Всё, что должен знать настоящий сеньор — короткие, но ёмкие заметки о разработке, инструментах, практиках, бизнесе. Выходят каждый день. Подписывайся!
加入频道
Парное программирование — это когда два программиста работают за одним компьютером.

Один пишет код, а другой наблюдает, предлагает улучшения и подмечает ошибки. Через полчаса-час они меняются ролями.

Плюсы: улучшение качества кода, обмен знаниями, повышение сплочённости команды.

⛔️ Минусы: требует больше времени и ресурсов, может быть утомительным для участников.

Практика была предложена Кентом Беком, автором экстремального программирования.

🔍 Представьте, что вы новоиспечённый тимлид в команде разработки партнёрского кода Рекламной сети Яндекса.

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

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

* Это не выдуманная история, а моя личная, из практики. Ваня, привет, если ты вдруг это читаешь! 😁

🔗 https://ru.wikipedia.org/wiki/Парное_программирование
😁15
Пост-знакомство

Меня зовут Олег Громов, и я приветствую тебя на канале Битмап!

🦸‍♂️ Я — человек-оркестр. Люблю проектировать и создавать полезные системы от начала и до конца. Мне неплохо даётся дизайн, написание текстов, маркетинговые активности и анализ их результатов. Умею нанимать и организовывать работу команды так, чтобы важные цели достигались, а людям было хорошо.

📝 Немного фактов обо мне
• Я тимлид команды AI tools и бэкендер в edtech-стартапе Oneday
• Живу в Лондоне, у меня Global Talent виза. Долго жил в Москве, гостил в Штатах и Швеции по полгода
• 3 года тимлидил в Яндексе в Рекламной сети, почти 2 года — в Toptal
• Провёл 200-250 собеседований разработчиков, немного дизайнеров и менеджеров. Сам прошёл (или провалил) порядка сотни
• Посмотрел на зарубежные бигтехи (Фейсбук, Klarna) и стартапы (Sourcegraph, Hook и пр.) изнутри
• Написал популярные статьи про удалёнку за доллары
• Запускаю разные сайд-проекты, включая этот канал

🔗 У меня есть сайт, линкедин, а также личный канал. А вот ссылки на мои перфомансы в интернете на русском и на английском.

❤️ Я даю платные личные консультации:
• развитие хард- и софт-скиллов, код-ревью
• планирование карьеры и релокация
• сайд-проекты

🏢 И для компаний:
• аудит веб-приложений, сайтов и их производительности
• аудит состояния кодовой базы
• помощь в настройке командных процессов и найма
• проведение собеседований
• создание и поддержка MVP

Записаться по ссылке: https://forms.gle/MyqcJCxZ6Phhzzi47
🔥11😁21
Поиск в глубину (DFS) — алгоритм обхода графов и деревьев.

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

DFS применяют для поиска пути и циклов в графах, в топологической сортировке (например, для построения графа зависимостей).

Сложность по времени: O(V + E).
💾 По памяти: O(V).

V — количество вершин, E — количество рёбер.

🔥 Плюсы: просто реализовать, особенно рекурсивную версию. Работает на направленных и ненаправленных графах.

⛔️ Минусы: не всегда находит кратчайший путь.

📝 Пример реализации для графа в виде списка смежности:
def dfs(graph, start, visited=None):
visited = visited or set()
visited.add(start)

print(start)

for next in graph[start] - visited:
dfs(graph, next, visited)
return visited

graph = {
'A': {'B', 'C'},
'B': {'A', 'D', 'E'},
'C': {'A', 'F'},
'D': {'B'},
'E': {'B', 'F'},
'F': {'C', 'E'}
}
dfs(graph, 'A')


🔗 https://ru.wikipedia.org/wiki/Поиск_в_глубину
👍6
Lean startup — способ работы над стартапом, когда команда проходит следующий цикл, пока не найдёт работающий продукт:

1️⃣ выдвинули измеримую гипотезу, обновили продукт
2️⃣ запустили обновлённый MVP, показали пользователям, измерили результаты
3️⃣ сделали выводы и вернулись в п.1

Методология была предложена и популяризована с выходом одноимённой книжки Eric Ries в 2011 году.

🚀 Плюсы: ускоряет вывод продукта на рынок. Поощряет регулярный сбор обратной связи от клиентов.

😞 Минусы: MVP могут не давать достаточно ценности клиентам. В череде пивотов легко потерять стратегию и видение (vision).

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

📝 Например, Dropbox творчески использовали этот подход, чтобы подтвердить спрос на свой продукт.

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

🔗 https://ru.wikipedia.org/wiki/Бережливый_стартап
👍3
— Какой XML-парсер лучший?
— rm your-file.xml

😂
😁16👍3🤔1
С праздником, коллеги! 🎉
🎉15
Same-origin policy (SOP) — механизм безопасности в браузерах, который частично запрещает обмен данными между разными origin.

Origin — это комбинация (protocol, hostname, port). Например, evil.com и bank.ru — разные origin, т.к. у них разный домен.

📚 Допустим, вы залогинились в bank.ru, а потом открыли evil.com. Его владелец вставил следующий скрипт:
fetch('http://bank.ru/transfer?amount=100000&to=<evil_account>', {method: 'POST'})

Если бы не SOP, браузер сделал бы этот запрос, отправив вместе с ним cookies, а значит потенциально выполнил бы запрос на перевод денег от вашего лица.

⚠️ Кроме этого, SOP также запрещает читать чужие cookies из JS, получать доступ к window и прочим внутренностям чужих сайтов, вставленных в iframe и кучу других мелочей.

SOP появился в Netscape Navigator 2 вместе с первой версией JavaScript ещё в 1995 году.

А уже спустя много лет появился CORS, Cross-origin Resource Sharing, который позволяет обойти SOP.

🔗 https://developer.mozilla.org/ru/docs/Web/Security/Same-origin_policy
🔥14👍2
JSON5 — это расширение формата JSON, которое поддерживает:

• комментарии /* */ и //
• висячие запятые в массивах и объектах: [1,2,]
• строки в одинарных кавычках: 'bitmap'
• ключи без кавычек, если это валидные JS-идентификаторы
• перенос строк с помощью \ в конце строки вместо \n
• 16-ричные числа: 0xCOFFEE
• пропущенный ноль в десятичных дробях: .41468
• плюс в положительных числах +3.14
Infinity, -Infinity и NaN, как в IEEE 754

Для поддержки JSON5 нужны сторонние библиотеки, например, json5 для node или json5 для python.

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

📝 Так выглядит пример JSON5:
{
// видали, как можно
bitmap18: 'твой любимый "cловарик"'
yo: "Привет! \
Уже рассказал друзьям о @bitmap18?",
i_love: 0xCOFFEE,
syntax_sugar: [.41468, +1, ],
}


🔗 https://json5.org/
👍9😁3🤔1
Пятница! Наработались уже? 🙃
Кидаем мемы в коменты!
😁9
SELECT FOR UPDATE — способ избежать состояния гонки (race condition) и взаимных блокировок в UPDATE, исполняющихся одновременною

Поддерживается в Postgres, MySQL c InnoDB, Oracle.

📚 Например, пользователь покупает товары 1 и 4 в интернет магазине, и нам надо обновить остатки в БД:
BEGIN;

SELECT *
FROM product_qty
WHERE product_id IN (1,4)
ORDER BY product_id
FOR UPDATE;

UPDATE product_qty
SET qty = qty - 1
WHERE product_id IN (1,4);

COMMIT;

🎯 Как это работает:

1️⃣ начинаем транзакцию

2️⃣ делаем SELECT ... FOR UPDATE: обновляем несколько строк, значит нужно использовать ORDER BY

3️⃣ дальше обычный UPDATE

4️⃣ наконец, COMMIT, чтобы завершить транзакцию и снять блокировки

Без ORDER BY в п.2 одновремено исполняющиеся транзакции могут попытаться взять блокировки в разном порядке, что может привести к дедлоку.

⚠️ В зависимости от уровня изоляции транзакций, другие SELECT без FOR UPDATE могут получить устаревшие значения.

🔗 https://ru.wikipedia.org/wiki/Select_for_update
👍13
Транзистор — полупроводниковый компонент, который используется для усиления и преобразования аналоговых сигналов (например, звука), а также в качестве переключателя (ключа, switch) для цифровых сигналов.

📅 Изобретен в 1947 году в Bell Labs тремя учеными: Джоном Бардином, Уолтером Браттейном и Уильямом Шокли.

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

🥇 Его создатали получили за своё изобретение Нобелевскую премию по физике в 1956 году.

Количество транзисторов в процессорах увеличилось от всего 2,250 штук в Intel 4004, выпущенном в 1971 году, до сотен миллиардов в самых современных процессорах.

Их размеры за это же время уменьшились до всего лишь десятков атомов: транзистор произведённый по 5-нм техпроцессу имеет размер около 70 атомов в ширину.

А вот как выглядит первый в мире транзистор ⬇️

🔗 https://www.youtube.com/watch?v=xvrjIJw3OSU
👍11
🤗 На прошлой неделе мы писали про:

- Задача двух генералов
- Сериализация
- Парное программирование
- DFS
- Lean-стартап
- Same-origin policy
- JSON5
- SELECT FOR UPDATE
- Транзистор

❤️‍🔥 Может, уже что-то пригодилось?
🔥6👍2
Десериализация — воссоздание объекта или структуры данных в памяти из его представления в виде строки байт/символов. Обратный сериализации процесс.

В отличие от парсинга, который обычно работает на произвольных входных данных — например, создаёт AST (abstract syntax tree) из исходного кода, десериализация чаще подразумевает использование определённой схемы.

Очевидно, что JSON или XML не ограничивают схему — потребуется JSON Schema или подобное решение.

🔍 Или можно попробовать взять protobuf, где типы обязательны. Создадим вот такой channel.proto:
syntax = "proto3";

message Channel {
string handle = 1;
int32 subscribers = 2;
}

Скомпилируем его для использования в python: protoc channel.proto --python_out=.

А затем десериализуем строку байт в объектное представление этого типа:
import channel_pb2

channel = channel_pb2.Channel()
channel.ParseFromString(b'\n\x07@bitmap\x10\x90N')

print(channel)

# handle: "@bitmap"
# subscribers: 10000


🔗 https://ru.wikipedia.org/wiki/Десериализация
👍2
Суррогатный ключ — сгенерированный уникальный идентификатор строки в реляционной БД.

💎 Зачем они нужны?

Скажем, в таблице Users натуральным ключом может быть:
email или phone
username
• комбинация first_name, last_name, birthday

⛔️ Натуральные ключи имеют недостатки:

• при обновлении ключа придётся обновлять и связанные таблицы

• требования к уникальности меняются: бизнес может разрешить разным клиентам использовать один email или телефон

• их опасно использовать в публичных URL, API и т.п.

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

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

📖 Суррогатный ключ можно сделать из монотонно растущего INTEGER:

CREATE TABLE Users (
user_id SERIAL PRIMARY KEY,
username VARCHAR(255),
email VARCHAR(255) NOT NULL,
);

Или же взять рандомный или около-рандомный идентификатор, например, UUID.

🔗 https://ru.wikipedia.org/wiki/Суррогатный_ключ
👍8
Пивот (pivot) — это серьёзное изменение в бизнес-модели или стратегии стартапа.

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

• продукт и его позиционирование
• целевую аудиторию
• способ привлечения и удержания клиентов

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

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

📚 Например, ваш стартап изначально делал приложение для фитнеса, ориентированное на профессиональных спортсменов.

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

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

🔗 https://ru.wikipedia.org/wiki/Пивот
👍5😁4
Stack overflow — ошибка, когда программа пытается использовать больше памяти на стеке, чем разрешено операционной системой.

📌 Обычно случается при:

• слишком большой глубине рекурсивных вызовов
• большом количестве локальных переменных

📖 Например, на моей MacOS максимальная глубина стека — 8172 Кб (ulimit -s). Если какая-то программа попробует использовать больше, ОС прервёт её выполнение.

Скомпилируем простейшую программу:

#include <stdio.h>

void go(int n) {
printf("%d\n", n);
go(n + 1);
}

int main() {
go(1);
return 0;
}

без оптимизаций (gcc -o test test.c) и запустим:

...
261471
[1] 78367 segmentation fault ./test

Программа попыталась занять больше памяти на стеке, чем разрешено ОС, и была завершена.

Если увеличить размер стека, например, до 16 Мб (ulimit -s 16384), то ошибка случится позже.

А если включить оптимизации через флаг -O2 в gcc, то она сможет работать бесконечно, т.к. комплиятор "развернёт" рекурсию в цикл — cм. комментарии.

🔗 https://en.wikipedia.org/wiki/Stack_overflow
🔥5
sort — это утилита в unix-подобных ОС для сортировки строчек в текстовых файлах.

🧩 Полезные ключи:

-t, — указать разделитель колонок ,
-k5,5 — сортировка по 5-й колонке
-n — числовая, а не лексикографическая (алфавитная) сортировка
-g — поддержка чисел с плавающей запятой
-r — обратная сортировка

📚 Возьмём файл с заказами orders.csv:
id,fname,lname,pid,qty,date,addr,price
1,Иван,Иванов,101,2,2024-09-01,Ленина 123,4000
2,Анна,Смирнова,202,1,2024-09-02,Пушкина 45,1999
3,Борис,Петров,303,3,2024-09-03,Гоголя 78,5998
4,Ольга,Кузнецова,404,1,2024-09-04,Чехова 90,2999
5,Алексей,Морозов,505,2,2024-09-05,Толстого 123,5000

Отсортируем по цене: sort -t, -k8,8nr orders.csv.

По фамилии: LC_ALL=C.UTF-8 sort -t, -k3,3 orders.csv.LC_ALL=C.UTF-8 необходим для поддержки юникода.

🌟 Как и другие unix-утилиты, sort удобно объединять с другими командами через |.

Например, отсортируем заказы по pid и возьмём только 3 поля: sort -t, -k4,4 orders.csv | cut -d, -f4,3,8

🔗 https://ru.wikipedia.org/wiki/Sort_(Unix)
👍6
hash в python позволяет получить хэш любого неизменяемого объекта, например, int, float, строки или tuple.

Скажем, hash('@bitmap18 лучше всех') == -952311228443755449.

🎯 Используется в словарях (dict), чтобы определить, где хранится значение (в каком bucket) для ключа, и множествах (set), чтобы понять, есть ли в нём данный ключ.

Также можно определить дандер-метод __hash__ для любого класса.

📖 Скажем, у нас есть класс Customer, и хочется создать список пользователей без дубликатов.

Для этого отлично подойдёт set():
class Customer:
def __init__(self, id, email):
self.id = id
self.email = email

def __hash__(self):
return self.id

customers: Iterable[Customer] = get_customers()
unique_customers = set(customers)

Без заданного Customer.__hash__ получилось бы создать set, только используя идентификаторы напрямую:
unique_customers = set(c.id for c in customers)

Что, конечно, менее элегантно.

🔗 https://www.programiz.com/python-programming/methods/built-in/hash
👍5
Мне кажется, это очень хорошо!

А вы говорите "на русском"?
🏆9😁5