Сайт The Daily WTF уже 16 лет собирает курьёзные, дикие и печальные истории из мира ИТ. Я перевёл несколько рассказов, показавшихся мне интересными. Все имена и названия компаний изменены. Предыдущие выпуски можно найти по метке "любопытные извращения".

Техлид от бога


Ссылка на оригинал

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

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

Отдел был небольшим — только Джаред и ещё пара разработчиков, Ларри и Барри. Тимлида у них не было, они просто координировали и распределяли работу. Их менеджер был почти невидим и в основном занимался тем, чтобы внешняя офисная политика не мешала работе. Работа была не особо простой, но оставалась понятной и чётко очерченной, а оплата приличной.

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

Если говорить вкратце, то это была лучшая работа, с которой сталкивался Джаред за всю свою карьеру.

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

«Что случилось?», — спросил Джаред.

Ответом был долгий вздох, за которым последовало «Просто… посмотри на новый код».

Джаред так и сделал. Последний коммит уничтожил всё. Большинство файлов в кодовой базе было удалено и заменено одним божественным объектом на 7 тысяч строк. Команда git blame выдала ему виновника — это был кто-то по имени Скотт.

«Кто такой Скотт?»

Ларри просто покачал головой и снова вздохнул. В разговор вступил Барри: «Он наш техлид».

«Что? У нас новый техлид?», — спросил Джаред.

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

Это признание вызвало ещё один вздох Ларри. Он покачал головой.

«Очевидно, это сотрудничество ему не понравилось», — объяснил Барри.

Чуть позже тем же утром в кабинет команды зашёл Скотт. «Привет, Джош, наверно, ты новый разработчик?»

«Меня зовут Джаред, я работаю здесь уже полгода».

«Я заметил, что вы немного сбились с курса», — сказал Скотт, не обратив внимания на слова Джареда. «Я занимался множеством разных проектов, потому что, знаешь ли, когда ты хорош, люди хотят, чтобы ты делал всё, и творил чудеса, понимаешь, о чём я? Мы внесём несколько изменений, чтобы повысить качество кода и улучшить структуру».

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

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

Кроме того, было удалено 18 человеко-месяцев работы — все новые фичи, добавленные Джаредом, Ларри и Барри за последние полгода. Конечные пользователи были в гневе от того, что потеряли огромную часть функциональности. К тому же, у многопоточной «производительной» версии уходили часы на то, что раньше выполнялось за секунды. А за несколько недель переделок Скотта количество багов в трекере Jira выросло в шесть раз.

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

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

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

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

Настройка производительности под эксабайтные запросы


Ссылка на оригинал

Хотя базы данных NoSQL определённо сыграли свою роль в разработке приложений, сферы применения реляционных СУБД по-прежнему существуют. Ключевое преимущество реляционных СУБД заключается втом, что при правильно нормализованной схеме возможен любой произвольный запрос, и вместо оптимизации запроса разработчики оптимизируют саму базу данных, чтобы обеспечить её соответствие требованиям к производительности — индексы, статистика, материализованные представления и т. д.

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

И это подводит нас к этому запросу, который Ти-Джей обнаружил при анализе проблемы производительности.

select Min(the.moddate) "ModifiedDate"
From T_91CDDC57 what , T_91CDDC57 the , T_91CDDC57 f
where f.rdate > sysdate-1095;

Во-первых, стоит поздравить того, кто назвал таблицу T_91CDDC57. Я подозреваю, что название сгенерировано, как и сгенерирован этот запрос. Баг очевиден — нет никаких причин указывать в операторе FROM три раза одну и ту же таблицу, если нам просто нужно найти самую раннюю moddate.

В этом и есть проблема. T_91CDDC57 — не особо большая таблица. Не сказать, что она мала: 4,5 миллиона строк и 34 миллиона данных; она увесиста, но не огромна. Проблема в соединении 4,5 миллиона строк с 4,5 миллиона строк без условия соединения, и в соединении всего этого с 4,5 миллиона строк снова без условия соединения.

Вот план объяснения того, как выполняется этот запрос:

-----------------------------------------------------------------------------------------------
| Id  | Operation                | Name                          | Rows  | Bytes | Cost (%CPU)|
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |                               |     1 |    16 |    19P  (1)|
|   1 |  SORT AGGREGATE          |                               |     1 |    16 |            |
|   2 |   MERGE JOIN CARTESIAN   |                               |    18E|    15E|    19P  (1)|
|   3 |    MERGE JOIN CARTESIAN  |                               |  4328G|    31T|  5321M  (1)|
|*  4 |     TABLE ACCESS FULL    | T_91CDDC57                    |   959K|  7499K| 18967   (2)|
|   5 |     BUFFER SORT          |                               |  4509K|       |  5321M  (1)|
|   6 |      INDEX FAST FULL SCAN| T_91CDDC57_TYPE_INDEX         |  4509K|       |  5544   (1)|
|   7 |    BUFFER SORT           |                               |  4509K|    34M|    19P  (1)|
|   8 |     INDEX FAST FULL SCAN | T_91CDDC57_MODDATE_INDEX      |  4509K|    34M|  4410   (1)|
-----------------------------------------------------------------------------------------------

Здесь примечательны несколько аспектов. Строка 4 выполняет TABLE ACCESS FULL. Это итерация f таблицы и мы видим, что благодаря оператору WHERE она подтягивает всего 959 тысяч строк. В строке 8 мы видим, что она сканирует T_91CDDC57_MODDATE_INDEX — она использует этот индекс для сортировки, чтобы можно было найти Min(the.moddate). Также мы видим, что она затрагивает 4509 тысяч строк. Строка 6, также для 4509 тысяч строк, является нашим доступом к what в запросе.

После того, как мы получили доступ к трём кучам данных, нужно их соединить. Так как отсутствуют операторы ON или WHERE для связывания таблиц, запрос соединяет каждую строку из каждой таблицы с каждой строкой в каждой другой таблице. И в строке 3, где мы соединяем первую пару таблиц, внезапно получается 4,3 триллиона строк и в целом 31 терабайт данных. А когда мы соединим это с третьей таблицей в строке 2, то размер увеличится до 18 * 1018 строк и 15 эксабайт данных.

Ти-Джей сказал:

Обработка более 15 эксабайт информации, вероятно, как-то связана со снижением производительности…

Да уж, вероятно.

Абсолютно актуальная база


Ссылка на оригинал

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

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

Время шло. Рынок книг рос экспоненциальными темпами, особенно после появления самиздата, а Интернет завоевал популярность. Теперь в библиотеках стояли десятки компьютеров, и все они были подключены к Интернету. Благодаря магии World Wide Web появилась возможность еженедельного, а то и ежедневного обновления.

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

И он быстро нашёл способ.

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

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

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

Удобная БД


Ссылка на оригинал

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

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

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

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

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

UPDATE CUSTOMER_TABLE SET FAX_PHONE_NUMBER = CAST (HAS_DOCK * 64 + HAS_LOCK * 32 + HAS_DOORBELL * 16 as varchar(10));

Проблема «решена».

Двойственный выбор


Ссылка


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

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

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

Всё это создавало некоторые технические сложности. Самая большая заключалась в том, что длина заголовка, сохранённая в виде текста, могла менять длину заголовка. Само по себе это решаемо, но проблемы создавали другие мелкие флаги. Если бы они описывали порядок байтов как BIGENDIAN=Y, то не запутает ли это пользователей? Будут ли пользователи путаться с тем, какую архитектуру они используют, или будут ожидать, что нужно использовать LITTLEENDIAN=Y?

В конечном итоге, было логичнее сделать все важные поля двоичными. Заголовок мог иметь и текстовый раздел, в котором могли храниться произвольные пары «ключ-значение». Для таких вещей, как порядок битов, существуют более простые способы решения проблемы, например, резервирование 32 бит, чтобы клиенты сохраняли в них 1. После этого парсер может определять, считывается ли единица как 0x00000001 или 0x10000000, и соответствующим образом реагировать. Хранение длины заголовка в виде integer, а не текста означало бы, что запись длины не повлияет на саму длину.

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

«Я думал, что мы выбрали текст!», — заявил Блез при проверке плана формата заголовков.

«Да, выбрали, но как я говорил, по техническим причинам эта схема гораздо более логична», — объяснил Тимоти.

«Верно, но если так сделать, то мы не сможем использовать cat или head для просмотра содержимого заголовка файла».

Тимоти моргнул. «В заголовке и так есть раздел для двоичных данных. Нельзя использовать cat или head для его просмотра».

«Но как ещё его просматривать?»

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

Блеза это не убедило. «У операторов может и не быть установлен этот инструмент! Я пользуюсь cat для чтения файлов, поэтому наш файл должен просматриваться через cat».

«Повторюсь, заголовок в любом случае содержит зарезервированный раздел для двоичных данных, само содержимое файла может быть двоичными данными, никогда не подразумевалось, что всё это должно работать с cat», — объяснял Тимоти, пытаясь сохранять спокойствие.

Блез запустил терминал, взял пример файла и открыл его через cat. «Вот!», — воскликнул он победно, указывая на раздел заголовка, где были видны пары «ключ-значение» в море двоичного хаоса. «Я всё равно вижу параметры заголовка. Мне нужно, чтобы файл был таким».

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

Как ни странно, заставить партнёров привыкнуть к новому формату почему-то было сложно…

Невидимые усилия


Ссылка на оригинал

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

После неудачи проекта Анита оказалась лишним звеном и опасалась, что её уволят. К счастью, вместо этого её перевели в другой отдел. И там она встретила Генри, своего нового менеджера.

Генри занимался базами данных. Непонятно, сколько опыта у него было в управлении проектами, но он определённо много знал в бизнес-аналитике. Генри объяснил, что Анита будет работать над реализацией фич, которые клиенты требовали уже много лет. Раньше Анита никогда не работала с аналитикой, но имела опыт в базах данных SQL. Она решила, что изучить многомерные базы данных будет не очень трудно. И она действительно училась, работая как армия из одного человека. Генри никогда не ставил ей жёстких дедлайнов, и всегда был рад ответить на её вопросы. Единственный недостаток работы с ним заключался в его пренебрежении решениями в open source. Анита не могла пользоваться пакетами NuGet; всё нужно было создавать с нуля. Она многому научилась, создавая собственную библиотеку парсинга JSON и разрабатывая аутентификацию OAuth 2.0.

После завершения проекта Анита приходила в офис Генри, чтобы продемонстрировать результаты. Удовлетворённый Генри говорил «Отлично!» и вручал ей новый проект. Когда Анита спрашивала, есть ли какой-то запрос на новую фичу, который бы она могла закрыть, ей говорили не беспокоиться об этом. Спрашивала она и о своих предыдущих проектах, её интересовало, как их протестировали и выпустили. Генри обычно отвечал что-то вроде «У меня пока не было времени, но скоро!»

Со временем Анита заметила неприятную тенденцию: примерно каждые 12 месяцев высшее руководство увольняло 20-30% от всего штата, обычно из отдела продаж или маркетинга. Компания не зарабатывала столько денег, сколько рассчитывали владельцы, поэтому они увольняли людей, ждали несколько месяцев, а потом нанимали новых. Однако чаще всего они щадили разработчиков, работающих над основным приложением. Они были достаточно умны, чтобы понять — никто из новичков не смог бы справиться с этим монстром.

Анита считала, что она в безопасности, однако спустя шесть лет её уволили. Генри пригласил её в офис, утверждал, что это не его решение, и подчеркнул, что ему очень жалко терять её.

После того, как Анита отошла от потрясения, ей в голову пришла одна мысль. «За все эти годы вы выдали мне восемь проектов».

Генри кивнул.

«Вы понимаете, что не тестировали ни один из них? Вы никогда не выпускали их в продакшен. Они по-прежнему лежат на SourceSafe, ожидая, пока их кто-нибудь использует. Вы понимаете, что компания не получила не цента за работу, которую я для вас делала?»

По выражению это лица было видно, что Генри этого никогда не осознавал.

«По крайней мере, это был хороший опыт. Спасибо за всё», — сказала Анита.

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

Комментарии (6)


  1. Jsty
    24.12.2021 11:16
    +2

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


    1. Ark_V
      24.12.2021 11:20
      +2

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


      1. K0styan
        27.12.2021 08:09

        Если бы в моём продукте вот такое произошло:

        Кроме того, было удалено 18 человеко-месяцев работы — все новые фичи, добавленные Джаредом, Ларри и Барри за последние полгода. Конечные пользователи были в гневе от того, что потеряли огромную часть функциональности.

        ..то техлид "от бога" очень быстро бы перед оным предстал. Максимально болезненным способом.


  1. svr_91
    24.12.2021 11:30

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


  1. Shiny2
    24.12.2021 18:10

    Очень интересно, продолжай пожалуйста


  1. korva
    26.12.2021 17:23

    Страшилки для программистов.

    У меня была история как у Аниты. Мы полтора года строили аналитическую систему, которая сократила отдел логистики на три человека, так как выдавала за пятнадцать минут их месячную работу. Но потом произошли трения между двумя компаниями холдинга, наш ИТ-директор ушел, а пришел такой же дебил, как в первой истории. В результате из 11 человек 9 ушли в первый же месяц, а крутющая система, аналог которой на ИИ собрал в Финляндии пару лет назад несколько десятков миллионов долларов инвестиций, заменили на 1с, которую так и не смогли заставить работать. Прошло уже 12 лет, а как вспомню, аж злость берёт.