Вот мой примерный шаблон проекта для генерации исполняемого модуля через PyInstaller, там много старья типа запускалки тестов, написанной почти 20 лет тому. Но работает, а работает — не трогай:
Хотя бы ради ваших студентов обновите на то, что в тренде.
Я на ruff пересел, вместо flake8 и black. Устанавливаются быстрей, работают быстрей, делают тоже самое. Ну и кроме этого всю контору перевели на него и uv.
После прочтения комментариев, у меня создалось впечатление, что многие потеряли мысль, что это рефакторинг. Код который не пригоден ни для многопоточности ни для локализации до рефакторинга, не должен стать таким после. Это написанно в определении рефакторинга.
Стал ли код после рефакторинга лучше? Однозначно да. Теперь вся разложенно по полочкам, все внутренние зависимости внутри функции разрешены.
Стал ли код после рефакторинга идеальным? Нет, код вонял до, код воняет после, но чуть меньше.
Можно ли было полностью переписать этот код оставив публичное апи? Да можно. Код бы от этого выиграл. Это был бы также рефакторинг. Но не подошёл бы для примера.
Пример плохой? Да. Чтобы понять такой подход для рефакторинга, нужно пример, где к середине чтения функции уже забываешь, что было в начале и на скролл уходит больше времени, чем на чтение. Такой рефакторинг как в статье можно сделать достаточно быстро, не за раз, но серией изменений. И после этого можно попробовать переписать нормально.
Линтер же не видит разницы между двумя ситуациями и заставляет убирать эту семантику в угоду своим правилам. В реальности конечно же все пишут как попало и о семантике не думают, но тем не менее.
Поэтому я и выбираю консистентность, ведь её можно реально достичь.
Есть ещё путаница с концепцией языка. Тот же декоратор в питоне может быть и прокси и кэш и декоратор и для обзёрвера использоваться, и фабрику можно с ним строить.
Если импортировать один и тот-же модуль из разных папок, например добавить текущую директорию и её родителя в sys.path то можно. Разные пути, разные модули.
Для Питона я решил делать без елсе, так как на это есть линтер и можно сделать консистентно для всего проекта.
Видел ещё предложение иметь только один return в функции, так проще следить за потоком управления, но получается больше бойлерплейта. Надо будет попробовать на каком-нибудь пет проекте.
Что-то кажется пропущенно в середине. Я понимаю, что вы хотите проиллюстрировать, но не понимаю вашего примера.
А ещё если убрать синглтон из этих рассуждений и заменить его простым классом, то проблема не решится. Не в паттерне тут дело.
А можно выкладку, как и что вы считаете?
Это делается человеком? Обычно black --check на CI запускают.
Мне по началу тоже было непривычно, но потом норм. Простота настройки и отсутствие споров какой параметр лучше того стоит.
Если вы работаете с кодом один, тогда норм запускать только локально. Хотя мне лень запускать и я через https://pre-commit.com/ настроил.
У него своя философия которая экономит время при работе в команде. Чем пользуетесь вы и сколько у вас настроек не по умолчанию?
Хотя бы ради ваших студентов обновите на то, что в тренде.
Я на ruff пересел, вместо flake8 и black. Устанавливаются быстрей, работают быстрей, делают тоже самое. Ну и кроме этого всю контору перевели на него и uv.
В вашем случае, какие из применёных практик стоило бы подключить с самого начала проекта?
Хорошая история успеха. Поставленна полезная цель. И метрики не забыли и коллаборации с другими командами есть. Кейс конфетка для резюме.
Если есть mypy или что-то подобное, то можно защитить при помощи аннотаций типов. Поставить на объект типа dict аннотацию только для чтения https://docs.python.org/3/library/collections.abc.html#collections.abc.Mapping и ловить все изменения. Это вполне бюджетно.
В первых статьях были ответики. Автору ещё предстоит сделать много открытий.
Меж тем не каждый пет-проект доходит до продаж. Ниша выбранна хорошо.
AI меняет правила игры. И это необратимый процес.
После прочтения комментариев, у меня создалось впечатление, что многие потеряли мысль, что это рефакторинг. Код который не пригоден ни для многопоточности ни для локализации до рефакторинга, не должен стать таким после. Это написанно в определении рефакторинга.
Стал ли код после рефакторинга лучше? Однозначно да. Теперь вся разложенно по полочкам, все внутренние зависимости внутри функции разрешены.
Стал ли код после рефакторинга идеальным? Нет, код вонял до, код воняет после, но чуть меньше.
Можно ли было полностью переписать этот код оставив публичное апи? Да можно. Код бы от этого выиграл. Это был бы также рефакторинг. Но не подошёл бы для примера.
Пример плохой? Да. Чтобы понять такой подход для рефакторинга, нужно пример, где к середине чтения функции уже забываешь, что было в начале и на скролл уходит больше времени, чем на чтение. Такой рефакторинг как в статье можно сделать достаточно быстро, не за раз, но серией изменений. И после этого можно попробовать переписать нормально.
Поэтому я и выбираю консистентность, ведь её можно реально достичь.
Есть ещё путаница с концепцией языка. Тот же декоратор в питоне может быть и прокси и кэш и декоратор и для обзёрвера использоваться, и фабрику можно с ним строить.
Я смотрю на это с другого ракурса, некоторые паттерны настолько хороши и актуальны, что их включили в спецификацию языка.
Если импортировать один и тот-же модуль из разных папок, например добавить текущую директорию и её родителя в sys.path то можно. Разные пути, разные модули.
Я так его и делаю, когда тесты не пишу. А когда пишу избегаю этот паттерн.
Для Питона я решил делать без елсе, так как на это есть линтер и можно сделать консистентно для всего проекта.
Видел ещё предложение иметь только один return в функции, так проще следить за потоком управления, но получается больше бойлерплейта. Надо будет попробовать на каком-нибудь пет проекте.