четверг, 28 мая 2009 г.

Капля ненависти

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

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

Задача осложнялась также тем, что сайт необходимо было интегрировать в общую систему публикации документов - для оффлайнового приложения и пары сайтов. Эта система публикации крутится в интранете компании. Редактор является простой надстройкой над MS Word'ом. Тут начальник отдела опять "посоветовался" со своим другом, который однозначно решил, что нужно перегонять новости ИЗ системы обновления НА сайт, а не С сайта В систему.

После всех этих советов и "додумок" проект упал на меня с аннотацией "надо, чтобы было надёжно, удобно, красиво и ещё вчера". Пока дизайнер рисовал макеты я переделывал привязку новостей к категориям, т.к. изначальная была абсолютно негодна к использованию на уважающем себя сайте. Вместо перечисления категорий в одном поле типа varchar я создал табличку для привязки новостей к категориям. Получилось простое отношение many-to-many. Хочется отметить, что уже на этом этапе мне стало грустно от кода ДЛЕ. Создалось чёткое ощущение, что писал его в лучшем случае студент-второкурсник, а то и вовсе старшеклассник. Ну надо же как-то оформлять код, не говоря уже об элементарных оптимизациях.

Наконец, от дизайнера пришли макеты, которые я красиво и вполне семантично сверстал. Когда я начал натягивать их на движок, я упёрся в ущербность встроенного шаблонизатора. Он ОЧЕНЬ многого не умеет. Ни циклов, ни условий. Да, к тому же, нагло вмешивается в DOM шаблонов, чего я ему до сих пор не могу простить. Кроме того, достаточно ощутимая часть дизайна прописана в контроллерах!!! Ну, в итоге, проматерившись пару дней, дизайн я на движок натянул.

Пришло время интегрировать сайт в систему публикации. Тут меня ждал очередной сюрприз. Я, разумеется, не стал слушать автора "доработок" (по совместительству друга шефа) и не стал убирать auto_increment с поля id таблицы новостей. Вместо этого я создал таблицу соответствия внутреннего id внешнему (внешний id - это id новости в общей системе публикации документов). Точно так же я поступил с категориями. За неделю я написал и отладил интерфейс, через который внешний софт мог публиковать новости на моём сайте, всё было красиво. До тех пор, пока программист, ответственный за систему публикации документов не отправил на сайт все новости с 2005 года по сей день.

Нет, сайт не упал. Он продолжил работать в штатном режиме (хвала небесам, даже не смотря на тестовый режим). Стала рубиться админка. Она просто засыпала на 30 секунд (дефолтное время исполнения РНР-скриптов), после чего вылетала с ошибкой. Причём, происходило это исключительно на странице со списком категорий. Тут я стал ковырять таблицу категорий, справедливо рассудив, что дело именно в ней. Очередной "приятный" сюрприз от разработчиков ДЛЕ - это отсутствие каких-либо индексов в таблице категорий, кроме первичного. Это при том, что дерево категорий формируется рекурсивным списком! Это при том, что выбираются они по полю alt_name, которое содержит название категории в транслите (для ЧПУ)! Это при том, что в таблице есть специальное поле, отвечающее за очерёдность категорий, по которому производится сортировка! И - один первичный ключ?! Поубивал бы... Нет, разработчики, вероятно, не рассчитывали, что их продукт будет использоваться на сайте с достаточно большим деревом категорий (около 60 тысяч категорий - это всё-таки серьёзно). Хотя на официальном сайте в характеристиках системы написано "неограниченное количество категорий".

Но это не самое страшное, в конце-концов, я добавил соответствующие индексы достаточно быстро. Самое интересное то, что после этой операции ничего не изменилось. НИ-ЧЕ-ГО! И я опять полез в код. Пять минут - и вот он кусочек кода, отвечающий за формирование массива категорий. Функция set_vars - кеширование переменной, get_vars - соответственно, чтение кеша. Ха! Ребята-разработчики, видимо, изрядно покумекали перед написанием файлового кеша! Пять строчек кода, а сколько поэзии, какая рифма! Сериализованная переменная кладётся в файл, файл чмодится, а с другой стороны - читается и десериализуется. А у меня массив из 60 тысяч элементов. Да ещё и многомерный. И вот - ОН - встречайте - кеш-файл с 2 мегабайтами сериализованных данных! Вот он, наш герой, заставивший 4-процессорный сервер с 16 гигабайтами оперативки пристыженно лечь и закрыть нос лапами, как проштрафившийся щенок!

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

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

1 комментарий:

Unknown комментирует...

Не memcached, а APC нужно ставить, ну или XCache, если у вас лайти :)