5 Software Patterns You Should Know As a Software Engineer - Part 1
Tags: systemdesign
Published: 2023-07-10 12:22:38

We are currently in an exciting new era of technology, where software-defined systems have revolutionized the way we live and work. With digitalization enabling us to connect more easily than ever before and cloud hosting making it possible for us to access data from anywhere, we are on the cusp of a new age of innovation.

This era is characterized by context-awareness, which will allow us to tailor our experiences to our individual needs and preferences. Services are now more people-centric, designed to improve the lives of individuals and communities alike. Event-driven technology enables us to automate processes and respond to changes in real-time, while cognitive software provides insights and analysis that shape our decisions and drive innovation.

To meet the identified goals for the future of knowledge, we require highly responsive, reliable, scalable, adaptive, and secure software suites and libraries. We also need a range of innovative and promising architectural, design, deployment, delivery, and integration patterns to simplify the increasingly complex processes involved in designing, debugging, and delivering robust and rewarding software applications.

Using software patterns is very helpful in this case. Their utilization is becoming increasingly widespread and common as their popularity and usage grow over time.

Software architecture patterns provide a way to simplify the complex processes involved in designing, debugging, and delivering software applications. They are a set of well-known solutions to common problems in software design, architecture, and development. By using software patterns, developers can save time and effort while creating software that is easy to scale, maintain, and efficient.

This is the first part of a two-part series. In this issue, we will discuss the client-server architecture, the pipe-filter architecture, and the service-oriented architecture. Understanding these architectures can help us build robust and scalable applications that function well both now and in the future.

## Client-Server Architecture
Client-server architecture is a common system design that separates an application into two main parts: the client and the server. The client, which is usually a user interface, sends requests to the server. The server then processes these requests, creates responses, and sends them back to the client.

The client-server pattern is an old way of organizing computer systems. The client (your computer or device) asks the server (another computer) for a service or information. The server then provides the service or information to the client. This happens over and over again as the client keeps making requests.


![client-server-architecture](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/txs824ylvp32x1v3aqk3.png)

Messages are sent back and forth between the client and server in a request-response format. In this model, the client initiates contact with the server by submitting a request for the service in question.

The server is usually a database with procedures that have application logic. This makes it possible to perform complex actions on the data. This way, the server can handle many requests at the same time without affecting the effectiveness of other system components. The client-server model is widely used in software development today because it's effective and adaptable.

Web and application servers act as servers by receiving requests from clients, handling them, and sending responses back to the clients. In contrast, peer-to-peer (P2P) application design allows clients and servers to switch roles so that files and information can be shared and kept in sync across multiple clients. However, each participating system can play both client and server roles. Ultimately, they are individuals who work together to ensure business operations run smoothly.

The client-server architectural pattern has the capability of storing all of its data on the server, which, in general, provides a higher level of control over the system's security than client machines do.

Additionally, during the whole of the application's lifespan, centralized data access is provided through the client-server design pattern. Access to the data and modifications to the data are much simpler to handle than they are in other architectural patterns since the data is only kept on the server.

Lastly, there is the convenience of upkeep. The server may be a single computer or a group of computers working together as a cluster. It is possible to configure the server application as well as the database to operate on a single system or to replicate them over numerous servers in order to provide simple scaling and high availability.

A similar thing happens in business-grade server applications. An enterprise app has many parts called subsystems or microservices. Each part runs on its own server machine within the cluster.

Executing server programs and databases using one or more server machines provides protection to clients from interruptions caused by server unavailability, upgrades, or relocations. This means that clients can continue to access and use the system without experiencing any interruptions or delays due to server issues.

The insistence on centralizing data and applications on a single server is a potential drawback that might prevent the system from growing as needed.

In addition to this, the server is a potential lone weak spot in the system. The major problem at hand is one of dependability. The client-server design has developed into the more generic three-tier (n-tier) architecture in order to overcome these challenges.

### DNS as a Client-Server Architecture

![dns-client-server](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/olz8d8vm1hdlmdojg7cw.png)

The Domain Name Server (DNS) is able to function thanks to the client-server approach, which is based on the notion of distributed databases. Clients of the Domain Name System (DNS) are entities that need name resolution, or the mapping of host names to Internet Protocol (IP) addresses. The Domain Name System (DNS) server is responsible for maintaining the data necessary for name resolution.

Take the following as an example: In the web browser of the DNS client (the user's computer), the address (URL) www.example.com is typed in. The browser establishes a connection to a DNS server so that it can obtain the relevant IP address. In order to complete this task, the DNS server will first establish a connection with one of the root DNS servers. The IP addresses of all DNS servers that are responsible for top-level domains, such as .org and .com, will be stored on the root servers. The root servers will also store any other top-level domains that are managed.

To visit a website, your computer needs to know its IP address. The process starts when you type in the website address. The root server then asks the top-level server for the IP address of the website. The top-level server replies with the IP addresses of the name servers for that website. The name server then asks the DNS server associated with the website for its IP address. The DNS server sends the IP address to the name server, which then sends it back to the root server. Finally, your computer gets the IP address and can visit the website.

## Pipe-Filter Architecture

![pipe-filter](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mand0cm02lxg6iqlu9ey.png)

Enterprises in the modern era are made up of thousands of different apps. A good number of them are commercial, ready-to-use apps; some of them are applications developed in-house; and some of the others are heritage programs that have been a component of the business for an extremely extended period of time. This is due to the fact that each company performs hundreds of different business operations, many of which are hard to carry out with only a single application.

Spreading different functions over several applications gives a higher level of business continuity. This is because even if one application fails, the others will continue to operate without creating any obstructions to the functions that are necessary for business. Another rationale for numerous apps is that spreading various functions across multiple applications guarantees a better level of business continuity.

All of these factors justify the need for an appropriate integration mechanism across the many apps that are components of a corporate ecosystem. Because of the wide variety of application types, businesses now have a pressing need to develop a comprehensive collection of capabilities for their integration platform. This is necessary for them to continue to be competitive in the present-day dynamics of agile enterprises, which are constantly shifting to meet the requirements and anticipations of their customers.

The message integration technique is a parent of the pipe-filter pattern. In this specific instance, the integration of programs is accomplished through the use of messaging. If one of the apps publishes a message to a message channel based on a set of pre-defined agreements and message formats, then all of the other applications are able to access that message.

The pipe and filter, as a sub-section of messaging, is an architectural pattern for stream processing. It is made up of a single or more filters as its constituent parts. Before sending the data via connections known as pipes, these filters will modify or filter it. These filters, whose only purpose is to consume and output data, can be understood as performing business logical functions such as sorting and counting.

Each of these filters is capable of operating concurrently with the others. Additionally, the operation of a filter is dependent on the contribution of each and every pipe that is linked to it. Data travels from the source (the pump) to the sink after passing through pipelines and filters en route. The pump may either be a static text file or an input from the keyboard. A file, a database, or even just the screen of a computer might serve as the sink.

Pipe and filter designs may have their size readily increased during implementation by having more pipes and filters added to the system. However, if both the data and the architectural size are increased to extremely high levels, the overall performance of the system may become sluggish, and buffer overflow may take place.

### Pipe-Filter: Use case
Pipe and filter is an architectural design that is useful for programs that need a predetermined sequence of separate calculations to be carried out on data. Because filters do not exchange states with one another, it is not necessary for them to know the identities of the filters that come before or after them in the processing chain. In other words, filters are capable of operating on their own.

![unix-shell](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pt9blciix5xsfxw6lb5z.png)
Shell scripts and compilers written for the Unix operating system provide an illustration of the pipe and filter architectural design. It is possible for the output of one program to be connected to the input of another program when working with Unix programs; this is referred to as linking Unix processes via pipes.

A compiler is a program that performs a crucial function in computer science. It is responsible for translating input in one language into output in another language. The input language is usually referred to as language A, while the output language is called language B. The process of transforming language A into language B is called language transformation.

To perform language transformation, the input goes through various stages inside the compiler, which is called a pipeline. The pipeline is made up of different stages, each of which has a specific function and purpose. The most commonly used pipeline division consists of three stages: front-end, middle-end, and back-end.

The front-end is responsible for parsing the input language and performing syntax and semantic analysis on it. The front-end is also responsible for generating an intermediate representation of the input language. This intermediate representation is usually in the form of a data structure that is easier for the compiler to work with.

The middle end is where most of the optimization steps take place. The middle-end performs several optimization steps on the intermediate representation that the front-end generates. The optimization steps are aimed at improving the performance of the output program and reducing the number of instructions needed to execute it.

The back-end is responsible for transforming the optimized intermediate representation into the output language, which is language B. The back-end is also responsible for generating the machine code that can be executed on the target platform.

Overall, a compiler is an essential tool for software development. It converts high-level code into computer-executable low-level machine code. Without compilers, software development would be much more difficult and time-consuming.

Systems that make use of pipe and filter patterns are very simple to maintain and improve with regard to the expansion of already existing architectures. Since the filters are isolated from one another and only communicate with one another through explicit connections, it is possible to include more filters in already operational systems.

Pipes and filters have some significant drawbacks.

A filter may have an indefinite number of input and output pipes. If any of these pipes only permit one data type to pass through, the filter will need to perform some sort of internal parsing, such as transforming particular data types so that they can fit within the pipe's one allowed data type. This behavior may cause the filters to move more slowly.

Pipes and filters are also a lot like black boxes. We don't know how they're put into place. For example, we give an input to a pipe, and the pipe sends this input to the filter. When the filter is done with the input, it makes an output, but we don't know what it did inside.

![black-hole](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xb04w014uo116fbzwr3p.jpg)
When an error is transferred from a pipe to a filter, there is a higher likelihood that it will also be transmitted unfettered to the next filter since this behavior is the default setting.

## Service-Oriented Architecture (SOA)
If you’ve ever been on different websites, you may have seen dashboards that show different important information. These dashboards have everything you need to get things done or reach your goals. You might wonder how a sales report and stock market quotes can be shown together. Service-oriented architecture makes this possible.

SOA is a proven and highly favorable architectural design style that helps modern software systems efficiently handle ever-changing user expectations by solving key problems.

SOA plays a significant role in the background of real-world applications, providing virtualization, event processing, business process management, and much more.

We can create a software system that combines different data sources and systems in a cost-effective way.

### What are Web Services and SOA?

The initial step in designing any web service is to strictly adhere to the characteristics and principles of Service-Oriented Architecture (SOA). The fundamental building blocks and stepping stones for any web service design are the SOA architecture patterns.

A web service is a type of software architecture that enables different applications, often developed by different organizations, to communicate with each other. This communication is made easier by bespoke software code, which, in addition to being reusable, is also intended to be as cost-effective as possible. Essentially, a web service acts as an intermediary between disparate systems, enabling them to integrate with one another in a seamless and efficient manner. This allows businesses to streamline their operations, reduce costs, and improve their overall efficiency.

A service should be able to work by itself. In SOA, this is called being autonomous. A product's service should not depend on other services. Another SOA principle, composability, suggests combining services to add business value. You can place an order by combining customer service and product service.

In essence, SOA is a set of services that communicate with each other. A service is an operation or function that is well-defined, self-contained, and independent of other service contexts and states.

A service is made available to use without being tied to any specific technology. One of the biggest advantages of services is that they hide the technology being used underneath. One team can create their services with Golang, while another uses Python or NodeJS. The way the backend is developed doesn't affect whether one team can use the other's service. Being able to share services is possible because SOA encourages the idea of a standard service agreement. In the beginning, SOAP and WSDL were the standard contracts for SOA.

### Life Cycle of SOA
The development of software for SOA goes through four cycles, which are as follows:

![life-cycle](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zwkwtyh3zr6esitte6cd.png)

**Discover and define:** Any service that has a clear set of communication standards, such as WSDL, SOAP, REST, and so on, can be found and used.

**Model and Availability:** The next important thing is service design. We need to find a good pattern and offer services that are model-driven, specific to business functions, can be tested on their own, and so on.


**Deploy and Manage:** After the phase of functional design, it is essential for any company or organization to have services that are produced, deployed, and consumed in order to go on to the next step, which is the deployment and management phase. On the other hand, in contrast to the waterfall technique, it is preferable for the development of the service to occur in an iterative and agile manner so that customers may satisfy ROI in the near term.

**Governance and Feedback:** these two components are essential for any developing service, as they both play an important part in the adoption of the service and assist businesses in achieving a return on investment (ROI) as quickly as possible.

### Principles of SOA

![principles-of-soa](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k8xg4gbmwdnc3hqru2qz.png)

There are some tenets that can be defined as core principles of SOA that help to realize all the characteristics of SOA mentioned above.

### Standardized Service Contract
Standardization is important in SOA. It requires services to have clear and defined functions and capabilities in a service contract. This helps SOA designers focus on things like service granularity, data types, service optimization, service versions, service endpoints, and more.

Service level agreements (SLA) are agreements that clearly define how services are consumed, governed, secured, versioned, and responded to. By standardizing service contracts, these agreements provide direction and pave the way for easier service consumption.

When it comes to standardization efforts for sending data between applications, two prominent options emerge from the crowd: DCE/RPC and CORBA. These two approaches have proven to be reliable ways to allow applications, regardless of the programming language used or the operating system they run on, to communicate with one another.

Simply put, DCE, RPC, and CORBA assist in addressing a frequent problem in software development by enabling various programs to communicate data and functionality without being restricted by language or operating system boundaries. This is a problem that affects almost all software development projects. By offering a set of standardized protocols and interfaces, these technologies allow developers to create efficient and interoperable systems that can be easily maintained and expanded over time.

### Service Interoperability
One key principle of Service-Oriented Architecture (SOA) is interoperability, which is the ability of services to share information and communicate efficiently across different software platforms. This principle applies at various levels, including operational (i.e., business process), informational, and technical architecture stages.

At each level, interoperability ensures that systems can communicate with each other effectively, allowing for the efficient exchange of information between different services. By adhering to this principle, developers can create software that is scalable, maintainable, and efficient, making it easier to design, debug, and deliver robust and rewarding software applications.

### Service Abstraction
Making services simpler to understand by hiding internal complexities can improve the way they are explained and operated, help consumers focus on their core logic, and prevent accidental changes to internal processes.

Abstractions can be used at different levels, such as language implementation or server management. For instance, the sales report only focuses on generating a sales report and does not cover how it relates to the customer's platform, how it connects to the sales database server, or how new sales details are added to the system.

What they all need to know as customers of a service is whether the service can show the reports effectively and correctly.

### Service Statelessness
Services should try to avoid maintaining states. Statelessness is a vital principle that can help services use fewer resources, be tested independently, and increase reusability.

To implement statelessness in the email service, it is necessary to ensure that all the necessary information required for sending emails is explicitly provided. This means that the email service should not rely on any additional information from a database or any other resources. The primary focus of the email service should be on the business logic of setting up schedules to send emails.

The schema of the email service can have more details, such as message, email IDs, and subject, explicitly provided, rather than just a booking ID. Making this information explicit can help the email service pick up all the necessary information required to send emails without having to rely on other resources and, in turn, help it function more effectively.

## Is SOA still relevant?
The principles of SOA are still important today, even though they were created a while ago. This is because it can share services that work with any technology. However, it was hard for developers to use because it needed a lot of skilled developers to create the basic parts of an application.

One of the challenges of SOA is its high dependence on skilled developers. This is especially true when it comes to ensuring security, as application-managed security is not suitable for SOA. Separate technologies and standards must be followed for this purpose. Additionally, as the specifications for SOA and Web Services are constantly changing, there is a shortage of manpower for the integration and construction of service infrastructure, making it more challenging for businesses.

Roy Fielding, however, introduced REST web services in 2000. REST allows for lightweight and resource-centric web service calls, which completely changed how businesses approached application development. This further diverted attention from service-oriented architecture.

This is the end of the first part of this series. Look for the second part of this series next week. We will discuss event-driven and microservice architectures. Be sure to subscribe [here](https://skylinecodes.substack.com/) to be one of the first people to receive this in your email.

You can also reach me on [LinkedIn](https://www.linkedin.com/in/onakoya-korede/) or [Twitter](https://twitter.com/skylineCodes).

Happy Learning!