IT 118 - SIA - Module 5
IT 118 - SIA - Module 5
Module 5
Software Architectural Patterns
Architectural Pattern
It’s all too common for developers to start coding an application without a formal architecture in place.
Without a clear and well defined architecture, most developers and architects will resort to the de facto
standard traditional layered architecture pattern (also called the n-tier architecture), creating implicit
layers by separating source-code modules into packages. Unfortunately, what often results from this
practice is a collection of unorganized source-code modules that lack clear roles, responsibilities, and
relationships to one another. This is commonly referred to as the big ball of mud architecture anti-
pattern.
Applications lacking a formal architecture are generally tightly coupled, brittle, difficult to change, and
without a clear vision or direction. As a result, it is very difficult to determine the architectural
characteristics of the application without fully understanding the inner-workings of every component
and module in the system. Basic questions about deployment and maintenance are hard to answer:
Does the architecture scale? What are the performance characteristics of the application? How easily
does the application respond to change? What are the deployment characteristics of the application?
How responsive is the architecture?
An architectural pattern is a proven structural organization schema for software systems. It helps define
the basic characteristics and behavior of an application. For example, some architecture patterns
naturally lend themselves toward highly scalable applications, whereas other architecture patterns
naturally lend themselves toward applications that are highly agile. Knowing the characteristics,
strengths, and weaknesses of each architecture pattern is necessary in order to choose the one that
meets your specific business needs and goals.
As an architect, you must always justify your architecture decisions, particularly when it comes to
choosing a particular architecture pattern or approach. The goal of this report is to give you enough
information to make and justify that decision.
Patterns
A pattern also describes rules and guidelines for organising the relationships among the subsystems.
The relationship between the client and the server is that the client asks questions and the server
answers them.
Patterns are written by people with lots of experience. Knowledge which could have remained hidden
in the heads of these experienced people is made explicit in the form of patterns. This enables others
to learn from that experience. Patterns are not constructed by a single person: they reflect the
experience of many developers. They capture existing, well-proven solutions in software development
and help to promote good design practices.
Architectural Style
Architectural patterns are also called Architectural styles, or standard architectures, but the word
architectural style is more often used for a concept that is less fine-grained than a pattern; several
patterns may therefore belong to the same architectural style. We will explain the subtle differences
later in this learning unit.
When a certain kind of problem is solved by many developers in a similar way, and it is generally
accepted that this way solves that problem well, it becomes a pattern. A pattern is therefore something
that addresses a recurring design problem for which a general solution is known among experienced
practitioners: a pattern documents existing design solutions that have proved their worth.
By writing a pattern, it becomes easier to reuse the solution. Patterns provide a common vocabulary
and understanding of design solutions.
Pattern names become part of a widespread design language. They remove the need to use a lengthy
description to explain a solution to a particular problem. Patterns are therefore a means for documenting
software architectures. They help maintain the original vision when the architecture is extended and
modified, or when the code is modified (but they cannot guarantee it).
Patterns support the construction of software with defined properties. When we design a client-server
application, for instance, the server should not be built in such a way that it initiates communication with
its clients.
Many patterns explicitly address non-functional requirements for software systems. For example, the
MVC (Model-View-Controller) pattern supports changeability of user interfaces. Patterns may thus be
seen as building blocks for a more complicated design.
Patterns are described using a pattern template or pattern schema. All of the many different templates
have at least the following components:
problem: the recurring problem in that context. A solution to the problem should fulfil
requirements, consider constraints and have desirable properties. These conditions are called
forces. Forces may conflict with each other (performance may conflict with extensibility, for
instance). Forces differ in the degree to which they are negotiable
solution: a proven solution for the problem. The solution is given as a structure with components
and relationships and as a description of the run-time behaviour. The first description is a static
model of the solution; the second is a dynamic one.
What is the difference between design patterns and architectural patterns? Design patterns offer a
common solution for a common problem in the form of classes working together. They are thus smaller
in scale than architectural patterns, where the components are subsystems rather than classes.
Design patterns do not influence the fundamental structure of a software system. They only affect a
single subsystem. Design patterns may help to implement an architectural pattern. For example, the
Observer pattern (a design pattern) is helpful when implementing a system according to the MVC
architectural pattern.
1. Layered Pattern
The most common architecture pattern is the layered architecture pattern, otherwise known as the n-
tier architecture pattern. We often use ‘N-tier architecture’, or ‘Multi-tiered architecture’ to denote
“layered architecture pattern”. It’s one of the most commonly used patterns where the code is arranged
in layers.
The Layers pattern helps to structure applications that can be decomposed into groups of subtasks,
each of which is at a particular level of abstraction. Each layer provides services to the next higher
layer. Services in a layer are implemented using services from the next lower layer. Service requests
are frequently done by using synchronous procedure calls.
In short, this pattern means that conceptually different issues are implemented separately, and that
layers of a higher abstraction level use services of a lower abstraction level, and not the other way
around.
A lower layer can be used by different higher layers. The TCP layer from TCP/IP connections,
for instance, can be reused without changes by various applications, such as telnet or FTP.
Layers make standardization easier: clearly defined and commonly accepted levels of
abstraction make it possible to develop standardized tasks and interfaces.
Dependencies are kept local. When a layer shows the agreed interface to the layer above, and
expects the agreed interface of the layer below, changes can be made within the layer without
affecting other layers. This means a developer can test particular layers independently of other
layers, and can develop them independently as well: this supports development by teams.
Components within the layered architecture pattern are organized into horizontal layers, each layer
performing a specific role within the application (e.g., presentation logic or business logic). Although
the layered architecture pattern does not specify the number and types of layers that must exist in the
pattern, most layered architectures consist of four standard layers: presentation, business, persistence,
and database. In some cases, the business layer and persistence layer are combined into a single
business layer, particularly when the persistence logic (e.g., SQL or HSQL) is embedded within the
business layer components. Thus, smaller applications may have only three layers, whereas larger and
more complex business applications may contain five or more layers.
Each layer of the layered architecture pattern has a specific role and responsibility within the
application. For example, a presentation layer would be responsible for handling all user interface and
browser communication logic, whereas a business layer would be responsible for executing specific
business rules associated with the request. Each layer in the architecture forms an abstraction around
the work that needs to be done to satisfy a particular business request. For example, the presentation
layer doesn’t need to know or worry about how to get customer data; it only needs to display that
information on a screen in particular format. Similarly, the business layer doesn’t need to be concerned
about how to format customer data for display on a screen or even where the customer data is coming
from; it only needs to get the data from the persistence layer, perform business logic against the data
(e.g., calculate values or aggregate data), and pass that information up to the presentation layer.
One of the powerful features of the layered architecture pattern is the separation of concerns among
components. Components within a specific layer deal only with logic that pertains to that layer. For
example, components in the presentation layer deal only with presentation logic, whereas components
residing in the business layer deal only with business logic. This type of component classification makes
it easy to build effective roles and responsibility models into your architecture, and also makes it easy
to develop, test, govern, and maintain applications using this architecture pattern due to well-defined
component interfaces and limited component scope.
Notice in figure above that each of the layers in the architecture is marked as being closed. This is a
very important concept in the layered architecture pattern. A closed layer means that as a request
moves from layer to layer, it must go through the layer right below it to get to the next layer below that
one. For example, a request originating from the presentation layer must first go through the business
layer and then to the persistence layer before finally hitting the database layer.
So why not allow the presentation layer direct access to either the persistence layer or database layer?
After all, direct database access from the presentation layer is much faster than going through a bunch
of unnecessary layers just to retrieve or save database information. The answer to this question lies in
a key concept known as layers of isolation.
The layers of isolation concept means that changes made in one layer of the architecture generally
don’t impact or affect components in other layers: the change is isolated to the components within that
layer, and possibly another associated layer (such as a persistence layer containing SQL). If you allow
the presentation layer direct access to the persistence layer, then changes made to SQL within the
persistence layer would impact both the business layer and the presentation layer, thereby producing
a very tightly coupled application with lots of interdependencies between components. This type of
architecture then becomes very hard and expensive to change.
While closed layers facilitate layers of isolation and therefore help isolate change within the architecture,
there are times when it makes sense for certain layers to be open. For example, suppose you want to
add a shared-services layer to an architecture containing common service components accessed by
components within the business layer (e.g., data and string utility classes or auditing and logging
classes). Creating a services layer is usually a good idea in this case because architecturally it restricts
access to the shared services to the business layer (and not the presentation layer). Without a separate
layer, there is nothing architecturally that restricts the presentation layer from accessing these common
services, making it difficult to govern this access restriction.
In this example, the new services layer would likely reside below the business layer to indicate that
components in this services layer are not accessible from the presentation layer. However, this presents
a problem in that the business layer is now required to go through the services layer to get to the
persistence layer, which makes no sense at all. This is an age-old problem with the layered architecture,
and is solved by creating open layers within the architecture.
As illustrated in figure below, the services layer in this case is marked as open, meaning requests are
allowed to bypass this open layer and go directly to the layer below it. In the following example, since
the services layer is open, the business layer is now allowed to bypass it and go directly to the
persistence layer, which makes perfect sense.
Leveraging the concept of open and closed layers helps define the relationship between architecture
layers and request flows and also provides designers and developers with the necessary information
to understand the various layer access restrictions within the architecture. Failure to document or
properly communicate which layers in the architecture are open and closed (and why) usually results
in tightly coupled and brittle architectures that are very difficult to test, maintain, and deploy.
Pattern Example
To illustrate how the layered architecture works, consider a request from a business user to retrieve
customer information for a particular individual as illustrated in figure below. The black arrows show the
request flowing down to the database to retrieve the customer data, and the red arrows show the
response flowing back up to the screen to display the data. In this example, the customer information
consists of both customer data and order data (orders placed by the customer).
The most stable abstractions are in the lower layer: a change in the behaviour of a layer has no effect
on the layers below it. The opposite is true as well: a change in the behaviour of a lower layer has an
effect on the layers above it, so this should be avoided.
Of course, changes in or additions to a layer without an effect on behaviour will not affect the layers
above it. Layer services can therefore be implemented in different ways (think of the Bridge pattern
here, where a dynamic link is maintained between abstraction and implementation).
Layers can be developed independently. However, defining an abstract service interface is not an easy
job. There may also be performance overhead due to repeated transformations of data. Furthermore,
the lower layers may perform unnecessary work that is not required by the higher layers.
In a Relaxed layered system, each layer may use the services of all layers below it, not only of
the next lower layer. This has efficiency benefits, but leads to a loss of maintainability. Windows’
microkernel architecture is an example of this variant. The user interface of Eclipse forms
another example: Eclipse makes use of the SWT (the Standard WidgetToolkit) and JFace. JFace
is a layer on top of the SWT and offers a higher level of abstraction than SWT, but it is possible
to use classes of both JFace and the SWT in the same application
Another variant is to allow callbacks for bottom-up communication: here, the upper layer
registers a callback function with the lower layer, as a result of which the upper layer is notified
when an event occurs.
2. Client-server Pattern
“Client-server software architecture pattern” is another commonly used one, where there are 2 entities.
It has a set of clients and a server. This architecture is used when a server and clients are connecting
through the internet. In here, Server is the service provider. And the client is the service consumer or
requester. Although both client and server may be located within the same system, they often
communicate over a network on separate hardware. Normally server is located in a local area network
or in the internet. If the server is located in a local area network, outsiders can’t access the server but
insiders can. There are some methods to deploy a server as follows,
In the Client-server architectural pattern, a server component provides services to multiple client
components. A client component requests services from the server component. Servers are
permanently active, listening for clients. The requests are sent beyond process and machine
boundaries. This means that some inter-process communication mechanism must be used: clients and
servers may reside on different machines, and thus in different processes. In fact, you can see the
Client-server pattern as a form of the layered pattern, crossing process or machine boundaries: clients
form the higher level and the server forms the lower level.
The client component initiates certain interactions with the server to generate the services needed.
While the client components have ports that describe the needed services, the servers have ports that
describe the services they provide. Both components are linked by request/reply connectors. The use
of a server is client send requests and server respond to that. A classic example of this architecture
pattern is the World Wide Web. The client-server pattern is also used for online applications such as
file sharing and email. Other examples of the Client-server pattern are remote database access (client
applications request services from a database server), remote file systems (client systems access files,
provided by the server system; applications access local and remote files in a transparent manner) or
web-based applications (browsers request data from a web server).
Another simple example is online banking services. When a bank customer accesses online banking
services using a web browser, the client initiates a request to the bank's web server. In this case, the
web browser is the client, accessing the bank's web server for data using the customer's login details.
The application server interprets this data using the bank's business logic and then provides the
appropriate output to the web server.
One major advantage of this architecture pattern is the central computing of data; all files are stored in
a central location for this network. Therefore, the data, as well as the network peripherals, are centrally
controlled. Other advantages of this pattern is as follows:
Instructor: Amie Dainne S. Esteves • A.Y. 2022-2023
Page 9 of 23
Bicol University College of Science
CS/IT Department IT 118 - System Integration and Architecture
Legazpi City Module 5: Software Architectural Patterns
Clients access data from a server using authorized access, which improves the sharing of data.
Accessing a service is via a ‘user interface’ (UI), therefore, there’s no need to run terminal
sessions or command prompts.
Client-server applications can be built irrespective of the platform or technology stack.
This is a distributed model with specific responsibilities for each component, which makes
maintenance easier.
A disadvantage, however, is that the server is expensive to purchase and manage. Another
disadvantages of this pattern is as follows:
The server can be overloaded when there are too many requests.
A central server to support multiple clients represents a ‘single point of failure’.
Requests are typically handled in separate threads on the server.
Interprocess communication causes overhead. Requests and result data often have to be
transformed or marshaled because they have a different representation in client and server, and
there is network traffic.
Distributed systems with many servers with the same function should be transparent for clients:
there should be no need for clients to differentiate between servers. When you type in the URL
for Google for instance, you should not have to know the exact machine that is accessed
(location transparency), the platform of the machine (platform transparency), or the route your
request travels, and so on. Intermediate layers may be inserted for specific purposes: caching,
security, load balancing for instance.
Sometimes, callbacks are needed for event notification. This can also be seen as a transition to
the Peer-to-peer pattern.
The client-server model is related to the peer-to-peer architecture pattern and is often described as a
subcategory of this pattern. The latter uses a decentralized system in which peers communicate with
each other directly.
Clients and servers are often involved in ‘sessions’. This can be done in two different ways:
With a stateless server, the session state is managed by the client. This client state is sent with
each request. In a web application, the session state may be stored as URL parameters, in
hidden form fields, or by using cookies. This is mandatory for the REST architectural style for
web applications.
With a stateful server, the session state is maintained by the server, and is associated with a
client-id.
State in the Client-server pattern influences transactions, fault handling and scalability. Transactions
should be atomic, leave a consistent state, be isolated (not affected by other requests) and durable.
These properties are hard to obtain in a distributed world.
Concerning fault handling, state maintained by the client means for instance that everything will be lost
when the client fails. Client-maintained state poses security issues as well, because sensitive data must
be sent to the server with each request. Scalability issues may arise when you handle the server state
in-memory: with many clients using the server at the same time, many states have to be stored in
memory at the same time as well.
REST architecture
REST stands for Representational State Transfer. A REST architecture is a client-server architecture,
where clients are separated from servers by a uniform interface. Communication is stateless. A server
may be stateful, but in that case, each server-state should be addressable (for instance, by a URL).
Servers offer addressable Resources. A REST architecture is also a layered system: for a client, it is
transparent whether it is directly connected to a server, or through one or more intermediaries.
Web applications with stateless communication follow the rules of this pattern.
3. Master-slave Pattern
This pattern consists of two parties; master and slaves. The master component distributes the work
among identical slave components, and computes a final result from the results which the slaves return.
It is used to improve system reliability and performance by dividing work between the master and slave
components. Each component has distinct responsibilities. All slave components have identical or at
least similar work, and that work must be defined prior to runtime. This pattern is not a divide-and-
conquer approach to architecture; rather, it is one where the slaves' work is predefined and must be
coordinated. The goal of the master–slave architectural pattern is to improve software efficiency.
The master-slave pattern is applied for designing a system if the system involves similar or identical
computations that need to be performed repeatedly with separate set of inputs and context. In contrast,
the client-server pattern focuses on multiple users and requests. The master-slave pattern provides
an example of delegating work within a system.
Master-slave architecture pattern is useful when clients make multiple instances of the same request.
The requests need simultaneous handling. The Master-slave pattern is applied for instance in process
control, in embedded systems, in large-scale parallel computations, and in fault-tolerant systems.
The Master-Slave pattern is often used for multi-threaded applications in which many instances of the
same problem must be solved. (Travelling Salesman Problem, for example.) The master creates and
launches slaves to solve these instances in "parallel". When all of the slaves have finished, the master
harvests the results.
Any application involving multi-threading can make use of this pattern, e.g., monitoring applications
used in electrical energy systems.
This pattern doesn’t support automated fail-over systems since a slave needs to be manually
promoted to a master if the original master fails.
Writing data is possible in the master only.
Failure of a master typically requires downtime and restart, moreover, data loss can happen in
such cases.
The strength of this pattern is the ability for a request to be shared across resources. However, note
that this does not come for free. Additional work is done to split up the task and merge the results.
That alone can be resource-intensive based on the job. Therefore, we should only use this pattern with
large jobs that have well-defined ways to split them up.
An example is processing a set of data. Each item within the collection can be shipped off to a slave
process and then results returned. Thus, the work is broken down per item, and we can spread the
work across the slaves available. Likewise, there are types of work within a request that make for good
lines to split it up. For example, there may be data manipulation required, storage retrieval, and
computations to be done. Again, these chunks of work can be sent to slaves that are best suited for
each type of work.
4. Pipe-filter Pattern
Pipe and Filter is another architectural pattern, which has independent entities called filters
(components) which perform transformations on data and process the input they receive, and pipes,
which serve as connectors for the stream of data being transformed, each connected to the next
component in the pipeline.
Many systems are required to transform streams of discrete data items, from input to output. Many
types of transformations occur repeatedly in practice, and so it is desirable to create these as
independent, reusable parts, Filters.
A single filter can consume data from, or produce data to, one or more ports. They can also run
concurrently and are not dependent. The output of one filter is the input of another, hence, the order is
very important. A pipe has a single source for its input and a single target for its output. It preserves the
sequence of data items, and it does not alter the data passing through.
However, there are a few drawbacks to this architecture and are discussed below:
Addition of a large number of independent filters may reduce performance due to excessive
computational overheads.
Not a good choice for an interactive system.
Pipe-and-fitter systems may not be appropriate for long-running computations.
The architectural pattern is very popular and used in many systems, such as the text-based utilities in
the UNIX operating system. Whenever different data sets need to be manipulated in different ways,
you should consider using the pipe and filter architecture. More specific implementations are discussed
below:
1. Compilers:
The front-end is responsible for parsing the input language and performing syntax and semantic and
then transforms it into an intermediate language. The middle-end takes the intermediate representation
and usually performs several optimization steps on it, the resulting transformed program in is passed
to the back-end which transforms it into language B.
Each level consists of several steps as well, and everything together forms the pipeline of the compiler.
2. UNIX Shell:
The Pipeline is one of the defining features of the UNIX shell, and obviously, the same goes for Linux,
MacOS, and any other Unix-based or inspired systems. In a nutshell, it allows you to tie the output of
one program to the input of another. The benefit it brings is that you don’t have to save the results of
one program before you can start processing it with another. The long-term and even more important
benefit is that it encourages programs to be small and simple.
There is no need for every program to include a word-counter if they can all be piped into wc. Similarly,
no program needs to offer its own built-in pattern matching facilities, as it can be piped into grep. In the
provided example, the input.txt is read and the output is then provided to grep as input which searches
for the pattern “text” and then passes the results to sort, which sorts the results and outputs into the
file, output.txt.
5. Broker Pattern
The Broker pattern is used to structure distributed systems with decoupled components, which interact
by remote service invocations. Such systems are very inflexible when components have to know each
other’s location and other details. A broker component is responsible for the coordination of
communication among components: it forwards requests and transmits results and exceptions.
A broker component coordinates the requests, responses, error and results between the components.
Platforms such as Microsoft’s OLE (Object Linking and Embedding) [BRO 94] and OMG’s CORBA
[OMG 92], IBM’s SOM and DSOM [CAM 94] are based on this pattern. The groups of users who could
benefit from this pattern are those working with existing broker systems and interested in understanding
the system, those who want to build lean system out of the existing systems or those who want to build
a full-fledged Broker system.
Servers publish their capabilities (services and characteristics) to a broker. Clients request a service
from the broker, and the broker then redirects the client to a suitable service from its registry. Using the
Broker pattern means that no other component than the broker needs to focus on low-level
interprocess-communication.
A broker component coordinates requests and responses between clients and servers.
The broker has the details of the servers and the individual services they provide.
Clients send requests, and the broker finds the right server to route the request to.
It also sends the responses back to the clients.
A broker is a messenger that is responsible for the transmission of requests from the clients to the
servers and the responses or the error message back to the client. The broker must have some means
of locating the receiver of a request based on unique system identification. It offers APIs to the Client
and the Server for the above operations.
The client side proxies represent a layer between clients and the broker. This additional layer is used
for the transparency purposes. Proxies help in hiding implementation details form the clients like inter
process communication messages. Marshalling of parameters and results. Proxies are also responsible
for translation of the pattern specified in the broker into object model used in the programming language
in the client. Server side proxies are responsible for receiving requests and unpacking them and
invoking the appropriate services.
The pattern offers location transparency to the clients. Clients do not have any information about the
location of the servers. The functionality of the servers could change, as long as the interfaces remain
the same. The use of proxies and bridges increase the reusability of the components. Portability, the
broker hides the operating system and network details from the clients and the servers. This enables
the clients and the server components to be ported to different components. Different broker system
can communicate if they all understand the same protocol.
This pattern is not without its liabilities. It is usually seen that applications using brokers are slower than
application distributions that are static and known. Most of the bindings are implementation specific in
nature. A broker-based system also offers a lower fault tolerance when compared to a non-distributed
software system.
The Broker pattern allows dynamic change, addition, deletion and relocation of objects, and it makes
distribution transparent to the developer. It requires standardization of service descriptions. When two
brokers cooperate, bridges may be needed to hide implementation details.
6. Peer-to-peer Pattern
In this pattern, individual components are known as peers. Peers may function both as a client,
requesting services from other peers, as a server, providing services to other peers and it can change
its role dynamically with time.
The peer-to-peer (P2P) architectural pattern, consists of a series of nodes, each with the same set of
functions to perform. With this pattern, there is no central controller and all nodes are created equally.
The peer nodes act as both receivers and distributors of data and resources. The description of peer-
to-peer is even less complex than client-server. We have two nodes with a bi-directional link between
them. Each node can serve as a client or as a server. Therefore, we also see this at times when we
want to keep two machines synchronized for load balance and fail-over purposes. The network can
expand to any number of nodes. However, each node connects to another as both a client and a
server, so direct communication is always available.
While there are many benefits for a peer-to-peer network, the primary focus is keeping each node
current with data. That data may be a file, a list of transactions, or even authorization lists. Any given
node may interact with numerous other nodes, but those interactions will always go both ways. Thus,
an update on node A may be broadcast to nodes B through Z, and then an update on Z may go out to
A through Y.
The following are examples of the Peer-to-Peer pattern: the Domain Name System for the internet, the
distributed search engine Sciencenet, multi-user applications like a drawing board and Peer-to-Peer
file-sharing like Gnutella [60] or BitTorrent.
An advantage of the Peer-to-Peer pattern is that nodes may use the capacity of the whole, while
bringing in only their own capacity. In other words, there is a low cost of ownership through sharing.
Also, administrative overhead is low, because Peer-to-Peer networks are self- organizing.
The Peer-to-Peer pattern is scalable and resilient to failure of individual peers. Also, the configuration
o f a system may change dynamically: peers may come and go while the system is running.
A disadvantage may be that there is no guarantee about quality of service, as nodes cooperate
voluntarily. For the same reason, security is difficult to guarantee. Performance grows when the number
of participating nodes grows, which also means that it may be low when there are few nodes.
7. Event-Bus Pattern
This pattern primarily deals with events and has 4 major components; event source, event listener,
channel and event bus. Sources publish messages to particular channels on an event bus. Listeners
subscribe to particular channels. Listeners are notified of messages that are published to a channel to
which they have subscribed before.
The Event-Bus pattern is a pattern that deals with events. It works as follows: event sources publish
messages to particular channels on a Channel event bus. Event listeners subscribe to particular
channels. Listeners are notified of messages that are published to a channel to which they have
subscribed.
Channels may be implicit. An explicit channel means that a subscriber subscribes directly to a specific
named publisher; an implicit channel means that a subscriber subscribes to a specific named channel
and does not need to know which producers produce for that channel
The Event-Bus pattern is used in process monitoring, in trading systems and in software development
environments. Another example is real-time data distribution middleware like OpenSplice.
The Event-Bus pattern has the following characteristics. New publishers, subscribers and connections
can be added easily, possibly dynamically. Delivery issues are important: for the developer of an event
listener, it is important to realize that assumptions about ordering, distribution and timeliness are hard
to formulate. Scalability may also be a problem, as all messages travel through the same event bus:
with an increase in the number of messages, the capacity of the event bus may turn into a bottleneck.
The Event-Bus pattern also allows several variations. The bus can provide event transformation
services, for instance, or the bus can provide coordination to script specific tasks.
8. Model-View-Controller Pattern
In the Model-View-Controller pattern, or MVC pattern, an interactive application is divided into three
parts:
The Model contains only the pure application data, it contains no logic describing how to present
the data to a user.
The View presents the model’s data to the user. The view knows how to access the model’s
data, but it does not know what this data means or what the user can do to manipulate it.
The Controller exists between the view and the model. It listens to events triggered by the view
(or another external source) and executes the appropriate reaction to these events. In most
cases, the reaction is to call a method on the model. Since the view and the model are connected
through a notification mechanism, the result of this action is then automatically reflected in the
view.
The MVC architecture pattern turns complex application development into a much more manageable
process. It allows several developers to simultaneously work on the application. The concept of MVCs
was first introduced by Trygve Reenskaug, who proposed it as a way to develop desktop application
GUIs. Today the MVC pattern is used for modern web applications because it allows the application to
be scalable, maintainable, and easy to expand.
The MVC pattern is particularly suitable for multiple graphical user interfaces (GUIs). The model does
not depend on the number and kind of GUIs, so the pattern allows for easy changes to the ‘look and
feel’.
The MVC pattern helps you break up the frontend and backend code into separate components. This
way, it's much easier to manage and make changes to either side without them interfering with each
other. But this is easier said than done, especially when several developers need to update, modify, or
debug a full-blown application simultaneously.
Consistency between model and view is maintained through notification. The MVC pattern often uses
the Observer pattern. User input can invoke a change in the model and a subsequent change in what
the view displays.
The MVC pattern was introduced with the Smalltalk programming language. It was called a paradigm
then: the concept of patterns did not yet exist. Examples of the MVC pattern are web presentation (see
the learning unit on patterns for enterprise application architecture) and the document view architecture
of Windows applications, which enables users to, for instance, see Word or PowerPoint documents in
different views (think of print layout, web layout, overview).
The MVC pattern makes it easy to have multiple views of the same model, which can be connected
and disconnected at run-time. It is possible to base an application framework on this pattern. Smalltalk
development environments already did this. However, the MVC pattern increases complexity. Not all
visible elements lend themselves for separation of model, views and control: menus and simple text
elements may be better off without the pattern. Also, the pattern potentially leads to many unnecessary
updates, where one user action results in different updates.
View and control are separated, but are very closely related. In practice, they are often put together.
Views and controllers are also closely coupled to the model. In web applications, a change in the model
(for instance, adding an email address to data about persons) will lead to a change in the view and
controller as well (the web site will have to show the property and the possibility to change the property
should be added as well).
9. Blackboard Pattern
The Blackboard pattern is useful for problems for which no deterministic solution strategies are
available. Several specialized subsystems assemble their knowledge to build a possibly partial or
approximate solution.
All components have access to a shared data store, the blackboard. Components may produce new
data objects that are added to the blackboard. Components look for particular kinds of data on the
blackboard and may find these by pattern matching.
Examples of problems to which the Blackboard pattern can be usefully applied are speech
recognition, submarine detection and inference of the 3D structure of a molecule. Tuple Space
systems, like JavaSpaces, form another example of this pattern.
Adding new applications is easy. Extending the structure of the data space is easy as well, but
modifying the structure of the data space is hard, as all applications are affected. Furthermore,
processes have to agree on the structure of the shared data space. There may be a need for
synchronization and access control.
The Interpreter pattern is used for designing a component that interprets programs written in a
dedicated language. The interpreted program can be replaced easily. This pattern suggests defining
grammar along with an interpreter that uses representations so that the system can interpret any given
sentences of a language.
Abstract expression or regular expression declares interpret operation, terminal expressions or literal
expressions implements symbols in the grammar, and non-terminal expressions (alternate, sequence,
repetition) has nonterminal symbols in the grammar.
Interpreter pattern, given a language, define a representation for its grammar along with an interpreter
that uses the representation to interpret sentences in the language. It map a domain to a language, the
language to a grammar, and the grammar to a hierarchical object-oriented design.
The Interpreter pattern discusses: defining a domain language (i.e. problem characterization) as a
simple language grammar, representing domain rules as language sentences, and interpreting these
sentences to solve the problem. The pattern uses a class to represent each grammar rule. And since
grammars are usually hierarchical in structure, an inheritance hierarchy of rule classes maps nicely.
An abstract base class specifies the method interpret(). Each concrete subclass implements interpret()
by accepting (as an argument) the current state of the language stream, and adding its contribution to
the problem solving process.
Rule-based systems such as expert systems, web scripting languages such as JavaScript (client-side)
or PHP (server-side) and Postscript are examples of the interpreter pattern.
Because an interpreted language is generally slower than a compiled one, performance may be an
issue. Furthermore, the ease with which an interpreted program may be replaced may cause a lack of
testing: stability and security may be at risk as well.
On the other hand, the Interpreter pattern enhances flexibility, because replacing an interpreted
program is indeed easy.
References
https://get.oreilly.com/rs/107-FMS-070/images/Software-Architecture-Patterns.pdf
https://www.geeksforgeeks.org/types-of-software-architecture-patterns/
https://towardsdatascience.com/10-common-software-architectural-patterns-in-a-nutshell-
a0b47a1e9013
https://www.geeksforgeeks.org/difference-between-system-architecture-and-software-architecture/
https://nix-united.com/blog/10-common-software-architectural-patterns-part-1/
https://www.redhat.com/architect/5-essential-patterns-software-architecture
https://ftacademy.org/files/materials/fta-m11-soft_arch-pre.pdf
https://develpreneur.com/master-slave-an-architecture-for-distributing-work/
https://syedhasan010.medium.com/pipe-and-filter-architecture-bd7babdb908
http://www.dre.vanderbilt.edu/~arvindk/public_html/ICS211/Softe_Patterns.htm
https://www.oreilly.com/library/view/architectural-patterns/9781787287495/5456ca48-e771-4535-
a130-54cfa05b6def.xhtml
https://develpreneur.com/peer-to-peer-an-architecture-pattern-where-everyone-shares-the-work/
https://www.ou.nl/documents/40554/791670/IM0203_03.pdf
https://sourcemaking.com/design_patterns/interpreter
Self - Assessment
1. What is Architectural Pattern?