How to expose use cases to users - web services, remoting & GUIs
In light of recent discussions I had with Arjen Poutsma about service oriented architectures and the development of web services I’d like to talk a bit about how to expose use cases to users. Users in this case in the broadest sense; meaning not only people, but also other systems.
Most of the material in this article is the result of discussions I had with Arjen Poutsma. On his blog, you can read more about his thoughts on web services and why web services are NOT the same as remote procedure calls.
Use cases
Application development is about implementing functionality of some sort. An application that enables the user to transfer money from one bank account to another usually contains some functionality that checks for the current balance of a bank account and iff enough money is available, transfers the money to the other account. The transferring of money to an account is what we call a use case.
We all know that layering is a Good Thing to do when implementing applications containing lots use cases involving complex business logic. Some argue here, but in the case of Kevin certainly for the wrong reasons. It’s clear that the reasons he gives for not layering your application design are completely overruled by the rise of ligthweight frameworks such as Spring. But let’s not argue too much with the purpose of ligthweight application frameworks here, afterall, the title of the post is ‘How to expose use cases to users’, it doesn’t state ‘the purpose of lightweight frameworks’!
Back to use cses. Most business applications consist of use cases modelled using one or more service interfaces. The following is a typical service interface:
public interface Teller {
void transferMoney(BankAccount from, BankAccount to, double amount)
throws InsufficientBalanceException;
}
The service interface defines what our application is capable of, it provides the user with a clearly defined collection of individual pieces of functionality. It doesn’t state how those pieces of functionality are implemented and as user of the application, you probably shouldn’t care less. One thing you do care about as a user is the ability to actually use the functionality the interface (the interfaces) defines.
A user interface - a way to access functionality
To cut things a bit short, when talking about accessing functionality of an application, we can divide users into two distinct groups: users as in people and users as in other systems. This division isn’t necessarily needed for the rest of the article, but it’s serves well to talk a bit about user interfaces.
A user interface is needed for users to interface with the functionality an application provides. The first group of users (the actual people) will most often access the functionality provided using a Graphical User Interface (GUI) and nowadays this often is a web interface. The second group of users will probably resort to using a different kind of interface. Some systems still have to screen scrape a mainframe terminal which you could call a graphical user interface as well, but oh well, fortunately I don’t have to deal with that too much so let’s forget about that.
Different users, different systems
Some people are (color-)blind, some are not, some are deaf, some are not. In short, there are different groups of people we have to deal with when implementing a Graphical User Interface. When implementing an interface for a system to access functionality provided by an application there are probably even more distinct groups we have to deal with. Some system users (as we’ll call ‘em throughout the article) might be implemented using Perl or Ruby, some might only know of a certain platform called .NET they live on. While others are fast as the latest Ferrari and demand a fast response, some might be really really slow. Last but probably not least, there might be system users that live in a single address space while others are distributed across several nodes on the other side of the globe.
To conclude my bit about different system users, I’d like to quote Waldo et. al:
Objects that interact in a distributed system need to be dealt
with in ways that are intrinsically different from objects that
interact in a single address space.
Inter-process communication
When two distinct processes positioned in one single address space implemented in the same language have to talk to eachother people often resort to something like RMI, CORBA, DCOM or some maybe a somewhat less common protocol such as Hessian. This kind of inter process communication is based on a lot of assumptions. When one of those assumption is dropped, things become a lot more complicated. When for example the two different applications that need communicate are implemented in different language, all of a sudden we have to deal with different type mechanisms. When the two systems are not in the same network segment firewall issues might arise or problems with network latency.
Re-reading the Waldo’s statement might help here :).
Concluding all this, we can say that designing ways to access use cases with a distributed topology in mind greatly increases complexity and introduces all kinds of aspects we don’t have to deal with when invoking functionality positioned in the same process.
Introducing web services
Web services are positioned as a way to solve some of the problems we introduced in the last paragraph. Wikipedia defines web services as follows:
A Web service is a collection of protocols and standards used for exchanging data between applications or systems. Software applications written in various programming languages and running on various platforms can use web services to exchange data over computer networks like the Internet in a manner similar to inter-process communication on a single computer. This interoperability (e.g., between Java and Python, or Windows and Linux applications) is due to the use of open standards. OASIS and the W3c are the steering committees responsible for the architecture and standardization of web services. To improve interoperability between web service implementations, the WS-I organisation has been developing a series of profiles to further define the standards involved.
When I started to use web services, I ended up exposing my service interface as a web service. Using something like Axis this is fairly easy. Until you run into somewhat more complex situations, transparently exposing your service interface is all you might need. But while at it, you quickly start to ignore the problems we’ve just reviewed; interoperability, network latency, et cetera. You might even start to think of web services as just another way to implement Remote Procedure Calls (RPC). This conclusion can in fact be quite dangerous because of all those latency and interoperabilitty issues.
Back to user interfaces
When reviewing what we’ve said about Graphical User Interfaces a surprising amount of aspects that come with developing GUIs also holds for developing user interfaces for system users. We have to deal with different types of users (systems) and so on. Furthermore we also have to deal with different types of functionality. Some applications are CRUD-only (for which we can easily develop a generic solution such as Ruby on Rails’ ActiveRecord or the Spring equivalent. Some are more complex and require more sophisticated form handling. Somehow we still haven’t been able to come up with one perfect solution that suits all our needs and removes the burden of custom coding alltogether. And to be honest, I think we’ll never get there! To some extend, a certain amount of programming will always be required when creating Graphical User Interfaces.
I’d like to conclude with the remark that in my opinion the same holds for other user interfaces. When creating web services, the simplest approach possible is transparently exposing your service interface and letting the stack generate (dynamically or at build time) all the necessary type conversions, protocol endpoints, etcetera. For Java-to-Java communication RMI or Hessian for example perfectly do the job here. However, the more complex your requirements are getting, the more coding you’ll have to do. You’ll probably end up using a web services stack with all its added complexity. When dealing with complex schemas for example, you might want complete control over the way your web service implementation is going to convert the XML to Java objects. You might want control over the SOAP headers that were passed as part of the SOAP request. Sometimes contract-first development is the best thing to do, sometimes you just want your web service description to be generated based on the service interface.
Arjen addresses all of those issues in the blog entries listed below. In my opinion, a web services stack should just as an MVC framework support both the simplest approach possible as well as the most complex approach you can think of. In other words: simple things should be made even simpler but complex things should always be possible!
More to come…
Excellent blog entries by Arjen on issues with web services:
- Thoughts on SOA - Introduction
- It’s not remoting
- It’s the Contract, stupid
- Implementing the contract
- To serialize or not to serialize

2 Responses to “How to expose use cases to users - web services, remoting & GUIs”