emacsway-log: Software Design, Clean Architecture, DDD, Microservice Architecture, Distributed Systems, XP, Agile, etc.
3.46K subscribers
105 photos
11 videos
19 files
1.07K links
Software Design, Clean Architecture, DDD, Microservice Architecture, Distributed Systems, Extreme Programming, SDLC, Agile, etc.

Chat: https://t.me/emacsway_chat

Consulting: @born_of_granite_bot

Persistence: https://dckms.github.io/system-architecture/
Download Telegram
emacsway-log: Software Design, Clean Architecture, DDD, Microservice Architecture, Distributed Systems, XP, Agile, etc.
Две известные статьи от Rober Martin на тему OOP vs FP: - http://blog.cleancoder.com/uncle-bob/2014/11/24/FPvsOO.html - https://blog.cleancoder.com/uncle-bob/2018/04/13/FPvsOO.html Ну а я, как поклонник Emacs и Lisp, не могу обойти вниманием его статью про…
Кстати, CQS - довольно обширная тема с довольно тонкими нюансами. Его невозможно познать, прочитав, например, статью в википедии. Только первоисточник - "Object-Oriented Software Construction" 2nd edition by Bertrand Meyer.

Я читал про CQS в многочисленных статьях и книгах, но когда я прочел о нем в первоисточнике, то я понял, что совершенно ничего о нем не знал.

#FunctionalProgramming #OOP #SoftwareDesign
Forwarded from Andrei Gordienkov
не знаю как к вам всем обратиться, но хочу поделиться успехом, что моя команда, а по большей части я, победили в том архитектурном конкурсе от O`Reilly
участвовало 100+ команд, и надо бало предаставить реальное решение. В финал вышли 10 команд. Мы победили.
https://github.com/ldynia/archcolider
для рассмотрения и отзывав
Forwarded from Andrei Gordienkov
завтра-послезавтра могу прислать ссылки на другие решения из финала
emacsway-log: Software Design, Clean Architecture, DDD, Microservice Architecture, Distributed Systems, XP, Agile, etc.
Кстати, CQS - довольно обширная тема с довольно тонкими нюансами. Его невозможно познать, прочитав, например, статью в википедии. Только первоисточник - "Object-Oriented Software Construction" 2nd edition by Bertrand Meyer. Я читал про CQS в многочисленных…
Поговорим немного о довольно дискуссионном вопросе, может ли CQRS-команда возвращать результат. CQRS лишь немного отличается от CQS по исполнению. Ввел этот термин Greg Young, поэтому, к нему и обратимся:

📝 "Starting with CQRS, CQRS is simply the creation of two objects where there [CQS] was previously only one. The separation occurs based upon whether the methods are a command or a query (the same definition that is used by Meyer in Command and Query Separation, a command is any method that mutates state and a query is any method that returns a value)... That is it. That is the entirety of the CQRS pattern. There is nothing more to it than that…"
- "CQRS, Task Based UIs, Event Sourcing agh!" by Greg Young
http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/

📝 "Command and Query Responsibility Segregation was originally considered just to be an extension of this [CQS] concept."
📝 "Command and Query Responsibility Segregation (CQRS) originated with Bertrand Meyer’s Command and Query Separation Principle."
📝 "Command and Query Responsibility Segregation uses the same definition of Commands and Queries that Meyer used and maintains the viewpoint that they should be pure. The fundamental difference is that in CQRS objects are split into two objects, one containing the Commands one containing the
Queries."

- "CQRS Documents by Greg Young"
https://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf

#DDD #Microservices #SoftwareDesign #SoftwareArchitecture #FunctionalProgramming #OOP
emacsway-log: Software Design, Clean Architecture, DDD, Microservice Architecture, Distributed Systems, XP, Agile, etc.
Поговорим немного о довольно дискуссионном вопросе, может ли CQRS-команда возвращать результат. CQRS лишь немного отличается от CQS по исполнению. Ввел этот термин Greg Young, поэтому, к нему и обратимся: 📝 "Starting with CQRS, CQRS is simply the creation…
В одном из самых авторитетных reference application eShopOnContainers от Microsoft, одна из CQRS-команд возвращает результат:

- https://github.com/dotnet-architecture/eShopOnContainers/blob/b1021c88d55d96c247eab75bde650ab4b194f706/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderDraftCommandHandler.cs#L40

- https://github.com/dotnet-architecture/eShopOnContainers/blob/b1021c88d55d96c247eab75bde650ab4b194f706/src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs#L151

Однако, в известной "Красной книге", Vaughn Vernon пишет:

📝 "This principle, devised by Bertrand Meyer, asserts the following:

"Every method should be either a command that performs an action, or a query that returns data to the caller, but not both. In other words, asking a question should not change the answer.More formally, methods should return a value only if they are referentially transparent and hence possess no side effects." [Wikipedia, CQS]

At an object level this means:

1. If a method modifies the state of the object, it is a command, and its method must not return a value. In Java and C# the method must be declared void .

2. If a method returns some value, it is a query, and it must not directly or indirectly cause the modification of the state of the object. In Java and C# the method must be declared with the type of the value it returns."


- "Implementing Domain-Driven Design" by Vaughn Vernon, Chapter "4. Architecture :: Command-Query Responsibility Segregation, or CQRS"

Другое, не менее авторитетное архитектурное руководство от Microsoft, утверждает:

📝 "A query returns data and does not alter the state of the object; a command changes the state of an object but does not return any data."
- "CQRS Journey :: Reference 2: Introducing the Command Query Responsibility Segregation Pattern :: What is CQRS?"
https://docs.microsoft.com/en-us/previous-versions/msp-n-p/jj591573(v=pandp.10)#what-is-cqrs

Противоречие? Архитектура - это, как известно, наука об ограничениях, о том, как не надо делать. Почему же тогда одно из самых авторитетных reference application, консультантами которого являются такие светила, как Cesar De la Torre, Jimmy Nilsson, Udi Dahan, Jimmy Bogard, и другие, это ограничение нарушает? Что это - компромисс, вызванный практической целесообразностью, или демонстрация принципиального архитектурно чистого решения?

Ответ на этот вопрос мы попытаемся найти в следующих постах.

#DDD #Microservices #SoftwareDesign #SoftwareArchitecture #FunctionalProgramming #OOP
emacsway-log: Software Design, Clean Architecture, DDD, Microservice Architecture, Distributed Systems, XP, Agile, etc.
В одном из самых авторитетных reference application eShopOnContainers от Microsoft, одна из CQRS-команд возвращает результат: - https://github.com/dotnet-architecture/eShopOnContainers/blob/b1021c88d55d96c247eab75bde650ab4b194f706/src/Services/Ordering/O…
Итак, начнем по порядку, ибо тему в один пост не впихнуть. Начнем с принципа CQS:

📝 "Command-Query Separation principle - Functions should not produce abstract side effects."
- "Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS"

Обратите внимание на термин abstract. B.Meyer различает abstract и concrete side effects.

📝 "Definition: concrete side effect: A function produces a concrete side effect if its body contains any of the following:
1. An assignment, assignment attempt or creation instruction whose target is an attribute.
2. A procedure call."
(там же)

📝 "Since not every class definition is accompanied by a full-fledged specification of the underlying abstract data type, we need a more directly usable definition of “abstract side effect”. This is not difficult. In practice, the abstract data type is defined by the interface offered by a class to its clients (expressed for example as the short form of the class). A side effect will affect the abstract object if it changes the result of any query accessible to these clients. Hence the definition:

Definition: abstract side effect: An abstract side effect is a concrete side effect that can change the value of a non-secret query.

The definition refers to “non-secret” rather than exported queries. The reason is that in-between generally exported and fully secret status, we must permit a query to be selectively exported to a set of clients. As soon as a query is non-secret — exported to any client other than NONE — we consider that changing its result is an abstract side effect, since the change will be visible to at least some clients." (там же)

#DDD #Microservices #SoftwareDesign #SoftwareArchitecture #FunctionalProgramming #OOP
emacsway-log: Software Design, Clean Architecture, DDD, Microservice Architecture, Distributed Systems, XP, Agile, etc.
Итак, начнем по порядку, ибо тему в один пост не впихнуть. Начнем с принципа CQS: 📝 "Command-Query Separation principle - Functions should not produce abstract side effects." - "Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter…
📝 "The Command-Query Separation principle brings referential transparency back." (там же)

📝 "Definition: referential transparency: An expression e is referentially transparent if it is possible to exchange any subexpression with its value without changing the value of e." (там же)

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

Не Команде запрещено возвращать информацию об объекте, а Запросу на получение информации об объекте запрещено нарушать ссылочную прозрачность.

На это указывает и сам B. Meyer (учтите, что Railway Oriented Programming ( https://fsharpforfunandprofit.com/rop/ ) и Result type ( https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/results ) в то время еще не было):

📝 "The first has to do with error handling. Sometimes a function with side effects is really a procedure, which in addition to doing its job returns a status code indicating how things went. But there are better ways to do this; roughly speaking, the proper O-O technique is to enable the client, after an operation on an object, to perform a query on the status, represented for example by an attribute of the object, as in

target.some_operation(…)
how_did_it_go := targetGstatus

Note that the technique of returning a status as function result is lame anyway. It transforms a procedure into a function by adding the status as a result; but it does not work if the routine was already a function, which already has a result of its own. It is also problematic if you need more than one status indicator. In such cases the C approach is either to return a “structure” (the equivalent of an object) with several components, which is getting close to the above scheme, or to use global variables — which raises a whole set of new problems, especially in a large system where many modules can trigger errors." (там же)

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

#DDD #Microservices #SoftwareDesign #SoftwareArchitecture #FunctionalProgramming #OOP
emacsway-log: Software Design, Clean Architecture, DDD, Microservice Architecture, Distributed Systems, XP, Agile, etc.
📝 "The Command-Query Separation principle brings referential transparency back." (там же) 📝 "Definition: referential transparency: An expression e is referentially transparent if it is possible to exchange any subexpression with its value without changing…
Таким образом, мы выяснили, что команда может быть функцией, возвращающей служебную информацию об успешности выполнения, если иной способ невозможен. Вернемся к основам:

📝 "Commands and queries.

A few reminders on terminology will be useful. The features that characterize a class are divided into commands and queries. A command serves to modify objects, a query to return information about objects. A command is implemented as a procedure. A query may be implemented either as an attribute, that is to say by reserving a field in each run-time instance of the class to hold the corresponding value, or as a function, that is to say through an algorithm that computes the value when needed. Procedures (which also have an associated algorithm) and functions are together called routines.

The definition of queries does not specify whether in the course of producing its result a query may change objects. For commands, the answer is obviously yes, since it is the role of commands (procedures) to change things. Among queries, the question only makes sense for functions, since accessing an attribute cannot change anything. A change performed by a function is known as a side effect to indicate that it is ancillary to the function’s official purpose of answering a query. Should we permit side effects?" (там же)

Отсюда следует ряд выводов. Основной вопрос CQS лежит в плоскости Queries, и сводится с ссылочной прозрачности.

Хотя B.Meyer и использует термин procedure, которая, по определению ничего не возвращает ("Procedure
A routine which does not return a result. (The other form of routine is the function.)" - glossary книги), он ясно выразил разделение Команд и Запросов по назначению: "A command serves to modify objects, a query to return information about objects."

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

#DDD #Microservices #SoftwareDesign #SoftwareArchitecture #FunctionalProgramming #OOP
emacsway-log: Software Design, Clean Architecture, DDD, Microservice Architecture, Distributed Systems, XP, Agile, etc.
Таким образом, мы выяснили, что команда может быть функцией, возвращающей служебную информацию об успешности выполнения, если иной способ невозможен. Вернемся к основам: 📝 "Commands and queries. A few reminders on terminology will be useful. The features…
А теперь самое важное. При обсуждении CQRS этот момент часто незаслуженно опускается. Кроме процедур-команд и функций-запросов, Bertrand Meyer вводит еще и функции-конструкторы! И вот тут кроется интересное:

📝 "Functions that create objects.

A technical point needs to be clarified before we examine further consequences of the Command-Query Separation principle: should we treat object creation as a side effect?

The answer is yes, as we have seen, if the target of the creation is an attribute a: in this case, the instruction !! a changes the value of an object’s field. The answer is no if the target is a local entity of the routine. But what if the target is the result of the function itself, as in !! Result or the more general form !! Result.make (…)?

Such a creation instruction need not be considered a side effect. It does not change any existing object and so does not endanger referential transparency (at least if we assume that there is enough memory to allocate all the objects we need).

From a mathematical perspective we may pretend that all of the objects of interest, for all times past, present and future, are already inscribed in the Great Book of Objects; a creation instruction is just a way to obtain one of them, but it does not by itself change anything in the environment. It is common, and legitimate, for a function to create, initialize and return such an object.

These observations assume that in the second form the creation procedure make does not produce side effects on any object other than the one being created." (там же)

#DDD #Microservices #SoftwareDesign #SoftwareArchitecture #FunctionalProgramming #OOP
emacsway-log: Software Design, Clean Architecture, DDD, Microservice Architecture, Distributed Systems, XP, Agile, etc.
А теперь самое важное. При обсуждении CQRS этот момент часто незаслуженно опускается. Кроме процедур-команд и функций-запросов, Bertrand Meyer вводит еще и функции-конструкторы! И вот тут кроется интересное: 📝 "Functions that create objects. A technical…
Это замечание B.Meyer является очень важным, так как наиболее частый вопрос CQRS - это возврат идентификатора созданного ресурса и исполнение требований RFC-7231 для HTTP-method POST REST API:

📝 "the origin server SHOULD send a 201 (Created) response containing a Location header field that provides an identifier for the primary resource created (Section 7.1.2) and a representation that describes the status of the request while referring to the new resource(s).
- "Section 4.3.3. POST of RFC-7231"
https://tools.ietf.org/html/rfc7231#section-4.3.3

#DDD #Microservices #SoftwareDesign #SoftwareArchitecture #FunctionalProgramming #OOP
emacsway-log: Software Design, Clean Architecture, DDD, Microservice Architecture, Distributed Systems, XP, Agile, etc.
Это замечание B.Meyer является очень важным, так как наиболее частый вопрос CQRS - это возврат идентификатора созданного ресурса и исполнение требований RFC-7231 для HTTP-method POST REST API: 📝 "the origin server SHOULD send a 201 (Created) response containing…
Говоря о side effect ( https://t.me/emacsway_log/278 ), B.Meyer накладывает ограничение на "abstract side effect", и поясняет на примере. Сразу скажу, без прочтения главы 11 вряд ли можно понять о чем здесь идет речь. Но обойти вниманием этот пример тоже нельзя.

📝 "Unfortunately, this would be unacceptably restrictive, explaining why the Command-Query Separation principle only prohibits abstract side effects, a notion that will now be defined. The problem is that some concrete side effects are not only harmless but necessary. They are of two kinds.

<...>

Side effects of the second acceptable category may change the state of the object, but only affecting properties that are not visible to clients. To understand the concepts in depth, it will be useful to make sure that you are familiar with the discussion of “abstraction function” and “implementation invariants” in the presentation of Design by Contract. (In particular, take a look at the accompanying figures to refresh your memory.)

We saw then that an object of our software (a concrete object) is the representation of an abstract object, and that two concrete objects may represent the same abstract object.

For example two different stack representations, each made of an array and a top marker count, represent the same stack if they have the same value for count and the same array elements up to index count. They may differ in other properties, such as the array sizes and the values stored at indices above count. In mathematical terms, every concrete object belongs to the domain of the abstraction function a, and we can have c1 ≠ c2 even with a(c1) = a(c2).

What this means for us is that a function that modifies a concrete object is harmless if the result of this modification still represents the same abstract object — yields the same a value. For example assume in a function on stacks contains the operation

representation.put (some_value, count + 1)

(with the guarantee that the array’s capacity is at least count + 1). This side effect changes a value above the stack-significant section of the array; it can do no ill.

More generally, a concrete side effect which changes the concrete state of an object c is an abstract side effect if it also changes its abstract state, that is to say the value of a (c) (a more directly usable definition of abstract side effects will appear shortly). If a side effect is only concrete — does not affect the abstract state — it is harmless.

In the object-as-machine metaphor, functions producing concrete-only side effects correspond to query buttons that may produce an internal state change having absolutely no effect on the answers given by any query button. For example the machine might save energy by automatically switching off some internal circuits if nobody presses a button for some time, and turning them on again whenever someone presses any button, queries included. Such an internal state change is unnoticeable from the outside and hence legitimate." (там же)

#DDD #Microservices #SoftwareDesign #SoftwareArchitecture #FunctionalProgramming #OOP
emacsway-log: Software Design, Clean Architecture, DDD, Microservice Architecture, Distributed Systems, XP, Agile, etc.
Говоря о side effect ( https://t.me/emacsway_log/278 ), B.Meyer накладывает ограничение на "abstract side effect", и поясняет на примере. Сразу скажу, без прочтения главы 11 вряд ли можно понять о чем здесь идет речь. Но обойти вниманием этот пример тоже нельзя.…
И последнее сообщение на тему CQS. Далее мы будем рассматривать уже CQRS. Как видим, тема CQS намного более обширна и тонка, чем может показаться на первый взгляд. И за один день её точно не освоить.

Для погружения в CQRS нужно обратить внимание на еще два существенных момента.

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

📝 "Function clone creates a new object as a carbon copy of an existing one. Sometimes the target object already exists; all we want to do is to overwrite its fields. Procedure copy achieves this. It is called through the instruction x.copy (y)"
- "Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "8.6 OPERATIONS ON REFERENCES :: Object copying"

Именно на этом основан Notification Pattern, который широко применяется в языках, не поддерживающих механизм исключений (Golang, например):
https://martinfowler.com/eaaDev/Notification.html

Как можно организовать ссылочную связь через сетевое взаимодействие? Через идентификатор адресации в виде callback url.

И второй момент - это известный кейс с примером, широко известным как метод .pop(), который одновременно и удаляет, и возвращает элемент списка.

B.Meyer решает эту проблему с помощью концепции буффера:

📝 "buffer — the concurrent equivalent of a first-in, first out queue."
- "Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "23.1 SIDE EFFECTS IN FUNCTIONS :: Objections"

И приводит пример:

next_element := buffer.item
buffer.remove

📝 "With the notation of this chapter, it is easy to obtain exclusive access without sacrificing the Command-Query Separation principle: simply enclose the two instructions above, with buffer replaced by b, in a procedure of formal argument b, and call that procedure with the attribute buffer as argument."
- "Object-Oriented Software Construction" 2nd edition by Bertrand Meyer, chapter "30.12 DISCUSSION :: Support for command-query separation"

Вы уже, наверное, догадались, что я подвожу к паттерну "Asynchronous Request-Reply pattern" ( https://docs.microsoft.com/en-us/azure/architecture/patterns/async-request-reply ), использующему "202 Response Status Code" ( https://tools.ietf.org/html/rfc7231#section-6.3.3 ).

#DDD #Microservices #SoftwareDesign #SoftwareArchitecture #FunctionalProgramming #OOP
emacsway-log: Software Design, Clean Architecture, DDD, Microservice Architecture, Distributed Systems, XP, Agile, etc.
И последнее сообщение на тему CQS. Далее мы будем рассматривать уже CQRS. Как видим, тема CQS намного более обширна и тонка, чем может показаться на первый взгляд. И за один день её точно не освоить. Для погружения в CQRS нужно обратить внимание на еще два…
Было много всего написано, поэтому подведем итог:

1. CQS - это больше о Query, нежели о Command, где основная цель - достижение referential transparency:
- https://t.me/emacsway_log/279

2. Query не должен иметь abstract side effect, но может иметь concrete side effect:
- https://t.me/emacsway_log/278
- https://t.me/emacsway_log/283

3. Кроме Command и Query существуют еще и функции-конструкторы. Накладывается ли на функцию-конструктор ограничение на side effect - зависит от контекста применения:
- https://t.me/emacsway_log/281

4. B.Meyer считал, что Command не должен возвращать служебную информацию об успешности принятия и выполнения Command потому, что в то время не располагал такими механизмами, которые имеются в нашем распоряжении сегодня:
- https://t.me/emacsway_log/279

5. Предыдущий пункт возникает именно из-за того, что команды, возвращающие значение, по мнению самого B.Meyer, все-таки могут быть:
- https://t.me/emacsway_log/279

6. Основная обязанность, которую Query отбирает у Command - это возврат информации об объекте. Мейер не говорит ничего о том, что делать со служебной информацией, которая не касается состояния самого объекта, за исключением случая, описанного в п.4:
- https://t.me/emacsway_log/280

7. Процедура не возвращает значения, но может изменить объект, переданный аргументом по ссылке. Эту возможность широко использует паттерн Notification.
- https://t.me/emacsway_log/284

8. Для разделения атомарных операций Command и Query (list.pop()) используется коцепция буффера:
- https://t.me/emacsway_log/284

9. Пункты 7 и 8 находят свое отражение в Asynchronous Request-Reply pattern:
- https://t.me/emacsway_log/284

10. Существует требование RFC-7231, которое гласит, что при создании объекта методом POST, сервер должен вернуть идентификатор созданного ресурса. И здесь уместно вспомнить про функции-конструкторы:
- https://t.me/emacsway_log/282

11. Reference Transparency открывает все выгоды использования Functional Programming, что становится особенно востребованным в распределенной среде:
- https://t.me/emacsway_log/264

#DDD #Microservices #SoftwareDesign #SoftwareArchitecture #FunctionalProgramming #OOP