Blog Home  Home RSS 2.0    
Arnon Rotem-Gal-Oz's Cirrus Minor - .NET
Archive
 
 Thursday, August 09, 2007
I've been taking a look at ruby for a few month, I am finally getting to a stage where (I think/hope) I can actually say something intelligent about it. Last time I had an "aha moment" about a language was the fist time I saw Java.  C++  was oh-so-powerful, but Java was (is)  much more elegant and nice. Now Ruby changes the rules of the game again.
When I first heard about ruby I thought it was just a fad, something that the cool kids are using but its just another language. I getting more and more convinced that it isn't so. I am trying not to get too "silvery-bulletey"  here but working in ruby seems to actually increase productivity.
Let's take Dependency Injection(DI) as an example. DI is one of the most important and powerful tool I've learned in regard to Object Oriented development. Instead of classes depending directly on other classes classes depends on interfaces. And external classes (assemblers) provide them with their dependencies. This allows for loose coupling, increase testability and a lot of other such goodies (you can read a concise explanation in a paper I wrote on OO principles or get a more thorough explanation in a paper Martin Fowler wrote on "Inversion of Control Containers and the Dependency Injection pattern".  The .NET and Java worlds are filled with a lot of frameworks to help solve this elegantly. Spring (and Spring.Net) is probably the most known one.

How do you do DI in Ruby? in two words - you don't
If I am to join the "Define DI in one sentence" challenge by Jim Weirich I would say that
"DI is a powerful and good workaround to  the collaboration coupling problem between objects which is best addressed at the language level"

Why doesn't ruby need DI?

Well, I would say that it all starts at the basics. I remember when I learned OO, I was told objects communicate using messages. I never really understood why they call "method invocation" messages - it doesn't make any sense. The point is that in ruby you really don't "call a method" you "send a message"*.  When you make a call like someVariable.SomeMessage - the ruby interpreter  doesn't really care about the type of someVairable just that the object it holds (and everything is an object) has some entry which can handle SomeMessage.
Let's start with a simple example
consider the following code:

class Foo
  def bar
    puts "Foo-bar"
  end
end

class Foosa < Foo
end

class Baruser
  def baruse(b)
    b.bar  #dependency
  end
end

bu= Baruser.new

bu.baruse(Foo.new)
bu.baruse(Foosa.new)   # sub-class

Well, nothing particularly exciting here. if you run this  you get foo-bar printed twice. That's very much like the dependency injection you see in .NET or Java
It gets a little more interesting when we consider that the following classes would all work as well

class Foz
  def bar
    puts "Foz-bar"
  end
end

class NoBar
  def method_missing(methodname, *args)
    puts "NoBar" if "bar" == methodname.to_s
  end
end

class MakeBar
   define_method(:bar) {puts "madebar"}
end

bu= Baruser.new

bu.baruse(Foz.new)     # another type altogether
bu.baruse(NoBar.new)   # a class that doesn't have bar method
bu.baruse(MakeBar.new) # a class where the bar method is created programatically
 
We can see from the examples that what ruby does is searching for a handler for the bar message. The handler can be a method (symbol) called bar or a generic handle like Missing_Method - ruby doesn't care as long as the message get handled

I think that's pretty nice, we have a lot of flexibility on the dependency side but the depending class still  essentially gets the dependency by injection (the call to baruse)
Well, ruby can help us flex the dependent side as well. The answer is in the last example which uses (an overly simple an uninteresting example of) meta-programming Consider the following code example using Mocha which is a Mock object library for ruby
 
Lets say we modify our Baruser class to the following.

class Baruser
  def initialize
    buildfoo()
  end
  def baruse
    foo = buildfoo()
    foo.bar  #dependency
  end
 
 private 
  def buildfoo
    Foo.new #dependency
  end
end

Note that buildfoo is private - if we wanted to test this in.NET we need to have Foo around. i.e. we can no longer test Baruser by itself
if we use Mocha in ruby we can do the following:
foo = mock('foo')
foo.expects(:bar).at_least_once.

bu = Baruser.new
bu.stubs(:buildfoo).returns(foo) # basically what happens here is that the instance we have is changed
bu.baruse

I can't believe they invented it  - You can get  ruby for just the price of download and if you call within the next 15 minutes we'll throw in a copy of gems free of charge :)

In any event what we see here that using meta-programming and other ruby constructs we can forgo using DI altogether - no wonder Neil Ford defined DI as :
"Dependency Injection enables a vitally important but nevertheless weak, limited, syntactically confounding, and dauntingly complex form of one of the kinds of meta-programming that should exist in the language."
 Not to mention that the resulting code is much more elegant. which is actually what I like best about ruby, the code is much cleaner (but that's for another post)

Some closing thoughts

  • .NET 3.5 bring some of the ruby goodness to C# - but as the previous post demonstrated it is just a move in the right direction but not the whole thing
  • While I am on the subject of the previous post the whole interface vs. class thing is, of course, a moot point in Ruby since there are no interfaces. Interfaces, like DI, are another thing that is very important in C# and Java and not needed in Ruby
  • I've read some complaints on Ruby's performance. performance is important but there are two things to remember. First, the fact that a solution is not the fastest doesn't mean that it isn't fast enough. Second, I can still vividly recall the performance benchmarks for our Java code before we got the first hot spot compiler installed. The point is, that if it is important to enough people it will get better.




* I know, I know, Smalltalk had it since the beginning of time. However in Smalltalk everything is an object, in ruby you can also write plain scripts and (more importantly for me) - I never really took more than a cursory look at smalltalk  so I never  saw that.

 

8/9/2007 1:01:43 AM (Jerusalem Standard Time, UTC+02:00)  #    Comments [5]   .NET | A&D2007 | Design | Everything | ruby  | 
 Monday, August 06, 2007
One of the interesting presentations I attended in Architecture & Design world was "User Interface Principles in API design" by Elliotte Rusty Harold.
Elliotte started off by mentioning that developers are people too (I guess...) and that designing an API we need to think about the people (developers) who are going to use it.  I totally agree, in fact, when it comes to API design is one place I insist developers use TDD even if they don't do it on their day-to-day development. Dogfooding their own API is probably the only way to really ensure you get a usable API. Elliotte thinks you should go further than TDD and write some sample programs first.

The challenges of API or library design come from the fact that you cannot be sure about Elliotte mentioned some of the fundamental principles of UI design that apply to API design.
  • The importance of consistency
  • Simple is better (and for god sake please keep complexity internal) which translated to YAGNI and "when in doubt, leave it out")
  • Smaller surface (API) is easier to use.
To demonstrate the point of proper API design Elliotte compared the complexity of JMidi vs. the elegance of JFugue. While in JFugue you just use a couple of lines to play a few notes:
Player player = new Player();
player.play("C D E F G A B")
JMidi required more than 20 lines of setting all sorts of things related to its internal structure.

Elliotte also had a lot of practical advice on varios aspects like maintenance, specific advice for Java, specific advice for .NET etc. - Instead of me reiterating it I suggest you just take  a look at the presentation which is available on his site.

One point Elliotte made which I don't completely agree with was that you should prefer classes over interfaces. we discussed this issue after the presentation and I said that it is true for libraries but I am not sure that it is always true for frameworks (see Frameworks vs. Libraries for more details on the difference). in IoC scenarios interfaces allows extending the framewok for use with user defined types. One real-life example I offered was a plug-in framework we developed internally a few years ago. This framework incorporated a fixed set of components based on certain 3-rd party components (grid, tree etc.) - This worked very nicely, until in one project we wanted to use other 3rd party components (let's say a ribbon or another grid) which left us with either waiting for the infrastructure guy to find the time to make the changes, fork the infrastructure code, or build something new (we went with building something new since working with end-users we found we actually  didn't need most of the capabilities the framework offers like security/roles, role tayloring capabilities etc.)

On the other hand one argument for using classes over interfaces that Elliotte is right about is that when you use interfaces and then make a change in that interface. The chage  breaks all clients. If however all the clientes used a subclass they would automatically inherit the new functionality.

I thought I could work around this limitation in .NET 3.5 (or whatever microsoft will end-up calling it) by using extension methods so I did something like the following (tests etc. are excluded for brevity)
  class Program
{
static void Main(string[] args)
{
testInterface tc = new testClass();
tc.DoSomthing();
tc.DoSomethingElse();

}
}

interface testInterface
{
void DoSomthing();
void DoSomthingElse(string test); // compilation error....
}

static class testInterfaceDefaultBehaviour
{
public static void DoSomethingElse(this testInterface ti)
{
System.Console.WriteLine("Doing something else");
}

}

class testClass : testInterface
{
public void DoSomthing()
{
System.Console.WriteLine("Doing something here...");
}
}
I was wrong....

Main does  recognized the DoSomethingElse pretty well - however adding it to the Interface definition caused a compilation error.
This is a shame since the MSDN documentation says that
 " In effect, extension methods make it possible to extend existing types and constructed types with additional methods."
If it had worked that would have let us have something like method_missing in ruby in C#. Well, .NET 3.5 is still in beta so maybe it would change (not counting on that)

8/6/2007 1:06:12 AM (Jerusalem Standard Time, UTC+02:00)  #    Comments [0]   .NET | A&D2007 | Design | Everything  | 
 Wednesday, August 01, 2007
I won't say anything about my presentations (that's for others to say :) ). The point of this post is just to let you download them. So here they are:
  • SOA Patterns (2.14mb) - Takes a look at different strategies (patterns) to solve common SOA pitfalls
  • Getting SPAMMED for architecture (4.56mb) - Takes a look at the activities architects can/should do when they think about software architectures. The presentation also covers architecture in agile projects.

8/1/2007 10:52:49 PM (Jerusalem Standard Time, UTC+02:00)  #    Comments [0]   .NET | A&D2007 | Agile | Everything | SOA | SOA Patterns | Software Architecture | SPAMMED Process  | 
 Friday, July 13, 2007
Evan H asked a question about distributed transactions and services in the MSDN architecture forum:

Are distributed transactions (ie.. WS-Transaction) a violation of the "Autonomous" tenant of service orientation?   Yes or No and Why?  Kudos if you can address concurrency and scalability (in an enterprise with multiple interacting services).

I answerd this questions back in april when I wrote a couple of posts that explained why cross-service transactions are a bad idea:cross service transactions and some more thoughts on cross service transactions.
Roger Sessions also agrees with this view (well, it seems actually, he wrote about it well before I did :) ):
When the WS-Transaction specification was first proposed, back in 2002, I wrote an article explaining why I thought the idea of allowing true transactions to span services was a bad idea. I published the article in The ObjectWatch Newsletter, #41: http://www.objectwatch.com/newsletters/issue_41.htm. Nothing since then has changed my mind. Atomic transactions require holding locks, and spanning transactions across services requires allowing a foreign, untrusted service to determine how long you will hold your very precious database locks. Bad idea. Just because IBM and Microsoft agreed on something doesn't make it good!

The reason I am bringing this issue back is that Juval Lowy (who wrote the article that triggered my first post on the subject) has recorded an Arcast with Ron Jabobs. Where he re-iterated the idea that "Transactions is categoricaly the only viable programming model" and you should strive to use it whenever you can. It seems Juval admits you sometimes need to use Sagas (which he called "long running transactions" - you can see in my link why I think that's a wrong name). He also agrees that you can also use a transactionable transport and then only do internal transactions from each service to the transport (a pattern I call "Transactional Service"). However, at the end of the day, he still thinks you should use WS-AtomicTransactions whenever you can.

I agree that transactional programming is important. I think it is the simplest programming model (from the developers side). I would probably never write an interaction with a database that is not transactional; I look very favorably at initiatives for in-memory ACI (no Durability) transactions such as the one Ralf talks about.  Until we get to Distributed Transactions...

First, we should note that transactions are not "the only viable" option.As Martin Fowler notes Ebay seems to be doing fine without distributed transactions. Not only that, they abandoned distributed transaction and went "transactionless"because they needed one simple thing... Scalable performance .

In most COM+ scenarios you have a single server or a few internal servers where the distributed transaction happen - and even there you should plan your transactions carefully if you want to get any kind of decent performance. In SOA scenarios the situation is more complicated as the distribution level is expected to be higher (even if you don't involve services from other companies). More distribution means longer times to complete transactions (especially if a participant can flow the transaction and extend it). It also means increasing the chances of failure (see Steve Jones series of posts on five nines for SOA). In my opinion, the more distributed components you have the more you want their interaction to be decoupled in time - i.e. the opposite of transactions.

Juval also said he doesn't buy the denial of service problem I mentioned (supporting a transaction means you allow locks - if an external party doesn't commit you retain the lock..). Juval said he assumes that a solutions has both authentication and authorization so this shouldn't be an issue. For one, I have seen too many projects where security was something that was neglected or quickly patched in at the latest moment - so I would hardly assume security. Even with security on - you increase your attack surface.
But that's just the half of it. Even if all your service consumers have good intentions - you still don't know anything about their code. SOA is not like the "good old days" where you owned the whole application  - this means you cannot trust their security to be ample. Also you don't know anything about their code quality. Services are likely (in the general case) to be deployed on different machines, even if they start co-located. I think that a Service boundary should be treated as a trust boundary just like a tier boundary. I strongly believe you should have reduced assumptions on what's on the other side of the service's boundary - transactions are not reduced assumptions

SOA and distributed transactions do not go hand in hand - it isn't just autonomy at stake here. It is a problem for performance and scalability and even security period.

To finish this post - I would also highly recommend looking at Pat Helland's paper "Life Beyond Distributed Transactions: an Apostate's Opinion" and a post he recently made called  "SOA and Newton's Universe", where he explains more eloquently than I ever could why SOA is not a good fit for distributed transactions.


7/13/2007 10:47:03 PM (Jerusalem Standard Time, UTC+02:00)  #    Comments [3]   .NET | Everything | SOA | SOA Patterns | Software Architecture  | 
 Wednesday, June 13, 2007
In addition to the drafts of selected patterns I publish on my site, you can now purchase my book via the Manning Early Access Program (MEAP).
MEAP means you can get chapter drafts as I write them and the complete book when its done (ebook or printed). Here is Manning's explanation:
"Buy now through MEAP (Manning Early Access Program) and get early access to the book, chapter by chapter, as soon as they become available. You choose the format - PDF or ThoutReader - or both. By subscribing to MEAP chapters, you get an opportunity to participate in the most sensitive, final piece of the publishing cycle by offering feedback to the author. Reader feedback to the author is welcome in the Author Online forum. As new chapters are released, announcements are made in the MEAP Announcement Forum. After all chapters are released, you will be able to download the complete edited ebook. If you order the print edition, we will ship it to you upon release, direct from the bindery, weeks before it is widely available elsewhere.
By the way, this is probably also a good time to mention that I'll be speaking about quite a few of the patterns in Architecture & Design World 2007 which will take place this July.

There is still a lot of work, but I already like to thank all the people in manning that helped me get this far. especially to Cynthia Kane my editor (hey, maybe now she'll give me more slack :) )
Ok, 'nuff blubbering, back to completing chapter 5...

6/13/2007 10:37:18 AM (Jerusalem Standard Time, UTC+02:00)  #    Comments [0]   .NET | Everything | SOA | SOA Patterns | Software Architecture  | 
 Tuesday, May 29, 2007
Udi Dahan writes that ".NET/Java Interop is not a reason for SOA". Udi writes that companies that  need to integrate two technologies turn to web-services and that
"The only problem is that in order for things to work right, they really must have a chatty interface, and flow transaction context between these “services”, and all the other things I describe as anti-patterns"

Udi is right that if you don't rethink and remodel your systems you will (probably) not  have an SOA as you are likely to find your self implementing  anti-patterns such as the ones he mentions.

However, using Web-services does not automatically mean that you are doing an SOA. If you don't think about moving to SOA you can still opt to use web-services as a remoting  or RPC technology to connect two systems. The advantage over the other proprietary products Udi mentions is that web-services are a standard technology. This will work well or fail is orthogonal to the technology choice. It depends on the architectures of the systems you integrate. If you need to flow transaction between the systems you'd also need that even if you cross-compile one of the applications in the other environment.

Another thing I don't agree with is the word must Udi uses. First, while it is likely that older systems has chatty interfaces it is not a must. The designers of the legacy system may have thought about the consequences of distribution without regard to SOA. Also you can still wrap an existing system with a service contract (using web-services or any other technology) and not get to chatty interfaces etc. However that means that the wrapper should have some substance or business logic inside it to mask the old system's behavior this is especially important  if you are thinking about moving to SOA and you take into consideration that the business will not just halt and wait there until you are done. You have to think about interim solutions, such interim solutions can include wrapping a legacy system with an Edge Component and a SOA facade (a pattern I call Legacy Bridge) while you move in the grader direction of a full blown SOA.

5/29/2007 10:12:00 AM (Jerusalem Standard Time, UTC+02:00)  #    Comments [3]   .NET | Everything | SOA | SOA Patterns | Software Architecture  | 
 Thursday, May 24, 2007

I just read Shy Cohen's (via Nick Malik) article in Microsoft's Architecture Journal entitled "Ontology and Taxonomy of Services in a Service-Oriented Architecture" Shy provides a list of what he calls service types. He identifies two major types  bus services and application. He then continues to sub-divide them, the Bus Services are divided into communication and utility services and the Application services  are divided into entity, capability, activity and process services. I have to say it was quite alarming to see this coming from someone who had deep involvement in defining Windows Communication Foundation Indigo.

Where do I start?

well, for one, it seems completely fails to make the distinction between Services as in Service Oriented Architecture and Services as in capabilities or features an infrastructure provide. The "Communication services" are for the most part capabilities that a service infrastructure (such as an ESB) provides. Not Services you would define in an SOA initiative And then there's the matter of service granularity and the difference between Remote objects and SOA for instance, the example  Shy gives for  a "method" (his word) on a Customer service (entity service):

"An example of a domain-specific operation is a customers service that exposes a method called FindCustomerByLocation that can locate a customer's ID given the customer's address"
why would a service return a customer ID? This is the kind of call you would make on an object you hold a reference to not some remote "Something" that also want to authorize your call and may reside in a different company. This kind of thinking is what made remote objects fail. Gregor Hohpe explained that nicely in a paper  called Developing software in a Service Oriented World
The Transparency Illusion.  Distributed components promised to hide remote communication from the developer by making the remoteness "transparent". While the basic syntactic interaction between remote components can be wrapped inside a proxy object, it turned out that dealing with partial failures, latency, and remote exceptions could not be hidden from the developer. It turned out that 90% transparency was actually worse than no transparency because it gave developers a false sense of comfort.
As a side note, Gregor recently gave a presentation that covers this paper at JavaZone which you can watch online at InfoQ

Returning to Shy's article let's take a look at another quote:
Capability Service may flow an atomic transaction in which it is included to the Entity Services that it uses. Capability Services are also used to implement a Reservation Pattern over Entity Services that do not support that pattern, and to a much lesser extent over other Capability Services that do not support that pattern.
I already explained why cross-service transactions and especially flowing transactions is not a good idea in SOA so I won't do it again here - but you can read about it both here ("Transactions between Services? No, No, No!") and here ("Cross-Service Transactions"). Also I truly hope Shy didn't mean .NET data sets when he said "In some cases, typically for convenience reasons, Entity Service implementers choose to expose the underlying data as data sets rather than strongly-schematized XML data. Even though data sets are not entities in the strict sense, those services are still considered Entity Services for classification purposes." In any event the whole decomposition of Services into fine grained "capability", "Activity" and "process" takes no account of the fact the SOA is a distributed architecture...maybe Microsoft is not affected by the  fallacies of distributed computing ?
*ad nauseam (latin)- to the point of disgust

5/24/2007 12:06:19 AM (Jerusalem Standard Time, UTC+02:00)  #    Comments [0]   .NET | Everything | SOA | Software Architecture  | 
 Monday, May 07, 2007
In the article mentioned in the previous post, I talk about adding EDA to SOA and how you can use Complex Event Processing (CEP) to process the event streams and infer the trends and enhance the understanding of what happen inside your business. All the tools I knew about were Java tools I knew about were Java tools but now I've found out (via Nauman Leghari's blog) that there's also a .NET CEP engine and it is even open source - It is called NESper and like many other tools it is a port of a Java tool.
I am not sure how good it is - but at least I'll have an interesting evening today :)

5/7/2007 7:15:47 PM (Jerusalem Standard Time, UTC+02:00)  #    Comments [0]   .NET | Everything | SOA  | 
 Monday, April 30, 2007
An article I wrote on Business Intelligence (BI) and Service Oriented Architecture (SOA) has just been published on MSDN.
You can find it here http://msdn2.microsoft.com/en-us/library/bb419307.aspx.

The article explains the SOA & BI mismatch and how to bridge it by adding EDA to SOA. (I bloged about it here before, but the article is more ordered and complete)

4/30/2007 8:34:19 PM (Jerusalem Standard Time, UTC+02:00)  #    Comments [0]   .NET | Everything | SOA | SOA Patterns | Software Architecture  | 
 Sunday, April 29, 2007
Back in January, I took part in an architect panel that Microsoft Israel organized. The panel was led by Ron Jacobs and it featured Udi Dahan, Assaf Jacoby, Coby Cohen, Dudu Benabou and myself. A few days ago Ron edited this recoding and turned it into a podcast in his Arcast series.

The panel's focus was on lessons learned from mistakes made in past project. Ego maniac as I may be :) -- even though you don't get to hear me much in the final edited version -- I think the podcast is worth listening to, as the panel raised some interesting points. You can download the podcast here (don't worry it is in English even though it was recorded in Israel)

PS

I am the first speaker after the introduction, in case you are wondering.

4/29/2007 4:14:04 PM (Jerusalem Standard Time, UTC+02:00)  #    Comments [0]   .NET | Everything | General | Software Architecture  | 
 Tuesday, April 17, 2007

After seeing Juval Lowy's article on WCF transaction propagation in the May issue of MSDN magazine. I posted  " Transactions Between Services? No, No, No! " in my DDJ blog. I've got a few comments which I thought warrant a post in their own-right.

The previous post was triggered by an article that promoted flowing transactions (i.e. you perform a transaction against one or two services and then one of the services calls an additional service and it joins the transaction). It is important to say that I think transactions between services should be discouraged regardless of automating extension of transactions. Transaction propaqgation just makes the matters worse.


There might still be some edge case where you have to have an atomic transaction from a service consumer to the service. I think that in the vast majority of SOA implementations you shouldn't do that and I would think real hard about the other options before allowing it in my architecture.In general  I think cross-service transactions are an antipattern (and that's the way you'd find them documented in my SOA patterns book :) )

One of the comments I received began with:

"Cross service transactions are a sure way to introduce coupling and performance problems into your SOA." I'm not sure I agree with that thought. Logically speaking, cross service transactions are a must. The question is how to implement them. There are two mechanisms we can use for implementing TXs: (1) ACID TXs; (2) Long-running TXs. The latter is preferable for the cases Arnon is talking about (large geographical distances, multiple trust authorities, and distinct execution environments). ACID TXs are more suitable for what Guy has mentioned (DeleteCustomer service invokes the DeleteCustomerOrder service internally). I agree with Arnon the a-synchronicity is preferable, but we all have encountered use-cases where ACID-ness is required from a business requirement level... [snipped]


One minor point in regard to this comment is that I don't like the term long running transaction - there is a long running interactions between services and I think the term SAGA describes them better. Sagas are made of a series of business activities that flow back and forth between services to realize a larger business process. Note that these interactions doesn't necessarily have transaction-like behavior.


which brings me to the more important point of looking at the statement "Logically speaking, cross service transactions are a must". I don't think so. For instance, if a service that manages the inventory in a warehouse receives a request for some items and later a cancelation of that request. The first request can trigger the inventory service to order some more items from a supplier. Whether or not the cancellation would cause a cancellation of the order of the supplier depends on the business rules of the inventory service for inventory levels for the items ordered. it might also depend on whether or not the items have already been received etc. The cancellation (the "abort") of the original request does not have to translate to an abort (or compensation) on the request receiver. Furthermore if the service communications model is based on the push model (e.g. using EDA with SOA) the cancellation notice would just be propagated without regard to the inventory service -. It is the inventory service's responsibility to understand the ramifications of this event and act accordingly. Even the example given in the comment 'DeleteCustomer service invokes the DeleteCustomerOrder service internally" is not a good candidate from ACID transactions (there's also a problem of service granularity here - I'll talk about it later). Since when the customer service decides to delete a comment and request the Orders service to delete orders - there's a reasonable chance that some of the orders are already paid for but not delivered. In this case the customer cannot really delete the customer until all the paid orders are resolved. Or maybe the order service is a facade to a night batch that does the actual deletion. - I know I am just fantasizing with these examples but the point is that the customer service has no knowledge on the order service or the inventory service above except the messages supported in their contract. To assume something about the internal behavior is problematic. Even if you know about the internal structure on the onset, the whole idea of SOA is that the services can evolve independently from each other...


Another thought triggered by the example in the comment originated by the granularity of the services (DeleteCustomer service vs. a Customer Service that also supports deleting customers) is that we should be really conscious to the difference between other architectures like 3-tier client/server and SOA. SOA is actually more distributed than 3-tier - we cross a distribution boundary every time we pass a message from a service to a service and not just when we move a massage from a client-tier to an application server. We add this distribution to gain advantages in flexibility and agility. However, we should note that this is a weakness of SOA (considering for example, that Martin Fowler's first law of distributed object design is" Don't distribute your objects!") means we should really pay attention to the way services interact with each other.

  • The granularity of services - having a lot of fine grained services means there will be a lot of interactions over the wire (even if you don't go out to the network you still have to serialize/deserialize, follow the security policy etc.) rather than internal interactions that much faster
  • The Granularity of messages - The same considerations should also guide us to try to create larger and fewer messages. for the example above . Instead of a DeleteCustomerOrder message maybe something like an UpdateCustomersOrders message that can hold a list of customers and orders and the status changes or . by the way this would also support off-line clients better since they can accumulate changes.
  • The assumptions we can make on the other service's availability, performance, internal structure, the trust we have for it etc. - We should try to minimize the assumptions we make and concentrate on what can be inferred from the contract. Remember that policies can change externally so the business logic within a service cannot count on them being constant. this brings us back to the issue of transaction. every cross-wire interaction increases the chances of failure - in transactions one failure invalidates all the transaction is invalidate. every cross-wire interaction within a transaction increases the length of time we lock internal resources (even if we do trust all the involved parties) - especially if that transaction can extend itself automatically. Also as I've mentioned in the previous post the transactions also open the door for denial of service attacks.

If we want to reap the benefits that are sold under the SOA moniker, like flexibility and agility, we really have to pay attention to this extra distribution and design our services differently than we would components in a 3-tier architecture - but hey, that's why they pay us the big bucks, right ? :)

I should probably also add  that building SOAs is not a goal in itself. We can build perfectly good solutions using other architectures - but if we find that we do need SOA (or any other architecture for that matter) we have to pay attention to the way we implement it to both keep its benefits and not harm other quality attributes like performance, security etc..


4/17/2007 2:58:15 PM (Jerusalem Standard Time, UTC+02:00)  #    Comments [0]   .NET | SOA | SOA Patterns | Software Architecture  | 
 Tuesday, April 10, 2007
Back in January I opined that  moving to web applications was not the optimal solution to the real problem we have/had with desktop applications which was  installation woes. What we got was a poor UI without installation problems so we (software industry) started to resolve problems like we had when we moved from  terminals to graphical UIs etc. - 
So now we have Rich Internet Applications (RIA) - using technologies like AJAX - but they suffer from other problems  which again we've already been through

Well that was the topic of the post in January. Now I've stumbled upon an interesting/amusing  twist - called Adobe Apollo
Apollo let's you, yes you've guessed it, take your RIA applications and deploy them as desktop applications.  you can now take your HTML, CSSs , AJAX scripts pack them up as a single file (AIR) and lo and behold deploy them on the desktop. You even get these nifty start menu and desktop shortcuts :)

The reason not to dismiss this a complete waste of time - is that what we actually see here is another example of a trend to convergence  web and desktop UI architectures  and programming models. I say "another" because coming from the desktop direction Microsoft is doing pretty much the same thing. WPF brings the web-programming model  with its markup (XAML) and "code-behind" concepts to the desktop as well as pushing the same model to the browser with WPF/E .

The difference between Microsoft's and Adobe's solutions is that, Adobe is coming from the web-side and, as I said, Microsoft is coming from the Desktop side - both companies are striding toward the same goal -  and what we are left with,  is yet another technology war




4/10/2007 2:25:07 PM (Jerusalem Standard Time, UTC+02:00)  #    Comments [0]