Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I have been modifying an application to have a cleaner client/server split to allow for load splitting and resource sharing etc. Everything is written to an interface so it was easy to add a remoting layer to the interface using a proxy. Everything worked fine. The next phase was to add a caching layer to the interface and again this worked fine and speed was improved but not as much as I would have expected. On inspection it became very clear what was going on.

I feel sure that this behavior has been seen many times before and there is probably a design pattern to solve the problem but it eludes me and I'm not even sure how to describe it.

It is easiest explained with an example. Let's imagine the interface is

interface IMyCode {
    List<IThing> getLots( List<String> );
    IThing getOne( String id );
}

The getLots() method calls getOne() and fills up the list before returning.

The interface is implemented at the client which is proxied to a remoting client which then calls the remoting server which in turn calls the implementation at the server. At the client and the server layers there is also a cache.

So we have :-

Client interface
      |
 Client cache
      |
 Remote client
      |
 Remote server
      |
  Server cache
      |
Server interface

If we call getOne("A") at the client interface, the call is passed to the client cache which faults. This then calls the remote client which passes the call to the remote server. This then calls the server cache which also faults and so the call is eventually passed to the server interface which actually gets the IThing. In turn the server cache is filled and finally the client cache also.

If getOne("A") is again called at the client interface the client cache has the data and it gets returned immediately. If a second client called getOne("B") it would fill the server cache with "B" as well as it's own client cache. Then, when the first client calls getOne("B") the client cache faults but the server cache has the data.

This is all as one would expect and works well.

Now lets call getLots( [ "C", "D" ] ). This works as you would expect by calling getOne() twice but there is a subtlety here. The call to getLots() cannot directly make use of the cache. Therefore the sequence is to call the client interface which in turn calls the remote client, then the remote server and eventually the server interface. This then calls getOne() to fill the list before returning.

The problem is that the getOne() calls are being satisfied at the server when ideally they should be satisfied at the client. If you imagine that the client/server link is really slow then it becomes clear why the client call is more efficient than the server call once the client cache has the data.

This example is contrived to illustrate the point. The more general problem is that you cannot just keep adding proxied layers to an interface and expect it to work as you would imagine. As soon as the call goes 'through' the proxy any subsequent calls are on the proxied side rather than 'self' side.

Have I failed to learn or not learned something correctly?

All this is implemented in Java and I haven't used EJBs.

It seems that the example may be confusing. The problem is nothing to do with cache efficiencies. It is more to do with an illusion created by the use of proxies or AOP techniques in general.

When you have an object whose class implements an interface there is an assumption that a call on that object might make further calls on that same object. For example,

public String getInternalString() {
    return InetAddress.getLocalHost().toString();
}

public String getString() {
    return getInternalString();
}

If you get an object and call getString() the result depends where the code is running. If you add a remoting proxy to the class then the result could be different for calls to getString() and getInternalString() on the same object. This is because the initial call gets 'deproxied' before the actual method is called.

I find this not only confusing but I wonder how I can control this behavior especially as the use of the proxy may be by a third party.

The concept is fine but the practice is certainly not what I expected.

Have I missed the point somewhere?

share|improve this question
    
So from what I can understand your getLots call repeatedly calls your getOne call? –  Martijn Verburg Nov 1 '11 at 11:20
1  
That is correct but once the getLots calls has been 'deproxied' the getOne call occurs on the server and it should ideally be on the client. –  AndyH Nov 1 '11 at 12:04
    
So the problem is the way the proxy library works? What you really want is for getLots to be implemented via getOne on the client side. It doesn't need to be proxied. –  Jon Strayer Apr 2 '12 at 14:59

2 Answers 2

Relation between any two methods is unknown to a proxying library.

So the method

public String getString() {
  return getInternalString();
}

once proxied and implemented on server side is equivalent to any method

public String getString() {
  //some executable statements along with a return.
}

But if you want to preserve the relation between the methods then you may want to not proxy the higher methods

public String getString() {

or

List<IThing> getLots( List<String> );

each client of the proxying library would code for this separately i.e. it is no more part of the interface IMyCode which is expected to be supported by the proxying library.

share|improve this answer
    
you could use decorator pattern at client side. –  kunkunur Dec 4 '11 at 7:27

I'm bashing this out in a hurry before a talk, so apologies if I'm a little unclear

I think the main issue is that your getLots() call basically goes into a loop of multiple getOne() calls. Without seeing your code and your infrastructure in detail - I'd be tempted to have the getLots() call do exactly that, get lots of objects in a single call, loading up your two caches along the way.

Yes there's a one-off upfront cost for this call, but afterwards your caches are fuller, making subsequent getOne() calls much more likely to be faster and getLots() calls also likely to get faster (depending on your search key range). Of course you have to think about how you ensure that the getLots() calls efficiently search and return from your caches as well as going down the layers as required.

It sounds like you measure performance before and after you make changes, which is good. You can use that to measure the most efficient size of the getLots() calls that you make to the server (when there's no cache or partial cache or full cache involved).

share|improve this answer
    
I'm sorry but my example has mislead you. The problem is not one of cache efficiencies. It is more to do with being confused be the simplicity of adding layers of functionality by the use of proxies or even AOP in general. I will edit my original post with another example to try and illustrate the issue. –  AndyH Nov 1 '11 at 13:22
    
OK so you say "The call to getLots() cannot directly make use of the cache." - I ask why not? –  Martijn Verburg Nov 2 '11 at 17:58
    
It could but the example is contrived. The point is to understand where a method is de-proxied because it changes the behaviour. The second example hopefully illustrates this. –  AndyH Nov 9 '11 at 14:05
    
Hmm, I think you're now talking about whether you should lazily load or load up front all of the connected objects into the cache. Did what I just say there make sense? Or am I barking up the wrong tree? –  Martijn Verburg Nov 9 '11 at 18:05

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.