OS Sivelkiriya: software development process

Hello, Habr.

This post continues the cycle of publications about the Sivelkiriya OS project. In the first article of the cycle, a general description of the concept was given, in the second it was explained why it was necessary and in what form the product could see the light, in the third architectural solutions were described thesis. Since many commentators have raised the issue of development convenience for this OS, this article is intended to highlight this topic.

Software development process


The software development process under Sivelkiriya differs from that under other OSs (Windows, Linux, Android, etc.), since developers in all cases prepare common components, the specific use case of which is unknown at the time of development. In other words, development is carried out as if in all cases libraries were developed and never applications.

No module can take on unusual functions. No module can strictly demand or implicitly assume that it will interact specifically with the module that the developer intended or with which he was tested during development. Thus, the module obviously does not depend on the version of any other module, which prevents the problem of dependency hell. We emphasize once again that within the framework of Sivelkiriya, the paradigm of applications is rejected, including as programs consisting of a predefined set of modules.

In this case, the module can determine through which interfaces it interacts with other modules. In addition, it may require and recommend that specific tests presented in the central repository be passed for the counterparty module. The module is not always required to use the latest version of each interface - it can use any supported version, and the operating system is responsible for bringing the versions.

In terms of languages ​​and environments, Sivelkiriya provides the same flexibility as other operating systems. A module can contain both machine code and byte code or interpreted code. Moreover, for different types of code, different executors are used, which themselves are modules. Their task is to ensure the execution of the module code and the passage of calls and data across its boundaries, as well as the implementation of the necessary maintenance (for example, garbage collection). Thanks to this approach, it is planned to support a large number of languages ​​(both interpreted and compiled) and environments. At the same time, the restrictions set by the operating system apply to the module regardless of the language and method of loading, since any executor ultimately interacts with the operating system through calls to interface methods,permissions for which are controlled in a universal manner.

The concept of dynamic libraries in Sivelkiriya is almost completely replaced by the concept of modules. The modules distributed jointly can, if necessary, transfer part of the code to the shared library, however, no other module that is not included in this package will be able to access it. The problem of finding a shared library is also solved by the fact that in all cases the exact library that is included in the package is used. Any other interactions with the common code occur through a system of modules.

Organization of interaction of developers


Obviously, this structure of the operating system requires a special approach to organizing the interaction of module developers with the developers of the operating system: it would be most naive to believe that the developers of the operating system will be able to compose a set of interfaces at a time that covers all future ways of using devices running this OS . On the contrary, the organization of universal compatibility requires continuous bilateral cooperation between developers of the OS, which provides interfaces and prototypes, and developers of the software that uses them.

Each interface is characterized by a version number consisting of major and minor parts. With an increase in the minor version, the interface may be supplemented with new entities within the same older version, however, deletion or alteration of existing entities is not allowed. New older versions are released when the interface requires deep processing.

All minor versions within one major version are compatible with each other. In case of coincidence of actually implemented by the object and expected by the calling context minor version numbers, such compatibility is obvious. If the actually used object implements a higher minor version of the interface than the calling context expects, then some of the data and functions provided by the interface are simply not used. If the object implements a lower minor version than expected, then when accessing entities that are not actually implemented, default handlers are called, whose work is based on data and algorithms already presented in an earlier version of the interface. So, if a later younger version of the “Article” interface adds to the data accessible through the interface the field “Advertising text”, which is used in some publications, for example,on banners that provide access to the full text of the article, for compatibility the default handler can use the first paragraph or the first sentence of the full text as such text. Another approach is to return “Not implemented” special values ​​(exceptions) when accessing inaccessible data, which shifts the responsibility for processing such restrictions to the calling context.

Older versions of interfaces can be either compatible with each other or not. For example, in the hypothetical case of moving from considering the position of points on the screen in Cartesian coordinates to using polar coordinates, the “Point Position 1.0” interface uses Cartesian coordinates, while the “Point Position 2.0” interface contains a representation in polar coordinates. Since there is a one-to-one correspondence between these two representations, the operating system can always recalculate coordinates in cases when the actual version of the interface used differs from the expected one.

Unfortunately, this masking of the actual version number is not always possible. For example, if the “Melody” interface in version 1.0 describes the work as a score, and in version 2.0 as an audio recording, then there is no one-to-one correspondence between them: the same melody can be played on different instruments, while the recording can contain sounds that cannot be expressed on a sheet of music. Similarly, if the Note interface was originally designed for textual content, and then adapted for handwriting, translating one into the other will be difficult: a handwritten note may contain pictures, while hidden characters (for example, soft transfers). Finally, city maps are traditionally depicted in two dimensions,however, for megacities with multi-level interchanges, this is increasingly becoming insufficient; if in the future a transition is made from two-dimensional cards to three-dimensional, getting from one to the other will not be so easy.

Similar rules apply when changing prototype versions of modules. Since the main task of the module is to implement data interfaces, we will not dwell on this in more detail.

Distribution of interfaces is centralized through a repository supported by a team of developers of the operating system. New versions are loaded when the operating system is updated. The existence of other repositories that distribute interfaces is not allowed, since it will put an end to universal compatibility, which is the main goal of creating the Sivelkiriya OS. The only exception may be intra-corporate repositories, used in cases where the fact of the development of some interfaces is a commercial secret. Such interfaces, however, cannot go beyond firms that use them for their internal work.

Distribution of the modules is possible both through the repository supported by the operating system development team, and through repositories supported by third parties (commercial software companies, open source communities, corporate servers, etc.). At the same time, the central repository, supported by the OS development team, is positioned as the main one, since it provides some unique services.

So, when loading new versions of modules into the repository, they are tested using a replenished library of integration and unit tests, as well as performance tests. Information on passing such tests becomes available to both developers and users. When adding new tests, they also apply to older versions of modules present in the repository. All tests provided by the central repository are available to all developers for use both inside it and on their own infrastructure; the only exception is opposing the optimization of modules for specific tests to the detriment of use in a general context.

In addition, the central repository collects information about all modules available in other open repositories, and also tests them whenever possible, although downloading such modules is still only available from the repositories that hosted them. This allows users to have all the information about available modules in one place, and software developers to get additional promotion of their own repositories (stores).

Finally, the central repository helps arbitrate in contentious cases (for example, when distributing unlicensed software to third parties). Creating a third-party repository is impossible without registration in a central repository (including intracorporate repositories); the support team for the central repository has the authority and ability to block violators of the rules (pirates, hackers, software developers with a closed architecture) both at the level of individual modules and at the level of entire third-party repositories.

Previous articles in the series are available here: one , two , three . The full text, as before, is available on the project website .

All Articles