Skip to content

Latest commit

 

History

History
108 lines (73 loc) · 12.6 KB

README.md

File metadata and controls

108 lines (73 loc) · 12.6 KB

Практическое задание по курсу PL-001

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

Мануалы

  • Запуск локальных проверок — как установить uv на macOS и Windows и запустить скрипты, которые локально выполняют те же проверки кода, что и CI на GitHub.
  • Сдача домашнего задания — как загрузить решение в свой форк, оформить Pull Request в исходный репозиторий и что нужно для того, чтобы работа была принята на проверку.

Задания

  • Часть 1. Генератор идентификаторов Twitter Snowflake — нужно написать генератор 64-битных числовых идентификаторов, в которые упакованы метка времени, номер узла и счётчик последовательности. Такие идентификаторы уникальны и примерно упорядочены по времени, а из самого идентификатора можно узнать, когда и на каком узле он был создан.
  • Часть 2. CRUD и корзина для интернет-магазина — нужно реализовать хранилище товаров в памяти (список кортежей), операции создания, чтения, изменения и удаления записей, аккуратную работу с ценами через Decimal и корзину покупателя, в которую товары переносятся со склада и обратно без потери количества.

Критерии оценивания

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

Условия принятия работы

Работа принимается к оцениванию, только если выполнены все условия:

  • код проходит проверки ruff и MyPy (запустить их можно локально);
  • работа сдана до дедлайна.

Если хотя бы одно условие не выполнено, работа не принимается и оценивается в 0 баллов.

Как считается балл за правильность

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

Группа тестов Доля веса блока Что проверяет
Базовые (типичные входные данные) 70% Основная логика реализована верно
Граничные (пустой ввод, нулевые и предельные значения, повторы и т. п.) 30% Обработка особых случаев

Формулы:

балл_блока = 0.7 · доля_пройденных_базовых + 0.3 · доля_пройденных_граничных
балл_за_правильность = 10 · Σ(вес_блока · балл_блока) / Σ(вес_блока)

Дополнительные правила:

  • Нереализованный функционал. Блок, в котором функционал не реализован (заглушка, pass, NotImplementedError), получает 0 баллов. Остальные блоки оцениваются как обычно, дополнительного штрафа за нереализованное нет.
  • Ошибки выполнения. Тест, в котором возникло необработанное исключение, считается проваленным.
  • Зависание. У каждого теста есть ограничение по времени выполнения. Если решение не укладывается в него (например, из-за бесконечного цикла), тест считается проваленным.

Штрафы за оформление

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

У каждого нарушения есть уникальный код: S — серьёзные, M — средние, T — типовые. При проверке преподаватель указывает в комментарии к работе только коды (например, S1, M2, T1), а расшифровку и штраф можно найти в таблицах ниже.

Серьёзные нарушения (−1 балл за каждое)

Код Нарушение Что имеется в виду
S1 Копипаста Вместо вынесения повторяющейся логики в функцию, метод или цикл один и тот же (или почти тот же) код скопирован несколько раз. Мешает расширяемости: любое изменение приходится вносить во все копии
S2 Слишком длинные функции Функция делает много разных вещей одновременно (вычисления, проверки, преобразования, форматирование в одном месте) и не читается целиком. Ориентир: более 30–40 строк или несколько несвязанных обязанностей. Такой код тяжело читать и поддерживать
S3 Магические значения Числа и строки с неочевидным смыслом прописаны прямо в коде, а не вынесены в именованные константы. Как и копипаста, мешает расширяемости: значение приходится искать и менять по всему коду
S4 Слишком широкий перехват исключений Голый except: или except Exception: без необходимости; молча проглоченные ошибки (except ...: pass). Так можно пропустить что-то важное
S5 Изменение входных данных Функция неожиданно изменяет переданные ей аргументы, хотя из названия и описания это не следует. Неожиданное поведение, источник серьёзных ошибок

Средние нарушения (−0.5 балла за каждое)

Код Нарушение Что имеется в виду
M1 Большая вложенность Более трёх уровней вложенности (if, for, while, try, with) внутри одной функции. Лечится ранним возвратом (return, continue) и выносом логики в отдельные функции
M2 Неинформативные имена Имена вроде a, tmp, data2, x1, а также имена, не отражающие суть, или не соответствующие PEP 8 (например, camelCase для функций и переменных)
M3 Избыточные глобальные переменные Изменяемое глобальное состояние там, где достаточно параметров, возвращаемых значений или атрибутов класса
M4 Мёртвый код Код, который нигде не используется: неиспользуемые функции, классы, переменные, константы, импорты, недостижимые ветки. Сюда же относятся крупные куски закомментированного кода «на будущее» и оставленный отладочный print. Затрудняет чтение, но на работу программы не влияет

Типовые нарушения хорошего тона (−0.25 балла за каждое)

Код Нарушение
T1 else или elif после return, raise, continue или break
T2 Явное приведение к bool в условиях (if bool(x):) и сравнение с True / False (if x == True:)
T3 Сравнение с синглтонами и членами enum'ов через == / != вместо is / is not
T4 Проверка пустоты коллекции через len(x) == 0 вместо if not x
T5 Обход через for i in range(len(items)), когда индекс не нужен (вместо for item in items или enumerate)
T6 if cond: return True else: return False вместо return cond
T7 Изменяемое значение по умолчанию у аргумента (def f(x=[]))
T8 Ручная конкатенация строк вместо f-строк
T9 Избыточные комментарии, пересказывающие очевидный код

Штраф за списывание

Если работа подозревается в списывании, студент получает −5 баллов. Эти баллы не вычитаются из оценки за правильность, а заменяют итоговую оценку: итоговой оценкой становится −5, независимо от результата тестов.

Студент может оспорить этот балл на занятии, доказав, что не списывал, а написал код самостоятельно (например, объяснив решение и ответив на вопросы по нему). Если подозрение снимается, работа оценивается по обычным критериям.

Итоговая оценка

если есть подозрение в списывании:
    итоговая_оценка = −5
иначе:
    итоговая_оценка = max(0, балл_за_правильность − штрафы_за_оформление)

Итоговая оценка за домашнее задание округляется до ближайшего целого по правилам математики: дробная часть от 0.5 и выше округляется вверх, меньше 0.5 — вниз (например, 7.5 → 8, 7.4 → 7).

Как оспорить оценку

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