Рассмотренная выше подсистема состоит из минимального набора слоёв трёхзвенной архитектуры на основе веб-служб. Тем не менее даже в таком минимальном варианте обилие деталей, промежуточных и служебных классов, проекций и преобразований должно дать представление о проблеме сложности современного состояния софтостроения.
Одним из способов обхода этой проблемы является описанная технология программной фабрики, несомненно далёкая от совершенства и ограниченная в наборе целевых платформ.
Какова же эффективность?
Если рассмотреть метрики относительно небольшого проекта, то 40 прикладных сущностей в модели, состоящей примерно из 600 строк XML-описаний, порождают:
• около 3 тысяч строк SQL-скриптов для каждой из целевых СУБД;
• порядка 10 тысяч строк домена;
• 1200 строк XML для проекций классов на реляционные структуры (таблицы);
• около 17 тысяч строк веб-служб и интерфейсов.
Таким образом, соотношение числа строк мета-кода описания модели к коду его реализации на конкретных архитектурах и платформах составляет около 600 к 30 тысячам или 1 к 50.
Это означает, что оснащённый средствами автоматизации программист с навыками моделирования на этапе разработки рутинного и специфичного для платформ/архитектур кода производителен примерно так же, как и его 50 коллег, не владеющих технологией генерации кода по моделям. Любое внесение изменений в модель тут же приводит в соответствие все генерируемые слои системы, что ещё более увеличивает разрыв по сравнению с ручными модификациями. Наконец, для генерируемого кода не нужны тесты. Производительность возрастает ещё как минимум вдвое.
Даже если принять во внимание, что доля рутинного и прочего инфраструктурного кода по отношению к прикладному, то есть решающему собственно задачи конечных пользователей, снижается с масштабом системы, есть о чём поразмыслить в спокойной обстановке.
Cherchez le bug, или Программирование по-французски
Этот рассказ я написал более 10 лет назад, летом 2001 года, в поездках на пригородном поезде между Парижем и Moulin-Galant, где размещался филиал IBM, и поначалу сомневался в необходимости его включения в книгу. Но, просмотрев старый текст, с некоторым удивлением я обнаружил, что если заменить аббревиатуры в названиях технологий на «новые и прогрессивные», то суть повествования останется прежней. Изменится ли что-нибудь ещё через 10 лет, покажет время.
Хаос наступает внезапно
Что такое «баг» знают, наверное, все программисты. Кто не знает, поясню: «баг» (от англ. bug – жучок) – это «жучок-вредитель» в программе, то есть ошибка, аномалия, сбой. По-французски это интернациональное словечко произносится примерно как «бёг», но буква «ё» произносится ближе к звуку «о». Особенностью французской, как, собственно, и любой другой программной индустрии – громкое слово, несколько облагораживающее нашу всемирную «багодельню», является одно из национальных состояний французской души, характеризующее этакого сангвиника после распитого с друзьями бокала вина, галантного и совсем не торопящегося жить. Разумеется, сангвиник считает, что все продукты его труда велики и прекрасны, как вид на ночной Париж с Монмартрского холма или пыльный гобелен над кроватью Наполеона в замке Фонтенбло.
Первый опыт пришёл ко мне уже через пару недель после начала работы на новом месте. Не считая себя экспертом по программированию на С++, увидев исходные тексты, я ощутил мягко говоря, некоторое беспокойство. Столкнулся я с этими текстами не сразу, так, прежде в конторе трудились двое русских программистов, один из которых по разным причинам покинул фирму, а с другим, Димой, мы работали немногим более года вплоть до её ликвидации.
Итак, некоторое время я находился в счастливом неведении относительно общего состояния дел. Прежде всего пришлось оценить качество кода. То, что единые соглашения отсутствовали, а Java-подобный стиль не очень хорош в программах на С++ не являлось большим недостатком – лучше такой стиль, чем никакой, тем более что кода на Java в системе было много. Прежние авторы, видимо, не смогли выразить себя в объектно-ориентированным подходе, а до структурного программирования и функциональной декомпозиции не опустились. Если первое не сразу бросалось в глаза наличием достаточного числа классов с пустыми конструкторами, то второе резало глаз обилием возвратов из разных мест одной функции и очень похожими кусками кода в одноимённых перегруженных функциях, написанных методом копирования текста через буфер обмена, «copy-paste». При виде некоторых фрагментов кроме чисто русских эмоциональных выражений из меня периодически вылезало французское «что за бордель», вызвавшее похвалу моего коллеги, отмечавшего, что я делаю успехи в освоении языка.
В жизни каждого мало-мальски сложного программного продукта есть стадия, когда система проходит некий порог увеличения сложности, за которым наступает состояние, которое я называю «самостоятельной жизнью». Это ещё далеко не полный хаос, но уже давно и далеко не порядок. Все попытки как-то организовать процесс разработки программ, всяческие методологии, применение парадигмы конвейера, стандарты и административные меры худо-бедно, но помогают оттянуть этот критический порог на некоторое время. В идеале – до того момента, когда развитие системы останавливается и она, побыв некоторое время в стабильном состоянии, потихоньку умирает. Одна из проблем организации промышленного производства программного обеспечения состоит в отсутствии каких-либо формальных описаний деятельности программиста. Можно определить в технологической карте, как работает сварщик или каменщик, но как пишет программу программист зачастую не знает и он сам. До художника, конечно, далеко не все дотягивают, а вот с деятельностью рядового журналиста «независимой» газеты непосвящённому в софтостроение человеку сравнивать вполне можно. Этакий ядрёный сплав ремесла, некого богемного искусства, со вкраплениями науки, вперемешку с халтурой, шабашкой и постоянным авралом. Попытки же принудить программиста делать однотипные операции противоречат самой цели существования программного обеспечения как самого гибкого из существующих средств автоматизации рутинных процессов и потому изначально обречены на неудачу.
Вернемся к нашим «жучкам». Система, с которой я начал работать, уже успешно прошла свой порог несколько месяцев назад и жила полнокровной, отдельной от авторов жизнью. Определить, что критический порог пройден, несложно, для этого у меня есть один простой признак: «Ты изменил чуть-чуть программу в одном месте, но вдруг появилась ошибка в другом, причём даже автор этого самого места не может сразу понять, в чем же дело»[128]. Существует и второй признак, не менее практичный: «Смотришь на чужой текст программы, и тебе не вполне понятен смысл одной его половины, а вторую половину тебе хочется тут же полностью переписать».
Поскольку я определил, что налицо сразу два признака, то, кроме как включиться в борьбу за продление жизни системы, уже ничего не оставалось.
При самых удачных раскладах такая борьба может длиться годами. Например, в таком богатом и «багатом» учреждении, как Microsoft, несколько лет боролись за жизнь Windows 95, выпустили даже Windows 98, но в результате все-таки сил осталось только на Windows 2000. Для неспециалистов это может быть неочевидно, поэтому поверьте мне на слово, что эти системы совершенно разные, как дельфин и русалка. Второй способ: прекратить текущую разработку программы и начать новую, используя опыт предыдущего прототипа. На это кроме обычного мужества признания ошибок и риска полететь с должности начальника требуется ещё и немало денег. Третий способ – выдать желаемое за действительное, побольше маркетинга, шуму, «подцепить» несколько заказчиков и на их деньги попытаться всё-таки перейти ко второму или первому способу. Такой трюк может сработать, если заказчику честно предлагают за какие-то вкусные для него коврижки побыть немного «подопытным кроликом», на котором система вскоре «должна заработать».
Кстати, если программист говорит вам, что в данном месте программа «должна работать», это значит, что с очень большой вероятностью она не работает, а он её просто не проверял в этом месте. Если же программист уже после обнаружения ошибки говорит: «А у меня она в этом месте работает…», лучше сразу его уволить, чтобы не мучился. Это проза жизни, также относящаяся к коллекции моих практик.
Контора пошла по третьему пути с прицелом на последующий переход к первому. Одно из самых скромных маркетинговых утверждений на рекламном проспекте гласило: «Наша система работает под Windows и под UNIX, она может взаимодействовать с любыми базами данных». Далее шёл список названий СУБД из первой десятки, в одном названии была ошибка. Реально же, уже к моменту, когда порог сложности был перейдён, имелась только версия программных модулей с постоянным номером, «текущая» под Windows NT и отстающая от нее на пару недель под Linux Mandrake, а из баз данных использовался Microsoft Access. Заказчики ходили косяками, поэтому шанс найти авантюриста увеличивался от недели к неделе. Но он всё не находился. И только благодаря тому, что у пары конкурирующих контор дела обстояли ещё хуже (это было для меня просто потрясающей новостью!), некая достаточно крупная фирма после небольшого конкурса решилась на опытное внедрение. Её примеру последовала и вторая. Тут-то и начались настоящие приключения.
Что-то с памятью моей стало
Отступив от основной темы, опишу в общих чертах структуру конторы, в которой мы работали. Основателей у фирмы двое: генеральная директриса Софи – экспрессивная француженка, незамужняя, уже в летах, и технический директор Блез – почти наш ровесник, но, по-видимому, реально взявшийся за свой первый проект. Тут ведь всё неспешно происходит, студенты учатся, а не работают, поэтому такая ситуация для специалиста к тридцати годам нормальна. Софи заведует общими вопросами и руководит подразделением маркетинга, то есть создаёт полезный фон или, наоборот, шумовые помехи в зависимости от ситуации и квалификации представителей заказчика. Блез, соответственно, должен заниматься созданием продукта. Изначально продукт делался силами нескольких человек в течение полугода, включая самого техдиректора, после чего кое-кто ушёл, сам Блез понял, что программировать он уже не успевает, а некоторые оставшиеся просто откровенно не умеют. В результате появились двое русских программистов, на которых легла вся системная разработка и поддержка последнего уровня. Из тех, кто программировать не умеет, была составлена группа прикладных программистов и некое подобие группы поддержки всего процесса в виде администрирования репозитория исходного кода, создания резервных копий и дистрибутивов. В задачу прикладного программиста должно было входить быстрое создание веб-приложения для заказчика на основе собственно продукта. Итого набралось человек 15, включая директоров и весёлый шумный маркетинг.
Центральным звеном системы является модуль с типичным названием «ядро» (kernel). Многострадальное ядро, несмотря на месяцы групповых измывательств со стороны коллектива программистов с меняющимся составом, каким-то чудом все-таки компилировалось и запускалось, хотя нам приходилось прибегать к помощи «лома и такой-то матери».
Заказчики, конечно, и не подозревали о том, что месяцев десять назад ядро состояло из кучки «ядрышек», которые просто слили в один кусок, когда на первых запусках время ожидания ответа не устроило даже самих авторов. Однако после результатов такого слияния бдительность была потеряна надолго, хотя ничто не мешало параллельно с разработкой делать хотя бы простые тесты и прогоны. В результате после первых дней работы системы в условиях опытной эксплуатации наш технический директор стал ещё более нервным, чем раньше, особенно когда Дима или я заводили разговор о том, что «вообще-то это все не будет работать» и надо не перекраивать испорченный костюмчик, а шить новый, хотя бы по старым выкройкам.
Нервность Блеза раньше выражалась в том, что он просто частенько прохаживался по нашей комнате и раз в неделю, вдохновившись беседами с потенциальными клиентами, выдавал очередную гениальную идею о развитии продукта, иногда противоречащую идее предыдущей недели, но всегда очень расплывчатую и вызывающую необходимость нам с Димой садиться и писать некое подобие спецификации. Созданная спецификация Блезом практически никогда не менялась и периодически вовсе игнорировалась, поскольку это означало необходимость отвечать за свой же «базар» в уже конкретном формальном виде, но нам она была нужна для самоконтроля и взаимодействия, к тому же ее мы выдавали ещё и как заменитель инструкции для прикладного программиста.
Усиление нервозности выражалось в хождении по комнате, причём с гораздо большей скоростью, теперь уже практически всё время в перерывах между поездками к потенциальным заказчикам и встречами с ними в офисе. К тому же теперь хождение часто сопровождалось разговорами по телефону. Блез брал аппарат в правую руку, трубку в левую и объяснял заказчику недокументированные тонкости души продукта, попутно периодически задевая шнур и роняя телефон. На самом деле я очень не люблю, когда в комнате, где люди работают большее время дня в сидячем положении и относительной тишине, начинает кто-то мельтешить перед глазами и шуметь. Думаю, многие будут со мной солидарны. Отвлекает.
После нескольких дней падений блезовского телефона выяснилось, что ядро с немереным аппетитом кушает оперативную память сервера и никак не хочет отдавать ее обратно даже после отключения всех пользователей. Утечки памяти составили около одного гигабайта (!) в сутки. Мы принялись за тесты, которые по-хорошему надо было бы начинать ещё первым авторам месяцев десять назад, и на напоминания о необходимости которых уже с нашей стороны ответов не следовало. Тесты на небольшом макете показывали примерно ту же картину, что и у заказчика, оставалось со спокойным сердцем сесть и разобраться в причинах. Однако времени, как выяснилось, уже не было. Прибежавшая в восемь часов вечера Софи застала нас с Димой уже практически в дверях и сообщила, что все плохо, надо срочно что-то делать, иначе контора может просто накрыться.
В тот день мы просидели до трех часов ночи, на следующий день ещё до часу, пришлось выйти и в воскресенье. Таким образом, три дня к отпуску я заработал, сам того не желая. Но результаты были не очень хорошими: удалось только ликвидировать утечки памяти, но остались проблемы взаимных блокировок, которые появлялись изредка и в совершенно разных ситуациях. Если вспомнить, на что похожи исходные тексты программ, то поиск таких ситуаций был на порядок сложнее поиска иголки в стоге сена.
Три дня в IBM
У второго заказчика был сервер от всемирно известной фирмы IBM, под управлением операционной системы AIX–IBM-овского варианта UNIX. Поскольку нашим маркетингом заявлялось, что система будет работать чуть ли не везде, то по русской поговорке «назвался груздем…» следовало лезть в этот самый кузов. Блез договорился с филиалом IBM о том, что в их демонстрационно-учебном зале несколько дней поработают программисты. Дима, как единственный из нас двоих знакомый с Linux, ответственный за компиляцию и сведение версии ядра под него, был настроен оптимистично и поехал собирать систему под AIX. Я остался в офисе делать сервис под Windows NT, который управлял бы запуском нашей системы в рабочем режиме.
Однако прошла неделя, а от Димы приходили только редкие послания с описаниями новых проблем. Например, компилятор C++ от IBM не переваривал некоторые конструкции, которые заявлялись как стандартные, но не оказывались таковыми на практике. Поскольку система состоит из многих собственных компонентов на C++ и Java, а также нескольких библиотек сторонних разработчиков, то проблемы нарастали как снежный ком, причём всплыла и старая, казалось бы, ликвидированная беда с утечкой памяти, появились уже стабильные признаки блокировки процесса. В итоге Блез решил отправить меня на подмогу Диме, поскольку мы периодически с ним весьма эффективно практиковали парное программирование – один из полезных методов для работы в экстремальных условиях.
Филиал IBM находился в 25 километрах к юго-востоку от Парижа, недалеко от железнодорожной станции с названием Moulin-Galant. Дорога туда не ближняя и занимала около полутора часов от дома до входа в офис, располагавшийся в помещениях завода по производству полупроводников. Я мысленно пожалел бедного коллегу, который уже вторую неделю каждый день вставал в 7 утра и приезжал домой в 10 часов вечера. От станции надо пройти пешком 15–20 минут, но, когда мы шли, то кроме ещё одного человека ни одной живой души на расстоянии нескольких километров не было, только проезжали по узкому шоссе машины. Вдоль дороги тесными рядами стояли домики и малоэтажные постройки – типичный европейский пейзаж. За все три дня ни одного человека во внутренних садиках этих домиков я так и не увидел.
Первый день мы начали с экспериментов. Сделали тестовое приложение, которое работало со сторонней библиотекой, и через пару часов убедились, что память расходуется именно в ней. Заодно, даже не помню точно, как, выяснилось, что устойчивая ошибка, приводящая к краху ядра, была обусловлена настройками памяти на уровне операционной системы. Консультант, дядька лет пятидесяти, исправил нам эти параметры и пожелал дальнейших успехов. Кстати, у них там вся команда консультантов и менеджеров состояла из мужчин предпенсионного возраста – факт отрадный, если вспомнить откровенную и циничную дискриминацию по возрасту при приёме на работу во многих российских фирмах.
Ещё несколько часов ушло на настройку альтернативного компилятора GNU С++ и – о, чудо! – получение нормального результата без всяких утечек для того же теста. К сожалению, прежний компилятор от IBM этим происшествием нас разочаровал полностью, это была капля, переполнившая чашу, ставшая причиной исключения виновника из арсенала. Но радоваться было рано. Другая используемая библиотека просто не имела официальной версии под AIX для нашего альтернативного компилятора, в наличии была только версия, сделанная «репрессированным» нами IBM-овским транслятором. Исходные тексты библиотеки также не содержали файлов инструкций (makefiles) компиляции, поэтому пришлось создавать их шаманскими способами, то есть собственными руками, подбирая опции по «образу и подобию». Наконец, успешно скомпилировав модули, мы не смогли их запустить, так как одна парочка, не выдавая никакой содержательной диагностики после запуска, тут же завершала свою работу по ошибке.
В итоге мы задержались с этим процессом до половины девятого вечера, поэтому, придя на станцию, обнаружили неприятный сюрприз: станция фактически закрылась, а поезда кончились ещё час назад. Собственно говоря, станция представляла собой домишко и две длинные платформы. Телемониторы, на которых обычно показывают четыре-пять ближайших поездов, были выключены, а домик закрыт на замок, и металлические жалюзи опущены. Поскольку мы не сразу обнаружили отсутствие поездов, то сначала купили билеты. Автомат по продаже был один, и он сильно напоминал старый аппарат по продаже топлива для «пепелацев» из культового кинофильма «Кин-дза-дза». Набрав номер станции назначения, я услышал скрип и с содроганием сунул в кривую прорезь кредитную карточку. После минутной паузы автомат издал визгливый звук – это модем пытался соединиться и отправить сведения об оплате в свой центр. Ещё секунд через 30 из самого нижнего окошечка выпал жёлтый билет, который я засунул в другую неровную прорезь для компостирования. Наконец, выждав ещё секунд 20, зловеще поскрежетав иголками принтера, автомат выплюнул отмеченный билетик все из того же нижнего окошечка. Я слегка присел перед ним, расставив руки, и сказал «Ку!».
То, что народу на станции было полтора человека, нас не насторожило, это обычное дело. Но вот погасшие мониторы были плохим признаком. Наконец, после поисков мы увидели на стенке домика болтающийся листок, оказавшийся ксерокопией расписания и поведавший нам горькую правду. Не теряя времени, мы поднялись к шоссе в надежде сесть на автобус и доехать до узловой станции, где поезда ещё ходили. Но и там нас ждало разочарование: последний из них ушёл ещё в половине восьмого вечера. Смеркалось, вокруг практически ни души. Дима решил использовать преимущества мобильной связи и вызвать такси. Однако диспетчер после долгого выяснения, где же мы все-таки находимся, сказала, что этот район не обслуживается, после чего связь прервалась. Засунув телефон обратно в карман, Дима предложил идти до узловой станции пешком: хотя карты у нас не было, но он вроде как помнит примерное направление. По нашим расчётам станция находилась в трех-четырёх километрах, поэтому мы двинули в путь.
Через сорок минут быстрой ходьбы по практически безлюдным улицам мы вышли к цели и, купив по «Сникерсу» в другом автомате, сели на отходящий в 22:08 полупустой поезд на Париж. Я попытался воспользоваться Диминым телефоном и позвонить домой, дабы предупредить жену о вынужденной задержке вследствие наших мытарств, но голос оператора сообщил, что денежки практически закончились и сделать вызов нельзя. Дима решил сразу же пополнить счёт по карте, однако и здесь нас ждало разочарование: сервер по обслуживанию платежей был «на обслуживании», или, попросту говоря, не работал. До дому я добрался к полуночи, но мы договорились, что приедем завтра на час позже, чтобы немного отдохнуть.
Назавтра, в поезде, Дима опять пытался зарядить мобильный телефон порцией денег с «Визы», но сервер все ещё не воскрес, и телефон мог только принимать периодические звонки Блеза, который внезапно обнаружил серьёзную проблему в одном из модулей сопряжения с администраторским интерфейсом. По приезде в офис нас ждал новый сюрприз: вчерашний день был по плану последним, тогда как начальство забыло предупредить IBM-овцев о том, что мы ещё поработаем немного. Поэтому мы застали все временные каталоги на нашей машине чистыми от файлов после регулярной утренней процедуры «уборки мусора за клиентами». Но это не было большой бедой, через час Блез примчался на своем мотоцикле с кассетой, и мы благополучно восстановили файлы недельной давности, а ещё за пару часов повторили с ними все вчерашние манипуляции. Но модули в новой редакции все так же не работали, как и вчера. Ну что же, опять чтение документации в Интернете, шаманство с опциями компиляции, сравнение работающего примера с неработающим модулем… Наши неутомимые поиски прервал менеджер, который попросил нас в целях соблюдения режима безопасности (интересно, а вчера что, день особый был?) закончить работу в шесть-тридцать вечера. Мы двинулись домой, что называется, несолоно хлебавши, но зато нас провели коротким путём через помещения завода. Я обратил внимание на многочисленные большие залы с IBM-овскими вычислительными машинами, представлявшими собой металлические шкафы размером с платяной. Рядом высились стойки с магнитными лентами. Я даже ощутил подобие ностальгии по безвременно разрушенным и разворованным на цветные металлы большим машинам у нас в СССР. А тут они ещё работали, и никто пока их выбрасывать не спешил.
Третий день начался ударными темпами. Удалось, буквально ткнув пальцем в небо, выяснить причину ошибки в модуле. Ею оказался настолько искусно криво написанный цикл в одной из многочисленных функций, что не сразу была видна его нехорошая тенденция при определённых условиях превращаться в бесконечный. Зная привычку авторов копировать текст, мы нашли и исправили пару таких же мест и в других функциях. Тем не менее модули все ещё не запускались в штатном режиме, но за пару часов экспериментов мы выяснили, что если некоторые библиотеки подключить статически, а не динамически, то всё в итоге будет жить нормально. Время как раз подходило к вечеру, мы оперативно отослали Блезу, который сидел у заказчика и, заговаривая ему зубы, ждал результатов, исправленный модуль и приступили к записи на диск наработанных за последние дни файлов. Провозились с этим до семи часов вечера, а дело было в пятницу, когда народ старается уйти с работы пораньше. В зал опять зашёл менеджер, осведомился о планах на вечер и, услышав, что всё сделано, обрадовался и даже предложил подвезти нас до города.
Хорошо там, где нас нет
Читатель может справедливо подумать, что пример нашей конторы не показателен. Она маленькая, да и специалистов сейчас повсеместно не хватает, они
дороги, а для небольших фирм зачастую недоступны. Однако с подобными проблемами сталкиваются практически все мои знакомые и коллеги. Если фирма с 50 % национального рынка электронных платежей вполне может работать без системы управления версиями исходного кода и дублированием таблиц в базе данных, то что же тогда говорить о стартапе…
Зато вы можете быть спокойными: без работы в ближайшие десятилетия не останетесь. Некоторые мои друзья в США жаловались на некоторую неопределённость в связи с разыгравшимся там кризисом лопнувших «дот-комов». Но вряд ли следует бояться заразиться насморком во время эпидемии чумы.