Friday, November 11, 2005

What is meant by “Service Opacity” and “Managed Transparency”?

Okay – so you all know about Service Oriented Architecture (SOA) and have your ideas of what it is. While we all are likely to disagree with the finer points of SOA, most will agree on a few core tenets of SOA. If you want to discuss this with me, the standard contribution of a vintage Bordeaux applies.

Core to SOA is the existence of services as autonomous entities that act as a boundary between some “functionality” and the entity that consumes that functionality via the service. Service implementers should take care to design services as opaque as possible. This means that as a service consumer, you should talk to the service, but not really care about how the service implements the functionality it provides. This Black Box aspect of SOA is really a specialized notion of the definition of software architecture in the great green book “Documenting Software Architectures: Views and Beyond” by Clements, Bachman et al. In this book, software architecture is defined as “the structure or structures of the system, which consist of elements and their externally visible properties, and the relationships among them”. The key words here are “externally visible properties”. A service provider adhering to this basic axiom should strive to only reveal externally visible properties that are critical for the consumer to know, but no more.

Critique: That is a broad statement. Why? As with anything in technology, don’t run out and do it just because I said so. Question everything. Critique this if you don’t agree.

Rationale: Services provide a healthy abstraction between functionality and those using the functionality. By not revealing the specific implementation behind the service, no consumer of that service has to create a tighter integration than necessary. This frees the service provider to implement, maintain, replace or update the functionality behind the service with the least amount of concern for dependencies from consumers. As long as the replacement, update still supports the existing service interface, the consumer will not notice changes. Please note that I qualified my statement with “than necessary” – the exact level of this is specific to each implementation and it is unlikely anyone could create a hard and fast rule for this.

Specific details of how the service is fulfilling its’ functions are generally not relevant to the consumer either. One should not make assumptions about specific interactions that may happen behind the service and only stick to the externally visible real world effect (RWE). A service is a black box with an interface. As long as the interface allows you to do what you want, you shall be happy. Like this blog, all you need to know is that you enter a URI into the location window of your browser and you get this content back, formatted in HTML. You should not care whether or not this is static text residing on an Apache server or if I just typed into a blackberry really fast to give you this real time.

Example:

Some people have advocated that a service must provide a guarantee of delivery assurances between the service itself and the ultimate (application) destination. This delivery assurance effectively suggest that a service must deliver messages it receives to another destination, possibly with additional guarantees for “in order” and “eliminate duplicates” amongst other functions. I strongly disagree with this for a number of reasons. Is this really an externally visible property of a service we should expose? Perhaps in some cases it can be justified but I have trouble making any normative statements for such that apply to all cases. A functionality similar to this may be a higher level matter which I will try to explain at the end of my rant below.

Rant:

First, even specifying in a standard or protocol that there is an “application destination” behind a service is errant since it implies a specific model for infrastructure to be implemented behind the service interface. If this were accepted within the standard, does it imply that all implementations must now have a specific architecture where nothing can be processed locally on the service?

Secondly, assuming you are going to send a sequence of six messages to a specific service and invoke a delivery assurance/guarantee that all messages in that sequence are delivered “in order”, this now implies a cardinality of 1:1 between a service and the “thing” that must process the messages. Does this disallow the service itself to process part of the message?

Third, this model constrains implementers from dividing up an incoming message to distribute it to several processing classes or applications. The mechanism as it stands today essentially requires a sequence number for each incoming message which must monotonically increase by a factor of one. The intentions are that the service will forward incoming messages to the application destination in the same order it received them in. A cardinality of 1:1 is sub-optimal for scaling IMO. What about pooling? Does this count as one application or several? And why should the service consumer care about this?



The UML model above captures the implied infrastructure. It implies that all incoming messages in a sequence flagged with “in order” delivery MUST be forwarded intact as whole units to one application destination. Why should an implementer not be able to forward messages 1 and 3 to one application destination and messages 4 and 6 to another then simply coordinate those activities to ensure they are “processed” in order? Is the following second diagram below illegal if a guarantee of “in order” delivery is requested? Note that in the following diagram, I have replaced Service.forward() with Service.coordinateProcessing() since this is really what the service consumer is after. After all, even if messages *are* delivered “in order”, there is no guarantee that they have been processed in order.



Note: Please excuse my poor UML style of multiple ApplicationDestination classes but I felt compelled to depict it this way to illustrate the splitting of various messages to different endpoints.

An operation such as “forward()” (from the first diagram) should not be a mandatory externally visible property of a service. It implies a specific model for implementing a service and any specifications that deal with service interoperability should not try to impose specific implementation styles on service providers. My argument does not mean that implementers cannot do this if they see fit or determine that it is necessary, but this is not a one size shoe that should force all to fit within.

A higher level look at the goal.

The real goal is to allow a service consumer to flag that a sequence of messages are meant to be “processed sequentially”. It should not care how that is done, just that this is done or, in the alternative, the service generates a fault. What mechanisms do we need to do this?

1. We need to ensure that the message on the wire between the service consumer and the service carries with it all the tokens to enable the service to understand what type of serial/cardinal processing assurances it requires.

2. We also need a messaging mechanism that allows a service to reassemble the complete stream representing the message in a deterministic manner matching the stream exactly as it was when it left the service consumer.

3. Another requirement is that services must have some form of service description that allows them to declare what their exact capabilities are WRT serial processing of multiple calls.

Does it look something like this?






Note that the cardinality between Service and ApplicationDestination is “any”. It is possible that a service may simply process an invocation request locally. Not all attributes and operations have been explicitly called out to avoid confusion but hopefully this will give you the idea.

Conclusion:

Managed transparency should be a core consideration of a service provider. Services should remain as opaque as possible but may need to expose some aspects of their operations to facilitate their use but consumers. Those implementing services must take both of these into account lest we risk building a world wide network of interdependent, tightly bound applications – the very thing that SOA is attempting to save us of.

What do you think?

Wednesday, November 09, 2005

Any minute now...


Yes - my wife is *very* pregnant. We are due to give birth any second. Since I have been innundated with requests for photos, I decided to make a short blog entry to illustrate exactly why I am the luckiest man alive. Our official due date is November 11th (two days from now).

It is hard to believe Bianca is now 2 and a half years old. Time flies.

Monday, November 07, 2005

Anti-patterns for SOA: Part Two

Three general rules for service granularity and redundancy

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?