Мы, даже с нашими достаточно небольшими потребностями, со вздохом сползли с aws на арендованное железо. Причина, если разобраться, простая: пока всё работает, все работает. Как только что-то не работает, концов не найдешь.
Сейчас опенсорс облака уже вышли на уровень, при котором кластер из арендованного baremetal хлама вполне жизнеспособен.
В качестве дисклаймера: я, на самом деле, django orm не люблю. Автокомплит в разных редакторах от плохого до омерзительного, паршивая расширяемость, куча магии плюс сильная заточка под OLTP, так что при малейших поползновениях в сторону аггрегации/аналитики удобней откатиться в сторону raw sql.
Но вашей проблемы я не прочувствовал :)
Если миграцией базы управляет django, то есть https://github.com/rapilabs/django-db-constraints, ну или на худой конец sql прямо в миграциях.
Если база управляется извне, то в чем проблема c unmanaged моделями-то?
Если же и так и так, то в проекте есть проблемы посерьезней, чем выбор орм =)
Про ОРМ — настолько феерический бред, что не могу не отметиться.
Все звучит красиво, пока твои потребности умещаются в select * from table. В реальности же… ну, давайте на примере DSL Django ORM (первое, что в голову пришло).
queryset = User.objects.all()
if len(statuses) > 0:
queryset = queryset.filter(status__in=statuses)
if last_comment:
queryset = queryset.filter(user__post__comment__сreated_at__gt=last_comment)
if signed_in_from:
queryset = queryset.filter(signed_in__gte=signed_in_from)
if signed_in_to:
queryset = queryset.filter(signed_in__lte=signed_in_to)
cnt = queryset.count()
admins = queryset.filter(is_admin=True)
data = admins[:100]
Знакомая ситуация? Думаю, да. Неужели кому-то по кайфу каждый такой запрос обписывать этим всем ворохом " AND ".join(chunks) и прочей бесполезной белибердой????
i7, да ладно, пусть i3, по производительности ну прямо совсем не арм. Пересобрать ядро? не вопрос. Plex, транскодящий видео для тупого телевизора? запросто
нагрева выше чем 55C так и не добился
аппаратные ethernet, wifi, и sata. В мира *pi это как розовый единорог.
Wifi ловит дальше, чем на 5 метров.
возможность при желании поставить windows.
Сравнимо с малиной:
потребление. В конфигурации i5, ssd + hdd)-- 7 Вт в простое, 12 в пике
Герметичный безвентиляторный корпус
Минусы по сравнению с малиной:
цена
отсутствие GPIO
Взял такого зверя в конфигурации i5 + 4G RAM + 30G mSATA SSD, докинул старый ноутбучный винт, поставил минимальную убунту. Внешний ip, Nginx, сертификаты от letsencrypt, radarr, качалка, Plex, файлопомойка/owncloud, облако. Занято 350мб оперы, 8gb диска, loadavg стремится к нулю.
Сейчас грустно смотрю на лежащие в ящике стола малину, апельсин и банан, и понимаю, что что попытки поднять домашний сервер на архитектуре ARM характеризуются емким выражением "из говна пулю".
# v1
from operator import is_
from itertools import filterfalse
from functools import partial
is_none = partial(is_, None)
filter_none = partial(filterfalse, is_none)
filtered = filter_none(seq)
filtered2 = filter_none(seq2)
all_filtered = filter_none(chain(seq, seq2))
# v2
filtered = (x for x in seq if x is not None)
filtered2 = (x for x in seq2 if x is not None)
all_filtered = (y for x in (seq, seq2) for y in x if y is not None)
# v3
from itertools import chain
filter_none = lambda seq: (x for x in seq if x is not None)
filtered = filter_none(seq)
filtered2 = filter_none(seq2)
all_filtered1 = filter_none(chain(seq, seq2))
# v4 -- для полных лентяев типа меня
def filter_none(seq):
return (x for x in seq if x is not None)
filtered = filter_none(seq)
filtered2 = filter_none(seq2)
all_filtered2 = filter_none(seq + seq2)
Дык все равно filter_none = lambda seq: (x for x in seq if x is not None) строчки на три короче и во сколько-то раз читаемей получается
Опять же, повторюсь, посыл понятен. Просто на таких масштабах пример выходит сомнительный. В сложных случаях тоже зачастую обычный for ... in ... получается куда более… readable
Очень уж в python LINQ-style filtered = seq.where(r=> r is not None) на борту на хватает.
Буквально пара придирок по примерам… Ну или мыслей вслух, кому как нравится.
@post_processing(list)
Вообще правила хорошего тона очень уж не рекомендуют декораторам менять тип возвращаемого значения.
List comprehansion VS functools
У list comprehension есть одна потрясающая особенность: они не прерывают контекст чтения. Одним взглядом сразу становится понятно, что здесь происходит и какой тип у нас на выходе.
Вы пытаететесь утвержать, что
filtered = [x for x in seq if x is not None]
это "куча ненужной фигни" по сравнению с
from operator import is_
from itertools import filterfalse
from functools import partial
is_none = partial(is_, None)
filter_none = partial(filterfalse, is_none)
filtered = filter_none(seq)
Серьезно что ли? Посыл понятен, но пример-то свидетельствует о совершенно противоположном
А чем собственно плоха система "1 задача — 1 ветка"? Проблема с merge conflicts в случае единой ветки разработки никуда не исчезает же, просто тонким слоем размазывается по всей истории коммитов. Ну и плюс правило "последний коммит в фичаветке — это мердж из мастера" это уже давно хороший тон.
Код ревью каждого отдельного коммита — это то, с чем справится pyflakes / статический анализатор. Без общего контекста задачи ревьюер на большее не способен.
Точечный перенос коммитов из ветки develop в master не работает. Нарушение хронологии приводит к тому, что ответственный за это будет 40 часов в неделю пытаться разрулить какие-то конфликты. Оно ему надо?
if(FEATURE_ENABLED) работает только в вакууме. Пример — практически любое изменение структуры БД.
Один поломанный коммит ленивого разраба внезапно убивает тесты / CI для всех последующих. За день до релиза вероятность этого увеличивается до 100%.
И наконец, где при такой схеме бедному разработчику хранить коммиты с шикарными описаниями "test" и "dummy", особенно если он работает из более чем одного места?
В качестве бонуса: могу ошибаться, но изменившаяся индентация вокруг if(FEATURE_ENABLED) делает бесполезным git blame.
Рискну не согласиться. В подавляющем большинстве случаев (если только это не очередной вордпресс), зафиксировать окружение не только можно, но и необходимо.
В тайпскрипте? От navigate<IItemParams>(route, <any>anyObject)? Никто не помешает, ясен перец. Но в первом же кодревью за это накажут.
В каком вам удобно, в таком и описывайте.
Отличный ответ. Лично мне ни в каком не удобно.
Честно, не понимаю о чем разговор. Вас устраивает — пользуйтесь на здоровье. Меня нет, по длинному списку озвученных выше причин. От продолжения спора для меня ничего не изменится, так что удаляюсь.
как его выразить в рамках системы типов ТС
да хоть public navigate<T>(route: string, params: T, options: RequestOptions>. Довести до абсолюта public navigate<T>(params: T, options: RequestOptions> по очевидным причинам не получится.
У вас есть ф-я, которая генерит роуты, в чем проблема проверять роут в ней?
Два контраргумента:
Зачем бить "туда" и "обратно" на два разных куска, если это всё можно задать 1 раз декларативно?
(new UrlBuilderService()).makeCategoryUrl(id, itemId)?
А чем вас, собственно, не устраивает /category;id={id}? тем, что ";" вместо "-"?
Если коротко — да хотя бы тем, что я хочу именно так а не иначе. Достаточная причина? Система маршрутизации, под которую приходится подстраиваться, веет 2001м годом а-ля category.php?id[]=12&id[]=13
Конкретно в текущем проекте у нас полу-статический контентный сайт с давней историей и кучей трафика по прямым ссылкам и букмаркам (да, такое еще существует). И этот сайт по нажатию кнопки "сделать п… то" превращается в современное spa.
И я хочу чтобы у ангулара были точно такие же ссылки, какие были уже второй десяток лет.
Я много фреймворков перевидал, но пока что это первый в котором, когда настолько примитивная функция сделана настолько "для галочки".
Ваш «общий случай» не учитывает синтаксиса аргументов и именованных аутлетов
На то, что структура URL для именованных аутлетов прибита девятидюймовыми гвоздями, я предпочел не жаловаться, в Router и без этого проблем хватает.
Данный способ как раз расширяем (e.g "/category-{id}{aux:/item-{id}}"), в отличии от встроенного "вот вам url.split('/'), радуйтесь"
P.S: Вообще, думаю, спор на самом деле ни о чем. Вам стандартной схемы хватает, мне однозначно нет. Так что буду плакаться, колоться, и делать велосипед. Спасибо за интересную дискуссию.
Не-не-не.
Мы, даже с нашими достаточно небольшими потребностями, со вздохом сползли с aws на арендованное железо. Причина, если разобраться, простая: пока всё работает, все работает. Как только что-то не работает, концов не найдешь.
Сейчас опенсорс облака уже вышли на уровень, при котором кластер из арендованного baremetal хлама вполне жизнеспособен.
В качестве дисклаймера: я, на самом деле, django orm не люблю. Автокомплит в разных редакторах от плохого до омерзительного, паршивая расширяемость, куча магии плюс сильная заточка под OLTP, так что при малейших поползновениях в сторону аггрегации/аналитики удобней откатиться в сторону raw sql.
Но вашей проблемы я не прочувствовал :)
Если миграцией базы управляет django, то есть https://github.com/rapilabs/django-db-constraints, ну или на худой конец sql прямо в миграциях.
Если база управляется извне, то в чем проблема c unmanaged моделями-то?
Если же и так и так, то в проекте есть проблемы посерьезней, чем выбор орм =)
И согласен, и нет.
Django is a quite opinionated framework. Со временем просто привыкаешь не писать поперек линованной бумаги, и количество палок резко снижается.
А вот с legacy database это полный ад, да.
Про ОРМ — настолько феерический бред, что не могу не отметиться.
Все звучит красиво, пока твои потребности умещаются в select * from table. В реальности же… ну, давайте на примере DSL Django ORM (первое, что в голову пришло).
Знакомая ситуация? Думаю, да. Неужели кому-то по кайфу каждый такой запрос обписывать этим всем ворохом " AND ".join(chunks) и прочей бесполезной белибердой????
Во мне каждый раз что-то умирает
Я просто оставлю это здесь:
https://ru.aliexpress.com/item/XCY-2016-fanless-Mini-Desktop-PC-Core-i3-4010Y-Core-i5-4210Y-1-5GHZ-Dual-core/32747926428.html?spm=a2g0s.9042311.0.0.nIPnc5
Плюсы по сравнению с малиной:
Сравнимо с малиной:
Минусы по сравнению с малиной:
Взял такого зверя в конфигурации i5 + 4G RAM + 30G mSATA SSD, докинул старый ноутбучный винт, поставил минимальную убунту. Внешний ip, Nginx, сертификаты от letsencrypt, radarr, качалка, Plex, файлопомойка/owncloud, облако. Занято 350мб оперы, 8gb диска, loadavg стремится к нулю.
Сейчас грустно смотрю на лежащие в ящике стола малину, апельсин и банан, и понимаю, что что попытки поднять домашний сервер на архитектуре ARM характеризуются емким выражением "из говна пулю".
Считать так считать ))
Какой вариант вызывает минимум WTF в минуту?
Дык все равно
filter_none = lambda seq: (x for x in seq if x is not None)строчки на три короче и во сколько-то раз читаемей получаетсяОпять же, повторюсь, посыл понятен. Просто на таких масштабах пример выходит сомнительный. В сложных случаях тоже зачастую обычный
for ... in ...получается куда более… readableОчень уж в python LINQ-style
filtered = seq.where(r=> r is not None)на борту на хватает.P.S: спасибо за controlcenter :)
Буквально пара придирок по примерам… Ну или мыслей вслух, кому как нравится.
@post_processing(list)
Вообще правила хорошего тона очень уж не рекомендуют декораторам менять тип возвращаемого значения.
У list comprehension есть одна потрясающая особенность: они не прерывают контекст чтения. Одним взглядом сразу становится понятно, что здесь происходит и какой тип у нас на выходе.
Вы пытаететесь утвержать, что
это "куча ненужной фигни" по сравнению с
Серьезно что ли? Посыл понятен, но пример-то свидетельствует о совершенно противоположном
Когда я уходил, тимлид (точнее, Ведущий Специалист) что-то начинал разбираться с SVN. Но это уже без меня было.
— Мужики, я работаю в oic/lib/
— Хорошо
....
— Мужики, никто oic/lib/bibl_stroki.c не трогал последние два дня?
— Я!
— И я!
— Мля!
Как-то так.
Но тем не менее, в том коллективе, где я был молодым специалистом, было принято именно так. Видимо, хипстеры и тогда были.
С ужасом представляю, что они использовали в 97
Когда-то, на рубеже веков, мы так и работали — rsync на машины остальных разрабов.
Читал и ностальгировал.
Мне казалось, первое апреля далеко.
Если по пунктам:
В качестве бонуса: могу ошибаться, но изменившаяся индентация вокруг if(FEATURE_ENABLED) делает бесполезным git blame.
P.S: CVS в 2017? Не-не-не, Дэвид Блейн
Рискну не согласиться. В подавляющем большинстве случаев (если только это не очередной вордпресс), зафиксировать окружение не только можно, но и необходимо.
А в нынешний контейнерный век это еще и удобно.
В тайпскрипте? От navigate<IItemParams>(route, <any>anyObject)? Никто не помешает, ясен перец. Но в первом же кодревью за это накажут.
Честно, не понимаю о чем разговор. Вас устраивает — пользуйтесь на здоровье. Меня нет, по длинному списку озвученных выше причин. От продолжения спора для меня ничего не изменится, так что удаляюсь.
navigate<T>(route, anyObject), парсер лох
А где я описываю роут, например, в случае lazyLoad? В каком из двух файлов?
Два контраргумента:
А теперь вопрос — зачем мне сервис маршрутизации, когда у меня уже есть сервис маршрутизации?
UPD: изменил, парсер съел угловые скобки
Вообще не понял аргумента. Строку нельзя превратить в типизированную структуру? JSON.parse негодует.
RouterTypeService.register("int", /\d+/, (val) => typeof val === "number", parseInt, x=>x.toString());
RouterTypeService.register("uuid", /[a-f0-9]{32}/, parseUuid, x=>x.toString());
{path: "/category-{id:int}{aux:/item-{itemId:uuid}", name: 'test'}
this.router.navigate('test, {id: 10, aux: {itemId: 'aa...00'}});
Вообще не понял вопроса, если честно.
(new UrlBuilderService()).makeCategoryUrl(id, itemId)?
Если коротко — да хотя бы тем, что я хочу именно так а не иначе. Достаточная причина? Система маршрутизации, под которую приходится подстраиваться, веет 2001м годом а-ля category.php?id[]=12&id[]=13
Конкретно в текущем проекте у нас полу-статический контентный сайт с давней историей и кучей трафика по прямым ссылкам и букмаркам (да, такое еще существует). И этот сайт по нажатию кнопки "сделать п… то" превращается в современное spa.
И я хочу чтобы у ангулара были точно такие же ссылки, какие были уже второй десяток лет.
Я много фреймворков перевидал, но пока что это первый в котором, когда настолько примитивная функция сделана настолько "для галочки".
Если навигация это "редко используемый функционал", то я даже не знаю, что такое часто используемый.
К сожалению, не панацея. Я хочу проверку ссылки в момент ее генерации (о проверке в compile-time я уже не говорю).
Или хоть что-либо отличное от каши any[] в [routerLink]
Сильное утверждение. Навскидку
https://twitter.com/hashtag/++++++++++
https://twitter.com/hashtag/llllllllll3llllllll
На то, что структура URL для именованных аутлетов прибита девятидюймовыми гвоздями, я предпочел не жаловаться, в Router и без этого проблем хватает.
Данный способ как раз расширяем (e.g "/category-{id}{aux:/item-{id}}"), в отличии от встроенного "вот вам url.split('/'), радуйтесь"
P.S: Вообще, думаю, спор на самом деле ни о чем. Вам стандартной схемы хватает, мне однозначно нет. Так что буду плакаться, колоться, и делать велосипед. Спасибо за интересную дискуссию.
/off