Monday, December 29, 2008

Thoughts about SOA and beyond

Preface

Every serious framework has its Collection classes. Why? Because there is no application that does not need List or Hashtable, thus framework designers thought about that and provided a ready implementation, so we can focus on our application needs instead of writing our Lists and Hashtables over and over again.

Yep, thanks a lot. Now how many times have you defined your own fresh implementation for Customer or Order?

A word about SOA

SOA is about contracts. Of course, there is a famous ABC - Address-Binding-Contract, but "AB" are mostly "solved" by tools, meaning we don't waste time to provide them. Most of our time is spent on contracts, i.e. creating the required classes, getting the relevant data and filling it in, sometimes with other services and other times with our business logic and finally calling the required operation. Actually calling the operation is the 'finally' thing, the time was spent on creating the required classes, getting the relevant data and filling it in.

Why does it happen, why the tools do not help us? Because they do not know how! They 'see' those classes as property bags, they know what are the low level basic types of those properties, but they know nothing about their applicative meaning. So we spend best years of our lives to mapping between different types, yet very common in principle, but invented by us or different vendors.

Can you explain more?

Yes, of course. Frameworks did a great job in helping us to describe how my object is passed between the services. Well, thanks, but I also need some help to use that object. I mean that if I have a Person object and a Phone service, I want to be able to give this Phone service my Person and the tools will get the phone # from the person and pass it to the service. Or even more, I want to feed my grid with Persons and Phone service. The grid should understand that one of the Person fields is actually her phone #, render it as a link that when clicked calls the Phone service! And if this field is email and the service is Mail service, the click will open a 'new mail' window or start a chat or whatever, depending on the field and service in use.

As an application developer I need only to tell where are the 'Persons' and where are the services, all the rest should be done by tools, visual tools.

 

Wow, what do you need to get it live?

Actually much, but not too much. I need a common application object schema. This schema should define what is phone #, what is email and what is person that contains email, phone # and other information. This schema should not cover everything, it should provide only the common denominator around which the majority of our lives revolves. Just consider how much services we would be able to build/consume if we just had Person with its contacts (also Persons) with Address, email and may be some ID. Half of Google applications are built just out of this! And of course this schema must be publicly available, reasonable extensible etc, so every vendor will be able to extend it for his own needs; hopefully opening it for public too!

Interestingly that an effort to create this kind of schema was started, just did not get enough attention. It was a part of LDAP specification, see rfc4519 or rfc4524. Most of the examples I talked about can be created with elements defined there! Of course we don't have to evolve LDAP specification, but this can be a good start: standard concept, description language and even good, ready elements and many existing tools.

 

OK, you got your schema. Describe your perfect world!

Suppose we have a reasonable big number of common types.

  • There will be a substantially big number of services 'working' with those types. It will be clear to the vendors what API the world expects. The leading platforms, like .Net, will probably provide some basic services, like persistence, out of the box.
  • It will be much easier to consume those services, since they will fit each other.
  • Workflow engines and their complementary graphical designers will be able to manipulate on a much higher level of abstraction: there can be a concept of Person, Customer, Order etc as basic types with corresponding graphical representation. Probably many services will be also able to identify themselves and get correct glyphs.
  • GUI controls will also upgrade and operate with higher level objects. They will be also able to take service references as parameters to get their work done!
  • And finally every platform will provide a class library with those common types implemented and having many useful methods. Those types will be really first class citizens in the SOA world and application developers will need only extend them, if required. Their learning capabilities and efficiency will also increase since there will be much more common in this world!

 

This is how I would like it to be, and very interested to hear you opinion.

Please leave your comments!

Monday, July 7, 2008

Method Hiding - Feature or Bug in Compiler?

Since its very beginning C# has a 'method hiding' feature, which lets us 'hide' base class non-virtual methods. In other words one can write:
class Base
{
public void Test() {
Console.WriteLine("Base");
}
}

class Derived : Base
{
public new void Test() {
Console.WriteLine("Derived");
}
}

//...

Derived d = new Derived();
d.Test(); // "Derived" is printed


So far so good, but what happens if I write:



Base d = new Derived();
d.Test(); // "Base" is printed


Is this an intended behavior? Well, may be yes, but may be no. In case of 'no', we just called a wrong function, and no warning or error was issued by the compiler... Just consider again what happened, we declared a non-virtual method - that's our contract that should be ensured by the compiler. Instead it provides us with a feature to break it.



That's not all, consider the situation where you have some 3rd party library and use it in your project. Now the vendor releases a new version where he hides some method and provides an alternative implementation. Your program will still call the old method until you recompile! So in case you have several modules some recompiled and some not, you may have inconsistent behavior...



Of course you can always find use-cases, where the feature is carefully used and actually is very useful in that context. Yet its disadvantages outweight the advantages, so I think it would be better if we will develop our programs without using it.



Unfortunately there is an additional very similar "feature" - private interfaces, which can be implemented by a type even if its base class already implemented it and declared it sealed. Again the language helps us to break the contract and if it's not done carefully enough, the bugs won't wait to come...

Friday, July 4, 2008

C# Co[ntra]variance

To get introduced to the topic, please read Eric Lippert's variance series first.

Here I would like to present my solution to the problem.

After all there are only 3 possibilites:

  1. Clear covariance (IEnumerator<T>).
  2. Clear contravariance (IComparer<T>).
  3. Undecidable (IList<T>).

All the 3 possibility are easily detectable by compiler and I believe for the first two we would like the compiler will decide the variance automatically. We need a solution for the third case only.

To see the solution, I would like first analyze how we selected which case the given interface belongs to. We analyzed the method signatures in which T is involved:

  1. If in all of them T is 'out' parameter, the interface is covariant.
  2. If in all of them T is 'in' parameter, the interface is contravariant.
  3. If there is a mix - undecidable.

My solution is to say the compiler how I'm going to use my variable and enable either covariant or contravariant invocations:

IList<Animal> aa = whatever;
IList<in Giraffe> ag = aa;
IList<out Giraffe> agX = aa; //fails to compile

ag user sees: 'int ag.IndexOf(Giraffe)' and 'object ag[int]'.

IList<Giraffe> ag = whatever;
IList<out Animal> aa = ag;
IList<in Animal> aaX = ag; //fails to compile

aa user sees: 'int aa.IndexOf(<only null can be passed>)' and 'Animal aa[int]'.

Now I can say in a type safe manner:



class X<T> {

T _t;

void Test(IList<out T> at) {
T t = at[0]; //clearly t is 'out' parameter
}

void Test(IList<in T> at) { //overloaded method!
int i = at.IndexOf(_t); //clearly _t is 'in' parameter
}
}

//...

new X<Animal>().Test(new List<Giraffe>()); //first method is called
new X<Giraffe>().Test(new List<Animal>()); //second method is called