In-house technologies
Our technologies we use to increase products quality and flexibility and to speed-up development process
We develop software for Linux, Windows and/or Elbrus (Russian VLIW CPU) using C++/Qt/Qml and C#/WPF (sometimes JVM based languages) using latest standards/frameworks available on target platforms: C++ up to 20, Qt up to the newest 6.x release, C# up to 9.x,.NET Core up to 3.x. OpenCV, CUDA/OpenCL/Vulkan or even OpenGL are used for fast image processing. MKL, compiled Matlab, etc. for mathematical processing.

As any software company we have our own library which covers most of the common tasks we face in practice. Below we shortly present the most interesting parts. Most of what is described here applies both to C++/Qt/Qml and C#/WPF but our present work is more related to the first one.
Declarative approach is known to be very useful in some aspects of software development. In contrast to the typical imperative way of thinking it promotes to design software from top to bottom, from final result back to simple separate steps.

For example, assume one needs to create an interactive OpenGL image view component with the possibility of real-time image processing. Let's start from the result desired, i.e. from the final image rendering on screen. The only prerequisites are the transformation matrix and the OpenGL texture of the processed image. One can already write this part of code, using (yet non-existent) sources of these two components. The transformation matrix is a combination of user induced translation, zoom factor and geometrical transformations. The OpenGL texture depends on the initial image and processing settings, etc. The initial image itself is just a function of filename. And so on following the dependency graph.

Connecting such building blocks from top to bottom not only makes life easier for the developer, but also allows us to change such blocks later. For example, we can easily replace the image source with a real-time image from a camera without touching existing code. Or one can refresh filenames 60 times per second and get a playback of processed video with user interaction.

This is how the software is usually designed in functional programming languages — everything is just a combination of various functions. Note that deeper level functions are lazy by default and computed only when their results are needed, namely during execution of "effects". Interactivity can be added here by implementing a notification conveyor to inform higher levels of the function graph about changes.

For our everyday work we developed a library called "the Flow". The base building blocks are "sources" which produce value and notify customers about their changes. The sources can be easily combined together and used like input arguments for other sources. All notifications are spread automatically through the whole computation graph. As written above they are lazy by default and are only computed upon request.

This approach is somewhat similar to Qt properties but encapsulates both the value and notification source in one shell which makes it much simpler to combine them together and pass them on over the application. No more manual "update" calls and no need to connect signal and slots manually. This approach will be familiar to React users with the difference that Flow is based on current state and not on the data flow.

The library also has several other convenient abilities. In particular, it has built-in lifetime control so the source will remain alive while it's used by other consumers. We use std::shared_ptr in C++, C# is naturally designed for this.

The consumer of long-lived sources don't have to worry about subscriptions/unsubscriptions, everything is done automatically. This helps to exclude the possibility of quite typical memory leaks. Furthermore, it is guaranteed that the object will remain alive until the last notification callback finishes execution. We use std::weak_ptr in C++, C# version use ConditionalWeakTable. One can still manually switch between several input sources or even disconnect the consumer by using special connector components (read-only or even mutable).

Flow tends to use immutable structures instead of single values where applicable. If several parameters are of interest as a whole structure this approach is preferable over single properties because it reduces the amount of code and number of connections.

The library preserves Qt thread affinity and provides native thread-safety. The changes to any source can be safely made from any thread without thinking about locks. All actions and triggers ("effects'' in FP) are automatically executed in a proper thread. One can also explicitly specify on which thread the computation must be run or even do it in the background. This is useful in many cases including interaction with OpenGL which is naturally single threaded.

Routines executed in other threads can throw exceptions accidentally. Flow catches all such situations and forwards them to a customizable central method of exception processing. Of course, one can catch any unexpected situation manually and process it in situ.

Apart from laziness Flow uses smart caching of computation results. It's easy to implement a custom cache limiter which can be fine-tuned for different usages. For example, one can limit the amount of RAM to cache numerical results and use separate policy for GPU textures.

There are several helpers out of the box. Converters can be used for two-way conversion of values forth and back, throttlers flexibly reduce on-change event intensity, barriers can prevent update during multiple input parameter changes, etc.

Flow is used in all our projects and shipped under LGPL v3.0 license.
Metasystem, Qml integration and serialization

In contrast to C#, C++ lacks reflection abilities so class methods and fields metadata are not available in real-time. Qt framework metasystem works quite well but is restricted in terms of adding any additional meta information not foreseen by the Qt team. Besides, complex type support like working with shared pointers, abstract types, dynamic lists, is not integrated to Qt metasystem and requires significant boilerplate code to implement.

Therefore in C++ version of Flow we have implemented our own metasystem to provide more flexible Qml integration, automatic Json/Bson support, etc. It requires only one line to describe any field or method which becomes then instantly available in Qml and can be automatically [de]serialized. It is dynamic by nature because it is based on Flow.

Most Qt and custom types are instantly supported, any other third-party types can also be easily added. It brings the idea of Qml integration to a new level by creating a "bridge" between C++ and Qml objects. For example, integer or QString fields are directly projected to Qml but QVector<T> becomes dynamic QAbstractItemModel. Then one can directly display the number of items in Qml, delete, move, insert without writing any code manually. The implementation will track changes in a clever way (O(N) complexity) and modify only items which were affected without refreshing the whole list. Or one can mark some class as abstract and have several descendants with different behavior. Then their type can be accessed from Qml and appropriate UI parts can be displayed for each item.

Object nesting is natively supported, so any complex object graph can be converted to Json using a single command or any nested sub-object can be accessed from Qml by dot notation starting from a single composition root. Versioning system is integrated into Json/Bson support and data migrations are done automatically on data load.

C# version does not require most of the above written and only includes seamless Flow integration with WPF which looks at the end very similar to Qml approach. Concerning [de]serialization we have forked Newtonsoft.Json to add proper versioning support.