?

Log in

No account? Create an account
   Journal    Friends    Archive    Profile    Memories
 

Microsoft Outlook - morfizm


Mar. 13th, 2013 04:50 pm Microsoft Outlook

За сетевой запрос на UI-треде надо сажать на кол, как минимум, выгонять с работы.

Current Mood: angryangry

26 comments - Leave a commentPrevious Entry Share Next Entry

Comments:

From:morfizm
Date:March 16th, 2013 04:35 am (UTC)
(Link)
omfg...
From:ygam
Date:March 16th, 2013 05:31 am (UTC)
(Link)
А мою любимую историю про Амазон я тебе рассказывал? Про умный указатель, увольнения и эргодическую теорему?
From:morfizm
Date:March 17th, 2013 11:37 pm (UTC)
(Link)
Я, честно говоря, не помню. Ты мог рассказывать, но по этим словам не вспоминается. Напомни?
From:ygam
Date:March 17th, 2013 11:53 pm (UTC)
(Link)
From:morfizm
Date:March 18th, 2013 01:01 am (UTC)
(Link)
Да, теперь вспомнил, что читал.
Но всё равно чудесно!
From:archaicos
Date:March 14th, 2013 12:34 am (UTC)
(Link)
Не, то самое кресло с выдвигающимися шипами чтобы таки было we feel/share your pain :)
From:morfizm
Date:March 16th, 2013 04:35 am (UTC)
(Link)
:)
From:birdwatcher
Date:March 14th, 2013 12:50 am (UTC)
(Link)
Мне сейчас в количестве приходит спам со ссылками вида
http://spoilnews.us/178e20f33fd4f5c46885602/
где хост произвольный, а после него более двадцати шетстандцатеричных цифр.
Каждый подвешивал preview pane аутлука на несколько минут. К счастью, оказалось легко простым регекспом доставлять его в /dev/null.
From:morfizm
Date:March 16th, 2013 04:36 am (UTC)
(Link)
Регексп в VBA?
Я уже давно перешёл на VBA вместо rules, легче справляться со всякими странными e-mail'ами, и легче потом переносить это на другой комп.
From:birdwatcher
Date:March 16th, 2013 04:43 am (UTC)
(Link)
Нет, в procmail, конечно. У меня все сортируется на линуксовой машине, аутлук только забирает из готовых мейлбоксов.
From:_m_e_
Date:March 14th, 2013 07:02 am (UTC)
(Link)
Ха, помню замечательную строчку -
new Oid("SHA1")
Подвисает при подходящих условиях секунд на 30. Но за это надо много народу выгнать, наверное пару в виндоусе, полдюжины в .NET.
From:morfizm
Date:March 16th, 2013 04:38 am (UTC)
(Link)
Ничего себе!

P.S. Мне кажется "много народу надо выгнать" не является сильным аргументом в пользу воздержания от этой меры :)
From:_m_e_
Date:March 19th, 2013 07:44 am (UTC)
(Link)
Мне тоже так показалось, когда я полдня убил в поисках почему наша программа вместо долей секунды работала минуты три :). Оказалось, эта гадость (которая естественно была не в нашем коде, а где-то глубоко, где ее и не исправишь) при определенных условиях лезла в сеть, и при других определенных условиях занимала не миллисекунды, а полминуты.

Вобщем, пришлось человеку объяснить что винды в домене, но без домен контроллера - это беда.
From:ermouth
Date:March 14th, 2013 09:18 pm (UTC)
(Link)
Это технический критерий, очень узкий и не всегда верный (запрос может быть, например, на уточнение данных, с очень коротким таймаутом: не пришло уточнение – показываем что есть).

Тут попроще и пошире правило – для веб-интерфейсов современных неприемлемы глухие блокировки интерфейса больше секунды, для десктопов – больше полсекунды. Причём это единичными случаями, а не постоянным поведением. Отклик на активное действие в 200-300мс воспринимается как комфортный. Визуальный отклик на действие менее 100-150мс нежелателен, всякие странные эффекты восприятия могут начать проявляться.

Вообще, тормоза пользователи легче прощают, когда эти тормоза повешены на явные кнопки или пункты меню Открыть, Сохранить или Настройки 8)
From:morfizm
Date:March 16th, 2013 04:47 am (UTC)
(Link)
"Это технический критерий, очень узкий и не всегда верный" - так..., я уже начинаю подозревать, что ты таки пишешь сетевые запросы на UI-треде.

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

Проблема с работой на UI треде не в том, что пользователю влом подождать 1000мс. Может, и не влом. Проблема в том, что приложение не реагирует ни на какие другие UI контролы, и иногда даже не отрисовывается. Это ужасный experience. Хочешь задержку более 300мс - показывай диалог с ожиданием (с *работающей* кнопкой отмены), или делай в фоновом режиме, каким-то образом отображая статус (и/или меняя курсор), но позволяя пользователю работать дальше.

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

Насчёт явных кнопок или пунктов меню - согласен, прощают легче.
Особенно отвратительно выглядят тормоза на чём-то вроде скроллинга туда-сюда.
From:ermouth
Date:March 16th, 2013 06:59 am (UTC)
(Link)
http://ermouth.livejournal.com/454390.html?thread=4040182#t4040182 – я прекрасно знаю, что это за экспириенс, увы. Дальше просто соображения и наблюдения.

Запрещать что-то _в принципе_ как жесткое архитектурное решение – не очень-то хорошая практика вообще. Сначала принятие, а потом propagation такого решения занимают некоторое время (в мсфт я думаю запросто это может в год-два вылиться) – за это время что-то меняется, а решение остаётся, не важно, насколько оно адекватно. Это же _жёсткое решение_, ога.

Когда такого рода "решения" генерятся регулярно, они начинают друг на друга причудливо накладываться. Плюс обычно в системах, приемлющих абсолютные инженерные запреты, есть и абсолютные инженерные "разрешения" (правила, к исполнению обязательные) – они формируют ещё более извилистую картинку итоговых constraints.

Всё это вместе, вся эта дурацкая практика, формирует годами разрабатываемые дорогущие неудобные продукты. Офис 2013 – это просто апофеоз выполнения дурацких правил при проектировании ui как минимум. Просто потому, что вместо нормального проектирования ui дизайнер занимается упихиванием задумок в тыщи глупейших ограничений – и получается какашечка. В офисе 2013 например прямо с порога меню капителями. Это вот придумал просто идиот – и распространил как всеобщее правило.

Непосредственно по теме. Ещё раз: очень редкий ui stall в пределах секунды – это приемлемо. Если для того, чтобы выкатить релиз веб-приложения быстро, мне надо будет сделать синхронный уточняющий сетевой запрос в главном потоке (в типичной html-страничке весь яваскрипт выполняется в одном потоке), я это сделаю не задумываясь, даже если это будет выглядеть как ui stall в секунду длительностью. Просто список необходимых доработок будет удлинён на пункт.

На вебе кста достаточно давно, уже лет 5, синхронные аяксовые запросы не практикуются практически. ui stall в веб-приложениях обычно бывает не из-за сетевых запросов, а из-за злоупотребления манипуляциями DOM либо при обработке больших объемов данных синхронным способом.
From:morfizm
Date:March 16th, 2013 07:41 am (UTC)
(Link)
Дим, по второму и третьему абзацу ты заблуждаешься - по-моему, ты пытаешься применить идеи, работающие в маленьких проектах, к большим.

Жёсткие архитектурные решения используются повсеместно. Для начала, без coding guidelines не проживёт ни один большой проект, потому что синтаксис любого языка программирования плюс доступные библиотеки позволяют писать немеренные нечитаемые извраты. Отсутствие дисциплины в минимизации контрактов (API сервисов, интерфейсов классов) вызывает abstraction leaks, и трудносопровождаемые зависимости. Плохая архитектура (разбиение на независимые компоненты и дизайн их взаимодействия) затрудняет тестирование, затрудняет возможность continuous deployment, создаёт почву для багов, и повышает стоимость любой дальнейшей работы над софтом.

Опытный инженер может интуитивно понимать все эти вещи и всё делать правильно. Два опытных инженера могут друг с другом много разговаривать, читать код друг друга, обмениваться опытом, и суммарно генерить нечто хорошее, не хуже, чем они бы отдельно написали. Один опытный техлид и команда из пяти человек - тоже отлично. Техлид может тренировать новеньких, делать code review каждому, сделить чтобы не было говна и тренировать, как правильно, он же может писать ключевые библиотеки, делать структуру компонент, и придумывать идеологически правильные решения. Команда из 20 человек на 7 лет - это уже совсем другая динамика. Один человек, как правило, не может следить за всем говном, которое пишут 20. Кроме того, за 7 лет с уровнем attrition 15% останется лишь 32% от изначального состава. Остальные 1-2 раза поменяются и будут разбираться с кодом, который уже написан. Будет менеджер или инвестор, который будет торопить выкатывать фичи, и новенький, вместо того, чтобы потратить месяц, чтобы по уму во всём разобраться, потратит два дня и сделает наиболее очевидное для него решение, исходя из того, что он успел изучить. А он много не изучит за два дня. Он и за месяц и близко не разберётся в том, что команда написала за 4 последних года. Нужна *система*, *автоматически* склоняющая тебя писать правильнее. И эта система всегда есть в любом более-менее большом проекте. Иначе оно не работает. Outlook это даже не 20 человек на 7 лет, а это сотни людей, и проекту лет 20. Кроме того, он тесно интегрирован с общими офисными компонентами, которые писали другие несколько сотен человек. И с shell'ом, и с разными технологиями и сервисами. Без жёстких архитектурных решений тут ну совсем никак.

Например, в большом проекте взаимодействие между сервисами выносят в отдельные библиотеки. Т.е. ты не пишешь на питоне urllib2.Request, чтобы сделать HTTP запрос, а пишешь какой-нибудь MyFancyBackend.request, из библиотеки FancyBackendClient, а в нём уже детали реализации - вызов через сетевую библиотеку. Любой инженер, когда видит чей-то код в code review, понимает, что кроме случая если речь идёт о самой библиотеке XYZClient, прямого использования библиотеки urllib2 быть вообще не должно. Это уже, в свою очередь, позволяет тебе отследить dependencies. Например, если твоя UI компонента не использует FancyBackendClient напрямую, а только по цепочке зависимостей через FancyCache, то ты видишь, что UI не будет делать блокирующих запросов, при условии, что кэш правильно имплементирован и будет подсасывать по сети в фоновом режиме. Это и есть пример жёсткого архитектурного решения. Кто-то должен сказать: "UI должен использовать FancyBackend только через Cache", и прописать именно такой порядок зависимостей компонент.


Очень редкий UI stall в пределах секунды это debatable. Я не думаю, что ты можешь гарантировать секунду. Может быть, не всегда, а ещё реже, но будет подвисать на минуту и это, возможно, будет потерянный customer. Разные косяки в UI так или иначе будут, этого не избежать. Надо избегать хотя бы тех, про которые ты знаешь и которые можешь контролировать. В том примере, про который ты думаешь, неужели там так сложно сделать уточняющий запрос фоном?
From:ermouth
Date:March 16th, 2013 08:14 am (UTC)
(Link)
Дима, то, что я написал никак вообще не противоречит тому, что пишешь ты.

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

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

Дела закончу сёдня – разверну постом в бложеке.
From:morfizm
Date:March 16th, 2013 10:57 pm (UTC)
(Link)
Я тебе ответил в посте. Мне кажется, то, что ты предлагаешь (с таймаутом) это тоже жёсткое архитектурное решение. Я про это написал.
From:ermouth
Date:March 16th, 2013 10:06 am (UTC)
(Link)
И ещё добавлю про "не можешь гарантировать секунду" – это для поста out of scope, так что здесь отвечу.

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

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

Пример, который я думаю, вполне себе практический, только там общий тайминг не секунда, а полсекунды. Таймаут синхронного запроса там – 250 мс. Если я в это время не укладываюсь (а пребывая за пределами корпоративной сети, особенно если я на мобильном, я довольно часто не укладываюсь), я рисую что есть и потом повторяю этот запрос асинхронно. И по приходу данных _всё_ перерисовываю, спросив пользователя (типа всплывайки как в гуглопочте при получении нового сообщения в тред, когда читаешь этот тред).

Конкретно этот случай – отображение расширенных данных юзера и документа с учётом этих данных. Эта операция – очень редкая и работнику за пределами офиса практически никогда не нужная. Реализация попытки показать документ сразу со всеми данными только асинхронными запросами была бы менее responsive и более тяжеловесной в плане кода.

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

Я когда всё это проектировал, у меня был большой соблазн не оставить нам возможности делать синхронные запросы вообще – у меня там как раз "MyFancyBackend.request" всё обслуживает. Я этот соблазн поборол – и уже несколько раз локтем перекрестился, что не повёлся на "рекомендации" не делать синхронных запросов никогда.

Never say never )
From:morfizm
Date:March 16th, 2013 10:59 pm (UTC)
(Link)
Реализация попытки показать документ сразу со всеми данными только асинхронными запросами была бы менее responsive

Почему была бы менее responsive?
В чём конкретно тут bottle neck? (Какой-то overhead, который браузеры добавляют в случае обработки call-back'ов?)
From:ermouth
Date:March 16th, 2013 11:25 pm (UTC)
(Link)
Если брать общее накрытие – преимущест нет. Конкретно в этом случае получается вот что.

Синхронный вариант. Я в те 300-500 мс, которые пользователь уже внутренне "зарезервировал" под ожидание ответа ui, произвожу полезную работу и чаще всего сразу радую юзера результатами. Он и не замечает ничего, для него 300 мс нормально, 500 – чуток тормозня.

Асинхронный вариант. Я сразу рисую что есть и жду ответа сервера, а потом обновляю по user intervention. Это явно хреновей, потому что:
а) выигрыш в скорости здесь мнимый – для юзера 50мс и 300мс для операций, приводящих к полному обновлению большей части области просмотра, малоразличимы
б) предоставление информации в результате таки неполное и в любом случае потребует вмешательства.

Теоретически, мы можем отложить перерисовку на 250 мс с начала асинхронного запроса и в начале отрисовки проверить readystate promise'а. И если всё уже пришло, рисовать полностью. Практически это изящное решение всё равно приводит к новой абстракции в диспетчере представлений, а где его ещё применить я не придумал.
From:morfizm
Date:March 17th, 2013 11:35 pm (UTC)
(Link)
Я не очень понимаю use case, т.е. как оно выглядит всё в результате, но, наверное, нет смысла в тут комментах это дебаггать, раз с двух раз до меня не дошло, шанс мал, что дойдёт с третьего :)

Если у нас есть какой-то список, кликая на элементы которого справа подгружается нечто, то если оно будет подгружаться синхронно, то даже 300-500 мс это слишком большая задержка. Что если я кликнул случайно не на тот элемент, и сейчас захочу кликнуть на другой?

Если же речь идёт о жирной кнопке "загрузить детали", после которой появляется какой-то фидбек ожидания (надпись "пожалуйста, подождите", или просто очистка какой-то области, в которой что-то появится), то подвешивать UI на 500 мс вполне адекватно, т.к. по сути это почти что переход на другую страницу, которая должна загрузиться, ну детали имплементации состоят в том, что это физически та же страница, а не другая. Мне кажется, тут у пользователя ожидания выстраиваются такие же как для загрузок страниц - типа, до 1000 мс нормально, 2000-3000 мс приемлемая тормозня, 3-10s очень неприятная тормозня, свыше 10s - всё подвисло намертво, плохой сайт.

Если же взаимодействие с UI - это простые вещи, не подразумевающие "переход на другую страницу" или "запуск тяжёлого таска" - вроде выбор из списка, клик на checkbox/radiobox, и т.п., то тут, наоборот, 300 мс это долго, и я бы не стал ничего подгружать, прежде, чем освободить UI thread, дав возможность продолжить взаимодействие с UI.
From:morfizm
Date:March 21st, 2013 04:44 am (UTC)
(Link)
Мне только что пришли эти комменты по почте, Gmail почему-то решил целую пачку комментов отправить в спам.

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

Вопрос про подвисание UI состоит не в "time to glass" для показа нового, а в том, может ли пользователь продолжить взаимодействовать с тем UI, который уже есть.
From:ermouth
Date:March 16th, 2013 04:15 pm (UTC)
(Link)