O kliencie internetowym 1C

Jedną z przyjemnych cech technologii 1C:Enterprise jest to, że aplikacja stworzona przy użyciu technologii form zarządzanych może działać zarówno w cienkim (wykonawczym) kliencie na Windows, Linux, MacOS X, jak i jako klient internetowy w 5 przeglądarkach – Chrome, Internet Explorer, Firefox, Safari, Edge, i to wszystko – bez zmiany oryginalnego kodu aplikacji. Co więcej – zewnętrznie aplikacja w cienkim kliencie i w przeglądarce działa i wygląda praktycznie identycznie.
Znajdź 10 różnic (pod katem 2 obrazki):

Okno cienkiego klienta na Linuxie:

O kliencie internetowym 1C

To samo okno w kliencie internetowym (w przeglądarce Chrome):

O kliencie internetowym 1C

Dlaczego stworzyliśmy klienta internetowego? Mówiąc nieco patetycznie, takie zadanie postawił przed nami czas. Od dawna praca przez Internet stała się niezbędnym warunkiem dla aplikacji biznesowych. Na początku dodaliśmy możliwość pracy przez Internet dla naszego cienkiego klienta (niektórzy nasi konkurenci, nawiasem mówiąc, na tym się zatrzymali; inni, wręcz przeciwnie, zrezygnowali z cienkiego klienta i ograniczyli się do realizacji klienta internetowego). My postanowiliśmy dać naszym użytkownikom możliwość wyboru tego wariantu klienta, który bardziej im odpowiada.

O kliencie internetowym 1C

Dodanie możliwości pracy przez Internet dla cienkiego klienta było dużym projektem, który wymagał pełnej zmiany architektury interakcji klient-serwer. Tworzenie klienta internetowego to zupełnie nowy projekt, który zaczął się od zera.

Sformułowanie zadania

Zatem wymagania do projektu: klient internetowy powinien robić to samo, co cienki klient, a mianowicie:

  1. Wyświetlać interfejs użytkownika
  2. Wykonywać kod kliencki, napisany w języku 1C

Interfejs użytkownika w 1C jest opisany w wizualnym edytorze, ale deklaratywnie, bez pikselowego rozmieszczania elementów; używa się około trzydziestu typów elementów interfejsu – przycisków, pól wprowadzania (tekstowych, liczbowych, daty/czasu), list, tabel, wykresów itd.

Kod kliencki w języku 1C może zawierać wywołania serwerowe, pracę z lokalnymi zasobami (plikami itp.), drukowanie i wiele więcej.

Zarówno cienki klient (podczas pracy przez sieć), jak i klient internetowy korzystają z tego samego zestawu usług internetowych do komunikacji z serwerem aplikacji 1C. Implementacja u klientów jest oczywiście różna – cienki klient napisany jest w C++, klient internetowy – w JavaScript.

Historia

Projekt stworzenia klienta internetowego rozpoczął się w 2006 roku, w którym (średnio) uczestniczyła ekipa pięciu osób. Na poszczególnych etapach projektu angażowano programistów do realizacji specyficznych funkcji (dokumentów tabelarycznych, diagramów itp.); zazwyczaj byli to ci sami programiści, którzy tworzyli tę funkcjonalność w kliencie stacjonarnym. To znaczy, że programiści pisali na nowo w JavaScript komponenty, które wcześniej stworzyli w C++.

Od samego początku odrzuciliśmy pomysł jakiejkolwiek automatycznej (choćby częściowej) konwersji kodu C++ z klienta stacjonarnego na JavaScript klienta internetowego z powodu dużych różnic koncepcyjnych między tymi dwoma językami; klient internetowy był pisany w JavaScript od podstaw.

W pierwszych iteracjach projektu klient internetowy konwertował kod klienta napisany w wbudowanym języku 1C bezpośrednio na JavaScript. Klient stacjonarny działa inaczej — kod wbudowany w języku 1C kompilowany jest do kodu bajtowego, który następnie jest interpretowany po stronie klienta. Później również klient internetowy zaczął działać w ten sposób – po pierwsze, zapewniło to wzrost wydajności, po drugie – umożliwiło ujednolicenie architektury klienta stacjonarnego i internetowego.

Pierwsza wersja platformy 1C:Przedsiębiorstwo z obsługą klienta internetowego została wydana w 2009 roku. Klient internetowy w tamtym czasie obsługiwał 2 przeglądarki – Internet Explorer i Firefox. W pierwotnych planach była również obsługa Opery, ale z powodu nie do pokonania wówczas problemów z obsługą zamykania aplikacji w Operze (nie udało się z 100% pewnością śledzić, kiedy aplikacja się zamyka i w tym momencie przeprowadzać procedurę rozłączenia z serwerem aplikacji 1C) musieliśmy z tych planów zrezygnować.

Struktura projektu

W platformie 1C:Przedsiębiorstwo istnieją 4 projekty, napisane w JavaScript:

  1. WebTools – ogólne biblioteki używane w pozostałych projektach (tutaj uwzględniamy Google Closure Library).
  2. Element sterujący FormatowanyDokument (zrealizowany w JavaScript zarówno w kliencie stacjonarnym, jak i w kliencie internetowym)
  3. Element sterujący Harmonogram (zrealizowany w JavaScript zarówno w kliencie stacjonarnym, jak i w kliencie internetowym)
  4. Klient internetowy

Struktura każdego projektu przypomina strukturę projektów Java (lub projektów .NET – w zależności od bliższych preferencji); mamy przestrzenie nazw, a każda przestrzeń nazw znajduje się w oddzielnym folderze. Wewnątrz folderu znajdują się pliki i klasy przestrzeni nazw. W projekcie klienta internetowego jest około 1000 plików.

Strukturalnie klient internetowy dzieli się na następujące podsystemy:

  • Zarządzany interfejs aplikacji klienckiej
    • Ogólny interfejs aplikacji (menu systemowe, panele)
    • Interfejs formularzy, obejmujący około 30 elementów sterujących (przyciski, różne typy pól wejściowych – tekstowe, numeryczne, data/czas itp., tabele, listy, wykresy itp.)

  • Model obiektowy dostępny dla programistów na kliencie (łącznie ponad 400 typów: model obiektowy interfejsu zarządzanego, ustawienia układów danych, formatowanie warunkowe itp.)
  • Interpreter wbudowanego języka 1C
  • Rozszerzenia przeglądarek (służą do funkcjonalności, która nie jest wspierana w JavaScript)
    • Praca z kryptografią
    • Praca z plikami
    • Technologia zewnętrznych komponentów, umożliwiająca ich użycie zarówno w cienkim, jak i webowym kliencie

Cechy rozwoju

Implementacja wszystkiego powyżej opisanego w JavaScript – nie jest to proste zadanie. Być może webowy klient 1C to jedna z największych aplikacji po stronie klienta napisanych w JavaScript – około 450.000 linii. Aktywnie stosujemy w kodzie webowego klienta podejście obiektowe, co ułatwia pracę z tak dużym projektem.

Aby zminimalizować rozmiar kodu klienta, początkowo używaliśmy naszego własnego obfuscatora, a zaczynając od wersji platformy 8.3.6 (październik 2014) zaczęliśmy stosować Google Closure Compiler. Efekt użycia w liczbach – rozmiar frameworka webowego klienta po obfuskacji:

  • Własny obfuscator – 1556 kB
  • Google Closure Compiler – 1073 kB

Użycie Google Closure Compiler pomogło nam zwiększyć wydajność webowego klienta o 30% w porównaniu do naszego własnego obfuscatora. Ponadto, ilość pamięci konsumowanej przez aplikację zmniejszyła się o 15-25% (w zależności od przeglądarki).

Google Closure Compiler bardzo dobrze działa z kodem obiektowym, dlatego jego skuteczność dla webowego klienta jest maksymalnie wysoka. Closure Compiler robi dla nas kilka dobrych rzeczy:

  • Statyczne sprawdzenie typów na etapie budowy projektu (zapewnia to pokrycie kodu adnotacjami JSDoc). W efekcie otrzymujemy typizację statyczną, bardzo bliską poziomowi typizacji w C++. Pomaga to wychwycić dość dużą ilość błędów na etapie kompilacji projektu.
  • Zmniejszenie rozmiaru kodu poprzez obfuskację
  • Szereg optymalizacji wykonywanego kodu, takich jak:
    • podstawowe podstawienie funkcji. Wywołanie funkcji w JavaScript to dość kosztowna operacja, a podstawienia inline często używanych małych metod znacznie przyspieszają działanie kodu.
    • Liczenie stałych na etapie kompilacji. Jeśli wyrażenie zależy od stałej, wstawiane jest faktyczne jej wartości.

Jako środowisko do tworzenia aplikacji klienckich używamy WebStorm.

Do analizy kodu używamy SonarQube, gdzie integrujemy statyczne analizatory kodu. Dzięki analizatorom śledzimy degradację jakości kodu źródłowego w JavaScript i staramy się jej unikać.

O kliencie internetowym 1C

Jakie problemy rozwiązywaliśmy/rozwiązujemy

W trakcie realizacji projektu napotkaliśmy szereg interesujących zadań, które musieliśmy rozwiązać.

Wymiana danych z serwerem i pomiędzy oknami

Istnieją sytuacje, w których obfuskacja kodu źródłowego może przeszkodzić w działaniu systemu. Kod zewnętrzny w stosunku do wykonywanego kodu aplikacji klienckiej, z powodu obfuskacji, może mieć nazwy funkcji i parametrów różniące się od tych, których oczekuje nasz wykonywany kod. Kod zewnętrzny dla nas to:

  • Kod przychodzący z serwera w postaci struktur danych
  • Kod innego okna aplikacji

Aby uniknąć obfuskacji podczas interakcji z serwerem, używamy tagu @expose:

/**
 * @constructor
 * @extends {Base.SrvObject}
 */
Srv.Core.GenericException = function ()
{
    /**
     * @type {string}
     * @expose
     */
    this.descr;

    /**
     * @type {Srv.Core.GenericException}
     * @expose
     */
    this.inner;

    /**
     * @type {string}
     * @expose
     */
    this.clsid;

    /**
     * @type {boolean}
     * @expose
     */
    this.encoded;
}

Aby uniknąć obfuskacji podczas interakcji z innymi oknami, używamy tak zwanych interfejsów eksportowanych (interfejsów, w których wszystkie metody są eksportowane).

/**
 * Экспортируемый интерфейс контрола 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 (){}

Używaliśmy Virtual DOM zanim stał się popularny)

Jak wszyscy deweloperzy zajmujący się złożonym interfejsem UI w sieci, szybko zrozumieliśmy, że DOM źle nadaje się do pracy z dynamicznym interfejsem użytkownika. Praktycznie od razu stworzono analog Virtual DOM w celu optymalizacji pracy z UI. W procesie obsługi zdarzenia wszystkie zmiany DOM są zapamiętywane w pamięci i dopiero po zakończeniu wszystkich operacji, gromadzone zmiany są stosowane do drzewa DOM.

Optymalizacja działania aplikacji klienckiej

Aby nasza aplikacja kliencka działała szybciej, maksymalnie staramy się wykorzystać domyślne możliwości przeglądarki (CSS itp.). Tak więc, pasek narzędzi formularza (umiejscowiony praktycznie w każdym formularzu aplikacji) jest rysowany wyłącznie za pomocą narzędzi przeglądarki, dynamicznym układem opartym na CSS.

O kliencie internetowym 1C

Testowanie

Do testów funkcjonalnych i wydajnościowych używamy narzędzia stworzonego we własnym zakresie (napisanego w Javie i C++), a także zestawu testów opartych na Selenium.

Nasze narzędzie jest uniwersalne – pozwala testować praktycznie wszystkie programy okienkowe, dlatego nadaje się do testowania zarówno klienta cienkiego, jak i klienta webowego. Narzędzie rejestruje działania użytkownika, który uruchomił aplikację "1C", w pliku skryptowym. W tym samym czasie rejestrowane są obrazy obszaru roboczego ekranu – wzorców. Podczas kontroli nowych wersji klienta webowego skrypty są odtwarzane bez udziału użytkownika. W przypadku niezgodności zrzutu ekranu z wzorcem na którymkolwiek kroku, test uznawany jest za nieudany, po czym specjalista ds. jakości prowadzi dochodzenie – czy to błąd, czy zaplanowana zmiana zachowania systemu. W przypadku zaplanowanego zachowania wzorce automatycznie zastępowane są nowymi.

Narzędzie dokonuje również pomiarów wydajności aplikacji z dokładnością do 25 milisekund. W niektórych przypadkach pętlamy części skryptu (na przykład kilkakrotnie powtarzamy wprowadzenie zamówienia) w celu analizy degradacji czasu wykonania w czasie. Wyniki wszystkich pomiarów są zapisywane w logu do analizy.

O kliencie internetowym 1C
Nasze narzędzie testowe i testowana aplikacja

Nasze narzędzie i Selenium uzupełniają się nawzajem; na przykład, jeśli jakiś przycisk na jednym z ekranów zmienił swoje położenie – Selenium może tego nie zauważyć, ale nasze narzędzie to dostrzeże, ponieważ wykonuje porównanie piksel po pikselu z wzorcem. Narzędzie jest również w stanie wykryć problemy z przetwarzaniem wejścia z klawiatury lub myszy, ponieważ to właśnie je reprodukuje.

Testy na obu narzędziach (naszym i Selenium) uruchamiają typowe scenariusze pracy z naszych aplikacji. Testy są automatycznie uruchamiane po codziennej kompilacji platformy "1C:Enterprise". W przypadku spowolnienia działania skryptów (w porównaniu do poprzedniej wersji) przeprowadzamy dochodzenie i usuwamy przyczynę spowolnienia. Kryterium jest proste – nowa wersja musi działać nie wolniej od poprzedniej.

Do dochodzenia w sprawie incydentów spowolnienia działania programiści używają różnych narzędzi; w większości przypadków korzysta się z Dynatrace AJAX Edition produkcji firmy DynaTrace. Rejestrowane są logi wykonywania problematycznej operacji w poprzedniej i nowej wersji, a następnie logi są analizowane. Czas wykonania pojedynczych operacji (w milisekundach) może nie być decydującym czynnikiem – w przeglądarkach regularnie uruchamiane są procesy serwisowe, takie jak sprzątanie pamięci, które mogą wpłynąć na czas wykonania funkcji i zniekształcić obraz. W takim przypadku bardziej istotnymi parametrami będą liczba wykonanych instrukcji JavaScript, liczba atomowych operacji na DOM itp. Jeśli liczba instrukcji/operacji w tym samym scenariuszu w nowej wersji wzrosła – prawie zawsze oznacza to spadek wydajności, który należy poprawić.

Jedną z przyczyn spadku wydajności może być również to, że Google Closure Compiler z jakiegoś powodu nie mógł przeczytać funkcji jako inline (na przykład dlatego, że funkcja jest rekurencyjna lub wirtualna). W takim przypadku staramy się poprawić sytuację, przepisując kod źródłowy.

Rozszerzenia przeglądarek

W przypadku, gdy aplikacja potrzebuje funkcjonalności, której nie ma w JavaScript, używamy rozszerzeń przeglądarek:

Nasze rozszerzenia składają się z dwóch części. Pierwsza część to tak zwane rozszerzenie przeglądarki (zwykle rozszerzenia napisane w JavaScript dla Chrome i Firefox), które współdziała z drugą częścią — binarnym rozszerzeniem, realizującym potrzebną nam funkcjonalność. Należy wspomnieć, że piszemy 3 wersje binarnych rozszerzeń – na Windows, Linux i MacOS. Binarne rozszerzenie dostarczane jest w ramach platformy 1C:Enterprise i znajduje się na serwerze aplikacji 1C. Przy pierwszym wywołaniu z klienta webowego jest ładowane na komputer kliencki i instalowane w przeglądarce.

Podczas pracy w Safari nasze rozszerzenia korzystają z NPAPI, natomiast w Internet Explorerze – z technologii ActiveX. Microsoft Edge jak na razie nie obsługuje rozszerzeń, więc klient webowy w nim działa z ograniczeniami.

Dalszy rozwój

Jednym z zadań dla zespołu odpowiedzialnego za rozwój aplikacji webowej jest dalszy rozwój funkcjonalności. Funkcjonalność aplikacji webowej powinna być identyczna z funkcjonalnością klienta lekkiego, a wszystkie nowe funkcjonalności są wprowadzane jednocześnie zarówno w kliencie lekkim, jak i w webowym.

Inne zadania to rozwój architektury, refaktoryzacja, zwiększenie wydajności i niezawodności. Na przykład, jednym z kierunków jest dalsze przejście w stronę modelu pracy asynchronicznej. Część funkcjonalności aplikacji webowej jest obecnie zbudowana na synchronizowanym modelu interakcji z serwerem. Model asynchroniczny staje się teraz coraz bardziej aktualny w przeglądarkach (i nie tylko w przeglądarkach), co skłania nas do modyfikacji aplikacji webowej poprzez zastąpienie synchronicznych wywołań wywołaniami asynchronicznymi (wraz z odpowiednią refaktoryzacją kodu). Stopniowe przejście do modelu asynchronicznego jest podyktowane koniecznością wsparcia wydanych rozwiązań oraz ich stopniową adaptacją.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster