Как стать автором
Обновить
3
0
Sergey Vasilyev @nolar

Пользователь

Отправить сообщение

Но это работает только в runtime. В type-checking time (e.g., mypy) декоратор не выполняется. Лишь type-checker решает там какие-то свои уравнения на основе одних лишь аннотаций.

wrapt в официальной документации такие случаи с опционально-параметризированным декоратором тоже предлагает решать в три этажа; ну или в два: https://wrapt.readthedocs.io/en/latest/decorators.html#decorators-with-optional-arguments. Так что про "всё реализовано" — не совсем верное утверждение.

Подход интересный. Стоит упомянуть, что помимо функций довольно часто декорируют классы. Но не всё можно передать в декоратор. Точнее, передать можно всё — если вызывать как функцию — но вот именно как декоратор Python позволяет его использовать только с def & class — на уровне синтаксиса; на переменные и, например, лямбды, наложить декоратор не получится (а хочется иногда).


Но увы, я лично не понял, так ли проблематична проблема, которую решает эта библиотека. Добавляют ли лишние парочка строк кода с типовым паттерном больше сложности, чем дополнительная 3rd-party зависимость, этот паттерн реализующая?


А если я хочу декоратор тройной вложенности, то это не просто так. Например, на первом уровне я проверяю валидность аргументов декоратора и выкидываю ошибку если что-то не сходится — ещё на этапе импорта модуля. На втором уровне я хочу сделать inspect оборачиваемой функции и что-то сохранить в памяти чтобы это не вычислять на каждом вызове; например, понять, sync она или async, returning или yielding. И на третьем уровне я не просто вызываю ту функцию, но оборачиваю её в другую логику, например, try-except или пост-обработку результата или вставку дополнительных аргументов. Каждый уровень делает своё дело — его нельзя пропустить.


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


Гораздо более болючей болью декораторов является типизация — пока нет ParamSpec + Concatenate из PEP-612 для Python 3.10. Да и с ним не сильно легче — особенно когда в оборачиваемую функцию добавляются/удаляются аргументы (hello, partials). А также боль управления пачкой однотипных декораторов с огромным списком почти одинаковых аргументов каждый, но так, чтобы это переваривал и mypy, и IDE (ну хотя бы PyCharm). Не уверен что тут вообще есть решение.

Круто! Поздравляю с релизом!


PS: Если кто-то ищет способы писать операторы именно на Python, то можете также глянуть https://github.com/nolar/kopf (ворую внимание ;-) ).

Почему забудут? Ну, почему бы и не забыть?


Почему некрасиво? Потому что в Python-based DSL их предметной области — K8s-оператор чего-нибудь — вносится сущность, которая не даёт им никакой пользы и выгоды, и не относится к предметной области, которой они оперируют, ни даже к предметной области K8s-операторов как таковых. Leaked abstraction во плоти.


И, кстати, потому и забудут: сущность, не относящаяся к предметной области, — первый кандидат на забывание. Чем больше правил, требований и соглашений вводится, тем хуже они соблюдаются (фраза верна в любом контексте с людьми).

Кстати, согласен. Полезная фича, хоть и спрятанная и неочевидная.


Во фреймворке Kopf сначала выполняется код фреймворка, потом пользовательские функции или обработчики, и потом опять код фреймворка для некоторых функций, вызываемых пользователями из обработчиков.


Совершенно бесполезно и бессмысленно просить пользователей передавать какие-либо аргументы "насквозь", даже если это будет один объект-контекст: всё равно забудут; да и будет некрасиво.


И тут контекстные переменные приходят на помощь: во фреймворке перед входом в пользовательские код устанавливаем значения, а в вызываемых пользователями функциях восстанавливаем значения. И так эти значения проходят "сквозь" пользовательский код, не требуя никаких действий со стороны пользователя.


Для примера, передача текущего обрабатываемого случая/объекта:



Или подобное — вызов вторичных обработчиков из главного обработчика, когда нужно знать хотя бы идентификатор главного:



Но есть нюансы, конечно. Нельзя вызвать одну задачу (например, login()), которая заполнит эти переменные, а потом другую, которая их использует (например, doit()). Значения переменных уходят вглубь стека и в порождённые задачи, но никак не в родительские или в одноуровневые родственные задачи. Это местами немного раздражает, так как приходится делать обёртку вокруг этих login-doit, которая сама и хранит состояние.


Но, несмотря на полезность для некоторых видов задач, эти контекстные переменные — просто хитрый вид глобальных переменных. Глобальные переменные чреваты тем, что в коде сложно проследить откуда приходят значения переменных — если они приходят не через аргументы функций по стеку вызовов. И эти контекстные переменные открывают портал в ад (в плане отладки). Вопрос лишь в том, когда (не "если") в проекте появится тот человек, который начнёт ими злоупотреблять.

Хорошая статья, спасибо. Приятно видеть что тема операторов стремительно набирает обороты — скоро будет k8s-оркестрация всего и вся, а не только контейнеров.


Немного отсутствует момент, где вызывается handle(specs) — чтоб понять как и что туда передаётся, и как он реагирует на изменения этих specs.


А если вам потребуется писать более сложные операторы, не обрастая при этом инфраструкторной логикой, а только лишь логикой предметной области, то рекомендую взглянуть на Kopf: https://github.com/zalando-incubator/kopf/ (документация: https://kopf.readthedocs.io/)


Мы тоже начинали с примерно того кода, который в статье. Но потом оно обрастало деталями, многими деталями, очень многими деталями, расползлось по паре-другой репозиториев, и в конце-концов вылилось во фреймворк.


Код задачи из примера выглядел бы как-то так:


import kopf
import kubernetes

rules = {}

@kopf.on.resume('flant.com', 'v1', 'copyrators')
@kopf.on.create('flant.com', 'v1', 'copyrators')
@kopf.on.update('flant.com', 'v1', 'copyrators')
def new_rule(name, spec, **kwargs):
    rules[name] = spec
    for namespace in _get_all_namespaces():
        _ensure(namespace, spec)

@kopf.on.delete('flant.com', 'v1', 'copyrators')
def no_more_rule(name, spec, **kwargs):
    for namespace in _get_all_namespaces():
        _purge(namespace, spec)
    if name in rules:
        del rules[name]

@kopf.on.resume('', 'v1', 'namespaces')
@kopf.on.create('', 'v1', 'namespaces')
def ns_in_sight(name, **kwargs):
    for rule in rules:
        _ensure(name, rule)

def _ensure(namespace, rule_spec):
    pass  # создаём secrets/configmaps

def _purge(namespace, rule_spec):
    pass  # удаляем secrets/configmaps

def _get_all_namespaces():
    api = kubernetes.client.CoreV1Api()
    return [ns.metadata.name for ns in api.list_namespace()]

Не уверен, что я уловил всю логику, конечно. И не тестировал, конечно. Но примерно так выглядел бы оператор, который и на rules, и на namespaces реагирует.


Фреймворк, конечно, пока в версии 0.x. Но уже почти устаканился.

Везде на западе з/п пишется gross per year (брутто в год). Потому что налоги+страховки варьируются очень индивидуально в зависимости от уровня совокупного дохода семьи, возраста, женатости, колва детей, состояния здоровья, региона проживания, вероисповедания, и чёрт знает чего ещё — в итоге могут варьироваться от 20% о 45% (для разработчиков скорее в районе 35-42%).
Средняя зарплата в Берлине по состоянию на начало 2017 — 60-65k (seniors), 45-50k (middles) — по данным опроса группы русскоязычных айтишников. Смотрите картинку:

image



В Мюнхене — 60-70k и 55-65k соответственно.

На текущий момент данных нет, но, судя по находимым офферам, в Берлине senior'ы уже получают 70-75k. Возможно, это штучные примеры, а не массовый тренд — ждём опроса в конце года.

На блюкарту в 2017 минимальный порог 51k вообще, и 39k для «особо востребованных профессий», в т.ч. айтишников всех мастей.
Рост вакансий по языкам сам по себе любопытен, но, увы, не отражает изменения баланса между языками.

Не могли бы вы посчитать не рост вакансий вообще, а либо рост/падение доли вакансий каждого языка в общей массе (например, php = было 5404/sum(2015), стало 9707/sum(2016), прирост = …), либо прирост каждго языка относительно прироста рынка в целом (например, php +79%, но все языки вместе взятые +50%, а, значит, php лишь +29%)?
А почему не Graylog (который тоже на ElasticSearch, но без Kibana, и специально для логов)? Чем не подошёл?
Готов предположить, что в БД есть логика (триггеры, процедуры), и вот там надо сбрасывать кеш. Была подобная ситуация, только с memcached из Oracle PL/SQL. Вполне себе реальная задача, а не just for fun.

Косяк, конечно, в том, что создатель кеша (PHP-что-то-там) и инвалидатор кеша (PostgreSQL) находятся в разных слоях архитектуры, и тем размазывают ответственность за кеш (ну или данные — как посмотреть). Но это исправлять дольше и дороже.
А можно ли вашу систему прикрутить для защиты трафика на кастомной баннерке? То есть не гуглы/яндексы, а вот собственная/сторонняя баннерокрутилка, но пропускать всё через вас.
Монетизация на чём строится? Только реклама? Или сервисы? В каких пропорциях? Основная проблема почти всех сайтов недвижимости — это то, что их трудно монетизировать; поэтому бесплатные альтруисты быстро умирают. Каковы ваши планы?
А разве это заслуга разработчика что проект принёс много денег? Вот что вовремя запущен — то да. А деньги — это заслуга продавцов и всех из направления BezDev'а.

Насчёт накосячил — разработчик может не согласиться что это его вина. И тогда всё скатывается к авторитаризму, где где решения принимаются лично руководителем, и теряется прозрачность и предсказуемость системы.
Очень интересная статья. Большое спасибо автору за ее публикацию. Тема численной оценки труда разработчиков меня сейчас интересует особенно сильно, и чужой опыт очень полезен. Есть ряд вопросов, которые хотел бы уточнить:

Как вы добиваетесь и проверяете достоверность отчетов по времени? Кто и как расставляет баллы сложности на задания/проекты? Насколько справедливой коллектив считает эту оценку? Сколько времени занимает процедура оценки задач? А сколько — подсчета итогов?

И самое главное: как масштабируется эта система при росте команды до 3-4-5 команд? Все предыдущие вопросы интересуют в большей степени именно в этом ключе.
Ну, раз на порше кайене, то тем более стартапер — известно ж что все стартаперы мужского пола мечтают о красной спортивной машине, желательно с открытым верхом :-)

Среди программистов тоже есть стартаперы. Полно стартаперов. Но в собеседованиях такого рода они не участвуют. Это удел рядовых наёмников, то есть «плотников-only» «программистов-only».

Предлагаю аналогии, коль уж они выстроены, проводить хотя бы в сопоставимых уровнях компетенции и режимах работы.

И, возвращаясь к исходной идее, если бы рядовые наёмные плотники без связей, стартаперства и инноваций, получали бы столько же, сколько и рядовые наёмные программисты без связей, стартаперства и инноваций, то и собеседовали бы их точно так же (вот как описано в посте).
Ну, во-первых мы тогда говорим уже скорее о предпринимателе, да ещё и инноваторе, и его надо сравнивать со стартаперами и фрилансерами. Некоторые из аналогичных программистов в месяц делают такие деньги, что ой. Тут другая шкала.

Во-вторых, это по слухам, и гипотетически. Я вот тоже слышал что некоторые программисты (ну, точнее софтварные инженеры) в некоторых компаниях делают по 400-500тр/мес. Но это уникумы или по ситуации, или по талантам. Рынок уникумов — тоже совсем другой рынок с другой шкалой.
Это среднестатистически для хорошего плотняка/столяра, или это какой-то конкретный индивид имеется в виду?
Трёшку чего, пардон?
1
23 ...

Информация

В рейтинге
Не участвует
Откуда
Москва, Москва и Московская обл., Россия
Дата рождения
Зарегистрирован
Активность