Pull to refresh
35
2.1
Максим @danilovmy

Программист разработчик

Send message

Может стоит убрать один из двух завершающих абзацев?

А по теме - то, скорее всего, речь идёт о переезде на архитектуру modular Monolith. Это я сужу по тексту, но и на практике именно эта архитектура является логичным звено эволюции монолита.

@Snooper Использую VSCodium https://github.com/VSCodium/vscodium (переработанная версия VS Code). Тормозов, кроме прокладки, между моим компом и клавиатурой, не встречал. Но настройка требует сил, там шаманить надо с магазином приложений.

@Pol1mus Codeium последние два месяца люто тормозил, у меня стояла 1.8.18 - 1.8.20. После 1.8.64 вроде работает опять нормально.

Очень круто! В "размер имеет" два мм в описании. Или это намек, что в миллиметрах?

Подтверждаю. После множества ОЙ-AI- плагинов, Codeium как глоток свежего воздуха

Спасибо @michaem Супер статья, прочел влет. Однако, отмечу важный момент про техдолг. Решение на устаревших технологиях не является техдолгом согласно его определению в этой статье. Кстати и Фаулер, популяризатор этого понятия в разработке ПО, и родоначальник этого термина Каннингем тоже не подразумевали этого. На примере - ставя новые оглобли на карету - я вроде использую устаревшую технологию, но решение не содержит никакого техдолга.

И далее в статье все упоминания, в т.ч. и про фатальные промахи, были именно про ошибки в коде, а не про то что версия устарела.

После прочтения созрел вопрос к автору, а есть ли ПО по отслеживанию техдолга? Типа как в продуктах sonar, но только что бы речь шла не про отслеживание ошибочных паттернов программирования, а о более высоком уровне абстракции слежения за разработкой кода?

Странно что не указано, что django-formtools .входил в состав Django до версии 1.8. Я вот сталкивался с этим в реальной жизни в Django и рад, что его выпилили. Поскольку использовать это в нормальном состоянии невозможно.

Первая проблема - wizard.manager который калька с formset.manager. Это который чистит current_step. С регулярной ошибкой ValidationError: [u'ManagementForm data is missing or has been tampered with'] придется смириться.

Вторая проблема - С регулярной ошибкой ImproperlyConfigured: TemplateResponseMixin из за неверного current_step придется смириться.

Третья проблема - Это все hardcode. .можно создать три View, и пересылать на form_valid с одного представления на следующее по цепочке. Но и это hardcode: поля форм статичные.

Именно потому этот очень-очень-очень частный случай в коде я бы избегал использовать, но да, для экзотики можно и попробовать ;)

Автору@badcasedaily1спасибо, напомнил мне про мои давние проекты, ээх меланхолия...

Чет намногокодил, можно проще. Обосную:

По аналогии с i18n_patterns ставим враппер urlpatterns_transformer на корневой urlpatterns и на старте сервера превращаем стандартный лист в пропатченный, не надо каждый path ручками менять:

# settings.urls.py
urlpatterns = urlpatterns_transformer([
    path("users/<int:user_id>", user_handler),
    path("users/me", me_handler),
]

Уже на этапе патчинга (старта сервера) можно проверять наличие статической составляющей, и ставить в Pattern:

path( .... Pattern=PrefixRoutePattern if idx and idx !=1 else RoutePattern)      

Но и это так себе улучшение, тогда уж третий StaticRoutePattern нужен. Но и это не надо делать, поскольку для префиксов, есть отличное решение с include, померяйте относительно примеров в статье с вот таким вариантом:

#urls = [
#    my_path("users/<int:user_id>", user_handler),
#    my_path("users/me", me_handler),
#]

urlpatterns = [path("users/", include('users.urls')),]

# users.urls.py
urlpatterns = [
    path("<int:user_id>", user_handler),
    path("me", me_handler),
]

Если не нравится новый файл - include принимает и контейнер с url:

class users_urls:
    urlpatterns = [path("int:user_id", user_handler), path("me", me_handler)]

urlpatterns = [path("users/", include(users_urls, 'users_sub_url')),]

Мне кажется, что результат удивит.

Как вариант копания URLdispatch предлагаю посмотреть на сепарирование urls по методам [GET, POST, PATCH], так делают многие фреймворки. Вот тут будет интересный расклад, если PATCH редкий, то он будет срабатывать максимально быстро. Я рассказывал об этом на своем недавнем докладе про "Django FTL", там же линк на репо.

Ну и конечно не плакать надо над 10 секундами ожидания ответа базы, а смотреть, что за ерунда творится. В качестве примера если есть условие с OR c несколькими JOIN - вероятно стоит переехать на Subquery, оказывается, он может работать быстрее, но без explain все равно говорить не о чем - нет информации.

Желаю автору @deliro успехов c Django, там много чего стоит подкручивать. И в первую очередь точно не url.

Почти угадал: в "Human IT Care" - работа с JWT токенами, созданными в AWS COGNITO. в "Kpler", CQRS по записи и выдаче GPS координат судов. Это то, что видел лично. Вероятно, другие варианты может рассказать Julia Solórzano, автор этой методологии и организатор DjangoCon US.

@Ritoneet- Спасибо. Я рад, если стало интересно.

В статье пример про healthcare data lake из реальной жизни. 340 000 строк кода, я работал на проекте в роли приходящего seniour back-dev. Доклад про проект, и как я его пилил, для распиливания написал скрипт. Суть - выбираем один endpoint, натравливаем скрипт, получаем папку с одним файлом и кучей зависимости в подпапках. Добавляем только 1 строку в начале файла, импорт asgi, пихаем в контейнер запускаем через uvicorn. Повторить 412 раз.

Что получили - Монолит разбитый на микро куски, разумеется с кучей повторений в каждом куске. Каждая часть запускается отдельно. Никакого рефакторинга, кроме одной строки импорта. Разбили команду на 5 подкоманд, каждая свою пачку сервисов отслеживает если что падает - правит только свое. Стало быстрее: поиск и отладка ошибок и тестирование. Стало сильно напряжнее у девопсов. Придумали систему автоматизации создания репозитория, чтобы все было однотипно, и минимизировались ошибки при создании очередного суб репозитория µСервиса, а то глаз замыливается, если вручную создавать.

После 10 выделений в сервис стало понятно, какие файлы не надо копировать, они просто устанавливаются из репозитория монолита как pip install git+https://github.com/...

В итоге одну команду усилили и отправили на работу с этим ядром, которое импортируется в каждом сервисе. Все еще никакого рефакторинга.

Что сейчас. 19 человек ведут проект, 5 команд, каждая работает со своими кусками кода, и это минимальное количество файлов. центральный кусок очень медленно начали рефакторить, методом вывода некоторого микро кода в модули. Поскольку отщипываем от монолита во внешние репозитории, то сам монолит работает, как и работал. Сервисы монолита потихоньку отключали, поскольку на standalone все работает. Пока не были уверены, работало параллельно.

Из больших доработок - композитный генератор openAPI документации. По нему у меня доклад будет в этом году.

После внедрения, (месяца 3) - я уже стал не нужен, ребята сами справляются. В реальности им нужна была просто инструкция, что делать с монолитом, в котором они копошились, но не могли вынырнуть и посмотреть снаружи.

А вот мне после этого контракта стало сложно с обычными Django проектами работать: так и хочется начать µ-Djangо всюду впихнуть, потому, как это проще и быстрее. История про молоток и гвозди в полной мере про меня сейчас.

Огромное спасибо, я передам Майе. Ей будет ооочень приятно.

Есть видео на немглийском на ютубе, где я именно это и делаю, плюс скрипт в репозитории, который вытаскивает файл для микрофичи ссылки в статье. Если с силами соберусь - превращу в статью. Суть в том, что мы создаем µ-сервис БЕЗ рефакторинга.

В другом докладе я переписываю микрофичу на Robyn и на Litestar. В репозитории смотреть в папках django-fastapi, django_and_litestar, django_and_robyn.

.

Спасибо. Согласен, путь именно туда...

Зарефакторить монстра - вряд ли получится, такой проект уже ничего не спасет :)
Эта технология поможет запустить в работу одни или несколько entpoints без рефакторинга.

Привет, спасибо за примеры.

Один вопрос, если на инициализации класса присваиваются константы, почему не сделать их атрибутами класса? Как то так:

class MLExperimentManager:
    data = None
    X_train = X_test = y_train = y_test = None
    model = None
    experiments_log = None
    log_path = 'experiments_log.csv'

По коду можно много поправить, но если работает, то, разумеется, лучше не трогать. ;)

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

Итак. Почему хорошо:

  1. Просто. Это хорошо. Это не задротство с selenuim.

  2. Молодец что не побоялся рассказать! Это прям очень смело заехать на хабр.

  3. Есть комментарии и отлов прерываний. Прям верным путем идете товарищи. Долго, еще, конечно, но направление норм.

Что стоит добавить:

@temabedдля поучиться чему-то реально современному, поставь камеру перед экраном, сделай распознавание объектов real-time и научи машину находить кнопку на экране, после добавь "человеческий" сдвиг курсора, что бы аналайзер не начал подозревать, что робот курсор дергает. В итоге прокачаешь требуемые навыки, станешь востребованным специалистом и перестанешь страдать такой фигней, как генерация псевдокоинов за дорогое и неэкологичное электричество.

И главное, автор, не слушай никаких советчиков. А то они тебе сейчас такое насоветуют... как я, например.

Все бы хорошо, и даже возьму на заметку...но.

Покрытие обычно относится к тестированию кода проекта. Инструменты покрытия кода, в данном случае coverage, помогают определить, насколько хорошо код тестирован путем анализа, какие части кода проекта выполняются во время Тестирования.

И если говорить о подсчете coverage в runtime получается, что проект это и есть "тест" для подсчета покрытия этим тестом проекта.

Я знаю, многие тестируют в runtime на клиентах, но, все же, best practices - это создать тест, который симулирует поведение клиента.

Вложенные библиотеки обычно не тестируют, отдавая тестирование на откуп создателям библиотек. А coverage считается относительно объема кода проекта.

Но если очень хочется посчитать покрытие импортируемых библиотек при запуске через командную строку используется ключ --source и после, например, имя импортируемого модуля --source flask.

Ну и конечно, если говорить про автоматизацию, то должен быть написан тест, который "запустит" app.py, сделает вызов по main route 127.0.0.1:5000 проверит что ответ верен (200 статус там и т.п.) и отключится. Желательно, чтобы тест еще сделал несколько других действий типа дернул фальшивый url и проверил что 404 или отправил post туда где только get и проверил статус ошибки.

А после автор тестов насладится прекрасной статистикой покрытия проекта открыв страницу, содержащую покрытие автоматическими тестами. ;)

Вероятно, потому, что смешивая, мы нарушаем принцип поиска информации. В итоге ответ на вопрос "где искать" становится не очевидным.

Автор, спасибо за ссылку! Очень познавательно.

запоздала статья. Лет эдак на ...дцать.

В последней Django к формам можно крепить html в котором и кнопки есть и все что надо.

https://docs.djangoproject.com/en/5.0/ref/forms/api/#django.forms.Form

Кроме этого, все виджеты имеют свои шаблоны Можно переопределить шаблоны виджетов полей. https://docs.djangoproject.com/en/5.0/ref/forms/widgets/#widget

И напоследок. Я очень сочувствую всем, у кого настройка рендера формы происходит в __init__ а не непосредственно перед рендером на методе render. Как-никак на POST приходит запрос и надо только данные проверить, но у тех, кто все запихал в __init__, еще и инициализация рендера происходит. На 170 полях это становится больно. Да, я знаю, что в форме не должно быть столько полей.

да, пожалуйста. Посмотри ещё соседнюю статью про метаклассы, там тоже интересно и обсуждение активное.

Спасибо за поднятие темы еще раз в этом месяце. Могу отметить, что к пониманию, что такое метаклассы, так и не подобрались. И только в комментариях @Andrey_Solomatin наконец-то дал максимально близкое объяснение. Поблагодарил его отдельно.

Повторяя свой комментарий из соседней статьи. Метакласс это объект, который уточняет поведение какого либо другого класса, и метакласс, как и любой объект python, можно создать runtime (вопреки утверждению в статье):

MyMetaclass = type('MyMetaClass', (type,), {})

Управлять поведением класса и экземплярами класса можно несколькими способами: через декоратор, через наследование, через метакласс. Так в чем же разница?

  • Метакласс - официальный способ вклиниться в код ДО объявления класса. Это в статье отмечено, но не подчеркнуто, а ведь это единственное существенное отличие.

  • Декоратор класса: может донастраивать класс ПОСЛЕ объявления, поскольку получает на вход уже объявленный класс.

  • Родительский класс - уточняет поведение класса или экземпляров в runtime, предоставляя доступ к атрибутам и методам как напрямую так и через вызов super.

Именно хук beforeCreateClass и является тем важным инструментом метакласса, ради чего нужны метаклассы. И вот именно этот хук используется в ABC, хотя лучше бы использовать Protocol. Не реализовал метод протокола - лови Exception ДО создания класса на старте а не в runtime. Но это тоже шито белыми нитками из-за возможности объявления классов в runtime. Именно поэтому я категорически против Protocols/ABC, поскольку они способны добавить более сложные ошибки в код вместо упрощения.

Причина использования Metaclass в Django аналогична. На объявлении класса модели происходит внесение модели в реестр моделей (django.apps.apps.all_models). Последнее можно было бы решить более стандартно, например, через сигналы, но что сделано - то сделано.

В остальном по статье - утверждение "в Python все является объектом" намного глубже, чем может показаться на первый взгляд, и желаю автору добраться до настоящего понимания этого высказывания. Для этого, вероятно, стоит посмотреть повнимательнее внутрь cpython/Objects/typeobject.c

Может попробовать сократить свидания до одного в месяц и начать называть это бурной личной жизнью? Хотя... может как раз это у них "не так"?

1
23 ...

Information

Rating
1,094-th
Location
Zams, Tirol, Австрия
Date of birth
Registered
Activity

Specialization

Backend Developer, Fullstack Developer
Lead
From 8,000 €
Python
Django
Ajax
OOP
Design patterns
Vue.js
JavaScript
HTML
CSS