# Thursday, March 31, 2005

Getting a better handle on CSS

I have used CSS for years now, but I never knew about this. Sure, it's sort of implied by the documentation, but I have never seen anyone come out and say "hey, this is how you organize it". So here is what I learned this weekend.

1. You can define specific hierarchies of nested tags to apply a style to. For example "DIV.outerdiv DIV.innerdiv {color:red;}" will set the font color of a div with a class attribute of "innerdiv" to red, but only if it is contained within another div with a class of "outerdiv". Thats super handy for complex layouts.

2. You can define a style more than once. The styles are then merged at runtime in the order which they are encountered (last writer of a style property wins). This means that you can seperate layout CSS from colors CSS and from text, or whatever. You can have a "colors.css" file that only contains color definitions, making it MUCH easier to update later. Super SUPER handy!

3. You can assign styles based on element IDs, not just Classes. Everyone using CSS knows you can use a style selector of ".somestyle" to apply a style to all elements with a class= "somestyle"... but most don't know that you can use a selector of "#element_id" to apply the style only to the element with id= "element_id". This is SUPERB for layout style properties. Generally, the colors/text/etc styles are used on many elements in a page, which is easily done using class="somestyle". But id values are supposed to be unique in a page, and they are all at different positions, with different layout rules (even though they share the same color/font/etc). Assigning layout style properties based on element id and other properties based on class allows you to have your cake and eat it too!

These are very simple concepts to pick up, but they have done wonders for my web design/layout abilities.

And I guess I should also give the disclaimer that I didn't know these things until I customized my dasBlog theme, and saw how it's CSS was designed. Very impressive work there.

 

Thursday, March 31, 2005 12:32:25 AM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Sunday, March 27, 2005

Thanks Michael!

Michael Earls is the man.

This afternoon I asked him a simple question: How do I get Master Pages type functionality without upgrading to Fx2.0 beta?

I am building a small administration application for a client, and I am tired of using "copy & paste templates" or "UserControl chunks" to build a reusable/consistent site design. I know he has done this type of thing a few times in the past, which is why I asked him.

He gave me some very concise and (most importantly) correct insights into the ASP.NET rendering engine, and where to place hooks to do what I wanted. He gave me just enough information to get it working, without giving me too much. The essentials: override the AddParsedSubobjects() method in a server control to re-parent the child page's contents to a placeholder.

While there are a few tricks and snags to overcome, that is essentially exactly what I had to do. I created a new server control, changed it to inherit from Web.UI.Page, instantiated LiteralControls for my static content, as well as a number of server controls that I needed in my base class (for example, the Coalesys PanelBar for navigation) in the new class's constructor. I did some footwork in the AddParsedSubobjects() method to relocate the child page's Form contents into a new HtmlForm that I maintain within my new class. I also had to copy the properties of the child form (enctype, name, method, etc)... so that should the child page developer decide to change any of it, their changes would carry over.

I did do a few things my own way. One of the ideas Michael gave me was to use regular expressions to construct the master page's LiteralControls (he used string constants for each Literal, which I am sure was probably a bit tedious when a change needed to be made). So instead of that approach, I added some well-known comment tags to my master page's source to demarcate the literal sections. I then used my NVEdit tool to store the entire master page as a single template resource. A simple regular expression was used to extract out all the literal sections (this was not hard at all since I used well-known comments to mark the sections). As a result, I can modify the master page layout without too much trouble (yes, it still requires a recompile). Perhaps a future exercise could be to make it fully dynamic, with the ability to use multiple master layouts on the fly. Hmm.

Anyways, the other features I added was a simple way to link external CSS (a new AddStylesheetReference(string url) method), as well as the obligatory Title property that alters the header tag appropriately. A side bonus is that the AddParsedSubobjects code is smart enough to read in existing Title and linked stylesheets from the child pages, and automatically set them with no developer code required. I will likely also extend this mechanism to support themes via CSS at a later time too. That would work nicely along with dynamic master page sourcing...

So I am now very happy. I effectively have master pages development in VS 2003. I don't have the ability to see the master while editing a child page in the designer, but I don't really care about that little bit. I can still link my child page to the site's CSS and get the right "look and feel". This is great.

Thanks again Michael!

 

Sunday, March 27, 2005 11:56:16 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [1] | 

Green Screens

As much as I like to gripe about AS/400's and mainframes, I gotta hand it to them. There are just some business-level tasks that a dumbed-down interface such as a 3270 or 5250 terminal provides.

It's really a grounding lesson in worker efficiency to watch a factory line worker scanning barcodes into a terminal every couple seconds, or punching the keys to enter an order - faster than you can even read the screen contents. I have never seen a web application capable of approaching that kind of worker efficiency.

Maybe this whole "rich design" craze will fade away... much like the idea of always-connected "client/server" database systems. Sometimes while I am busy building a "swiss army knife" website (is there *any* other kind that management ever asks for?), I just sit back and wonder what people will think of us in 20 years.

Will they think "man, those web applications are super-efficient"?

Or will they think "what a hunk of manure"?

My money is on the latter. There is a lot to be said for thinking through your actual processes and requirements before sitting down and banging out code. People need to start thinking about what they really need and why before jumping into development.

And choosing "web" applications over other forms as a default is crazy. The design should start simple (dumb terminal level), and then graduate to complex (windows forms), and finally to distributed (web). These are all increasing flexibility/coolness, but also greatly increasing development effort. Interestingly, they are all decreasingly efficient in terms of worker productivity when applied to real-world business processes.

Web apps belong on 1) the internet, and 2) intranet collaboration. 99% of the time they have no place in back-end businesses. It boggles me as to why people keep trying to fit this square peg in a hole it was not intended to fill.

 

Sunday, March 27, 2005 9:37:13 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [1] | 

# Thursday, March 24, 2005

Brief outage

You may or may not have noticed, my server was offline for most of today. My ISP decided to reassign my IP address, and I was left to figure it out on my own.

No big deal though.

I use DynDNS.org to manage my DNS addressing, so it took all of about 2 minutes to make the change, and for the change to take effect. I also use Inbox Genius to intercept my incoming email. Inbox Genius does two things for me - first, they filter out 95% of all spam before it ever hits my network. Second, they store-and-forward all inbound email, which means that when my server goes offline (like today), it just queues up the messages until my server is back online. So I didn't even lose any messages.

Cool stuff.

Thursday, March 24, 2005 11:58:53 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

IBM, why must thou suck so much?

I griped about IBM's DB2 drivers once already, but after uncovering this little gem I felt it warranted more complaining.

I discovered that the OleDB drivers for DB2/400 cannot handle the tab character.

With nearly every editor on the face of the planet supporting tabs ("\t"), and most SQL editors even reformatting with them for readability, IBM can't seem to make their driver handle them. It doesn't raise an error message indicating "hey, I dont do tabs". Nope, that would be too developer-friendly. Instead, when it recieves a tab character, it just bombs the connection. The pooled connection. And so your application is screwed until that pooled connection times out.

And this is not some "freebie" driver. This is the one that ships with iSeries Access... which you need to *own* an as/400 to obtain (it was a pain in the ass getting it as an independant developer without an as/400 here in my basement...). This bug has existed in at least the most recent 3 driver releases, according to my testing.

I can't imagine that I would be the only person ever afflicted by this bug - yet the IBM support information pretends their drivers are perfect. I hope that at least Google indexes this post and that it might help some other unfortunate soul later on.

IBM truly does suck.

Thursday, March 24, 2005 12:23:25 AM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Monday, March 21, 2005

How many times?

This weekend I got to write a data access layer. Again.

I think this is around the 10th time I have had to reinvent this wheel. Sure, every time I do it the result gets slightly better (more features, more robust, better performance, etc). But at this point I am splitting hairs. Most of the heavy lifting is done with code generation techniques, I just tweak some of the template code to add the features needed for a given client/project.... but it's still a pain in the ass.

This time around, I wrote the access layer templates in VB (normally would use c#, but VB was a requirement this time) with async query execution baked-in. But aside from that, it's all the SOS.

I just wish some kind of standard would get defined for database schemas. I am tired of every DBA having their own naming conventions and data model idiosyncrasies. For heaven's sake, you prefer INTs over GUIDs for PK's (or vice versa), yes, you want an extra "@UserID" parameter passed to every DML procedure. Yes, you follow some naming convention that makes sense to you. Guess what, ALL DBA's do this. But because there is no consistency from one database or DBA to the next, we have to reinvent this silly DAL for every project. And it costs us precious time that we could be spending on actual business code.

Even if we had to resort to something like ISO standardization for schema definitions, would it really be so bad when compared to this insanity we have today?

We have Patterns and Practices defined for nearly every other aspect of software system design. Why not have some for database design? Simple normalization categories are not good enough - they are too vauge.

Data Access code should be a commodity - but because of unpredictable schemas it isn't. Why do we allow such an intrinsic component of software to NOT be a commodity? It's far too important of a cornerstone for us to just re-invent every time!

 

Monday, March 21, 2005 4:38:43 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Sunday, March 06, 2005

Enterprise Architecture Focus Group

Natty Gur is hoping to start up an online focus group (fancy words for "mailing list" I think) for architecture discussions.

I for one support his idea, as I get the impression that a local architecture group just wouldn't work out due to a range of unfortunate reasons.

While developers and businessmen have long had "support groups" to lean on for knowledge, advice, and networking, it seems that architects have mostly been reclusive and seldom interact with others in their industry. And since architecture is all about having the "big picture" and keeping your options open, I can't help but see a community (even if it's online-only) as being a big benefit.

Sunday, March 06, 2005 4:33:25 PM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [1] | 

SOA Misunderstanding and Misuse

Part of my new job is making sure our applications meet scalability, reliability, and performance requirements once we deploy to "the wild". Damn near anything will work in a development or even QA environment (assuming you are like 95% of all shops and don't bother doing load analysis until a problem comes up). But just because something works on a development machine is no guarantee it will continue to work once it is placed under pressure. "But it works on my machine" has ended many a developer's career and/or project's budget.

Anyways, I am rambling, so on to the point of this post...

I am truly appalled at this "webservice.htc" IE behavior component. True enough, I can visualize the thought process at Microsoft that eventually arrived at creating this thing. But I do not agree with it at all.

First, what it does:

If you are unfamiliar with webservice.htc, essentially it is a chunk of javascript code that wraps calls to web services (via the XmlHttp IE COM component). It knows all about SOAP and WSDL. In fact, in order to use a SOAP web service, you simply point it to a WSDL document (it expects something along the lines of "BlahBlah.asmx?WSDL", in other words - always late-bound service discovery). It then allows you to interact with the web service using the SOAP operations ("methods"), not too unlike the "developer experience" of using a web service proxy class in managed .NET code.

It is very easy to use in fact.

All you need to do is attach the behavior to any DHTML tag... for example a DIV like this:

<div id="MyService" style="display:none;behavior:url(webservice.htc);" />

Then in your page somewhere (anywhere, but most often done in the onLoad event of the body tag), you load the WSDL:

<body onload="MyService.useService('BlahBlah.asmx?WSDL', 'svcBlahBlah');">....</body>

Then calling the operations ("methods" for OO-heads) is as simple as this code which can be used anywheres in your page javascript:

<script language=javascript>
var param = "some parameter...";
MyService.svcBlahBlah.callService(DisplayResult, "SomeOperationOnBlahBlah", param);
function DisplayResult(result)
{
   alert("Result: " + result.value);
}
</script>

Now that I have explained how it works in a nutshell, let me explain why I think its a really bad idea...

Second, my beef with it:

Each time useService() is called, the WSDL is downloaded to the browser. Chances are, a complete WSDL is massive overkill for the data a web application is wanting to pull via OOB (out of band). In the web service I am looking at right now, there are four operations supported. Each returns a simple string, and accepts one to three string parameters. However, the WSDL is over 8k! Since each page transition in the browser tosses all previously loaded script, this "wsdl setup" must happen at least once every time a page is loaded that needs to make web service calls.

On top of the WSDL cost, there is the cost of the HTC code itself. The webservice.htc file is 50K by itself! And since it is just linked javascript, it too must be reloaded every time a page transition or postback occurs.

So far, those costs are fairly hidden from view of the web developer. Not many will think adding the behavior style and calling a single method just once on a page will incur from 50k upwards to 100k or more bandwidth (the size of that WSDL can grow quite quickly as your web service becomes more complex). For reference, a page that is 100k *in total size* is considered effectively unusable in low-bandwidth settings, such as 56k dial-up or dedicated circuits. Not to mention if you ever hope to handle more than say three users or so....

On top of those hidden costs is the actual cost of the SOAP payload itself. Most developers are at least aware of this aspect, since there has been a great deal of discussion/ranting over the years about SOAP message bloat. In my test case here, this actually turned out to be the lesser cost when compared to the setup overhead. Each SOAP conversation is costing me roughly 2k for the request and 1k for the response, which honestly is not too bad. It's worth mentioning though that these tiny costs are exacerbated by the latency costs of the connections themselves, and if your design is inherently "chatty", these costs will add up very quickly.

Real Numbers:

So you might be rolling your eyes, thinking "so what. this guy is griping about a few extra bytes, he has too much spare time to dig this crap up". I would be skeptical as well. So I did some real analysis of this application using the simple ACT tool that comes with Visual Studio. This examined application uses Infragistics controls heavily, and I was expecting them them to be the worst offender, but measurements proved otherwise:

In ten minutes, my test ran 431 iterations of a simple "browsing" script, which logs in, does a few searches, and pokes around most of the application pages without modifying any data. In each test iteration, a total of 105 unique URLs were requested, though obviously many were hit multiple times. Between the pages themselves, images, and linked css and javascript files, a total of 82,224 requests were issued. 5,000 of those ended as "socket error", which indicates that I was hitting right up against the limits of my testing machine (Win XP) which was starting to have trouble handling the requests and thus dropped a few. 4,294 requests resulted in a 403 http error, which indicates also that the server was becoming saturated.

While only 441 calls were made to the web service in actual method calls (essentially once per iteration), 5,485 calls were made to retrieve the WSDL! In fact, this works out to roughly 12 times per iteration. No other resource was requested so often from the server... the next highest were about three aspx pages each requested roughly 3,500 times (they are reused in IFrames a lot, so this is somewhat understandable). The webservice.htc was also requested a total of 859 times, or roughly twice per iteration. So essentially, 8% of the total # requests, and 10% of the bandwidth of this application (even factoring in image files) was being expended simply to read a few strings of data without forcing a server postback.

In comparison, the notoriously bandwidth-heavy Infragistics grid, datetimepicker, and outlookbar controls had a combined impact significantly lower than the web service calls.

So, how to fix this?

The best approach is to just not do this. Chances are, an application that relies on OOB tricks probably should have been a Windows Forms application to begin with. But assuming you are 99% through the development (nobody ever thinks about load tests until then...), I assume a rewrite is out of the question. So, the question is "how to minimize the problem?".

There are three approaches I can think of to remedy this situation without resorting to drastic re-architecture.

  1. Roll-Your-Own. It is rather painless in my opinion to simply define your own (or go with "standard" XML-RPC) out of band mechanism. XmlHttp is quite easy to use, and writing the XML DOM code to construct requests and extract results/errors is not at all difficult. On the server end, its also not very hard to produce XML to match your needs manually, and simply write it out to the response. Using an HttpHandler would make it pretty lightweight too. This approach eliminates the huge webservice.htc downloads, and also eliminates the WSDL calls, since well... there wouldn't be any WSDL. Of course, the result is 100% proprietary, which may be considered a drawback.
  2. Use SOAP without WSDL. An extension to approach #1, you would interact with XmlHttp directly using your own javascript. However, you continue to use an ASMX web service on the server. As long as the parameters are simple datatypes, you can use the HTTP GET method and pass the parameters in the query string. Then, its just a matter of dealing with the (relatively clean) SOAP response. No WSDL to contend with in this approach, and no webservice.htc. You also get to use the strong tools support server-side for the ASMX web service. The downside is that you have to keep to simple parameters, and you have to code the response handling in javascript.
  3. Relocate the behavior code to a parent frame. By making an outer-level frameset with a single contained frame panel, you can link the behavior and associated WSDL calls in that one place, and call it from within nested frames. This has the benefits of retaining the SOAP conformance (allowing you to continue using ASMX), while reducing the WSDL and HTC requests to once per browser session. The downside is that now you have to pay more attention while coding. Calls to the webservice proxy have to be made by traversing the frameset (iterating through parent frames).

These are all decent ways to place a band-aid on the problem. But the problem itself is, to me, indicative of a much larger problem that I see widespread in the industry today...

Misuse of SOA tools and components

Web Services are a component of SOA (Service Oriented Architecture). WSDL and associated discovery/description technologies are tools of SOA. More and more, I keep seeing people attempt to use, or more accurately "misuse", these things. Web Services are implemented as if there was zero cost in performance/latency/reliability. WSDL is fetched at run-time to configure service proxies on the fly. This is NOT how these technologies were intended to be used, and they perform and scale miserably when used like that.

The purpose of WSDL is to define service contracts. This is for the purpose of being able to understand and properly interface with a service. You interpret the WSDL ONCE and ONLY ONCE (preferably at design time!). Your code will obviously depend on the semantics of the contract declared in the WSDL, and so it makes zero sense to interrogate for WSDL at run-time! In fact, once you go to production, its a pretty good idea to completely disable the WSDL handler in ASMX web services, if nothing else than to lower your DoS vulnerability profile (after all, generating WSDL in asmx isn't free).

And the invocation of Web Service operations themselves is not intended for such scenarios as OOB web browser activity. Web Services are a way of enabling applications to communicate via messages, which is useful in Enterprise Architecture (ESB's) and Integration (EAI), but of little value in a contained web browser application.

Microsoft really should be more responsible and put a warning on this thing. The documentation on MSDN reeks like a marketing brochure. It discusses all the wonderful benefits, but makes no mention whatsoever about the potential problems. Nor does it even mention the fact that accessing web services from a browser is a dubious idea from the outset.

 

Sunday, March 06, 2005 4:23:55 PM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [8] | 
View Keith Rome's profile on LinkedIn

On this page....

Archives

Navigation

Categories

About

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Sign In

Certification Logo Certification Logo Certification Logo Certification Logo Certification Logo

Powered by: newtelligence dasBlog 2.3.9074.18820