Successful projects rarely build all layers of the architecture at the same time. Most of them build it through a process I refer to as spiking . A spike is a user -visible piece of functionality (usually described by a use case or an XP-style story) that has been completely implemented through all appropriate subsystems or layers of the tarchitecture . It is suitable for alpha (and sometimes) beta testing and is stable enough for the end-user documentation team to begin online help and related end-user documentation features. The key attribute of a spike is that it " drives " some specific aspect of functionality through all relevant subsystems (I use the term "nail" to represent a connection made between two subsystems). Spikes are an approach to incremental development. I'm not the first person to advocate them, and I'm certain I won't be the last. That said, I've found that they are a good metaphor for the work of the team. Imagine, if you will, that a single subsystem is a four-by-six board. Your architecture can then be thought of as a series of these boards stacked one on top of the other. A nail joins two boards but a spike drives through all of them. One of my development managers recently pointed out that spiking is both a process and an eventa process because driving the spike through many layers can be hard work and new to many development teams ; when finished, it's celebrated as an event. While the first spike proves the basics of the architecture and is the foundation for sound risk management practices, there is still room to adjust the boards to make certain the system is lining up as intended. As more spikes are added, the system becomes more stable. The spikes also come more quickly as the team becomes skilled in driving them through all of the layers. The overall organization also benefits, as the specific functionality of the system is developed over time. If you have had some trouble adopting an iterative development process, consider spiking. However, even teams that have adopted spiking or another iterative approach can have trouble determining where to begin the development efforts. If you get stuck, try starting with either the services layer or the user interface, as shown in the top half of Figure 8-2. Figure 8-2. Spiking the architecture
The top half of Figure 8-2 illustrates the approach of starting with the services layer, preferably with a lo-fidelity user interface prototype to set expectations of how the services may be used by the user interface. With clear and concise interfaces for the services, the user interface team can begin to hoist their functionality on top of them. Note that in many projects the services don't have to be completely implemented before the user interface team begins using them. Many times a service that returns dummy data is more helpful than a service connected to a live data source, because you can move faster with dummy data. In this example, the system is relatively simple, and has no need for a complex domain model. Thus, as services are coded, they are connected to the database and the whole system grows organically through spikes. I place considerable emphasis on defining services because getting service interfaces right makes it is far easier to get the rest of the tarchitecture right. Getting them wrong puts the project at risk, because eventually it will have to be fixed. More importantly, if you're practicing an iterative development model, chances are good that you're going to base the implementation of additional services after existing services. More simply, after a few services are built, future services tend to be built using the same general style. Agile development methods , such as SCRUM, XP, or agile modeling, are especially useful in these first few spikes, because they are designed to provide explicit feedback loops . There are many other ways to build a layered architecture. Another option, shown in the bottom half of Figure 8-2, occurs when the team must deal with substantial amounts of existing data or when the persistent storage requirements are extremely demanding. In this case, it is safer to start with the design of the database and let it inform the design of the services and domain layers. There is a strong correlation between complex persistent storage requirements and complex domain models. Later in the project the user interface is hoisted on top of the services layer. If there are sufficient resources, multiple layers can be addressed in parallel. The key to this approach is to establish early on the core subsystems of the architecture. This is best accomplished by agreeing on subsystem interfaces early in the development of the project and using continuous daily or weekly builds to ensure that subsystems remain in sync. If you're going to attempt parallel development, make certain the development team agrees on which layer will be driving the other layers. Something has to come first, and a good rule of thumb is that it should be either the services or the domain layer. This doesn't mean that you'll get everything rightjust that you'll have an agreed upon way to get started. Suppose, for example, that in a complex application you agree that the domain model will drive development. As domain objects and complex business rules are implemented, they are exposed through services and connected to a persistent store. During the development of a given use case it is quite possible that the user interface development team will discover that an important attribute was missed during analysis. Rather than adding this attribute (and its associated semantics) only to the user interface, the user interface team should negotiate with other teams, starting with the domain team to add it (and its associated semantics) to the appropriate domain objects. The domain team, should, in turn , negotiate with the database team to ensure that the appropriate changes are made to the persistent storage model.
Unfortunately, there can be an unpleasant wait for all layers to catch up with each other. I have found that a two-stage process works best. First, the domain layer makes the necessary changes, allows the services layer to change to support the user interface, and simulates changes to the database model through an "in-memory" database. This allows the user interface team to proceed and allows the domain team to verify the changes to the application. While this is happening the database team is making their changes. When finished, the domain is connected to the database layer, and the entire application works. No matter what, you should spike the architecture as often as possible to reduce risk. |