Топ ошибок в Django-проектах, которые допускают начинающие разработчики

Я собрал в одном месте топ ошибок, которые допускают новички в проектах на Django. Речь о ситуациях, когда новичок в одну харю с нуля делает проект: например, тестовое или пет-проджект.
Я проверял много таких проектов: начиная домашками на моих курсах по веб-разработке и заканчивая недавними тестовыми от выпускников Learn Python.
Не ищите в этом списке неочевидных вещей: тут собраны довольно банальные вещи. Это скорее чеклист и план по дополнительному обучению, а не супер-секретные ниндзя практики.
У меня набралось 11 ошибок, от самых грубых к менее критичным по моей внутренней шкале. Для каждой ошибки я старался рассказать о том, почему это плохо и как это исправить.
Приватные данные в репо
Открываешь settings.py
, а там как минимум SECRET_KEY
, а то и ещё какой-нибудь пароль к базе данных и токен доступа к Фейсбучному аккаунту лежит плейнтекстом.
Главная проблема тут в том, что как только вы запушили код в публичный репо, все эти данные можно считать скомпрометированными: какой-нибудь бот их уже нашёл, протестировал и положил к себе в базу. Может быть, злоумышленник не сможет получить никакого профита от вот конкретно вашего секретного ключа, но чтобы не думать об этом каждый раз, лучше выработать правило: никаких секретов в репозитории.
Самый простой способ управлять секретными данными — использовать переменные окружения, просто через os.environ
. Более продвинутый — настроить управление конфигурациями в проекте. Например, с помощью django-configurations.
В репозитории лишние файлы
Смотришь такой репо, а там в папке media
куча тестовых файлов, где-нибудь лежит db.sqlite
и до кучи какой-нибудь pycache
.
В реальных проектах это зло потому что даже если эти файлы удалить, они останутся в истории гита и репозиторий после пары месяцев такой разработки начинает весить непозволительно много. Ещё это значит, что автор кода не очень хорошо владеет гитом.
Порешать эту проблему стабильно нужно в два этапа: настроить .gitignore
и ввести процесс саморевью перед коммитом. С .gitignore
всё просто: берёте какой-нибудь готовый шаблон (например, Гитхаб может его сгенерировать), добавляете туда свои специфичные директории, пушите этот файл первым коммитом. С саморевью посложнее, но профитнее. Каждый раз перед тем, как сделать коммит, я подробно смотрю дифф того, что в этот коммит попадает. Это помогает не добавлять в коммит те файлы, которых в нём быть не должно (и спасает от кучи других ошибок).
Нет ридми
Смотришь на репо на Гитхабе и вопросов всё больше: что это за проект, какая функциональность, на каком питоне/ОС запускать, как разворачивать, вообще нифига непонятно.
В реальных проектах это зло, которое приводит к тому, что знания о том, как делать разные вещи с проектом, передаются через Слак или типа того. Если мы говорим про опенсорс, то это неуважение к пользователю: он нашёл наш проект, заинтересовался, открыл его, время потратил, а мы ему фигу вместо приветствия показываем.
Потратьте полчаса на ридми. Найдите хороший шаблон, который вам нравится, и заполните его для своего проекта. Только не забываете поддерживать его актуальным со временем. Например, у меня для некоторых проектов стоит ежемесячная задача: проверить актуальность документации.
Неправильное разбиение по коммитам
Смотришь в историю коммитов, а там один коммит с комментарием “initial commit” и больше ничего нет.
Разбиение по коммитам и комментарии к ним — это очень важный кусок информации о проекте. В реальности с его помощью можно узнать, когда, кто, почему и как внёс изменения, что с ними было до этого, как человек думал и какие проблемы решал. К тому же это полезно самому разработчику. У вас бывало такое, что вы весь вечер что-то кодите и вот везде куча всего и нихрена не работает, хочется всё удалить? Вот при правильном использовании гита такого не бывает: вы двигаетесь маленькими шажками и фиксируете их в vcs. В любой момент можно откатиться, посмотреть как было раньше и не надо в голове держать весь контекст.
Чтобы этого добиться, надо стараться разбивать задачу на совсем маленькие кусочки, типа полчаса-час. Идеально брать большую задачу, расписывать её на такие шажки прям на бумаге и по очереди их выполнять, по коммиту на каждую.
Неправильный нейминг
Тут несколько частых типов ошибок. Во-первых, иногда встречаются названия, которые вообще ничего не значат, например i
,j
,foo
,temp
. Во-вторых, иногда названия нарушают PEP8, например, класс XML_VALIDATOR
. В-третьих, они иногда не говорят о том, для чего сущность нужна и что она делает, например xml
для генератора xml-файла заданного формата.
Для решения есть два шага: технический и организационный. Технический простой — настройте flake8
с нужными вам плагинами (например, flake8-variables-names) и гоняйте его каждый раз перед коммитом (можно настроить прекоммит хук, например, с помощью pre-commit). Организационный сложнее: надо вообще перестать использовать плохие названия переменных. Даже для “просто потестить”, даже если “да я сразу перепишу”. Давайте нормальные имена вещам сразу, это больно только первое время.
Неправильная структура проекта
В корне проекта много файлов с кодом, requirements.txt
лежит в какой-то директории, а докерфайл лежит в третьей.
Для расположения разных штук в проекте, как и для многого другого, есть правила. Если я вижу что-то кастомное, мне приходится это запоминать и переучиваться для этого проекта, это неудобно.
Лучшее, что можно сделать для борьбы с этой проблемой — освоить cookiecutter. Это штука, которая разворачивает проект из шаблона, шаблоны можно писать самим. Но и этого делать не нужно, их уже полно. Просто отыщите шаблон, который нужен вам для конкретного проекта. Например, Django+DRF+PostgreSQL+Docker. А потом просто воспользуйтесь им, подпилив для себя (обычно в таких шаблонах всегда есть что-то лишнее).
Неправильная декомпозиция
Самая частая проблема тут — вообще вся логика во вьюхах. Открываешь views.py
и там прям простыня.
В реальных проектах это смерти подобно потому что в таких вьюхах сразу появляются баги, которые никто кроме автора не может исправить, а следом появляется копипаста как самый простой способ переиспользовать код и ничего не сломать (сразу). В небольших проектах это значит, что автор не умеет в базовую декомпозицию кода, не понимает, зачем это нужно, а значит пишет плохорасширяемый и сложносопровождаемый код.
Правильно декомпозировать код — навык, которому надо долго учиться. В идеале — на практике, с ревью от опытных товарищей и всем таким. Если хотите начать хоть с чего-то, возьмите flake8-functions и настройте под себя. Этот плагин не даст вам писать слишком длинные функции с кучей параметров. О, а ещё у меня есть статья про дизайн функций.
Свои велосипеды вместо использования библиотек
Сидишь, пишешь-пишешь код, отлаживаешь, тратишь время. А потом всё удаляешь и заменяешь парой импортов из сторонних модулей, которые делают то же, только стабильнее, быстрее и правильнее. Обидно, да? Особенно часто такое происходит у начинающих разработчиков с Джангой — она ж огромная, там рил дохуя всего. Если вам нужна дефолтная авторизация по емейлу/паролю — она есть, даже вьюхи писать не надо. Нужно по модели отрисовать форму, дать заполнить, при удачном заполнении создать объект и сохранить в базу, а при неудачном отрисовать форму с ошибками? Это тоже есть, называется CreateView. Хотите по русскому названию сущности генерировать путь? Есть python-slugify или TitleSlugDescriptionModel
в django-extensions.
Даже если вам нужно что-то, что вы можете написать за полчаса, лучше взять эту функциональность из сторонней библиотеки, если это возможно. Очень часто это полчаса превращаются в два и ещё час на отладку и всё равно не обрабатывают какие-нибудь крайние случаи, а в коде из сторонней библиотеки всё чики-пуки.
Чтобы не изобретать изобретённое, надо знать, что изобретено. Поэтому советую взять за правило читать всю документацию модулей, которые вы используете. Да, для Джанго это задача не на часок. Зато закроете прочитанную документацию вы другим человеком, обещаю. Кроме этого, перед реализацией какой-то функции хорошо бы приучить себя гуглить, нет ли библиотек, которые это делают. Эта практика экономит десятки, сотни, тысячи часов.
Нет тестов
Это очень частая проблема не только у новичков: не писать тесты. Какие тесты, чё ты хочешь вообще, скажи спасибо, что код есть, окей?
Не окей, братан. Самые простые интеграционные тесты займут часок на написание и сразу будут приносить кучу профита. Если ты пишешь юнит-тесты, то это значит, что ты лучше декомпозируешь код. В конце концов это значит, что ты умеешь писать тесты, а это мастхев для почти любого реального проекта.
Чтобы научиться писать тесты, нужно писать тесты. Тут как с декомпозицией: это навык, который долго приобретается через практику. Начать можно, например, со статьи Getting Started With Testing in Python. Советую сразу начинать с использования pytest, он очень крутой и распространённый в боевых проектах.
Нет аннотаций типов
Какого типа аргумент принимает на вход функция get_api_auth(token)
? А что возвращает? Нифига непонятно. И так не только в этой функции, а в каждой функции в проекте. То ли дело get_api_auth(token: str) -> Header
.
Аннотации типов несут огромную пользу: делают код читаемее и защищают от ошибок (mypy
проверяет, что вы передаёте в функцию аргументы тех типов, что были заявлены). По моему опыту в реальных проектах аннотации пока используются не везде, но уже много где. Кроме того, я не видел ни одного джуна, который умеет в аннотации типов, поэтому если бы он мне попался, получил бы большую фору.
Я разделяю владение аннотациями типов на три уровня. Давайте сосредоточимся на первом, это когда вы умеете в аннотацию базовых типов без особых извращений и настроили mypy для проверки. Это работа на пару вечеров. Начать можно с пары гайдов (например, Using Python’s Type Annotations и Python Type Checking Guide), добавления в закладки базового читлиста и использования flake8-annotations-coverage (он не даёт писать неаннотированный код всегда).
Нет CI
Выше у нас появилось куча вещей, которые нужно постоянно запускать: flake8
, mypy
, pytest
. Если это не делается автоматом, то пиши пропало: нельзя всё время помнить про это всё, перед некоторыми коммитами что-то да забудешь. Тут-то и пригождается CI.
В 2021 настроить CI — совсем простое дело. В первый раз, конечно, придётся повозиться, но оно того стоит. Самые популярные варианты–Github Actions, Travis и Gitlab CI, у всех есть бесплатные варианты.
Короче, советую потратить время на овладение этим навыком, там нет каких-то хитрых инфрастурктурных девопс пререквизитов. Про Тревис я писал в отдельной статье (Короче говоря: TravisCI). Про Github Actions хорошо написано в официальной помощи, начать можно с интро.