Saturday, June 23, 2007

SOA: Ontology and Taxonomy of Services

As someone misinterpreted the use of the term "service" as an idiom in my last post, to imply that the post was about defining that "a specific service is a single business process step" (rather than being about semantic covenant services); let me point to two 'Architecture Journal' articles defining important terms for discussing service-orientation:
The articles are about the defining different categories of services and about creating business models and mapping business capabilities to services. The last article covers Motion (video at Channel9), which is now known as Microsoft Services Business Architecture (MSBA).

Think of this when reading the articles:

A service classification scheme should have the "hierarchy" taxomomy form. It should not use a scientific hierarchy nor a tree form. There must be no "is using" or "is dependent on" relation between the services in the taxonomy. There can be no dependency between services in SOA except for composite services realizing a business process by consuming the actual services. Taking a dependency on another service will break the central "services are autonomous" tenet of SOA. Having a service calling another service will just repeat the failure of DCOM/CORBA for distributed system design, using RPC over web-services solves nothing.

Thursday, June 14, 2007

Semantic Covenant: The Service is Always Right

This post is about service semantics and how to be “liberal in what you accept” in your service-oriented architecture implementation. Let me start by defining that in this post the term "service" is used for a specific business capability that can be composed and reused in different business processes. I.e. the idiom “service” used here is representing a building block business capability. This is not to say that a service equals a single business process step, it just makes it easier to talk about the topic of this post (which is not BPM): semantic covenants.

A service has a defined contract, but also some implied semantic. The semantic is hard to express through the contract, and the business compositions that utilizes (consumes) the operation can only assume that the service is a covenant, i.e. that the service will do B when provided with input A. Having semantic coupling is just another type of coupling that prevents services to be truly loosely-coupled and that will cause a breaking ripple effect through all consumers of the service when the inevitable thing happens: change.


There is some thinking in the SOA community that to avoid this ripple effect caused by a service contract or semantic change, it is up to the service to do the right thing independent of the information provided by the sender of the message. That is, that the service should behave as if the consumer is always right, and adapt its semantic to suit the sender.

A service can do no such thing, as it is an actual representation of a specific business capability. The capability does what it does, i.e. a credit check is just that – a credit check. It must be up to the business composition of the services to interpret the real-life events that have occurred and their context, and then invoke the right set of operations. Note that the service should still be liberal in what it accepts (message duck-typing), as it is the business event that is important, not the format of the event message.

It is easier to recognize that the service is always right when you think of messages as representing business events and apply EDA thinking such as publish/subscribe instead of a habitual SOA command and control pattern. A service will then subscribe to business events that must trigger the business capability, but the service need not know who the publisher is. Neither need the publisher know who is listening for the business process state changed events (event topics). Thinking in service “consumers” is very connected to having a request/reply, command and control style SOA. 

To simplify the “service is always right” notion, let us call the publisher a “consumer”. The consumer can send any message (business process event, context and state; mail-order analogy) it likes, as it is the publisher. However, as the consumer does not know who the subscribers are, it cannot know or depend on the services having specific semantic. The service cannot depend on who the publisher is, it just accepts that a business event happened that it must process. A business event message never specifies any handling operations, the logic to decide how to handle the event is part of the mechanism that routes messages to services. This ensures that the autonomous and loose coupling tenets of SOA are fulfilled.


When you apply EDA style thinking to service orientation, you’ll see that the service is always right. There cannot be any traditional “the consumer is always right” in relation to service semantic, as the services have no request/reply consumers.

Alas, still the consumer can still be right; it is just the responsibility of the process composition mechanism to accept what ever messages (events) the consumer (publisher) throws at it and invoke the applicable service operations. It is the business process composition mechanism that has to be the semantic covenant.

PS! Note that I have deliberately used the term "composition" here and not even mentioned using an ESB or BPM to implement this. The semantic covenant 
composition mechanism can simply be implemented as a mashup (composite application) instead of a composite service or an orchestration/saga.

What is WS-Splat anyway?

I just briefly gave an overview of the ten WS-* standards supported by WCF at my talk at NNUG a couple of weeks ago, as there are way too many topics there to cover in just one session. The ten supported standards are:
  • WS-Security
  • WS-Trust
  • WS-SecureConversation
  • WS-Policy
  • WS-SecurityPolicy
  • WS-Addressing
  • WS-ReliableMessaging
  • WS-AtomicTransaction
  • WS-Coordination
  • WS-MetadataExchange
Alas, Michele Leroux Bustamante has written an excellent introduction to all the different WS-* standards: Making Sense of all these Crazy Web Service Standards.

Definitely worth reading if you wonder whats the difference between WS-Security and WS-SecureConversation and other important issues. Then again, who wonders about such things...

Monday, June 04, 2007

Flex support for [Flags] enum - not

My last post showed how to get explicit semantics in a WCF contract description using [Flags] enum. As readers of my blog may know, our main service consumer is a Flex 2.x client. As it turns out, Flex has an issue with correctly interpreting such enumerations.

A [Flags] enum looks like this in the WSDL:

<s:simpleType name="DisciplineFlags">
<s:list>
<s:simpleType>
<s:restriction base="s:string">
<s:enumeration value="None" />
<s:enumeration value="Administration" />
. . .

The correct input format for an element that uses the above type is XML whitespace separated values, such as "None Administration". Flex, on the other hand, interprets the list schema construct too litterally, and tries to pass in an array. This causes an exception in the WCF service, as the message cannot be deserialized due to the incorrect XML.

As the Flex guys had no other solution to this problem, I just added a simple "FlexDisciplineFlags" string property to the contract. Flex has to pass a CSV list of the filter enum values, and the service will "cast" the input into the official filter condition:

private void HackFlexIssues(DocumentCardFilter filter)
{
if (String.IsNullOrEmpty(filter.FlexDisciplineFlags)==false)
{
//input string must be a CSV-list of enum items
filter.DisciplineFlags = (DisciplineFlags)Enum.Parse(typeof(DisciplineFlags), filter.FlexDisciplineFlags, false);
}
}

Note that I'm kind of making a workaround for a technical limitation, maybe I'll get sued by Adobe :)

Friday, June 01, 2007

Enum Flags, Specification Pattern & Explicit Semantics

We use the specification pattern for all the dynamic query operations in our WCF service, and this includes using Nullable<T> on all criteria elements and several "multiple choice" criteria based on [Flags] enumerations. To ensure that our contracts convey explicit semantics, we have used long meaningful names in the enumerations instead of the more cryptic codes that are wellknown in the internal system and that are the domain terms used by the biz-people. These internal codes is not, however, very meaningful to the partners that are consuming the WCF service.

As the multi-choice lists sometimes contain 20+ items, I feared that interpreting the [Flags] enum
and building the repository query would become huge switch statements with lots of ugly bit-wise "and" logic to deduce which of the 20+ items were specified in the criteria. In addition, I needed a way to add the translated code items to a SQL @parameter list as part of a SQL in clause to actually filter records on the criteria.

As I never embark on implementing something ugly, I decided to look for a simpler way of interpreting the [Flags] enum. Knowing that an enum internally is represented by the integers and not the human-friendly names, I decided to add another internal enum that exactly mirrors the contract enum, just using the internal domain codes, and then cast to the internal enum. But the DataContractSerializer has a simpler approach using the [EnumMember] attribute:

[DataContract]
[Flags]

public enum DisciplineFlags
{
None = 0,
. . .
[EnumMember(Value = "
Instrumentation ")]
I = 0x000100,
[EnumMember(Value = "
MarineOperations")]
J = 0x000200,
[EnumMember(Value = "
Materials")]
M = 0x000400,
[EnumMember(Value = "
Navigation")]
N = 0x000800,
//
[EnumMember(Value = "
Process")]
P = 0x001000,
[EnumMember(Value = "
QualityManagement")]
Q = 0x002000,
[EnumMember(Value = "
Piping")]
S = 0x004000,
[EnumMember(Value = "
Telecommunications")]
T = 0x008000,
. . .
}

Note that you must apply the [DataContract] attribute to the enum for the [EnumMember] to take effect. If you just use the plain enum as a [DataMember] property, then the internal names will be published in the contract.

The "None" item is there as the default value for the DataContractSerializer when the incoming XML specification contains no flags filter element (xsi:nil="true"). The nullable flags filter must be asserted like this before usage:

if (filter.DisciplineFlags.HasValue
&& filter.DisciplineFlags != DisciplineFlags.None)

{
. . .
}


So now I had the real one-letter domain codes, but how to avoid bit-wise interpretation ? Also, I needed a list of the codes making up the flags combination. The answer is really simple:

string disciplineList = filter.DisciplineFlags.ToString();
string[] inValues = disciplineList.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries);

The last problem is that you cannot add the list of values for an in-clause as a @parameter. Just concatenating the CSV-string into the SQL is not an option due to SQL-injection attacks. So a for-loop is needed to add SQL parameters and related values:

for (int i = 0; i < inValues.Length; i++ )
{
string param = "@in" + i;
if (i > 0) sql += ", ";
sql += param;
filterCommand.Parameters.AddWithValue(param, inValues[i].Trim());
}

I would rather have avoided the for-loop, but at least the specification interpreter became much simpler than I expected it to be. No pesky switch statements and bit-wise logic.

See the end of this earlier post for further details about implementing specification filters using TableAdapters.