3.3 Patterns of organization of business logic

Lecture



Considering the structure of the domain logic (or business logic) of an application, we study how the set of functions provided by it can be distributed over three sample solutions: a Transaction Script, a Domain Model, and a Table Module.

The simplest approach to describing business logic is using a transaction script — a procedure that receives input from the presentation layer, processes it, performs the necessary checks and calculations, stores it in a database, and activates the operations of other systems. The procedure then returns the presentation layer some data, possibly performing auxiliary operations to format the contents of the result. The business logic in this case is described by a set of procedures, one for each (composite) operation that the application is able to perform. A typical solution transaction script, therefore, can be interpreted as an action script, or a business transaction. It does not have to be a single piece of code. The code is divided into subroutines, which are distributed between different transaction scenarios.

A typical solution transaction script has the following advantages:

  • is a convenient procedural model, easily perceived by all developers;
  • it is successfully combined with simple schemes for organizing a data source layer based on typical solutions: a data recording gateway (Row Data Gateway) and a data table gateway (Table Data Gateway);
  • defines clear boundaries of the transaction.

With an increase in the level of complexity of business logic, a typical solution transaction script demonstrates a number of drawbacks. If several transactions need to perform similar functions, there is a danger of duplication of code fragments. With this

it is possible to partially manage the phenomenon by putting the general subroutines “out of the brackets”, but even in this case most of the duplicates remain in place. As a result, the application may look like a messy mess without a distinct structure.

Of course, complex logic is a good reason to think about objects, and an object-oriented solution to the problem involves using a domain model, which, at least as a first approximation, is structured primarily around the main entities of the domain in question. So, for example, in the leasing system, it would be necessary to create classes representing entities of "rent", "property", "contract", etc., and provide for the logic of checks and calculations: for example, an object representing the essence of "property" probably appropriate to provide the logic of calculating the cost.

The choice of the domain model as opposed to the transaction scenario is just that change of the programming paradigm that apologists of the object approach so much talk about. Instead of using a single subroutine that carries all the logic that corresponds to a certain user action, each object is endowed with only functions that correspond to its nature. If you have not used a domain model before, the learning process can be quite a bit annoying when you have to rush from one class to another in search of the necessary functions.

The cost of practical implementation of the domain model is determined by the degree of complexity of both the model itself and the specific version of the data source layer. To achieve success in the application of the model, beginners will have to spend a lot of time: some require several months of work on the relevant project before their thinking style changes in the right direction. After gaining experience, working becomes much easier - you even wake up enthusiasm. All who are so obsessed with the object paradigm have gone through this. However, unfortunately, it is not possible to drop the load of habits and take a step forward for many.

Of course, whatever the approach, the need to map the contents of the database into memory structures and vice versa still remains. The richer the domain model, the more complex the mapping of object structures into relational (the data mapper, usually implemented on the basis of a typical solution, becomes. Complex data source layer is expensive - in the financial sense (if you purchase third-party services ) or in relation to the cost of time (if you take the case yourself), but if you have one, consider that a good half of the problem has already been solved.

There is a third option for structuring business logic, which involves the use of a standard solution table module. The fundamental difference between a talitsa module and a domain model is that the domain model contains one contract object for each contract recorded in the database, and the table module is the only one object. The table module is used in conjunction with the standard solution set records (Record Set). By sending requests to the database, the user first forms a set of records, and then creates a contract object, passing it a set of records as an argument. If you need to perform operations on a separate contract, you must inform the object of the appropriate identifier (ID).

The table module in many ways represents an intermediate variant, compromise with respect to the transaction scenario and the domain model. Organizing business logic around tables, rather than in the form of straight-line procedures, makes it easier to structure and search for and delete duplicate code fragments. However, the decision module of the table does not allow using many technologies (say, inheritance, strategies and other object-oriented typical solutions), which are used in the domain model to refine the structure of logic.

The greatest advantage of the table module is how this solution is combined with other aspects of the architecture. Many graphical interface environments allow you to work with the results of processing a SQL query, organized as a set of records. Since the decision module of the table is also based on the use of multiple records, it is possible to execute the query, manipulate its result in the context of the table module and transfer data to the graphical interface for display. Some platforms, in particular Microsoft COM and .NET, support exactly this style of development.

Choosing a typical solution

  3.3 Patterns of organization of business logic

Figure 3.4 Dependence of the cost of implementation of various schemes for the organization of bmznes-logic on its complexity

So, which of the three typical solutions to give preference. The answer is not obvious and depends largely on the degree of complexity of business logic. In fig. 3.4 shows one of those informal graphs that many get on your nerves when you have to watch presentations. The reason for irritation is the lack of units of measurement of the values ​​represented by the coordinate axes. However, in this case, such a schedule seems appropriate, as it helps to visualize decision matching criteria. If the application logic is simple, the domain model is less tempting, since the cost of implementing it does not pay off. But with increasing complexity, alternative approaches are becoming less and less acceptable: the complexity of supplementing the application with new functions increases exponentially.

Of course, it is necessary to figure out which particular X-axis segment a particular application belongs to. It would be quite good if we had the right to say that the domain model should be applied in cases where the complexity of business logic is, for example, 7.42 or more. However, no one knows how to measure the complexity of business logic. Therefore, in practice, the problem usually comes down to listening to the opinions of knowledgeable people who are able to somehow analyze the situation and come to meaningful conclusions.

There are a number of factors that influence the curvature of the graph lines. The presence of a team of developers who are already familiar with the domain model allows reducing the initial costs - although not to the levels characteristic of the other two dependencies (the latter is due to the complexity of the data source layer). Thus, the more experienced you and your colleagues are, the more reason you have to apply a domain model.

The effectiveness of a table module seriously depends on the level of support for the structure of multiple records in a particular tool environment. If you are working with something like Visual Studio .NET, where many tools are built precisely on the basis of the record set model, this circumstance will certainly give the table module additional attractiveness. As for the transaction scenario, it is difficult to argue for its use in the .NET context.

Once an architecture has been chosen (albeit not completely), it becomes increasingly difficult to change it over time. Therefore, it is advisable to make some effort to decide in advance which way to go. If you started with a transaction script, but then realized your mistake, do not hesitate to refer to the domain model. If you started with it, the transition to the transaction scenario is unlikely to be successful, unless you can seriously simplify the data source layer.

The three sample solutions that we briefly reviewed are not mutually exclusive alternatives. In fact, the transaction script is often used for some piece of business logic, and the domain model or table module is used for the rest.

Service level

One of the general approaches to the implementation of business logic is to split the domain layer into two distinct layers: “on top of” the domain model or table module is a service layer [4]. Usually this is advisable only when using a domain model or a table module, since a domain layer that includes only a transaction script is not so complicated as to earn the right to create an additional layer. The presentation layer logic interacts with business logic solely through the mediation of a services layer that acts as an application API.

By maintaining a coherent application interface (API), the services layer is also suitable for hosting transaction management and security logic. This makes it possible to provide similar characteristics to each method of the services layer.

For such purposes, property files are usually used, but .NET attributes provide a convenient way to describe the parameters directly in the code. The main decision taken in the design of the service layer is what part of the functions it is appropriate to transfer to its management. The most "modest" option is to present the services layer as an intermediate interface, which only does what sends the calls addressed to it to the underlying objects. In this situation, the services layer provides an API that focuses on specific use cases of the application, and provides a good opportunity to include shell functions in the code that are responsible for transaction management and security checks.

At the other extreme, within the service layer, present most of the logic in the form of transaction scripts. The underlying domain objects in this case can be trivial; if they are concentrated in the domain model, it will be possible to ensure their unambiguous mapping to database elements and use a simpler version of the data source layer (say, Active Record).

There is a variant between the two indicated poles, which is more than a “mixture” of two approaches: it is a model of a “controller entity” (“controller entity”). The main feature of the model is that the logic related to individual transactions or use cases is located in the respective transaction scenarios, which in this case are called controllers (or services). They act as input controllers in typical model-view-controller (Model View Controller,) and application controller (4) solutions (you will learn more about them later) and are also called use case controllers. Functions that are characteristic of several use cases at the same time are transferred to domain entity entities.

Although the controller-entity model is quite common, it should be borne in mind that use-case controllers, like any transaction scenario, tacitly encourage duplication of code fragments.

3.3.1 Transaction Script Pattern

Title

Transaction Script (transaction script)

Purpose

The way of organizing business logic by procedures, each of which serves one request, initiated by the presentation layer.

Many business applications can be perceived as a sequence of transactions. One transaction is able to modify the data, the other - to perceive them in a structured form, etc. Each act of client-server interaction is described by a specific piece of logic. In some cases, the task is as simple as displaying part of the contents of the database. In others, numerous computational and control operations can be envisaged. The transaction scenario organizes the logic of the computational process mainly in the form of a single procedure that accesses the database directly or through the mediation of the thin shell code. Each transaction is associated with its own transaction script (general subtasks can be placed in subordinate procedures).

Operating principle

With a typical solution, the transaction script of the subject domain logic is distributed among the transactions executed in the system. If, for example, the user needs to book a hotel room, the appropriate procedure should include actions to check the availability of a suitable number, calculate the amount of payment and fix the order in the database.

Simple cases do not require special explanations. Of course, as with the writing of other programs, structure the code by module should be meaningful. This should be easy, unless the transaction is too complex. One of the main advantages of a transaction script is that you do not have to worry about the availability and options for the operation of other concurrent transactions. Your task is to obtain input information, interrogate the database, draw conclusions and save the results.

Where to place the transaction script depends on the organization of the system layers. This place can be a server page, a CGI script, or a distributed session object. I prefer to isolate transaction scripts as strictly as possible. In the most extreme case, you can place them in different subprograms, and better - in classes other than those that belong to the presentation and data source layers. In addition, calls routed from transaction scripts to the presentation logic code should be avoided; this will facilitate the testing of transaction scripts and their possible modification.

There are two ways to split the transaction script code into classes. The most common, straightforward and convenient in many situations is the use of a single class to implement multiple transaction scenarios. The second command following the typical solution scheme (Command) is associated with the development of a proprietary class for each transaction scenario (Fig. 3.5): a type is defined that is basic to all commands, which provides a certain execution method that satisfies the logic of the transaction scenario. The advantage of this approach is the ability to manipulate instances of scripts as objects at run time, although in systems where business logic is organized using transaction scripts, such a need arises relatively rarely. Of course, in many languages, the class model can be completely ignored, relying, say, only on global functions. However, it is quite obvious that the device for creating objects helps to overcome the problems of computational flows and facilitates data isolation.

  3.3 Patterns of organization of business logic

Figure 3.5. Using the Command Pattern in the Transaction Script Pattern

Applicability

The main advantage of a typical solution transaction script is simplicity. It is this kind of organization of logic, effective in terms of perception and performance, that is very characteristic and natural for small applications. As business logic becomes more complex, it becomes increasingly difficult to maintain it in a well-structured form. One of the notable problems associated with the repetition of code fragments. Since each transaction script is designed to serve one transaction, all common pieces of code inevitably have to be played over and over again.

Проблема может быть частично решена за счет тщательного анализа кода, но наличие более сложной бизнес-логики требует применять модель предметной области (Domain Model). Последняя предлагает гораздо больше возможностей структурирования кода, повышения степени его удобочитаемости и уменьшения повторяемости. Определить количественные критери выбора конкретного типового решения довольно сложно, особенно если одни решения знакомы вам в большей степени, нежели другие. Проект, основанный на сценарии транзакции, с помощью техники рефакторинга вполне возможно преобразовать в реализацию модели предметной области, но дело слишком хлопотно, чтобы им стоило заниматься. Поэтому, чем раньше вы расставите все точки над i, тем лучше. Однако каким бы ярым приверженцем объектных технологий вы ни становились, не отбрасывайте сценарий транзакции: существует множество простых проблем, и их решения также должны быть простыми.

3.3.2 Паттерн Domain Model

Title

Domain Model (модель предметной области).

Purpose

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

Принцип действия

The implementation of a domain model means the completion of an application with a whole layer of objects describing various aspects of a particular business area. Some objects are designed to imitate data elements that operate in this area, while others must formalize certain business rules. Functions are closely combined surrendered, which they manipulate.

Объектно-ориентированная модель предметной области часто напоминает схему соответствующей базы данных, хотя между ними все еще остается множество различий. В модели предметной области смешиваются данные и функции, допускаются многозначные атрибуты, создаются сложные сети ассоциаций и используются связи наследования. В сфере корпоративных программных приложений можно выделить две разновидности моделей предметной области. "Простая" во многом походит на схему базы данных и содержит, как правило, по одному объекту домена в расчете на каждую таблицу. "Сложная" модель может отличаться от структуры базы данных и содержать иерархии наследования, стратегии и иные шаблоны, а также сложные сети мелких взаимосвязанных объектов. Сложная модель более адекватно представляет запутанную бизнес-логику, но труднее поддается отображению в реляционную схему базы данных. В простых моделях подчас достаточно применять варианты тривиального типового решения активная запись (Active Record), в то время как в сложных без замысловатых преобразователей данных (Data Mapper) порой просто не обойтись.

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

С моделью предметной области связано большое количество различных контекстов.Простейший вариант— однопользовательское приложение, где единый граф объектов считывается из дискового файла и располагается в оперативной памяти. Такой стиль работы присущ настольным программам, но менее характерен для многоуровневых прило-жений, поскольку в них намного больше объектов. Размещение каждого объекта в памяти сопряжено с чрезмерными затратами ресурсов памяти и времени. Прелесть объектно-ориентированных систем баз данных заключается в том, что они создают впечатление, будто объекты пребывают в памяти постоянно.

Без такой системы заботиться о создании объектов вам придется самому. Обычно в ходе выполнения сеанса в память загружается полный граф объектов, хотя речь вовсе не идет обо всех объектах и, может быть, классах. Если, например, ведется поиск множества контрактов, достаточно считать информацию только о таких продуктах, которые упоминаются в этих контрактах. Если же в вычислениях участвуют объекты контрактов и зачтенных доходов, объекты продуктов, возможно, создавать вовсе не нужно. Точный перечень данных, загружаемых в память, определяется параметрами объектнореляционного отображения.

Одна из типичных проблем бизнес-логики связана с чрезмерным увеличением объектов. Занимаясь конструированием интерфейсного экрана, позволяющего манипулировать заказами, вы наверняка заметите, что только некоторые функции отличаются сугубо специфическим характером и узким назначением. Возлагая на единственный класс заказа всю полноту ответственности, вы рискуете раздуть его до непомерной величины. Что-бы избежать подобного, можно выделить общие характеристики "заказов" и сосредоточить их в одноименном классе, а все остальные функции вынести во вспомогательные классы сценариев транзакции (Transaction Script) или даже слоя представления. преобразователей данных (Data Mapper) порой просто не обойтись.

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

Applicability

Если вопросы как, касающиеся модели предметной области, трудны потому, что предмет чересчур велик, вопрос когда сложен ввиду неопределенности ситуации. Все зависит от степени сложности поведения системы. Если вам приходится иметь дело с изощренными и часто меняющимися бизнес-правилами, включающими проверки, вычисления и ветвления, вполне вероятно, что для их описания вы предпочтете объектную модель. Если, напротив, речь идет о паре сравнений значения с нулем и нескольких операциях сложения, проще прибегнуть к сценарию транзакции (Transaction Script).

Существует еще один фактор, который нельзя обойти вниманием: насколько комфортно чувствует себя команда разработчиков, манипулируя объектами домена. Изучение способов проектирования и применения модели предметной области - урок крайне сложный, пробудивший к жизни целый информационный пласт о "смене парадигмы". Чтобы привыкнуть к модели, нужны практика и советы профессионала, но зато среди тех, кто дошел до цели, редко встречаютсятакие, кто хотел бы вновь вернуться к сценарию транзакции, - разве только в самых простых случаях.

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

Встречаются ситуации, когда модель предметной области целесообразно снабдить более отчетливым интерфейсом API, и для этого можно порекомендовать типовое решение слой служб (Service Layer [4]) .

3.3.3 Паттерн Table Module

Title

Table Module (модуль таблицы)

Purpose

Одна из ключевых предпосылок объектной модели — сочетание элементов данных и пользующихся ими функций. Традиционный объектно-ориентированный подход основан на концепции объектов с идентификационными признаками в совокупности с требованиями модели предметной области (Domain Model). Если, например, речь идет о классе, представляющем сущность "служащий", любой экземпляр класса соответствует определенному служащему; коль скоро есть ссылка на объект, отвечающий служащему, с ним легко выполнять все необходимые операции, собирать информациюи следовать в направлении связей с другими объектами.

One of the challenges of the domain model is the difficulty of creating interfaces to relational databases; the latter in such a situation acquire the role of such poor relatives, with whom no one wants to deal. Therefore, reading the information from the database and writing it with the necessary transformations turns into a capricious mind game.

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

Принцип действия

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

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

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

Модуль таблицы способен содержать методы-оболочки, представляющие запросы к базе данных. Альтернативой служит шлюз таблицы данных (Table Data Gateway). Недостаток последнего обусловлен необходимостью конструирования дополнительного класса, а преимущество заключается в возможности применения единого модуля таблицы для данных из различных источников, поскольку каждому отвечает собственный шлюз таблицы данных.

The data table gateway allows you to structure information as a set of records, which is then passed to the designer of the table module as an argument (Fig. 3.6). If it is necessary to use several table modules, they can all be created on the basis of the same set of records. Then each module of the table applies business logic functions to the set of records and transfers the changed set of records to the presentation layer for displaying and editing information by means of graphical table controls. The latter are not “aware” where the data came from - directly from the relational DBMS or from the intermediate module of the table, which managed to carry out their preliminary processing. When editing is completed, the information is returned to the table module for review before being stored in the database. One of the advantages of this style is the ability to test a table module by “artificially” creating multiple records in memory without referring to the real database table.

The word "table" in the title of the standard solution emphasizes that the application provides for one module of the table for each database table stored. It is true, but not all. It is also useful to have table modules for commonly used virtual tables and queries, since the structure of the table module actually does not directly depend on the structure of the physical database tables, but is mainly determined by the characteristics of the virtual tables and queries used in the application.

Applicability

A typical solution to a table module is largely based on a tabular data structure and therefore allows obvious application in situations where access to information is provided through the mediation of sets of records. The data structure has a central role, so the methods for accessing the data in the structure should be straightforward and efficient.

  3.3 Patterns of organization of business logic

Figure 3.6 Diagram of interaction of code layers with a table module

The table module, however, does not allow using all the power of the object approach to the organization of complex business logic. You will not be able to create direct links from object to object, and the mechanism of polymorphism operates in these conditions not perfectly. Therefore, to implement a particularly sophisticated logic, the domain model is preferable. Essentially, the problem comes down to finding a compromise between the ability of the domain model to effectively map business logic and the ease of integration of application code and relational data structures provided by the table module.

If the objects of the domain model relate relatively accurately to the database tables, it may be better to apply the domain model together with the active record (Active Record). The table module, however, behaves better than a combination of the domain model and the active record, if different parts of the application are based on a common table data structure. However, in the Java environment, for example, the table module is not yet popular, although the situation may change with the proliferation of the record set model.

Most often, patterns of using a table module are seen in projects based on the Microsoft COM architecture. In COM (and .NET) technology, the set of records is the main data repository with which the application operates. Multiple records can be transferred to the control elements to reproduce information on the screen. A good mechanism for accessing relational data, represented as sets of records, is implemented in the Microsoft ADO library family. In such cases, the table module allows you to describe the business logic in a well-structured form.


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

Object oriented programming

Terms: Object oriented programming