Introduction to Service Oriented Architecture
Hello World!
double Add(double x, double y)
{
return x+y;
}
If you don't understand the above block of code you are in over your head. Stop reading. Google was not your friend today. If, however, you do understand the above block of code, this is where our discussion shall begin.
At a basic level, a service oriented architecture allows you to take code and place it on another machine. Actually, I just made a gross oversimplification. Service oriented architecture helps you do this, but the key is that it reduces the chance of everything blowing up in your face.
Take a look back at the code block up top. It's time to lay some groundwork. Quite a few web service introductions start by turning this block of code into a web service. In ASP.NET, this was as simple as adding an attribute:
[WebMethod]
double Add(double x, double y)
{
return x+y;
}
Boom! You're done! At least in theory.
Suppose we were building a calculator application. Addition would not be the only operation our calculator supported. Most likely, we would also provide support for subtraction, multiplication, division, to name a few operations.
As the number of operations increases, our application's design will start to show a few cracks. For example, what would it take to calculate the distance between two points? We all know the formula for distance: √(x2-x1)2+(y2-y1)2. Mapping this to our service, our code will look something like this:
CalculatorService service = new CalculatorService();
double xdist = service.Subtract(x2, x1);
double ydist = service.Subtract(y2, y1);
double xdistSquared = service.Exponent(xdist, 2);
double ydistSquared = service.Exponent(ydist, 2);
double distance = service.Root(xdistSquared+ydistSquared, 2);
We just made five calls across the network to perform a single operation. Suppose our network takes .2 seconds to return a response from any server, we just added 1 second of wait time to our operation. You might not consider a single second is not a lot of time, but considering the fact that the actual work done by the server takes less than 1/100 of that time. We just slowed our application down at least a hundred fold.
Consider as well that network traffic can be flaky. Everyone eventually learns the value of the refresh button in their browser. Sometimes the data get lost somewhere and you get a "this page cannot be found" message instead of the page you were expecting. You know that the page you are requesting exists, so you just retry until the data makes the round trip successfully. By making five calls to our server, our application is now five times more likely to fail than if it only had to make a single request. As our service increases in complexity, security checks and database persistence multiply this effect.
Coding services like this doesn't take a lot of thinking. It's doing the same thing you've always done and hoping for the best. However, as the responsible developers and architects that we are, we don't simply hope for the best. We minimize the chances of failure and maximize our room for future improvements. We solve the known problems as early as possible, because we know that they are always easier to fix earlier than later.
Enough talking. How might we improve the design of our calculator service to minimize our failure points? The first key to service oriented architecture is thinking about the big picture. The end goal of our service isn't really to let people add or subtract. We understand that add and subtract themselves aren't all that interesting. We understand that users of our service want to solve whole equations, not perform simple operations. Our service should reflect the bigger picture. Something more along the lines of this would more appropriately describe what the client is really doing:
CalculatorService service = new CalculatorService();
service.Solve(new SolveRequest()
{
Problem = new Sqrt(new Add(new Exponent(new Subtract(x2, x1), 2), new Exponent(new Subtract(y2, y1), 2)))
});
What is the difference between this approach and the previous? To start with, we have minimized the network traffic issues by combining everything into a single operation. More importantly, we have captured something meaningful with our request: the actual equation. This is a powerful thing and allows our service room to grow. For example, if people start passing us complicated operations that take minutes or hours to compute, we now have the ability to split equations up into smaller chunks and take advantage of multiple processors or entire server farms, with zero changes required as far as the caller is concerned.
What if we want to add a completely new feature, like solving for a specific variable? With a few non-breaking changes to our service, we can have version 2.0 ready to go that can be called like so:
CalculatorService service = new CalculatorService();
service.Solve(new SolveRequest()
{
Problem = new Equation("distance", Comparison.Equals,
new Sqrt(new Add(new Exponent(new Subtract(x2, x1), 2), new Exponent(new Subtract(y2, y1), 2)))),
Substitutions = new Substitutions()
{
{ "x1", 1 }, {"y1", 1 }, { "x2", 0 }, { "distance", 10 }
},
SolveFor = "distance"
});
The key is this: if you want to build a good service oriented architecture, you need to think differently. You need to start thinking about the big picture. Rather than supporting bunches of little requests that must be pieced together, make every request capture something meaningful and significant.