Сайт The Daily WTF уже 14 лет собирает курьёзные, дикие и/или печальные истории из мира ИТ. Я перевёл несколько рассказов, показавшихся мне интересными. Все имена и названия компаний изменены.
На работу за 3 000 миль
Правдивая история из личного опыта нашего автора Snoofle. [Оригинал]
Много десятков лет назад оборонный подрядчик DefCon Inc работал на армию США и пытался получить новый контракт на создание какого-то приложения, применяемого в бою. Компания хотела продемонстрировать в своём предложении, что у неё хватит персонала для выполнения этого проекта. Поэтому она наняла более тысячи разнообразных программистов, руководителей проектов, менеджеров и так далее. Военные, изучавшие различные коммерческие предложения, увидели кучу новых сотрудников, абсолютно незнакомых с необходимыми процессами, процедурами и требованиями, поэтому передали контракт другой фирме. Подрядчик, со своей стороны, уволил всю эту тысячу человек.
Спустя несколько месяцев возник ещё один подобный контракт. Компания снова наняла тысячу человек, чтобы показать, что у неё есть персонал. Ещё через несколько месяцев контракт снова был передан другому подрядчику, и компания снова уволила всю тысячу.
На протяжении двух лет такое повторялось несколько раз.
После всего этого основная масса доступных для найма сотрудников уже была в курсе об очень коротком цикле найма-увольнения в компании, поэтому подрядчик не мог привлечь никого, кроме новичков, только что выпустившихся из учебных заведений. Наконец, какого-то руководителя из верхнего звена озарило, что все эти люди только что из-за парты гораздо дешевле, чем опытные разработчики в штате компании, и те, кого компания нанимала-увольняла ради контрактов. Поэтому он выпустил приказ, что весь опытный персонал компании должен быть заменён дешёвыми молодыми сотрудниками. Процесс занял два года, но это всё-таки произошло.
Теперь, когда расходы на зарплаты значительно снизились, и они чертовски разозлили всех опытных разработчиков-кандидатов, компания могла увеличить постоянный штат, не раздувая бюджет на зарплаты. Ей можно было нанимать только молодых, неопытных разработчиков, чтобы наконец-то получить контракт.
К сожалению, у всех этих молодых разработчиков было очень мало опыта, а в фирме больше не осталось побывавших в окопах людей, способных их обучить. Поэтому результатом их двухлетнего контракта стал этого ненадёжный проект, который часто вылетал, вёл себя непредсказуемо и который невозможно было модифицировать. Подобные свойства нежелательны, когда имеешь дело с системой, которая должна стрелять и взрывать.
В какой-то момент один из высших руководителей осознал, что произошло, заставил компанию прекратить вести себя, как слон в посудной лавке, и нанять высокооплачиваемых консультантов. К сожалению, высокооплачиваемые консультанты хорошо помнили о цикле найма-увольнений и не хотели иметь ничего общего с организацией. Спустя какое-то время компании пришлось существенно улучшать условия найма, пока наконец несколько опытных работников согласилось устроиться на работу в качестве штатных сотрудников. Это произошло в Нью-Джерси.
После того, как руководство назначало этих новых сотрудников на проект для ускорения работы над ним, новые сотрудники сказали «Постойте-ка, посередине этого проекта есть огромная дыра!» Руководство ответило, что эта часть проекта засекречена, и может изучаться только людьми с допуском к секретной информации и только на предприятии в Калифорнии. Были запрошены и получены соответствующие допуски, после чего опытных сотрудников отправили на две недели на предприятие в Калифорнии.
Прежде чем соглашаться на поездку, разработчики хотели узнать, как они смогут получать доступ к материалам после изучения. Ведь доступ возможен только на месте, в Калифорнии, а все сотрудники живут и работают в Нью-Джерси. Им сказали, что о подробностях они узнают в Калифорнии.
Ну ладно, все они прилетели на восточное побережье, заселились в отели и поехали в офис.
В тот момент им сообщили обо всех проблемах, которые необходимо устранить. В четверг второй недели работы было решено, что для выполнения всех необходимых модернизаций необходимо примерно два года работы. Разработчики опять спросили: «Как же мы будем получать доступ к материалам из Нью-Джерси?» Менеджеры ответили, что вся работа должна выполняться на месте, и они будут оставаться в Калифорнии в течении следующих двух лет. Начиная с ближайшего понедельника.
Но, постойте у них же не было возможности обсудить это с семьёй! Как отсутствие 90% времени одного из родителей повлияет на детей? Захотят ли они жить в гостиницах и аэропортах в течение двух лет? Какого хрена компания не наняла сотрудников на месте, в Калифорнии, а занималась этим в Нью-Джерси?
Оказалось, что поскольку подрядчик находится в Нью-Джерси, нанимаемый им персонал тоже должен быть зарегистрирован там же. Разумеется, если бы об этом сообщили до трудоустройства, то большинство сотрудников (если не все из них) отказалось бы от работы. Если бы они знали, то никто из работников не поднялся бы на борт самолёта и не полетел бы в Калифорнию для ознакомления с проектом.
Можно и не говорить, что остаток рабочего для менеджеры втирали о необходимости жертв ради компании, а разработчики задавались вопросом: «Какого чёрта?» Вечер четверга был занят бесконечными звонками домой. Утром пятницы все сотрудники уволились и направились в аэропорт, чтобы вернуться домой.
Представители армии повели себя достойно и с пониманием отнеслись к тому, что люди не хотят бросать свои дома и семьи на два года. Однако стали гораздо жёстче, когда дело дошло до разговора с подрядчиком и до выполнении его обещаний о наличии опытного персонала на месте работы.
В результате контракт с подрядчиком был расторгнут, а на его место наняли для наведения порядка нового.
Случай отказа
В первый день на новой работе Себастьян не был особо воодушевлён. Он уже многое повидал и набрался равнодушия и пессимизма. Эта новая работа не должна была отличаться ни одной другой: куча надоедливых коллег, плохо продуманных требований, старых кодовых баз, полных спагетти-кода. Но она хорошо оплачивалась, а он устал от своей старой группы, ему надоели одни и те же привычные лица. Поэтому он внутренне приготовился к слегка новым оттенкам той же офисной политики и муторных заданий.
Он даже особо не расстроился, зайдя в ИТ-отдел за своими учётными данными и услышав жужжание и щёлканье старых серверов Packard Bell. Себастьян просто опустил на несколько уровней свою планку требований к рабочему компьютеру, и вернулся в новый офис. Да, его должность подразумевала собственный офис и соответствующую оплату. Ради этого он мог смириться со многим другим.
Его логин сработал с первой попытки, что было приятной неожиданностьюю. Он ожидал Windows XP; когда загрузилась Vista, он не был уверен, стоит ли ему радоваться более новой ОС, или ужасаться тому, что это Vista. Завершив получение полномочий администратора и урезав UAC, он даже на какое-то время мог притвориться, что это «семёрка». «Чтобы испугать меня, потребуется что-то большее», — подумал он и запустил Outlook.
Во входящих уже была почта: несколько приветственных писем с информацией для новых сотрудников, а также первая задача от его менеджера. Впечатлённый, если не сказать больше, эффективностью назначения задач, он открыл письмо от своего нового руководителя.
Первое письмо было примерно таким:
Здравствуйте, Себастьян, добро пожаловать в нашу идеально отточенную рабочую среду. В ней всё делается правильно. При создании проектных документов вы будете работать с Bonk-Word (веб-приложение для документирования компании IBM). Не забывайте часто сохранять работу! При аварийном завершении Bonk-Word вам необходимо будет написать письмо в отдел ИТ для его перезапуска.
Компания составляет проектную документацию. Пишите всё в страдательном залоге, используйте фиолетовый для обозначения заголовком глав и зелёный — для заголовков разделов. Документы ежедневно проверяются президентом компании в 9 утра, так что будьте к этому готовы. Ошибки в заголовках станут «чёрной меткой» в вашем личном деле.
Начните с проектирования решения проблемы со шрифтами на Macintosh, которую мы не можем решить четыре года. Завтра к 9 часам утра у вас должен быть готовый проектный документ. Спасибо.
«Шесть страница на завтра?», — забеспокоился Себастьян. «Наверно, я возрадовался эффективности слишком рано. Ну, по крайней мере, не будет скучно», — он хрустнул костяшками пальцев, открыл Bonk-Word и начал разбираться с так называемыми проблемами со шрифтами.
Первое, что он выяснил — менеджер не шутил о частом сохранении. К концу дня он мысленно делал ставки: что свалится первым — Bonk-Word или сама Vista. Оба они крашились примерно через каждые полчаса. Но ведение статистики вылетов на листочке почему-то успокаивало Себастьяна. Оно напоминало ему: в мире что-то ещё работает. Простейшие математические действия не впечатляли, но были надёжными. Регулярными. Стабильными.
Возможно, в этом офисе Себастьян чувствовал себя одиноко. Но он был тихим и отдельным. Пусть постоянные вылеты раздражали, но Себастьян всё-таки двигался вперёд. Он задержался на работе, чтобы изучить разнообразную литературу, посвящённую рендерингу шрифтов, в том числе спецификацию Postscript, сопроводительную литературу с рекомендациями по его использованию и информационные центры в World Wide Web, созданные для коллекционирования мудрости лучших умов отрасли в знакомом и удобном формате вопросов и ответов. Он пространно описал в документе «создание программы на Python для рендеринга каждого символа». Он потратил две страницы на описание того, что можно было рассказать в двух словах.
«Если им нужно шесть страниц, они получат шесть страниц», — думал Себастьян.
Первый день оказался странным, но Себастьян видел, что вполне выдержит это в течение как минимум нескольких лет. Он закончил работу, вышел из здания (которое подозрительно пахло старым кожаным нижним бельём) и медленно подошёл к своему «бесплатному месту на парковке» (ещё одно преимущество, оправдывающее эту работу в его глазах). Медленно — потому что стоянка была совершенно разъедена ржавчиной, и во многих местах бетон полностью отвалился, обнажив арматуру пола и колонн.
Следующим утром, ровно в 9:00, Себастьян находился в офисе своего менеджера, ожидая первой проверки проекта от президента компании, позвонившего по телефону. Себастьян чувствовал себя некомфортно от разговора с президентом напрямую, учитывая то, что в к компании было шестьдесят сотрудников, но ему пришлось это вытерпеть.
«Я сделал, как просили, и в нужном объёме. Скорее всего, это просто формальность, после которой я смогу приступить к работе».
Спустя час униженный и измотанный Себастьян вернулся в свой офис. В его ушах всё ещё звенела полученная им абсурдная, но жестокая критика. По словам президента, его заголовки разделов были едва «зеленоватыми», а не зелёными, как требовала компания, а заголовки глав — непростительно «красноватыми» вместо ожидаемо фиолетовых. Кроме того, ему недвусмысленно сообщили, что отладить шрифты с помощью Python «невозможно». Вместо него Себастьяну приказали работать на C++ и использовать «чудесные» программные библиотеки компании. Ожидая звонка президента, менеджер Себастьяна расхваливал документ, но во время проверки не сказал ни слова, неотрывно смотря на кирпичную стену за своим столом.
Себастьян закрыл дверь офиса, отгородившись от остальной части компании. Он сел на свой роскошный кожаный стул и уставился на экран едва работавшего компьютера. Он снова открыл свой документ, а потом перезапустил машину, потому что Vista решила вылететь. Когда компьютер снова загрузился, он проверил свой банковский счёт, подумал о платежах по ипотеке, и сжал зубы.
«Ну ладно», — сказал он вслух в пустом офисе. «Взглянем на эти библиотеки».
Первое, что он начал искать — это документация. Естественно, что в такой помешанной на документах компании документация к «чудесным» библиотекам должна быть точно набрана правильным шрифтом с идеально точным оттенком, с правильными заголовками глав и названиями разделов. Но документации… не было. Была уйма проектных документов с идеальным зелёным и фиолетовым цветами. Но в них описывалась только методология разработки библиотеки и ничего не говорилось об её использовании.
«Я что, схожу с ума?», — спросил себя Себастьян, когда машина перезагрузилась в третий раз. «Возможно, код самодокументированный...»
Он испытал ужас, но особого удивления не было: библиотеки состояли из плохо продуманных обёрток строковых функций из стандартной библиотеки.
Несмотря на постоянные фиаско, Себастьян держал удар. Его ежедневно вызывали для очередного раунда словесных запугиваний. Компания за четыре года не могла справиться с этой шрифтовой проблемой; тем не менее, ничто из предлагаемого им не устраивало президента. Себастьян отказался от собственной библиотеки компании, начав решать проблему на известном ему Python; в конце концов, если его всё равно будут гнобить, то зачем делать то, что тебе говорят? Но что бы он ни применял: собственный тестер на Python, или тестер Microsoft, или Apple, или Adobe — шрифт оставался полным хаосом. 488 неискоренимых, неисправимых, не решаемых заплатками конструктивных ошибок.
Президент категорически отказывался признать правду. Он утверждал, что это вина Себастьяна, ведь тот не использует великолепные библиотеки C++.
Исчерпав все варианты, Себастьян оставил ключ от ржавеющего гаража на столе менеджера вместе с заявлением об уходе. Он попрощался со своим милым офисом и адской машинкой, которую выдавали за компьютер. Глубоко вдохнул, в последний раз почувствовав муторный запах кожи и вышел, окончательно и бесповоротно.
Почему-то он сомневался, что будет скучать по компании.
От такого здравоохранения можно заболеть
В любой отрасли есть информация, которую необходимо переносить между несовместимыми системами. Если вы жили жизнью праведника, то эти системы были просто разными приложениями на одной платформе. Однако если вы отклонились от благого пути, то эти системы были написаны на разных языках для разных платформ, работающих в разных операционных системах с разным порядком следования байтов. Представьте какое-нибудь Java-приложение в Safari под какой-нибудь версией Mac OS, которому нужно обмениваться данными с какой-то версией .NET под какой-нибудь версией Windows, которой, в свою очередь, нужно общаться с какой-то версией COBOL с двоичным кодом EBCIDIC, работающей на каком-нибудь мейнфрейме.
Задолго до того, как кто-нибудь мог вообразить подобный кошмар, мы работали с SGML, который деградировал эволюционировал в XML, который должен быть тривиальным приемлемым способом задания содержащихся в документе формата и полей с доступным на всех платформах парсером, благодаря чему информацией можно обмениваться, не зная ничего, кроме DTD и/или схемы для валидации и парсинга.
Не надеясь на лучшее, для упрощения работы мы написали поверх XML библиотеки обёрток.
К сожалению, они с задачей не справились.
В отрасли здравоохранения какие-то работающие с сopen-source ребята создали проект (H)ealthcare (API), или HAPI, который по сути является объектно-ориентированным парсером текстовых сообщений отрасли здравоохранения. К сожалению, они, похоже, страдали от синдрома «не знаю, когда остановиться».
Вместо того, чтобы реализовать обобщённый парсер, который просто разбивает строку с разделителями или строку фиксированного формата на список из значений текстовых полей, последняя версия реализует 1205 разных парсеров, каждый из которых имеет собственную высокоуровневую структуру данных. Самые высокоуровневые структуры имеют десятки подструктур. Каждый парсер имеет один или несколько методов доступа к каждому полю. Поле может быть единственным экземпляром или списком экземпляров, и в этом случае необходимо программно определять, какой метод доступа использовать.
Это API с приблизительно 15 тысячами вызовов методов! О чём вообще думали эти разработчики?
Например, класс: EHC_E15_PAYMENT_REMITTANCE_DETAIL_INFO может иметь от нуля и более product service разделов. Поэтому я сразу же начинаю думать о каком-нибудь массиве или списке. Поэтому вместо чего-то наподобие такого:
EHC_E15_PAYMENT_REMITTANCE_DETAIL_INFO info = ...; List<EHC_E15_PRODUCT_SERVICE_SECTION> prodServices = info.getProductServices(); // итерируем
… нам требуется выполнить что-то из этого:
// Получаем подструктуру EHC_E15_PAYMENT_REMITTANCE_DETAIL_INFO info = ...; // Получаем из подструктуры встроенные product-service // ...если мы точно знаем, что в сообщение он только один: EHC_E15_PRODUCT_SERVICE_SECTION prodSvc = info.getPRODUCT_SERVICE_SECTION(); // ...если мы не знаем, сколько их будет: int n = infos.getPRODUCT_SERVICE_SECTIONReps(); for (int i=0; i<n; i++) { EHC_E15_PRODUCT_SERVICE_SECTION prodSvc = info.getPRODUCT_SERVICE_SECTION(i); // используем это } // ...или можно просто взять их и выполнить итерацию List<EHC_E15_PRODUCT_SERVICE_SECTION> allSvcs = info.getPRODUCT_SERVICE_SECTIONAll();
… и нужно вызвать нужный метод, иначе рискуешь получить исключение. Но если существует множество способов выполнения одной задачи через API, то возникает множество способов её выполнения в коде с помощью API, что неизбежно приводит к проблемам.
Можно сказать: «Да ладно, всё не ТАК уж плохо»; достаточно использовать то, что тебе нужно. Но потом ты осознаёшь, что некоторые из этих структур данных встроены на десять и более уровней вглубь, у каждой есть десятки подструктур и/или полей, и у всех них несколько методов доступа. Да ещё у всех них реально длинные названия. А потом ты осознаёшь, что разработчики HAPI устали печатать текст и начали использовать для всего сокращения с такими понятными названиями структур данных, как LA1, ILT и PCR.
API пытается быть полезным: если он не находит в поле, парсинг которого ты запрашиваешь, ожидаемого, то он выбрасывает исключение, и тебе нужно самостоятельно разбираться, что пошло не так. Разумеется, при этом подразумевается, что ты уже знаешь, что тебе передаётся в потоке данных.
Аноним работал в здравоохранении и занимался поддержкой библиотеки, обёрнутой вокруг HAPI. Ему регулярно давали задания (на выполнение которых отводилось по несколько недель) по простому парсингу одного дополнительного поля. Потратив кучу времени на пережёвывание томов документации по API, он написал общий парсер из одного класса в 300 строк с несколькими split, substring, parseDate и parseInt, в качестве замены всего интерфейса.
После этого добавление нового поля стало занимать не больше десяти минут.
Автор: PatientZero