Однією з приємних особливостей технології 1С: Підприємство є те, що прикладне рішення, розроблене за технологією керованих форм, може запускатися як у тонкому (виконуваному) клієнті під Windows, Linux, MacOS X, так і як веб-клієнт під 5 браузерів - Chrome, Internet Explorer, Firefox, Safari, Edge, і все це без зміни вихідного коду програми. Більше того – зовні додаток у тонкому клієнті та у браузері функціонує та виглядає практично ідентично.
Знайдіть 10 відмінностей (під катом 2 картинки):
Вікно тонкого клієнта на Linux:
Те ж саме вікно в веб клієнті (в браузері Chrome):
Навіщо ми зробили веб-клієнт? Говорячи дещо пафосно, таке завдання нам поставило час. Вже давно робота через Інтернет стала необхідною умовою для бізнес-додатків. Спочатку ми додали можливість роботи через Інтернет для нашого тонкого клієнта (деякі наші конкуренти, до речі, на цьому зупинилися; інші, навпаки, відмовилися від тонкого клієнта і обмежилися реалізацією веб-клієнта). Ми ж вирішили дати нашим користувачам можливість вибрати варіант клієнта, який їм підходить більше.
Додавання можливості роботи через Інтернет для тонкого клієнта було великим проектом із повною зміною архітектури клієнт-серверної взаємодії. Створення веб-клієнта - і зовсім новий проект, що починався з нуля.
Постановка завдання
Отже, вимоги до проекту: веб-клієнт повинен робити те саме, що і тонкий клієнт, а саме:
Відображати інтерфейс користувача
Виконувати клієнтський код, написаний мовою 1С
Інтерфейс користувача в 1С описується у візуальному редакторі, але декларативно, без попіксельної розстановки елементів; використовується близько трьох десятків типів елементів інтерфейсу – кнопки, поля введення (текстові, цифрові, дата/час), списки, таблиці, графіки тощо.
Клієнтський код на мові 1С може містити серверні виклики, роботу з локальними ресурсами (файлами і т.п.), друк і багато іншого.
І тонкий клієнт (при роботі через інтернет), і веб-клієнт користуються одним і тим же набором веб-сервісів для спілкування з сервером додатків 1С. Реалізація клієнтів, звичайно, різна – тонкий клієнт написаний на С++, веб-клієнт – на JavaScript.
Трохи історії
Проект створення веб-клієнта стартував у 2006 році, в ньому (в середньому) брала участь команда із 5 осіб. На окремих етапах проекту залучалися розробники для реалізації специфічної функціональності (табличного документа, діаграм тощо); як правило, це ті самі розробники, що робили цю функціональність у тонкому клієнті. Тобто. розробники заново писали JavaScript компоненти, раніше створені ними на C++.
З самого початку ми відкинули ідею будь-якої автоматичної (хоча б часткової) конверсії C++ коду тонкого клієнта в JavaScript веб-клієнта через сильні концептуальні відмінності цих двох мов; веб-клієнт писав JavaScript з чистого листа.
У перших ітераціях проекту веб-клієнт конвертував клієнтський код вбудованою мовою 1С безпосередньо в JavaScript. Тонкий клієнт надходить інакше - код вбудованою мовою 1С компілюється в байт-код, а потім цей байт-код інтерпретується на клієнті. Згодом так само став робити і веб-клієнт – по-перше, це дало виграш у продуктивності, по-друге – дозволило уніфікувати архітектуру тонкого та веб-клієнтів.
Перша версія платформи 1С:Підприємство з підтримкою веб-клієнта вийшла у 2009 році. Веб-клієнт на той момент підтримував два браузери - Internet Explorer і Firefox. У початкових планах була підтримка Opera, але через непереборні на той момент проблеми з обробниками закриття програми в Opera (не вдавалося зі 2% впевненістю відстежити, що програма закривається, і в цей момент зробити процедуру відключення від сервера додатків 100С) від цих планів довелося відмовитись.
структура проекту
Всього у платформі 1С:Підприємство є 4 проекти, написані на JavaScript:
WebTools – спільні бібліотеки, які використовуються іншими проектами (сюди ж ми включаємо Бібліотека закриття Google).
Елемент управління Форматований документ (реалізований на JavaScript і в тонкому клієнті, і веб-клієнті)
Елемент управління Планувальник (реалізований на JavaScript і в тонкому клієнті, і веб-клієнті)
Веб-клієнт
Структура кожного проекту нагадує структуру Java-проектів (або .NET проектів – кому що ближче); ми маємо неймспейси, і кожен неймспейс лежить в окремій папці. Усередині папки лежать файли та класи неймспейсу. У проекті веб-клієнта близько 1000 файлів.
Структурно веб-клієнт по-великому поділяється на такі підсистеми:
Керований інтерфейс клієнтської програми
Загальний інтерфейс програми (системні меню, панелі)
Інтерфейс керованих форм, що включає, зокрема, близько 30 елементів управління (кнопки, різні типи полів введення – текстові, цифрові, дата/час тощо., таблиці, списки, графіки тощо.)
Об'єктна модель, доступна розробникам на клієнті (загалом понад 400 типів: об'єктна модель керованого інтерфейсу, налаштування компонування даних, умовного оформлення тощо)
Інтерпретатор вбудованої мови 1С
Розширення браузерів (використовуються для функціональності, що не підтримується JavaScript)
Робота з криптографією
Робота з файлами
Технологія зовнішніх компонент, що дозволяє їх використовувати як тонкому, так і веб-клієнті
особливості розробки
Реалізація всього вищеописаного на JavaScript – справа непроста. Можливо, веб-клієнт 1С – один із найбільших client-side додатків, написаних на JavaScript – близько 450.000 рядків. Ми активно використовуємо в коді веб-клієнта об'єктно-орієнтований підхід, який спрощує роботу з таким великим проектом.
Для мінімізації розміру клієнтського коду ми спочатку використовували власний обфускатор, а починаючи з версії платформи 8.3.6 (жовтень 2014) стали використовувати Компілятор Google Closure. Ефект використання у цифрах – розмір фреймворку веб-клієнта після обфускування:
Власний обфускатор – 1556 кб
Google Closure Compiler – 1073 кб
Використання Google Closure Compiler допомогло нам підвищити швидкість веб-клієнта на 30% порівняно з нашим власним обфускатором. Крім того, на 15-25% (залежно від браузера) знизився обсяг пам'яті, що споживається програмою.
Google Closure Compiler дуже добре працює з об'єктно-орієнтованим кодом, тому його ефективність для веб-клієнта максимально висока. Closure Compiler робить для нас кілька гарних речей:
Статична перевірка типів на етапі складання проекту (забезпечується тим, що ми покриваємо код анотаціями JSDoc). У результаті виходить статична типізація, дуже близька за рівнем до типізації С++. Це допомагає виловити досить великий відсоток помилок на стадії компіляції проекту.
Зменшення розміру коду через обфускацію
Ряд оптимізації виконуваного коду, наприклад, такі як:
inline-підстановки функцій. Виклик функції JavaScript - досить дорога операція, і inline-підстановки невеликих методів, що часто використовуються, істотно прискорюють роботу коду.
Підрахунок констант на етапі компіляції. Якщо вираз залежить від константи, у нього буде підставлено фактичне значення константи
Як середовище розробки веб-клієнта ми використовуємо WebStorm.
Для аналізу коду ми використовуємо SonarQube, куди інтегруємо статичні аналізатори коду За допомогою аналізаторів ми відстежуємо деградацію якості вихідного коду JavaScript і намагаємося її не допускати.
Які завдання вирішували/вирішуємо
У ході реалізації проекту ми зіткнулися з багатьма цікавими завданнями, які нам довелося вирішувати.
Обмін даними з сервером та між вікнами
Існують ситуації, коли обфускування вихідного коду може стати на заваді роботі системи. Код, зовнішній по відношенню до виконуваного коду веб-клієнта, внаслідок обфускації може мати імена функцій і параметрів, які відрізняються від тих, які чекає наш виконуваний код. Зовнішнім кодом для нас є:
Код, що надходить із сервера у вигляді структур даних
Код іншого вікна програми
Щоб уникнути обфускації при взаємодії з сервером, ми використовуємо тег @expose:
А щоб уникнути обфускації при взаємодії з іншими вікнами ми використовуємо так звані інтерфейси, що експортуються (інтерфейси, у яких всі методи є експортованими).
/**
* Экспортируемый интерфейс контрола DropDownWindow
*
* @interface
* @struct
*/
WebUI.IDropDownWindowExp = function(){}
/**
* Перемещает выделение на 1 вперед или назад
*
* @param {boolean} isForward
* @param {boolean} checkOnly
* @return {boolean}
* @expose
*/
WebUI.IDropDownWindowExp.prototype.moveMarker = function (isForward, checkOnly){}
/**
* Перемещает выделение в начало или конец
*
* @param {boolean} isFirst
* @param {boolean} checkOnly
* @return {boolean}
* @expose
*/
WebUI.IDropDownWindowExp.prototype.moveMarkerTo = function (isFirst, checkOnly){}
/**
* @return {boolean}
* @expose
*/
WebUI.IDropDownWindowExp.prototype.selectValue = function (){}
We used Virtual DOM before it became mainstream)
Як і всі розробники, що мають справу зі складним Веб UI, ми швидко зрозуміли, що DOM погано підходить для роботи з динамічним інтерфейсом користувача. Практично відразу було реалізовано аналог Virtual DOM для оптимізації роботи з UI. У процесі обробки події всі зміни DOM запам'ятовуються в пам'яті і, тільки після завершення всіх операцій, накопичені зміни застосовуються до дерева DOM.
Оптимізація роботи веб-клієнта
Щоб наш веб-клієнт працював швидше, ми максимально намагаємося задіяти штатні можливості браузера (CSS і т.п.). Так, командна панель форми (розташована практично на кожній формі програми) малюється виключно засобами браузера, динамічною версткою на базі CSS.
Тестування
Для функціонального тестування та тестування продуктивності ми використовуємо інструмент власного виробництва (написаний на Java та C++), а також набір тестів, побудованих на базі Селен.
Наш інструмент універсальний - він дозволяє тестувати практично будь-які віконні програми, тому підходить для тестування як тонкого клієнта, так і веб-клієнта. Інструмент записує дії користувача, який запустив прикладне рішення "1С", у файл-сценарій. У цей час відбувається запис зображень робочої області екрана — стандартів. При контролі нових версій веб-клієнта сценарії програються без участі користувача. У випадках розбіжності скріншота з еталонним на якомусь кроці тест вважається таким, що провалився, після чого фахівець з якості проводить розслідування – помилка це або запланована зміна поведінки системи. У разі запланованої поведінки зразки автоматично підміняються на нові.
Інструмент також проводить вимірювання продуктивності додатків з точністю до 25 мілісекунд. У ряді випадків ми закільцюємо частини сценарію (наприклад, кілька разів повторюємо введення замовлення) для аналізу деградації часу виконання з часом. Результати всіх вимірів записуються в балку для аналізу.
Наш інструмент тестування та тестований додаток
Наш інструмент та Selenium доповнюють один одного; наприклад, якщо якась кнопка на одному з екранів змінила своє місцезнаходження – Selenium це може не відстежити, але наш інструмент помітить, тому що. робить попіксельне порівняння скріншоту з еталоном. Також інструмент може відстежити проблеми з обробкою введення з клавіатури або миші, оскільки саме їх він і відтворює.
Тести на обох інструментах (нашим та Selenium) запускають типові сценарії роботи з наших прикладних рішень. Тести автоматично запускаються після щоденного складання платформи «1С:Підприємство». У разі уповільнення роботи сценаріїв (порівняно з попереднім складанням) ми проводимо розслідування та усуваємо причину уповільнення. Критерій у нас простий – нова збірка має працювати не повільніше за попередню.
Для розслідування інцидентів уповільнення роботи розробники використовують різні інструменти; в основному використовується Видання Dynatrace AJAX виробництва компанії DynaTrace. Проводиться запис логів виконання проблемної операції на попередній і новій збірці, потім логи аналізуються. При цьому час виконання одиничних операцій (у мілісекундах) може не бути вирішальним фактором – у браузері періодично запускаються службові процеси типу прибирання сміття, вони можуть накластися на час виконання функцій та спотворити картину. Релевантнішими параметрами в цьому випадку буде кількість виконаних інструкцій JavaScript, кількість атомарних операцій над DOM тощо. Якщо кількість інструкцій/операцій в тому самому сценарії в новій версії збільшилася - це майже завжди означає падіння швидкодії, яке потрібно виправляти.
Також однією з причин падіння продуктивності може бути те, що Google Closure Compiler з якоїсь причини не зміг зробити inline-підстановку функції (наприклад, тому що функція рекурсивна або віртуальна). І тут ми намагаємося виправити ситуацію, переписавши вихідний код.
Розширення браузерів
У випадку, коли прикладному рішенню потрібна функціональність, якої немає в JavaScript, ми використовуємо розширення браузерів:
Наші розширення складаються із двох частин. Перша частина – те, що називається розширенням браузера (зазвичай написані на JavaScript розширення для Chrome і Firefox), які взаємодіють з другою частиною — бінарним розширенням, що реалізує потрібну нам функціональність. Треба згадати, що ми пишемо три версії бінарних розширень – під Windows, Linux та MacOS. Бінарне розширення поставляється у складі платформи 3С:Підприємство та знаходиться на сервері додатків 1С. При першому дзвінку з веб-клієнта воно завантажується на клієнтський комп'ютер і встановлюється у браузері.
При роботі в Safari наші розширення використовують NPAPI, під час роботи в Internet Explorer – технологію ActiveX. Microsoft Край поки не підтримує розширення, тому веб-клієнт у ньому працює з обмеженнями.
Подальший розвиток
Одна з груп завдань для розробки веб-клієнта – це подальший розвиток функціональності. Функціональність веб-клієнта має бути ідентична функціональності тонкого клієнта, вся нова функціональність реалізується одночасно і тонкому, і веб-клієнті.
Інші завдання - розвиток архітектури, рефакторинг, підвищення продуктивності та надійності. Наприклад, один із напрямків – подальший рух у бік асинхронної моделі роботи. Частина функціональності веб-клієнта зараз побудована на синхронній моделі взаємодії із сервером. Асинхронна модель зараз стає в браузерах (і не тільки в браузерах) більш актуальною, і це змушує нас модифікувати веб-клієнт шляхом заміни синхронних викликів на асинхронні (і відповідний код рефакторингу). Поступовий перехід до асинхронної моделі пояснюється необхідністю підтримки випущених рішень та поступової їх адаптації.