Messaging Patterns in Service-Oriented Architecture, Part 1
Cap Gemini Ernst & Young
Summary: This first of a two-part series discusses how messaging patterns exist at different levels of abstraction in SOA. Rather than explicitly declaring how systems will interact through low-level protocols and object-oriented architectures, SOA provides an abstract interface through which a service can interact with other services or applications through a loosely coupled (often asynchronous), message-based communication model. (23 printed pages)
Introduction: Process Configuration and Flexibility Trends
What Is Service-Oriented Architecture?
Discoverability and Dynamic Binding: Messaging in SOA
Message Type Patterns
Messaging Channel Patterns
Message Routing Patterns
Service Consumer Patterns
The need for process flexibility is not a new trend. The trend has been evident for the last two decades. The Internet, Web, and mobile computing came along and enabled a global productivity boom, resulting in technology innovations that are constantly laying the foundation for renovating industrial-age processes.
These solutions are built primarily on proprietary or system-based messaging platforms aimed at providing a platform for integration and communication between various business components. The typical method for accessing these systems is through a wide assortment of pre-built adapters that provide a bi-directional connectivity to many types of application processes. Rather than explicitly declaring how systems will interact through low-level protocols and object-oriented architectures, Service-Oriented Architecture (SOA) makes it possible to provide an abstract interface through which processes or services can interact. It can be imagined as an interconnected process-based enterprise that exposes a set of loosely coupled, coarse-grained services.
SOA is the aggregation of components that satisfy a business need. It comprises components, services, and processes. Components are binaries that have a defined interface (usually only one), and a service is a grouping of components (executable programs) to get the job done. This higher level of application development provides a strategic advantage, facilitating more focus on the business requirement.
SOA isn't a new approach to software design; some of the notions behind SOA have been around for years. Jess Thompson, a research director at Gartner, argues that the underlying concepts date back to the early 1970s, when researchers started drawing boundaries around software and providing access to that software only through well-defined interfaces.
A service is generally implemented as a coarse-grained, discoverable software entity that exists as a single instance and interacts with applications and other services through a loosely coupled (often asynchronous), message-based communication model.
The most important aspect of SOA is that it separates the service's implementation from its interface. Service consumers view a service simply as a communication endpoint supporting a particular request format or contract. How service executes service requested by consumers is irrelevant; the only mandatory requirement is that the service sends the response back to the consumer in the agreed format, specified in contract.
SOA consists of various entities configured together to support the find, bind, and execute paradigm as shown in Figure 1.
Figure 1. SOA explained
The service consumer is an application, service, or some other type of software module that requires a service. It is the entity that initiates the locating of the service in the service registry, binding to the service over a transport, and executing the service function. The service consumer executes the service by sending it a request formatted according to the contract.
The service provider is the network-addressable entity that accepts and executes requests from consumers. It can be a mainframe system, a component, or some other type of software system that executes the service request. The service provider publishes its contract in the service registry for access by service consumers.
A service registry is a network-based directory that contains available services. It is an entity that accepts and stores contracts from service providers and provides those contracts to interested service consumers.
A contract is a specification of the way a consumer of a service will interact with the service provider. It specifies the format of the request and response from the service. A service contract may require a set of preconditions and post conditions. The preconditions and post conditions specify the state that the service must be in to execute a particular function. The contract may also specify quality of service (QoS) levels, specifications for the nonfunctional aspects of the service.
The lease (the time for which the state may be maintained), which the service registry grants the service consumer, is necessary for services to maintain state information about the binding between the consumer and provider. It enforces loose coupling between the service consumer and the service provider, by limiting the amount of time consumers and providers may be bound. Without a lease, a consumer could bind to a service forever and never rebind to its contract again.
SOA supports the concept of dynamic service discovery. The service consumer queries the "service registry for a service, and the service registry returns a list of all service providers that support the requested service. The consumer selects the cost-effective service provider from the list, and binds to the provider using a pointer from the service registry entry.
The consumer formats a request message based on the contract specifications, and binds the message to a communications channel that the service supports. The service provider executes the service and returns a message that conforms to the message definition in service contract.
The only dependency between provider and consumer is the contract, which the third-party service registry provides. The dependency is a runtime dependency and not a compile-time dependency. All the information the consumer needs about the service is obtained and used at runtime. The service interfaces are discovered dynamically, and messages are constructed dynamically. The service consumer does not know the format of the request message or response message or the location of the service until the service is actually needed.
The ability to transform messages has the benefit of allowing applications to be much more decoupled from each other. Messaging underpins SOA; we don't have SOA without messaging.
Messaging Patterns Catalogue Within SOA Context
Messaging patterns exist at different levels of abstraction with the SOA. Some patterns are used to represent the message itself, or attributes of a messaging transport system. Others are used to represent creation of message content or change the information content of a message. Patterns are also used to discuss complex mechanisms to direct messages. SOA messaging patterns can be divided into the following categories:
- Message type patterns. Describe different varieties of messages that can be used in SOA.
- Message channel patterns. Describe the fundamental attributes of a messaging transport system.
- Routing patterns. Describe mechanisms to direct messages between Service Provider and Service Consumer.
- Service consumer patterns. Describe the behavior of messaging system clients.
- Contract patterns. Illustrates the behavioral specification to maintain a smooth communication between Service Provider and Consumer.
- Message construction patterns. Describes the creation of message content that travel across the messaging system.
- Transformation patterns. Change the information content of a message within the enterprise level messaging.
These patterns are shown in Figure 2.
Figure 2. Messaging patterns catalogue within SOA context
The message itself is simply some sort of data structure—such as a string, a byte array, a record, or an object. It can be interpreted simply as data, as the description of a command to be invoked on the receiver, or as the description of an event that occurred in the sender. Sender can send a Command Message, specifying a function or method on the receiver that the sender wishes to invoke. It can send a Document Message, enabling the sender to transmit one of its data structures to the receiver. Or it can send an Event Message, notifying the receiver of a change in the sender.
The following message type patterns can commonly be used in SOA.
How to invoke a procedure in another application?
Solution: Use a command message to reliably invoke a procedure in another application as shown in Figure 3.
Figure 3. Command message
A command message controls another application, or a series of other applications, by sending a specially formatted message to that system. A command message includes intelligent instructions to perform a specific action, either through headers and attributes, or as part of the message payload. The recipient performs the appropriate action when the message is received. Command messages are closely related to the Command pattern .
A command message is simply a regular message that happens to contain a command. A Simple Object Access Protocol (SOAP) request is a command message.
Command messages are usually sent on a point-to-point channel so that each command will only be consumed and invoked once.
How can you transfer data between services?
Use a document message to reliably transfer a data structure between applications. See Figure 4.
Figure 4. Document message
A document message is just a single unit of information, a single object or data structure that may decompose into smaller units. The important part of a document message is its content; the document. This content is retrieved by un-marshalling / or de-serializing data.
Document messages are usually sent using a point-to-point channel. In request-reply scenarios, the reply is usually a document message where the result value is the document.
A document message can be any kind of message in the messaging system. A Simple Object Access Protocol (SOAP) reply message is a document message.
Several applications would like to use event notification to coordinate their actions, and would like to use messaging to communicate those events. How can messaging be used to transmit events from one service to another?
Use an event message for reliable, asynchronous event notification between applications. See Figure 5.
Figure 5. Event message
An event message extends the Observer model to a set of distributed applications. Event messages can be sent from one service to another to provide notification of lifecycle events within a service-oriented enterprise, or to announce the status of particular activities. Applications for this pattern include enterprise monitoring and centralized logging.
An important characteristic of event messages is that they do not require a reply.
An event message can be any kind of message in the messaging system. An event can be an object or data such as an XML document.
"If a message says that the Stock price for certain symbol has changed, that's an event. If the message provided information about the symbol, including its new price, that's a document."
Messages travel into a message channel in one direction, from the sender to the receiver. This asynchronous transmission makes the delivery more reliable and decouples the sender from the receiver. The problem is that communication between components often needs to be two-way. When one component notifies another of a change, it may want to receive an acknowledgement.
How can messaging be two-way?
Send a pair of request-reply messages, each on its own channel. See Figure 6.
Figure 6. Request reply message
Request-Reply has two participants:
- Requester (Service Consumer). Sends a request message and waits for a reply message.
- Replier (Service Provider). Receives the request message and responds with a reply message.
The request channel can be a point-to-point channel or a publish-subscribe channel. The difference is whether the request should be broadcast to all interested parties or should only be processed by a single consumer. The reply channel, on the other hand, is almost always point-to-point, because it usually makes no sense to broadcast replies.
The request is like a method call. As such, the reply is one of three possibilities:
- Result value
The request should contain a return address to tell the replier where to send the reply. The reply should contain a correlation identifier that specifies which request this reply is for.
Channels, also known as queues, are logical pathways to transport messages. A channel behaves like a collection or array of messages, but one that is magically shared across multiple computers and can be used concurrently by multiple applications.
A service provider is a program that sends a message by writing the message to a channel. A consumer receives a message from a channel. There are different kinds of messaging channels available.
The sender dispatches a message to a messaging system, which is responsible for relaying the message to a particular recipient. The messaging system might proactively deliver the message (by contacting the recipient directly), or hold the message until the recipient connects to retrieve it.
How can you ensure that exactly one consumer will receive the message?
Send the message on a point-to-point channel, which ensures that only one receiver will receive a particular message. See Figure 7.
Figure 7. Point-to-point channel
A point-to-point channel ensures that only one consumer consumes any given message. If the channel has multiple receivers, only one of them can successfully consume a particular message. If multiple receivers try to consume a single message, the channel ensures that only one of them succeeds, so the receivers do not have to coordinate with each other. The channel can still have multiple consumers to consume multiple messages concurrently, but only a single receiver consumes any one message.
The service provider broadcasts an event once, to all interested consumers.
Send the event on a publish-subscribe channel, which delivers a copy of a particular event to each receiver. See Figure 8.
Figure 8. Publish-subscribe channel
A publish-subscribe channel that is developed based on Observer pattern , and describes a single input channel that splits into multiple output channels—one for each subscriber. After publishing an event into the publish-subscribe channel, the same message is delivered to each of the output channels. Each output channel is configured on one-to-one topology to allow only one consumer to consume a message. The event is considered consumed only when all of the consumers have been notified.
A publish-subscribe channel can be a useful for systems management, error debugging and different level of testing.
The receiver must know what type of messages it is receiving, or it won't know how to process them. For example, a sender might send different objects such as purchase orders, price quotes, and queries, but a receiver will probably take different steps to process each of these, so it has to know which is which.
Use a separate datatype channel for each data type, so that all data on a particular channel is of the same type. See Figure 9.
Figure 9. Datatype channel
In any messaging system there are several separate datatype channels for each type of data. All of the messages on a given channel will contain the same type of data. Based on data type, the service provider sends the data to the channel and the consumer receives data from the appropriate datatype channel.
Dead Letter Channel
There are a number of reasons for message delivery to fail. Issues might be message channel configuration problem, a problem with consumers, or message expiration.
When there is any delivery issue with the message, it can be moved to a different messaging channel called a dead letter channel. See Figure 10.
Figure 10. Dead letter channel
A dead letter channel is a separate channel dedicated for bad messages or invalid messages. From this channel messages can be rerouted to the mainstream channel or even in separate channel for special processing of the message.
One of the main advantages of asynchronous messaging over RPC is that the participants don't need to be online at the same time. While the network is unavailable, the messaging system has to use a store and forward mechanism to ensure message durability. By default, the messages are stored in memory until they can be successfully forwarded to the next contract point. This mechanism works well when the messaging system is running reliably, but if the messaging system crashes, all of the stored messages are lost. As a preventative measure, applications use persistent media like files and databases to ensure recovery from system crashes.
Use a guaranteed delivery mechanism to make messages persistent. See Figure 11.
Figure 11. Guaranteed delivery
With guaranteed delivery, the messaging system uses a built-in data store (local storage disk space in a participant computer) to persist messages in each participant computer on which the messaging system is installed. The message is safely stored until it is successfully delivered. In this way, it ensures guaranteed delivery.
This guaranteed delivery mechanism increases system reliability, but at the expense of performance as it involves considerable numbers of I/O and consumes a large amount of disk space. Therefore if performance or debugging/testing is the priority try to avoid using guaranteed delivery.
An enterprise consists of various independent applications communicating with each other in a unified manner.We need an integration /service architecture that enables those applications to coordinate in a loosely coupled fashioned.
Structure the connecting middleware between these applications as a message bus that enables them to work together using messaging as shown in Figure 12.
Figure 12. Message bus
A message bus is a combination of a common data model, a common command set, and a messaging infrastructure to allow different heterogeneous systems to communicate through a shared set of interfaces.
A message bus can be considered as a universal connector between the various enterprise systems, and as a universal interface for client applications that wish to communicate with each other. A message bus requires that all of the applications should use the same canonical data model. Applications adding messages to the bus may need to depend on message routers to route the messages to the appropriate final destinations.
Almost all messaging system uses built in router as well as customized routing. Message Routers are very important building blocks for any good integration architecture. As opposed to the different message routing design patterns, this pattern describes a hub-and-spoke architectural style with few specially embedded routing logic.
In Search of the Right Router
An important decision for an architect is to choose the appropriate routing mechanism. Patterns that will help you make the right decision are:
- Pipes and filter
- Content-based router
- Content aggregator
Pipes and Filter
How can you divide a larger processing task into a sequence of smaller, independent processing steps?
Use the pipes and filters pattern to divide a larger processing task into a sequence of smaller, independent processing steps (filters) that are connected by channels (pipes). See Figure 13.
Figure 13. Pipes and filter
Each filter exposes a very simple interface: it receives messages on the inbound pipe, processes the message, performs business transformations, and publishes the results to the outbound pipe. The pipe connects one filter to the next, sending output messages from one filter to the next. It's very similar to execution of a method call through passing parameters and getting a return value. It follows 'chain of responsibility'  pattern. Because all components use the same external interface they can be composed into different solutions by connecting the components to different pipes. The connection between filter and pipe is sometimes called port. In the basic form, each filter component has one input port and one output port.
The pipes and filters pattern uses abstract pipes to decouple components from each other. The pipe allows one component to send a message into the pipe so that it can be consumed later by another process that is unknown to the component. One of the potential downsides of pipes and filters architecture is the larger number of required channels that consume memory and CPU cycles. Also, publishing a message to a channel involves a certain amount of overhead because the data has to be translated from the application-internal format into the messaging infrastructure's own format.
Using pipes and filters also improves module-wise unit testing ability. It can help to prepare a testing framework. It is more efficient to test and debug each core function in isolation because we can tailor the test mechanism to the specific function.
The routing can be based on a number of criteria such as existence of fields, specific field values, and so on.
Use a content-based router to route each message to correct consumer based on message content. See Figure 14.
Figure 14. Content-based router
The content-based router examines the message content and routes the message onto a different channel based on message data content. When implementing a content-based router, special caution should be taken to make easily maintainable routing logic. In more sophisticated integration scenarios, the content-based router can be implemented as a configurable rules engine that computes the destination channel based on a set of configurable rules.
The messaging system exchanges messages between a variety of sources. The messages have similar content but different formats, which can complicate the processing of combined messages. It would be better processing decision if we assigned different components with different responsibilities . For example, if we want to select all of the transactions of a particular customer from different business zones for a particular quarter. This method is called event linking and sequencing.
Use a stateful content aggregator, to collect and store individual messages and combine those related messages to publish a single aggregated message. See Figure 15.
Figure 15. Content aggregator
A content aggregator is a special filter that receives a stream of messages and correlates related messages. When a complete set of messages has been received, the aggregator collects information from each correlated message and publishes a single, aggregated message to the output channel for further processing. Therefore, aggregator has to be stateful, because it needs to save the message state with processing state until the complete formation of the aggregation.
When designing an aggregator, we need to specify the following items:
- Correlation ID. An identifier that indicates messages internal relationship
- End condition. The condition that determines when to stop processing
- Aggregation algorithm. The algorithm used to combine the received messages into a single output message
Every time the content aggregator receives a new message, it checks whether the message is a part of already existing aggregate or a new aggregate. After adding the message, the content aggregator evaluates the process end condition for the aggregate. If the condition evaluates to true, a new aggregated message is formed from the aggregate and published to the output channel. If the process end condition evaluates to false, no message is published and the content aggregator continues processing.
There are several possible types of Service Consumer. In this pattern catalogue we will present a set of consumer patterns.
Transactions are important part of any messaging system and are sufficient for any participant to send or receive a single message. However, a few specific scenarios might need a broader transactional approach, which in turn may need special transactional coordination. These cases include (but are not limited to):
- Send-receive message pairs. Receive one message and send another.
- Batch message. Send or receive a group of related messages in a batch mode.
- Message/database coordination. Send or receive a message combined with database update. For example, when an application receives and processes a message for ordering a product, the application will also need to update the product inventory database.
Scenarios like these require a different specification of transactional boundaries with much more complexities involving more than just a single message and may involve other transactional stores besides the messaging system.
How can you solve this kind of transactional problems?
Use a transactional client—make the client's session with the messaging system transactional and ensure that the client can specify complex transaction boundaries. See Figure 16.
Figure 16. Transactional client sequence diagram
Both participants can be transactional. From a sender's point of view, the message isn't considered added to the channel until the sender commits the transaction. On the other hand message isn't removed from the channel until the receiver commits the transaction.
With a transactional receiver, messages can be received without actual removal of the message from the channel. The advantage of this approach is that if the application crashed at this point, the message would still be on the queue after message recovery has been performed; the message would not be lost. After the message processing is finished, and on successful transaction commit, the message is removed from the channel.
In any messaging system, the consumer needs an indication that application is ready so that it can consume the message. The best approach for the consumer is to repeatedly check the channel for message availability. If any message is available, the consumer consumes it. This checking is a continuous process known as polling.
The application should use a polling consumer, one that explicitly makes a call when it wants to receive a message. See Figure 17.
Figure 17. Polling consumer
A polling consumer is a message receiver. A polling consumer restricts the number of concurrent messages to be consumed by limiting the number of polling threads. In this way, it prevents the application from being blocked by having to process too many requests, and keeps any extra messages queued up until the receiver can process them.
The problem with polling consumers is that it's a continuous process involves dedicated threads and consumes process time while polling for messages.
Instead of making the consumer poll for the message, a better idea might be to use event driven message notifications to indicate message availability. See Figure 18 and Figure 19. The application should use an event-driven consumer. Event-driven consumers automatically consume messages as they become available.
Figure 18. Event-driven consumer
Figure 19. Event-driven consumer sequence diagram
An event-driven consumer is invoked by the messaging system at the time of message arrival on the consumer's channel. The consumer uses application-specific callback mechanism to pass the message to the application.
In some cases you might require guaranteed message delivery where a message consumer is not connected to publish-subscribe channel or has crashed before receiving a message. In this case the messaging system needs to ensure guaranteed message delivery when the consumer reconnects to the system.
Use a durable subscriber. See Figure 20 and 21.
Figure 20. Durable subscriber
Figure 21. Durable subscriber sequence diagram
A durable subscription saves messages for an off-line subscriber and ensures message delivery when the subscriber reconnects. Thus it prevents published messages from getting lost and ensures guaranteed delivery. A durable subscription has no effect on the normal behavior of the online/active subscription mechanism.
For certain scenarios, instead of using Durable Subscription mechanism, some reliable messaging implementations can produce duplicate messages to ensure guaranteed, at-least once Delivery. In these cases, message delivery can generally only be guaranteed by resending the message until an acknowledgment is returned from the recipient. However, if the acknowledgment is lost due to an unreliable connection, the sender may resend a message that the receiver has already received.
We need to ensure that the messaging system is able to safely handle any messages that are received multiple times.
Design a receiver to be an idempotent receiver. See Figure 22.
Figure 22. Duplicate message problem
The term idempotent is originated from mathematics to describe the ability of a function that produces the same result if it is applied to itself, i.e. f(x) = f(f(x)). In messaging Environment this concept ensures safely resent of same message irrespective of receipt of same message multiple times.
In order to detect and eliminate duplicate messages based on the message identifier, the message consumer has to maintain a buffer of already received message identifiers. One of the key design issues is to decide message persisting timeout. In the simplest case, the service provider sends one message at a time, awaiting the receiver's acknowledgment after every message. In this scenario, the consumer efficiently uses the message identifier to check that the identifiers are identical. In practice, this style of communication is very inefficient, especially when significant throughput is required. In these situations, the sender might want to send a whole set of messages in a batch mode without awaiting acknowledgment for individual one. This will necessitate keeping a longer history of identifiers for already received messages, and the size of the message subscriber's buffer will grow significantly depending on the number of message the sender can send without an acknowledgment.
An alternative approach to achieving idempotency is to define the semantics of a message such that resending the message does not impact the system. For example, rather than defining a message as variable equation like 'Add 0.3% commission to the Employee code A1000 having a base salary of $10000', we could change the message to 'Set the commission amount $300.00 to the Employee code A1000 having a base salary of $10000'. Both messages achieve the same result—even if the current commission is $300. The second message is idempotent because receiving it twice will not have any effect. So whenever possible, try to send constants as message and avoid variables in messages. In this way we can efficiently achieve idempotency.
When designing service consumer for multiple styles of communication, it might seem necessary to define the service for each style, and this concept can be linked to the Factory Design Pattern . In SOA it's a challenge to invoke the right services based on the style of communication.
Design a service factory that connects the messages on the channel to the service being accessed. See Figure 23.
Figure 23. Service factory
A service factory may return a simple method call or even a complex remote process invocation. The service factory invokes the service just like any other method invocation and optionally can create a customized reply message.
Message Facade Pattern
Depending on business requirements, you might need to encapsulate business logic flow and complexity behind a standard facade.
A message facade can be used asynchronously and maintained independently. It acts as an interceptor between service consumer and service provider. See Figure 24.
Figure 24. Message facade
The client creates a command message and sends it to the message facade through messaging channel. The facade receives the message (using a polling consumer or an event-driven consumer) and uses the information it contains to access business tier code to fulfill a use case. Optionally, a return message is sent to the client confirming successful completion of the use case and returning data.
So far we have understood how messaging patterns exist at different levels of abstraction in SOA. In this paper, which is the first of a two-part series on messaging patterns in Service-Oriented Architecture, Message Type patterns were used to describe different varieties of messages in SOA, Message Channel patterns explained messaging transport systems, Routing patterns explained mechanisms to route messages between the Service Provider and Service Consumer, and finally Service Consumer patterns illustrated the behavior of messaging system clients. In the next issue of JOURNAL, the final part of this paper will cover Contract patterns that illustrate the behavioral specifications required to maintain smooth communications between Service Provider and Service Consumer and Message Construction patterns that describe creation of message content that travels across the messaging system.
G Hohpe & B Woolf, Enterprise Integration Patterns, (adapted material from pages 59-83), (c) 2004 Pearson Education, Inc. Reproduced by permission of Pearson Education, Inc. Publishing as Pearson Addison Wesley. All rights reserved.
- Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions, Gregor Hohpe and Bobby Woolf, Addison-Wesley, 2004
- Service-oriented architecture: A Primer, Michael S Pallos, EAI Journal, December 2001
- Solving Information Integration Challenges in a Service-Oriented Enterprise, ZapThink Whitepaper, http://www.zapthink.com
- SOA and EAI, De Gamma Website, http://www.2gamma.com/en/produit/soa/eai.asp
- Introduction to Service-Oriented Programming, Guy Bieber and Jeff Carpenter, Project Openwings, Motorola ISD, 2002
- Java Web Services Architecture, James McGovern, Sameer Tyagi, Michael Stevens, and Sunil Mathew, Morgan Kaufman Press, 2003
- Using Service-Oriented Architecture and Component-Based Development to Build Web Service Applications, Alan Brown, Simon Johnston, and Kevin Kelly, IBM, June 2003
- The Modular Structure of Complex Systems, Parnas D and Clements P, IEEE Journal, 1984
- Design Patterns: Elements of Reusable Object-Oriented Software, Gamma E, Helm R, Johnson R, and Vlissides J, Addison-Wesley, 1994
- Computerworld Year-End Special: 2004 Unplugged, Vol. 10, Issue No. 10, 15 December 2003—6 January 2004
- Applying UML and Patterns—An introduction to OOA/D and the Unified Process, Craig Larman, 2001
About the author
Soumen Chatterjee is a Microsoft Certified Professional and Sun Certified Enterprise Architect. He's significantly involved in enterprise application integration and distributed object oriented system development using Java/J2EE technology to serve global giants in the finance and health care industries. With expertise in EAI design patterns, messaging patterns and testing strategies he designs and develops scalable, reusable, maintainable and performance tuned EAI architectures. Soumen is a Senior Consultant with Cap Gemini Ernst & Young. He's an admirer of extreme programming methodology and has primary interests in AOP and EAI. Besides software, Soumen likes movies, music, and follows mind power technologies. Soumen can be reached at firstname.lastname@example.org.
This article was published in the Architecture Journal, a print and online publication produced by Microsoft. For more articles from this publication, please visit the Architecture Journal website.