Imagine if you have these 3 methods:
public Employee GetEmployee(string alias);
public Department GetDepartment(Employee employee);
public Employee GetManager(Department department);
Now imagine if you want to find the Manager of the Department that some Employee (lets say “alexj”) works in.
If this was all in one tier it would be a no brainer…
Employee manager = GetManager(GetDepartment(GetEmployee(“alexj”)));
You can do the same thing if you are interacting with a web-service that exposes those methods too.
everything get a whole heap less efficient. The code looks the same, but masses of hidden work gets done:
Client: Send a GetEmployee(“alexj”) request. Server: Get the employee from wherever (probably a database) then serialize it and send it back to the client Client: Deserialize the employee and then reserialize it and send it as an parameter to a GetDepartment(..) request. Server: Deserialize the employee, get the department for the employee, serialize the department and send it back to the client Client: Deserialize the department and then immediately reserialize it and send it back to the server as a parameter to a GetManager(..) request Server: Deserialize the department, get the manager for the employee and serialize the manager and send it back to the client Client: Deserialize the manager.
Wow… talk about chatty.
We are doing a lot of superfluous serialization / deserialization. And as if that isn’t bad enough, we are incurring the network latency of, count them, 3 network round trips.
On two occasions, the server serializes and send an object to the client, just so the client can sent it back completely unchanged.
What an awful waste!
Surely there must be a better way…
If the client could send their intent to the server, there would be no need to move anything other than the final result, i.e. the Manager, back to the client.
Why couldn’t every webservice have a meta-service that allows you to send expressions in terms of the public contract of the service:
i.e. something like:
Employee manager = service.Execute<Employee>( “alexj”, (s) => GetManager(GetDepartment(GetEmployee(s))) );
This new meta service doesn’t allow the customer to do anything new, because it only allows expressions that reference service methods.
But now the flow becomes:
Client: Send a request to the meta-service on the server, two parameters (‘alexj’) and the serialized expression. Server: Deserialize the expression, and re-write as a valid CLR expression bound to the actual method implementations and the parameters from the client. Execute the expression, serialize the resulting employee and send it back to the client.
Client: Deserialize the manager.
And low and behold we are doing a lot less serialization and deserialization, and, most importantly, we are down to one network round trip, so it will be a *lot* faster.
Other potential benefits include:
Its pretty easy to imagine how this might be implemented.
So why can’t I do this today?