Split Application Backend Logic

Updated: Published: EuroPLoP 2025

Context and Motivation

An application implements a domain model with its entities, relationships, services, and so on. Parts or all of the data are stored in a database or other data store.

As an application architect, I want to (re-)locate the components realizing business logic (i.e., computations, manipulation of business objects) on physical tiers in such a way that design-time and runtime properties are able to meet the project goals, functional and non-functional requirements, and constraints in an adequate, balanced way.

Stakeholder Concerns

#availability
Failures in one part of the system can impact others unless fault isolation is carefully designed. In distributed systems, service dependencies and network issues increase the risk of cascading failures. In monoliths, a single crash can bring down the entire application. Availability must be addressed explicitly during design, evolution, and operation.
#consistency
Data stored together can be guaranteed to meet the ACID properties more easily than distributed data. A single, local system transaction manager (such as a relational database management system) can take care of that. “Software Architecture: The Hard Parts” discusses this concern as one of the difficult-to-make architectural decisions that are required [Ford et al. 2021].
#coupling
Application logic and data storage within a single deployment unit are inherently coupled in terms of change management and scaling, even when separated by local interfaces. The amount of coupling is a multidimensional stakeholder concern. See for instance “The Many Facets of Coupling”.
#ethicality
Openness, transparency, accuracy are typical ethical values and values requirements, for instance for Web applications that work with personal sensitive information. Distributing application logic and data might raise additional value requirements, for instance regarding data privacy. Furthermore, teams responsible for deployment units might prioritize values differently than developers, end users, product managers, or project sponsors [Kapferer, Zimmermann, and Stocker 2024]. Irrespective of the chosen architectural styles and patterns, no application content should violate “Netiquette” or other guidelines and principles for communication and digitalization.
#flexibility
Distribution of backend logic decouples the build cycles of the parts. For instance, independent changeability, deployability, and scalability are among the drivers for microservices.
#observability
Distributed business logic increases the requirements for and the complexity of monitoring and debugging. Logging, tracing, and metrics must be designed to work across service boundaries, which requires extra design and implementation work. For instance, distributed traces must be correlated with each other and with the business transaction they belong to. The Context Representation pattern, which is the target of the Encapsulate Context Representation refactoring in IRC, may help to consolidate and correlate trace information to achieve end-to-end observability.
#scalability
Backend components may carry different workloads, which suggests to scale them independently. This is possible with a distributed application backend, but not with a monolith.
#service-rightsizing
A major problem when adopting microservices and other approaches to server-side componentization and decomposition is the myth that it is inherently better than a monolith. Inadequate expectations and misunderstandings occur easily. Which evolution and maintenance problems are addressed? Is there an actual need for independent scalability and changeability? What is easier to do in a distributed, service-based system than in a monolith? [Mendonça et al. 2021]

Initial Position Sketch

This refactoring targets the business logic layer of logically layered applications; logical layering is a prerequisite for it. Figure 1 illustrates a monolithic backend organized into three logical layers: presentation, business logic, and persistence (data access and storage). These layers are explained further in the Initial Position Sketch of Distribute Application Frontend; detailed descriptions can be found in the literature [Fowler 2002].

Split Application Backend Logic: Initial Position Sketch. A logically layered monolithic backend. It may or may not contain presentation logic; the latter is more common in practice, but not shown in the figure (client tier, e.g. desktop PC or mobile phone running a Web browser, missing).

Figure 1: Split Application Backend Logic: Initial Position Sketch. A logically layered monolithic backend. It may or may not contain presentation logic; the latter is more common in practice, but not shown in the figure (client tier, e.g. desktop PC or mobile phone running a Web browser, missing).

Smells

Bad developer experience
Some teams have to work less agile than they would like to because certain application parts are owned and DevOps-ed by other teams. The different parts do not evolve at the same speed, but there is a compile-time and/or build-time dependency between them. Team and system boundaries might not align, causing friction and lack of clear responsibility.
Insufficient changeability
During maintenance and evolution, new features are implemented and existing ones patched. Not all parts of a monolithic backend have to change at the same speed when implementing new features, responding to change requests, and fixing bugs; the reasons for change differ from use case to use case. Monolith parts are compiled, built, tested, and deployed jointly; the fast moving parts have to wait for the slower changing ones or the slow changing parts have to be touched more often than needed. As a consequence, a monolith might become hard to maintain and extend; technical debt is accumulated as compromises are made to speed up development. As a result, API providers may experience that they are slower to respond to change requests from the business. Not all use cases supported by an application backend face the same scalability requirements.
Inflexible scalability
Workload patterns [Fehling et al. 2014] and thus scalability requirements can differ per application component. For instance, the product catalog in an online ticket shop is accessed much more frequently than the monthly financial reporting. The ticket shop has to be available around the clock, and especially during pre-sale periods.
Missing fault isolation
In a monolith, a failure in one part of the system (e.g., reporting) can bring down unrelated critical functions (e.g., production tracking). In operational environments, this lack of isolation can disrupt business processes and halt production entirely.
Poor response times, e.g., queries take long to complete
Critical application parts cannot be scaled up easily because they are co-located with others, and the resource consumption and workload caused by the monolith are rather high. Another reason for slow query response times (long latency) might be that the database has become very large, and the query processing is challenged to meet its performance NFRs.
#team-organization
See Distribute Application Frontend.

Instructions

The general option for splitting an application backend logic was identified and captured in pattern form back in 1997 [Renzel and Keller 1997]:

  • Distribute Application Kernel. Refactor from monolithic business logic to distributed application kernel.

There are two more options to split the backend, Remote Database and Distributed Database. They are featured as Split Application Backend Persistence.

Target Solution Sketch (Evolution Outline)

The distribution pattern Distributed Application Kernel is one of the client-server-cuts from Renzel and Keller [1997]. It can be combined with the other two cuts focussing on the backend and with the two cuts dealing with application frontend decomposition.

The general option to refactor monolithic business logic to distributed application kernel is sketched in Figure 2.

Split Application Backend Logic: Target Solution Sketch. From Monolithic Business Logic in a single backend tier to Distributed Application Kernel. Note that again the client tier (application frontend) is not shown.

Figure 2: Split Application Backend Logic: Target Solution Sketch. From Monolithic Business Logic in a single backend tier to Distributed Application Kernel. Note that again the client tier (application frontend) is not shown.

The business logic is now split and distributed to different physical hardware nodes (actual or virtual ones); its components communicate via a remote protocol such as gRPC or HTTP.

When the database is split and distributed along with the application logic, the backend morphs into a set of microservices.

Example(s)

Lakeside Mutual splits its application logic into microservices. Its database may reside on a separate host, depending on the JDBC configuration and chosen RDBMS.

The service mesh Istio realized the reverse transformation and went from microservices to modular monolith [Mendonça et al. 2021].

Hints and Pitfalls to Avoid

Splitting an application backend is a “big” architectural decision, which requires careful evaluation and justification [Zimmermann and Stocker 2021]:

  • Do not introduce microservices just because. Trace the decision to refactor monolithic business logic into a distributed application kernel back to project-specific requirements that justify investing in independent deployability, scalability, and changeability [Mendonça et al. 2021; Singjai, Zdun, and Zimmermann 2021].
  • Apply an API first approach and consider using API design patterns when creating the required remote APIs. Document the API contract. Secure the API access properly; do not store database or connection credentials in inappropriate places such as source code; consult the OWASP API Top 10 for more advice.
  • Provide test mock-ups and test data. Do not let continuous integration builds fail because of the distribution introduced here.
  • Adapt the Test, Explain, Let Know, and Learn (TELL) steps featured online and in our 2023 EuroPLoP paper [Stocker and Zimmermann 2023] on/for the architectural level.
  • Apply strategic Domain-Driven Design (DDD) to identify adequate splits that reflect the subdomains and bounded contexts of the domain [Kapferer and Zimmermann 2020]. See the Design Practice Repository and the corresponding e-book [Zimmermann and Stocker 2021] for a brief introduction to Strategic DDD.
  • In distributed backends, faults still affect other services if isolation is not carefully designed. Design for fault isolation using patterns such as Circuit Breakers [Nygard 2018] or separate runtimes to prevent local failures from affecting unrelated features.
  • Implement service health checks. This allows orchestration platforms and monitoring tools to detect failures early, isolate faulty services, and avoid propagating errors across the system. “Release It!” [Nygard 2018] is a hands-on guide to designing and deploying resilient, scalable, and production-ready software systems.

Other architectural refactorings in this catalog include Segregate Commands from Queries and Distribute Application Frontend. Segregate Commands from Queries can be seen as a special type of backend split. Note that these refactorings can be combined and also be applied multiple times/progressively.

In “Serverless Land”, Direct Database Access can be seen as inverting the client-server-cut Remote Database [Renzel and Keller 1997] in a particular application context.

“Software Architecture: The Hard Parts” by Ford et al. [2021] discusses criteria for splitting application kernels (and reasons not to do so) under service disintegrators (service scope and function, code volatility, fault tolerance, security, extensibility) and integrators (database transactions, workflow and choreography, hared code, database relationships). The book also covers architectural decisions regarding communication (APIs!), coordination (state management), and consistency (atomic versus eventual), which have to be made when applying one or more of the splitting options described here and in Split Application Backend Persistence.

In Domain-Driven Design (DDD) this refactoring could correspond to splitting a so-called Bounded Context [Evans 2003]. Context Mapper [Kapferer and Zimmermann 2020] therefore implements this refactoring with Split Bounded Context by Features and Split Bounded Context by Owner. The inverse refactoring in Context Mapper is Merge Bounded Contexts.

References

Evans, Eric. 2003. Domain-Driven Design: Tacking Complexity in the Heart of Software. Addison-Wesley.

Fehling, Christoph, Frank Leymann, Ralph Retter, Walter Schupeck, and Peter Arbitter. 2014. Cloud Computing Patterns: Fundamentals to Design, Build, and Manage Cloud Applications. Springer. https://doi.org/10.1007/978-3-7091-1568-8.

Ford, N., M. Richards, P. Sadalage, and Z. Dehghani. 2021. Software Architecture: The Hard Parts. O’Reilly Media.

Fowler, Martin. 2002. Patterns of Enterprise Application Architecture. Boston, MA, USA: Addison-Wesley Longman Publishing Co., Inc.

Kapferer, Stefan, and Olaf Zimmermann. 2020. “Domain-Driven Service Design.” In Service-Oriented Computing, edited by Schahram Dustdar, 189–208. Springer International Publishing. https://doi.org/10.1007/978-3-030-64846-6_11.

Kapferer, Stefan, Olaf Zimmermann, and Mirko Stocker. 2024. “[Value-Driven Analysis and Design: Applying Domain-Driven Practices in Ethical Software Engineering]{.nocase}.” In Proceedings of the 29th European Conference on Pattern Languages of Programs, People, and Practices. EuroPLoP ’24. New York, NY, USA: Association for Computing Machinery. https://doi.org/10.1145/3698322.3698332.

Mendonça, Nabor C., Craig Box, Costin Manolache, and Louis Ryan. 2021. “[The Monolith Strikes Back: Why Istio Migrated From Microservices to a Monolithic Architecture]{.nocase}.” IEEE Software 38 (5): 17–22. https://doi.org/10.1109/MS.2021.3080335.

Nygard, Michael T. 2018. Release It!: Design and Deploy Production-Ready Software. Pragmatic Programmers. Pragmatic Bookshelf.

Renzel, Klaus, and Wolfgang Keller. 1997. “[Client/Server Architectures for Business Information Systems – A Pattern Language]{.nocase}.” In Proceedings of the Conference on Pattern Languages of Programs. PLoP ’97.

Singjai, Apitchaka, Uwe Zdun, and Olaf Zimmermann. 2021. “[Practitioner Views on the Interrelation of Microservice APIs and Domain-Driven Design: A Grey Literature Study Based on Grounded Theory]{.nocase}.” In 18th IEEE International Conference on Software Architecture (ICSA 2021). https://doi.org/https://doi.org/10.5281/zenodo.4493865.

Stocker, Mirko, and Olaf Zimmermann. 2023. “[API Refactorings to Patterns: Catalog, Template and Tools for Remote Interface Evolution]{.nocase}.” In Proceedings of the 28th European Conference on Pattern Languages of Programs. EuroPLop ’23. New York, NY, USA: Association for Computing Machinery. https://doi.org/10.1145/3628034.3628073.

Zimmermann, Olaf, and Mirko Stocker. 2021. Design Practice Reference - Guides and Templates to Craft Quality Software in Style. LeanPub. https://leanpub.com/dpr.