It's 2008. Where's my flying car? RSS 2.0
 Monday, May 17, 2004

This here reminds me of the box that's quietly humming in my home office and serves as my domain controller, firewall, RAS and DSL gateway. I upgraded the machine (a rather old 400 MHz Compaq) to Windows Server 2003 the day before I flew to TechEd Malaysia last year (August 23rd, 2003). I configured it to auto-update from Windows Update and reboot at 3:00AM in case updates have been applied.

Guess what: I got back home from that trip (which included 4 days touring the Angkor temples in Cambodia and another 10 days hanging out at the beach on Thailand's Ko Samui island) and realized that I forgot the Administrator password. Tried to get in to no avail. I've got rebuilding the box on my task list, but there's no rush. I haven't really touched or switched off the machine ever since. It keeps patching itself every once in a while and otherwise simply does its job.

Monday, May 17, 2004 1:21:22 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [4] - Trackback
Technology

Want to win an XBox? You run dasBlog? Michael Earls shows you how.

[I just knew that the <%newtelligence.aspnetcontrol("TechEdBloggersFeed.ascx")%> macro would eventually be good for something ;-) ]

Monday, May 17, 2004 12:24:31 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [0] - Trackback
TechEd US

I am not a “smart client” programmer and probably not even a smart client programmer and this trick has probably been around for ages, but …

For someone who’s been doing WPARAM and LPARAM acrobatics for years and still vividly recalls what (not necessarily good) you can do with WM NCPAINT and WM NCMOUSEMOVE (all that before I discovered the blessings of the server-side), it’s pretty annoying that Windows Forms doesn’t bubble events – mouse events specifically. It is actually hard to believe that that wouldn’t work. But I’ve read somewhere that bubbling events is “new in Whidbey”, so it is probably not my ignorance. Anyways … include the following snippet in your form (add MouseDown, MouseUp, … variants at your leisure), bind the respective events of all labels, panels and all the other “dead stuff” to this very handler (yes, all the controls share that handler) and that’ll have the events bubble up to your form in case you need them. I am just implementing custom resizing and repositioning for some user controls in a little tool and that’s how I got trapped into this. Voilá. Keep it.

 

protected void BubbleMouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
      Point pt = this.PointToClient(((Control)sender).PointToScreen(new Point(e.X,e.Y)));
      MouseEventArgs me = new MouseEventArgs(e.Button,e.Clicks,pt.X,pt.Y,e.Delta);
      OnMouseMove(sender,me);
}

Monday, May 17, 2004 12:13:42 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [2] - Trackback
Technology

Omar Shahine, who took the role of the "Program Manager" for dasBlog 1.6 added a new macro feature (I am actually not really sure who added it; someone correct me if I am wrong; at least Omar OK'd the feature) that totally rocks and put us on par with MovableType in terms of easy access to older entries:

<%newtelligence.drawarchivemonths()%> 

The macro creates a list of links for all months that have blog entries and if you look at my site (not at the RSS feed), you'll see it on the left-hand side of the page just under the "What's News" section. Thanks! Now I can find my old stuff again. ;-)

if you haven't see it already; Omar's comments about the 1.6 drop and links to release notes and binaries/source are on his blog.

Monday, May 17, 2004 2:27:21 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [0] - Trackback
Blog | dasBlog
 Sunday, May 16, 2004

One of the reasons why I run Windows Server 2003 on my notebook is that "Services without Components" (managed incarnation is System.EnterpriseServices.ServiceDomain) didn't work on XP. If you just touch the ServiceConfig or ServiceDomain classes on XP, you get rewarded with a PlatformNotSupportedException, because the unmanaged implementation of that feature was present, but not quite-as-perfect-as-it-should-be on XP. That will soon be history. Windows XP SP2 and the COM+ 1.5 Rollup Package 6 will fix that and will bring COM+ 1.5 pretty much on par with Windows Server 2003.

Sunday, May 16, 2004 11:55:11 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [2] - Trackback
Enterprise Services

Ralf Westphal responded to this and there are really just two sentences that I’d like to pick out from Ralf’s response because that allows me to go a quite a bit deeper into the data services idea and might help to further clarify what I understand as a service oriented approach to data and resource management. Ralf says: There is no necessity to put data access into a service and deploy it pretty far away from its clients. Sometimes is might make sense, sometimes it doesn’t.

I like patterns that eliminate that sort of doubt and which allow one to say “data services always make sense”.

Co-locating data acquisition and storage with business rules inside a service makes absolute sense if all accessed data can be assumed to be co-located on the same store and has similar characteristics with regards to the timely accuracy the data must have. In all other cases, it’s very beneficial to move data access into a separate, autonomous data service and as I’ll explain here, the design can be made so flexible that the data service consumer won’t even notice radical architectural changes to how data is stored. I will show three quite large scenarios to help illustrating what I mean: A federated warehouse system, a partitioned customer data storage system and a master/replica catalog system.

The central question that I want to answer is: Why would you want delegate data acquisition and storage to dedicated services? The short answer is: Because data doesn’t always live in a single place and not all data is alike.

Here the long answer:

The Warehouse

The Warehouse Inventory Service (WIS) holds data about all the goods/items that are stored in warehouse. It’s a data service in the sense that it manages the records (quantity in stock, reorder levels, items on back order) for the individual goods, performs some simplistic accounting-like work to allocate pools of items to orders, but it doesn’t really contain any sophisticated business rules. The services implementing the supply order process and the order fulfillment process for customer orders implement such business rules – the warehouse service just keeps data records.

The public interface [“Explicit Boundary” SOA tenet] for this service is governed by one (or a set of) WSDL portType(s), which define(s) a set of actions and message exchanges that the service implements and understands [“Shared Contract” SOA tenet]. Complementary is a deployment-dependent policy definition for the service, which describes several assertions about the Security and QoS requirements the service makes [“Policy” SOA tenet].

The WIS controls its own, isolated store over which it has exclusive control and the only way that others can get at the content of that data store is through actions available on the public interface of the service [“Autonomy” SOA tenet].

Now let’s say the company running the system is a bit bigger and has a central website (of which replicas might be hosted in several locations) and has multiple warehouses from where items can be delivered. So now, we are putting a total of four instances of WIS into our data centers at the warehouses in New Jersey, Houston, Atlanta and Seattle. The services need to live there, because only the people on site can effectively manage the “shelf/database relationship”. So how does that impact the order fulfillment system that used to talk to the “simple” WIS? It doesn’t, because we can build a dispatcher service implementing the very same portType that accepts order information, looks at the order’s shipping address and routes the allocation requests to the warehouse closest to the shipping destination. In fact now, the formerly “dumb” WIS can be outfitted with some more sophisticated rules that allow to split or to shift the allocation of items to orders across or between warehouses to limit freight cost or ensure the earliest possible delivery in case the preferred warehouse is out of stock for a certain item. Still, from the perspective of the service consumer, the WIS implementation is still just a data service. All that additional complexity is hidden in the underlying “service tree”.

While all the services implement the very same portType, their service policies may differ significantly. Authentication may require certificates for one warehouse and some other token for another warehouse. The connection to some warehouses might be done through a typically rock-solid reliable direct leased line, while another is reached through a less-than-optimal Internet tunnel, which impacts the application-level demand for the reliable messaging assurances. All these aspects are deployment specific and hence made an external deployment-time choice. That’s why WS-Policy exists.

The Customer Data Storage

This scenario for the Customer Data Storage Service (CDS) starts as simple as the Warehouse Inventory scenario and with a single service. The design principles are the same.

Now let’s assume we’re running a quite sophisticated e-commerce site where customers can customize quite a few aspects of the site, can store and reload shopping carts, make personal annotations on items, and can review their own order history. Let’s also assume that we’re pretty aggressively tracking what they look at, what their search keywords are and also what items they put into any shopping cart so that we can show them a very personalized selection of goods that precisely matches their interest profile. Let’s say that all-in-all, we need to have storage space of about 2Mbytes for the cumulative profile/tracking data of each customer. And we happen to have 2 million customers. Even in the Gigabyte age, ~4mln Mbytes (4TB) is quite a bit of data payload to manage in a read/write access database that should be reasonably responsive.

So, the solution is to partition the customer data across an array of smaller (cheaper!) machines that each holds a bucket of customer records. With that we’re also eliminating the co-location assumption.

As in the warehouse case, we are putting a dispatcher service implementing the very same CDS portType on top of the partitioned data service array and therefore hide the storage strategy re-architecture from the service consumers entirely. With this application-level partitioning strategy (and a set of auxiliary service to manage partitions that I am not discussing here), we could scale this up to 2 billion customers and still have an appropriate architecture. Mind that we can have any number of dispatcher instances as long as they implement the same rules for how to route requests to partitions. Strategies for this are a direct partition reference in the customer identifier or a locator service sitting on a customer/machine lookup dictionary.

Now you might say “my database engine does this for me”. Yes, so-called “shared-nothing” clustering techniques do exist on the database level for a while now, but the following addition to the scenario mandates putting more logic into the dispatching and allocation service than – for instance – SQL Server’s “distributed partitioned views” are ready to deal with.

What I am adding to the picture is the European Union’s Data Privacy Directive. Very simplified, the EU directives and regulations it is illegal to permanently store personal data of EU citizens outside EU territory, unless the storage operator and the legislation governing the operator complies with the respective “Safe Harbor” regulations spelled out in these EU rules.

So let’s say we’re a tiny little bit evil and want to treat EU data according to EU rules, but be more “relaxed” about data privacy for the rest of the world. Hence, we permanently store all EU customer data in a data center near Dublin, Ireland and the data for the rest of the world in a data center in Dallas, TX (not making any implications here).

In that case, we’re adding yet another service on top of the unaltered partitioning architecture that implements the same CDS contract and which internally implements the appropriate data routing and service access rules. Those rules which will most likely be based on some location code embedded in the customer identifier (“E1223344” vs. “U1223344”). Based on these rules, requests are dispatched to the right data center. To improve performance and avoid having to data travel along the complete path repeatedly or in small chunks during an interactive session with the customer (customer is logged into the web site), the dispatcher service might choose to have a temporary, non-permanent cache for customer data that is filled with a single request and allows quicker and repeat access to customer data. Changes to the customer’s data that result from the interactive session can later be replicated out to the remote permanent storage.

Again, the service consumer doesn’t really need to know about these massive architectural changes in the underlying data services tree. It only talks to a service that understands a well-known contract.

The Catalog System

Same picture to boot with and the same rules: Here we have a simple service fronting a catalog database. If you have millions of catalog items with customer reviews, pictures, audio and/or video clips, you might chose to partition this just like we did with the customer data.

If you have different catalogs depending on the markets you are selling into (for instance German-language books for Austria, Switzerland and Germany), you might want to partition by location just as in the warehouse scenario.

One thing that’s very special about catalog data is that very much of it rarely ever changes. Reviews are added, media might be added, but except for corrections, the title, author, ISBN number and content summary for a book really doesn’t ever change as long as the book is kept in the catalog. Such data is essentially “insert once, change never”. It’s read-only for all practical purposes.

What’s wonderful about read-only data is that you can replicate it, cache it, move it close to the consumer and pre-index it. You’re expecting that a lot of people will search for items with “Christmas” in the item description come November? Instead of running a full text search every time, run that query once, save the result set in an extra table and have the stored procedure running the “QueryByItemDescription” activity simply return the entire table if it sees that keyword. Read-only data is optimization heaven.

Also, for catalog data, timeliness is not a great concern. If a customer review or a correction isn’t immediately reflected on the presentation surface, but only 30 minutes or 3 hours after is has been added to the master catalog, it doesn’t do any harm as long as the individual adding such information is sufficiently informed of such a delay.

So what we can do to with the catalog is to periodically (every few hours or even just twice a week) consolidate, pre-index and then propagate the master catalog data to distributed read-only replicas. The data services fronting the replicas will satisfy all read operations from the local store and will delegate all write operations directly (passthrough) to the master catalog service. They might choose to update their local replica to reflect those changes immediately, but that would preclude editorial or validation rules that might be enforced by the master catalog service.

 

So there you have it. What I’ve described here is the net effect of sticking to SOA rules.

·         Shared Contract: Any number of services can implement the same contract (although the concrete implementation, purpose and hence their type differ). Layering contract-compatible services with gradually increasing levels of abstractions and refining rules over existing services creates very clear and simple designs that help you scale and distribute data very well

·         Explicit Boundaries: Forbidding foreign access or even knowledge about service internals allows radical changes inside and “underneath” services.

·         Autonomy allows for data partitioning and data access optimization and avoids “tight coupling in the backend”.

·         Policy: Separating out policy from the service/message contract allows flexible deployment of the compatible services across a variety of security and trust scenarios and also allows for dynamic adaptation to “far” or “near” communications paths by mandating certain QoS properties such as reliable messaging.

 

Service-Orientation is most useful if you don’t consider it as just another technique or tool, but embrace it as a paradigm. And very little of this thinking has to do with SOAP or XML. SOAP and XML are indeed just tools.

Sunday, May 16, 2004 4:58:07 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [4] - Trackback
Architecture | SOA

I didn't spend much time for anything except writing, coding, travel, speaking and being at geek parties in the past weeks. Hence, I am sure I am the last one to notice, but I find it absolutely revolutionary that the Microsoft Visual C++ 2003 command line compiler (Microsoft C/C++ Version 13.1) is now a freebie.

Sunday, May 16, 2004 12:46:49 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [0] - Trackback
Technology | CLR
 Saturday, May 15, 2004

Rebecca Dias from Microsoft asked us to do a bit of work for her team and write a demo app for TechEd 2004. As things happen and being the serious German engineers we are, it just turned out to be a little too serious, little too big to be useful as a “and now here’s a bit of code!” demo app for TechEd (U.S.).

What we’ve built is a very serious service-oriented application and your feedback will contribute to the final decision about how Microsoft is going to make the application and code available to you. What’s already clear is that I will do a TechEd Europe talk that will cover the most important architecture and technology choices made for the application. Unfortunately the decision to have such a talk came too late to squeeze it into the TechEd U.S. agenda. Come to Amsterdam, TechEd Europe isn’t sold out, yet.

Comment on Rebecca’s blog entry here and let her know whether you rather like little samples like Duwamish or a full-blown SOA system that you can stick your head into for a week.

Saturday, May 15, 2004 2:07:42 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [0] - Trackback
TechEd US | TechEd Europe

[This might be more a “note to self” than anything else and might not be immediately clear. If this one goes over your head on the first pass – read it once more ;-)]

Fellow German RD Ralf Westphal is figuring out layers and data access. The “onion” he has in a recent article on his blog resembles the notation that Steve Swartz and I introduced for the Scalable Applications Tour 2003.  (See picture; get the full layers deck from Microsoft’s download site if you don’t have it already)

What Ralf describes with his “high level resource access” public interface encapsulation is in fact a “data service” as per our definition. To boot, we consider literally every unit in a program (function, class, module, service, application, system) as having three layers: the outermost layer is the publicly accessible interface, the inner layer is the hidden internal implementation and the innermost layer hides and abstracts services and resource access. The concrete implementation of this model depends on the type of unit you are dealing with. A class has public methods as public interface, protected/private methods as internal implementation and uses “new” or a factory indirection to construct references to its resource providers. A SQL database has stored procedures and views as public interface, tables and indexes as internal implementation and the resource access is the database engine itself. It goes much further than that, but I don’t want to get carried away here.

A data service is a layered unit that specializes in acquiring, storing, caching or otherwise dealing with data as appropriate to a certain scope of data items. By autonomy rules, data services do not only hide the data access methods, but also any of these characteristics. The service consumer can walk up to a data service and make a call to acquire some data and it is the data service’s responsibility to decide how that task is best fulfilled. Data might be returned from a cache, aggregated from a set of downstream services or directly acquired from a resource. Delegating resource access to autonomous services instead of “just” encapsulating it with a layer abstraction allows for several implementations of the same data service contract. One of the alternate implementations might live close to the master data copy, another might be sitting on a replica with remote update capability and yet another one may implement data partitioning across a cluster of storage services. Which variant of such a choice of data services is used for a specific environment then becomes a matter of the deployment-time wiring of the system.

Data services are the resource access layer of the “onion” model on the next higher level of abstraction. The public interface consists of presentation services (which render external data presentations of all sorts, not only human interaction), the internal implementation is made up of business services that implement the core of the application and the resource access are said data services. On the next higher level of abstraction, presentation services may very well play the role of data services to other services. And so it all repeats.

Now … Ralf says he thinks that the abstraction model works wonderfully for pulling chunks of data from underlying layers, but he’s very concerned about streaming data and large data sets – and uses reporting as a concrete example.

Now, I consider data consolidation (which reporting is) an inherent functionality of the data store technology and hence I am not at all agreeing with any part of the “read millions of records into Crystal Reports” story. A reporting rendering tool shall get pre-consolidated, pre-calculated data and turn that into a funky document; it should not consolidate data. Also, Ralf’s proposed delivery of data to a reporting engine in chunks doesn’t avoid that you’ll likely end up having to co-locate all received data into memory or onto disk to actually run the consolidation and reporting job --- in which case you end up where you started. But that’s not the point here.

Ralf says that for very large amounts of data or data streams, pull must change to push and the resource access layer must spoon-feed the business implementation (reporting service in his case) chunks of data at a time. Yes! Right on!

What Ralf leaves a bit in the fog is really how the reporting engine learns of a new reporting job, where and how results of the engine are being delivered and how he plans to deal with concurrency. Unfortunately, Ralf doesn’t mention context and how it is established and also doesn’t loop his solution back to the layering model he found. Also, the reporting service he’s describing doesn’t seem very flexible as it cannot perform autonomous data acquisition, but is absolutely dependent on being fed by the app – which might create an undesirable tightly coupled dependency between the feeder and a concrete report target.

The reporting service shall be autonomous and must be able to do its own data acquisition. It must be able to “pull” in the sense that it must be able to proactively initiate requests to data providers. At the same time, Ralf is right that the request result should be pushed to the reporting service, especially if the result set is very large.

Is that a contradiction? Does that require a different architecture? I’d say that we can’t allow very large data sets to break the fundamental layering model or that we should have to rethink the overall architectural structure in their presence. What’s needed is simply a message/call exchange pattern between the reporting service and the underlying data service that is not request/response, but duplex and which allows the callee to incrementally bubble up results to the caller. Duplex is the service-oriented equivalent of a callback interface with the difference that it’s not based on a (marshaled) interface pointer but rather on a more abstract context or correlation identifier (which might or might not be a session cookie). The requestor invokes the data service and provides a “reply-to” endpoint reference referencing itself (wsa:ReplyTo/wsa:Address), containing a correlation cookie identifying the originator context (wsa:ReplyTo/wsa:ReferenceProperties), and identifying an implemented port-type (wsa:ReplyTo/wsa:PortType) for which the data service knows how to feed back results. The port-type definition is essential, because the data service might know quite a few different port-types it can feed data to – in the given case it might be a port-type defined and exposed by the reporting service. [WS-Addressing is Total Goodness™]. What’s noteworthy regarding the mapping of duplex communication to the presented layering model is that the request originates from within the resource access layer, but the results for the requests are always delivered at the public interface.

The second fundamental difference to callbacks is that the request and all replies are typically delivered as one-way messages and hence doesn’t block any resources (threads) on the respective caller’s end.

For chunked data delivery, the callee makes repeated calls/sends messages to the “reply-to” destination and sends an appropriate termination message or makes a termination call when the request has been fulfilled. For streaming data delivery, the callee opens a streaming channel to the “reply-to” destination (something like a plain socket, TCP/DIME or – in the future -- Indigo’s TCP streaming transport) and just pumps a very long, continuous message.

Bottom line: Sometimes pull is good, sometimes push is good and duplex fits it all back into a consistent model.

Saturday, May 15, 2004 1:48:32 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [0] - Trackback
Architecture

People often ask me what I’ve done before Bart, Achim and I started newtelligence together with Jörg. So where do we come from? Typically, we have given somewhat “foggy” answers to those kinds of questions, but Achim and I talked about that yesterday and we’ve started to ask ourselves “why we do that”?

In fact, Achim, Bart and I had been working together for a long time before we started newtelligence. We used to work for a banking software company called ABIT Software GmbH, which then merged with two other sibling companies by the same owners to form today’s ABIT AG. We’ve only reluctantly communicated that fact publicly, because the formation of our company didn’t really get much applause from our former employer – quite the contrary was true and hence we’ve been quite cautious.

For us it was always quite frustrating that ABIT was sitting on heaps on very cool technology that my colleagues and I developed over the years (including patented things) and never chose to capitalize on the technology itself. Here are some randomly selected milestones:

We had our own SOAP 0.9 stack running in 1999, which was part of a framework that had a working and fully transparent object-relational mapping system based on COM along with an abstract, XML-based UI description language (people call those things XUL or XAML nowadays).

In 1998 we forced (with some help of our customer’s wallet) IBM into a 6 months avalanche of weekly patches for the database engine and client software that turned SQL/400 (the SQL processor for DB/400 on AS/400) from a not-quite-to-perfect product into a rather acceptable SQL database.

In 1996 we fixed well over 500 bugs and added tons of features to Borland’s OWL for OS/2 with which we must have had the pretty unique framework setup where cross-platform Windows 3.x, Windows NT and OS/2 development actually functioned on top of that shared class library.

In 1994 we already had what could be considered as the precursor to a service-oriented architecture in with collaborating, (mostly) autonomous services. The framework underlying that architecture had an ODBC C++ class library well over 6 months before Microsoft came out with their first MFC wrapper for it, had an MVC model based centered around the idea of “value-holders” that we borrowed from SmallTalk and which spoke, amongst other things, a text-validation protocol that allowed us to have a single “TextBox” control could be bound against arbitrary value holders that would handle all the text-input syntax rules as per their data type (or subtype). All of this was fully based on the nascent COM model which was then still buried in three documentation pages of OLE 2.0. I didn’t care much about linking and embedding (although I wrote my own in-place editing client from scratch), but I cared a lot about IUnknown as soon as I got my hands on it in late 1993. And all applications (and services) built on that framework supported thorough OLE Automation with Visual Basic 3.0 to a degree that you could fill out any form and press any button programmatically – a functionality that was vital for the application’s workflow engine.

And of course, during all that time, we were actively involved in project and product development for huge financial applications with literally millions of lines of production code.

None of the technology work (except the final products) was ever shared or available to anyone for licensing.  We were at a solutions company that supported great visions internally, but never figured out that the technology would be a value by itself.

newtelligence AG exists because of that pain. Years back, we’ve already designed and implemented variations of many of the technologies that are now state of the art or (in the case of XAML) not even shipping yet. At the same time, we continue to develop our vision and that’s how we can stay on top of things. So it’s really not that we’re not learning like crazy and go through constant paradigm shifts – we’re lucky that we can accumulate knowledge on top of the vast experience that we have and adjust and modernize our thinking. However, what’s different now is that we can share the essence of what we figure out with the world. That’s a fantastic thing if you’ve spent most of your professional life “hidden and locked away” and were unable to share things with peers.

So every time you’ll see a “Flashback” title here on my blog, I’ll dig into my recollection and try to remember some of the architectural thinking we had back in those times. We’ve made some horrible mistakes and had some exuberant and not necessarily wise ideas (such as the belief that persistent object-identity and object-relational mapping are good things); but we also had quite a few really bright innovative ideas. The things that really bring you forward are the grand successes and the most devastating defeats. We’ve got plenty of those under our belt and even though some of these insights date back 10 years, they are surprisingly current and the “lessons learned” very much apply to the current technology stacks and architectural patterns.

So – if you’ve ever thought that we’re “all theory” authors and “sample app” developers – nothing is further away from the truth. Also: Although I fill an “architecture consultant” role more than anything else now, I probably write more code on a monthly basis than some full-time application developers – what’s finally surfacing in talks and workshops is usually just the tip of that iceberg and often very much simplified to explain the essence of what we find.

Saturday, May 15, 2004 6:40:12 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [2] - Trackback
Architecture | Flashbacks
 Friday, May 14, 2004

At the SDC conference in Arnhem (NL), Chris Anderson entered the following task into his Pocket Outlook: "Turn Clemens from a server developer into a smart client developer within the next 15 months." We'll see how that goes. Chris: For that to happen, you'll have to give me something that I can seriously fall in love with.

Friday, May 14, 2004 6:42:59 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [2] - Trackback
Avalon

It's interesting that I get far more than 10000 unique daily unique page views on the site along with a similar number of aggregator views daily without even posting much. At least that was true for the last couple of months. Today is my "get back to blogging day". At the same time, the number of tracked direct referrals that I get when someone navigates to an entry via a link on another site is relatively low and accounts for less than 3% of the daily traffic.

I am sure I am the last to realize this phenomenon, but: I conclude that I must have a "root blog". That means that the overwhelming majority of readers don't find me via links; instead, I am on their daily reading list or in their RSS aggregator. I don't really get many on-topic inbound links, but I give links. Other great examples for "higher order" root blogs are those of Robert Scoble and Don Box, because once they link to me, the number of direct referrals rises significantly.

When I started blogging (when blogosphere was much smaller), I had a "leaf blog" that wouldn't get many reads except through other people's links. It's interesting to observe how those things change.

Friday, May 14, 2004 5:33:55 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [0] - Trackback
Blog

The two biggest conferences in Microsoft space (save PDC) are coming up and I am already looking forward to be in San Diego in two weeks and in Amsterdam four weeks later. Those two events are always very special because they are big, because they are really well organized and because I get to meet and party with very many good friends who I see regularly at some place somewhere on earth, but only once a year we’re all together.

As much as I value the technical education aspect of events like that (yes, I do attend sessions, too), the primary reason for me to go to TechEd is too meet friends and make new friends. And the “networking” on the professional level that goes on at TechEd is very important as well: There’s nothing in this industry as valuable as learning from other people.

What I am also looking forward to is some time off when TechEd Amsterdam is over. At that time, I will have been to 25 countries since January of this year (several of them twice or even more often) and I would have to do some serious analysis of my calendar to assess how many events it were. My friend Lester Madden made the best comment on that sort of traveling lifestyle some time back in February. We boarded one of those planes together and he threw himself into the seat grinning sarcastically “Ah! Home, sweet home”.

So with the somewhat slow summer time ahead, I’d like to say “Thank you for all the beer”, because Microsoft (most, but not all events were hosted by them) certainly knows how to throw great parties. So here are my Feierabend Awards” for the first half of 2004 and before the “big two” events:

 

My “Winter/Spring 2004 Best Conference Party Award” goes to: The Beach Party at Microsoft TechEd Israel (Elat, Israel). Close runners up are the Arabian Night at the North Africa Developer Conference 2004 (Casablanca, Morocco) and the “Wild West” party at the NT Konferenca 2004 in Portoroz, Slovenija.  

My “Winter/Spring 2004 Best Organized-After-Work-Activity Award” goes – hands down – to Microsoft Finland and their Architecture Bootcamp in Ruka, where we did a 25km snow mobile ride in beautiful northern Finland and afterwards had a very Finnish “now let’s get naked with all the customers and go to Sauna” experience. Runner up is a great evening hosted by Microsoft Turkey at Galata Tower in Istanbul. The restaurant up there is an absolute tourist trap, but we had a fun night and the views from up there can’t be beat.

My “Winter/Spring 2004 Best Beer Award” must of course go to Dublin. Not much (except our local beer in and around Düsseldorf) beats a fresh Guinness. Along with that goes the sub-award for  “most inappropriate workplace discussion” about how cleavage (Def. 6) is most effectively used in business.

The “Winter/Spring 2004 Best Restaurant Award” goes to the Vilamoura Restaurant (Portuguese) at the Intercontinental Hotel in Sandton/Johannesburg for absolutely awesome shellfish. Runner up is another Portuguese restaurant: the Doca Peixe in Lisbon/Portugal. The special Best Homefood Award goes to Malek’s mother. The “Winter/Spring 2004 Best Nightclub Award” goes to the Amstrong (sic!) Jazz Club (which it really isn’t) in Casablanca, Morocco.

The “Winter/Spring 2004 Gorgeous Event Hostesses Recruiting Award” (sorry, but while that’s not strictly “after work” that’s a category that I can’t leave out) has to be evenly split between four winners: Morocco’s North Africa Developer Conference 2004 (just ask Mr. Forte),  Slovenija’s NT Konferenca 2004 (reliable winner each year), the Longhorn Developer Preview event in Budapest/Hungary and the MS EMEA Architect Forum Event in Milan, Italy. Israel already won the best party event and that should speak pretty much for itself. Therefore they’re runner up in this category.

The “Winter/Spring 2004 Best Travel Buddy Award” goes to Arvindra Sehmi for the EMEA Architect Tour, and Lester Madden, Nigel Watling, Hans Verbeeck, and David Chappell for the Longhorn Developer Preview Tour.  

Finally, the “Winter/Spring 2004 Best Host Award” goes to my great friend Malek Kemmou from Morocco, whose house became “Speaker’s HQ” before, during and after the NDC conference and who took us all around the country to experience Morocco – and refused to let any of us pay for anything.

Friday, May 14, 2004 4:11:53 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [4] - Trackback
Talks | TechEd Europe | TechEd US

I talked about transactions on several events in the last few weeks and the sample that I use to illustrate that transactions are more than just a database technology is the little tile puzzle that I wrote a while back. For those interested who can't find it, here's the link again. The WorkSet class that is included in the puzzle is a fully functional, lightweight, in-memory 2 phase-commit transaction manager that's free for you to use.

Friday, May 14, 2004 2:03:33 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [0] - Trackback
Architecture | Technology

Sometimes you’re trying to fix a problem for ages (months in our case) and while the solution is really simple, you only find it by complete accident and while looking for something completely different.

(And yes, I do think that we need to finally get a network admin to take care of those things) 

For several months, our Exchange server “randomly” denied communicating with several of our partner’s mail servers. There were several of our partners who were not able to send us email and their emails would always bounce, although we could communicate wonderfully with the rest of the world. What was stunning is that there wasn’t any apparent commonality between the denied senders and the problem came and went and sometimes it would work and sometimes it wouldn’t.

First we thought that something was broken about our DNS entries and specifically about our MX record and how it was mapped to the actual server host record. So we reconfigured that – to no avail. Then we thought it’d be some problem with the SMTP filters in the firewall and spent time analyzing that. When that didn’t go anywhere, we suspected something was fishy about the network routing – it wasn’t any of that either. I literally spent hours looking at network traces trying to figure out what the problem was – nothing.

Yesterday, while looking for something totally different, I found the issue. Some time ago, during one of the email worm floods, we put in an explicit “deny” access control entry into the SMTP service for one Korean and one Japanese SMTP server that were sending us hundreds of messages per minute. The error that we made was to deny access by the server DNS name and not by their concrete IP address.

What happened was that because of this setting our SMTP server would turn around and try to resolve every sender’s IP address back to a host name to perform that check and that’s independent of the “Perform reverse DNS lookup on incoming messages” setting in the “Delivery”/“Advanced Delivery” dialog. It would then simply deny access to all those servers for which it could not find a host name by reverse lookup. I removed those two entries and now it all works again.

Of course, the error isn’t really ours, but the problem was. What’s broken is that the whole reverse DNS lookup story is something that seems (is) really hard to set up and that quite a few mail servers simply don’t reversely resolve into any host name. DNS sucks.

Friday, May 14, 2004 1:51:10 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [0] - Trackback
Technology

Welcome back ;-)

On one of those flights last week I read a short article about Enterprise Services in a developer magazine (name withheld to protect the innocent). The “teaser” introduction of the article said: “Enterprise Services serviced components are scalable, because they are stateless.” That statement is of course an echo of the same claim found in many other articles about the topic and also in many write-ups about Web services. So, is it true? Unfortunately, it’s not.

public class AmIStateless
{
       public int MyMethod()
       {
              // do some work
              return 0;
       }
}

 “Stateless” in the sense that it is being used in that article and many others describes the static structure of a class. Unfortunately that does not help us much to figure out how well instances of that class help us to scale by limiting the amount of server resources they consume. More precisely: If you look at a component and find that it doesn’t have any fields to hold data across calls (see the code snippet) and does furthermore not hold any data across calls in some secondary store (such as a “session object”), the component can be thought of as being stateless with regards to its callers, but how is the relationship with components and services that are called from it?

But before I continue: Why do we say that “stateless” scales well?

A component (or service) that does not hold any state across invocations has many benefits with regards to scalability. First, it lends itself well to load balancing. If you run the same component/service on a cluster of several machines and the client needs to make several calls, the client can walk up to any of the cluster machines in any order. That way, you can add any number of machines to the cluster and scale linearly. Second, components that don’t hold state across invocations can be discarded by the server at will or can be pooled and reused for any other client. This saves activation (construction) cost if you choose to pool and limits the amount of resources (memory, etc.) that instances consume on the server-end if you choose to discard components after each call. Pooling saves CPU cycles. Discarding saves memory and other resources. Both choices allow the server to serve more clients.

However, looking at the “edge” of a service isn’t enough and that’s where the problem lies.

The AmIStateless service that I am illustrating here does not stand alone. And even though it doesn’t keep any instance state in fields as you can see from the code snippet, it is absolutely not stateless. In fact, it may be a horrible resource hog. When the client makes a call to a method of the service (or otherwise sends a message to it), the service does its work by employing the components X and Y. Y in turn delegates work to an external service named ILiveElsewhere. All of a sudden, the oh-so-stateless AmIStateless service might turn into a significant resource consumer and limit scalability.

First observation: While no state is held in fields, the service does hold state on the stack while it runs. All local variables that are kept in on the call stack in the invoked service method, in X and in Y are consuming resources and depending on what you do that may not be little. Also, that memory will remain consumed until the next garbage collector run.

Second observation: If any of the secondary components takes a long time for processing (especially ILiveElsewhere), the service consumes and blocks a thread for a long time. Depending on how you invoke ILiveElsewhere you might indeed consume more than just the thread you run on.

Third observation:  If AmIStateless is the root of a transaction, you consume significant resources (locks) in all backend resource managers until the transaction completes – which may be much later than when the call returns. If you happen to run into an unfortunate situation, the transaction may take a significant time (minutes) to resolve.

Conclusion:  Since the whole purpose of what we usually do is data processing and we need to pass that data on between components, nothing is ever stateless while it runs. “Stateless” is a purely static view on code and only describes the immediate relationship between one provider and one consumer with regards to how much information is kept across calls. “Stateless” says nothing about what happens during a call.

Consequence: The scalability recipe isn’t to try achieving static statelessness by avoiding holding state across calls. Using this as a pattern certainly helps the naïve, but the actual goal is rather to keep sessions (interaction sequence duration) as short as possible and therefore limit the resource consumption of a single activity. A component that holds state across calls but for which the call sequence takes only a very short time or which does not block a lot of resources during the sequence may turn out to aid scalability much more than a component that seems “stateless” when you look at it, but which takes a long time for processing or consumes a lot of resources while processing the call. One way to get there is to avoid accumulating state on call stacks. How? Stay tuned.

Friday, May 14, 2004 1:10:02 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [5] - Trackback
Architecture
 Monday, May 03, 2004

I am slowly getting out of a very, very long period of "working too much". In the last 3 1/2 weeks I worked pretty much for 18 hours every day in order to get a fairly large service oriented application done (sharing the workload with my newtelligence partner Achim Oellers). The stats: 13 services, about 20 portTypes, 1.6 MB of C# code, 10 SQL Server databases (autonomy!), countless stored procedures. We have duplex (one-way with reply path), simplex (one-way) and request/response communication paths, use ObjectPooling, Just In Time Activation, Role Based Security, Compensating Resource Managers, Process Initialization, Automatic Transactions, Service Domains, Run-As-Service, and Loosely Coupled Events from Enterprise Services, we use several features from ASP.NET Web Services, we use quite a bit of the Web Service Enhancements Tools, have full instrumentation with Eventlog support an Performance Counters, have deployment tools that create domain accounts, elevate their privileges and configure all the security settings to run a service in "locked down" mode, and use SQL Server Replication. The core services were supposed to ship yesterday and we made that date.

Now I need to work on the backlog. I am late on delivering some PowerPoint decks. I have a 12 hour travel day today. That means writing PPTs on the plane.

Monday, May 03, 2004 11:33:35 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [2] - Trackback
Other Stuff

The EMEA Architect Tour 2004 Videos from Finland are online and certainly one of the rare chances to see me speaking in a proper suit. And we speak about FABRIQ...

Monday, May 03, 2004 2:20:07 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [1] - Trackback
Architecture
 Friday, April 23, 2004

I am writing a very, very, very big application at the moment and I am totally swamped in a 24/7 coding frenzy that’s going to continue for the next week or so, but here’s one little bit to think about and for which I came up with a solution. It’s actually a pretty scary problem.

Let’s say you have a transactional serviced component (or make that a transactional EJB) and you call an HTTP web service from it that forwards any information to another service. What happens if the transaction fails for any reason? You’ve just produced a phantom record. The web service on the other end should never have seen that information. In fact, that information doesn’t exist from the viewpoint of your rolled back local transaction. And of course, as of yet, there is no infrastructure in place that gives you interoperable transaction flow. And if that were the case, the other web service may not support it. What should you do? Panic?

There is help right in the platform (Enterprise Services that is). Your best friend for that sort of circumstance is System.EnterpriseServices.CompensatingResourceManager.

The use case here is to call another service to allocate some items from an inventory service. The call is strictly asynchronous and I the remote service will eventually turn around and call an action on my service (they have a “duplex” conversation using asynchronous calls going back and forth). Instead of calling the service form within my transactional method, I am deferring the call until the transaction is being resolved. Only when DTC is sure that the local transaction will go through, the web service call will be made. There is no way to guarantee that the remote call succeeds, but it does at least eliminate the very horrible side effects on overall system consistency caused by phantom calls. It is in fact quite impossible to implement “Prepare” correctly here, since the remote service may fail processing the (one-way) call on a different thread and hence I might never get a SOAP fault indicating failure. Because that’s so and because I really don’t know what the other service does, I am not writing any specific recovery code in the “Commit” phase. Instead, my local state for the conversation indicates the current progress of the interaction between the two services and logs an expiration time. Once that expiration time has passed without a response from the remote service, a watchdog will pick up the state record, create a new message for the remote service and replay the call.

For synchronous call scenarios, you could implement (not shown here) a two-step call sequence to the remote service, which the remote service needs to support, of course. In “Prepare” (or in the “normal code”) you would pass the data to the remote service and hold a session state cookie. If that call succeeds, you vote “true”. In “Commit” you would issue a call to commit that data on the remote service for this session, on “Abort” (remember that the transaction may fail for any reason outside the scope of the web service call), you will call the remote service to cancel the action and discard the data of the session. What if the network connection fails between the “Prepare” phase call and the “Commit” phase call? That’s the tricky bit. You could log the call data and retry the “Commit” call at a later time or keep retrying for a while in the “Commit” phase (which will cause the transaction to hang). There’s no really good solution for that case, unless you have transaction flow. In any event, the remote service will have to default to an “Abort” once the session times out, which is easy to do if the data is kept in a volatile session store over there. It just “forgets” it.

However, all of this is much, much better than making naïve, simple web service calls that fan out intermediate data from within transactions. Fight the phantoms.

At the call location, write the call data to the CRM transaction log using the Clerk:

AllocatedItemsMessage aim = new AllocatedItemsMessage();
aim.allocatedAllocation = <<< copy that data from elsewhere>>>
Clerk clerk = new Clerk(typeof(SiteInventoryConfirmAllocationRM),"SiteInventoryConfirmAllocationRM",CompensatorOptions.AllPhases);
SiteInventoryConfirmAllocationRM.ConfirmAllocationLogRecord rec = new RhineBooks.ClusterInventoryService.SiteInventoryConfirmAllocationRM.ConfirmAllocationLogRecord();
rec.allocatedItemsMessage = aim;
clerk.WriteLogRecord( rec.XmlSerialize() );
clerk.ForceLog();

Write a compensator that picks up the call data from the log and forwards it to the remote service. In the “Prepare” phase, the minimum work that can be done is to check whether the proxy can be constructed. You could also make sure that the call URL is valid, the server name resolves and you could even try a GET on the service’s documentation page or call a “Ping” method the remote service may provide. That all serves to verify as good as you can that the “Commit” call has a good chance of succeeding:


using System.EnterpriseServices.CompensatingResourceManager;
using …

 

///


/// This class is a CRM compensator that will invoke the allocation confirmation
/// activity on the site inventory service if, and only if, the local transaction
/// enlisting it is succeeding. Using the technique is a workaround for the lack
/// of transactional I/O with HTTP web services. While the compensator cannot make
/// sure that the call will succeed, it can at least guarantee that we do not produce
/// phantom calls to external services.
///

public class SiteInventoryConfirmAllocationRM : Compensator
{
  private bool vote = true;

  [Serializable]
  public class ConfirmAllocationLogRecord
  {
    public SiteInventoryInquiries.AllocatedItemsMessage allocatedItemsMessage;           

    internal string XmlSerialize()
    {
      StringWriter sw = new StringWriter();
      XmlSerializer xs = new XmlSerializer(typeof(ConfirmAllocationLogRecord));
      xs.Serialize(sw,this);
      sw.Flush();
      return sw.ToString();
    }

    internal static ConfirmAllocationLogRecord XmlDeserialize(string s)
    {
      StringReader sr = new StringReader(s);
      XmlSerializer xs = new XmlSerializer(typeof(ConfirmAllocationLogRecord));
      return xs.Deserialize(sr) as ConfirmAllocationLogRecord;
    }
  }

  public override bool PrepareRecord(LogRecord rec)
  {
    try
    {
      SiteInventoryInquiriesWse sii;
      ConfirmAllocationLogRecord calr  = ConfirmAllocationLogRecord.XmlDeserialize((string)rec.Record);
      sii = InventoryInquiriesInternal.GetSiteInventoryInquiries( calr.allocatedItemsMessage.allocatedAllocation.warehouseName );
      vote = sii != null;    
      return false;
    }
    catch( Exception ex )
    {
      ExceptionManager.Publish( ex );
      vote = false;
      return true;
    }
  }

  public override bool EndPrepare()
  {
    return vote;
  }


  public override bool CommitRecord(LogRecord rec)
  {
    SiteInventoryInquiriesWse sii;
    ConfirmAllocationLogRecord calr  = ConfirmAllocationLogRecord.XmlDeserialize((string)rec.Record);
    sii = InventoryInquiriesInternal.GetSiteInventoryInquiries( calr.allocatedItemsMessage.allocatedAllocation.warehouseName );
 
    try
    {
      sii.ConfirmAllocation( calr.allocatedItemsMessage );
    }
    catch( Exception ex )
    {
      ExceptionManager.Publish( ex );
    }
    return true;
  }
}

 

 

Friday, April 23, 2004 1:27:54 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [2] - Trackback
Architecture | Enterprise Services | Web Services
 Monday, April 05, 2004

Here's a life sign. I am buried under lots of work of which pretty much all will see the light of day at TechEd. We're getting close to having a first public version of the FABRIQ project with Microsoft EMEA and we're very busy here at newtelligence writing a huge SOA sample application using and combining all the good things of ASP.NET Web Services, WSE 2.0, Enterprise Services, MSMQ, SQL, and Remoting. The result is quite likely going to play some role at TechEd US and other TechEds this year. Between then and my last technical blog positing I've written several thousand lines of code again and there are several thousand more to follow. Hence the silence. Once those two projects are done or close to being done, expect a flood of explanations.

Monday, April 05, 2004 8:25:27 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [1] - Trackback
Architecture | newtelligence