In this part, I will show how the user interface division initially looked like and what the View and Controller were. Let me try to tell you why modern GUI libraries use their union and what interesting solutions can be found in this area today. References to the original sources are given at the beginning of the first part .
I'll start with the view. Despite the fact that the View is defined as a module that displays the Model - " and the view is a (visual) representation of its model ", in practice , all graphical GUI elements are usually referred to as a viewport; that is, the View what we see on the computer screen.
It is clear that there is some contradiction here, since such graphic components as menus, buttons, toolbars are not used to display information about the system, but primarily to control the system. The keyboard and mouse have always been the means of control of the program and were in the “list” of the Controller (no matter how it was interpreted). Therefore, it seems illogical and strange that the buttons made of plastic are considered controls and belong to the Controller, and the buttons drawn on the screen, and in fact perform the same functions (produce incoming events), for some reason belong to the View.
In addition, since it is reasonably considered that it is not good to “prescribe logic” in graphic elements, it is often concluded that the View should be thin and stupid (dumb View) and, accordingly, the logic of the interface can be found in the most unexpected places, up to the domain model (even Fowler writes about “pollution” of the Model with the settings of the GUI Architectures interface).
And again, in order to clarify the situation, we propose to turn to the "architectural principles" and primary sources. When it comes to decomposition, one of the basic “architectural” rules is that it is necessary to divide into modules primarily based on the tasks that the system solves. Each module should be responsible for solving a specific task (preferably one) and perform the corresponding function.
Accordingly, in order to understand how to divide the user interface into modules, first of all, it is necessary to analyze what it does and what tasks it solves. After all, the interface is a function , not graphic elements. And this function is to ensure user interaction with the system. What does it mean:
That is, in the general case, the user interface is bidirectional and solves two problems, one of which is connected with the output and presentation of information, and the second with the input of commands and data. It is these tasks that determine how to divide the interface into modules. Again, look at the picture from the source (Reenskaug):
As you can see, the user interface is quite naturally and logically divided into two relatively independent functional modules. Moreover, such a functional division based on solvable problems is universal. No matter the sound is an interface, graphic or touch, it should have a module responsible for entering control commands and data (hence the name Controller - control), and the module responsible. Output and presentation of information about the system and what is happening in it (View - View, presentation).
Now let's see how the View / Control division looked like in practice. And in order to do this, we need a little excursion into history. The fact is that initially the term CONTROLLER did not exist at all. Instead, Reenskaug used the term EDITOR ( MODEL-VIEW-EDITOR) and wrote about the separation of the user interface into View and Editor. " This was the first set. " (Trygve Reenskaug). I'll try to explain why.
In spite of the availability of technical capabilities (raster screens) during the creation of MVC and SmallTalk, user interfaces were still mostly command-based ( Command-Based Interface ) and were essentially ordinary text editors. In SmallTalk, the interface was called Editor. And that's how he looked:
We can say that the Editor combines the functions of the Controller and View. He made it possible to relatively conveniently enter commands and data (displaying keystrokes and processing input from the keyboard), and at the same time output information about the execution of commands and what is happening in the system in general.
Only gradually this Editor was transformed into what we are now used to understand by GUI.
Initially, a simple but very fruitful idea arose - to divide a single window into multiple panels. The multi-panel paradigm appeared much earlier than MVC (multi-panel browsers were definitely present in Smalltalk-76) and was a significant advance in itself. It is still actively used in almost all text interfaces.
Reenskaug, of course, also used it. It must be borne in mind here that Dynabook, around which smallTalk and graphical interfaces and, in particular, MVC, were created in Xerox Parc, was conceived as a “children's computer”. Therefore, the task was to make work with computer programs available to any unprepared user, in particular a child. Reenskaug proceeded from the fact that the user may be completely unaware of the program and how it works. And in order for it to interact with the program, it is necessary in some way to display to it the basic information about the system and the domain model underlying it, so that the user understands what he is dealing with.
Such information was displayed on separate panels, which actually became the View. As a rule, the domain model was displayed using several different Views: " MVC was conceived as a general solution enabling users to control large and complex data sets ... It is especially useful when the user needs to see the Model simultaneously in different contexts and / or from different points of view. "And since Reenskaug believed that the graphical presentation of information was clearer than the textual one, his main types were graphs and diagrams of various kinds.
Further. Since the user knows nothing (or almost nothing) about the system, and sees only various View, conveniently and visually displaying the information he needs, respectively, and the management of the system should have looked as if the user controlled directly the View and the fact that they are displayed. Therefore, not one “General Editor” was used to enter commands, but a whole multitude of specialized editors, each of whom was associated with his own View and was focused on entering commands (interacting with the domain model) only in the context of this View. the information that is presented by the view .
Thus, if for the specialist the interface was usually served as a general editor, giving the opportunity to enter any commands into the system (but for this it was necessary to study the manuals, know the commands and understand how the system works), then for the unprepared user the minimum interface becomes a pair - View and the associated specialized Editor (which itself will later be renamed the Controller). Such an interface provided a very reduced set of commands and capabilities, but they could be used without prior training.
The first report of Reenskaug was called: "THING-MODEL-VIEW-EDITOR. An Example from a planning system". It presented the first MVC implementation using the example of a large project planning and management system (a kind of task-manager). The domain model was the network (network) of "activities", which described what should be done (activity), in what order, for what time, who participates in what activities and what resources are required for each activity. An example was intended to show that “ one Model can be displayed with the help of many different Views” and this is how the user interface looked like:
The domain model was displayed using three different diagrams (Views). It should be noted that the views of both Reenskaug and SmallTalk were not at all “passive”, they independently processed the user's actions related to them, in particular, they allowed scrolling and selection of elements: “ A list of textual items and a possible selection within the list. It is able to make it to the scroll itself. “This is an important moment and I will come back to it.
The first diagram shows a set of activities related to a certain project / network and the connections between them. Just as the list allows you to select / highlight a certain element, this diagram allows you to select an activity. Associated with the diagram is an editor that allows you to query and edit information related to the selected activity from the system. For example: the duration of the activity, who participates in it, what activities precede and TP
The second chart - GanttView (Gantt’s calendar or timeline) shows the location of the project and its activities over time. This chart also allows you to select an activity. The editor associated with GanttView allows " to pass on to operations on the network ." In particular, it allows you to change the planned start and end date of the selected activity, as well as plan and manage the project / network as a whole.
The third diagram is a diagram of the resources required for the implementation of activities, depending on time. It is curious that not the editor is associated with this diagram, but a list, and depending on what activity is selected in this list, the resource diagram displays only those resources that relate to the selected activity. This combination of two types, one of which "controls" the displayed information of the other is characteristic of many interfaces. And the idea to use for "control" is not a text editor, but the list will form the basis of most controllers in SmallTalk-80.
The term Controller arose almost just before Reenskaug left Xerox PARC " After long discussions, particularly with Adele Goldberg ". And because of this, the original works of Reenskaug can be difficult to read, since he calls the whole interface (and in this case, writes about the primary separation of the application into Model and Editor) and the editor panels that are associated with the same View to enter commands and “control View” and which later became the Controllers themselves - “ The controller from Smalltalk-80 was called the Editor ” (Reenskaug)
Also, the responsibilities of the Controller Reenskaug assigned management of the interface itself, and in particular the set of its Views : " Controller was responsible for creating and coordinating its subordinate views ." Accordingly, he sometimes writes that the Controller is a connection between the user and the system, and sometimes it is a connection between the user and the Views and that the Controller transmits commands to the Views.
Nevertheless, as can be seen from the example, the Reenskaugovsky Editor-Controller was quite visible and had a graphic representation.
Let's see how things were in SmallTalk-80.
First, in SmallTalk-80, the text editors that Reenskaug used to enter commands became “officially” Controllers.
“ ParagraphEditor ” and “ TextEditor ”, which have standard text input and editing functions, in SmallTalk-80 were descendants of the “ Controller ” class:
Since, as already mentioned, the editors combined the Input and Output functions, they were also used to display textual information in many Views - TextView, TextEditorView.
Steve Barbeck gives a rather detailed explanation about this: " All controllers that accept keyboard input are the ParagraphEditor inheritors in the Controller hierarchy. ParagraphEditor preceded the creation of the MVC paradigm. It simultaneously performs two functions - it processes text input from the keyboard and displays on the screen. Therefore, in a sense, it is a cross between a View and a Controller. Views that use the ParagraphEditor subclasses as a controller completely overturn standard roles - for In order to display the text, they send it to their controller "[ All controllers that control the hierarchy. ParagraphEditor predates paradigm. It is a handful of ways to control the text. Roles for display controller; they implement the controller ].
I will try to write further about the reason for such “paradoxes”, for now just pay attention to it.
Second: in SmallTalk-80, each Type (subspecies) MUST be associated with its own Controller, which made it possible to perform certain operations with the information that the View displays
Accordingly, any set of Views (subspecies) that make up the user interface is in fact always accompanied by exactly the same set of Controllers associated with it. Again, Steve Barbek has a whole section devoted to this topic, which is called “Communication Between Controllers”.
Third: the main improvement was that the mouse was used rather than the keyboard for entering commands.
In SmallTalk-80, in addition to the controller editors ( ParagraphEditor and TextEditor ), MouseMenuController appears, which becomes the main tool for entering commands. User interfaces from Command-driven become Menu-driven ( User Interfaces )
Available commands for each species were formed explicitly in the form of a list. And MouseMenuController associated with the View provided for their display and convenient input a special graphical tool - pop-up pop-up menu , which appeared when you click the corresponding mouse button. So they looked like this:
I repeat: the pop-up menu belonged to MouseMenuController. The menus were a special graphical tool / tool for conveniently displaying and entering commands (defined in the context of a certain type), which the Controller associated with this View provided to the user. Here is what Krasner writes: " Although the menu can be viewed as a pair of view-controller, but most often they are considered input devices and therefore belong to the controller sphere ... MouseMenuController class is responsible for creating pop-up menus when you click a mouse button ... By default, PopUpMenus returns numeric the value that the controller that called them uses to determine what action he needs to take ... Due to the extensive use of pop-up menus, most user interface controllers are under MouseMenuController "lasso.
So the main controller SmallTalk-80 (MouseMenuController) also had its graphical part - the pop-up menu , and the separation of the user interface into Views and Controllers began to look like this (illustration taken from Glenn Krasner's article):
The menu related to MouseMenuController can be seen absolutely in all SmallTalk applications and examples. So with the expanded menus, the already mentioned Workspace and Inspector look like:
And this is what the Browser looks like, which includes 5 Views (subviews) and their corresponding Controllers
I suppose that precisely because of the wide use of pop-up menus, Reenskaug wrote that the controller in smalltalk " is an ephemeral component that View creates, if necessary, as a link between the View and input devices such as a mouse and keyboard ".
So, we can dispel another myth:
Myths: All graphical elements of the user interface belong to the View. The controller is solely a logic for handling mouse movements, keyboard keys and other incoming events produced by the user.
In fact, both in the implementation of Reenskaug and then in Smalltalk-80 most of the Controllers had a “ graphic component helping the user to enter commands and data ”. And it was these Controllers that were mainly used in user applications. Although, of course, there were Controllers without a graphic component, but they were mainly used for lower-level system tasks (more on that later).
Summing up, it turns out that the Controller is a part of the user interface that is responsible for 1) providing the user with convenient means for entering commands and data , and then 2) translating user actions into calls to the corresponding Model methods and transferring them to it.
This is how the controller itself defined Reenskaug: " The controller is the connection between the user and the system. It provides the user with a menu and other means to enter commands and data. The controller receives the result of such user actions, translates them into appropriate messages and sends these messages " [ A controller is the link between the user and the system. It provides a means for users of The controller receives these messages .]
Modern graphical interfaces (GUI) for entering commands use the whole range of available tools: text and graphic menus, buttons, pop-up pop-up menus, various switches (as in real devices), text fields for data entry (TextEditor reduced to TextField). All these elements are mainly for management, not for displaying information. In English, they are called - controls (controls).
And if we continue the analogy, the separation of the View / Controller in modern systems would look something like this:
It can be said that the Controller is the “control panel”. A View is a “overview panel” or “system monitoring panel” that includes text descriptions, lists, tables, charts, scales, light displays, and all sorts of status indicators.
The beauty of MVC is that its ideas are universal and applicable not only to information systems. It does not matter whether the device or the program, in the simplest case, the interface, as a rule, contains a control unit / panel that allows you to enter commands — the Controller, and a display unit — View.
What does this give us? Well, firstly, it becomes clear that the logic of the View cannot be placed in the Controller:
If all the logic of the GUI work were brought to the Controller, then this would violate several principles at once:
The second. Thin View, considered solely as a set of graphic elements, does not perform any function and therefore is of little use in terms of re-use. If we consider the View as a full-fledged functional module that solves a fairly general and popular task - visualization and convenient presentation of data, then with the right approach, it becomes an ideal candidate for re-use.
In this sense, the separation of the user interface into View and Controller is a very beautiful step - the Controller has absorbed most of the dependencies. The view from the Model needs only data to be displayed in a specific format. Accordingly, potentially the same View can be used to visualize information in different applications.
Recently, the concept of Dashboards (information panels) has been actively developed and used, for which sets of universal widgets are created, which allow visualizing and conveniently visualizing "anything." In contrast to the "stupid look," such " full-fledged blocks of visualization " (encapsulating its own logic, settings and able to work independently) are very much in demand and valuable by themselves.
When the View and the Controller are treated as functional modules responsible for solving certain tasks, it becomes clear that in order to encapsulate their work logic, they do not need to mix it with graphics. After all, any module, if necessary, can be divided into sub-modules and have its own internal structure.
As we found out the main SmallTalk-80 controller - MouseMenuController was not at all “just a handler of user actions with a mouse and keyboard”, in fact, he did quite a few things:
For such Controllers, the MVC architecture simply “asked”. And in SmallTalk-80 it was used: " pop-up menu are implemented as a special kind of MVC class " (Krasner).
Here it is important to understand that the Model in this “internal” MVC has nothing to do with the domain model, it is the internal auxiliary model that describes the “state” of the controller itself (in particular, which command is selected) and the logic for changing this state.
The situation is similar with the view.
Myths: The fact that View is just a “graphic” is the same idealization as the Controller is “purely logic”.
Visualization of information is not an easy task, for the solution of which, as a rule, additional data are required that characterize the very process of display. Most species used in real-world applications are rather complex objects with their “state” and the logic of its change.
For example, a View rarely can display the entire Model as a whole, it usually reflects only some part of it and it needs to “know” which “part of the Model” should be reflected at the moment. Many types allow you to "select" some elements, and then they need to store information about the secretions somewhere.
Where was this kind of additional data stored and the logic of their change? In principle, the answer is obvious and, if you remember, Reenskaug answered this question - of course, in the View itself. But! Not mixed with graphics, but in a separate sub-module / class / script, that is, in some internal model .
, , . , . , ScrollController. MVC. — .
, — Presentation Model : Presentation Model pulls the state and behavior of the view out into a model class that is part of the presentation .
! , MVC «» - . " Presentation Model is not a GUI friendly facade to a specific domain object " PresentationModel, ViewModel, ApplicationModel , .
, , , PresentationModel . Microsoft : " Presentation model class acts as a façade on the model with UI-specific state and behavior, by encapsulating the access to the model and providing a public interface that is easy to consume from the view " ( MSDN: Presentation Model )
, , . .
Java . Java Swing «application-data models» «GUI-state models» . , , Java Swing MVC. , M . , …
JList . , – ListModel . — ListSelectionModel , (item selection). – «GUI-state model»:
" The models provided by Swing fall into two general categories: GUI-state models and application-data models.
GUI state models are interfaces that define the visual status of a GUI control, such as whether a button is pressed or armed, or which items are selected in a list. GUI-state models typically are relevant only in the context of a graphical user interface (GUI).
An application-data model is an interface that represents some quantifiable data that has meaning primarily in the context of the application, such as the value of a cell in a table or the items displayed in a list. These data models provide a very powerful programming paradigm for Swing programs that need a clean separation between their application data/logic and their GUI " ( A Swing Architecture Overview ).
JTable application-data , – TableModel , GUI-state — ListSelectionModel TableColumnModel .
JButton GUI-state – ButtonModel . . , , (/ ).
, , application-data , . GUI-state , . GUI-state .
, GUI data. , . .
, ( ). ( SmallTalk — ScrollController) . GUI-state , , , / .
, : «On», , - … «On». - " ", .
. ButtonModel, isSelected() , ( ). , ButtonModel GUI-state application-data
, :
. PresentationModel "". . (2), ui-, ui-state . (1), PresentationModel. PresentationModel ApplicationModel . … , . , (, - ?). , GUI-state , .
Java Swing, – SmallTalk-80 pop-up MVC ( , ) Swing gui « MVC», , . : ViewController UI-object , IU-delegate . , : MVC meets Swing .
, « MVC» - GUI SmallTalk-80: VisualAge Smalltalk IBM, Visual SmallTalk, VisualWorks SmallTalk, MacApp… ( Smalltalk, Objects, and Design 124-125).
MVC, , , SmallTalk-80 . Why? .
SmallTalk-80 . . , «». .
, , « » .
, . ui-, Swing: " this split didn't work well in practical terms because the view and controller parts of a component required a tight coupling (for example, it was very difficult to write a generic controller that didn't know specifics about the view) ".
SmallTalk-80 : , . , : " , , , – defaultControllerClass. " [ Because view and controller classes are often designed in consort, a view's controller is often simply initialized to an instance of the corresponding controller class. To support this, the message defaultControllerClass, that returns the class of the appropriate controller, is defined in many of the subclasses of View – Glenn Krasner ].
? , " ". , SmallTalk-80 , . - ( ) , , popup menu, .
: " ; «aMessage» aMessage , «aMessage». " [ Finally, the controller messages were almost always passed directly on to the model; that is, the method for message aMessage, which was sent to the controller when the menu item aMessage was selected, was almost always implemented as ↑model aMessage ].
, «» . , pop-up , , .
, : - – , – -, GUI – ui-state . ( , ) .
, GUI smallTalk-80 ui- . : pop-up , TextEdit .
«ui-» «», , – , . .
, ui- ParagraphEditor, – , . , , (toggle button, radio button, check box) ...
. () . , , (popUpMenu), – (ListView). — .
: " , , " ( Model, View and Controller are actually roles that can be played by the objects … – The DCI Architecture: A New Vision of Object-Oriented Programming ) .
, SmallTalk-80 , , , , TextView .
? . , " " . ( ) . , , pop-up , « ». gui- — , , , … – , « » / , . ui- .
Another important idea that has definitely remained is the understanding that the interface should be divided into modules, and not into a single block or page.
As can be seen from the examples, most of the interfaces were composite and included many Views and Controllers.
For the designation of such difficult-to-composite Interfaces, Reenskaug in his second later work uses the special term “Tool” (user tool) and he has a separate section devoted to this topic, which is called “ Tool as a Composite ”.
In the figure, the Tool already shows the interface from the first Reenskaug report consisting of three blocks (which Reenskaug calls the Editor). And this is what Reenskaug writes about this:
Complex editors can be again subdivided into a Controller. This is a composite pattern.
As you can see, the Composite pattern for Reenskaug refers to the entire interface, and not to the View at all. Where did the idea come from that the Composite in MVC refers exclusively to the View?
Everything is simple - because in SmallTalk-80 each Kind had its own Controller, then the composition there was explicitly specified for Species only, and the corresponding composition (hierarchy) of the Controllers was simply “calculated”: " Since each view is associated with a unique controller, the tree view of the tree with each controller . " This decision was not particularly successful and led to the fragility of the system - it was enough to leave some Species without a Controller and the whole system collapsed. Therefore, in SmallTalk-80 a “crutch” was invented - the Controller, which was called “NoController”. This controller did nothing and, by default, contacted Views that “exclusively displayed information” and did not need a controller. Its sole purpose was to ensure that the chain of controllers corresponding to the species was not interrupted. (You can read in detail with Steve Barbek in the section “Communication Between Controllers”).
So in reality, both in SmallTalk-80 and in Reenskaug, the user interface always included not only the composition of Views, but also the exact composition of the corresponding Controllers.
And if we talk about the Composite template, then, of course, it is more correct to refer it not to the View but to the entire user interface, as is done in Reenskaug and how it is done in modern GUI libraries. The interfaces of large applications are divided into "gui-components" or widgets, which in turn can be divided into simpler components and form a tree structure.
Each such gui-component is a stand-alone module that simultaneously displays some information and processes the user's actions related to it, causing high-level events to which it is convenient to bind the execution of commands (View + Controller). He also encapsulates his work logic, usually in the form of an internal GUI-state model. That is, in essence, is MVC (or "simplified MVC"). And such full-fledged gui-components can really be developed in parallel and independently, and also reused.
The consequence of the Composite pattern and the fact that each gui component can be implemented as a small MVC is some hierarchy or recursiveness of MVC. Due to the fact that they rarely write about it, the analogs of this idea are also being rediscovered. Here is a famous article on this topic - the Hierarchical model – view – controller and an interesting discussion - the Recursive Model View Controller . And here is a picture from the article:
In practice, building interfaces from independent and fully-fledged ui-components actively uses and develops ebay. You can read about this in detail in their great article Don't Build Pages, Build Modules : " When it comes to view, people still think pages instead of building UI modules. We found that as the complexity of the pages grows, it becomes exponentially more difficult to maintain. What we we want to divide the page into small manageable parts, each of which can be developed independently. We want to get away from the idea of ​​building pages directly. Instead, we divide the page into logical UI modules and do it recursively until the module It will not be in FIRST . This means that the page is constructed from high-level modules that are built from sub-modules "in turn.
I don’t want to say that the original MVC is the only correct one. My goal was only to show that it was much more complicated and richer than the simplified schema, which we are usually presented as MVC. Creating real applications based on them is like building an airplane based on schemes from a children's designer and it’s surprising that it doesn’t fly. On the other hand, if we consider MVC not as a scheme, but first of all, as a set of architectural ideas, then it really becomes simple, logical and very understandable, and literally deduced from these ideas.
And when there is an understanding of exactly what is being done, with the help of what “tools”, for the sake of which, then MVC ceases to be “dogma” and it can be varied depending on the needs of a particular project. And the terms are not so important.
When I hear or read about the front controller or that "the controller is a single point of entry into the system," I understand that the term Controller in these guys is called the facade. And this does not mean that their architecture is wrong. On the contrary, at least it’s good that they have a Facade in general, but then you need to look at how it is implemented, whether the implementation of the business of logic and so on does not delay
When it is said that the Controller is a business logic, then it is not terrible ... Just accept that in this case the Domain Model is called the Controller. What is important is not how it is called, but how it is implemented and whether it is separated from the user interface.
The term View is often used interchangeably with the term User Interface. So, too, "can."
The point is not in terms, but in essence. It seems to me that the root of most problems lies in the fact that very few people write about the essence of MVC. Instead, the terms Model, View and Controller are taken out of the context of architectural ideas, they are given some formal definitions, and then they are often used to denote modules in poor-quality decomposition, the Observer pattern is hung, and all this is presented under the “MVC brand”.
As Wirth wrote: " The most difficult project task is to find the most adequate system decomposition into hierarchically built modules, with minimization of functions and code duplication ."
Therefore, the main idea that I wanted to convey, is that MVC is not about Model, View and Controller, not about how they are interconnected and not about the Observer pattern. MVC is about how to correctly divide the system into functionally meaningful modules that are loosely connected with each other and useful in their own right. Modules that can actually be developed and used independently can be reused ... Which is actually the basis of any good architecture.
A Model, View and Controller is just the result of the initial decomposition offered by talented people. Also, the Facade , Observer, Linker patterns are simply the tools that they used to ease connectivity and reduce complexity.
Thanks to everyone who “reached out” to the end. We will be very grateful for valid criticism. Especially interesting is the opinion of people closely acquainted with SmallTalk.
Source: https://habr.com/ru/post/322700/
All Articles