Русский
Русский
English
Статистика
Реклама

Ошибки

Как убрать назойливое предупреждение о сертификате для RDP

02.07.2020 12:23:15 | Автор: admin

Привет Хабр, это супер короткое и простое руководство для новичков о том, как подключаться по RDP по доменному имени, чтобы не вылезало назойливое предупреждение о сертификате, подписанным самим сервером. Нам понадобится WinAcme и домен.

Все, кто хоть раз пользовался RDP, видели эту надпись.


В руководстве приведены готовые команды для пущего удобства. Скопировал, вставил и заработало.

Так вот, это окно можно в принципе пропустить, если выдать сертификат подписанный сторонним, трастовым центром сертификации. В данном случае, Lets Encrypt.

1. Добавляем А запись




Просто добавляем A запись и вписываем в неё IP адрес сервера. На этом работа с доменом окончена.

2. Качаем WinAcme


Качаем WinAcme с их сайта. Архив лучше всего распаковать туда, куда вы не доберетесь, исполняемые файлы и скрипты вам еще пригодятся в будущем для автоматического обновления сертификата. Лучше всего вытряхнуть архив в C:\WinAcme\.

3. Открываем 80 порт




Авторизация вашего сервера осуществляется по http, поэтому нам нужно открыть 80 порт. Для этого введите в Powershell команду:

New-NetFirewallRule -DisplayName 80-TCP-IN -Direction Inbound -Protocol TCP -Enabled True -LocalPort 80

4. Разрешаем выполнение скриптов


Чтобы WinAcme смог без проблем импортировать новый сертификат, нужно разрешить выполнение скриптов. Для этого переходив в папку /Scripts/



Перед запуском WinAcme нам нужно разрешить выполнение двух скриптов. Для этого двойным кликом запустите PSRDSCerts.bat из папки со скриптами.

5. Устанавливаем сертификат




Дальше скопируйте строку ниже и введите имя домена, по которому хотите подключатсяь к серверу и выполните команду.

C:\Winacme\wacs.exe --target manual --host VASHDOMAIN.RU --certificatestore My --installation script --installationsiteid 1 --script "Scripts\ImportRDListener.ps1" --scriptparameters "{CertThumbprint}"

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

Готово! Вы великолепны и избавились от надоедливой ошибки.

А какие системные ошибки раздражают вас?

Подробнее..

Бег по граблям 10 уязвимостей компьютерного криминалиста

13.04.2021 12:15:42 | Автор: admin

Не кажется ли вам странным, что на фоне глобальной цифровизации, развития аппаратных и программных решений, пик популярности форензики как науки уже прошел, а интерес к ней угасает с каждым днем? Старейшие производители и поставщики решений для криминалистических исследований такие, как Guidance Software (Encase Forensics) и AccessData (Forensic Toolkit), "золотой эталон" для экспертов, детективов, следователей, судей и адвокатов, поглощены третьими компаниями. Ряд ведущих специалистов и авторов бестселлеров в области форензики по тем или иным причинам покинули эту область.... а оставшиеся специалисты частенько наступают на одни и те же грабли. Вот об этих "граблях", проблемах и "болевых точках" криминалистов решил порассуждать Игорь Михайлов, ведущий специалист Лаборатории компьютерной криминалистики Group-IB.

1. Ставить на быструю форензику

В мире компьютерных криминалистов довольно долго считались нерушимыми требования о неизменности цифровых доказательств эти принципы были описаны еще в 2000 году в документе "ACPO Good Practice Guide for Digital Evidence".

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

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

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

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

Наиболее распространенный прием защиты информации, используемый при изъятии мобильного устройства перевести его в режим полета или выключить. Однако в некоторых случаях это не защищает информацию на устройстве от изменения, а иногда и от уничтожения. Кроме того, ряд производителей, например, Apple, экспериментируют с взаимодействием выключенного устройства с другими устройствами подсистемы Apple по протоколу Bluetooth. В перспективе это может позволить владельцу устройства взаимодействовать даже с выключенным аппаратом.

Наши рекомендации:

Соблюдать процедуры криминалистически правильного изъятия носителей информации, использовать клетки Фарадея.

2. Слепо доверять результатам работы программ-комбайнов

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

В совокупности с большим потоком цифровых носителей, поступающих к криминалистам, это привело к такому явлению, как Кнопочная форензика (Push Button Forensics). Исследователь обрабатывает поступающие к нему носители информации этой программой и передает сгенерированные ею отчеты заказчику, не анализируя результаты и не проверяя их на достоверность и полноту. Увы, подобная работа быстро приводит к деградации специалистов в профессиональном плане. У них пропадает понимание того, почему получен именно такой результат, а не иной.

Наши рекомендации:

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

3.Неэффективно использовать программные и аппаратные средства

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

К сожалению, политика добралась и до форензики. Часть криминалистических технологий и оборудования и раньше не поставлялась западными разработчиками в Россию. В этом году наибольший резонанс вызвало то, что израильская компания Cellebrite отказалась поставлять оборудование для криминалистического исследования мобильных устройств. Компания объяснила свое решение тем, что это оборудование якобы использовалось для попыток (попыток!) взлома устройств, изъятых у оппозиционера Любови Соболь. Между тем доподлинно известно, что взломать эти устройства с помощью оборудования Cellebrite невозможно у него просто нет такого функционала.

Наши рекомендации:

Постарайтесь научиться работать с минимальным набором инструментов, но использовать его максимально эффективно.

4. Не перепроверять получаемые результаты и не относиться к ним критически

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

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

Наши рекомендации:

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

5. Плохо подготовиться к изъятию накопителей информации

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

Поэтому перед изъятием носителей информации надо определить, на каких носителях может находиться нужная информация, как они защищены, где находятся физически, какие пароли и иные средства защиты использует человек, у которого они находятся, и т.п.

Наши рекомендации:

Необходимо тщательно готовиться к мероприятиям по изъятию носителей информации и продумывать действия, которые смогут нейтрализовать контрмеры владельца информации.

6. Использовать распознавание текста в графических файлах и видеофайлах

В настоящее время нет ни одного форензик-продукта, который бы хорошо распознавал тексты в графических файлах и видеофайлах. Поэтому криминалист всегда стоит перед выбором: использовать интегрированный функционал по распознаванию текстов в форензик-продуктах и допускать, что часть текстов останется нераспознанной или распознанной некорректно, или применять сторонние средства (например, ABBYY). Как правило, это приводит к тому, что часть текстовых данных, находящихся на исследуемых носителях в виде графических файлов и видеофайлов, упускается из анализа при поиске по ключевым словам.

7. Следовать популярным тенденциям вопреки здравому смыслу

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

8. Пытаться делать все одним специалистом

Напомню, что есть следующие виды компьютерно-технической экспертизы:

  • аппаратно-компьютерная;

  • программно-компьютерная;

  • информационно-компьютерная;

  • компьютерно-сетевая.

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

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

Наши рекомендации:

Как сказано выше, необходимо специализироваться в какой-то определенной области компьютерной криминалистики. Оцените, что вам больше всего подходит и развивайтесь в этом направлении.

9. Работать без профильного образования и с низким уровнем подготовки

В России специальность компьютерного криминалиста можно получить только в двух вузах. Первый Московский государственный технический университет имени Н.Э. Баумана. Там на кафедре юриспруденции готовят специалистов по судебной компьютерно-технической экспертизе. Второй вуз это ведомственное учреждение, Воронежский институт МВД. Он проводит обучение по специальности Компьютерная безопасность со специализацией Информационно-аналитическая и техническая экспертиза компьютерных систем. Кроме того, на базе этого вуза проходят повышение квалификации сотрудники экспертно-криминалистических подразделений МВД, занимающиеся компьютерными экспертизами.

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

Еще одна проблема отсутствие в вузах преподавателей, которые бы, c одной стороны, занимались практической деятельностью, связанной с форензикой, а с другой стороны обучением. Это необходимо, чтобы преподаватель понимал, чему и как учить студентов, актуализировал учебные материалы под существующие тренды в форензике.

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

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

Наши рекомендации:

Пройдите учебные курсы на базе образовательных учреждений. Повысить квалификацию можно на курсах, проводимых HackerU, Академией информационных систем, учебными центрами Информзащита и Специалист, Group-IB и Kaspersky.

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

10. Остановиться в своем развитии, пеняя на необъективный рынок труда

Есть довольно затертая, но меткая цитата Льюиса Кэрролла, которая годится и для нашей темы: в форензике, чтобы оставаться компетентным, надо бежать изо всех сил. А чтобы развиваться в ней, надо бежать еще быстрее. Таковы наши реалии.

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

На рынке труда складывается уникальная ситуация. Работодатели предъявляют высокие требования к компетенциям криминалистов, но обычно не готовы адекватно оценивать их работу. Например, от специалиста в области форензики, требуется знание основ обратной разработки (реверса). При этом специалисту в области реверса готовы платить на 20-35% больше, чем специалисту в области форензики (причем требования к реверс-инженеру в целом значительно ниже). Еще печальнее ситуация выглядит, если сравнить уровень зарплат криминалиста и программиста и требования к ним. Криминалисту приходится тратить гораздо больше усилий, чтобы получать столько же или меньше, чем специалисты из смежных областей. Подобные условия приводят к оттоку специалистов из форензики в другие области, связанные с информационными технологиями, программированием и информационной безопасностью.

Наши рекомендации:

Покажите работодателю, насколько важна ваша работа и насколько вы ценный специалист.


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

Подробнее..

Чему равно выражение -33u3 на С? Не угадаете. Ответ -4. Приглашаю на небольшое расследование

04.05.2021 18:23:50 | Автор: admin

Вот пример для проверки:

#include <iostream>int main(){    std::cout << "-3/3u*3 = " << int(-3/3u*3) << "\n";}

Посмотреть результат можно тут.

Или попробуйте поиграться с этим примером здесь или здесь.

Вообще-то мне не удалось найти хоть какой-то компилятор С++, который бы выдавал результат отличный от -4. Даже старый GCC-4.1.2, clang-3.0.0 или Borland C 1992 года. Так же заметил, что результат одинаковый и для константы, вычисляемой в момент компиляции и для времени выполнения.

Предлагаю внимательно рассмотреть результат выражения -3/3u*3.

Если убрать приведение к типу intв примере выше, то получим 4294967292 или 0xFFFFFFFС(-4). Получается, что компилятор на самом деле считает результат беззнаковым и равным 4294967292. До этого момента я был свято уверен, что если в выражении используется знаковый тип, то и результат будет знаковым. Логично же это.

Если посмотреть откуда берется -4 вместо -3, посмотрим внимательней на ассемблерный код примера, например здесь.

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

int main(){    volatile unsigned B = 3;    int A = -3/B*3;}

Для x86-64 clang 12.0.0 видим, что используется беззнаковое деление, хотя числитель откровенно отрицательное -3:

        mov     dword ptr [rbp - 4], 3    // B = 3        mov     ecx, dword ptr [rbp - 4]        mov     eax, 4294967293        xor     edx, edx        div     ecx                       // беззнаковое деление !!        imul    eax, eax, 3               // знаковое умножение        mov     dword ptr [rbp - 8], eax

Для x64 msvc v19.28 тот же подход к делению:

        mov     DWORD PTR B$[rsp], 3      // B = 3        mov     eax, DWORD PTR B$[rsp]        mov     DWORD PTR tv64[rsp], eax        xor     edx, edx        mov     eax, -3                             ; fffffffdH        mov     ecx, DWORD PTR tv64[rsp]        div     ecx        imul    eax, eax, 3        mov     DWORD PTR A$[rsp], eax

Получается, что для деления беззнакового числа на знаковое используется БЕЗЗНАКОВАЯ операция деления процессора div. Кстати, следующая команда процессора, это правильное знаковое умножение imul. Ну явный баг компилятора. Банальная логика же подсказывает, что знаковый тип выиграет в приведении типа результата выражения если оба знаковый и беззнаковый типы используются в выражении. И для знакового деления требуется знаковая команда деления процессора idiv, чтоб получить правильный результат со знаком.

Проблема еще и в том, что число 4294967293 не делится на 3 без остатка:4294967293 = 1431655764 * 3 + 1и при умножении 1431655764 обратно на 3, получаем 4294967292 или -4. Так что прикинуться веником и считать, что 4294967293 это то же -3, только вид сбоку, для операции деления не прокатит.

Двоично-дополнительное придставление отрицательных чисел.

Благодаря представлению чисел в двоично-дополнительном виде, операции сложения или вычитания над знаковыми и без-знаковыми числами выполняются одной и той же командой процессора (add для сложения и sub для вычитания). Процессор складывает (или вычитает) только знаковое со знаковым или только без-знаковое с без-знаковым. И для обоих этих операций используется одна команда add (или sub) и побитово результат будет одинаковый (если бы кто-то решил сделать раздельные операции сложения для знаковых и без-знаковых типов). Различие только во флагах процессора. Так что считать знаковое без-знаковым и складывать их оба как без-знаковых корректно и результат будет побитово правильным в обоих случаях. Но для деления и умножения этот подход в корне неправильный. Процессор внутри использует только без-знаковые числа для деления и умножения и результат приводит обратно в знаковое с правильным признаком знака. И для этого процессор использует разные команды для знакового (idiv) и без-знакового деления (div) и так же и для умножения (imul и соответственно mul).

Я когда обнаружил, что используется без-знаковое деление, решил, что это бага компилятора. Протестировал много компиляторов: msvc, gcc, clang. Все показали такой же результат, даже древние трудяги. Но мне довольно быстро подсказали, что это поведение описано и закреплено в самом стандарте.

Действительно, стандарт говорит об этом прямо:

Otherwise, if the unsigned operand's conversion rank is greater or equal to the conversion rank of" "the signed operand, the signed operand is converted to the unsigned operand's type.

Иначе, если ранг преобразования без-знакового операнда больше или равен рангу преобразования знакового операнда, то знаковый операнд приводится к типу без-знакового операнда.

Вот где оказывается собака зарыта: "the signed operand is converted to the unsigned operand's type"!! Ну почему, почему, Карл!! Логичнее наоборот: "the unsigned operand is converted to the signed operand's type", разумеется при соблюдении ранга преобразования. Ну вот как -3 представить без-знаковым числом?? Наоборот кстати можно.

Интересная получается сегрегация по знаковому признаку!

Заметил, что это правило почему-то работает только для операции деления, а операция умножения вычисляется правильно.

Проверим на ассемблере здесь этот пример:

int main(){    volatile unsigned B = 3;    int C = -3*B;}
Вот ассемблерный код:

mov dword ptr [rbp - 4], 3 mov eax, dword ptr [rbp - 4] imul eax, eax, 4294967293 mov dword ptr [rbp - 8], eax

Стандарт ничего не говорит о неприменимости этого правила для операции умножения. И деление и умножение должны быть БЕЗЗНАКОВМИ.

Я подумал, что что-то в стандарте сломалось и надо срочно это исправить. Написал письмо напрямую в поддержку Стандарта со всеми моими выкладками и предложением поправить это странное правило стандарта пока еще не поздно.

Ага! Наивный!

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

Хоть это исследование и было больше года назад, я до сих пор под впечатлением от многих вещей в этой истории:

  • Как я не натыкался на это раньше? Не один десяток лет интенсивно кодирую на С и С++ с погружением в ассемблер, но только сейчас споткнулся на неё. Хотя может и натыкался ранее, но не мог поверить что причина именно в этом.

  • Ассемблер я выучил раньше С и поэтому всегда считал С удобной заменой Ассемблера. Но правила работы процессоров неизменны и даже языки высокого уровня им следуют.

Интересно, что это правило всё же не работает и для операций с указателями. С ними нет такого поведения. Видать понимают разработчики компиляторов, что иначе рухнет очень многое. Посмотрите этот пример здесь:

int main(){    const unsigned a[] = {3,4,5,6,7};    unsigned p = (&a[0] - &a[3])/3u*3;    // -3    unsigned b = -3/3u*3;   // -4}

Хоть я и понимаю, что могу ошибаться в логике работы этого мира, но задумайтесь, в следующий раз садясь в современный, нашпигованный вычислительной логикой самолёт (или автомобиль), а не сработает ли вдруг не оттестированный кусок кода в какой-то редкой нештатной ситуации, и не выдаст ли он -4 вместо элементарных -3, и не постигнет ли его участь подобная Boeing 737 MAX?

Учитывая, что сейчас кода на С++ производится гораздо больше, чем его успевают покрывать тестами, надежда, что будет отловлена такая базовая операция, тает ниже плинтуса.

Ошибка в команде просессора FDIV у Интела

Помните, в начале 2000-х была выявлена ошибка с вычислением в команде FDIV у Интела. Там было различие в 5 знаке после запятой в какой-то операции деления. Какой был шум тогда!!
Но исправили оперативно и быстро. В компиляторы добавили условный флаг для обхода этой команды. Интел срочно исправил логику в кристалле и выпустил новые чипы.

И это всего лишь 5-й знак после запятой! Многие его даже и не заметили, подумаешь, мелочь какая! А тут -4 вместо -3 и считаем знаковое без-знаковым и вместо -3 имеем еще и 4294967292! И тишина в ответ! И в этой тишине тихо падают Боинги.

Предвижу возражение, что есть рекомендация использовать преимущественно без-знаковый тип. Понимаю, с таким правилом Стандарта по другому никак. Но как -4 в беззнаковое перевести, и чтоб всё остальное работало? И почему на других языках и всех процессорах не надо этими танцами с бубном заниматься, а в С++ надо? И что делать с константными выражениями, вычисляемыми компилятором? Вместо элегантных выражений, в которых мы уверены, надо записывать их с оглядкой, чтоб у компилятора небыло изжоги!

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

Как хорошую подсказку познавательно добавить предупреждение в компилятор когда он применяет это правило из Стандарта:"Signed value is intentionally converted to unsigned value. Sorry for crashing one more airplane. Have a nice flight!" Вот удивимся тогда, как мало мы тестируем и как много нам открытий чудных приносит компилятор друг.

Можно еще исправить Стандарт, ограничив правило только операциями сложения и вычитания. Как компромис. Но это крайне маловероятно в этой Вселенной. Да и Боингов еще много летает.

Представьте студента (С) на экзамене у преподавателя по информатике (П) в ВУЗе.

- П: Хорошо, последний вопрос на 5. Можно ли привести знаковое число к беззнаковому типу?
- С: Хе, можно. НУЖНО! Обязательно НУЖНО! Ставте 5, я пойду.
- П: Как НУЖНО?? О_О. Подумайте. Как можно представить, например, -4 беззнаковым числом? - С: Чего тут думать! Стандарт С++ сказал, что НУЖНО, значит НУЖНО и точка. А то что -4 станет беззнаковым очень большим числом - это уже ни печалька Стандарта, ни моя. - П: Подумайте еще раз. Вы на экзамене по информатике и вас спрашивают о базовых вещах, которые общие для всех языков программирования и процессоров, а не только для С++. - С: Чего вы пристали к мне со своими языками и процессорами. У меня в билете вопрос про С++, вот я про С++ и отвечаю. А вы про какой то там Ассемблер, базовые вещи, языки программирования! Стандарт С++ сказал, компилятор сделал, я ответил! У вас есть вопросы к Стандарту про базовые вещи, вот ему их и задавайте, а я ответил правильно! - П: Да уж. Подстава конкретная.

Подробнее..

Trace, Info, Warning, Error, Fatal кто все эти люди..?

01.03.2021 16:18:41 | Автор: admin

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

Info: все ожидаемые события, учет которых запланирован.
Warning: неожиданные/подозрительные события - иначе говоря аномалии, после которых еще возможно продолжение работы приложения.
Error: событие, после которого невозможно дальнейшее выполнение программы.
Fatal: событие, требующее по-настоящему немедленного вмешательства.

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

"Продолжить работу"

Трактовать возможно продолжить работу можно очень по разному. Скажем, на экране пользователя можно настроить любимый цвет рамки вокруг экрана: пусть будет розовый. Если по каким-то причинам хранилище, где мы держим эти настройки цвета было недоступно и мы не можем отобразить этот цвет - можно ли это считать как возможно продолжить или это катастрофа? К сожалению, я еще ни разу не встречал хорошего универсального формального критерия, чтобы четко можно было разделять "катастрофа-терпимо". А раз не можешь остановить - значит нужно направить. Потому я предлагаю инвертировать споры об это неправильный уровень: если в коде написано, что отсутствие цвета - это Error - значит программист Вам говорит, что этот цвет чертовски важен в этом домене - возможно, именно этот цвет сигнализирует, что сейчас надо продавать акции на миллионы долларов, и наоборот. Соответственно, чтение кода немного меняется: когда видите место, где из-за какой-то на Ваш взгляд ерунды прерывается выполнение, вопрос, который должен возникать автору, Почему ты считаешь, что это так важно? вместо Истинно тебе говорю - ты программируешь неправильно!.

Схожая инверсия может помочь в вечных спорах на тему это исключительная ситуация или нет. Опять же, все довольно просто. Важна не техническая составляющая: нет соединения к базе - это исключение, а серверу прислали неправильный id - так это ожидаемо. Важно то,чья это будет головная больи как ее можно избежать или хотя бы минимизировать урон. Чьи планы на вечер пятницы пойдут к черту из-за того, что это сломалось? Если Вашим сервисом пользуются приложения, которые вне Вашего контроля, то Вам действительно плевать на то, что они присылают некорректные id и у них там что-то идет не так. Если Ваше приложение - это инструмент для управления базой данный - наподобие Sql Server Magement Studio - очевидно, что отсутствие доступа к базе - не Ваша печаль. А если Вашим сервисом пользуются приложения, за которые Вы же и в ответе - то это Ваши неприятности в конечном счете. Вопрос лишь в том, как и когда Вы об этом узнаете - быстро из сработавшей сигнализации или от звонка злого как черт владельца бизнеса, которому Вы пишете софт. А также вопрос в том, как дешево, надежно и сердито эту сигнализацию наладить.

"Error"

Давайте представим себе экран, где есть кнопка Открыть и текстовое поле. Эта кнопка по замыслу должна открыть Вам какой-то полезный функционал, а в текстовом поле предполагается ввести имя и фамилию. После нажатия на кнопку принципиально возможны два сценария: приложение либо крэшится либо нет. Если же мы были удачливы и оно не упало, у нас опять два варианта: мы получили желанный экран или мы получили сообщение об ошибке вместо него. Сообщение об ошибке в свою очередь можно принципиально разделить еще на два класса: может ли пользователь сам исправить ситуацию в рамках программы или нет - имеется ввиду корректирование своего ввода, а не обратиться к Вашему системному администратору.

Жаль, что нет комикса о том, как программист ловит льва в пустыне - он здесь был бы очень уместенЖаль, что нет комикса о том, как программист ловит льва в пустыне - он здесь был бы очень уместен

На практике сообщение вида Обратитесь к администратору это просто подслащенные крэш. Да, несомненно это лучше, чем убить весь процесс со всеми пользовательскими данными, но от этого оно не перестает фактически блокировать работу. В тоже время ошибка может быть сообщением о неправильных с точки зрения программы действиях, а именно надо было ввести имя и фамилию Джон Иванов, а человек ввел просто Джон и валидатору это не нравится. К чему это все? Что вообще у нас тут речь идет о 3-х достаточно разных сущностях, но при том на каждую из них можно сослаться как Error, что вызывает изрядную путаницу. Крэш приложения - это несомненно уровень Error в нашей системе определений, но это очень важный Error.

Ошибка валидации имя-фамилии - это несомненно уровень Info - мы ждем, что пользователь будет норовить записать все что угодно, а мы - пресекать это. Ну и записывать все те разы, когда пользователь был неправ. Но от этого ошибки не перестают бесить людей, которые их видят. То, что напрямую связано с людьми и их UX - важно; и неплохо бы присматривать за этим, не допускать, чтобы сообщения об этом тонули в километрах унылых Info записей Пользователь такой-то залогинился. Иными словами, чтобы устранить путаницу, хочется иметь уровни Error+ и Info+.

Я предвижу восклицания Так погодите, ведь крэш приложения - это недопустимо! Надо сразу действовать! Это Fatal уровень!" На это я неспеша прикурю воображаемую сигарету, затянусь и задумчиво отвечу: Ну всех ведь все равно не спасти...". Ладно, я не курю, но, думаю, образ понятен. Появление сообщения Fatal должно быть эквивалентом запуска тревоги воздушной угрозы, когда в офисе разработки врубается сирена и это жуткое красное аварийное освещение. Вот честно, Вы именно так реагируете на то, что у кого-то из бухгалтерии на экране, который раз в сто лет запускают, упало приложение? Вполне может быть нормально, что у Вас сейчас даже и нет подобной ситуации, где уровень Fatal - согласно такой системы определений - нужен. Так вот трюк в том, чтобы не блокировать возможность добавить обработку такой потенциальной ситуации в будущем, забивая сейчас Fatal уровень сообщениями, которым важностьError+ в самый раз.

Таким образом, мы приходим к тому, что в действительности неплохо бы иметь уровни вида

Info
Info+
Warning
Error
Error+
Fatal

Плюсовые уровни можно легко организовать в Вашей любимой библиотеке логгирования расширив ее существующие методы Error/Info, которые бы просто унифицировано добавляли какой-то хэштэг в обычные сообщения, скажем #IMPORTANT.

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

Подробнее..

5 распространенных ошибок разработчиков, влияющих на время загрузки страницы

29.12.2020 12:11:44 | Автор: admin

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

Почему время загрузки страницы важно?

Время загрузки страницы напрямую связано с производительностью сайта.

Если загрузка занимает более 3 секунд, вы потеряете половину посетителей еще до того, как они попадут на ваш сайт.

  • Видимость - Google учитывает время загрузки страницы при ранжировании в результатах поиска. Следовательно, время загрузки сайта влияет на то, насколько легко пользователи смогут найти его в Интернете.

  • Конверсия - чем быстрее загружается страница, тем больше пользователи взаимодействуют с сайтом. Медленные сайты убивают конверсии. Потенциальные клиенты будут неохотно пользоваться сайтом и следовать призывам к действию (CTA), если ваша веб-страница будет долго загружаться. Это приведет к разочарованным пользователям, они будут уходить с сайта, не покупая ваш продукт или не используя ваши услуги.

  • Удобство использования - чем меньше время загрузки, тем больше будет удовлетворен пользователь. В результате, удержание клиентов будет выше.

Давайте рассмотрим несколько примеров, основанных на исследовании, проведенном HubSpot.

  • Если Yahoo сократит время загрузки страницы на 0,4 секунды, трафик может увеличиться на 9%.

  • Замедление загрузки страницы на 1 секунду может стоить Amazon 1,6 миллиарда долларов продаж в год.

  • 2-секундная задержка поиска Bing приведет к потере дохода на 4,3% на посетителя, уменьшению числа кликов на 3,75% и сокращению количества запросов на 1,8%.

Согласно приведенным выше фактам, можно увидеть, насколько важно время загрузки страницы.

Факторы, влияющие на время загрузки страницы, а также советы и рекомендации по оптимизации

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

1. Большое количество HTTP-запросов

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

Браузер обычно ограничивает количество одновременных запросов от 4 до 8. Следовательно, нельзя делать много запросов параллельно.

Исследования, проведенные Yahoo, показывают, что 80% времени загрузки приложения зависит от HTTP-запросов.

Можно сделать следующее, чтобы уменьшить количество HTTP-запросов:

  • Объединение файлов CSS / JS - файлы CSS, а также файлы JS можно объединить в один файл, а не получать несколько файлов с сервера. Поскольку все файлы CSS блокируют рендеринг, уменьшение количества файлов CSS значительно сократит время загрузки страницы.

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

  • Включить кэширование браузера - можно разрешить кэширование статических изображений или содержимого сайта, которое не будет часто меняться. Когда пользователь посещает сайт во второй раз, кэш может загрузить это содержимое без необходимости отправлять новый HTTP-запрос на сервер. Это ускоряет загрузку контента.

  • Поддержка HTTP/2 на сервере. При использовании HTTP/2 из браузер выполняет только одно соединение с сервером для загрузки сайта, и одновременно разрешается несколько запросов. Это намного эффективнее, чем создавать новое соединения для каждого ресурса.

2. Отсутствие CDN

Если у веб-сайта нет CDN, время загрузки увеличивается, когда пользователь находится далеко от сервера. Эти задержки заметны, поскольку они влияют на все HTTP-запросы к серверу.

Использование CDN сокращает время загрузки страницы.

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

Например, если ваш исходный сервер находится в Калифорнии, ваша CDN может выглядеть следующим образом.

Однако также важно правильно настроить CDN для кэширования контента с правильными значениями TTL для эффективного использования.

Но что происходит с самым первым запросом или когда срок действия кэша CDN истечет?

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

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

Совет: делитесь повторно используемыми компонентами между проектами с помощью Bit (Github).

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

Bit поддерживает Node, TypeScript, React, Vue, Angular и др.

3. Большие размеры файлов и размер страницы

Получение большого файла или страницы с веб-сервера занимает много времени. Выборка нескольких таких больших файлов увеличивает размер страницы и увеличивает время загрузки страницы.

Уменьшение размеров файлов за счет сжатия может сократить время загрузки страницы.

Сжатие файлов - лучший способ уменьшить размер файлов и ускорить загрузку. Для этого обычно используется Gzip. Он находит похожий код в ваших файлах и временно заменяет их. Большинство веб-серверов поддерживают сжатие Gzip.

Доступна другая схема сжатия, сжатие Brotli, которую вы также можете использовать в зависимости от типов файлов.

Сжатие файлов HTML или CSS обычно экономит около 50% или 70% размера файла, что приводит к меньшему времени загрузки страницы и меньшей пропускной способности.

Вы можете еще больше сократить время загрузки страницы, уменьшив размер изображений, используемых в приложении.

4. Загрузка всех ресурсов одновременно

Одновременная загрузка всех файлов HTML, CSS и JS увеличивает время загрузки страницы, так как отрисовка будет заблокирована до тех пор, пока не будут загружены все эти ресурсы.

Загрузка файлов JS после других элементов улучшает время загрузки страницы.

Отложенная загрузка JavaScript - это механизм загрузки больших файлов JS после других элементов. Этот метод гарантирует, что остальная часть вашего контента загружается без каких-либо блокировок большими JS-файлами.

Пусть у вас есть HTML, вам нужно сделать вызов внешнего JS-файла (defer.js) перед тегом </body>.

<script type="text/javascript"> function downloadJSAtOnload() {   var element = document.createElement("script");   element.src = "defer.js";   document.body.appendChild(element); } if (window.addEventListener)   window.addEventListener("load", downloadJSAtOnload, false); else if (window.attachEvent)   window.attachEvent("onload", downloadJSAtOnload); else window.onload = downloadJSAtOnload;</script>

Смысл приведенного выше кода: Подождите, пока загрузится весь документ, затем загрузите файл defer.js.

5. Большое количество переадресаций

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

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

Что касается переадресации, существует два типа:

  • на стороне сервера - быстрые и кэшируемые

  • на стороне клиента - медленные и не кэшируемые

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

Заключение

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

Для оценки производительности своего веб-сайта можно использовать множество инструментов, таких как Google Pagespeed Insights, Pingdom, YSlow и т.д. Они дадут некоторое представление о том, в каком месте сайт тормозит.

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

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

Подробнее..

Большие ошибки в больших данных проблемы анализа на практике

28.07.2020 16:18:22 | Автор: admin


При работе с big data ошибок не избежать. Вам нужно докопаться до сути данных, расставить приоритеты, оптимизировать, визуализировать данные, извлечь правильные идеи. По результатам опросов, 85 % компаний стремятся к управлению данными, но только 37% сообщают об успехах в этой области. На практике изучать негативный опыт сложно, поскольку о провалах никто не любит говорить. Аналитики с удовольствием расскажут об успехах, но как только речь зайдет об ошибках, будьте готовы услышать про накопление шума, ложную корреляцию и случайную эндогенность, и без всякой конкретики. Действительно ли проблемы с big data существуют по большей части лишь на уровне теории?

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

Ошибки выборки



В статье Big data: A big mistake? вспомнили об интересной истории со стартапом Street Bump. Компания предложила жителям Бостона следить за состоянием дорожного покрытия с помощью мобильного приложения. Софт фиксировал положение смартфона и аномальные отклонения от нормы: ямы, кочки, выбоины и т.д. Полученные данные в режиме реального времени отправлялись нужному адресату в муниципальные службы.

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

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

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

По словам авторов исследования Обзор методов обработки селективности в источниках больших данных, существует множество источников big data, не предназначенных для точного статистического анализа опросы в интернете, просмотры страниц в Твиттере и Википедии, Google Trends, анализ частотности хештегов и др.

Одной из самых ярких ошибок такого рода является прогнозирование победы Хилари Клинтон на президентских выборах в США в 2016 году. По данным опроса Reuters/Ipsos, опубликованным за несколько часов до начала голосования, вероятность победы Клинтон составляла 90%. Исследователи предполагают, что методологически сам опрос мог быть проведен безупречно, а вот база, состоящая из 15 тыс. человек в 50 штатах, повела себя иррационально вероятно, многие просто не признавались, что хотят проголосовать за Трампа.

Ошибки корреляций


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


На диаграмме выше показано общее количество наблюдений НЛО с 1963 года. Число зарегистрированных случаев из базы данных Национального центра отчетности по НЛО в течение многих лет оставалось примерно на одном уровне, однако в 1993 году произошел резкий скачок.

Таким образом, можно сделать совершенно логичный вывод, что 27 лет назад пришельцы всерьез взялись за изучение землян. Реальная же причина заключалась в том, что в сентябре 1993 года вышел первый эпизод Секретных материалов (на пике его посмотрели более 25 млн человек в США).


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

Эти веселые корреляции имеют далеко идущие последствия. Так, например, исследование Доступ к печати в сообществах с низким уровнем дохода показало, что школьники, имеющие доступ к большему количеству книг, получают лучшие оценки. Руководствуясь данными научной работы, власти Филадельфии (США) занялись реорганизацией системы образования.

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

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

Потеря данных



(с)

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

Авторы Фрикономики, профессор экономики Чикагского университета Стивен Левитт и журналист Стивен Дабнер, через несколько лет признались, что в итоговое исследование абортов попали не все собранные цифры, поскольку данные просто исчезли. Левитт объяснил методологический просчет тем, что в тот момент они очень устали, и сослался на статистическую незначимость этих данных для общего вывода исследования.

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

Ошибки анализа



(с)

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

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

Например, как указывает генетик Стивен Липкин, для генома есть возможность делать высококлассные анализы, но информация о контроле качества часто закрыта для врачей и пациентов. Иногда до заказа теста вы не можете заранее узнать, насколько велика глубина покрытия при секвенировании. Когда ген прочитывают недостаточное число раз для адекватного покрытия, программное обеспечение находит мутацию там, где ее нет. Зачастую мы не знаем, какой именно алгоритм используется для классификации аллелей генов на полезные и вредные.

Тревогу вызывает большое количество научных работ в области генетики, в которых содержатся ошибки. Команда австралийских исследователей проанализировала около 3,6 тыс. генетических работ, опубликованных в ряде ведущих научных журналов. В результате обнаружилось, что примерно одна из пяти работ включала в свои списки генов ошибки.

Поражает источник этих ошибок: вместо использования специальных языков для статистической обработки данных ученые сводили все данные в Excel-таблице. Excel автоматически преобразовывал названия генов в календарные даты или случайные числа. А вручную перепроверить тысячи и тысячи строк просто невозможно.

В научной литературе гены часто обозначаются символами: например, ген Септин-2 сокращают до SEPT2, а Membrane Associated Ring Finger (C3HC4) 1 до MARCH1. Excel, опираясь на настройки по умолчанию, заменял эти строки датами. Исследователи отметили, что не стали первооткрывателями проблемы на нее указывали более десятилетия назад.

В другом случае Excel нанес крупный удар по экономической науке. Знаменитые экономисты Гарвардского университета Кармен Рейнхарт и Кеннет Рогофф в исследовательской работе проанализировали 3,7 тыс. различных случаев увеличения госдолга и его влияние на рост экономики 42 стран в течение 200 лет.

Работа Рост за время долга однозначно указывала, что при уровне госдолга ниже 90 % ВВП он практически не влияет на рост экономики. Если же госдолг превышает 90 % ВВП, медианные темпы роста падают на 1 %.

Исследование оказало огромное влияние на то, как мир боролся с последним экономическим кризисом. Работа широко цитировалась для оправдания сокращения бюджета в США и Европе.

Однако несколько лет спустя Томас Херндорн, Майкл Эш и Роберт Поллин из Университета Массачусетса, разобрав по пунктам работу Рогоффа и Рейнхарта, выявили банальные неточности при работе с Excel. Статистика, на самом деле, не показывает никакой зависимости между темпами роста ВВП и госдолгом.

Заключение: исправление ошибок как источник ошибок



(с)

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

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

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

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



Правильно анализировать большие данные мы можем научить в Академии MADE бесплатном образовательном проекте от Mail.ru Group. Заявки на обучение принимаем до 1 августа включительно.
Подробнее..

Где и как обычно ошибаются стоматологи (частично применимо и к другим врачам)

24.12.2020 14:22:40 | Автор: admin
image
В корневом канале кто-то оставил мне кусок инструмента.

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

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

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

В результате диагностики рождается план лечения. Пациент в случае дорогих вмешательств врачу не доверяет, поэтому идёт в другую клинику. Через день образуется ситуация три врача и шесть планов лечения, что ещё больше путает.

Почему бывает недодиагностика?


Потому что в коммерческой медицине в России нет протоколов. Точнее, они как бы иногда есть, но по факту их всё равно нет. В случае критичных заболеваний в ОМС есть схема показаний, которые однозначно ведут к определённым анализам и исследованиям. Если пациент отметил что-то в анамнезе, это занесли в карточку, а исследование на такой случай не назначили, то врач в конечном итоге может даже отправиться за решётку после суда (случается редко, чаще речь идёт про серьёзные штрафы клинике от страховых фондов).

То есть на каждый критичный случай, угрожающий жизни или здоровью, есть схема. Это важно для государства, ведь стоимость жизни гражданина, по сути, может считаться как недопроизведённый ВВП, то есть как недоделанная за время этой ожидаемой жизни работа. Качество жизни обычно рассматривается не как ОМС, а как ДМС или коммерция. В случае работы с качеством жизни такой схемы нет. Стоматология крайне редко бывает про угрозу жизни: пожалуй, это редкие онкологии и разные интересные инфекции с зубов в мозг. Во всех остальных случаях можно выбросить зуб в тазик и выдать обезболивающее. 15 минут, 220 рублей вот примерно сколько это стоит для ОМС-клиники.

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

Ну, пациент, что будем лечить?

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

С одной стороны, делать полную диагностику выгодно: это увеличивает чек, потому что можно уговорить пациента заодно вылечить кариес на ранней стадии, про который он не знал. С другой стороны, сами пациенты этого не любят, потому что считают, что это способ развести их на дополнительные деньги. И не всегда они неправы. Ещё одна особенность это когда маркетолог клиники даёт задачу нагрузить КТ-аппарат, потому что он медленно окупается. В этот момент количество дополнительных исследований на нём начинает расти.

В моей клинике есть только протоколы и case selection. То есть любой пациент всегда проходит одну и ту же диагностику. Если определяется патология тут же выбирается следующий кейс с дополнительными методами под неё. Никакого творчества, никакой отсебятины, в двух одинаковых случаях будут абсолютно одинаковые наборы исследований. Эта диагностика несколько избыточна в сравнении с ОМС-стандартами, но мы работаем в дорогом сегменте: наша задача не героически решать проблемы, а снимать их до появления. Пациенты это очень хорошо понимают (в нашем случае такая репутация появилась примерно через два года от начала работы).

Самый простой пример недодиагностики не сделать интерпроксимальные снимки, то есть не увидеть кариес.

Не доказал важность лечения


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

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

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

Если врач был неубедителен, то пациент откладывает лечение или идёт советоваться к следующему. Если вдруг так совпадёт, что там будет недодиагностика, то вполне возможна ситуация: Какие корни? У вас два кариеса, их глазами видно. Вас там разводят, давайте сейчас посверлю, и всё будет готово через полчаса! К сожалению, не могу отрицать, что где-то действительно разводят.

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

В России по пациенту решение часто принимает врач, который более убедительно рассказал. А рассказывает он иногда на голубом глазу. В итоге многие отличные медицинские специалисты, не способные говорить с пациентом, часто страдают в коммерческом плане.

Неверный выбор кейса


Доказательная медицина, основанная на математике и научном подходе, предполагает следующее:

  1. Пациент достаточно полно продиагностирован для принятия решения.
  2. Диагностика выполняется до тех пор, пока не будет определён конкретный случай (диагноз) с уточнениями.
  3. Для этого случая есть выбор из нескольких вариантов лечения: нужно оценить каждый в соответствии с особенностями пациента и характером случая, возможностями врача и клиники.
  4. После выбора варианта нужно реализовать его максимально качественно.

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

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

Только очень редко на переднем крае пациенты приходят с Доктор, что это у меня?, а врач говорит:

Ой! Что это у вас?

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

Если врач лечит зубы в Африке, то, наверное, case selection сводился к вырвать так или вырвать с частичным обезболиванием спиртным.

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

Ещё я часто вижу переоценку тяжести состояния. Здесь вопрос денег: агрессивный маркетинг производителей имплантов часто двигает обучение в сторону зуб к чёрту, ставим имплант, это всё решает. Опять же для своей клиники я выбрал парадигму максимального сохранения тканей при лечении, то есть мы спасаем зубы даже при очень сложных ситуациях. Парадокс в том, что в нашем исполнении это часто дороже, чем вырвать зуб и поставить имплант в региональной клинике. Обычно же в клинике это немного дороже, но менее маржинально, чем имплантация.

И совсем интересный случай это когда план лечения выбирает один врач на границе специальностей. Если в клинике терапевт сильнее хирурга, то будет много сохранений зубов. Если хирург сильнее терапевта будет много имплантаций. Консилиумов в стоматологии нет, поэтому просто помните, что первый врач определит, что с вами будет. И хирурги склонны что-нибудь отрезать.

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

Кривые руки


Следующая ошибка простая и понятная: хирург ошибся.

Тут ситуация двоякая. С одной стороны, в России традиционно сильная хирургия. С другой, Россия страна доморощенной стоматологии. Учат у нас по учебникам 60-х годов прошлого столетия. Как врач закончил университет, так и сидит, а лечит по тем же методам, как научили. Если нужно пройти что-то новое либо пробует сам, либо платит за дорогие курсы повышения квалификации. Второе случается в регионах реже, а в ОМС вообще почти никогда не случается. В итоге объективно быстро можно учиться либо на бомжах (я серьёзно: речь идёт про благотворительное лечение тяжелейших запущенных случаев с информированием о его характере), либо на ничего не подозревающих платных пациентах.

Поскольку часто сильная хирургия 60-х сочетается с отсутствием денег, мы видим совершенно дикие вещи, которые пациенты приносят в челюсти. Скрепка вместо титанового штифта пожалуйста. Штифт дорогой, а скрепка почти такая же, правда? Или вот клинышек он вообще-то для другого, но наши врачи способы взять любое устройство и использовать его не по назначению. Главное, чтобы у него были похожие физико-химические свойства. Это вызывает и восторг за изобретательность, и разочарование, потому что иногда это даёт побочки, а лечить нам.

Часто врачи ломают инструмент в корневом канале. Вы об этом крайне редко узнаёте. Часто обломок хоронят прямо под пломбировочным материалом. Дальше всё зависит от того, что это за инструмент: был инфицирован или нет, обошли его дальше в ходе вмешательства или нет. Самая частая моя находка сломанный каналонаполнитель. Это такая пружинка, её загоняют до верхушки корня, потом врубают мотор, что делать в такой ситуации нельзя. Она ломается. Оставлять её в канале не полностью безопасно, но часто это бывает безопаснее, чем доставать.

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

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

И это только один пример протокола. Часто у нас встречаются вещи вроде обработайте препаратом 1, его раздуйте и экпонируйте 10 секунд, затем препаратом 2 в таком-то количестве, но не раздувайте и оставьте сверху на 20 секунд, затем третий и раздуйте, потом поместите конструкцию в раствор, просушите и приклейте. Пропуск пункта или неверное его выполнение ведёт к тому, что это что-то отклеивается.

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

Поскольку врачи не пользуются ни математикой, ни статистикой, большинство случаев ошибок переваливается на технологии. А дело-то простое: если ты знаешь, что метод при правильном применении даёт 98 % успеха, 3 % побочных эффектов и 0,2 % необратимых побочных эффектов, а у тебя в клинике было 18 пациентов с этим за год и успех достигнут только у 12, а ещё двое с серьёзными побочными эффектами, то, возможно, дело не в методе. Возможно, дело в том, что это исполнитель поражён редким генетическим заболеванием simlicitum. Импланты не прижились это оно. Приживается даже ржавый гвоздь при соблюдении протокола.

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

Частично к случаю кривых рук можно отнести отсутствие нужного оснащения. Про микроскопы и их обязательное использование в клинике я писал в прошлый раз. За это нас до сих пор не любят, потому что микроскоп требует переобучения и выявляет мельчайшие ошибки. Плюс видеофиксация снижает самооценку на разборах. Но он даёт огромные преимущества, в том числе численные по успеху лечения воспалений. Кстати, по ряду клиник я знаю, что наличие микроскопа и внутриротового сканера не гарантирует, что врач будет работать с ними: далеко не факт, что ему не будет привычнее, как в 80-х.

В России для меня регулярно становится сюрпризом, что в клинике нет автоклава. Стерилизация инструмента это просто базовая вещь. Более того, она нужна для прохождения лицензирования. То есть они принесли автоклав, показали проверяющим и унесли его обратно в какую-то другую клинику. Совет простой: если вам выпало лечить зубы в небольшой клинике, то прямо спрашивайте, как стерилизован инструмент. Для этого на пакетах есть метки. Работает это так: грязные инструменты после предстерилизационной очистки (дезинфекции) кладутся в пакеты для автоклава, потом они греются в нём, и метка на пакете при пике температуры меняет цвет. Вам нужно убедиться, что инструмент достали при вас из пакета с зелёной меткой с проступившей буквой S. Бывают и другие вариации меток, но эта самая частая. Хорошие ассистенты это делают с сочным звуком вскрытия пакета прямо перед лицом пациента.

Вот так выглядит метка до стерилизации, она рыже-коричневая:

image

А вот так после стерилизации, зелёная, видно букву S:

image

image

Но тут надо сказать, что автоклавирование нужно от обычных инфекций, речь не обязательно идёт про гепатит или ВИЧ. Их возбудитель нестойкий, и на самом деле вполне возможна ситуация, что он просто развалится между вмешательством одним и тем же инструментом в двух разных пациентах. Я не призываю работать грязным инструментом и сейчас объясню, почему такие клиники не закрывают сразу после первого же заболевшего: потому что при несоблюдении протокола дезинфекции заболевшего может не быть долго. Это не столовая, где сразу десяток случаев отравления в один день. Гемотрансфузий в обычной стоматологии нет.

И ещё. Если вам два года не снимают брекеты это была ошибка ортодонта, и сейчас вам пытаются её исправить. У меня был пациент, который к моменту первого приёма носил брекеты шесть с половиной лет: на нём, кажется, ошибались трижды. Помогли, конечно, ещё за полтора года, но это были сложные полтора года. Итого восемь лет брекетов.

Злонамеренное увеличение счёта


Первый случай простой: в маленький город приезжает звезда-хирург из Москвы, и ему нужно набить 108 пациентов. 105 есть, ещё троих не помешало бы, и вот кто-то, кому можно было сохранить зуб, едет на имплантацию.

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

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

Если в клинике есть бесплатная консультация для пенсионеров часто дальше будет что-то агрессивное, часто вводящее в заблуждение. Стоит скидка 40 % на услуги и конструкции? Это обман ну или врач только учится. Единственный нормальный случай, который я видел, это когда прямо пишут, что врач новый, его нужно загружать, и потому по четвергам бесплатные консультации.

Есть методы с недоказанной эффективностью или недостаточно исследованные. Есть методы с ограниченным применением, которые можно расширять с кратным увеличением риска побочных эффектов. Это часто видно на имплантах: Сейчас всё дёрнем импланты поставлю, всё за неделю. Метод называется all-on-4, all-on-6. Он очень хорош для ряда достаточно узких ситуаций, но сейчас его испортят горе-врачи, которые используют его везде. Потому что дёшево и быстро, пациентов очень легко убеждать. Не надо бояться врача, всё и сразу, зубы белые, красивые. А коварство в том, что работу могут закончить временной конструкцией из пластика: она нужна как способ жевать, пока готовится постоянная конструкция. Первый год она выглядит очень красиво, но биосовместимость у неё не очень. Дальше начинается износ, в щелях поселяются бактерии, и начинается запах. А потом всё это ещё и начинает разваливаться. Несколько десятков лет назад ещё были нейлоновые протезы, тоже такая же история. Но я их уже давно не видел.

Почему так? Врачи хотят вас обмануть? Всё плохо?


Я знаю, что в этом месте принято ругать страну и медицинскую систему.

Нет. Медсистема в целом в порядке. Работать можно. Проблемы есть, но другие медицинские системы при всех плюсах (как в США с протоколами) могут иметь другие фатальные недостатки (как в США с полисами).

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

В 90-х на уши врачам присели дельцы. Это поменяло способы продажи и вызвало передиагностику и перелечение. Мы знали одну компанию, которая делала отличную медицинскую систему. В какой-то момент их купил крупный холдинг, выгнал врачей и запустил маркетологов. Они расширили показания по применению и начали агрессивно продавать. Результат система себя дискредитировала. Не система нужна пациенту, а врач, который примет объективное решение.

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

Наука двигается только энтузиастами, нет фреймворка совместных исследований и испытаний, как в Европе. Это, пожалуй, самая важная стратегическая часть, но мои врачи ведут исследования за пределами РФ, публикуются и преподают тоже чаще не в России. Это то, что потенциально будет тормозить медицину сильнее всего: если врачу не платят за новые технологии и исследования, то он идёт зарабатывать сам или работать не в стране. А платить сейчас может только коммерческая медицина и только передового края.

Спасибо за внимание! Теперь вы знаете чуть больше про то, как вас лечат стоматологи. И примерно можете переложить это на другие области медицины.
Подробнее..

Как анализатор PVS-Studio стал находить ещё больше ошибок в проектах на Unity

29.06.2020 12:20:00 | Автор: admin
image1.png

Разрабатывая статический анализатор PVS-Studio, мы стараемся развивать его в различных направлениях. Так, наша команда работает над плагинами для IDE (Visual Studio, Rider), улучшением интеграции с CI и т. д. Увеличение эффективности анализа проектов под Unity также является одной из наших приоритетных целей. Мы считаем, что статический анализ позволит программистам, использующим этот игровой движок, повысить качество своего исходного кода и упростить работу над любыми проектами. Поэтому хотелось бы увеличить популярность PVS-Studio среди компаний, занимающихся разработкой под Unity. Одним из первых шагов в реализации данной задумки стало написание нами аннотаций для методов, определённых в движке. Это позволяет контролировать корректность кода, связанного с вызовами аннотируемых методов.

Введение


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

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

Конечно же, нами уже написано множество аннотаций для анализатора. Например, проаннотированы методы классов из пространства имён System. Кроме того, существует и механизм автоматического аннотирования некоторых методов. Подробнее об этом можно узнать здесь. Отмечу, что указанная статья больше рассказывает про часть PVS-Studio, отвечающую за анализ проектов на C++. Тем не менее, ощутимой разницы в принципе работы аннотаций для C# и C++ нет.

Написание аннотаций для методов Unity


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

Изначальная идея состояла в том, чтобы покрыть аннотациями вообще все методы Unity, однако, их оказалось очень много. Вследствие этого, мы решили для начала проаннотировать методы из наиболее часто используемых классов.

Сбор информации


Сначала необходимо было выяснить, какие же именно классы используются чаще других. Кроме того, важным аспектом является обеспечение возможности сбора результатов аннотирования новых ошибок, которые анализатор найдёт в реальных проектах благодаря написанным аннотациям. Поэтому первым шагом был поиск соответствующих open-source проектов. Однако сделать это оказалось не так уж просто.

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

Конечно, иногда везло. Например, жемчужиной в этой коллекции является MixedRealityToolkit. Кода в нём уже прилично, а значит, и собранная статистика использования Unity-методов в таком проекте будет более полной.

Таким образом, было набрано 20 проектов, использующих возможности движка. Для того, чтобы найти наиболее часто используемые классы, была написана основанная на Roslyn утилита, производящая подсчёт вызовов методов из Unity. Такую программу, кстати, тоже вполне можно назвать статическим анализатором. Ведь если задуматься, она действительно анализирует исходники, не прибегая к запуску самого проекта.

Написанный "анализатор" позволил найти классы, средняя частота использования которых в найденных проектах наиболее высока:

  • UnityEngine.Vector3
  • UnityEngine.Mathf
  • UnityEngine.Debug
  • UnityEngine.GameObject
  • UnityEngine.Material
  • UnityEditor.EditorGUILayout
  • UnityEngine.Component
  • UnityEngine.Object
  • UnityEngine.GUILayout
  • UnityEngine.Quaternion
  • И т.д.

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

Аннотирование


После получения необходимой информации пришло время заняться собственно аннотированием. Верными помощниками в этом деле были документация и редактор Unity, где был создан тестовый проект. Это было необходимо для проверки некоторых моментов, не уточнённых в документации. К примеру, далеко не всегда было ясно, приведёт ли передача null в каком-либо аргументе к ошибке, или же выполнение программы продолжится без проблем. Конечно, передача null, как правило, это не совсем хорошо, но в этом случае мы считали ошибками лишь то, что прерывало поток выполнения, либо же логировалось редактором Unity как ошибка.

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

MeshRenderer renderer = cube.GetComponent<MeshRenderer>();Material m = renderer.material;List<int> outNames = null;m.GetTexturePropertyNameIDs(outNames);

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

MeshRenderer renderer = cube.GetComponent<MeshRenderer>();Material m = renderer.material;string keyWord = null;bool isEnabled = m.IsKeywordEnabled(keyWord);

Указанные проблемы актуальны для редактора Unity 2019.3.10f1.

Сбор результатов


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

Процедура тестирования аннотаций выполняется в автоматическом режиме с помощью специально написанной под эти нужды программы CSharpAnalyserTester. Он производит запуск анализа на проектах, после чего сравнивает получаемые логи с эталонными и формирует файлы, содержащие информацию о различиях.

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

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

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

Например, был найден несколько странный вызов GetComponent:

void OnEnable(){  GameObject uiManager = GameObject.Find("UIRoot");  if (uiManager)  {    uiManager.GetComponent<UIManager>();  }}

Предупреждение анализатора: V3010 The return value of function 'GetComponent' is required to be utilized. ADDITIONAL IN CURRENT UIEditorWindow.cs 22

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

А вот ещё один пример дополнительных срабатываний анализатора:

public void ChangeLocalID(int newID){  if (this.LocalPlayer == null)                          // <=  {    this.DebugReturn(      DebugLevel.WARNING,       string.Format(        ....,         this.LocalPlayer,         this.CurrentRoom.Players == null,                // <=        newID        )    );  }  if (this.CurrentRoom == null)                          // <=  {    this.LocalPlayer.ChangeLocalID(newID);               // <=    this.LocalPlayer.RoomReference = null;  }  else  {    // remove old actorId from actor list    this.CurrentRoom.RemovePlayer(this.LocalPlayer);    // change to new actor/player ID    this.LocalPlayer.ChangeLocalID(newID);    // update the room's list with the new reference    this.CurrentRoom.StorePlayer(this.LocalPlayer);  }}

Предупреждения анализатора:

  • V3095 The 'this.CurrentRoom' object was used before it was verified against null. Check lines: 1709, 1712. ADDITIONAL IN CURRENT LoadBalancingClient.cs 1709
  • V3125 The 'this.LocalPlayer' object was used after it was verified against null. Check lines: 1715, 1707. ADDITIONAL IN CURRENT LoadBalancingClient.cs 1715

Отметим, что PVS-Studio не обращает внимания на передачу LocalPlayer в string.Format, так как это не приведёт к ошибке. Да и выглядит код так, будто написано это намеренно.

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

Дело в том, что в методе DebugReturn производится несколько вызовов, которые в теории могли бы повлиять на значение свойства CurrentRoom:

public virtual void DebugReturn(DebugLevel level, string message){  #if !SUPPORTED_UNITY  Debug.WriteLine(message);  #else  if (level == DebugLevel.ERROR)  {    Debug.LogError(message);  }  else if (level == DebugLevel.WARNING)  {    Debug.LogWarning(message);  }  else if (level == DebugLevel.INFO)  {    Debug.Log(message);  }  else if (level == DebugLevel.ALL)  {    Debug.Log(message);  }  #endif}

Анализатору неизвестны особенности работы вызываемых методов, а значит, и неизвестно, как они будут влиять на ситуацию. Так, PVS-Studio предполагает, что значение this.CurrentRoom могло измениться во время работы метода DebugReturn, поэтому далее и производится проверка.

Аннотации же дали информацию о том, что методы, вызываемые внутри DebugReturn, не повлияют на значения других переменных. Следовательно, использование переменной перед её проверкой на равенство null можно считать подозрительным.

Заключение


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

Анализатор постоянно развивается и дорабатывается. Добавление аннотаций для методов Unity лишь один из примеров расширения его возможностей. Таким образом, со временем эффективность работы PVS-Studio растёт. Поэтому, если вы ещё не пробовали PVS-Studio, самое время исправить это, загрузив его с соответствующей страницы. Там же можно получить триальный ключ для анализатора, чтобы ознакомиться с его возможностями, проверив различные проекты.


Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Nikita Lipilin. How the PVS-Studio analyzer began to find even more errors in Unity projects.
Подробнее..

Из песочницы 11 предпосылок того, что ваш сайт убогий

20.06.2020 12:14:32 | Автор: admin
Сейчас каждой уважающей себя компании следует иметь свой сайт. Иногда это сводится к абсурду: сеть из двух-трёх автомоек в пределах одного города покупает домен, находит дизайнеров и программистов и пилит персональный лендинг. На фоне всего этого растет количество псевдо-дизайнеров и псевдо-программистов, которые после первого более-менее красивого проекта бегут на фриланс и создают сайты, выглядящие, мягко говоря, не очень.

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

1. Главная страница намного красивее других


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

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

2. Стиль сайта не соответствует сфере деятельности компании


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

Важно сохранить особенности выбранной вами отрасли: где-то нужно подчеркнуть стабильность и спокойствие, где-то динамичность и современность.

Дизайнерам: гуглите цвета и эмоции и отталкивайтесь для начала от этого, а затем действуйте по профессиональной интуиции.

3. Неправильные цвета


image

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

4. Много интерактива, всплывающих окон


image

Интерактив это красиво и прогрессивно, но в меру. А всплывающие окна хрень ещё та, которую не любит ни один пользователь. Их лучше заменить блоками в самой структуре сайта. К примеру, вместо модального окна обязательной регистрации при входе на сайт лучше просто оповестить посетителя, что без регистрации он ничего не сделает.

То же самое и с формами заявок. Лучше пусть они будут внизу сайта, а по клику пользователь будет перемещаться к ним.

5. У сайта нет адаптивности или даже отзывчивости


image

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

Но не стоит указывать дизайнерам делать разные разрешения для сайта, ведь это задача frontend-программистов.

6. Стиль лого не соответствует стилю сайта


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

7. Много или мало разделов


image

Разделов принято делать от трёх, но не более шести. Тут всё максимально просто: много разделов путаница, мало разделов та же путаница.

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

8. Много текста


image

За текстом в Войну и мир, пожалуйста! Сайт компании должен быть минималистичным, а с лонгридами без иллюстраций это уже стрёмный журнал, а не канал привлечения клиентов.

9. На главной странице нет ключевого действия


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

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

10. Нельзя связаться


Люди разные и к каждому нужен индивидуальный подход. Внедрить искусственный интеллект на сайт, конечно, можно, но не рационально. Поэтому лучше дать возможность потенциальному клиенту позвонить вашему администратору или вам самим.

11. Изображения с фотобанков


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

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

Автор статьи Арсен Осипян
Подробнее..

Ловим баги на клиенте как мы написали свою систему для сбора клиентских ошибок

08.10.2020 16:23:54 | Автор: admin

У нас в Badoo довольно много клиентских приложений. Помимо основных продуктов Badoo и Bumble, у которых есть как веб-версии (десктопная и мобильная), так и клиенты под нативные платформы (Android и iOS), ещё есть с десяток внутренних инструментов со своими UI. Для сбора клиентских ошибок мы используем собственную разработку под кодовым названием Gelatо. Последние два года я работал над её серверной частью и за это время открыл для себя много нового из мира разработки Error Tracking систем.

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


Что вас ждёт:

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

  • дам краткий обзор нашей системы, её архитектуры и технологического стека;

  • перечислю особенности, которые нужно учитывать, если вы решите разрабатывать свою систему сбора клиентских ошибок.

Как мы используем информацию об ошибках

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

Второе проводим анализ ошибок. Мы в Badoo релизимся довольно часто:

веб-приложения: один-два раза в день, включая серверную часть;

нативные приложения: раз в неделю (хотя многое зависит от того, как быстро билд примут в App Store и Google Play).

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

Третье. Информация об ошибках, собранная в одном месте, значительно упрощает работу разработчиков и QA-инженеров.

Что использовали раньше

Исторически для сбора клиентских ошибок в Badoo использовались две системы: HockeyApp для сбора краш-репортов из нативных приложений и самописная система для сбора JS-ошибок.

HockeyApp

HockeyApp полностью удовлетворяла наши потребности, до тех пор пока в 2014 году её не приобрела Microsoft и не начала менять политику использования, чтобы подтолкнуть людей к переходу на свою систему App Center. App Center на тот момент нашим требованиям не соответствовала: она находилась на стадии активной разработки, и часть необходимой нам функциональности отсутствовала, в частности деобфускация стек-трейсов Android-приложений с использованием DexGuard mapping-файлов, без которой невозможна группировка ошибок. О деобфускации я расскажу ниже; если вы слышите об этом впервые, значит, точно узнаете что-то новое.

Microsoft установила дедлайн 16 октября 2019 года, к этому дню все пользователи HockeyApp должны были мигрировать в App Center. К слову, поддержка DexGuard появилась в App Center лишь в конце декабря 2019 года, спустя несколько месяцев после официального закрытия HockeyApp.

В дополнение к этому мы столкнулись с проблемой некорректного подсчёта общего количества ошибок в HockeyApp. Так как Microsoft фактически остановила разработку HockeyApp, нам пришлось начать дублировать эту информацию во внутреннюю систему аналитики, чтобы понимать реальное количество ошибок. Это послужило ещё одним толчком к поиску альтернативного решения.

Наша система для сбора JS-ошибок

Что касается самописной системы для сбора JS-ошибок, то долгие годы она работала без нареканий, хотя обладала лишь базовой функциональностью.

Архитектура у неё была довольно простой:

  • данные хранились в MySQL (мы хранили информацию о последних 1020 релизах);

  • для каждой версии приложения была отдельная таблица;

  • работал поиск по фиксированному набору полей средствами MySQL, плюс мы использовали Sphinx для полнотекстового поиска.

В 2017 году у нас примерно в два раза увеличилась команда фронтенд-разработки. Системой начали пользоваться более активно и разработчики стали всё чаще упираться в её ограничения. Кому-то не хватало возможности поиска по произвольным полям, кто-то хотел видеть историю ошибок между релизами, кого-то не устраивало, что мы храним информацию только о последних релизах.

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

Поэтому мы решили постепенно переходить на новую систему, которая бы покрывала весь существующий функционал и удовлетворяла всем нашим актуальным требованиям.

Требования к новой системе

  • Хранение всех клиентских ошибок в одном месте.

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

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

  • Отказоустойчивость чтобы минимизировать риск потери данных.

  • Способность давать ответ не только на вопрос Сколько произошло ошибок?, но и на вопрос Сколько пользователей это затронуло?.

  • Группировка похожих ошибок с сохранением мета-информации (время первой и последней ошибки в группе, в каком релизе появилась ошибка, статус ошибки и т. п.).

  • Гибкий поиск по любой комбинации полей с поддержкой полнотекстового поиска.

  • Разнообразная статистика: количество ошибок за период, количество ошибок в разбивке по релизам, по браузерам, по операционным системам и т. п.

  • Интеграция с Jira. Наша разработка ведётся с использованием Jira, поэтому нам необходима возможность создавать тикеты для определённых ошибок.

  • Self-hosted. Мы хотим, чтобы система работала на нашем железе. Это обеспечит нам полный контроль над данными и возможность в любой момент изменить конфигурацию кластера.

Почему мы не выбрали готовое решение

Конечно, прежде чем писать своё решение, мы проанализировали существующие на рынке системы.

Платные сервисы

Сбором клиентских ошибок занимаются многие SaaS-решения, и это неудивительно: быстрое обнаружение и исправление ошибок один из ключевых аспектов современной разработки. Среди самых популярных решений можно выделить Bugsnag, TrackJS, Raygun, Rollbar и Airbrake. Все они обладают богатым функционалом и в целом соответствуют нашим требованиям, но мы не рассматривали облачные решения: не было уверенности в том, что ценовая политика и политика использования со временем не изменятся, как это случилось с HockeyApp. А миграция на новое решение довольно сложная и длительная процедура.

Open-source-решения

С open-source-системами всё было не так радужно. Большинство из них либо перестали развиваться, либо так и не вышли из стадии разработки и были непригодны для использования в продакшене.

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

  • вместо хранения всех событий в ней использовалось семплирование;

  • в качестве базы данных использовалась PostgreSQL, с которой у нас не было опыта работы;

  • были сложности с добавлением новой функциональности, так как система написана на Python, а наши основные языки PHP и Go;

  • отсутствие части необходимой нам функциональности (например, интеграции с Jira).

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

Так на свет появилась система под кодовым названием Gelato (General Error Logs And The Others), о разработке которой и пойдёт речь дальше.

Краткий обзор системы

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

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

Кликнув на то или иное приложение, мы попадём на страницу со статистикой по его релизам.

Кликнув на версию, мы попадём на страницу со списком ошибок.

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

Так эта страница выглядит для нативных приложений:

Кликнув на ошибку, мы попадём на страницу с детальной информацией о ней.

Здесь доступны общая информация об ошибке (1), график общего количества ошибок (2) и различная аналитика (3).

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

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

Выбираем версии для сравнения:

И попадаем на страницу со списком ошибок, которые есть в одной версии и которых нет в другой:

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

  • интеграция с нашим A/B-фреймворком для отслеживания ошибок, которые появились в том или ином сплит-тесте;

  • система уведомлений о новых ошибках;

  • расширенная аналитика (больше графиков и диаграмм);

  • email-дайджесты со статистикой по приложениям.

Общая схема работы

Теперь поговорим о том, как всё устроено под капотом. Схема довольно стандартная и состоит из трёх этапов:

  1. Сбор данных.

  2. Обработка данных.

  3. Хранение данных.

Схематически это можно изобразить следующим образом:

Давайте для начала разберёмся со сбором данных.

Сбор данных

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

Что входит в задачи API:

  • прочитать данные;

  • проверить данные на соответствие требуемому формату, чтобы сразу отсечь шум (чаще всего это запросы от мамкиных хакеров, которые натравили сканеры на наше API);

  • сохранить всё в промежуточную очередь.

Для чего нужна промежуточная очередь?

Если полагаться на то, что у нас достаточно низкий EPS (errors per second), и на то, что все части нашей системы будут работать стабильно всё время, то можно значительно упростить систему и сделать весь процесс синхронным.

Но мы-то с вами знаем, что в реальном мире так не бывает и на каждом из этапов в самый неподходящий момент может произойти нечто непредвиденное. И к этому наша система должна быть готова. Так, ошибка в одной из внешних зависимостей приложения приведёт к тому, что оно начнёт крашиться, что повлечёт за собой рост EPS (как это было с iOS Facebook SDK 10 июля 2020 года). Как следствие, значительно увеличится нагрузка на всю систему, а вместе с этим и время обработки одного запроса.

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

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

Что можно использовать в качестве очереди?

  1. Первое, что приходит в голову, популярные брокеры сообщений, например Redis или RabbitMQ.

  2. Также можно использовать Apache Kafka, которая хорошо подходит для случаев, когда требуется хранить хвост входящих данных за определённый период (например, для какой-то внутренней аналитики). Kafka используется в частности в последней (десятой) версии Sentry.

  3. Мы остановились на LSD (Live Streaming Daemon). По сути, это очередь на файлах. Система используется в Badoo довольно давно и хорошо себя зарекомендовала, плюс у нас в коде уже есть вся необходимая обвязка для работы с ней.

Хранение данных

Тут нужно ответить на два вопроса: Где хранить? (база данных) и Как хранить? (модель данных).

База данных

При реализации прототипа системы мы остановились на двух претендентах: Elasticsearch и ClickHouse.

Elasticsearch

Из очевидных плюсов данной системы можно выделить следующие:

  • горизонтальное масштабирование и репликация из коробки;

  • большой набор агрегаций, что удобно при реализации аналитической части нашей системы;

  • полнотекстовый поиск;

  • поддержка UPDATE по условию (процесс обработки данных у нас асинхронный, и нужна возможность выполнять некоторые шаги пайплайна повторно, а значит, и возможность обновлять определённые поля у конкретных событий);

  • поддержка DELETE по условию (мы храним данные за полгода, а значит, нам нужна возможность удалять устаревшие данные);

  • гибкая настройка через API, что позволяет разработчикам менять настройки индексов в зависимости от задач.

Конечно, как у любой системы, у Elasticsearch есть и недостатки:

  • сложный язык запросов, поэтому документация всегда должна быть под рукой (в последних версиях появилась поддержка синтаксиса SQL, но это доступно только в платной версии (X-Pack) либо при использовании Open Distro от Amazon);

  • JVM, которую нужно уметь готовить, в то время как наши основные языки это PHP и Go (например, для оптимизации сборщика мусора под определённый профиль нагрузки требуется глубокое понимание того, как всё работает под капотом; мы столкнулись с этой проблемой при обновлении с версии 6.8 до 7.5, благо тема не нова и есть довольно много статей в интернете (например, тут и тут));

  • плохое сжатие строк; мы планируем хранить довольно много данных и, хотя железо с каждым годом дешевеет, хотим использовать ресурсы максимально эффективно (конечно, можно использовать deflate-сжатие вместо LZ4, но это увеличит потребление CPU, что может негативно сказаться на производительности всего кластера).

ClickHouse

Плюсы данной базы:

  • отличная производительность на запись;

  • хорошее сжатие данных, особенно длинных строк;

  • MySQL-совместимый синтаксис запросов, что избавляет от необходимости учить новый язык запросов, как в случае с Elasticsearch;

  • горизонтальное масштабирование и репликация из коробки, хоть это и требует больше усилий по сравнению с Elasticsearch.

Но на начало 2018 года в ClickHouse отсутствовала часть необходимых нам функций:

  • Поддержка DELETE по условию (мы планировали хранить данные за полгода, поэтому нам была необходима возможность удаления устаревших данных; в ClickHouse удаление данных по произвольному критерию предусмотрено не было, а партиционирование по произвольному полю (в нашем случае по дате) на тот момент находилось на стадии экспериментальной фичи и не рекомендовалось к использованию в продакшене);

  • поддержка UPDATE по условию: ClickHouse заточена под неизменяемые данные, поэтому реализация обновления произвольных записей задача не из лёгких (этот вопрос не раз поднимался на GitHub и в конце 2018 года функцию всё же реализовали, но она не подходит для частых обновлений);

  • полнотекстовый поиск (была опция поиска по RegExp, но он требует сканирования всей таблицы (full scan), а это довольно медленная операция).

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

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

Модель данных

Теперь немного поговорим о том, как мы храним события.

Все данные у нас разбиты на несколько групп и хранятся в отдельных индексах:

  • мета-информация;

  • сырые события.

Данные изолированы в рамках конкретного приложения (отдельный индекс) это позволяет кастомизировать настройки индекса в зависимости от нагрузки. Например, для непопулярных приложений можно хранить данные на warm-нодах в кластере (мы используем hot-warm-cold-архитектуру).

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

Сама идея была позаимствована из Sentry и незначительно доработана в процессе эксплуатации. В Sentry у события есть базовые поля, есть поле tags для данных, по которым нужна возможность поиска, и поле extra для всех остальных специфических данных.

Обработка данных

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

Начнём со случая попроще.

Обработка краш-репортов из Android-приложений

Чтобы максимально уменьшить размер приложения, в Android-мире принято при сборке билда использовать специальные утилиты, которые:

  • удаляют весь неиспользуемый код (code shrinking сокращение);

  • оптимизируют всё, что осталось после первого этапа (optimization оптимизация);

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

Подробнее про это можно узнать из официальной документации.

Сегодня есть несколько популярных утилит:

  • ProGuard (бесплатная версия);

  • DexGuard на базе ProGuard (платная версия с расширенным функционалом);

  • R8 от Google.

Если приложение собрано с режимом обфускации, то стек-трейс будет выглядеть примерно так:

o.imc: Error loading resources: Security check requiredat o.mef.b(:77)at o.mef.e(:23)at o.mef$a.d(:61)at o.mef$a.invoke(:23)at o.jij$c.a(:42)at o.jij$c.apply(Unknown Source:0)at o.wgv$c.a_(:81)at o.whb$e.a_(:64)at o.wgs$b$a.a_(:111)at o.wgy$b.run(:81)at o.vxu$e.run(:109)at android.os.Handler.handleCallback(Handler.java:790)at android.os.Handler.dispatchMessage(Handler.java:99)at android.os.Looper.loop(Looper.java:164)at android.app.ActivityThread.main(ActivityThread.java:6626)at java.lang.reflect.Method.invoke(Native Method)at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:811)

Из него мало что можно понять, за исключением сообщения об ошибке. Чтобы извлечь полезную информацию из такого стек-трейса, его нужно расшифровать. Процесс дешифрования обфусцированных классов и методов называется деобфускацией, для этого необходим специальный файл mapping.txt, который генерируется в момент сборки билда. Вот фрагмент такого файла:

AllGoalsDialogFragment -> o.a:    java.util.LinkedHashMap goals -> c    kotlin.jvm.functions.Function1 onGoalSelected -> e    java.lang.String selectedId -> d    AllGoalsDialogFragment$Companion Companion -> a    54:73:android.view.View onCreateView(android.view.LayoutInflater,android.view.ViewGroup,android.os.Bundle) -> onCreateView    76:76:int getTheme() -> getTheme    79:85:android.app.Dialog onCreateDialog(android.os.Bundle) -> onCreateDialog    93:97:void onDestroyView() -> onDestroyView

Следовательно, нам нужен сервис, которому мы могли бы скормить обфусцированный стек трейс и mapping-файл и на выходе получить оригинальный стек-трейс.

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

На её базе наши Android-разработчики написали простенький сервис на Kotlin, который:

  • принимает на вход стек-трейс и версию приложения;

  • скачивает необходимый mapping-файл из Ceph (маппинги заливаются автоматически при сборке релиза в TeamCity);

  • деобфусцирует стек-трейс.

Обработка краш-репортов из iOS-приложений

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

Thread 0:0   libsystem_kernel.dylib              0x00000001bf3468b8 0x1bf321000 + 1537841   libobjc.A.dylib                     0x00000001bf289de0 0x1bf270000 + 1059522   Badoo                               0x0000000105c9c6f4 0x1047ec000 + 216941963   Badoo                               0x000000010657660c 0x1047ec000 + 309755004   Badoo                               0x0000000106524e04 0x1047ec000 + 306416685   Badoo                               0x000000010652b0f8 0x1047ec000 + 306670006   Badoo                               0x0000000105dce27c 0x1047ec000 + 229464287   Badoo                               0x0000000105dce3b4 0x1047ec000 + 229467408   Badoo                               0x0000000104d41340 0x1047ec000 + 5591872

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

Что можно использовать для символикации?

  • Можно написать свой сервис на базе консольных утилит, но, скорее всего, он подойдёт только для ручной символикации и будет доступен только на macOS. У нас же, например, всё работает на Linux.

  • Можно взять сервис Symbolicator от Sentry, который недавно был выложен в открытый доступ (рекомендую почитать статью о том, как он разрабатывался). Мы какое-то время экспериментировали с ним и пришли к выводу, что as is этот сервис будет сложно интегрировать в нашу схему: пришлось бы допиливать его под наши нужды, а опыта использования Rust у нас нет.

  • Можно написать свой сервис на базе библиотеки Symbolic от Sentry, которая, хоть и написана на Rust, но предоставляет C-ABI её можно использовать в языке с поддержкой FFI.

Мы остановили свой выбор на последнем варианте и написали сервис на Golang с учётом всех наших нюансов, который под капотом обращается к Symbolic через cgo.

Группировка ошибок

И ещё один процесс, которому следует уделить внимание, группировка ошибок. От неё зависит, как быстро вы сможете обнаруживать наиболее критичные ошибки среди всех остальных событий.

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

Мы решили не усложнять свою систему и остановились на группировке по хешу:

  • JS-ошибки группируются по полям message, type и origin;

  • Android краш-репорты группируются по первым трём строчкам стек-трейсов (плюс немного магии);

  • iOS краш-репорты группируются по первому несистемному фрейму из упавшего треда (тред, который отмечен как crashed в краш-репорте).

В качестве заключения

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

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

Ну а если вы решите последовать нашему примеру и станете разрабатывать собственную систему, то в этой статье я постарался максимально раскрыть основные моменты, на которые следует обратить внимание.

Если резюмировать, то:

  • храните как можно больше данных: это может сэкономить вам драгоценные часы и нервы, которые в противном случае придётся потратить на дебаг;

  • будьте готовы к резкому росту количества ошибок;

  • чем больше аналитики вы построите, тем лучше;

  • символикация iOS краш-репортов это сложно, присмотритесь к Symbolicator;

  • предусмотрите систему уведомления о новых ошибках: это даст вам больше контроля и возможность своевременно реагировать на резкий рост ошибок;

  • запаситесь терпением и приготовьтесь к увлекательному путешествию в мир разработки систем сбора ошибок.

Подробнее..

А на прошлом месте работы было по-другому

23.04.2021 02:12:06 | Автор: admin

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

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

Прошлые статьи

Примерный план будущих статей:

  • О выгорании на ранних этапах

  • О важности изучения языка, но не фреймворка

  • Когда ты перестаешь быть junior разработчиком

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


Disclaimer: эта статья не является абсолютным правилом, и ваш опыт может отличаться.

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

  1. Это ваше первое местое работы

  2. Вы работаете там достаточно продолжительное время (1 - 1,5 года +)

  3. Вы работаете с одним и тем же лидом/ментором

  4. Вы работаете на одном и том же проекте с одинаковым стеком

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

В чем же суть проблемы, спросите вы? Первая работа и опытный ментор имеют крайне сильное влияние на человека. У вас нет времени оценивать каждое требование, нет каких-либо особых предпочтений, вы полностью доверяете старшему разработчику и это нормально. В какой-то момент вы так привыкаете к каким-то правилам (или отсутствию правил), что весь процесс работы над задачей проходит автоматически.

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

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

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

И workflow хорош именно тем, что он гибкий. Он изменяется под нужды текущей команды, проекта, релизов, постановки задач. То есть нет такого единого стандартного решения, есть база, которая видоизменяется со временем.

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

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

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

Пример из жизни о правиле, которое не понятно сразу

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

Пример о хорошей практике разработчика, которая не была принята

Один из моих разработчиков довольно тесно работал с husky, и он предлагал ввести его в проект. И это действительно хороший инструмент, но было принято решение отдать предпочтение ci/cd, так как в команде есть правило о маленьких, атомарных коммитах, и частенько возникала ситуация, когда коммитили частично, и остальные файлы могли быть еще на стадии доработки.

Да, husky можно было бы настроить на изменения в коммите, или перевести на команду push, но то ли я не доразобралась, то ли что, но на push оно в результате все равно отправлялось несмотря на то, что проверки проваливались.

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

То есть в результате, контроль качества кода проводился, просто другим способом, который более привычен для большей части команды. Но разработчику все равно было некомфортно, потому что для него это было не то решение, к которому он привык.

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

Пример из жизни на эту тему

Дано: есть проект на Vue, который был написан бэкендщиком без знания клиентской архитектуры, и который в кратчайшие сроки нужно было привести в более менее работающий вид. Разработчик из команды предлагает ввести RxJS в проект (до этого он долго работал с Angular, это было кстати его первое место работы).

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

В том же проекте, часть файлов он написал на TypeScript (большая часть была на JS). Мне очень нравится TS, но по опыту я знаю что 2-я версия Vue не очень хорошо с ним работает, и местами это вызывает трудности. В результате больше времени тратится на то, как правильно этот тип прокинуть, а то и вовсе просто пишется any. Также нужно учитывать момент, что перевод проекта на TS - это увеличение сроков, и в данном случае это было нецелесообразное решение. Причина по которой он начал это делать довольно проста, привычка и мысль, что так правильно, а по-другому плохо, значит нужно переделать.

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

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

Пример о непринятии замечаний в силу неопытности

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

Для меня это было абсолютно ново, и мне казалось что он отправляет на доработку просто из-за мелочей, которые не особо важны. По сути он научил меня тогда, как делать правильно, как улучшить UI/UX для обычного рядового пользователя, и почему важны такие мелочи. Конечно потом я поняла, что была не права, но также поняла для себя, что это сильно зависит от проекта и его задачи.

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

Пример о непринятии новой архитектуры

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

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

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

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

Немного о фрилансе

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

По секрету

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

Заключение

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

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

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

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

Подробнее..

5 самых частых ошибок на экзамене IELTS и как их избежать

05.02.2021 20:16:55 | Автор: admin

IELTS это один из двух самых популярных экзаменов для оценки уровня английского языка. Каждый год его проходит свыше 3 млн людей во всем мире.

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

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

Больше всего ошибок допускается на этапах Writing и Speaking. То есть, во время написания текстов и диалога с экзаменатором. Сложность в том, что на этих этапах нужно говорить и писать своими словами, а не выбирать из вариантов или писать краткие ответы из одного или нескольких слов.

Поэтому давайте обратим внимание на распространенные ошибки и важные моменты.

1. Объем текстов в блоке Writing

В письменной части экзамена необходимо написать два текста. Первое эссе или письмо на заданную тему, а второе аргументировать свою точку зрения. И объем написанного в этом случае критичен.

В первом задании нужно написать не менее 150 слов, во втором как минимум 250. Даже если у вас будет 149 и 249 слов соответственно, экзаменатор может поставить за весь блок по нулям.

Если в бумажном варианте экзаменатору может быть просто лень подсчитывать слова поштучно, то в электронном это делает система.

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

Оптимальная тактика написать тексты на 170-280 и 270-280 слов соответственно, а оставшееся время потратить на их вычитку.

2. Слишком много филлеров в Speaking

Вставные слова это хорошо. Они показывают высокий уровень владения языком. Это так, но не совсем.

С одной стороны, носители языка используют много слов-паразитов. И если проанализировать речь среднестатистического американца, она будет наполнена различными well, literally, you know, like и другими.

Но к уровню владения языком это не имеет никакого отношения. Это лишь привычка заполнять пробелы в речи, чтобы не было неловкого молчания.

Знание слов-филлеров и уместное их использование действительно даст вам пару дополнительных баллов у экзаменатора. Но злоупотребление ими и попытки замаскировать паузы для осмысления следующей фразы даже наоборот.

Использовать вставные слова в блоке Speaking вполне нормально. Но оптимальная тактика использовать один филлер не чаще чем на три-четыре предложения.

3. Уход от темы обсуждения

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

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

Это не работает. Экзаменатор следит за актуальностью речи и текста. Если вы слишком сильно отклоняетесь от темы или вовсе не раскрываете ее, то за все задание можете получить ноль баллов.

Возьмем для примера реальное задание IELTS с комментариями экзаменаторов.

Текст задания:

Children who are brought up in families that do not have large amounts of money are better prepared to deal with the problems of adult life than children brought up by wealthy parents. To what extent do you agree or disagree with this opinion?

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

Вот один из примеров ответов:

И комментарий экзаменатора по этому заданию.

While it is obviously related to the topic, the introduction is confusing and the test takers position is difficult to identify. Ideas are limited and although the test taker attempts to support them with examples from experience, they remain unclear. There is no overall progression in the response and the ideas are not coherently linked.

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

По сути экзаменуемый пытается аргументировать свою точку зрения на основе личного опыта, но ответ размывается настолько, что его реальную позицию трудно определить.

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

4. Важны не идеи, а то, как вы их описываете

Еще одна очень распространенная ошибка попытка блеснуть оригинальным ответом.

Многие забывают, что экзаменатору абсолютно все равно, что именно вы ответите он оценивает язык, а не идею или жизненную позицию.

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

Выделиться и сформулировать оригинальную и уникальную точку зрения никто не запрещает.

Но у этой тактики есть два главных минуса:

  • Дополнительных баллов за оригинальность ответа никто давать не будет. Оценивается форма, а не уникальность мысли.

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

Если нужно выразить точку зрения и аргументировать ее, не нужно гнаться за оригинальностью. Будет вполне достаточно подтвердить тезис или опровергнуть его с помощью аргументов и логических доказательств.

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

Вот пример хорошего и слабого ответа на вопрос It is better for students to work before their university study. Do you agree or disagree?.

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

Ясно, что первый ответ получит минимальный балл, а второй высокий.

5. Акцент не важен важно произношение

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

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

Постараемся ее объяснить. В английском языке акцентов существует великое множество. Помимо самых распространенных RP и американского есть еще ирландский, шотландский, канадский, австралийский, кокни этот список можно продолжать долго.

У каждого из них свои особенности произношения слов.

Можно услышать, насколько сильно отличаются некоторые слова в британском, американском и австралийском акценте. Но при этом все они правильно произнесенные.

К примеру, возьмем слово chaos хаос. Русскоговорящему человеку очень хочется прочитать его именно как [хаос]. Но это будет уже ошибкой, потому что правильный вариант [ke.s].

Или другой пример слово bear (медведь). В американском английском оно произносится как [ber], в английском [be(r)]. Но если сказать [br], то медведь волшебным образом превратится в пиво. И за это снимут баллы.

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

***

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

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

Онлайн-школа EnglishDom.com вдохновляем выучить английский через технологии и человеческую заботу

Только для читателей Хабра первый урок с преподавателем в интерактивном цифровом учебнике бесплатно! А при покупке занятий получите до 3 уроков в подарок!

Получи целый месяц премиум-подписки на приложение ED Words в подарок. Введи промокод 5ielts на этой странице или прямо в приложении ED Words. Промокод действителен до 05.03.2021.

Наши продукты:

Подробнее..

Перевод Советы Golang почему указатели на срезы полезны и как их игнорирование может привести к хитрым ошибкам

02.11.2020 12:06:03 | Автор: admin

Сомнения

Сегодня, пока я работал, возник хороший вопрос:

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

Например, в реализации api-machinery Kubernetes мы можем увидеть функцию со следующей сигнатурой:

func ConvertSlicestringTostring (input * [] string, out * string, s conversion.Scope) error

И в примере очередей с приоритетом мы снова можем найти нечто подобное:

func (pq * PriorityQueue) Pop () interface {};

Разве срезы уже не являются указателями на хранимые в нем данные?

Давайте немного разберемся, используя Go-Playground, чтобы проверить поведение кода.

Во время всего объяснения я буду использовать один и тот же пример: функция, которая инициализирует срез, передает его в качестве аргумента второй функции, изменяет его, а затем печатает срез для проверки содержимого.

Принято считать, что срезы передаются по ссылке. В следующем примере, на самом деле, будут напечатаны [b, b]и [b, b] даже если срез был инициализирован как [a, a], поскольку он был изменен во время выполнения анонимной функции, и изменение видно в main.

func main() {    slice:= []string{"a","a"}        func(slice []string){        slice[0]="b";        slice[1]="b";        fmt.Print(slice)    }(slice)    fmt.Print(slice) }

Использование указателей приводит к тому же по сути результату:

func main() {    slice:= []string{"a","a"}     func(slice *[]string){        (*slice)[0]="b";        (*slice)[1]="b";         fmt.Print(*slice)    }(&slice)    fmt.Print(slice) }

Этот код также напечатает [b, b]и [b, b] Поэтому передача по указателю выглядит бесполезной, и кажется, что срез все равно передается по ссылке, а содержимое изменяется в обоих случаях.

Так почему же у этих функций такая сигнатура?

Объяснение

Вы можете примерно представить реализацию среза так:

type sliceHeader struct {    Length        int    Capacity      int    ZerothElement *byte}

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

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

Таким образом, ответ на вопрос прост, но он скрыт внутри реализации самого среза:

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

Указатель на срез является неизменяемым в момент, когда функция собирается изменить структуру, размер или расположение среза в памяти. А эти изменения должны быть видны тому, кто вызывает функцию.

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

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

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

Следовательно, в том же примере, но с принудительным повторным выделением среза будут напечатаны [b, b, a]и [a, a] Переместив append()ниже в место после манипулирования срезом, мы можем заметить, что поведение отличается, поскольку срез был перераспределен после манипуляции значениями, а указатель все еще указывает на начальный адрес памяти.

func main() {    slice:= []string{"a","a"}     func(slice []string){        slice= append(slice, "a")        slice[0]="b";        slice[1]="b";         fmt.Print(slice)    }(slice)    fmt.Print(slice) }

Проверим это на коде ниже:

func main() {    slice:= []string{"a","a"}     func(slice []string){        slice[0]="b";        slice[1]="b";         slice= append(slice, "a")        fmt.Print(slice)    }(slice)    fmt.Print(slice) }

Он печатает [b, b, a]и [b, b]по объясненным выше причинам.

Такое поведение может привести к трудно обнаруживаемым ошибкам, поскольку результат зависит от размера исходного массива, например, следующий код:

func main() {    slice:= make([]string, 2, 3)     func(slice []string){                slice= append(slice, "a")                slice[0]="b";        slice[1]="b";         fmt.Print(slice)    }(slice)    fmt.Print(slice) }

Напечатает [b, b, a]и [b, b] поскольку на массив больше не происходит выделение памяти и указатель остается прежним.

Однако при добавлении еще одной строки slice = append (slice, a, a) под массив снова выделяется память, и результатом будет [b, b, a, a]и [](пустой массив, поскольку он не был инициализирован).

Выявить такие ошибки среди сотен или тысяч строк может быть довольно сложно.

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

Теперь вы готовы понять, что выведет следующий код:

func main() {    slice:= make([]string, 1, 3)      func(slice []string){        slice=slice[1:3]        slice[0]="b"        slice[1]="b"        fmt.Print(len(slice))        fmt.Print(slice)    }(slice)    fmt.Print(len(slice))     fmt.Print(slice)}

Можете запустить код на GoPlayground или написать ответ в комментариях.

Подробнее..
Категории: Go , Ошибки , Slices , Pointer , Gotcha

Топ-5 ошибок нейтивов в английском, которые сейчас считаются нормой

18.05.2021 18:11:11 | Автор: admin

Английский язык постоянно меняется. Это средство коммуникации и оно постепенно трансформируется в угоду удобства людей, которые на нем говорят.

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

Двойное отрицание

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

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

Давайте сразу на примере.

I didnt see nothing.

Didnt это отрицание глагола, а nothing отрицание объекта. Но если следовать грамматике, то перевести фразу как Я ничего не видел нельзя. Правильный вариант Я видел что-то, что в контексте звучит довольно странно.

Чтобы грамматически правильно сказать Я не видел ничего, нужно использовать только одно отрицание: I didnt see anything или I saw nothing.

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

Сегодня это правило игнорируется практически полностью. В разговорном английском двойное отрицание встречается довольно часто и только для усиления.

Если нейтив говорит I didnt see nothing, то это означает Я ничего не видел. Точно так же, как и в русском.

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

В качестве музыкального примера вспомним песню группы The Rolling Stones Satisfaction. Обратите внимание на фразу I cant get no satisfaction Я не могу получить никакого удовольствия.

Предлог в конце предложения

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

Сравните два предложения:

Which journal was your article published in?

In which journal was your article published?

В каком журнале опубликована твоя статья?

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

Причина в том, что многие студенты еще в школе запоминают, что вопрос должен начинаться с вопросительного слова. Это настолько глубоко вбивается в память, что частные случаи вроде To whom should I give this thing? (Кому мне стоит отдать эту штуку?) кажутся ошибочными.

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

Правило очень старое, родом из XVII века. Его создал лингвист Джошуа Пул, который писал, что в английском языке слова должны быть расположены в их естественном порядке.

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

Вопросы без do

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

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

А чтобы вспомнить все пять типов вопросов и правила, по которым их грамотно строить, смотрите вот это видео:

Порядок слов в общих вопросах запомнить довольно просто. Сначала нужно поставить вспомогательный глагол do в нужной форме, затем подлежащее и основной глагол. А дальше все остальное.

Do you like this pie? Тебе нравится этот пирог?

По самой форме предложения уже ясно, что это вопрос. Прочитать его иначе невозможно.

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

You like this pie?

Или можно даже короче: Like it?. Если вопросительная интонация есть, то вопрос будет понятным даже в такой форме.

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

Fewer и less

По нормам английского языка fewer нужно использовать вместе с исчисляемыми существительными (к примеру, friends, animals, books, rooms), а less с неисчисляемыми (money, rice, water).

Это правило было описано еще в 1770 году в словаре Мерриам-Вебстер:

As far as we have been able to discover, the received rule originated in 1770 as a comment on less: "This Word is most commonly used in speaking of a Number; where I should think Fewer would do better. 'No Fewer than a Hundred' appears to me, not only more elegant than 'No less than a Hundred', but more strictly proper."

Насколько нам удалось обнаружить, принятое правило возникло в 1770 году как комментарий к слову less: Это слово чаще всего используется, применимо к количеству, где я считаю, что fewer подошло бы лучше. No Fewer than a Hundred кажется мне не только более элегантным, чем 'No less than a Hundred', но и более правильным.

Замечания Бейкера, редактора словаря, относились к его собственному мнению, но со временем их возвели в абсолют. Если можно посчитать fewer, если нельзя less. Это правило все еще остается нормой языка и в официальных документах нужно писать именно так.

Сегодня же существует еще одно правило, более разговорное и упрощенное, по которому less используется с единственным числом, а fewer с множественным. И как можно заметить, эти два правила противоречат друг другу.

По факту получается, что нейтивы используют fewer и less в предложениях как попало. И очень часто fewer просто остается не у дел, а less пихается абсолютно везде.

Less money, less problems. Меньше денег меньше проблем.

Типичная неправильная фраза. Потому что грамматически верный вариант должен быть Less money, fewer problems. Но в качестве разговорного вполне рабочая и понятная схема.

Me как субъект предложения

У английских местоимений есть только два падежа: именительный и объектный. И по правилам языка только именительный падеж может быть подлежащим.

I went to the park last Sunday. Я ходил в парк в прошлое воскресенье.

Соответственно, обжектив может быть только дополнением.

What do you want from me? Что ты от меня хочешь?

Но с составным подлежащим правило часто дает сбой. Допустим, у нас есть рассказчик (I) и его друг (Jack). По правилам английского в составном подлежащем рассказчик должен назвать сначала друга, а потом себя:

Jack and I went to the cinema. Джек и я пошли в кино.

Но в разговорном варианте оно часто трансформируется в:

Me and Jack went to the cinema.

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

Бывает даже следующий вариант:

Me and him went to the cinema.

Сразу два объектных падежа в качестве подлежащего вместо классических He and I. Или можно привести еще более естественный вариант: You and me. К примеру, You and me should go to the cinema Ты и я должны сходить в кино. Среди нейтивов не так много людей, которые скажут здесь You and I даже несмотря на то, что это абсолютно правильно грамматически.

***

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

Онлайн-школа EnglishDom.com вдохновляем выучить английский через технологии и человеческую заботу

Только для читателей Хабра первый урок с преподавателем в интерактивном цифровом учебнике бесплатно! А при покупке занятий получите до 3 уроков в подарок!

Получи целый месяц премиум-подписки на приложение ED Words в подарок. Введи промокод may_21 на этой странице или прямо в приложении ED Words. Промокод действителен до 01.07.2021.

Наши продукты:

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru