Back to Home

Platform "1C: Enterprise" - what's under the hood?

Hello · Habr! In this article · we will begin the story of how the 1C: Enterprise 8 platform is built inside and what technologies are used in its development. Why do we think this is ...

Platform "1C: Enterprise" - what's under the hood?

    Hello, Habr!
    In this article, we will begin the story of how the 1C: Enterprise 8 platform is built inside and what technologies are used in its development.

    image

    Why do we think this is interesting? Firstly, because the 1C: Enterprise 8 platform is a large (over 10 million lines of code) C ++ application (client, server, etc.), JavaScript (web client), and, more recently, and Java . Large projects can be interesting, if only because of their scale, because the issues that are invisible in a small code base in such projects stand up to their full potential. Secondly, “1C: Enterprise” is a replicated, “boxed” product, and there are very few articles about such developments on Habré. And it’s always interesting to find out how they live in other teams and companies.

    So let's get started. In this article we will give an overview of some of the technologies that are used in the platform, we will outline the landscape without deep immersion in the implementation. Indeed, for many mechanisms a detailed story will pull on a separate article, and for some - on a whole book!
    To begin with, it is worth deciding on the basic things - what is the 1C: Enterprise platform and what components it consists of. The answer to this question is not so simple, because the term “Platform” (for brevity we will call it that) means both a tool for developing business applications, an execution environment, and administrative tools. Conventionally, the following components can be distinguished:
    • server cluster
    • “Thin” client, able to connect to the server via http and its own binary protocol
    • client for working in a two-tier architecture with a database located on a hard disk or network folder
    • web client
    • application server administration tools
    • development environment (known as Configurator)
    • runtime for iOS, Android and Windows Phone (1C mobile platform)

    All of these parts, with the exception of the web client, are written in C ++. In addition, there is a recently announced next-generation Configurator written in Java.

    Native apps


    For the development of native applications, C ++ 03 is used. Under Windows, Microsoft Visual C ++ 12 (a profile compatible with Windows XP) is used as a compiler, and under Linux and Android - gcc 4.8, for iOS - clang 5.0. The standard library is used uniformly for all OS and compilers - STLPort. This solution reduces the likelihood of errors specific to the implementation of STL. Now we are planning a transition to the STL implementation that comes with CLang, since STLPort has stopped its development and is not compatible with the enabled C ++ 11 support mode in gcc.
    The code base of the server at the same time is 99% total, the client - 95% percent. Moreover, even the mobile platform uses the same C ++ code as the “large” one, although there the percentage of unification is somewhat lower.
    Like most C ++ users, we do not claim to use 100% of the features of the language and its libraries. So, we practically do not use Boost, and one of the features of the language is dynamic type casting. At the same time, we are actively applying:
    • STL (particularly strings, containers, and algorithms)
    • multiple inheritance, including multiple implementation inheritance
    • patterns
    • exceptions
    • smart pointers (native implementation)

    By using multiple inheritance of interfaces (completely abstract classes), a component model becomes possible, which will be discussed below.

    Components


    To ensure modularity, all the functionality is divided into components that are dynamic libraries (* .dll for Windows, * .so for Linux). There are more than a hundred and a half components in total, we will provide descriptions of some of them:
    backendContains a platform metadata engine
    accntObjects that application developers use to build accounting (charts of accounts and accounting registers)
    bslEmbedded Language Execution Engine
    nukeNative implementation of memory allocator
    dbeng8The file base engine. A simple ISAM-based file server database engine that also includes a simple SQL processor
    wbaseContains base classes and functions for implementing the Windows user interface - window classes, access to GDI, etc.

    Separation into many components is useful from several points of view:
    • Separation contributes to better design, in particular better code isolation
    • You can flexibly assemble different delivery options from a set of components:
      • For example, a thin client installation will contain wbase but no backend
      • and on the wbase server, on the contrary, there will not be
      • both options will of course contain nuke and bsl

    All components necessary for this startup option are loaded at program startup. This, in particular, is necessary for registering SCOM classes, which will be discussed below.

    Scom


    For decomposition at a lower level, the SCOM system is used - a library similar in ideology to ATL. For those who did not work with ATL, we briefly listed the main features and features.
    For a specially designed SCOM class:
    • Provides factory methods to create a class from another component, knowing only its name (without disclosing the implementation)
    • Provides an infrastructure of smart pointers with reference counting. The lifetime of the SCOM class does not need to be monitored manually
    • Allows you to find out whether an object implements a specific interface and automatically cast a pointer to an object to a pointer to an interface
    • Create a service object, always accessible through the get_service method, etc.

    For example, you can describe in the json.dll component a class for reading JSON (for example, JSONStreamReader).
    Classes, instances can be created from other components you need to register in the SCOM machine:
    SCOM_CLASS_ENTRY(JSONStreamReader)
    

    This macro will describe a special static registrar class whose constructor will be called when the component is loaded into memory.
    After that, you can create an instance of it in another component:
    IJSONStreamReaderPtr jsonReader = create_instance<IJSONStreamReader>(SCOM_CLSIDOF(JSONStreamReader));
    

    To support services, SCOM offers an additional, quite complex infrastructure. Central to it is the concept of a SCOM process, which serves as a container for running services (i.e., acts as a Service Locator), and also contains a binding to localized resources. The SCOM process is bound to the OS thread. Thanks to this, inside the application you can get services like this:
    SCOM_Process* process = core::current_process();
    if (process)
             return get_service<IMyService>(process);
    

    Moreover, by switching logical (SCOM) processes that are tied to a thread, you can get applications that are almost independent from the point of view of the information space and run within the same thread. This is how our thin client working with the file base is arranged - two SCOM processes are located inside one OS process, one is connected to the client, and the second to the server. This approach allows you to unify the writing of code that will work both on the local file base and in the “real” client-server version. The price for such uniformity is overhead, but practice shows that they are worth it.

    Based on the SCOM component model, both business logic and the 1C: Enterprise interface part are implemented.

    User interface


    Speaking of interfaces. We do not use standard Windows controls; our controls are implemented directly on the Windows API. For the Linux version, a layer has been made that works through the wxWidgets library.
    The library of controls is independent of other parts of 1C: Enterprise and is used by us in several other small internal utilities.

    Over the years of 1C: Enterprise development, the appearance of controls has changed, but a major change in principles has occurred only once, in 2009, with the release of version 8.2 and the emergence of “managed forms”. In addition to changing the appearance, the principle of form layout has fundamentally changed - there was a rejection of pixel-by-pixel positioning of elements in favor of flow-layout of elements. In addition, in the new model, controls do not work directly with domain objects, but with special DTOs ( Data Transfer Objects ).
    These changes made it possible to create a 1C: Enterprise web client that repeats the C ++ control logic in JavaScript. We try to maintain functional equivalence between thin and web clients. In the case when this is not possible, for example, due to restrictions available from the JavaScript API (for example, the possibilities for working with files are very limited), we often implement the necessary functionality using browser extensions written in C ++. We currently support Internet Explorer and Microsoft Edge (Windows), Google Chrome (Windows), Firefox (Windows and Linux) and Safari (MacOS).

    In addition, the technology of managed forms is used to create the interface of mobile applications on the 1C platform. On mobile devices, control rendering is implemented using technologies "native" to the operating system, but the same code is used for the layout logic and interface reactions as in the "large" 1C: Enterprise platform.

    image
    Interface 1C on Linux OS

    image
    Interface 1C on a mobile device

    1C interface on other platforms
    image
    1C interface on Windows

    image
    1C interface - web client


    Open source


    Although we do not use standard libraries for Windows for C ++ developers (MFC, controls from WinAPI), we do not write all the components ourselves. The wxWidgets library has already been mentioned , and we also use:
    • cURL for working with HTTP and FTP.
    • OpenSSL for working with cryptography and establishing TLS connections
    • libxml2 and libxslt for XML parsing
    • libetpan for working with mail protocols (POP3, SMTP, IMAP)
    • mimetic to parse email messages
    • sqllite for storing user logs
    • ICU for internationalization

    The list can still be continued.
    In addition, we use highly modified versions of Google Test and Google Mock when developing unit tests.
    Libraries required adaptation for compatibility with the SCOM model of component organization.
    The prevalence of 1C makes the platform an excellent test of strength for the libraries used in it. A variety of users and scripts quickly detect errors even in the most rarely used parts of the code. We correct them ourselves and try to give them back to the authors of the libraries. The experience of interaction is very different.
    The cURL and libetpan developers respond quickly to pull-request, but the patch, for example, in OpenSSL we didn’t manage to give it back.

    Conclusion


    In the article, we touched on several basic aspects of the development of the 1C: Enterprise platform. In a limited volume of the article, we touched on only some interesting, in our opinion, aspects.
    A general description of the various mechanisms of the platform can be found here .
    What topics would be of interest to you in future articles?

    How is 1C mobile platform implemented?
    Description of the internal device of the web client?
    Or maybe you are interested in the process of selecting features for new releases, development and testing?

    Write in the comments!

    Read Next