
Component frameworks allow you to quickly cost applications using ready-made building blocks - components. They allow you to quickly build applications of small and medium complexity, but it is very difficult to create large, flexible and customizable applications. Also, as the application develops, it becomes harder and harder to adapt to new customer requirements. The goal of this article is to find out the causes of these problems and find a suitable solution.
Components - Application Building Blocks

Components are the primary means of extending the functionality of an application. They are intended for reuse, have a specific interface and interact with the software environment through events. The process of creating components is somewhat different from creating an application based on them. The component should not only contain useful functionality, but also be initially designed for reuse.
Component reuse

In order for components to be reused, they must be designed according to the principle of loose coupling. For this, many frameworks implement an event model based on the Observer template. It allows multiple recipients to subscribe to the same event.
The browser is a kind of intermediary, which keeps a list of recipients. When an event occurs within a component, it is sent to all recipients by this list.
')
Thanks to the intermediary component does not know about their recipients. And recipients can subscribe to events from different components of a particular type.
Using components is easier than creating them.

Using components you can quickly create different forms, panels, windows and other components of the interface. However, in order to be able to reuse new components, they need to be turned into components.
At what cost is this achieved? To do this, determine which external events will be generated by the component, and be able to use the mechanism for sending messages.
Those. you need to create at least new event classes and define interfaces or callback methods for receiving these events. This approach adds complexity to the implementation of reusable application elements (forms, panels, windows, pages). It is good, if in system about ten components. This approach can still be followed. But what if the system consists of hundreds of elements?
If you do not follow this approach, it will lead to a strong binding between the elements of the system and will reduce to zero the chances of their reuse. And this, in turn, will entail duplication of the code, which will complicate support in the future and lead to an increase in errors in the system.
The problem is further aggravated by the fact that component users often do not know how to define and send new events for their constituent elements. But at the same time, they can easily use ready-made events defined in the component framework. Those. they know and know how to receive events, not how to create and send them.
To solve this problem, let's look at how you can simplify the use of the event model in an application.
Too much event listeners
In Java Swing, GWT, JSF, Vaadin, the Observer pattern is used to implement the event model. Where multiple recipients can subscribe to a single event. The implementation here is a list to which Event Listeners are added. When an event occurs, it is sent to all recipients from this list. Each component creates its own set of Event Listeners for one or more events.

This leads to an increase in the number of classes in the application. Which, in turn, complicates the support and development of the system.
For example, in Java, this state of affairs was before the appearance of annotations. With annotations it became possible to sign methods on certain events. An example is the implementation of the event model in CDI (
Contexts and Dependency Injection ) from Java EE 6.
public class PaymentHandler { public void creditPayment(@Observes @Credit PaymentEvent event) { ... } } public class PaymentBean { @Inject @Credit Event<PaymentEvent> creditEvent; public String pay() { PaymentEvent creditPayload = new PaymentEvent();
As well as implementing
Event Bus in Guava Libraries:

As a result, there is no need to implement multiple Event Listeners for its components. Using events in the application has become much easier.
Using Event Bus is convenient when application components are simultaneously placed on the screen and exchange messages through it, as shown in the figure below.

The title, the menu on the left, the content in the middle, the panel on the right, all of these elements are transformed into reusable components using EventBus. Since they are not directly dependent on each other, but use a common bus for communications.
Subscribed to the event - do not forget to unsubscribe!
Replacing the Event Listeners with annotations - a big step forward was made to simplify the use of the event model.
However, in order for a component to receive events from the Event Bus, it must be registered. And to stop receiving events, remove it from the list of recipients. Who should take on these responsibilities?

Also subscribe to his events and, more importantly, unsubscribe from them at the right moment. It is quite possible that a single recipient subscribes to the same event several times. This can lead to multiple re-alerts. It is also possible that many different components of the system subscribe to one event. In this case, one event can cause a series of avalanche-like events.
In order to better control the event model, you can put work with events into the configuration and assign responsibility for managing events to the application container. Since Since certain events are only available under certain application states, it is reasonable to bring this state into the configuration as well.

The controller, guided by the configuration, signs the corresponding screens for events in the Event Bus, depending on the current state of the system.
Finite State Machines were just designed for this purpose. They also contain states in which events occur. And the events that initiate state transitions.
The benefits of using Finite State Machines to configure application states.
The configuration of the application in most cases is set statically. By customizing the application using, for example, dependency injection, we specify how the application will be structured at launch. At the same time, we forget that in the process of using the application, its state changes. A state change is often rigidly prescribed in the application code, which entails the difficulty of changing it and further supporting it.

Carrying out the transitions between states in the configuration, we get a new level of flexibility in building systems. And therefore, at the stage of creating the composite elements of the application, such as forms, windows, panels, we can not worry about the state in which the application should go. This can be done later by customizing the behavior in the configuration.

In this case, all system components can communicate using a unified event sending mechanism — through a controller (Statemachine).
This approach turns all components of an application (forms, windows, panels) into reusable components that can be easily managed using the external configuration.
How effectively to use Statemachine for application configuration we will describe in the following article.
PS If you are interested, you can see sample configurations in
Enterprise SamplerIt would be interesting to know how you see the future of component architecture and its role in creating applications?
PPS A new article has been released that describes in detail how to use this solution:
Navigation: an implementation option for a corporate application