Like it or not, we live in a world where expectations are high: development teams are asked to get more done, in less time, in the face of moving targets, last-minute design changes, and complex, difficult-to-understand systems.
And those are the easy engagements.
In managing software development projects for well over two decades (yes, I’m that old — you can check my LinkedIn profile) there’s one specific problem for which many solutions have been proposed — managerial, organizational, governance — and which seems to elude most approaches and slow-down most development teams.
The canonical example is a project, where the team is tasked to put up a new website, one that includes dynamic content display, based on data accessed and delivered by back-end services. If all of these components (or even just some of them) must be developed from scratch, the typical proposed project plan looks like this:
But, given the reality of simultaneously developing a UI layer, a services layer and a data access layer, the schedule soon becomes this:
Now, no development team, no matter how professional, experienced and well-managed, can hope to avoid the fundamental issue that creates this “integration chaos” without understanding just why this happens.
In a nutshell:
When a project has multiple layers, and one layer depends on one or more other layers to be functional before the stakeholders can see the result in action, a framework or process is needed to insure each layer can continue its development, testing and stakeholder review uncoupled from other layers. That uncoupling should be done in a manner that permits — at all times — checking of the correctness of the developed layer in the face of a wide range of behaviors from the replaced layer.
A pretty obvious statement, it would seem. But the devil is in the details of the framework/process chosen to uncouple these efforts.
One framework, likely in use since modern software development began, is “stubbing” or “mocking”.
Stubbing and mocking are intended to be very context-specific, short-term solutions to missing or hard-to-access software components, usually early in a development cycle.
Stubs provide replacement implementations for objects, methods, or functions in order to remove external dependencies. Stubs are typically used during unit and component testing for two main purposes:
- To isolate the code under test from the integrated environment.
- To enable testing to proceed when it is not possible to access an external resource or problematic method/function/object.
If you’re trying to write a unit test and need to replace a simple call to a database, external libraries (e.g., file I/O) or other system API, stubbing might be perfectly suited for your needs.[…] stubs/mocks are typically used to “skip” unavailable system components… — http://stackoverflow.com/questions/12055654/stubs-mocks-vs-service-virtualization-yikes
While there are situations in which stubbing/mocking can help with development tasks in the face of missing dependencies, such a solution is exposed to the same issue as any such solution in a fast-moving environment where changes can happen unexpectedly. Stubs are typically throw-away placeholders, designed with only enough fidelity to the missing dependency to represent a limited and short-term solution.
However, with the advent of large development teams, the widespread use of SOA (including the user of third-party services), and the rise of Agile methodologies, stubbing and mocking became less valuable to the development process.
Service virtualization, on the other hand, is generally not context-specific and can be used throughout the project cycle, including production, by all developers.
In software engineering, service virtualization is a method to emulate the behavior of specific components in heterogeneous component-based applications such as API-driven applications, cloud-based applications and service-oriented architectures. It is used to provide software development and QA/testing teams access to dependent system components that are needed to exercise an application under test (AUT), but are unavailable or difficult-to-access for development and testing purposes. — Wikipedia
Service virtualization may appear, at first, to be not much different from stubbing or mocking. Both classes of solution allow development and testing of software components in the absence of dependent components.
Where they differ, however, is in:
- How they do their work.
- Their flexibility in responding to changes in design.
- Their ability to mimic the missing dependency with high fidelity.
Service virtualization, in its most common use, replaces missing dependencies at well-defined and well-documented interfaces that are:
- Defined, at least partly if not fully, early in the development cycle. Web services APIs are a good example of this.
- Well documented, using appropriate approaches, so as to be clear and unambiguous to the developers on “both sides” of the interface. WSDLs and XSDs are good examples of this.
- Encapsulate logic for the missing dependency that can be easily modified in response to design changes. This is probably the most difficult part of creating and using service virtualization, but tools exist to make this somewhat easier.
The bottom line is, no matter how a service is virtualized, this should always be true:
…as far as an application is concerned, those responses issued by virtual services are as good as the real thing — What is Service Virtualization?, SmartBear.com
As a result of this creation of a replacement for a missing dependency, and one which is of high fidelity, indistinguishable from the real service:
- Development of a software component can proceed without waiting for a dependent component to progress far enough to “come alive”–for instance, a UI layer can be running and available for feedback before web services are fully ready.
- The virtualized service can serve as a “sanity check” on architecture and design decisions — errors can be corrected before they propagate throughout multiple layers.
- The service implementation may serve as a basis for documentation of the system behavior and as a baseline for proper operation of the real service.
How does one accomplish implementation of a virtual service? A full exposition would be rather long (and perhaps the subject of another posting), but the general answer is pretty simple.
There are two common ways of setting up a virtualized service.
- Start with the contract (e.g. a WSDL or other protocol-specific descriptor) and create predetermined responses. This can be done manually using normal Java or .NET code, or you can use a commercial product. An advantage of this method is that the team writing the component doesn’t have to wait for the real version of the service to be completed. The downside is that the real version needs to actually match the fake one, which becomes a questionable proposition as timelines become longer.
- Use traffic recordings. A tool sits between the component under test and its down-stream dependencies. This tool basically acts as a proxy, gathering information about how the components interact. Later those recordings can be used to simulate the conversation between the component and the servers it depends on.
Most COT frameworks support all four techniques to some extent:
- CA LISA Pathfinder.
- IBM Rational Test Virtualization Server.
- Parasoft Virtualize.
- HP Service Virtualization.
- Many open-source toolsets (e.g., WireMock and Betamax, though these are really mocking tools).
In addition, where warranted:
- Bespoke implementations.
The choice of toolset often depends upon the client’s existing vendor relationships, knowledge and supporting infrastructure.
An excellent checklist of service virtualization tool attributes can be found at: