Recently I've been working to move the access to a SOAP service from a web tier component to a service tier component, so that we could network restrict access to the SOAP service behind a firewall.
The SOAP service is accessed via Axis2 with an adapter. My original design intended to use this to encapsulate the interface and provide our own business object based interface to the we service. Unfortunately as new service methods were added, a short cut was taken to use the Axis2 generated request and response objects on the adapter's interface. Hence they've leaked beyond the adapter. This worked in the original implementations but has made the implementation very fragile.
Once we wanted to move the access to a different tier we've hit the problem that we needed to pass the request parameters and response objects across the network and we don't want to have to create Axis2 objects in the web tier and serialise them across to the service tier - mainly because we're using a custom marshalling scheme.
This highlights just how important it is to encapsulate external services. Whenever you use an external service you should encapsulate it behind an adapter.
Of course this isn't the only reason to do this, just where a poor implementation has come back to bite us. It could easily have been any of the following:
- Changing implementations of our XML binding tool, if we changed from Axis2 to another technology we would have hit the same problems.
- Web service schema updates. As the back end service changes we'll need to regenerate our Axis2 objects. If it's encapsulated then only the adapter and its test suite need to change, if it's not encapsulated then it affects the whole code base.
- Changing business requirements that affect how we interpret or use the data the from the back end service. If we can encapsulate it, then we know where to go to make those changes.
While the refactoring has been a bit time consuming and laborious, the advantage of our agile development approach is that we've been able to take this change in our stride. Since we have well over 90% unit test coverage and a set of automated acceptance/integration tests we've been able to refactor the code to bring back the encapsulation that was originally intended with the confidence that we haven't broken any of the functionality.