5 Tips When Managing Multiple Service Versions

November 28, 2009

Many teams that build service capabilities have to manage multiple versions – this is a problem for any shared asset really – be it a library, component, or service. Using extensible schema contracts (also referred to as Consumer Driven Contracts) you can design service contracts that allow both provider to evolve and consumer to integrate in a flexible manner. In this post, I want to suggest five additional tips when managing web services:

1. Figure out how many versions your team will support concurrently. Too little will force all your consumers to be on a single version and too many will become a maintenance nightmare for you (the provider). In past implementations, I have maintained upto 3 versions while actively moving all service consumers towards one target version. A related approach is to have multiple flavors for your service capability one that returns data that most consumers want, the second that provides the minimal set of attributes, and a third flavor that returns the full list of data items. This may or may not be possible in your case, but something to consider when designing contracts.

2. Figure out how you are going to support multiple versions as a service provider. You can use xml schema namespaces to indicate versions: http://some-company.com/services/CustomService_ver1_0.xsd, ver1_1.xsd and so on. Consider creating a service adapter that can translate back and forth between a new service implementation and the existing one. This can potentially help you with one server side implementation of the functional logic and still service your current and new consumers. This adapter component can perform necessary data transformations, error code & error message translations, and massage response with data attributes as appropriate.

3. Communicate the change in the service capability and gauge the appetite with existing consumers for their ability to absorb the changes in the same release time frame that you are targeting to drop your new version. If you co-ordinate the release, you can get them to new version when you go live. However, for mission critical applications you will want to support both your current and new version concurrently for a small time period before switching the old one off.

4. When you design forward-compatible schemas, you can test the data-binding against multiple platforms. For example, use WSDL2Java if you are using Apache Axis in Java or wsdl.exe if you are in .NET and generate appropriate web service proxy classes and data binding classes. What i have done is to implement JUnit and NUnit automated test cases that run everytime there is a new WSDL or service contract (XSD) change. This will not only validate the service functional logic, but also the forward-compatibility of existing clients. Make sure your when you generate bindings that you generate with both the new schema/wsdl (your updated version) and the existing schema/wsdl files (the version currently used by production clients).

5.  Establish lightweight service governance – it is critical to plan how many service flavors and versions you will support, when will they get upgraded, deprecated, decommissioned, etc. and communicate those with your consumers. Identify checkpoints in your development process where contracts can be reviewed and service behavior can be discussed openly. The well thought out service orientation strategy is a benefit for both the provider and the consumers in your organization.

What other tips/techniques have you used?

Like this post? Subscribe to RSS feed or get blog updates via email.

tweet this add to del.icio.us post to facebook


Systematic Reuse Success Factor #9 – Consistent API

November 26, 2009

Have you noticed how some application interfaces are consistently named and exhibit consistent behavior across components and services? This can be a critical success factor for systematic reuse. Reusable components are not isolated islands of functionality. Instead, they are meant to be leveraged in a variety of applications and business processes. Consistent interfaces provide several benefits:

  • They reduce learning curve when a developer tries to understand and evaluate the asset for his/her need.
  • Reduces technical debt – consistent API reduces the need to refactor code and reduces regression testing efforts as well.
  • They increase the likelihood of predictable behavior across applications. This is critical for assets that get reused across business processes with an impact ultimately to end user experience (e.g. what if your customer can update address when opening accounts but won’t be able to do that when updating accounts?).
  • Eases integration and testing efforts. Consistent behavior can simplify testing reusable assets. If an asset behaves consistently whether it is invoked by a web application or a backend process, knowledge about test data and integration behavior is applicable across multiple projects
  • Makes documentation easier to follow: consistent interfaces can facilitate the use of templates for document generation as well where similar files/hyperlinks can be generated.

These aren’t the only benefits – feel free to suggest additional ones.


Prefer Real-time Capabilities Even If Your Consumers Don’t

November 25, 2009

Build near real-time capabilities even if your consumers don’t want them. Your consumer may not want a real-time interface or maybe unable to integrate with one. It is tempting to just go for a batch based solution because, that is what your consumer is asking for. For now at least. However, if you build one off batch file extracts or directly expose your legacy system to make one consumer happy, you will encounter the ill effects of tightly coupled systems.

There are several approaches to achieve long-term reuse goals and address the immediate customer need:

  1. Publish a standard message that you will want to treat as a reuse candidate going forward. A subscriber can drain, accumulate messages, transform them to a customer-specific format, and and append it to a file. A scheduled job or process can transfer this file to your customer.
  2. Create a reusable service capability that provides the data in the target format that you want to maintain/evolve going forward. You can create a batch process that shares the same interface that the real-time service uses.  Note: volume is a critical factor here though – you don’t want to make several atomic calls when it is more efficient to fetch data in bulk. You could have a configurable parameter for fetching multiple records at a time – the real-time service can use a much smaller number when compared to the batch process.
  3. For large data volumes,  consider populating a read-only data store using database replication. File extracts can then be driven off this new database. This has the advantage of reducing load on your operational data stores at the same time facilitating additional consumers who might prefer a SQL interface or a file extract based solution. Downsides: additional moving parts and increased cost for a new data store.

When you build real-time capabilities,  adding consumers doesn’t involve too much effort. Are there additional approaches to pursue?

Like this post? Subscribe to RSS feed or get blog updates via email.

tweet this add to del.icio.us post to facebook


Software Reuse Quick Tip #24

November 25, 2009

Tip #24 – Identify common behavior and encapsulate it

Looking for common behavior across classes is an effective way to reuse behavior. When you find yourself cutting and pasting code, take a step back and reflect on the common behavior that is being implemented. If the duplication is due to the same behavior realized in different ways, introduce a new interface. If multiple objects have the same functionality and can derive from a parent object, introduce an inheritance hierarchy.

This can be done in an iterative fashion as well – if you failed to recognize an interface initially that is okay. Look for opportunities to refactor existing code to introduce a new interface. For example, you can use the Eclipse IDE’s refactoring feature – extract interface – to create a new interface from an existing class.

Why is this important for systematic reuse? Because, by isolating and realizing common behavior you reduce the need for multiple components and classes to re-implement the same functionality. If two classes need the same piece of data, or if they both connect with the same external system, why would you want to code them separately?

Like this post? Subscribe to RSS feed or get blog updates via email.

tweet this add to del.icio.us post to facebook


Visualize Service Metrics

November 24, 2009

Business applications often utilize log files and databases to capture metrics about usage and error patterns. However, analysis and pattern detecting becomes challenging with additional data and system complexity.  Tree map visualization of application metrics could greatly aid rapid view of system state, error analysis, trends, and remedial actions.  A tree map visualization can be generated using metrics from a database.  It can generate useful views and present information of use to both business stakeholders and the system support team.

Service View – a treemap of metrics organized by service invoked on your SOA platform. The idea is to provide a comprehensive view of the metrics captured and answer questions such as the following: which services are being invoked in the system? Which services receive the highest volume of invocations? How does the volume of service invocations compare with each other? What proportion of invocations in each service was successful and what proportion ended in generating errors?

Transport View – a treemap of metrics organized by kind of transport used to invoke requests in your SOA platform. This is especially useful for systems support staff who need to quickly assess the system-wide impact of messaging providers and their non-availability. The idea is to provide a transport-level view of the metrics captured and answer questions such as the following: what are the transports used by clients when invoking services in your SOA paltform? Which transport mechanism is being used to process the bulk of requests? How does volume of invocations via a transport compare with one another? Which transport is having a higher proportion of errors? Are the failing invocations using reliable transports or are they using unreliable ones?

Status Code View – a treemap of metrics organized by kind of status codes that service requests returned. This is very useful for both development staff and systems support staff. This view displays a bird’s-eye view of the metrics with respect to return codes and answer questions such as the following: what service codes are being returned to clients? What proportion of codes are success codes and erroneous codes? What is the volume of error codes with respect to each other? In summary, this view provides a sense of how the system is performing as a whole – what matters most is whether the platform can provide good response to clients and this is a succinct visualization that answers that.

Are there additional opportunities for visualizing metrics using data in your services layer?

Like this post? Subscribe to RSS feed or get blog updates via email.

tweet this add to del.icio.us post to facebook


Systematic Reuse Recipe #1 – Minimize Point to Point Integrations

November 21, 2009

Problem Statement

A consuming application/business process wants to integrate with your reusable asset. However, the consumer doesn’t want to take your standard message – wanting a specific format that will make it easier for them. Why? Could be because of several reasons: lack of time/money/skills or technical limitations (e.g. their system can handle only delimited files and cannot parse XML).

Suggested Approach

The immediate, tactical (and often tempting) solution would be to just format the data per the consumer’s format and integrate in a point-to-point fashion. Don’t settle for this option too quickly! Prefer to publish a standard publication in that is in line with your long-term direction (e.g. offer reusable message publications in XML format indicating changes to critical data entities or state changes in business processes). Create a subscriber that tranforms the standard message to the consumer-specific format.

Rationale

If point to point integrations go ungoverned, you will end up with a rat’s nest of tightly coupled integrations that ultimately hurt business agility.Your long-term intent is to have multiple consumers (web applications, backend systems, business processes, etc.) consume reusable message publications.If several business processes need the same core data or notifications about state changes, why would you want to integrate with them separately? Publications will not only reduce integration effort, they place less strain on your system resources – publish once and subscribe several times. No need to query databases or invoke external systems every time there is a new integration.

Note: The additional transformation logic will require extra logging/error handling but over the long haul is a better option than going for a point-to-point integration approach.

This will enable the asset provider, to integrate new applications faster (no need to custom develop messages and integration code for every new consumer) and reduce the cost of maintenance. Reducing application to application coupling is a key motivation for pursuing this approach as well.

Like this post? Subscribe to RSS feed or get blog updates via email.

tweet this add to del.icio.us post to facebook


Using a Common Architecture for the Services Product Line

November 20, 2009

I introduced the data services product line in earlier posts here and here. As  a follow up I wanted to set the context for a common architecture for this product line. The idea is to have all products in a services product line need to share the same underlying architecture. The common architecture enables the development of a set of common software components and also facilitates variation management, product configuration, and consistent behavior across all the services.

The architecture typically consists of both domain agnostic technical assets and domain specific assets. The domain agnostic assts includes logging, error handling, auditing, metrics, and legacy service invocation modules. The domain specific assets includes data assets, relationships, domain events, and business process workflow components that get triggered based on rules. The common architecture also provides components to integrate with the workflow engine, initialize business processes, as well as provide approval, routing, and escalation steps for any kind of enterprise data entity.

The architecture needs to be reviewed to ensure that it meets the product line’s non-functional requirements such as availability, scalability, and runtime performance.  For instance, supporting high availability can be tricky when data repositories undergo scheduled maintenance on a periodic basis. Scalability is also a key quality attribute that needs to be addressed by the architecture where the need for connection pools, thread pools, and messaging session pools are extensively utilized. Additionally, the architecture can provide caching capabilities for most accessed data records as well as integrate with a lightweight rules engine for fast and efficient rule execution.

Data visibility is another key capability that the architecture needs to address – it can do so by providing an extension point in the processing lifecycle to integrate visibility logic (e.g. filtering attributes, masking data, or utilizing a third party authentication service to validate the identity of the caller etc.).  Ability to assign priorities to jobs in the processing queue based on SLA needs is another feature that could be provided by the common architecture.

Finally, the architecture needs to support several utility features: manage connectivity to each data source, allocate dedicated processor threads based on message volume, and monitor the health of each integration point outside the data service logic. The common product line architecture can potentially address both domain agnostic & domain specific needs.

In a follow up post, I will provide more detail on each of these capabilities and how they align with an agile software reuse approach.

Like this post? Subscribe to RSS feed or get blog updates via email.

tweet this add to del.icio.us post to facebook


Addressing Integration Complexity with Reusable Assets

November 19, 2009

One of the often-cited concerns with leveraging reusable software is design complexity. This is indeed a legitimate concern and as designers, we ought to ensure that it is managed appropriately. In this post, I want to provide some strategies for tackling integration complexity:

  1. Build Iteratively: this is undoubtedly an effective way to avoid over-engineered assets. Building assets iteratively means realizing functionality in small bites, over multiple releases even. Instead of trying to implement a perfect reusable asset, prefer building in increments. This has several benefits: reduced risk, increased relevance for your applications, early feedback on whether the asset has captured domain relationships appropriately, and opportunities to remove code or refactor behavior on a continuous basis.
  2. Capture natural variations in the domain:  reusable assets that don’t reflect the natural variations in the problem domain run into lots of issues. If you keep scratching your head trying to infer what the asset is trying to accomplish – examine the consumer-facing interfaces and ask yourself, does the interface reflect domain variations or is it providing needless variations or worse, ignoring must-have ones?
  3. Prefer convention over configuration: This is one of the foundational principles behind why frameworks such as Ruby on Rails are so popular. You can use this idea and simplify assets in many ways! For example, instead of forcing configuration for files, maybe a standard location would suffice. This idea can be leveraged with scripts that setup developer environments, automated regression tests, and reading/saving program output etc.  There might also be cases where input data is used to determine class instantiation or stylesheet selection. Again, if you come up with a simple convention, many lines of configuration can be eliminated.
  4. Loosely Couple Capabilities: Loosely coupled capabilities are easier to change and integrate. By creating reusable assets in a loosely coupled manner, you will also make it beneficial for consumers. Loose coupling provides another important benefit – making it easy to isolate assets and test them as individual components. If you are building service capabilities, explore the use of asynchronous message publications for real-time notifications to data/status updates.
  5. Strive for consistent naming and behavior: consistent naming reduces learning curve for developers as well as makes it easy for the asset provider to debug, integrate, and test reusable assets. Consistent behavior should go beyond simple method calls – you can extend this to services and business processes as well.
  6. Make Assumptions Explicit: A lot of design complexity can arise due to incorrect assumptions – for instance, there may be operating assumptions about security, data integration, tracking, and error handling.  There are a lot of design assumptions that get made as a natural part of the development process (e.g. every customer will always have a address, or that every customer needs to get authenticated prior to instantiating a business process). Make sure these assumptions are put in the open and for everyone to validate. It often turns out that an asset doesn’t have to implement a feature or that it may be implement an existing feature incorrectly.
  7. Provide consumer-friendly interfaces: Start designing from the consumer’s standpoint and strive for simple yet functionally rich interfaces. This has several benefits: you won’t expose needless internal complexity associated with the asset to the consumer (i.e. achieve right level of encapsulation) and also make it simple for consumers to integrate with the asset. If you have 10 options for a reusable asset but most customers use 2 frequently, why not set the other parameters with sensible defaults? Consumer friendly interfaces also ensure that you build assets that have tangible business value.
  8. Avoid abstractions for the sake of technical elegance: not every abstraction is meaningful, especially with respect to your problem domain. I wrote earlier about the domain-specific nature of variations and why one set of abstractions isn’t always appropriate for your problem. Experiment and iterate to get the right abstractions – they will help establish a shared language within the team and reduce needless complexity because of overly generic interfaces.
  9. Minimize compile-time and runtime dependencies: Reducing the number of moving parts – both in terms of compile time libraries and runtime libraries, services, and systems will make it easier to manage design complexity. Always, ask yourself – is this dependency absolutely essential? Does it introduce a single point of failure in the overall architecture? Is there a way to cache frequently accessed data or return that isn’t 100% up to date?
  10. Provide Mock Interfaces: When possible provide mock data/objects that can help consumers integrate and test assets quickly. This is related to the earlier point about minimizing dependencies but is also useful for customers to get a flavor for the kind of data or business rules that get executed as part of the asset’s functionality. Mocking also helps with another key benefit: asset co-creation. If you are developing in parallel with a consumer, mocking is a great way to agree on interfaces and develop in parallel.

What is your view on these strategies? Can you share some of the ideas/approaches that you have pursued to tackle integration complexity?

Like this post? Subscribe to RSS feed or get blog updates via email.

tweet this add to del.icio.us post to facebook


List of Return Codes for SOA

November 18, 2009

List of Return Codes

I wrote earlier about the idea of using consistent error codes for reusable assets. As a follow up, here is a document with a list of reusable return codes that can be used when building service capabilities as part of SOA initiatives. They are categorized into:

  • request processing
  • data processing
  • dependency access
  • transactions

This isn’t an exhaustive list by any means but can get you started in terms of achieving consistency across services and projects.The service consumer can use the return code to understand the service provider’s response. This consistent, uniform categorization of return codes can help you reuse error handlers (e.g. handle a particular error in the same way regardless of which service capability raised it).  It will also help with production support and troubleshooting – less learning curve for support staff and developers to categorize errors at runtime.

Note: The return code derived based on errors need not necessarily be the return code sent back to the service consumer. It is entirely possible that you return a friendly error to the consumer and a detailed error to production support.

Are there additional ones to include in this list?

Like this post? Subscribe to RSS feed or get blog updates via email.

tweet this add to del.icio.us post to facebook


Code Analysis Tools – Sample Ant Script

November 17, 2009

When you develop reusable components quality is very important. The higher a reusable asset’s usage, the higher the need for robustness. Unlike monolithic code, defects with reusable assets can rapidly impact several business processes and applications. All the more reason for the criticality of automated testing. In addition to testing, code analysis tools can detect defects, warn regarding unsafe/potentially buggy code, and also recommend various source code style/formatting improvements. All of these contribute to higher quality. I have used findbugs, pmd, and checkstyle in this space and they are very useful to analyze source code. You can also include these in your continuous integration suite.

Many readers have requested that I post sample code and scripts – so here is a sample apache ant build script that you can use with your code. Just be sure to modify the properties file to point to appropriate folders. The script will produce html reports for pmd and checkstyle as well as a find bugs output file (for viewing it with the findbugs client).

Code Analysis Script

Pre-requisites prior to running this script:

Set JAVA_HOME to your JDK 1.5 or above folder

Install apache ant 1.6+, findbugs, pmd, and checkstyle in your environment

Make sure the findbugs, pmd, and checkstyle jar files are in ant’s CLASSPATH.

Let me know if you have issues with using this script. Enjoy!

 

Like this post? Subscribe to RSS feed or get blog updates via email.

tweet this add to del.icio.us post to facebook


%d bloggers like this: