О важности оценок пост

Занудная вводная

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

Весь этот набор осознаваем, логичен и прост. К сожалению, идеальный мир портят реальные процессы, потому что в нескольких направлениях сидят реальные люди, которые совершают ошибки. Потому что проект начинали люди, которые в условиях ограниченных ресурсов несколько упростили исходные формулы. Потому что информационные системы могут давать сбой, из-за чего на момент Х нельзя быть уверенным в том, что владеешь полной информацией. Потому что сумма S, которая выплачивается N раз округленными кусочками K * S, где K всегда разный, набегает погрешность в масштабах года ощутимая.

Для совершения операций используются фактические данные, страдающие вышеописанными недостатками. Потому требуется некий механизм корректировок. Мой механизм прост – рассчитать идеальный мир на каждый момент времени, потом сравнивать его с реальным показателями и вносить изменения.

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

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

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

Суть пста

Условно, дело в том, что я отвечаю за техническую реализацию проекта, а мой руководитель за логику и процессы. И в 70% случаев именно он понимает, что что-то не так. Он смотрит на происходящее, считает какие-то свои суммы, видит, что они не бьются, после чего бьет тревогу. В начале мне было сложно понять, как человек ни с того ни с сего, может увидеть проблему в настолько сложных расчетах. Сейчас я потихоньку начинаю это осознавать.

Если отбросить «он просто умнее меня» или «у него просто опыта больше» и начать разбираться, то есть несколько интересных путей для размышления.

Во-первых, замечаю у него сильную склонность к графическому решению задач. Помните в школе «решить уравнение графически»? Я всегда считал, что это от лукавого, а единственный правильный путь – это переписывание символов («решить аналитически»). Но он постоянно использует визуализацию.

Во-вторых, он легко дает оценки тем вещам, которые я буду считать на калькуляторе минут 5. Тут дело в том, что он сходу (пока не знаю как) выводит допустимую погрешность в расчетах для оценки, а потом очень грубо и быстро находит результат. Я про эту саму погрешность ничего не знаю, потому выполняю все формальные вычисления. Я, конечно, читал книжку «Как измерить все, что угодно. Оценка стоимости нематериального в бизнесе», то есть могу догадываться как в конкретном случае он это делает, но скорость и точность меня поражает.

В какой-то момент я задумался о том, откуда идёт эта разница. Если мы ровесники, если оба можем в простейшую математику, оба двое достаточно дотошны в своих задачах. И большая разница нашлась в образовании, точнее в предмете «физика». Я, начиная с 10 класса, этот предмет терпеть не мог: 100500 констант, значимые символы, интуитивное создание моделей. В 11 классе и ВУЗе, я не знал физику сознательно, не хотел с ней иметь ничего общего и низкие допустимые оценки меня не смущали. У руководителя все наоборот: профильная школа, вуз и специальность в нем, первые работы, – всё как раз в области «физики».

Не могу сказать, что «прикладная математика» – неудачное направление. Меня всё устраивает. Но сейчас я вижу разницу в применении математического аппарата. В моем случае – это переписывание символов (программирование), в другом – абсолютно утилитарное использование  ради более материальных целей.

Вывода «физика > математика» не будет. Но есть мнение, что она дает больше полезных навыков для реальной жизни.
[dw]

Что нащет микросервисов, ммм?

Был хайп лет 5-6 назад, когда вся хабра была забита трактовками термина, размышлениями, опытами и прочими рекомендациями на этот счет. Я к этому относился скептически, считая, что моя работа над проектом с прогнозируемой нагрузкой, где во главу угла ставится «скорость доставки фич» («выкатывание новой функцинальности» - можно называть как угодно), при том, что все, что надо масштабировать уже сделано соответствующим образом (воркеры, слушающие очереди), не требует структурной реорганизации. А значит, можно не париться, по поводу очередного веяния.

 

Всё изменилось, когда я сменил работу. Попал в ситуацию, где соотношение сервисов к количеству разработчиков было 3-4 к 1. И, конечно, всё это называлось «сервисной» архитектурой, а при продумывание того, как нам делать новую функциональность люди ориентировались на непонятные мне каноны микросервисов и «облачную архитектуру».

 

Что вообще я знал про микросервисы из статеек в интернете:

  • Всегда есть противопоставление некоему «монолиту»
  • Есть понимание, что «монолит» - енто некий сервис с API, который крутит внутри себя кучу фоновых процессов
  • Выделяем фоновые процессы в самостоятельные сущности, получаем микросервисы
  • Разбиваем большое сложное API на логически связанные разделы, уносим в самостоятельные сущности, и вуаля микросервисы

 

Что я вообще понимал под термином «микросервис»:

  • Технически это сайт или служба/демон, который имеет простой и понятный API
  • Инкапсулирует в себе некую атомарную часть «бизнес-логики» (кавычки потому, что адепты микросервисов чому-то редко употребляют ентот термин)

 

Какие я видел плюсы подобного подхода:

  • Настоящее разграничение и изолированность (грабли в сервисе А, не долетают до всех от него зависимых, технически невозможно доступиться до условного синглтона)
  • Простота архитектуры и реализации (чем проще задача, тем меньше надо инфраструктурных наворотов)
  • Масштабируемость по людям (раз уж мы все сегментировали даже технически, то можно нагонять ораву)
  • Разнообразность технологий (если потребителям видно только API, то похуй как оно врутри сделано)
  • Простота тестирования (меньше логики и внутренних инфраструктурных сложностей – проще писать тесты)

 

Что на практике:

  • Пересечение логических зон ответственности нескольких микросервисов (самое страшное, имхо, тому что не понять, куда впиливать фичу)
  • Сложный и плохо формализуемый граф зависимостей (если в условном монолите, написанном на популярном языке, можно легко посмотреть граф, кто от кого зависит и пробежаться по конкретным примерам использования, то в миросервисах енто все крайне затруднено)
  • Дисбаланас функционалисти (один сервисы делаю дохуя, другие реально «микро»)
  • Дисбаланс нагрузки (следствие предыдущих 2 пунктов, то есть от одного сервиса зависят 100500 других и, значит, его будут  нагружать)
  • Невероятная сложность тестирования (из-за того, что зависимости стали «физическими», тк реально разные приложения работают, то находить несостыковки можно только интеграционными тестами, а они сами по себе в 1000 раз более долгие чем юнит-тесты, а «моки» на таком уровне – енто сложнее чем вся фича)
  • Замедление разработки (если фича требует поддержки от 2 или более сервисов, то надо общаться с людьми, а потом синхронизировать процесс деплоя и тестирования)
  • К любой вообще логике добавляется A/B тестирование (как следствие предыдущего пункта, тому что при количестве сервисов более определенного порога,  просто невозможно поднимать согласованное окружение на одной машине, а тестироваться полными окружениями в облаке ради 2-3 сервисов невероятно дорого).
  • Усложнение формальных процессов, тому что даже автотесты через A/B предполагают хотя бы наличие веток в разных репозитариях с единым названием (или любой подобный механизм согласования)
  • Невероятно сложные релизы, тому что заказчик хочет в проде «вон те 2 фичи», которые невероятно сложно отодрать от общего потока разработки

 

Резюмируя. Сам по себе переход на микросервисную архитектуру не решает ни одну проблему вообще. Максимум, что он дает – это много боли, через которую, можно дойти до достаточно удобной инфраструктуры управления всем ентим зверинцем. Те же самые выстраданные A/B-тесты -- большой профит. Да и то, это реально только в условиях ГОМОГЕННОЙ инфраструктуры, когда для одних и тех же вещей, используется одна и та же технология и общие библиотеки для них. В противном случае, можно весело смотреть, как при появлении нового микросервиса пишется клиент для него на первом ЯП, потом втором и так далее. Это все идиотская трата времени. При гетерогенной инфраструктуре теряется экспертиза, потому что вот эти все разговоры типо «вот тут у на MySql, а вот тут возьмем PostgreSQL, у нас же микросервисы», ведут лишь к снижению уровня требований по работе с каждой конкретной технологией. Кроме того, очень сильно падает уровень вовлеченности. Люди знают, что отвечают за свои 3.5 сервиса и им поебать, чо там происходит в остальных. Я могу допустить, что есть некий уровень сложности, где подобных подход решает, без него никак. Но если подобная дичь творицца лишь потому, что в интернетах зафорсили как «последнее слово техники», то нахуй нахуй.

[dw]

Как профилировать память CLR?

У нашей системы загрузки данных есть особенности: наличие жесткого дедлайна и единомоментное массовое появление данных на ключевых источниках. То есть в теории мы пытаемся получать информацию в реальном времени, а на практике выходит, что бОльшую часть суточного объема мы получаем в конкретные часы ночью и должны полностью отпроцессить к началу рабочего дня. Двигать делайн нельзя, потому что источники начинают выкладывать данные ночью по Москве, а во Владивостоке люди уже сидят и работают. Из-за чего можно видеть пики загрузки подсистем: сначала на получении первички, потом на трансформации, потом на раскладывании данных в детальный слой, на построении витрин и, наконец, индексации на полнотекстах.

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

По логам это выглядит так: интервал между двумя записями job'а, в который, грубо говоря, происходит лишь одна операция "создание из одного гигантского хэшсета другого с добавлением туда новых элементов", составлял чуть ли не 30 минут. Плюс в этот же период идут алерты, что на сервере кончилась память, потому что процесс всё пожрал. То есть, как я понимаю, процесс начал свопить и все замедлилось в зигалион раз.

Можно сходу набросать несколько вариантов, как эффективней работать:

  • не создавать новый хашсет, а мутировать старый

  • не работать с архивами в памяти, а распаковывать их в tmp

  • уменьшить фрагментацию памяти, используюя пул стримов

  • и так далее.



Другой вопрос, что перебирать варианты опасно и долго. И тут я понял, что плохо представляю себе как профилировать память приложения, которое жрет по 16+Гб на удаленном сервере. Варианты, которые я испробовал:

  1. JetBrains dotMemory через RemoteAgent. Не сработало, потому что долго конектится к процессу, долго делает дамп, НЕВЕРОЯТНО долго качает этот дамп, еще дольше его процессит. В итоге ни один дамп таким образом у меня открыт не был.

  2. Делаешь дамп штатными средствами ОС, качаешь Far'ом, открываешь в WinDbg и через sos смотришь !dumpheap -stat. Работает, но опять же долго делать дамп и очень долго качать.

  3. Открываешь дамп в dotMemory. Эта возможность помечена как "beta", работает 100500 лет, плюс у меня дважды упала ОС из-за ентова. На третий раз всё открылось быстро, но информация была крайне странная. профайлинг ёба
    (В ЖЖ почему-то не отображается картинка, если что она есть)
    Первая попытка профилирования, когда у меня помер пека, остановила процесс, потому что с того момента он больше не делал ничего. А что за дамп загрузился после второго падения, я хз. Хотя фантазия успела разыграться, несмотря на полное несоотвествие даже абсолютных значений реальной картине.

  4. Вспомнил, что видел у Саши Голдштейна какую-то утилиту на этот счет. Она не работает. Совсем. По крайней мере, у меня.

  5. Вспомнил, что есть clrmd и написал маленькую тулу вот такого вида. Она работает около минуты, дает более-менее похожие на правду значения. Вот ей пока и пользуюсь, только модифицировал, чтобы можно еще режим задавать (не только NonInvasive, но и Passive выбрать) и поставил в планировщик писать енти "логи" каждые 15 минут. Завтра буду разбирать.



Как вообще нормально профилировать память в серверных .Net приложениях? Поделитесь опытом. А то вот это всё дикое время на создение дампа, на перекатывание его туда-сюда просто убивает. Это как смотреть на растущее дерево. Должны же быть какие-то нормальные способы.

[dw]

Про распил

Хотел в заголовок поставить слово "микросервисы", но все же не про них речь.

Дело такое. Есть у меня сервис, обеспечивающий первые 2 этапа ETL-процесса: загрузка сырых данных с источников и трансформаця их в каноничный внутренний формат. Этот формат потом жрет платная сложная тула, которая раскидывает из него данные по табличкам детального слоя, data vault и всё такое.

Сервис представляет из себя планировщик quartz, в который пихаются задачи на загрузку и трансформацию. При этом с одного источникам мы можем загружать разные документы, и, скорей всего, это будут разные процессы. В простейшем случае (всего один тип документа и один "реестр") имеем 2 джоба (загрузка и трансформация), в сложном - 2-3 десятка. Есть еще такой момент, что может существовать одна реализация YobaLoaderJob, которая в конфигах тиражируется на 12 задач с разными параметрами.

С точки зрения кода, если отбросить весь common и utility код, имеем ОДНУ библиотеку, где по папочкам разложены реализации всего этого зверинца. В целом, это было достаточно удобно:
- простая и понятная структура проектов (хост, реализация, тесты)
- элементарное добавление нового источника (запилил реализацию, накалякал тестов, занес задачи в конфиг планировщика нужного контура и погнали)
- удобный рефакторинг (с точки зрения унификации - все рядышком, посмотрел, подумал, обобщил; с точки зрения правок базовых классов - всё, что можно сломать, лежит в этом же проекте)
- легкий деплой (один раз настроил сценарий разворачивания хоста и всё)

К сожалению, минусы стали такими жирными, что теперь каждый новый источник делает меня грустить. А именно:
1. правка одного источника приводит к необходимости рестартовать все (аналогично, если надо отключить один конкретный процесс)
2. библиотека с реализациями обросла диким количеством зависимостей, а ее выхлоп весит много мегабайтов
3. когда хост запущен, он штатно жрет память в пределах 8-14 Гб, что сильно осложняет снятие и исследование дампов
4. когда какие-то процессы штатно не реагируют на сигнал завершения работы (сервис не тормозит ни за 2, ни за 5, ни за 15 минут) очень трудной найти причину (см. п3)
5. примитивные мониторинги (состояние сервиса, его потребление ресурсов) становятся абсолютно бесполезны, поскольку на фоне больших и ресурсоемких источников мелкие не видны
6. все задачи кроме своего штатного расписания имеют триггер "выполниться при запуске", что реально нагибает базу, из-за чего треть процессов получает отлуп и логи краснеют
7. долгий цикл CI/CD (для одного контура оно строится 3-4 минуты, примерно столько же идут тесты, еще 3-10 минут уходит на деплой). Итого, между запуском билда и наблюдаемой активностью проходит минут 10 минимум.

Логично, что всё это дело надо распилить, но у меня нет четкого понимания, как это сделать, чтобы не усложнять разработку. Как организовать структуру проектов и как правильно выбрать гранулярность. То есть, можно представить вот такую шкалу, на какое количество логики надо создавать отдельный сервис:
1. один для всех (текущий вариант)
2. один на источник
3. один на группу зависимостей (идея примерно такая: все джобы которые, к примеру, ходят на ftp, наследуют один класс ведут себя одинаково и им не нужен остальной хлам)
4. один на каждый джоб (другая крайность)
* п2 и п3 могут только чуть облегчить боль, но проблему они не решают


Понятно, что хотелось бы иметь п4 ОДИН ХОСТ НА КАЖДЫЙ ДЖОБ. Но как этого добиться?

По поводу сценариев сборки и развертывания я беспокоюсь мало, в худшем случае всегда можно на коленке собрать "сервер приложений", который будет мониторить папки, находить изменения, стопарить процесс и запускать с новыми сырцами. Это просто. Написать билд, который что-то соберет по определенным паттернам названий проектов еще проще.

Но я не понимаю, как это организовать в коде. Я уже выше писал, одна имплементация может иметь несколько инстансов в конфиге. И так выходит, что у меня 350+ джобов, и на каждый на выходе должен получиться типо отдельный запускаемый бинарник? Очень стремно. На каждую реализацию делать по одному проекту, прикладывать туда все необходимые конфиги, а сервер приложений из них запустит по отдельному хосту?


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

[dw]

Code review

Регулярно читаю в твитттуре, что мол парни, чей код просматривают, неадекватно реагируют на критику. Ну или не только парни, может и девушки, но этот нюанс не раскрыт. И все эти росказни сводятся к тому, что люди типо реально начинают переживать. Дальше идет пояснение, что не надо воспринимать критику своего кода на свой счет. Дескать, ты не тупой мудак, просто код твой - говно. А затем разворачивается не сильно большая, не особо маленька, а такая, прямо в меру, дискуссия, как же правильно ревьюить чужой код. Набегают профессионалы самых разных высот квалификации, высказывают авторитетные мнения, которые начинают интерферировать. Ну это же понятно, что анскилед лелкам в твитторг путь заказан, потому там только ревьюверы сидят, а не ревьювируемые. И какбэ все хорошие ревьюверы хороши одинаково, а вот ревьювируемые мудаки - мудаки по своему.

ревью - это просто праздник какой-тоCollapse )

[dw]

чат рисёч

ну ты же робот ёбана

А кто-то пытался на основе лога обычного чата построить некое подобие древовидного форума?

Я к тому, что у нас же тут развиваются лингвистические продукты, машинное обучение, в том смысле, что изначально древовидных форумов хватает, и есть за счет чего добивать эвристики.

Очевидные эвристики: обращения к конкретному нику, цитирования части сообщения, использования редко встречающихся слов (с точностью до N-го расстояния Левенштейна), скоростной постинг одним юзером нескольких сообщений подряд (скорей всего они должны составлять единое целое), разбивки по приветствиям, разбору содержимого линков (опять же в поиск редких слов) и тд и тп.

Понятно, что в первом приближении это не очень полезно и удобно, но должны же быть какие-то наработки. Ведь никто не вычитывает чаты дальше N-го сообщения с конца, НО увиденные обрывки обсуждений могут быть интригующими.

Интересен еще такой момент. Предположим, у нас есть такая система. А мы ее натравливаем на обычный пост в ЖЖ, где каждое предложение ОПа трактуем, как отдельно сообщение в чате. И тогда для нытико-технического поста вида "Вот мой опыт, что дураки-идиоты, так сяк робят плохо. А я туда-сюда с {technology_name} стою в белом пальто" чудо-технология сможет побить дискуссию на {technology_name} и сочувствующих "а у меня инитакоебыла" с прочими технофелософами.

Так где?

[dw]

Microsoft вышел из под контроля

Как писали в твитторе, в интересные времена живем:
- Microsoft без лишней скромности вкатился в Linux Foundation
- Заманил Google в .NET Foundation, который запиливает подержку дотнета для своего облака
- Показал Visual Studio для маководов. Студия уже приветствует неофитов
- Выложил для проб SQL Server, который v.Next, который можно пускать на линунксах
- Бомпанул Слек
- Сообщил, что Samsung отвлекся от производства взрывчатки, и опубликовал .NET SDK для Tizen
- Обратил внимание на проекты сообщества, такие как BenchmarkDotNet и NancyFX, приняв их в .NET Foundation
- Довел ASP.NET Core до такого состояния, что мы можем увидеть дотнет во всем известном некорректном бенчмарке


MS, правда, как я понял, прикончил WinPhone. Зато запустил совершенно непонятную мне ёбу. С другой стороны, пишут, что всё правильно MS делает




Сможешь ли ты совладать с ним?

[dw]

Рукописных парсеров пост



Хочу написать парсер поисковых запросов. Набор возможных операций мал: "и", "или", "не", группировка скобками (изменение приоритета), группировка кавычками1 (фразовый поиск), группировка кавычками2 (точное совпадение), пробел/табуляция/что-то еще - разделитель (он же implicit "и"), перевод строки - разделитель (он же implicit "или"), escape-символ (возможно, это будет '\').

Сложным мне представляется обработка ошибок. Пользователи будут вводить любую ерунду и удивляться любому поведению. Тут политика партии ещё не ясна: либо будем сыпать ошибки, либо достраивать до корректного запроса, либо и то и другое. Сыпать ошибки придётся, инфа под сотню, а значит они должны быть разумными и понятными. Это, как я понимаю, отсекает возможность применения парсер-комбинаторов и генераторов (TDOP, PEG, EBNF и прочих).

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

Что-то выглядит очень громоздко и скучно. Может, чего не знаю и есть короткий путь? Или, может, кто из вас видел красивые и компактные реализации чего-то подобного? В общем, я достаточно далек от разбора текста и надеюсь на любую помощь.


ЗЫ: зря я не читал дракона, да?

[dw]

REPL LEL




Достаточно занятная тема, которую я обычно избегаю, ибо синдром утёнка, начинал сразу с C в IDE (тогда в borland c++ 3.1). Но вот вчера внезапно выслушал монолог о том, как REPL ускоряет разработку. Знакомо, ведь я тоже радовался так когда-то. А потом всё встает на свои места.

Похоже, что радоваться REPL'у могут либо измученные тяжелой инфраструктурой программисты, которые устали создавать ConsoleApplication1488, чтобы проверить какую-нибудь ерунду, либо ребята, у которых вообще ничего нет.

Read more...Collapse )

[dw]