16: Programming from reuse

Lecture



It may seem strange that we did not specifically identify modular programming in the review of styles. However, it is obvious that the requirement to develop programs in which stand-alone and, accordingly, easily replaced by others fragments that solve logically closed tasks are identified, is a general logical and general technological, and not exceptional, inherent in any special method .

This requirement is usually interpreted as a modular software product. The advantages of modularity, understood in a general sense, are the possibility of replacing a module without changing the rest and reusing software fragments. The latter can already be considered as a special programming style for which modularity is one of the means.

Means of supporting modularity do not even characterize a style, but a specific language that supports this style. Therefore, it is legitimate to speak not about style, but about a specific language, to what extent it supports the modular construction of programs within its style.

What you need to reuse

The style of reuse is characterized by the fact that when drafting a program, they strive to make the most of what has already been done - by the programmer himself , his colleagues, or elsewhere. It has long been generally accepted that, ideally, programming as an assembly from pre-prepared blocks — assembly programming — should replace programming as the coding of algorithms. This term was introduced in 1978. G. S. Zeitin later separated this concept from theoretical considerations and introduced it from the programmer side. Note that mathematics have long abandoned the construction of new theorems (corresponding to computer science programs) and new concepts (corresponding to abstract data types) from scratch. In mathematics, previously obtained results are reused in a very professional manner. Here, due to the conceptual unity of the system of concepts and strict criteria of validity, there is no problem of compatibility of new versions, which often ruins attempts not only to reuse, but also simply to use old programs.

Nevertheless, it is interesting to do the following thought experiment: what would happen if mathematicians worked in approximately the same conditions as programmers?

Well, it is clear that if the mathematician, who published the theorem, would take money (and even more would require it in advance) for each use, then reuse would be immediately and immediately reduced.

Even if he didn’t take money for the theorem by itself, but would classify its evidence and threaten criminal prosecution to anyone who dares to understand (`disassemble ') the text he wrote, the situation would have come to the same dead center. the words `deadlock 'are better than the Russian word` dead end').

Apparently, it would be enough to pay for the work of mathematicians on a time-based basis, checking the validity of the reports on the time spent on the number of lines of written evidence. This, perhaps, would not cease re-use completely, but any mathematician (and not just rogues) would rewrite other people's proofs with his own terms and with small changes at every opportunity. Here to the dead point would come more slowly, but equally inevitable.

As you see, we can make an important social and practical conclusion: the only chance for curing the current adolescent programming diseases is the work of open software communities and open project documentation [34].

It is clear that when using prefabricated building blocks losses are possible. Nevertheless, the potential benefit from reuse is simply enormous. In mathematics, where there are accurate estimates, it is shown that the length of the proof (read, the programs) can be reduced to the TOWER EXPONENT ONCE without significant loss of efficiency only by introducing lemmas (read, using the already constructed programs).

Consider two real-world situations that demonstrate development that is not oriented and re-oriented. In the first situation, there is a programmer who works with a very developed system that has everything. Nevertheless, he writes his own procedure for the lexicographical ordering of strings, because "it is easier to write it yourself than to find it, and then you have to adjust it as well." Conclusion: firstly, there is no desire to reuse here, and secondly, reuse can be hindered by the difficulty of finding out what needs to be included in the program being compiled, as well as version compatibility issues.

The second situation is the other extreme. Java programmer needed to build a syntax analysis. On the question of how he does it, an answer was received: "Why do I need to know this? I have a JavaCC package that does everything as it should!" At the same time, further questioning showed that this programmer does not even imagine what type of analysis method supports JavaCC, and, therefore, can say nothing about how the grammar assignment for this package is related to the efficiency of the analysis. Having learned the possible options, the programmer became thoughtful, but did not change anything. Why? The answer is simple: "So everything is already working!" In short, the quality of use of ready-made components of the system depends on knowledge of them .

The situation is again the same as in mathematics, especially in applied one. The qualified use of theoretical results requires knowledge of the relevant theory, and sometimes ideas of evidence of the results (since in a real situation theories of the theory are never exactly fulfilled). The depth of knowledge required is different: sometimes a fairly general idea, such as when using mathematical functions, sometimes you need information about the principles of implementation, but you can always specify the level of familiarity with the reusable.

A comparison of the situations shows that there are few wishes and guidelines for reuse. Knowledge is required of which portable components can be used and how. Getting the same knowledge often requires substantial labor costs. It is necessary that the software itself being reused should be adapted for this purpose, in particular, that it should follow good practice accumulated in mathematics, and not ignore it as a pure theory .

Deciphering the previous sentence will allow the thoughtful reader to derive all the conditions necessary to ensure reuse in a specific situation. Any instructions here are useless (if a person has not yet realized the previous one) or are harmful (if he thinks he has realized, in fact, he does not understand anything). You can only give general advice for those who are still engaged in (self) education.

In mathematics, for a programmer, not so much specific results are important (they can also be referred to in the reference literature), as the structure of concepts and evidence, the ways in which abstractions are introduced and the use of exclusively abstract concepts in particular situations .

Sometimes the use of advanced language tools contributes to reuse. In particular, C ++ and Java quite often allow you to transfer programs from one operating environment to another (transfer is one of the forms of reuse). But those who are really involved in the transfer of programs, will certainly remember when reading the previous sentence annoying inconsistencies, which C ++ and Java do not help in identifying and preventing.

Re-use contributes to the improvement of the level of language concepts, at least to the second or third type (object-oriented language). Sometimes OOP also helps with the possibilities of inheritance of properties and methods of objects (but often in the most critical situations, a poorly thought-out concept of inheritance hinders so much).

All this is the germ of support for a programming style aimed at reuse. But in the main, the current practice largely hinders reuse, and the level of support systems is not yet high enough and inadequate to the overall task of applying this style.

Reuse also depends on the general level of knowledge and skills of the programmer (those who are able to rise to the method level are inclined to reuse, and those who cannot rise above tactical planning usually avoid it).

If we restrict ourselves to the programmer's activities, then, first of all, we need to point out two aspects of this style: the use of existing components and the development of reusable components.

The use of reusable components is characterized by the following style features:

  • the main characteristic of the style from reuse: the preference to search for candidates for the introduction into the program of their own development;
  • the desire to explore existing candidates, to identify in them features that are useful or harmful to the problem being solved;
  • Attempts to adapt your solution to the feasibility of implementation (in particular, some of the patterns (see below) consider exactly those cases where the data structures of your program and the component being reused are significantly different);
  • comparison and evaluation of implementation options and self-hypothetical development;
  • adaptation of the material being introduced into the program, if it is required, which is possible only under two conditions:
    • openness of program text;
    • the availability of adequate and open high-level documentation for this text - without it, the program text is useful only for hackers.

When developing reused components, it is necessary to take into account that such development always requires additional costs, which are associated with the following requirements:

  • special attention should be paid to documenting (best of all, self-documenting) reused components, and the documentation should clearly highlight the essential features of the algorithm, show ghosts and used props, so it should not be a comment to the program text, but a high-level description of the idea and what turned out to be necessary for its specific implementation;
  • It requires a serious analysis that applicants for reuse can be attributed to standard programming techniques, i.e. have a wide enough range of applicability for further use 1 ;
  • it is necessary to work out not only the options for the complete reuse of as is components, but also their partial reuse in vides templates, ready-made fragments, etc., when the component needs to be configured;
  • Specifications are required for both the areas of adequate use of the component and the limits of applicability (the second part is almost always absent in the current specifications);
  • in the specifications, it is necessary to clearly distinguish the fundamental points from the props and highlight the ghosts;
  • it is necessary to evaluate the effectiveness of the component;
  • Special care is required for publishing a component to potential users: they should be able to hear about it.

Reuse and Styles

In the characteristics of both aspects of programming from reuse, there is no explicit mention of the specifics of traditional computational models . Therefore, they do not depend on the style in which the components are written , and to a large extent on the characteristics of the computing systems on which they are implemented 2 . But the components and the computation model serve as the foundation on which the reuse add-in is based. And the stability of the building and even its architecture significantly depend on the quality of the foundation.

Consider the previously presented styles in terms of their adaptability to the combination with the style of reuse.

Automata programming is clearly related to the notion of a set of states that is global for each program, and to use a program fragment in isolation from this set is, generally speaking, meaningless. This indicates the natural reuse framework for this style.

First, if a fragment can be selected as a black box, that is, we are only interested in the ratio between its input and output data, then it can be viewed at the program level as an independent data processing node and thus gains independence from the program states. In turn, this is precisely what makes it possible to use such a fragment as an independent processing node of another program - to reuse it. On this principle all library math functions are built, the realization of which quite often is not required even to know when using.

Conventional reuse units for any programming style are procedures. They are autonomously described, and if they turn out to be independent of the context shared with other components, then, in fact, they become the same black boxes that we just talked about.

Another possible case, when the part clearly understood by the programmer, of the states of the external program can be interpreted as a homomorphic image of the part (again, explicitly distinguished) of the component states (gray box). Then the component can even be modified, i.e. it can be reused as a fragment or template. However, the methods of establishing a homomorphism between states are that high-level superstructure above automaton programming, which has not yet been created, and therefore the programmer here is highly dependent on the quality of meaningful conceptual analysis.

Ironically, little is better suited to combining structured programming with the reuse style . The requirements for the structure of the information space of the task and for the coordination with it of other components of the program provide regulated links between subtasks, which means that the task of identifying independent components is facilitated (but does not disappear). In addition to fully self-reusable components, here you can indicate reuse, in which the new part provides the necessary part of the context (that is, the component and this part of the context are reused; see Modula-2 and Object Pascal language modules). Modules can be thought of as gray boxes for structured programming. The possibilities of modularization are rather well studied and correctly implemented in the languages ​​mentioned above.

It should be noted that for the cases considered, the reuse task often enough requires modification of what is provided. Consider the simplest example that does not go beyond reusing a black box. The square root function is defined only for non-negative arguments. Question: Does the reusable subroutine need to check this function? On the one hand, it increases the reliability of programming, but on the other hand, it turns out to be redundant, when it is known (can be proved) that the argument is greater than zero. In the framework of traditional techniques, simple mechanisms for disabling checks cannot exist, since they all violate the black box principle. In imperative languages, such multivariate subroutines are traditionally interpreted as something rudely non-structural and even non-automatic, like deformity.

Attention !

Multivariance as a form of gray boxes corresponds to the natural expansion of logic - the calculation of predicates with partially ordered quantifiers - and can be correctly added to imperative structural languages, and it is added to automatic programming languages ​​naturally, and one only regrets the absence of such a possibility .

When using the probential style, the possibility of restructuring the reusable component under the situation is much higher due to the high-level principles of computation. However, there are no precise practical estimates of this yet. As a rule, large and meaningfully complete fragments of programs are reused, most often those that constitute the basic mechanisms that develop the model of language computation. The lack of experience in developing large production projects with a significant use of this style makes one speculate about it presumably.

But non-imperativeness is in its essence better adapted for reuse and, in particular, for pattern reuse, since ratios instead of orders are easier to automatically transform or even simply reinterpret in a different environment (lack of imperativeness is another factor that causes the almost complete reversibility of mathematical results) . It is not surprising, for example, that fact database in Prolog programs often become their common parts.

In event programming, a program decomposition is prescribed in advance: highlighting the levels of event generation and processing in it. Already it itself suggests the feasibility of a common generator for similar programs.We should not forget that the event-based mechanism or control with the help of priorities inevitably increases the autonomy of handlers: for example, they may not necessarily rely on a certain sequence of calls, and, as a result, their flexibility increases.

Today, the most debugged in terms of reuse are programs in object-oriented and functional style. The common reason for this is the flexible means of abstraction of the respective languages ​​and the clear separation of interfaces from implementations. This increases the potential and real possibilities of reuse. At the same time, say, an object-oriented style is effective only for sufficiently large systems and thus inspires programmers to build large systems of classes and objects that are strongly interconnected. And this, in turn, makes technologize development. The technology is currently associated with the development of typical models of fragments of object-oriented systems. Design patterns are created (called patterns), which are prescribed to be used to minimize communication in the system,ensure its developability [8].

Designing for future reuse of results is possible at four levels.

  1. Application Layer . During project management, care is taken to ensure that candidate components for reuse are identified during decomposition and development of system components. These components are allocated in independent units and are made out independently of the project.
  2. The level of specifications and documentation . In the specifications, the ghosts behind the program are clearly described, the documentation separates the props from the solutions and does not forget about the ghosts.
  3. Level tools . Development of a project almost always includes the creation of tools that support unification: uniform libraries of publicly available tools for a project, general context and uniform means of access to it, means of supporting the implementation of technological agreements and regulations, design patterns, etc. This toolkit (or part of it) in many cases it can be designed independently of the project for possible re-use as libraries.
  4. Level of decisions . The value for reuse may be the architectural level of the project. Good architectural solutions, as a rule, allow distribution beyond the specific project in which they appeared. These may be fragments that are suitable for use as samples for other projects, and then their re-use requires an appropriate template. Another independent solution is the project framework, i.e., a set of interrelated components that require further definition, as a result of which an application, subsystem, module, etc. can be built. Using templates or frameworks in another project links the reuse style with the programming style from samples.

Приведенный перечень упорядочен по степени значимости уровней для переиспользования. Наибольшая эффективность достигается, когда удается при проектировании выйти на уровень решений, но одновременно этот уровень является наиболее сложным и трудоемким для разработки.

В заключение отметим, что условия применения стиля от переиспользования в реальном программировании должны включать в себя оценку как экономических показателей, так и уровня квалификации исполнителей. А это уже функции менеджера проекта, который должен решать, ориентироваться ли на переиспользование (в обоих аспектах) или нет, и если да, то решить многие финансовые и организационные проблемы, выходящие за рамки собственно программирования.

Предупреждение !

Здесь необходима трезвая оценка уровня своих специалистов и организованности работ, поскольку на действительно выгодное для переиспользования решение способны, как правило, лишь высококвалифицированные специалисты в хорошей инфраструктуре .

Программирование от образцов

Программирование от образцов - вариант стиля от переиспользования, часто игнорируемый специалистами, но тем не менее он является весьма распространенным (даже профессионалы им пользуются). Это - подход к разработке программ по заданным заранее шаблонам. Это - скорее, целый набор вырожденных стилей, каждый из которых выделяется в связи с тем, что в той или иной ситуации скрывается под понятием образец, фрейм, шаблон.

Не всякое переиспользование уместно считать программированием от образцов. Так, когда повторно используется фрагмент, который можно рассматривать как черный ящик, то ничего, кроме результатов вычислений фрагмента, не внедряется в новую программу. Следовательно, фрагмент не предписывает метода построения программы. Противоположная ситуация с переиспользованием уровня проектных решений. Эти решения диктуют, как будет построена программа. Шаблоны и каркасы, появившиеся в какой-либо разработке или построенные специально, становятся образцами для нового программного проекта. При этом совсем не обязательно, чтобы образец и конструируемая программа были бы написаны на одном языке. Напротив, можно извлечь определенную выгоду из того, что образец не привязывается к модели вычислений разрабатываемой программы. Если образец специально создается для данной программы, например, чтобы лучше понять решаемую задачу, то для него целесообразно выбирать язык повышенного уровня или другой модели вычислений и за счет этого иметь возможность быстрее реализовать пробную версию, макет и т. д. Подобные соображения мотивируют разновидность стиля программирования от образцов, получившую название prototyping (see below). In this case, it is clear that there is not reuse, but actually programming from the sample. But such an ideal case is the exception rather than the rule: most often it is difficult to draw the line between an independent style and technological methods of reuse.

You can specify the following typical cases of application programming from samples.

  • A program written in any style in which you need to change something is given. It is precisely known in what places it is necessary to change it. The result is a new program. This case is often in a professional language called a program patch. Skilled programmers use a set of such samples, they began to include them in the manuals on the PLO.
  • Given a set of software tools developed by specialists, and the method of their application, which includes a scheme for the preparation of the required program. In the ideal case, a meaningfully described algorithm is used that generates a program. Such a set is often called a technological or instrumental system for a certain class of applications.
  • The development environment of the new program is provided , as in the previous case, created in advance by experts, including descriptions fixing the system of concepts of the new program. The program itself is written in the usual way. This is one of the common ways of work and professionals, and semi-professionals, and amateurs.
  • Программирование от макета . Разработчики быстро готовят прототип, который рассматривается как макет. Макет затем доводится до реального программного изделия. От макета в программной системе часто остается лишь система понятий, сам метод разработки полностью меняется (например, макет был написан на языке Prolog, а окончательная программа - на Java). Макет (особенно в системах, поддерживающих его представление в графической форме, таких как UML [ 18 ] ) нередко становится частью документации готовой программы.
  • Предоставляется технологический фрейм: нечто, для чего известны слоты, т. е. позиции (пункты, пустые значения того или иного типа, в том числе и процедурного), которые требуется заполнить. В результате должна получиться программа, архитектурная схема которой задана априори. Это, собственно говоря, и есть программирование от образцов в самой чистой форме, которое, в свою очередь, распадается на ряд направлений:
    • семантические сети искусственного интеллекта;
    • фирменная методика и технология, которая погружает один из предшествующих случаев в систему стандартизованных форм и документов. Пример Rational Unified Process (RUP) [ 37 ] ;
    • табличное программирование, примеры которого приведены в данном пособии;
    • компонентное программирование, например, с использованием XML или иного языка разметки (которая задает фрейм ) и языка обработчиков разметки (разделение, как говорят на программистском жаргоне, на парсер и обработчик). Это как раз то, что дает объектная модель документа.
  • Предоставляется технический фрейм - то, что нужно заполнять. Он, в отличие от технологического фрейма, совершенно не требует знания логики будущей программы. Это - облегченный и упрощенный вариант предыдущего подхода. Вообще говоря, неясно, программирование ли это, но такой подход очень даже востребован (см., например, язык Forms из Oracle), а потому замалчивать его нельзя, тем более что результат - все равно программа.

Использование технологического и технического фреймов демонстрирует возможность и особенности сочетания программирования отобразцов с другими стилями. Фрейм, как основа конструируемой программы, может быть разработан в каком угодно стиле (например, как событийная система), но он предписывает программисту правила, а иногда и стиль, в котором должны заполняться слоты. Когда сочетание таких разнородных стилей, которое без специальной методики и поддержки было бы неосуществимым, становится продуктивным, тогда можно с полным правом говорить о программировании от образцов как о самостоятельном стиле и о реализующей его методике либо методологии.

The programming style of the samples is characterized by the fact that the developer of the program when creating slots is not at all interested in how these components will be used - this has been decided in advance within the framework of this programming system. The context in which the components are immersed is all that provided by the template or frame, and therefore there is no question of directly specifying global actions or using global conditions. It is precisely due to the strict localization of everything the programmer deals with that in this case the productivity and quality of his work are achieved.


Comments


To leave a comment
If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Programming Styles and Techniques

Terms: Programming Styles and Techniques