Use a relay server to examine data transfers.
Reduce the number of messages transferred.
Cache data and objects to change distributed requests to local ones.
Batch messages to reduce the number of messages transferred.
Compress large transfers.
Partition the application so that methods execute where their data is held.
Multiplex communications to reduce connection overhead.
Stub out data links to reduce the amount of data required to be transferred.
Design the various components so that they can execute asynchronously from each other.
Anticipate data requirements so that data is transferred earlier.
Split up data so that partial results can be displayed.
Avoid creating distributed garbage.
Optimize database communications. Application partitioning is especially important with databases.
Use statically defined database queries.
Avoid database transactional modes if possible.
Use JDBC optimizations such as prepared statements, specific SQL requests, etc.
Try to break down the time to execute a Web Service into client, server, and network processing times, and extract the marshalling and unmarshalling times from client and server processing.
Don't forget about DNS resolution time for a Web Service.
Try to load-balance high-demand Web Services or provide them asynchronously.
The granularity of a Web Service is important. For more scalable and better performing Web Services, create coarser services that require fewer network requests to complete.