├── .gitignore ├── README.md ├── interview_notes ├── brokers.md ├── computer_science.md ├── databases.md ├── isolation_levels_guide.sql ├── python.md └── web.md └── interview_questions.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # База знаний для Python backend разработчиков 2 | 3 | ## Теория для подготовки к собесам 4 | * [Python](https://github.com/nightblure/Python-backend-knowledge-base/blob/main/interview_notes/python.md); 5 | * [Web](https://github.com/nightblure/Python-backend-knowledge-base/blob/main/interview_notes/web.md); 6 | * [Базы данных](https://github.com/nightblure/Python-backend-knowledge-base/blob/main/interview_notes/databases.md); 7 | * [Брокеры/очереди сообщений](https://github.com/nightblure/Python-backend-knowledge-base/blob/main/interview_notes/brokers.md); 8 | * [Computer Science](https://github.com/nightblure/Python-backend-knowledge-base/blob/main/interview_notes/computer_science.md); 9 | 10 | --- 11 | 12 | ## FastAPI/SQLAlchemy 13 | * [Серия видео по FastAPI x SQLAlchemy x Pydantic (автор - Сурен Хоренян)](https://www.youtube.com/@SurenKhorenyan/videos) 14 | * [FastAPI, SQLAlchemy, Pydantic and etc (автор - Артем Шумейко)](https://www.youtube.com/@artemshumeiko/playlists) 15 | 16 | --- 17 | 18 | ## Usable code 19 | * [injection - фреймворк для внедрения зависимостей](https://github.com/nightblure/injection) 20 | 21 | * [Много полезного бойлерплейта на каждый день](https://github.com/nightblure/boilerplate) 22 | 23 | * [Сервис авторизации на базе JWT (FastAPI, integration and unit tests)](https://github.com/nightblure/jwt_auth) 24 | 25 | * [Flask x Kubernetes x Helm](https://github.com/nightblure/flask-x-helm-x-k8s) 26 | 27 | * [Реализация отказоустойчивого кластера RabbitMQ с балансировщиком нагрузки HAProxy + Docker](https://github.com/nightblure/Python-x-RabbitMQ-failover-cluster) 28 | 29 | * [Реализация простого примера асинхронной логической репликации с Django и PostgreSQL](https://github.com/nightblure/pg_replica_app) 30 | 31 | * [Оптимальные и проверенные решения алгоритмических задач с Leetcode + немного теории](https://github.com/nightblure/Leetcode) 32 | 33 | --- 34 | 35 | ## Tooling (package managers, linters and etc.) 36 | * [uv](https://github.com/astral-sh/uv) 37 | * [Hatch](https://github.com/pypa/hatch) 38 | * [ruff](https://github.com/astral-sh/ruff) 39 | 40 | --- 41 | 42 | ## Dependency injection 43 | * [injection](https://github.com/nightblure/injection); 44 | * [that-depends](https://github.com/modern-python/that-depends); 45 | * [python-dependency-injector](https://github.com/ets-labs/python-dependency-injector). 46 | 47 | --- 48 | 49 | ## Opensource code 50 | 51 | * [Apache Superset](https://github.com/apache/superset) 52 | * [Netflix Dispatch](https://github.com/Netflix/dispatch) 53 | * [Бэкенд сайта Школы сильных программистов на Django/DRF](https://github.com/tough-dev-school/education-backend) 54 | * [Cosmic Python (DDD, event sourcing, CQRS and etc.)](https://github.com/cosmicpython/code) 55 | * [testcontainers](https://github.com/testcontainers/testcontainers-python) 56 | 57 | --- 58 | 59 | ## Django & Django REST Framework (DRF) 60 | * [Бесплатный курс по Django от Сергея Балакирева](https://youtube.com/playlist?list=PLA0M1Bcd0w8xO_39zZll2u1lz_Q-Mwn1F) 61 | * [Теория по DRF на русском языке](https://github.com/ilyachch/django-rest-framework-rusdoc) 62 | * [Бесплатный курс по DRF от Сергея Балакирева](https://youtube.com/playlist?list=PLA0M1Bcd0w8xZA3Kl1fYmOH_MfLpiYMRs) 63 | 64 | --- 65 | 66 | ## Testing [pytest] 67 | 1. [Документация](https://pytest-docs-ru.readthedocs.io/ru/latest/contents.html) для ```pytest``` на русском языке 68 | 2. [Полезный чек-лист](https://stribny.name/blog/pytest/#web-apps) для ```pytest``` (пробежка по общим вещам + обвесы по типу многопоточного запуска тестов, плагинов и т.д.) 69 | 3. [Цикл из 7 статей про pytest на Habr](https://habr.com/ru/post/448782/). Много инфы про фишки и разные возможности ```pytest``` 70 | 71 | --- 72 | 73 | ## ООП/SOLID 74 | * [Хороший источник на русском языке про принципы SOLID](https://solidbook.vercel.app/dip) 75 | 76 | --- 77 | 78 | ## Асинхронность, многопоточность и многопроцессность 79 | * [Computer Science Center: Многопоточность и GIL](https://www.youtube.com/watch?v=nR8WhdcRJwM&ab_channel=ComputerScienceCenter) 80 | * [Computer Science Center: Быстрее, Python, ещё быстрее](https://www.youtube.com/watch?v=-lMiAKKyLFI&ab_channel=ComputerScienceCenter) 81 | * [Отличное видео про асинхронность, многопоточность и многопроцессность в Python](https://youtu.be/_4QY1nGFRY8) 82 | 83 | --- 84 | 85 | ## Вопросы на собеседовании 86 | [Списочек вопросов для HR, технических спецов и команды](https://github.com/nightblure/Python-backend-knowledge-base/blob/main/interview_questions.md) 87 | 88 | --- 89 | 90 | ## Мои контакты 91 | * [Telegram](https://t.me/nightblure) 92 | 93 | -------------------------------------------------------------------------------- /interview_notes/brokers.md: -------------------------------------------------------------------------------- 1 | # Apache Kafka 2 | 3 | ## Гарантии доставки 4 | 5 | У **паблишера** можно указать параметр `acks` с одним из значений: 6 | - **none** - не ждать подтверждения (семантика **most once**); 7 | - **one** - ждать подтверждение от лидера (семантика **least once**); 8 | - **all** - ждать подтверждения от лидера и `in-sync` реплик (семантика **least once** с повышенной надежностью). 9 | 10 | У **консьюмера** есть следующие возможности: 11 | 1. `offset commit` **до обработки сообщения** (семантика **most once**); 12 | 13 | 2. `offset commit` **после обработки сообщения** - 14 | сообщение не теряется, но может быть повторно обработано, если в консьюмер упадет (семантика **least once**): 15 | 16 | Семантика **exactly once** достигается за счет: 17 | - **идемпотентных продюсеров** (конфиг параметр `enable.idempotence=true`); 18 | - **транзакции** kafka. 19 | --- 20 | 21 | ## Разные вопросы 22 | * **гарантия порядка сообщений**: **гарантируется** только **в рамках одной партиции**; 23 | 24 | 25 | * **DLQ/DLT** - можно сделать мидлварь и при ошибках скидывать сообщения в заранее выделеный топик; 26 | 27 | 28 | * **как параллельно обрабатывать данные из одного топика** - для **параллельного** чтения данных из топика 29 | нужно **объединить консьюмеров в консьюмер-группу** с помощью указания одинакового **идентификатора группы** 30 | (_каждая партиция будет назначена своему выделенному консьюмеру_); 31 | 32 | 33 | * **запись в определенную партицию** можно сделать с помощью **ключа партиции**, **указываемого у продюсера**; 34 | 35 | --- 36 | 37 | ## Отличия RabbitMQ от Apache Kafka 38 | 39 | 1. **RMQ** работает по **push**-модели (**консьюмеры сами получают сообщения**), 40 | а **Kafka** реализует **pull**-модель (**консьюмеры сами ходят в кафку за сообщениями**); 41 | 42 | 2. **RMQ удаляет сообщения** из очереди после их обработки и подтверждения (**acknowledgment**), 43 | **Kafka хранит сообщения на диске** в соответствии с _retention policy_; 44 | 45 | 3. **RMQ** умеет в гибкую маршрутизацию сообщений. 46 | --- 47 | -------------------------------------------------------------------------------- /interview_notes/computer_science.md: -------------------------------------------------------------------------------- 1 | ## Разница между контейнеризацией и виртуализацией (ВМ) 2 | 3 | ВМ имеет полноценную операционную систему. Виртуализация осуществляется средствами железа 4 | 5 | Контейнеры в свою очередь виртуализированы средствами ОС, поэтому они менее изолированы 6 | 7 | --- 8 | 9 | ## Почему float имеет погрешность или почему 0.1+0.2 != 0.3? 10 | 11 | CPU владеет только двоичной арифметикой. 12 | Поддержка чисел с плавающей запятой `float` реализуется **аппаратно**, а не программно (в отличие от Decimal). 13 | 14 | Проблема в том, что не все числа можно точно представить в двоичной системе счисления - это и есть причина неточности float 15 | 16 | --- 17 | 18 | 19 | -------------------------------------------------------------------------------- /interview_notes/databases.md: -------------------------------------------------------------------------------- 1 | ## Материализованное представление 2 | 3 | Материализованное представление – это **копия результатов запроса**. 4 | Данные из запроса, связанного с материализованным представлением, 5 | будут сброшены на диск (**закэшированы**), что увеличит скорость доступа к данным такого представления. 6 | 7 | _Материализованное представление нужно обновлять вручную для поддержания актуальности данных_! 8 | 9 | --- 10 | 11 | ## Индексы 12 | 13 | **Индекс** – объект, создаваемый с целью повышения производительности поиска данных. 14 | **Индекс хранит ссылки на страницы**, в которых лежат записи. 15 | 16 | Индексы могут уменьшить производительность, если применяются в таблицах, 17 | где часто происходят операции *INSERT*, *DELETE* и *UPDATE*, 18 | т.к. меняя содержимое таблицы нужно перестраивать и ее индексы. 19 | 20 | **Индексы занимают дополнительный объем памяти**, т.к. хранятся на диске. 21 | 22 | | **Индекс** | **Кейсы для применения** | 23 | |---------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 24 | | ***btree*** – **сбалансированное дерево**. Является индексом по умолчанию*.* Наиболее часто применяемый вид индекса | Любые данные, с которыми можно проводить **операции сравнения** | 25 | | ***hash*-индексы** – хеширование значений индексированного поля таблицы | **Работает только с простыми условиями равенства** Используется *PostgreSQL* для соединения таблиц, если у таблиц нет индексов. СУБД временно создает хеш-индексы для таблиц, соединяет их и затем удаляет хеш-индексы. | 26 | | ***GiST (R-Tree)*** | Позволяет индексировать значения, перекрывающиеся между собой. Это могут быть значения многомерных структур хранения данных типа координат в многомерном пространстве Индексация географических типов данных | 27 | | ***GIN* (инвертированный индекс)** | Полнотекстовый поиск, поиск по *JSON*-полям | 28 | | **Частичный индекс** | Применяется, когда нет цели индексировать данные целиком. **Пример**: *CREATE INDEX idx_table_field ON table (field) WHERE field IS NOT NULL* **Недостаток**: чтобы индекс применялся, необходимо в запросы «таскать» выражение, указанное при создании индекса (в примере это выражение *IS NOT NULL*). | 29 | | **Функциональный индекс** | Применяется, когда есть необходимость проиндексировать не сами значения, а результаты функций от этих значений. **Пример**: *CREATE INDEX idx_table_field ON table (LOWER(field))* **Недостаток**: чтобы индекс применялся, необходимо в запросы «таскать» выражение, указанное при создании индекса (в примере это выражение *LOWER(field)*). | 30 | | **Кластерный индекс** | Кластеризация сортирует данные по указанному индексу. То есть она применяется к таблице и ранее созданному индексу Кластеризация является одноразовой операцией: последующие изменения в таблице нарушают порядок кластеризации | 31 | 32 | --- 33 | 34 | ## Оптимизация запросов 35 | 36 | Сначала нужно понять к каким данным СУБД обращается чаще всего и какие запросы выполняются дольше всего. 37 | 38 | **Долгое выполнение запросов может быть связано с внешними факторами**: 39 | например, в момент выполнения запроса выполнялось резервное копирование или в то же 40 | время сервер обрабатывал другие тяжелые запросы. **То есть дело может быть не в самом запросе.** 41 | 42 | **1 шаг (статистика)**: собрать статистику выполнения запросов, например, с помощью расширения ***pg_stat_statements***. 43 | Сначала нужно активировать расширение в файле конфигурации ***postgresql.conf***, добавив в него строки: 44 | 45 | ```bash 46 | shared_preload_libraries = ‘pg_stat_statements’ 47 | -- соберет статистику по 1000 наиболее используемых запросов 48 | pg_stat_statements.max = 1000 49 | pg_stat_statements.track = all 50 | ``` 51 | 52 | **Обращение к статистике**: 53 | 54 | ```sql 55 | SELECT 56 | query, calls, total_time, rows, 57 | 100.0 * shared_blks_hit / nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent 58 | FROM pg_stat_statements 59 | ORDER BY total_time DESC LIMIT 10; 60 | ``` 61 | 62 | **1 шаг (альтернативный способ: лог)**: подключить в ***postgresql.conf*** логирование запросов, 63 | время выполнения которых **превышает заданную величину** в миллисекундах: 64 | ```bash 65 | log_duration = on 66 | log_lock_waits = on 67 | 68 | -- время выполнения (в мс.), превысив которое запрос попадает в лог 69 | log_min_duration_statement = 100 70 | log_filename = ‘postgresql-%Y-%m-%d_%H%M%S’ 71 | log_directory = ‘/var/log/postgresql’ 72 | log_destination = ‘csvlog’ 73 | logging_collector = on 74 | ``` 75 | 76 | Просматривать отчеты, сделанные на основе логов, можно с помощью утилиты ***pgbadger***, 77 | которую необходимо установить отдельно. 78 | 79 | **2 шаг:** посмотреть план запроса с помощью операторов ***EXPLAIN ANALYZE* 80 | (**их можно использовать как вместе, так и раздельно, см. далее**)**. 81 | 82 | ***EXPLAIN*** построит и покажет только план выполнения, но не выполнит запрос. 83 | 84 | ***ANALYZE*** соберет статистику используемых таблиц, **выполнит** **запрос** **(!)** и покажет время его выполнения. 85 | 86 | **Пример** 87 | ```bash 88 | EXPLAIN SELECT * FROM tenk1; 89 | 90 | QUERY PLAN 91 | 92 | ------------------------------------------------------------- 93 | 94 | Seq Scan on tenk1 (cost=0.00..458.00 rows=10000 width=244) 95 | ``` 96 | 97 | Числа, перечисленные в скобках (слева направо), имеют следующий смысл: 98 | 99 | * приблизительная **стоимость запуска** (время, спустя которое начнётся этап вывода данных); 100 | * приблизительная **общая стоимость (*cost*). 1 *cost* = 1 операция чтения страницы с диска**; 101 | * ожидаемое **число строк**, которое должен вывести этот **узел плана**; 102 | * ожидаемый **средний размер строк**, выводимых этим узлом плана (в байтах). 103 | 104 | Если требуется проанализировать с помощью *EXPLAIN* *ANALYZE* запросы типа *DELETE*, *UPDATE* и *INSERT*, то необходимо обернуть их в транзакцию, т.к. *ANALYZE* выполняет запрос: 105 | ```sql 106 | BEGIN; 107 | EXPLAIN ANALYZE ; 108 | ROLLBACK; 109 | ``` 110 | 111 | Важно помнить о том, что при выполнении запроса **планировщик выбирает план выполнения**, 112 | **опираясь на** **статистику**. 113 | Следовательно, при анализе запроса путем использования оператора *EXPLAIN* **нужно убедиться, что статистика не устарела**. 114 | 115 | **Собрать статистику** можно, вызвав *ANALYZE* с именем таблицы, или просто *ANALYZE*, чтобы проанализировать все таблицы БД. 116 | 117 | **Шаг 3: анализ**: при анализе нужно обращать внимание на следующие моменты: 118 | 119 | * операции с большой ***cost***; 120 | * узлы плана с последовательным чтением (***seq scan***), часто указывающие на отсутствие необходимых индексов; 121 | * ***sort*** – операции сортировки являются дорогими. 122 | 123 | **Дальнейшие возможные шаги**: 124 | 125 | * на сервере **можно запускать** **автоочистку и автоанализ** (***autovacuum***) 126 | для удаления неиспользуемых записей (мертвых кортежей); 127 | 128 | * **денормализация** – привнесение избыточности; 129 | 130 | * **использование** **табличных пространств** – управление размещением объектов 131 | по физическим устройствам ввода/вывода. Например, активно используемые данные хранить на *SSD* дисках, 132 | а архивные – на более медленных *HDD*. 133 | 134 | * **партиционирование** – разделение большой таблицы на множество более мелких; 135 | 136 | * **замена подзапросов в запросах на соединения**; 137 | 138 | * **деградация функциональности** – намеренное понижение количества 139 | передаваемых клиенту данных (например, вместо топ-100 друзей отдаем топ-10). 140 | 141 | --- 142 | 143 | ## Масштабирование баз данных 144 | 145 | **Вертикальное масштабирование** предполагает наращивание мощности текущего сервера (добавление памяти, замена CPU и т.д.). 146 | 147 | **Горизонтальное масштабирование** предполагает разделение данных по разным серверам или разным инстансам сервисов. 148 | 149 | Реализовать масштабирование можно несколькими способами: 150 | 151 | * **партиционирование** – разбиение данных на несколько частей по определенному признаку (например, разбиваем таблицу на две части по четности поля *ID*); 152 | * **шардирование** – хранение данных на разных серверах или инстансах БД; 153 | * **репликация**. 154 | 155 | --- 156 | 157 | ## Уровни изолированности транзакций 158 | 159 | Стандарт SQL определяет **4 уровня изолированности транзакций**. 160 | 161 | Пусть **T1** – **первая транзакция**, а **T2** – **вторая транзакция**. 162 | 163 | ***L1. READ UNCOMMITTED*** – **T1** **видит изменения**, выполненные **незавершенной** **T2**. 164 | Этот уровень не реализован в *PostgreSQL*, т.к. не представляет практической ценности. 165 | 166 | ***L2. READ COMMITTED*** – *T1* видит изменения, выполненные *T2*, после коммита *T2*. 167 | 168 | Защищает от аномалии "грязного чтения", но не защищает от "неповторяемого чтения". 169 | 170 | Попытка изменения одних и тех же данных в *T2* до коммита изменений *T1* будет заблокирована. 171 | ***Является уровнем по умолчанию в *PostgreSQL***. 172 | 173 | ***L3. REPEATABLE READ*** – *T1* увидит изменения, выполненные *T2*, только после коммита *T2* и *T1*. 174 | 175 | Защищает от аномалии "неповторяемого чтения", но не защищает от "фантомного чтения". 176 | 177 | Фантомное чтение может возникнуть тогда, когда Т1 внутри себя не увидит строк, которые успела создать Т2. 178 | 179 | Попытка изменения одних и тех же данных в *T2* до коммита изменения в *T1* будет заблокирована. 180 | 181 | ***L4. SERIALIZABLE*** – уровень, на котором моделируется последовательное выполнение всех зафиксированных транзакций. 182 | Если транзакции пытаются менять пересекающийся набор данных, то упадет ошибка 183 | `could not serialize access due to concurrent update`. 184 | 185 | Шаблон для наглядного представления и работы с уровнями изоляции можно посмотреть в файле `isolation_levels_guide.sql`. 186 | 187 | --- 188 | 189 | ## CAP-теорема 190 | 191 | Это утверждение о том, что в любой реализации распределенных вычислений возможно обеспечить **не более двух** 192 | из трех следующих свойств (возможные комбинации свойств: ***CA, CP, AP***): 193 | 194 | ***Consistency*** – состояние согласованности данных во всех вычислительных узлах (одни и те же данные у мастеров и реплик и т.д.); 195 | 196 | ***Availability*** – доступность системы; 197 | 198 | ***Partition tolerance*** – система способна работать в случае отказа некоторых вычислительных узлов 199 | (**это свойство по умолчанию соблюдается микросервисной архитектурой.** 200 | Иными словами, для микросервисной архитектуры стоит выбор отказа от **_Consistency_** или **_Availabiblity_**). 201 | 202 | --- 203 | 204 | ## Репликация 205 | 206 | **Репликация** – механизм синхронизации нескольких наборов данных. 207 | 208 | Существуют два вида репликации: **физическая** и **логическая**. Оба вида будут описаны ниже. 209 | 210 | Также существуют **гарантии** **репликации**: **синхронная** и **асинхронная.** 211 | 212 | **Синхронная** репликация подразумевает, что мастер-сервер фиксирует транзакцию только после момента подтверждения получения данных репликой. 213 | 214 | **Асинхронная** же подразумевает обратное: **мастер не ждет подтверждения получения данных** от реплики. 215 | 216 | **По виду взаимодействия** репликация может быть **мастер-слейв** и **мастер-мастер.** 217 | 218 | **Мастер-слейв репликация** предполагает главного (мастер) сервера и подчиненного (слейв) сервера. 219 | **Слейв повторяет состояние мастера** и не может менять данные самостоятельно. 220 | 221 | **Репликация** **мастер-мастер предполагает равенство серверов**. 222 | Оба сервера могут обрабатывать запросы на чтение и изменение данных. 223 | 224 | **Применение** репликации: 225 | * **балансировка нагрузки**; 226 | * **обеспечение отказоустойчивости** (переход на реплику в случае сбоя основного сервера); 227 | * **тестирование новых версий *PostgreSQL***. 228 | 229 | ### Физическая репликация 230 | 231 | **Физическая** (**потоковая**) репликация – вид репликации, 232 | в основе которого лежит **передача записей журнала транзакций** (_WAL_) от мастера к реплике. 233 | **Реплика применяет изменения**, принятые от мастера, **чисто механически**, 234 | без «понимания смысла», работая **в режиме постоянного восстановления**. 235 | Поэтому данный вид репликации можно применить только в условиях полной 236 | программно-аппаратной совместимости мастер и слейв серверов. 237 | 238 | **Недостатки**: 239 | * мастер может отдать слейву испорченные данные, например, в случае сбоев *RAM*; 240 | * на реплике не может быть локальных изменений схемы данных; 241 | * требовательность к платформе и версии *PostgreSQL*; 242 | * невозможность репликации мастер-мастер. 243 | 244 | ### Логическая репликация 245 | 246 | В основе **логической** репликации лежит принцип ***publisher*-*subscriber***, 247 | при этом у серверов нет выделенных ролей: **один и тот же сервер может публиковать изменения и быть подписчиком**. 248 | 249 | Сервер-паблишер читает журнальные записи и предварительно декодирует в **логический**, **платформо-независимый** вид. 250 | Поэтому логическая репликация не требует жесткой совместимости серверов, реплика должна лишь понимать протокол репликации. 251 | 252 | **Логическая репликация не реплицирует** команды *DDL* (все изменения схемы данных нужно переносить вручную), 253 | значения последовательностей. 254 | 255 | **Плюсы**: 256 | * репликация остановится, если мастер имеет аппаратные неисправности; 257 | * нетребовательность к программной совместимости; 258 | * возможность использования различающихся схем данных на мастере и слейве; 259 | * возможность настройки мастер-мастер репликации. 260 | 261 | --- 262 | 263 | ## Денормализация 264 | 265 | Под денормализацией понимают **намеренное нарушение требований нормализации**. 266 | 267 | Денормализация обычно проводится путем добавления данных, которые согласно требования 268 | нормальных форм должны выноситься в отдельную таблицу (избыточность данных). 269 | 270 | Денормализация приводит к **избыточности** и **дублированию** данных, поэтому выигрыш от нее должен оправдывать затраты. 271 | 272 | --- 273 | 274 | ## ACID (свойства транзакционной СУБД) 275 | 276 | ***Atomicity*** – **атомарность** операций. Транзакция должна быть выполнена полностью, либо вовсе не выполнена. 277 | 278 | ***Consisitency*** – **согласованность**. Обеспечение целостности данных, 279 | выполнения определенных правил и ограничений (триггеры, непустые поля, ограничения на уникальность и внешние ключи и т.д.). 280 | 281 | ***Isolation*** – **изолированность**. Выполнение параллельных транзакций 282 | не должно влиять на итоговый результат другой транзакции. 283 | **Это очень дорогое требование, поэтому оно частично и по-разному выполняется в соответствии с уровнями изолированности транзакций**. 284 | 285 | ***Durability*** – **долговечность**. Изменения успешно завершенной транзакции не должны пропасть в случае сбоев. 286 | 287 | --- 288 | -------------------------------------------------------------------------------- /interview_notes/isolation_levels_guide.sql: -------------------------------------------------------------------------------- 1 | /* 2 | if __name__ == '__main__': 3 | from testcontainers.postgres import PostgresContainer 4 | with PostgresContainer(image="postgres:alpine3.16") as pg_container: 5 | pg_container.start() 6 | url = pg_container.get_connection_url() 7 | print(url) 8 | x = 0 # здесь можно поставить брейкпоинт, чтобы контейнер не закрылся 9 | */ 10 | REVOKE ALL PRIVILEGES ON SCHEMA public FROM user1; 11 | REVOKE ALL PRIVILEGES ON SCHEMA public FROM user2; 12 | drop role user1; 13 | drop role user2; 14 | drop table if exists levels_test; 15 | create table if not exists levels_test 16 | ( 17 | id serial primary key, 18 | name varchar(30), 19 | money integer 20 | ); 21 | create user user1 WITH PASSWORD 'user1' 22 | superuser createdb createrole replication bypassrls; 23 | 24 | create user user2 WITH PASSWORD 'user2' 25 | superuser createdb createrole replication bypassrls; 26 | 27 | GRANT ALL PRIVILEGES ON SCHEMA public TO user1; 28 | GRANT ALL PRIVILEGES ON SCHEMA public TO user2; 29 | 30 | insert into levels_test (name, money) values ('Vanya_1', 100); 31 | insert into levels_test (name, money) values ('Vanya_2', 100); 32 | insert into levels_test (name, money) values ('Vanya_3', 100); 33 | 34 | -- не забудь создать 2 отдельных коннекшена для user1 и user2! 35 | 36 | /* READ COMMITTED: уровень по дефолту, 37 | защищает от аномалии "грязного чтения", 38 | не защищает от "неповторяемого чтения" 39 | 40 | Ниже запросы для создания аномалии "неповторяемое чтение": 41 | 1. начинаем Т1 и смотрим в ней запрос - вернется 1 строка 42 | 2. меняем money в Т2 и фиксируем 43 | 3. запрос внутри незавершенной Т1 вернет 0 строк - чтение не повторилось 44 | */ 45 | 46 | -- T1 47 | BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; 48 | -- важно увидеть возврат нуля строк ДО коммита 49 | select * from levels_test where name = 'Vanya_1' and money = 100; 50 | COMMIT; 51 | 52 | -- T2 53 | BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; 54 | update levels_test set money = 150 where name = 'Vanya_1' returning id; 55 | COMMIT; 56 | 57 | ------------------------------------------------------------------------------ 58 | 59 | /* REPEATABLE READ: читаемые данные внутри начатой транзакции 60 | будут одни и те же в любом случае 61 | 62 | защищает от аномалии "неповторяемого чтения", 63 | НО не защищает от "фантомного чтения": 64 | например Т1 до своего коммита не увидит новые строки, созданные Т2 65 | 66 | Можно убедиться, что аномалии "неповторяемого чтения" теперь нет: 67 | 1. начинаем Т1 и смотрим запрос - вернется 1 строка 68 | 2. меняем money в Т2 и коммитим ее 69 | 3. смотрим запрос в незавершенной Т1 - все еще имеем 1 строку 70 | 4. коммитим Т1 и смотрим запрос - видим 0 строк, что и ожидаем 71 | */ 72 | 73 | -- T1 74 | BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; 75 | -- вернется 1 строка как и ожидаем, т.к. на этом уровне транзакция видит свой снэпшот данных 76 | select * from levels_test where name = 'Vanya_2' and money = 100; 77 | COMMIT; 78 | -- а теперь ничего не увидит 79 | select * from levels_test where name = 'Vanya_2' and money = 100; 80 | 81 | -- T2 82 | BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; 83 | update levels_test set money = 150 where name = 'Vanya_2' returning id; 84 | COMMIT; 85 | 86 | ------------------------------------------------------------------------------ 87 | 88 | /* SERIALIZABLE: самый строгий уровень, не допускающий 89 | изменений пересекающися данных в разных транзакциях 90 | 91 | защищает от всех аномалий: 92 | 1. начинаем T1 и выполняем запрос 93 | 2. начинаем Т2 и выполняем запрос - он должен залагать, т.к. данные "захвачены" Т1 94 | 3. коммитим Т1, должны увидеть ошибку ERROR: could not serialize access due to concurrent update 95 | */ 96 | 97 | -- T1 98 | BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; 99 | update levels_test set money = 150 where name = 'Vanya_3' returning id; 100 | COMMIT; 101 | 102 | -- T2 103 | BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; 104 | update levels_test set money = 200 where name = 'Vanya_3' returning id; 105 | COMMIT; 106 | -------------------------------------------------------------------------------- /interview_notes/python.md: -------------------------------------------------------------------------------- 1 | ## Интерпретатор Python 2 | 3 | Python является **интерпретируемым** языком. 4 | При запуске скрипта на Python код **компилируется в байткод** (.pyc файлы), 5 | а далее **байткод выполняется на виртуальной машине (ВМ)**. 6 | 7 | Байт-код обеспечивает **кроссплатформенность**, его выполнением занимается часть интерпретатора, 8 | называющаяся **виртуальной машиной**. 9 | 10 | --- 11 | 12 | ### GIL (Global Interpreter Lock) 13 | ***GIL*** – это **мьютекс**, защищающий внутренние объекты интерпретатора от 14 | некорректного взаимодействия с несколькими потоками. 15 | 16 | Главным образом GIL обеспечивает **безопасную работу сборщика мусора** (механизм подсчета ссылок). 17 | 18 | --- 19 | 20 | ### GC - Garbage Collector (сборщик мусора) 21 | Каждый объект интерпретатора **_CPython_** имеет **атрибут** `ref_count` – **счетчик ссылок**. 22 | Когда он становится равным 0, объект сразу **деаллоцируется**. 23 | 24 | При этом **оператор** `del` не удаляет объект, а **декрементирует счетчик ссылок**. 25 | 26 | Сборщик мусора работает с **тремя поколениями объектов**. 27 | **Изначально объект принадлежит первому поколению**, 28 | далее если он пережил сборку мусора, переходит в следующее поколение. 29 | 30 | **Порог перехода в следующее поколение это количество сборок мусора**, его можно переопределить 31 | с помощью метода `gc.set_threshold` пакета `gc`. 32 | 33 | Чем выше поколение, тем реже оно сканируется сборщиком мусора. 34 | 35 | --- 36 | 37 | ## Генераторы 38 | 39 | Генератор – подвид итератора, хранящий закономерность вычисления последовательности. 40 | Генераторы **хранят в памяти только текущий элемент последовательности**. 41 | 42 | Генератор генерирует значения, возвращающиеся по запросу, 43 | и после возврата одного значения выполнение функции-генератора приостанавливается до запроса следующего значения. 44 | Между вызовами **генератор сохраняет свое состояние, помнит о контексте** в отличие от функций с оператором `return`. 45 | 46 | Генераторы можно создать **двумя способами**: 47 | 1. **генераторное выражение**; 48 | 2. **функция-генератор** с оператором `yield`. 49 | 50 | **Генераторы поддерживают 3 метода**: 51 | 1. `close` - **закрытие** генератора; 52 | 2. `send` - генератор может **принять значение** после (`value = yield`); 53 | 3. `throw` - возбудить **исключение** (`gen.throw(AnyError)`). 54 | 55 | **Пример**: 56 | ```python 57 | # generator expression 58 | genexpr = (x**2 for x in range(1, 5)) 59 | 60 | next(genexpr) 61 | >> 1 62 | next(genexpr) 63 | >> 4 64 | next(genexpr) 65 | >> 9 66 | 67 | # generator 68 | def batch_read(lines): 69 | buff = [] 70 | batch_count = None 71 | 72 | for line in lines: 73 | if batch_count is None: 74 | batch_count = yield 75 | 76 | buff.append(line) 77 | 78 | if len(buff) == batch_count: 79 | # такой синтаксис юзается для одновременного принятия значения из метода send и возврата значения 80 | batch_count = yield buff 81 | buff.clear() 82 | 83 | if buff: 84 | yield buff 85 | 86 | # подобным образом можно было бы вычитать файл любого размера 87 | lines = ['1', '', '3', '4', '5', '', '7', '8', ''] 88 | gen = batch_read(lines) 89 | # Иницализация генератора, причем next(gen) это то же самое, что и gen.send(None) 90 | next(gen) 91 | 92 | print(gen.send(2)) 93 | print(gen.send(1)) 94 | print(gen.send(1)) 95 | print(gen.send(4)) 96 | >> ['1', ''] 97 | >> ['3'] 98 | >> ['4'] 99 | >> ['5', '', '7', '8'] 100 | 101 | ``` 102 | 103 | --- 104 | 105 | ## Итерируемый объект, итератор 106 | 107 | **Итерируемый объект (`Iterable`)** - объект, предоставляющий логику перебора последовательности. 108 | Реализует метод `__iter__` или `__getitem__`. 109 | 110 | **Итератор (`Iterator`)** - итерируемый объект, умеющий запоминать свое состояние. Для этого он реализует метод `__next__`. 111 | 112 | **Отличие** `Iterable` от `Iterator`: **итератор** - это **подвид** `Iterable`, **исчерпывающийся** при полном переборе. 113 | 114 | **Примеры**: 115 | * **список** - это **Iterable**, но **не Iterator** (_список перебирается, но не может быть исчерпан_); 116 | * **генератор** относится и к **Iterable** и к **Iterator** (_генератор перебирается и исчерпывается_). 117 | 118 | **Как работает цикл** `for`: 119 | 1. цикл пытается взять итератор от объекта (`iter(obj)`); 120 | 2. на каждой итерации цикл вызывает у объекта метод `__next__` до возникновения исключение `StopIteration`. 121 | 122 | --- 123 | 124 | ## Хеш-таблицы (словари) 125 | 126 | **Хеш-таблица** или **словарь** выглядит как **одномерный массив**, каждый элемент которого называется **бакетом**. 127 | 128 | **Алгоритм добавления элемента**: 129 | 1. для ключа **вычисляется хеш** с помощью встроенной функции `hash`; 130 | 2. хеш используется для определения индекса бакета: 131 | `bucket_idx = hash_value % len(arr)`, где `arr` – **массив бакетов**; 132 | 133 | 3. в бакет записывается **пара ключ-значение**. 134 | 135 | **Получение элемента по ключу**: для ключа **вычисляется хеш**, **определяется бакет** 136 | и из него берется пара ключ-значение. 137 | 138 | **Алгоритмическая сложность получения элемента** в хеш-мапе **константная** – `O(1)` 139 | (равняется времени работы алгоритма хеширования). 140 | 141 | **Коллизии**: ситуация, при которой алгоритм хеширования выдает для разных ключей одинаковые значения, 142 | называется коллизией. 143 | 144 | **Коллизии можно резолвить** несколькими способами. 145 | Например, **методом цепочек**, в котором вместо значения в бакет кладется **связный список** значений. 146 | При этом, **алгоритмическая сложность** получения элемента становится **линейной**, 147 | потому что придется пробежаться по всем элементам связного списка, чтобы найти искомый элемент. 148 | 149 | Хеш-таблицы занимают много памяти, т.к. необходимо выделять память под количество бакетов примерно равное количеству элементов. 150 | 151 | **Ключами словаря** в Python **могут являться только хешируемые объекты** - 152 | объекты с реализацией методов `__hash__` и `__eq__` (_второй метод может использоваться для резолва коллизий_). 153 | 154 | --- 155 | 156 | ## Асинхронность и asyncio 157 | 158 | **Корутина** – результат вызова асинхронной функции. Главное свойство - **запоминание контекста** 159 | (подобно генератору). 160 | 161 | **Сокет** – абстракция сетевого взаимодействия ОС (**представляет из себя особый файл**). 162 | Сокет поддерживает операции **чтения и записи**. 163 | С точки зрения сетевого взаимодействия сокет - это **хост + порт**. 164 | 165 | asyncio следует модели **кооперативной многозадачности**, когда вместо ОС мы сами определяем 166 | точки переключения контекста с помощью оператора `await`, а весь конкурентный рантайм 167 | выполняется в **одном потоке**. 168 | 169 | ### Принципы работы и внутреннего устройства asyncio 170 | Корутины сами по себе **не предоставляют возможности конкурентного выполнения**, 171 | но конкуретность возможна благодаря **задачам**. 172 | 173 | **Задача** - **обертка** над корутиной, которая управляется **циклом событий**. 174 | 175 | asyncio использует низкоуровневое API пакетов `select`/`selectors`, которые 176 | по сути обертывают вызовы в ядро операционной системы. 177 | 178 | По сути, любую **задачу** можно проассоциировать с **сокетом**, а далее опрашивать ОС 179 | на предмет доступных для взаимодействия сокетов с помощью вышеупомянутого API. 180 | 181 | Когда сокет станет доступным, ОС выполнит заданный **коллбэк**. 182 | Коллбэк можно повесить как на операцию чтения, так и записи. 183 | 184 | asyncio опрашивает ОС знает состояние сокета (можем ли мы делать операции *read*/*write* в сокете). 185 | Если сокет недоступен, контекст переключается (подобно `yield` в генераторе) 186 | и **выполняются следующие задачи из очереди цикла событий**. 187 | 188 | --- 189 | 190 | ## Чистая функция 191 | 192 | **Чистая функция** – функция, удовлетворяющая следующим **критериям**: 193 | 1. **всегда возвращает одно** и то же **значение** **для одних и тех же** значений **входных** **параметров**; 194 | 2. **не имеет побочных эффектов** (не влияет на код, содержащийся вне функции. Например, не меняет значения глобальных переменных, не использует потоки ввода-вывода). 195 | 196 | **Преимущества**: 197 | * предсказуемость; 198 | * легкая тестируемость. 199 | 200 | --- 201 | 202 | ## MRO (порядок разрешения методов) 203 | 204 | *MRO* представляет из себя **алгоритм линеаризации иерархии класса для разрешения конфликтных ситуаций при множественном наследовании**. 205 | 206 | В старых версиях *Python* реализация *MRO* напоминала **обход** бинарного дерева **в глубину**, 207 | но это порождало множество проблем, т.к. в глубину можно было дойти до класса `object` 208 | (могли вызываться бы одноименные методы класса `object`). Теперь *MRO* работает подобно **обходу в ширину**. 209 | 210 | Чтобы увидеть линейный вид иерархии и понять приоритетность каждой сущности в иерархии наследования, 211 | можно распечатать результат вызова **у класса** метода `mro` или магического атрибута `__mro__` у объекта. 212 | 213 | --- 214 | 215 | ## Метаклассы 216 | **Все сущности** в языке *Python* **являются** **объектами**, включая классы. 217 | **Метакласс – это сущность, объекты которой являются классами**. 218 | 219 | Для определения типа класса можно вызвать метод `type` и увидеть, что метод возвращает ``. 220 | То есть, любой объект в Python имеет тип `type`. 221 | 222 | `type` является метаклассом и может работать в двух режимах, в первом из которых `type` принимает 223 | 1 аргумент – тип объекта, и возвращает его базовый тип, а во втором принимает **3 аргумента**: 224 | * ***name*** - название класса; 225 | * ***base*** - кортеж родительских классов (может быть пустым); 226 | * ***attrs*** - словарь, содержащий имена и значения атрибутов. 227 | 228 | Используя `type` во втором режиме, можно **динамически** **создавать классы** с атрибутами. 229 | 230 | Также можно создать свой метакласс, наследуясь от `type`, и в определении целевого класса указать `metaclass=<имя метакласса>`. 231 | 232 | --- 233 | 234 | ## SOLID 235 | 236 | ***SOLID*** это совокупность 5 базовых принципов проектирования объектно-ориентированных систем. 237 | 238 | ***S (Single Responsibility)*** – **принцип единственной ответственности**, 239 | согласно которому сущность должна выполнять только одну задачу (у сущности должна быть только одна причина для изменения); 240 | 241 | ***O (Open-Closed Principle)*** – **принцип открытости-закрытости**. 242 | Добавление и модификация функционала не должны приводить к изменениям существующего; 243 | 244 | ***L (Liskov Substitution Principle)*** – **принцип подстановки Лисков**. 245 | Классы-наследники не должны противоречить базовому классу; 246 | 247 | **Пример**: **наследование класса *Square* от *Rectangle* является нарушением** данного принципа, 248 | т.к. эти сущности ведут себя по-разному: 249 | 250 | ```python 251 | # сущность типа Rectangle пройдет данный тест, 252 | # но Square как наследник Rectangle – нет, т.к. у квадрата все стороны равны 253 | 254 | def test_shape_area(figure: Rectangle): 255 | figure.width = 10 256 | figure.height = 20 257 | 258 | assert figure.get_area() == 200 259 | ``` 260 | 261 | Тест выше можно сделать корректным, **усложнив** его логику проверками типов: 262 | ```python 263 | if is_instance(figure, Rectangle) ... 264 | 265 | if is_instance(figure, Square) ... 266 | ``` 267 | 268 | Но подобные **усложнения** показывают, что мы делаем что-то не так. 269 | Полиморфизм и наследование придуманы для обобщения, а не для лишних проверок на типы, 270 | в зависимости от которых выполнялась бы разная логика. 271 | 272 | ***I (Interface Segregation Principle)*** – **принцип разделения интерфейсов**. 273 | Лучше создавать много мелких узкоспециализированных интерфейсов, чем большие, 274 | часть функционала которых будет не нужна некоторым классам. 275 | 276 | ***D (Dependency Inversion Principle)*** – **принцип инверсии зависимостей**. 277 | Метод/функция должна зависеть от абстракции, а внедряемая зависимость должна реализовывать интерфейс абстракции: 278 | ```python 279 | # функция зависит от абстракции 280 | def do_smth(dep: Abstraction): ... 281 | # конкретная реализация соответсвует интерфейсу абстракции 282 | class ConcreteEntity(Abstraction): ... 283 | 284 | dep = ConcreteEntity() 285 | do_smth(dep=dep) 286 | ``` 287 | 288 | Также можно понимать **инверсию** с точки зрения **потоков управления** и **зависимостей**: 289 | * **поток управления** - `api layer -> service layer -> ...` 290 | * **поток зависимостей** - `api layer <- service layer <- domain` 291 | 292 | 293 | **Пример**: . 294 | 295 | Также в контексте *SOLID* часто употребляются следующие **два термина**: 296 | 297 | 1. [**Зацепление**](https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D1%86%D0%B5%D0%BF%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%28%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%29) - **степень зависимости** разных модулей друг от друга. Чем выше зацепление, тем хуже; 298 | 2. [**Связность**](https://ru.wikipedia.org/wiki/%D0%A1%D0%B2%D1%8F%D0%B7%D0%BD%D0%BE%D1%81%D1%82%D1%8C_%28%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%29) - степень следования принципу _SRP_. 299 | 300 | --- 301 | -------------------------------------------------------------------------------- /interview_notes/web.md: -------------------------------------------------------------------------------- 1 | ## HTTP 2 | 3 | **HTTP** (*HyperText Transfer Protocol*) – протокол, описывающий **правила взаимодействия клиента и сервера**. 4 | 5 | **Взаимодействие** **клиента и сервера** осуществляется путем обмена *HTTP*-сообщениями. 6 | 7 | *HTTP*-запрос **клиента** состоит из следующих частей: 8 | ``` 9 | <Метод> <Ресурс> <Протокол/версия> 10 | <заголовки запроса> 11 | <тело запроса> (требуется не для всех методов) 12 | ``` 13 | 14 | **Пример**: 15 | ``` 16 | PUT /some-resource HTTP/1.1 17 | <заголовки запроса> 18 | <тело запроса> (требуется не для всех методов) 19 | ``` 20 | 21 | **Заголовки** – пары вида ключ-значение, необходимые 22 | для передачи служебной информации (тип контента, браузер, устройство и т.д.). 23 | 24 | **Метод** – последовательность символов, определяющую операцию для осуществления над ресурсом. 25 | Спецификация *HTTP* не ограничивает набор методов, но принято использовать конкретные методы: 26 | * ***GET*** – получение ресурса (***HEAD*** –то же самое только без содержимого); 27 | * ***POST*** – создание ресурса; 28 | * ***PUT*** – изменение ресурса (***PATCH*** – частичное изменение); 29 | * ***DELETE*** – удаление ресурса; 30 | * ***OPTIONS*** – информация о соединении. 31 | 32 | ***URL*** – **идентификатор/путь до ресурса**. 33 | 34 | *HTTP* не обязывает сервер реализовывать методы строго определенным образом и понимать все методы. 35 | Только метод *GET* **является обязательным** для реализации. 36 | 37 | *HTTP*-**ответ сервера** выглядит следующим образом: 38 | ``` 39 | HTTP/<версия> <Код состояния> <Пояснение> 40 | <заголовки> 41 | <тело ответа> 42 | ``` 43 | 44 | **Код состояния** указывает на результат обработки запроса клиента. Коды принято классифицировать следующим образом: 45 | * **1xx**: *Information* (**информационные**); 46 | * **2xx**: *Success* (**успешные**); 47 | * **3xx**: *Redirect* (**перенаправления**); 48 | * **4xx**: *Client* *Error* (**клиентские ошибки**); 49 | * **5xx**: *Server* *Error* (**серверные** **ошибки**). 50 | 51 | 52 | --- 53 | 54 | ## **Как браузер обрабатывает запрос клиента** 55 | 56 | 1. **браузер получает** из адресной строки **протокол** (*http*/*https*), 57 | **доменное имя хоста** и **ресурс** (`/api/v2/some_resource/...`)`; 58 | 59 | 2. **браузер получает IP адрес хоста** путем **одним из способов**: 60 | * из кэша ОС, если ранее на этот хост отправлялись запросы; 61 | * резолв доменного имени хоста в *IP* с помощью ***DNS***; 62 | 63 | 3. **браузер устанавливает соединение** с хостом **одним из способов**: 64 | * **незащищенное** по протоколу *http* по 80 порту; 65 | * **защищенное** по *https* по 443 порту с проверкой подлинности, хендшейками и т.д. 66 | 67 | 4. браузер получает ответ от хоста и рендерит *HTML*. 68 | 69 | 70 | --- 71 | 72 | ## Идемпотентность HTTP методов 73 | 74 | Метод *HTTP* является **идемпотентным**, 75 | если один и тот же неоднократно выполненный запрос оказывает один и тот же эффект, 76 | не изменяющий состояние сервера. 77 | Другими словами, идемпотентный метод не должен иметь никаких сайд-эффектов, кроме сбора статистики или подобных операций. 78 | 79 | Методы [***GET***](https://developer.mozilla.org/ru/docs/Web/HTTP/Methods/GET), 80 | ***[***HEAD***](https://developer.mozilla.org/ru/docs/Web/HTTP/Methods/HEAD)***, 81 | [***PUT***](https://developer.mozilla.org/ru/docs/Web/HTTP/Methods/PUT), 82 | [***DELETE***](https://developer.mozilla.org/ru/docs/Web/HTTP/Methods/DELETE) и 83 | ***OPTIONS*** **идемпотентны** в отличие от методов 84 | [***POST***](https://developer.mozilla.org/ru/docs/Web/HTTP/Methods/POST) и ***PATCH***. 85 | 86 | Для идемпотентности нужно рассматривать только изменение фактического внутреннего состояния сервера, 87 | а возвращаемые запросами коды статуса могут отличаться: 88 | первый вызов [*DELETE*](https://developer.mozilla.org/ru/docs/Web/HTTP/Methods/DELETE) вернёт код [**200**](https://developer.mozilla.org/ru/docs/Web/HTTP/Status/200), 89 | а любой следующий вызов вернет [404](https://developer.mozilla.org/ru/docs/Web/HTTP/Status/404) (поэтому *DELETE* идемпотентен). 90 | 91 | --- 92 | 93 | ## ***REST* / *RESTful*** 94 | 95 | **REST** – это архитектурный стиль построения клиент-серверных приложений. 96 | 97 | **_RESTful_** приложение должно соблюдать следующие **5/6** принципов ***REST***: 98 | 99 | 1. **клиент-серверная архитектура**; 100 | 101 | 2. ***stateless*** (**отсутствие хранения состояния**) – сервер не должен хранить информацию о предыдущих запросах клиента; 102 | 103 | 3. **кэшируемость** – должна быть возможность по требованию клиента сохранить данные в кэш и отдавать эти данные из кэша; 104 | 105 | 4. **единообразие** **интерфейса** – использование одного протокола для общения клиента и сервера; 106 | 107 | 5. **многоуровневая система –** система может быть сложной, но эта сложность скрыта от клиента; 108 | 109 | 6. **код по требованию** (необязательное требование *RESTful*) – 110 | при необходимости сервер может расширить функционал клиента (валидация номера телефона на форме и т.д.). 111 | 112 | --- 113 | 114 | ## ***JSON Web Tokens (JWT)*** 115 | 116 | ***JWT*** – это открытый стандарт для создания токенов, основанных на формате ***JSON***. 117 | Этот вид токенов **используется для аутентификации в веб-приложениях**. 118 | 119 | ***JSON Web Token*** делится на **3 составляющие** и может выглядеть следующим образом: 120 | 121 | ``` 122 | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV\_adQssw5c 123 | ``` 124 | 125 | **Компоненты JWT**: 126 | 127 | * **заголовок** (***header***) – содержит **закодированную** информацию об алгоритме шифрования **подписи** 128 | (`{'alg':''HS256', 'typ':'JWT'}`); 129 | 130 | * **полезная информация** (***payload***) – любая **закодированная** информация, которую сервер может передать клиенту 131 | (`{'email':'example@mail.com'}`); 132 | 133 | * **подпись (*signature*) –** строка вида `MAC-SHA256(f'{header}.{payload}, SECRET_KEY)`, 134 | **зашифрованная** **секретным** **ключом** на стороне сервера аутентификации. 135 | 136 | 137 | ### Принцип работы 138 | 139 | **Принцип работы *JWT***: любой пользователь сможет **раскодировать заголовок и полезную информацию**, 140 | т.к. они **закодированы**, а **не зашифрованы**. 141 | Изменение содержимого любой части токена потребует создания новой подписи, 142 | но злоумышленник не сможет сгенерировать корректную подпись, т.к. не знает секретного ключа. 143 | 144 | **Токены обычно генерируются парами**: 145 | * ***access_token*** – **токен для аутентификации пользователя**, 146 | имеющий ограниченное время действия, заданное сервером аутентификации; 147 | 148 | * ***refresh_token*** – токен, необходимый для генерации нового *access\_token* после завершения срока действия последнего. 149 | 150 | ### Механика работы access и refresh токенов 151 | 152 | **Access token (АТ)** живет как правило очень **короткое время** и его можно хранить в **local storage** или **cookie**. 153 | При этом **refresh token (RT)** должен жить намного дольше **АТ** и храниться в куке с флагами **httpOnly** и **Secure**. 154 | 155 | Когда **АТ** истек, а **RT** еще жив, клиент должен получить новый **AT** с помощью **RT**. 156 | А когда **RT** истек, нужно повторить процесс логина (обычно с логином и паролем). 157 | Обычно принято возвращать из эндпоинта логина пару **AT**+**RT**. 158 | 159 | --- 160 | 161 | ## CORS (Cross Origin Resource Sharing) 162 | 163 | _CORS_-политики работают **только в браузерах** по следующему принципу: 164 | 1. браузер подставляет **заголовок** `Origin` со значением хоста, откуда летит запрос в бэкенд; 165 | 166 | 2. бэкенд заранее знает о доверенных `allowed origins` и в них он он проверяет наличие текущего `Origin`; 167 | 168 | 3. если _origin_ есть среди доверенных, бэкенд отправит **заголовок** `Access-Control-Allow-Origin`, 169 | в противном случае фронтенд не увидит этого заголовка и возникнет ошибка _CORS_. 170 | 171 | --- 172 | -------------------------------------------------------------------------------- /interview_questions.md: -------------------------------------------------------------------------------- 1 | ## Вопросы к HR 2 | 3 | * чем компания занимается, в чем бизнес-ценность продукта; 4 | * для каких целей нужен новый разраб в команде; 5 | * вилка и ЗП (и из чего состоит оклады/премии/бонусы и тд); 6 | * удаленка и гибкий график; 7 | * есть ли **электронная система документооборота**; 8 | * как взять отпуск и можно ли перенести; 9 | * предоставляется ли **техника**; 10 | * есть ли **ДМС** и активно ли его юзают; 11 | 12 | --- 13 | 14 | ## Вопросы к команде 15 | 16 | * какие цели ставите для нового разраба в команде; 17 | * состав команды и роли ее участников; 18 | * процесс онбординга; 19 | * что ждет на испыталке; 20 | * полный флоу фичи (от кого/откуда берется и как доходит до исполнителя), взаимодействие в команде и процессы; 21 | * есть ли временная **оценка** задач? если есть, каким образом оцениваете? 22 | * сколько бэкендеров и как строится взаимодействие между ними (есть ли дизайн-ревью, техтоки, иные встречи и процессы); 23 | * работа с техдолгом (обновление зависимостей, рефакторинг и т.д.); 24 | * перфоманс ревью (с кем проводится, как часто, каким образом) 25 | 26 | --- 27 | 28 | ## Вопросы на тех. собесе 29 | 30 | * какие цели ставите для нового разраба в команде; 31 | 32 | * уточнить стек; 33 | 34 | * в среднем на какой версии питона кодовая база; 35 | 36 | * архитектура в общих словах (количество сервисов, как и чем они между собой связаны); 37 | 38 | * как устроен CI/CD (что происходит в джобах, как дела с линтингом и форматированием кода); 39 | 40 | * как проводится код ревью; 41 | 42 | * пишутся ли тесты? Если да то какие (есть ли интеграционные, чем пользуетесь для этого, запускается ли это нормально в локальной среде), 43 | в среднем какого покрытия добиваетесь или какие места покрываете, а какие нет; 44 | 45 | * следите ли за тулингом и экосистемой, пытаетесь использовать новые тулзы и практики? 46 | 47 | * допустим я выхожу к вам работать. 48 | как вы поймете, хорошо или плохо я работаю? как оцениваете тех кто с кем вы уже работаете? 49 | 50 | --- 51 | 52 | --------------------------------------------------------------------------------