Understand what the ideal architecture for an enterprise-ready composite application should look like. Discover the pitfalls involved, how to avoid them, and how your decisions influence the overall complexity of the final application. By following these recommendations, you can develop applications that are well prepared for your always-changing IT landscape.
Key Concept
The basic idea behind composite applications is to build completely new applications that cover business processes that are unique for your business or industry. In contrast to classic packaged applications where everything is built from scratch, a composite application tries to reuse as many existing business functions as possible by calling services that are accessible by standard means, such as the Web services standards. The developer can concentrate solely on new business logic and hand over responsibility to back-end systems where appropriate.
Instead of analyzing why the projects failed, SOA in general was questioned. From my experience, many SOA-based projects were simply started without sufficient preparations. The key aspect that caused most of the trouble was how the new composite applications interacted with the back-end systems. In most cases, the services were directly invoked out of the end application. Although this approach worked perfectly in the packed application area, this is not appropriate for SOA-based applications.
The goal of SOA must be to separate the business part from the technical part using a very special kind of application: a loosely coupled composite application. Although this sounds very intuitive, in the first SOA projects wrong architectures led to applications that lost all their promised flexibility and adaptability.
In a loosely coupled composite, you do not reuse any existing screens from running applications. You also do not call the back-end services directly out of the composite. These are all indicators pointing in the wrong direction. You should aim for a clear separation between the composite application and the back-end systems.
You also need an additional layer between the composite application and back-end system that mediates between the two. This creates timeless software that interacts with your existing landscape.
Note
The method outlined here is not the only way to develop applications based on SOA principles. Other valid use cases exist that simply require tight coupling. However, you should be aware of the consequences, such as increased maintenance costs and less flexibility. My goal is to give you enough information for sound decisions.
Development Approach for Composite Applications
You might wonder if any guidelines are available to help you avoid the trap of a tightly coupled application. Let me give you two very simple guidelines that help you avoid the biggest pitfalls.
1. You Don’t Know Against Which IT Landscape Your Final Composite Will Run
For a composite application it is essential to start top down. Be guided by your new process idea and collect all the process steps, user interfaces, services, and data that you need to fulfill your business functionality.
Note
Services in this context refer to how the composite application requires them, not about how the back-end systems provide the services. This is a significant difference.
For example, say you want to specify a service for creating purchase orders. Within your composite, you want to collect products that you need to order and enhance it with the quantity of those products. In this example, the composite’s requirement for the Create Purchase Order service is a very simple interface with the products and their respective quantities as input and a short message about the order completion as an output parameter. That’s the composite’s view on the service call.
You also have back-end systems that provide this functionality. For my example, SAP provides an enterprise service with an operation called PurchaseOrderCreateRequestConfirmation_In. If you take a more detailed look at the service, you find many fields that do not relate to the composite’s goal. Go for the simplified interface as your composite requires it. You can later connect the simplified interface of the composite with the interface of the providing system. Typically, the functionality that the composite requires cannot be fulfilled with only one back-end call. In these cases, you have to combine several back-end calls to implement the business functionality that the composite requires.
Keep in mind that the composite is the driver. Its requirements are crucial for defining the service’s signature. By following this guideline, you are automatically forced to separate your composite and its requirements from the actual implementation of the requirements, which is good practice. It allows you to easily replace one implementation with another one at a later time, if necessary.
Also, with the loosely coupled approach, you have flexibility for adaptations to changing landscapes. You aren't making assumptions about the landscape your application is running against, so you can adapt it as needed, provided your frameworks and tools support you in this process the way SAP NetWeaver Composition Environment does. This is especially important for partners and independent software vendors (ISVs). They can develop applications once and easily install and configure them at their customers' site. The application itself stays untouched.
Not only partners and ISVs benefit from the loosely coupled approach. It is useful within companies as well. Once you've established a successful new application, you most likely will want to reuse it within your company in other locations or regions. Often the IT landscape in the new locations differs from the one for which the application was originally designed.
Another aspect you should consider is the probability of landscape changes during the lifetime of your new application. Due to mergers and acquisitions, system consolidations, outsourcing of functionality to a service provider, or the use of new deployment options such as cloud computing, the landscape underneath your application is constantly changing. If you are not prepared for loose coupling, you must adapt your application over and over again.
2. Assume You Are Implementing a Product
Products have much more demanding requirements regarding maintainability than project-based software. Often companies develop applications on a project basis. To keep the project costs low, they make architectural compromises that don’t pay off in the long run. Although developing applications in this manner might be easy and inexpensive at the beginning, you can incur time and money loss the longer the application is in use.
For example, what if the service you are directly calling out of your composite differs in the new release of your back-end system? What if you have to involve more than one system due to a merger? The answer: You have to adapt the composite as well. In fact, most companies tend to have several composites built this way. The maintenance nightmare begins because you have mixed the new business logic in your composite with the technical details of the called services. If you had separated this adequately using the loosely coupled method, adaptations would be much easier.
Keep in mind that project costs are one-time costs, whereas maintenance costs burden you during the entire lifetime of the software. Spending a little bit more time and money on the project to develop product-like applications helps you to keep the overall costs lower.
Architecture of Composite Applications
Now I’ll dive into the details of an enterprise-ready architecture for a composite application (
Figure 1). I start with the key characteristics of a composite, which are summarized as follows:
- Composite applications follow a layered approach consisting of a business process layer, a user interface (UI) layer, and a business object and service layer
- The business process layer concentrates on innovative collaborative business processes that bring companies a competitive advantage. Rather than re-implementing standard functionality available in packaged applications such as SAP ERP, look for processes that distinguish your company from the competition.
- The UI layer cares for task-oriented UIs. The UIs are tailored to the needs of the current role. From where the data is actually retrieved is irrelevant for the UI design.
- The business object and services layer provides all the necessary services that the UI and process layers require. This can be new business logic, data persistency, or a connection to external services.
- Composite applications are loosely coupled with their back-end systems. This means that composite applications only define their business needs via a clearly defined interface description (called a service contract) with a short explanation about the business functionality they require to work correctly. How this interface is implemented is not important for the composite. Composite applications benefit from this approach because you can replace service implementations as needed.
- Composite applications have their own life cycles. There are no dependencies between composite and called back-end systems, so they can have their own release cycles independent from releases of the integrated applications.
- Composite applications work only on data that their business processes require. The composite architect should always be guided by the business processes that the composite contains. Concentrate only on the business entities the composite requires and within a business entity, take only the necessary fields. Reduce the number of attributes for a business entity to the bare minimum.
- Composite applications are not invasive, so no adaptations in the back-end systems are needed to benefit from a composite
- Composite applications rely on a canonical data type system. They refuse to reuse proprietary data types available in the connected back-end systems because this would make composites dependent on the reused data types.
Note
In a canonical data type system, you apply a universal cross-system data model. This model defines the business data aspects of an interface or the business entities on which your application works.
Figure 1
Composite application architecture summary
In
Figure 1, you can see that the back-end, independent composite application is at the top and the layer containing the back-end systems is at the bottom. Between these two layers is the back-end dependent service contract implementation layer (SCIL). With this architecture you have clearly separated responsibilities — the composite application takes care of the new business processes and the back-end systems provide the required services on which the composite relies. The SCIL fulfills the mediation between the two in a loosely coupled manner. (For a detailed discussion about loosely coupled applications and asynchronous communication see the sidebars “What Does ‘Loose Coupling’ Really Mean?” and “Asynchronous Communication and Loose Coupling.”)
The composite application comprises the new business functionality. It is solely built using the canonical data type system. The SAP Global Data Types (GDTs) are one example of this data model. I recommend using GDTs because they are reused in SAP enterprise services as well as in SAP NetWeaver Process Integration (SAP NetWeaver PI). By using GDTs, the need for data type mappings within the SCIL is significantly reduced.
Besides implementing the new business functionality, the composite also defines the external service needs in the form of a service contract. Recall that the interface comprises the signature of the service call from the composite’s point of view — lean and restricted to the fields the composite requires. The description of the interface is expressed by using the Web Services Description Language (WSDL) standard. You should add some notes to the interface that briefly describe the required business functionality so that the interface implementer knows what to deliver to the composite. To define the interface itself, you use the same canonical data type system that you used in the composite before.
The service contract can now be fulfilled by the SCIL, which resides between the composite application and the back-end systems. It has to negotiate between the composite’s requirements and the available functionality of the back-end systems. However, the tasks the SCIL has to fulfill are diverse and can best be described by explaining a concrete scenario. This scenario also enables you to distinguish the tasks for which each layer is responsible. I start with a discussion of the different communication styles a composite typically uses: synchronous read operations vs. asynchronous write operations.
Note
Keep in mind that you can implement the interface (and the necessary business functionality) in many different ways depending on the IT landscape you are programming against without implying any changes in the composite. This is the key point to understand when thinking about the flexibility and agility aspect of SOA-based applications.
Composite Applications in Action
The scenario I use is an ordering process (
Figure 2). Assume within your company you are responsible for ordering hardware. You are sitting in front of your order form and search for a particular laptop (
Figure 3). You need an external service to retrieve the products because information about the products is typically available in one of the back-end systems.
Figure 2
Simple demo scenario: ordering process
Figure 3
The order form
Your task as architect is to describe this requirement in the form of a WSDL file (the service contract). In this example, assume two input parameters (productID and description) as search criteria and a list of found products as the return parameter. Each found product contains the productID, the description, the price, and the currency.
Figure 4 shows a summary of what the interface looks like. This code shows you how you can define interfaces from the composite’s point of view and reduce it to the bare minimum. The composite requires only the mentioned fields, although available services certainly have much more complex interfaces
Figure 4
Code for the example
Now that you’ve defined the service contract, the next question is how the SCIL should implement the service. The answer is by calling the back ends synchronously. You may ask yourself, “He’s talking about loose coupling and now he recommends synchronous calls? Isn’t that a contradiction?” Yes and no. Although you are aiming for loose coupling by calling back ends asynchronously, this doesn’t make sense for read operations.
Be aware of the fact that the end user is sitting in front of his computer waiting for an answer. If the application doesn’t respond within a certain time frame, the user becomes nervous. You cannot afford an additional overhead for asynchronous communication. Therefore, the SCIL must be optimized for fast synchronous service execution. Even if you have to call several systems, synchronous calls are the recommended approach. From a transactional perspective, this is not a problem because read operations are not critical.
Tip!
In the testing phase, you might find that the response times are still not ideal. In this case, I recommend duplicating the data to the server on which your composite is running so that the services can be called locally, which improves the performance significantly. This may sound strange at first because it implies double maintenance of master data, but modern master data management systems are well prepared for data replication. This solution has been applied successfully in many custom projects.
After the end user has selected the product from the hit list and added the quantity, he wants to submit the data. He expects a confirmation in the form of an order ID or something similar. Now things become tricky because this part of the process involves a write operation, which is much more critical than a read operation. Because you don’t know how many systems are involved to actually fulfill this order (remember the first guideline), you cannot call the back-end systems synchronously. You cannot even call them asynchronously because you don’t know how long the system needs to finish the operation (and an order creation can take some time).
How do you solve this dilemma? Quite simple: Out of the UI, you write the order data synchronously in the composite’s local database. The operation is fast, the user gets immediate feedback, and the call returns an internal ID for the order on the fly. The UI could look like the one depicted in
Figure 5.
Figure 5
Confirmation screen for the order
As you can conclude from
Figure 3, the UI is implemented using a wizard control (recognize the two steps named Order and Confirmation at the top of the screen). The first screen comprises the order form, the second one the confirmation screen. So far the data has been successfully saved.
It’s important to know that the UI is part of the executable business process shown in
Figure 2. The UI implements the Enter Request Data step. After a manager approves the request, you continue to the Create Purchase Order step. Now the time has come to actually write the data into the back-end system. Again, start with the definition of the interface. In this example, the composite wants to hand over the data asynchronously. Therefore, your interface contains only input parameters — no output parameters. You only submit the selected product with its quantity resulting in interface in
Figure 6.
Figure 6
The code for the Create Purchase Step
As you can see, you submit one additional parameter called internalReservationID. What is the purpose of this parameter? Consider what is happening behind the scenes. You are handing over the responsibility for the order creation to the SCIL. The SCIL can implement the functionality with any technology using any programming language. It is only important that it sticks to the interface and to the required functionality.
Your implementation of the Create Purchase Order business functionality in
Figure 6 could use a process engine (e.g., Business Process Management [SAP NetWeaver BPM]). Often you coordinate service calls that potentially could run into problems due to technical or business reasons (such as systems that are not available due to maintenance or a product that is not on stock). In these situations, it makes sense to involve system experts who solve these issues. You can use process modeling within both the composite application (the business composition represented by the business process) and the service contract implementation layer (the technical composition represented by a technical process).
The Technical Composition in Action
By handing over the parameters from the business process to the SCIL, you activate another (technical) process that takes care of all the technical details. The business process then enters a wait state — it waits for the technical process to finish. To notify the waiting business process, the technical process needs some kind of reference so that it knows which of the waiting business processes it should wake up. This is where the internalReservationID parameter can help. As the technical process is the implementation of the Create Purchase Order step in the business process (
Figure 2) it becomes obvious how closely business and technical processes are working together.
Figure 7 shows the main tasks of the technical process.
Figure 7
SCIL as a Business Process Modeling Notation (BPMN) process
The Create Purchase Order step contains the service call to the back-end system. In this example, the service call invokes an appropriate enterprise service, which can indicate problems via specialized error messages. The SCIL should handle problems as closely as possible to the respective back-end systems because the probability of solving problems is higher if you are close to the root of the problem. That’s why I modeled an error handling process flow that points to the Care For Error step. The BPMN error symbol

placed directly on the border of the associated automated activity indicates the error situation and how the process should react to it. You can imagine how easy it is to add additional service calls in cases in which more than one system is involved to fulfill the service contract.
Note
Don’t forget that the SCIL is back-end dependent. As it calls the concrete back-end services, it also has to handle all data type conversions. You cannot avoid them, but as a result of the clear separation between the composite and SCIL, all these technical issues are handled in one location.
The next automated activity in my process model is named Save in XRef Table. This step is necessary to maintain references between the ID that was assigned to the order data in the composite application (internalreservationID) and the IDs the data is saved under in the back-end systems. For example, if you assign the internal ID 4711 to the order data and the back-end system stores the same data under the number 0815, then the reference table contains one row with these two values as entries.
If you have more systems to which you are writing the data, you have to add more columns to this cross-reference table. The cross-reference table ensures that you are always able to find associated data. For example, the back-end system prints an invoice that contains the back-end system’s ID. By using the cross-reference table, you can always find the original order in the composite application and vice versa.
Finally, the Confirm PO Creation step takes care of notifying the waiting business process instance that originally kicked off the technical process. With that, the technical process completes its tasks.
Besides these fundamental tasks I’ve described so far for the service contract implementation layer, there are other technical aspects that you need to consider as well. The SCIL handles all the technical tasks, so it is responsible for fulfilling them. Here is an overview of those tasks.
Optimistic Locking in Back-End Systems
In a loosely coupled environment, it is best to go with optimistic locking. In this case, the data is not locked after a read operation. However, the back end ideally returns a timestamp when the data was modified last during the read operation. When you update the data in a write operation, the timestamp from the read operation is also part of the write operation’s interface. The back end can then identify whether the data has been modified because the timestamp in the back end and the timestamp parameter of the write operation differ. The back end can now react accordingly, such as to indicate a write conflict by throwing an exception or returning an error message.
How do you react if those write conflicts occur? You can implement some kind of merge routine that combines the changed values, most probably involving an expert. Again, this can easily be modeled using BPMN. You can also split the affected business entity in more fine-grained entities so that write conflicts are less probable. Finally, you can rearrange your business processes in such a way that the conflict situation cannot occur.
Note
One word of warning: Don’t implement an explicit check-in/check-out mechanism for business entities. This type of locking on the application level brings additional complexity to your composite. You have to foresee all kinds of problems, such as the end user not releasing a lock due to illness or vacation. Be aware that the back-end systems must consider this concept as well and must support it. You cannot achieve this without changes in the back-end system which contradicts the noninvasive approach for composite applications.
Transaction Handling Using Compensation
Transaction handling can become tricky if you are not used to loosely coupled environments. In the world of tightly coupled packaged applications, everything runs within one database. If there is a need for transaction handling across two database systems or across database systems and messaging environments, the two-phase-commit protocol works perfectly. However, for loosely coupled environments this doesn’t work (yet).
Although the Web Service-Atomic Transactions (WS-Atomic Transactions) standard tries to bring transactional behavior into the Web services world, I doubt its widespread adoption in the near future. You have to look for alternatives. The solution is the use of compensational services.
Every write or update service needs an associated compensational service. For example, the service for booking a flight can be compensated by a service for cancelling the flight. This indicates that the compensation has to be done on a business level and not on a technical level (e.g., database level). In situations in which no compensational services are available or it is impossible to implement them, you should involve business experts in the process model. BPMN can help out because it explicitly foresees modeling of transactional behavior based on compensational services.
Idempotency
Idempotent behavior means that you can call a service with the same data several times and the results you receive from the call are always the same. A simple example is a service for calculating taxes. It always returns the same value for the same input parameters. Conversely, a service for counting (e.g., open orders) is not idempotent because each call increases the number of open orders.
Why is idempotency important? Because services are typically called using the SOAP protocol over HTTP. However, HTTP is not a reliable protocol. Therefore, you could call a service without receiving an answer. In these situations, one typical error resolution strategy is to retry the call after a certain time period because you assume that the back end is only temporarily not available. However, if your services are not idempotent, the outcome of the retry calls can be completely different depending on the error situation.
For example, see what the behavior looks like for an order service. You call your service and do not receive a reply. You try again because this is the default error-handling strategy. This time, you receive a response and continue in your program as planned.
So, what happened in the back end? If the first call did not reach the back end, everything is fine. The system handles the second call normally and creates the order. If the first call was successful and only the response didn’t find its way back to the caller, the situation changes radically. If your order service is not prepared for idempotency, the second call creates another order resulting in two or even more orders depending on the number of retries. Keep in mind that the caller cannot distinguish the error situations and know whether the call to the back end or the response message failed.
The challenge for the called service is to identify its invocation uniquely to achieve only one execution. The solution is one additional input parameter in the service’s signature reserved for a unique identifier. The behavior of the service changes as follows:
- The unique identifier is passed to the service
- The service processes the message on first receipt and caches the result it will send back to the caller in an internal table under a certain key. This key is in fact the unique identifier the caller provides.
Now it becomes clear how the service identifies the first call — it always looks up the entries in the internal table using the unique identifier as the key and if the key is not yet available, it must be the first call. For subsequent calls with the same ID, the server returns the cached results. By following this technique, you can make services idempotent. It’s also important to note that the retry error resolution strategy and idempotency work hand in hand.
Tip!
One final tip for Java programmers: As the caller, you can conveniently create unique IDs by using the standard Java library function java.util.UUID.randomUUID().
Loose coupling is a fundamental SOA concept in large distributed heterogeneous landscapes. Use the checklist below to get started with loose coupling:
Checklist
- Basic guideline 1: Assume that you don’t know against which IT landscape your final composite will runBasic guideline 2: Assume that you are implementing a product
- Follow a top-down approach. Let your new business idea be the guide for the process flows, required UIs, services, and business entities.
- Separate business composition (the composite application itself) from technical composition (the SCIL)
- Use a canonical data type system within the composite application. Don’t pollute the composite with any data types coming from back-end systems.
- Define the composite’s service requirements as a WSDL file that represents the contract between the composite and the SCIL. Use the canonical data type system for the contract as well. Reduce the number of fields to those that the composite really requires.
- For read operations, enable fast execution in the SCIL
- Write operations use the asynchronous write pattern:
- From the UI, save the data in the local database of the composite and generate an internal ID
- Hand over the data with the internal ID asynchronously to the SCIL to kick off the technical process
- The business process (composite application) enters the wait state. It waits for the technical process to complete.
- The technical process covers all technical aspects (e.g., calling the back-end system, converting data types, and handling errors)
- The technical process wakes up the business process after completion
- Maintain an ID cross-referencing table within the SCIL
- Use optimistic locking in SOA environments
- Error and exception handling strategies differ for loosely coupled environments. You can use compensations, retries, and manual interventions to solve them.
- For every modifying service (write, update) provide a compensational service
- Make your services idempotent
What Does "Loose Coupling" Really Mean?
The key question is: How can you measure loose coupling? Often the discussion is reduced to the question of whether an application talks synchronously or asynchronously with its peers. Although this is certainly one aspect, it doesn't cover all relevant dimensions of loose coupling.
The goal of loose coupling is to reduce dependencies between systems. Therefore, to determine how tightly an application is coupled to other systems, consider a second question: What are the consequences for system A (the calling system) if you make changes in system B (the called system)? Typically, this question reveals many dependencies between your application and others that go further than a classification of the communication style between them.
Here are a few more assumptions to make that point more explicit:
- Location of the called system (its physical address). Does your application use direct URLs to access systems or is your application decoupled via an abstraction layer that is responsible for maintaining connections between systems? The new service group paradigm used in SAP NetWeaver Composition Environment (SAP NetWeaver CE) is an example of what such an abstraction might look like. Using an enterprise service bus (ESB) is another one.
- Number of receivers. Does your application handle service call receivers? Or does it simply drop a message somewhere and other mechanisms take care of transporting the message to the receiving systems? Don't underestimate this assumption. This implies a different architecture compared to tightly coupled applications. You never know when or if a service call returns due to the number of involved systems — your application must be prepared for that.
- Availability of systems. Does your application require that all the systems that you are connecting be up and running all the time? Obviously, this is a difficult requirement, especially if you want to connect to external systems that are not under your control. If your answer is “Yes, all the systems must be running all the time,” you are tightly coupled in this regard.
- Data format. Does your application reuse data formats as they are provided by the back-end systems or are you using a canonical data type system that is independent from the type systems used in the called applications? If you are reusing the data types of the back ends, you probably have to struggle with data type conversions in your application. This goes against the loosely coupled approach.
- Response time. Does your application require the called systems to respond within a certain (acceptable) timeframe or is it acceptable for your application to receive an answer minutes, hours, or even days later?
You can probably find even more dependencies, but the message should be clear: Loose coupling is not one dimensional. For each of the aforementioned aspects of loose coupling, you have to make difficult decisions. Moving toward loose coupling has serious implications for the architecture of your application.
Asynchronous Communication and Loose Coupling
The asynchronous communication style is especially important for modifying service calls. In a loosely coupled environment, you never know how many systems are involved, whether the systems are available, or how long it takes to complete certain change operations in the involved back-end systems. In addition, all kinds of errors can occur, which have to be handled appropriately. It is (almost) impossible to handle business-critical change operations in such an environment synchronously.
You not only have to consider the best case scenario in which everything works perfectly, you also have to consider all kinds of error situations (technical and business errors) and how to act on them. This goes beyond simple request-response Web service calls and has severe implications for your application's architecture. If the services you want to call are only synchronous ones, you have to think about decoupling the calls using asynchronous means. You can achieve this by introducing an ESB, but that is not the only way to handle it. You can also achieve this by using SAP NetWeaver CE.

Dr. Volker Stiehl
Prof. Dr. Volker Stiehl studied computer science at the Friedrich-Alexander-University of Erlangen-Nuremberg. After 12 years as a developer and senior system architect at Siemens, he joined SAP in 2004. As chief product expert, Volker was responsible for the success of the products SAP Process Orchestration, SAP Process Integration, and SAP HANA Cloud Integration (now SAP HANA Cloud Platform, integration service). He left SAP in 2016 and accepted a position as professor at the Ingolstadt Technical University of Applied Sciences where he is currently teaching business information systems. In September 2011, Volker received his Ph.D. degree from the University of Technology Darmstadt. His thesis was on the systematic design and implementation of applications using BPMN. Volker is also the author of Process-Driven Applications with BPMN as well as the co-author of SAP HANA Cloud Integration and a regular speaker at various national and international conferences.
You may contact the author at
editor@SAPpro.com.
If you have comments about this article or publication, or would like to submit an article idea, please contact the
editor.