I recently made a blog entry about “anti-patterns” for SOA. This is funny since I never took the time to define either "SOA" or “anti-patterns” at the beginning of the blog which lead to almost everyone reading it walking away with a different opinion. I say funny because I am the sort of person who finds that type of thing amusing ;-)
Okay – seriously, before I continue, I would like to put some definitions around both of these. For SOA, I will rely on the OASIS Service Oriented Architecture Reference Model Technical Committee’s work to develop a Reference Model for SOA. While only an editors’ draft at this time, the basic premise is that SOA is an architectural paradigm or simply stated – a way of viewing/doing things that center’s around the concept of a service. Revision 10 is coming out soon.
http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=soa-rm
SOA definitions are like a tush. Everyone has one. Anti-pattern definitions are similar. To lexically scope the rest of this blog, I will rely on the following definition introduced by Hayes McCormick, a lead engineer from Mitre:
“Anti patterns are negative patterns that present more problems that they produce”
http://www.antipatterns.com/briefing/sld003.htm
Hays also compares various types of anti-patterns. In IT, anti pattern examples may be the god class ( one large class that does everything), spaghetti code (procedural and un-ordered/unstructured), Design by Committee (always problematic) and those of you who use vi instead of emacs or pico (miscreants – you know who you are!!). Social anti-patterns include terrorism, pyromania, drug abuse and those or you who use vi instead or emacs of pico.
Rule 1: Granularity is in the eye of the beholder.
The question of service granularity seems to be a pervasive and confusing topic. Someone recently told me that an SOA with ten million services is probably a bad practice since it has too large a number of services and hence is hard to manage. I argued that number of services as a sole metric for whether or not SOA is implemented correctly is not a good metric given that it is subjective to the eye of the beholder. The point is that the rationalization for these things is not always obvious to the viewer.
Case in point? How about the Internet. The internet has over ten million individual services yet each of those services have a unique and valid function, at least to the owners of the content and those wishing to retrieve it. So look at this in terms of granularity. Should clusters of those services be bundled together? No. You are reading this blog which aggregates a few things (my posts plus thousands of comments calling for my banishment for heresy), however I will argue that IMO this blog should remain its’ own service.
If someone also owned a distributed grid computing network, they may wish to allow consumers to make leases to individual nodes via services. This means that each node in the cluster would have at least one service. The alternative is to implement an uber-service that then locates and leases the appropriate node on the cluster on behalf of the consumer and forces the consumer to remain agnostic with respect to the physical contract to the cluster node. So which is valid? Well, both. There are advantages to doing it each way.
So how far could you take the granularity/number of services concept before it becomes a legitimate anti-pattern? In J2EE many have made assertions about patterns and anti-patterns. The issue of granularity is measured by java programmers in terms of what they deem efficient or justifiable based on expected overhead. Puneet M. Sangal wrote:
“Accessing Fine-grained EJB Interfaces
Marshaling and unmarshalling data involved in a remote call across the network can cause major time latency in applications. Latency can also occur due to multiple remote calls. Based on the needs on the application, the solution might involve redesigning the EJBs, but if that's not the case, servlets should not remotely access an EJB entity via a fine-grained API. If the EJB's expose both fine and coarse-grained APIs then servlets should use single calls to the coarse-grained API in preference to making multiple calls to the fine-grained methods.”
Is this view justified? IMO, it gives us hints about some concepts upon which to base our decisions.
Convoluted SOA Contest Winning Idea?
Let’s take this to an extreme case. Imagine you wanted to render a raster graphic of some new platform. Let’s assume that the native format for the graphic returned a large hash of pixel values in Hex format. I will use text to make this easy to understand:
1, 1, #C0C0FF //pixel located at quadrant 1 from top, 1 from left, color is Hex #C0C0FF
1, 2, #C0C0C0
1, 3, #FFFFFF
Etc.
Now imagine that each pixel’s value had to be parameterized to web service call that would return the Hex value in RGB values. We can make this more granular by forcing the consumer to call a different service for each Hex value. Accordingly, the service endpoints would be http://www.domain-example.com:port/[hex_value]/ws
If you sent in #FFFFFF, the response would be rgb(255,255,255) which would render white. It is possible to make rendering software for your new raster graphic format make one service call for each pixel in the image.
I probably don’t have to tell you that this is a bad idea. It is very black and white (no irony intended) however there are other examples that are less ambiguous.
Rule 2: It is probably not possible to write a rule for granularity that is applicable to all situations.
For the record, the preceding idea was not original, it is merely a new twist on an old ploy to make a picture using an HTML table with hundreds of rows and columns, each having its’ own background color. Collectively, the table cells being rendered in an HTML client application would look like a picture. Hey – maybe we could produce that table by linking up the results of all the service calls……? Somebody shoot me now!!
In the preceding case, it would have made sense to call a single service that returned a large lookup table for all values, then simply iterate each Hex value against that for the corresponding value locally. My gut instinct would have been to architect it this way, but others may object (for various and perhaps legitimate reasons).
There are several questions that I will pose to you on this subject, interspersed with my answers. YAMMV (Your actual mileage may vary):
1. Should service calls be used in places where the overhead of incurring them exceeds the resources required to enable the functionality locally?
[Duane]: My gut reaction is that this is a consideration but will not always be the largest factor in the equation.
2. Would it be prudent to state that the call to the service should be coded in less lines that it would take to reproduce the functionality locally. For example, making a call to multiply two numbers together may take 25 lines of code in Java, including wrapping it in a “try/catch” construct. Doesn’t it always make more sense to simply write:
…
int var1;
int var2;
int result;
try {
result = var1 * var2;
}
catch (Exception e) {
//do something with error here…
}
…
[Duane]: Many programmers will probably not make remote calls for simple functions they can easily write. I am not sure if any rule can be made from this.
3. Is there any chance that “catch all” rules can be made to determine whether or not services are too granular? Consider the fact that some programming languages allow for sentences to be of type “String” and also allow them to be treated as an array of chars.
[Duane]: I do not believe this will be possible given we all tend to look at problems form different aspects.
4. If any of these rules are violated, is the thing still SOA?
[Duane]: SOA is SOA, whether good or bad design.
All of this is dependent upon your own views and principles.
I started thinking about this in terms of how other related efforts handle this. The first thing that struck me is the use of inheritance in object oriented programming has a strong effect on whether or not you use a local method or make a remote call. For example, imagine the following example as a class hierarchy.
If you need to do a multiplication operation on two or more integers, you would logically use the Calculus class. If you are writing a new class, you would import the Calculus class then call the multiply() method and feed it parameters. This would return a result. Importing the class gives you access to all the methods that class has.
It would be highly illogical to make a remote procedure call to another class for some functionality your imported class already possesses such as the multiply() method.
You will notice that in the hierarchy I established above, there are two methods on the language side that are very similar – WriteBookReport() in the English Literature class and writeReport() in the Grammar class. This illustrates another problem that exists within SOA – the number of similar or overlapping services. This has also been raised as a possible anti-pattern of SOA by a number of people.
In this case, the designer of the overall programming language would have the ability to re-architect the class hierarchy to form a more generic operation that may be called “writeReport()” and take a parameter of reportType (which might have a value of “book report” in certain instances).
This often has not been addressed within the context of SOA. class hierarchies are commonplace in every modern language. Service classification hierarchies are not as common. This may be an interesting thing to look at.
Conceptually, it the writeReport() operation the same as the writeBookReport() operation? This depends upon your perspective on the problem and the granularity of which you examine the operation.
A simple table with some generic aspects highlighted seems to indicate that the two operations are the same:
The two operations seem pretty similar from this perspective. Of course, when you examine other aspects, this starts to fall apart.
Okay – so this example was a little daft. Let’s look at a more relevant issue. Is an HTTP get() different from an HTTP post()? The patterns are both the same. You marshall a message into text and route it over the internet using an established protocol. It reaches a service which then evaluates the message and forms a response message which is then routed back to the sender. They both do this. So do the HTTP put(), delete() and other operations. Where they differ in functionality is not at the wire level, it is at the conceptual or real world effect level. This is an important consideration for SOA. What is the real world effect of invoking the service.
Rule 3: Duplication of Services is in the eye of the beholder.
Conclusion:
Alongside the issue of service granularity, we have a similar issue of duplication of services. Both of these issues are probably beyond some form of an immediate “best practices” guide that is applicable in all situations.
What do you think?
