HackIT-2017 - Форум по кибербезопасности - 5 тренингов, 20+ докладов и воркшопов, разбор громких кибератак и методов защит. 23 сентября, Харьков
×Закрыть

Fail review: о проблемах в разработке и методах их решения

[«Fail review» — это сборник историй о рабочих провалах: что произошло, как исправляли и какие выводы сделали. Если есть, чем поделиться — приглашаем присылать свои истории на valentina@dou.ua]

Игорь Зенич, Frontend Developer в EPAM

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

На тот момент я буквально месяц как пришел работать в компанию, которая занималась этим проектом. Кое-какой опыт работы с видео у меня был, и мне поручили задание — перекодировать видео из DVD в другие форматы. Задача была срочной, и в спешке я сделал ошибку в скрипте, в результате которой на видео исказились пропорции сторон. Лекторы стали выглядеть толще килограмм на 15 :)

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

Я задумался, как мне быть. Расскажу о баге — придется выслушивать от шефа, что опозорил компанию перед клиентом. Тем более, я сам еще на испытательном сроке. И не сказать — тоже не вариант, потому что рано или поздно все равно обнаружат, и будет еще хуже. Решил, что всё-таки надо признаваться. Подошел к шефу, говорю, так и так, такая вот штука. А он в ответ: «А, и фиг с ней, не парься. Исправим, найдем способ». У меня сразу гора с плеч.

Исправляли долго: часть видео перезаливали заново, для части писали костыли. Сидели ночами, но сделали.

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

Андрей Губский, CTO Торф

История № 1: Не работайте с клиентами, которые не осознают своих желаний

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

Слово «стартап» сейчас очень модное. И среди ваших друзей и знакомых точно есть кто-то, кто уже пробовал запустить свой проект или даже предлагал вам стать ко-фаундером. Такая же история произошла и с моим товарищем. Пришёл к нему потенциальный клиент и попросил разработать, ну, скажем, клон Facebook. Идея вроде неплохая. Выход на IPO спланирован, список, куда потратить миллиардные доходы, уже написан. Осталось дело за малым — заказать софт, который и позволит в считанные дни заработать эти самые миллиарды. Инвестиции в новый стартап клиент тоже подготовил — гигантскую сумму в 5000 евро. Ударили по рукам, закипела работа.

Вот только убийцу Facebook сделать не удалось ни через планируемые 3 месяца, ни через полгода. А когда для ускорения процесса разработки была привлечена дополнительная команда, и клиенту был выставлен счёт за проделанные работы — выдержке его пришёл конец. Мало того, что ожидаемые миллиарды не появились, Forbes не стал брать интервью, так ещё и затраты оказались в несколько раз выше, чем планировались. И если для тех, кто знаком cо спецификой рынка ИТ, данная история — одна из тысячи подобных, и каждый, кто довольно давно работает в этом бизнесе, понимает, что на один выстреливший продукт может приходится до сотни неудачных, то для нового человека это может быть шоком. Ведь именно он автор гениальной идеи, и именно он заработает завтра свой первый миллиард.

Выводов из этой истории два:

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

Вывод второй — не работайте с людьми, которые не осознают своих желаний. Мало прийти в компанию по разработке ПО и сказать: «Я хочу второй Facebook». Клиент должен понимать законы индустрии, в которую он входит, осознавать, что и для чего ему нужно.

История № 2: Не гонитесь за большим количеством фич

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

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

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

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

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

Денис Резник, Data Architect в Intapp

Когда-то давно мне посчастливилось работать на одном интересном проекте. Проект представлял из себя доску объявлений, которая в то время входила в топ-10 по США и имела неплохой трафик. Вы удивитесь, сколько интересного было под капотом, казалось бы, обычного проекта, но история не об этом. История об IpBanner — одной из подсистем проекта, назначением которой была борьба со спамерами.

Внешне IpBanner представлял из себя веб-страничку, на которую мог зайти владелец или админ проекта и внести айпишник, с которого идет спам (под спамом понимаем постановку одного и того же объявления в разные категории, постановку его много раз, объявления нехорошего содержания и т.п.). Внутри это была просто табличка в базе данных. При попытке поставить объявление на сайте айпишник проверялся по табличке IpBanner, и если айпишник был забанен, человека перекидывало на страницу /potsnewad вместо /postnewad. Дизайн у /potsnewad был точно таким, как и у страницы постановки объявления — за исключением того, что вместо функционала создания объявления там был опросник, сделанный в виде wizzard-а, когда следующий новый вопрос появляется после ответа на предыдущий.

Вопросы были из разряда : «Как вас зовут?», «Где вы живете?», «Есть ли у вас машина?» и т.п., и так около 10 вопросов. В конце опросника показывалось сообщение, что хватит нас спамить, мы собрали о вас информацию и передали ее в ФБР, теперь вас разыскивают :) Не знаю, кто и когда это придумал и сделал, но я всегда находил эту фичу очень забавной. Ровно до того момента, когда как-то вечером в пятницу мы не выкатили код, который стал кидать всех пользователей из Индии (или вообще всех пользователей, уже не помню) на страницу /potsnewad :)

Было много звонков в службу поддержки, один человек (судя по слухам) даже позвонил в ФБР и спросил, почему его разыскивают. В понедельник утром владелец сайта попросил полностью выпилить из проекта IpBanner, что мы и сделали.

Мораль истории: не держите на сайте опасный функционал. Если он уже есть — избавьтесь от него, по возможности, быстро. Не искушайте судьбу.

Сергей Сыроватченко, SQL Server DBA

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

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

Первый показательный случай произошел еще на первом году моей работы. У нас был DEV сервер с SQL Server, в котором вся дисковая подсистема была завязана на одном RAID 0 (про то, что на серверную стойку капал конденсат, я умолчу). Резервные копии делались админом регулярно и складывались на удаленном сетевом диске. В один прекрасный момент одно из заданий стало завершаться с ошибкой, в котором делалось обращение к dm_db_index_physical_stats. Сделав выборку из этого DMV, я увидел, что один из некластерных индексов был поврежден.

В тот же день сообщил об этом админу, на что тот отмахнулся со словами: «Все диски чекаются регулярно и проблем с его стороны нет». Нет так нет. Письмом уведомил руководство, что нужно менять диски на сервере. Увы, сказали, что это не в приоритете. После по-быстрому исправил проблему со своей стороны — сделал REBUILD индекса и выполнил CHECKDB для базы.

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

Последствия этой истории таковы: 4 часа down-time, за которые мы всей фирмой хорошо поиграли в теннис. За это время вспомнили про мое письмо с просьбой о новых дисках, и ко мне стали чуть больше прислушиваться. А еще через неделю у нас появился новый DEV сервер. Happy end...

Вторая история чуть веселее. Во всяком случае, мне это кажется забавным до сих пор. С коллегой мы сканировали зарубежные интернет-магазины. На очередном митинге клиент попросил делать на его iPhone почтовую рассылку и показывать основные ценовые тренды. Чтобы не нагружать коллегу, решил все быстро — генерировал HTML с помощью FOR XML PATH и отправлял письма через DatabaseMail.

Через пару недель клиент попросил к письму прикреплять файлы с Excel. В это время коллеге еще докинули работы, поэтому решил опять отделаться малой кровью — с помощью bcp генерировал Excel файлы и с помощью опять того же DatabaseMail доставлял нотификации клиенту. Потом был еще один интересный случай — клиент попросил, чтобы ячейки в Excel файлах были разукрашены в разные цвета. Вот так невинно был развернут SSRS, и через него начала делаться почтовая рассылка. Я думал, что на этом все... Но нет.

Хардкор на T-SQL начался после очередного реквеста: «А можно мне в письме еще и графики показывать?». Печаль в том, что не все почтовые клиенты (особенно мобильные) поддерживают JavaScript, поэтому пришлось использовать ImageChartsAPI от Google и генерировать особую ссылку, которая возвращала бы при открытии письма картинку с графиком.

Все всех устраивало, но потом данных для визуализации стало больше, и клиент попросил увеличить размер графиков. Размер возвращаемой картинки в ImageChartsAPI имеет строгое ограничение (сейчас точно не вспомню, сколько) и пришлось выкручиваться. На этот раз решили потратить больше времени на эту задачу и написали свой сервис, который подключался в качестве CLR библиотеки к SQL Server. Я передавал в виде XML, какой график мне нужно сгенерировать, и на выходе получал картинку в base64, которую затем вставлял в тело письма. Вот такой вариант почтовой рассылки работает до сих пор.

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

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

Можно было радоваться, но в плане поддержки этого кода программисты плавали и попросили все хранимые процедуры сделать более универсальными — вынести похожий код в функции. Есть хорошая фраза по этому поводу: «Универсальный код работает универсально плохо». Да... Сократили количество строк в отчётах и выиграли в сопровождении кода на T-SQL, но серьезно проиграли в скорости.

Все потому, что программисты часто проецируют свой опыт из ООП на работу с базами данных. Если говоришь, что скалярные функции — это зло, то зачем упираться? Бездумно использовать INSERT EXEC, если тебе уже сказали, что результаты выборки могут вначале временно материализоваться в tempdb, а уже только потом вставляются в целевую таблицу. Parameter sniffing и постоянная рекомпиляция плана — «Не, не слышал». Чего говорить про использование курсоров с поводом и без... Как мне сказал один коллега: «Мне просто так понятнее, чем WHILE и пакетная обработка».

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

Никита Галкин, System Architect в Ezetech

В СССР последний пункт в любой инструкции по сборке:
«Обработать напильником»

Обычная ситуация: в последний момент от заказчика прилетели новые требования. На первый взгляд простое требование изменить на фронтенде формат отображения дат в графиках с 26.01.2017 на 26 Jan. Проблема в том, что формат даты захардкоджен внутри библиотеки, которая имеет третий уровень вложенности. Инженеры спорят, как и с какой библиотекой переписывать. Уже рассматривается вариант отключить CI и залить костыль руками. PM пьет валерьянку и не знает, как объяснять клиенту, что тут сложного. В общем, атмосфера гнетущая.

Обычно в историях в комнату заходит консультант/менеджер/девушка/коллега-из-соседнего-отдела и дает совет. К нам пришел «Пофиг». Так появилось решение — после установки зависимостей в postinstall скрипте поправить код требуемой библиотеки. Так сказать, «обработать напильником».

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


Если есть желание рассказать свою историю — приглашаем присылать текст на valentina@dou.ua

7 комментариев

Подписаться на комментарииОтписаться от комментариев Комментарии могут оставлять только пользователи с подтвержденными аккаунтами.

Хорошая подборка. Спасибо.
Интересно было почитать.

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

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

Так может не стоит в своем функционале полагаться на зависимость зависимости зависимости?)

Так может не стоит в своем функционале полагаться на зависимость зависимости зависимости?)
Я не вижу, чтобы кто-то полагался на зависимость зависимость.
Формат даты не передается параметром. Сразу писать свой виджет? Нафиг сторонние либы, мы лучше набросаем?

Про второй уровень зависимости важно потому, что если б сам компонент «не предусматривал» — то сделать пулл-реквест, обоносвать и обновить зависимость — еще реально.
А вот, если надо в несколько проектов пулл-реквесты пихать, то да, проще на лету что-то у себя менять.

Впрочем, можно и все зависимости форкать, но замахаешься этим потом рулить.

3-я история от DBA самая близкая к моей теме — высокая производительность.

Для себя знаю один вывод:
Красивый код часто не работает быстро, а некрасивый — зачастую да.

Подписаться на комментарии