Особенности разработки интернет приложений масштаба предприятия.

Николай Приезжий, Алексей Закис, Ирина Борисова, Михаил Лужецкий (Компания HRS)

Введение.

Идея аренды программного обеспечения, или предоставления информационных услуг (Application Service Providing, ASP) появилась и была реализована, по крайней мере, в 70-х годах прошлого века.

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

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

Почему интернет, почему ASP?

Появление и победное шествие интернета в последнем десятилетии прошлого века взбудоражило разработчиков информационных систем, уже успевших оценить все проблемы сопровождения клиент-серверных приложений. Идея "тонкого" клиента на основе броузера (прежде всего, для интранета) казалась привлекательной и легко реализуемой. Однако реальность оказалась не столь радужной.

Во-первых, особой экономии на клиентских машинах не получилось - оказалось, что броузер (интерпретатор HTML) требует значительно больших ресурсов, чем откомпилированный "толстый" клиент, и отказывается работать на "все еще находящихся на балансе" компьютерах.

Во-вторых, избавив системных администраторов от трудоемкой (но весьма примитивной и не такой уж частой) процедуры обновления "толстого" клиента на десятках (или даже сотнях) пользовательских машин, "тонкий" клиент перенес нагрузку на серверную часть приложения (и добавил генерацию HTML). А это существенно увеличило требования к серверам, установленному на них системному программному обеспечению (ОС, СУБД, Web-сервера, сервера приложений и т.д.) и, соответственно, квалификации системных администраторов.

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

Назад? Уже поздно. Поздно потому, система управления предприятием без интернет-интерфейса (хотя бы урезанного до потребностей руководителей) уже не может удовлетворить пользователя. Значит, вперед - к арендуемому интернет приложению.

Рынок таких приложений стремительно растет. Достаточно сказать, что основанный 25 компаниями в 1999 году ASP Industry Consortium в 2001 году уже насчитывал более 700 членов из 30 стран с пяти континентов. Но в России компания HRS оказалась одним из пионеров, поэтому мы и хотим рассказать о нашем опыте разработки арендуемых интернет приложений масштаба предприятия для использования в модели ASP на примере созданных компанией HRS систем для гостиничного бизнеса (Nimeta - www.nimeta.net и Phone Mate - www.phonemate.hrs.ru ).

Системы управления собственностью.

Вероятно, последняя фраза вызовет недоумение у многих слушателей, поскольку системы управления собственностью (Property Management Systems, PMS) достаточно скудно освещены в литературе, а стоящий у портье компьютер производит (на просвещенного посетителя гостиницы) впечатление терминала простенькой учетной системы. На самом деле это не так. Современная PMS крупного отеля (а тем более, цепи гостиниц) отнюдь не ограничивается регистрацией бизнес операций (весьма многочисленных и не сводящихся к поселению/выписке гостя и приему оплаты), но позволяет решать задачи:

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

Принципиальные моменты разработки

Выбор платформы.

Основными критериями выбора серверной платформы для ASP приложений являются

В соответствии с этими критериями были выбраны

Вероятно, здесь стоит комментировать только соответствие третьему критерию. Естественно, он выполняется только при значительном числе клиентов, которые могут пользоваться услугами одного хостинг-центра. Причем для провайдера услуг для предприятий с неравномерной по времени суток активностью весьма выгодной является балансировка нагрузки за счет разницы местного времени клиентов. Конечно, это накладывает определенные ограничения на выбор хостинг-центра и интернет провайдера. Наши системы размещены в московском хостинг-центре компании Cable&Wireless. Клиентскую платформу выбирать очень не хотелось ("любой броузер на любой платформе" - очень привлекательный лозунг, HTML ведь стандартный!). Но пришлось признать, что броузера, обеспечивающего лишь отображение "классического" HTML, "заточенного" на решения задач поиска и отображения информации, явно недостаточно для реализации полноценного пользовательского интерфейса ввода информации. Поведение стандартной HTML формы, передающей всю введенную пользователем на сервер для обработки и возвращающей сообщение "дата отъезда гостя не может быть меньше даты приезда" совершенно неприемлемо для производственной системы. К тому же, оно невыгодно и клиенту (очень большой трафик), и провайдеру, для которого идея "тонкого" клиента (свободного от бизнес логики) не слишком привлекает. Он обещал арендатору приложения, что тому не придется администрировать систему, и все. В остальном он свободен, и ему невыгодно строить "интернет-мейнфрейм" с терминалом на базе процессора Pentium. Используя DHTML, Java Script и XML, можно не только построить удобный и функциональный пользовательский интерфейс и снизить трафик, но и перенести на клиента часть задач сервера приложения. К сожалению, такой "двухслойный" клиент в настоящее время не может быть независимым от платформы. И здесь выбор также не нуждается в комментариях

Архитектура серверной части.

Конечно, в разработке, начатой в 21 веке, хотелось реализовать "правильную" многоуровневую модель с использованием EJB (Enterprise Java Beans) и прочих достижений конца прошлого века. Увы, архитектура получилась многоуровневой, но без EJB и, что совсем "неправильно", с реализацией большей части бизнес логики на сервере БД. Что повлияло на наше решение?

Во-первых, то, что мы разрабатывали не систему с единой бизнес логикой и интерфейсом для всех клиентов, а настраиваемую систему. И здесь использование разных вариантов Oracle PL/SQL пакетов и разных настроек интерфейса, хранящихся в БД (подробнее об этом - ниже), оказалось гораздо более удобным, чем реализация многовариантности на уровне сервера приложения. Напомним, что нам выгодно держать клиентов из разных стран (и, соответственно, с разной бизнес логикой) на одном сервере.

Во-вторых, то, что мы выбрали Oracle для реализации системы и не планируем ее переноса на другие СУБД. В этих условиях основным критерием при выборе способа реализации бизнес логики становится производительность.

Управление правами доступа и защита информации

Необходимость передачи информации о деятельности предприятия по интернету на какой-то хостинг-центр является психологически очень тяжелым моментом для руководства предприятия, внедряющего ASP систему. Поэтому начинать разработку без надежного решения вопросов защиты информации при передаче и разграничения прав доступа к информации БД было бы просто бессмысленно. Причем это решение должно быть не только надежным, но и убедительным для арендатора приложения, что предполагает:

Защита информации при передаче.

В качестве возможных методов шифрования трафика в открытых сетях рассматривались:

1. встроенный в броузер механизм соединения по протоколу SSL и шифрования данных при помощи алгоритма RSA (поддерживаемый сервером приложения Oracle IAS),

2. аппаратное шифрование на сетевом уровне или использование технологии VPN (Virtual Private Network).

Второй вариант был отвергнут поскольку:

Управление правами доступа к информации.

Изоляция информации различных арендаторов и управление доступом в систему обеспечивается стандартными средствами СУБД Oracle:

В отличие от управления правом доступа в систему на уровне приложения, такое решение обеспечивает:

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

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

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

Разработка пользовательского интерфейса

При разработке пользовательского интерфейса для нашей системы перед нами встали следующие проблемы.

Интернационализация.

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

При этом

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

Для выполнения этих требований были реализованы следующие решения:

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

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

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

Функциональность клиента

Как мы уже говорили выше, для сокращения трафика и ускорения работы системы было необходимо превратить HTML в некое подобие языка четвертого поколения. Этим несколько забытым сейчас термином назывались языки программирования, которые обеспечивали возможность связи полей для ввода и редактирования данных с полями таблиц базы данных, в том числе, возможность проверки соответствия вводимого значения указанному типу данных и другим ограничениям, налагаемым на поле. JavaScript позволяет решать эти проблемы, но решение "в лоб" предполагало написание весьма большого объема кода для каждого поля. В результате мы рисковали не уменьшить, а существенно увеличить трафик и получить в придачу неудобный в отладке и трудный в сопровождении код.

К сожалению, старые версии Интернет Эксплорера, на которых мы начинали разработку, не давали полноценной поддержки элементов поведения. Сейчас мы, возможно, пошли бы по пути их использования, но тогда мы были вынуждены разработать специальную библиотеку JavaScript функций, позволяющих по коротким описаниям создавать полноценные интерфейсные объекты. Это прежде всего поля с проверкой вводимых значений на заданный тип данных (длина строки, формат числовых значений и дат), это полноценная грид форма, позволяющая выделять строки и редактировать данные непосредственно в ней, и это заголовки, которые, как уже говорилось, получали значение в зависимости от языка, на котором работает пользователь. В результате описание страниц стало простым и наглядным. И легко формализуемым. А от этого уже оставался совсем маленький шаг до следующего решения: хранить в базе данных формальные описания экранных форм и генерировать их по мере необходимости. Тем более, что используемая технология JSP оказалась для этого очень удобной. Для формирования этих описаний был разработан специальный "Конструктор экранов", также выполненный по веб технологии.

Какие преимущества мы получили, пойдя по этому пути? Их достаточно много:

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

Использование XML

Использование описанной выше библиотеки типовых объектов пользовательского интерфейса обеспечило выполнение многих действий непосредственно на клиенте. Однако, обновление данных по-прежнему требовало перерисовки экранных форм с новыми "цифрами". Избавиться от этого удалось за счет использования для получения данных XML для реализации подзапроса запроса обновления части полей отображаемой страницы.

Поддержка версионности

Управление версиями в процессе разработки такой системы оказалась не простой задачей. Ведь тут много кода, который хранится разбросанным по отдельным записям в различных таблицах базы данных. Например, экранная форма хранится в виде набора атрибутов для входящих в нее элементов. А очередная версия может отличаться от предыдущей и структурой таблиц БД или их связями. Кроме того, задачи управления версиями не ограничиваются этапом разработки. Как уже говорилось, предполагается распространение системы в разных странах с разным законодательством, для разных гостиниц с различными корпоративными бизнес правилами, что, безусловно, потребует создания специализированных версий системы. И при этом будет необходимо вносить в систему различные изменения, связанные с расширением функциональности и, увы, исправлением неизбежных ошибок.

Чтобы решить все эти задачи нам пришлось достроить стандартную систему версионного контроля, взятую "за основу" - Clear Case - и, пользуясь возможностями Oracle (триггера, включая триггера на системные события, и выгрузка данных в текстовые файлы), дооснастить ее способностью фиксировать изменения в структуре БД, описаниях экранных форм и бизнес логики. Эти способности не отключаются и в схемах, предоставленных пользователям. В результате фиксируются все настройки, выполненные пользователем. Далее по этим настройкам может быть сформирован "патч". Выполнение этого патча после установки новой версии системы приведет к тому, что будут восстановлены все настройки системы. Причем патчи могут быть многоуровневыми. Это внесение изменений и исправлений в "базовую" систему, это региональные настройки (например, на особенности налогового законодательства определенной страны), это настройки на особенности бизнес логики гостиницы или цепочки гостиниц или даже индивидуальные настройки. Последовательное выполнение соответствующих патчей приведет к обновлению системы с сохранением ранее выполненных настроек. А продуманная система разделения прав на изменение различных элементов системы и даже на изменение отдельных атрибутов полей экранных форм приводит к тому, что наиболее принципиальные настройки выполняются наиболее профессиональными разработчиками.

Отчеты

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

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

Поскольку отчет показывается в броузере, пользователь без труда может распечатать любой отчет. Кроме того, отчет может быть отправлен по электронной почте. Этот прием используется, в частности, для регулярно формируемых отчетов (ежедневные, еженедельные и так далее).

Среди дополнительных возможностей отчетов можно отметить:

1. Возможность создания отчетов для печати на бланках (например, формы для регистрации клиентов)

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

3. Возможность перехода на другие отчеты, связанные с текущим по какому-либо полю (ПРИМЕР!!!)

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

Как и в случае с экранными формами пользователи системы могут в определенных пределах настраивать отчеты по собственному желанию.

Анализ данных

Успешная работа гостиницы требует от руководства постоянных усилий, направленных на разработку наиболее эффективных приемов привлечения клиентов и предоставления им максимального количества услуг. Необходимым инструментом для этого является анализ накопленных данных. Результаты такого анализа чаще всего представляются в форме различных таблиц, диаграмм или графиков и напоминают обычные отчеты. Однако, в отличие от регулярных отчетов они должны, во первых, обеспечивать возможность получения различных срезов данных, различных группировок и т.п. Причем эти возможности должны быть предоставлены непосредственно пользователю, поскольку невозможно заранее предугадать, какие именно зависимости ему будет необходимо исследовать. Тем не менее понятно, что предметом таких отчетов являются либо деньги, либо люди. Поэтому в системе предусмотрен механизм накопления необходимых данных в формате, удобном для последующего анализа (денормализованные данные). Формирование этих данных производится на сервере БД в автоматическом режиме.

Модуль позволяет получать по подготовленным данным различные аналитические отчеты с произвольными наборами полей, различными условиями группирования данных, вычислением различных показателей и с различными условиями сортировки. Для выбора данных могут использоваться различные фильтры, а для большей наглядности представления данных могут использоваться различные условия выделения данных в отчете (цветом, шрифтом или размером). Для создания и настройки аналитических отчетов от пользователя не требуется ни знания SQL, ни знания реляционной структуры данных в системе. А подготовка данных позволяет получать результаты за ограниченное время.

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

Инструмент также обеспечивает возможность графического представления данных в виде достаточного набора диаграмм и графиков.

Взаимодействие с локальными системами

Как уже отмечалось, система управления собственностью должна обеспечивать взаимодействие с локальными системами, установленными в гостинице; подобные проблемы, очевидно, возможны и на других предприятиях. Для решения этой задачи был разработан универсальный интерфейсный модуль, взаимодействующий с ядром системы по протоколу HTTP, а с локальными системами - с использованием поддерживаемого ими программного интерфейса или протокола обмена. Последний случай был наиболее типичным, и единственным способом взаимодействия со многими системами был обмен сообщениями. В качестве несущего протокола для взаимодействия в локальных системах (с которыми нам приходится работать) используются RS-232, TCP/IP и протокол файлового обмена (был даже экзотический заказ на управление телефонной станцией через модем). В передаваемых сообщениях используются форматы

И в дополнение ко всему этому - отсутствие стандартов на сообщения для однотипных систем.

Однако при детальном рассмотрении проблема оказалась не столь безнадежной, и нам не пришлось (и не придется) разрабатывать тысячи интерфейсов, как это делается в некоторых PMS (это не преувеличение). Дело в том, что функциональность систем в пределах одного класса (телефонных станций, систем платного телевидения и пр.) достаточно стандартна - в них возникают одни и те же события и обрабатываются одни и те же события (команды) PMS, которые характеризуются (по максимуму) одинаковым набором атрибутов. Поэтому достаточно было сделать по одному обработчику событий (внешних и внутренних) для каждого класса систем, настроив его на представителя с максимальной функциональностью.

Естественно, обработчику событий нужен переводчик, преобразующий сообщения локальных систем к стандартному виду и упаковывающий стандартные сообщения PMS в соответствии с используемым логическим протоколом. Настроечные параметры протоколов конкретных систем (например, для CSV - используемый разделитель, перечень событий и порядковый номер в строке для каждого атрибута) хранятся в таблицах базы данных, для работы с которыми реализован графический интерфейс (но не для пользователя, а для разработчика).

Наиболее удобным средством реализации программ перевода и обработки событий оказался PL/SQL, в результате мы пришли к следующей архитектуре модуля

1. на одной из клиентских машин устанавливается "агент", который обеспечивает:

2. на сервере приложения хранятся JSP, обеспечивающие

Для установки "агента" в системе реализован графический интерфейс, который обеспечивает автоматическую установку программы на клиентской машине и позволяет осуществить настройку взаимодействия на физическом уровне (например, номер порта для TCP/IP). Эти настройки выполняются специалистом, обслуживающим локальную систему.

Служба сообщений.

Одной из неприятных особенностей интернет систем является то, что система становится "пассивной" - она только отвечает на запросы пользователя, но не может по своей инициативе передать ему сообщения. А такая потребность достаточно часто возникает. В качестве примеров можно привести

Система отслеживает эти события, знает кому о них надо сообщить (вспомним про бизнес роли), но как это делать? Конечно, можно встроить в каждую страницу объект, который будет регулярно опрашивать сервер и при наличии нового сообщения выводить его на экран. Но такое решение существенно (и бесполезно - события редкие) увеличивает трафик и не дает никакой гарантии доставки своевременной доставки сообщений (пользователь может просто не работать с системой). Пришлось создавать службу сообщений, которая обеспечивает передачу сообщений на активные устройства: пейджер, мобильный телефон (SMS), IP телефон (об этом ниже). Эта же служба обеспечивает и обмен сообщениями между пользователями системы, при этом (в менее критичных ситуациях) кроме перечисленных выше средств доставки могут

Эта же служба используется для передачи сообщений о возникших проблемах в службу поддержки.

Служба поддержки.

Система, надежно работающая без IT отдела благо для предприятия, но беда для неопытных пользователей. Кого же спросить "А почему она говорит…?" Конечно, можно позвонить в службу поддержки, но если это междугородний или международный звонок? Можно воспользоваться ICQ или другой "болталкой", но их использование достаточно часто запрещается корпоративными стандартами безопасности. Пришлось реализовать в системе встроенный коммуникатор, обеспечивающий двустороннюю связь:

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

Использование IP телефонов в интернет приложениях.

Идея использования IP телефонов появилась случайно - московское представительство Cisco предложило нам участвовать в Cisco XML Contest. И неожиданно для себя мы обнаружили, что IP телефон - это то устройство, которого нам так не хватало. В данном докладе мы не будем рассуждать о выгодах IP телефонии и перспективах ее распространения (и то и другое есть), а рассмотрим вопрос о возможном использовании установленных на предприятии IP телефонов в информационных системах. Что же нас так заинтересовало?

Во-первых, давайте вспомним начало доклада - для эффективного функционирования PMS вынуждена использовать в качестве терминалов весьма странные устройства - телевизор, телефон и т.д. IP телефон тоже есть в каждом номере, но это - броузер, который без всяких ухищрений (вспомним организацию взаимодействия с локальными системами) может взаимодействовать с интернет приложением. Причем состав передаваемой и получаемой информации не ограничен жесткими рамками протокола обмена телефонной станции или системы платного телевидения.

Во-вторых, в отличие от компьютера IP телефон - постоянно включенное и активное устройство (вспомним нашу службу сообщений).

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

Именно так мы и поступили. И в системе появились:

1. Учет персонала (зарегистрировать приход и уход можно с любого телефона)

2. Мониторинг заданий (назначить исполнителя и зафиксировать начало и конец работы)

3. Модуль Гостя, обеспечивающий:

Но такие возможности нужны не только нашей системе, но и любой гостиничной. В результате появилась система Phone Mate.

А кому еще они нужны? Да любому предприятию - бытовые проблемы есть везде. Почему сотрудник должен дозваниваться электрику или офис менеджеру? Достаточно оставить заказ, система зарегистрирует время его поступления и время исполнения.

Вы хотите встретиться с партнером. Для этого вам надо заказать пропуск (чем это отличается от заказа столика в ресторане - те же дата и время?). Вы хотите пригласить на встречу коллегу (чем это отличается от записи к парикмахеру?). Во время встречи Вы предложите ему чай или кофе… Все это и многое другое укладывается в реализованную в Phone Mate модель бронирования ресурсов и заказа услуг. Для того, чтобы описать новый ресурс или сервис достаточно ввести несколько записей в таблицы базы данных…

Заключение

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