| Scott 的个人资料Scott's "SiteExperts" Pl...照片日志列表 | 帮助 |
|
|
2006/5/4 Watch my Engineering Great AJAX Experiences Talk...My presentation from the Mix06 Conference, Lessons from the Trenches: Engineering Great AJAX Experiences is now online:
Description:
Explore the challenges and lessons learned developing the Windows Live and Gadgets Web client frameworks powering Windows Live, Hotmail (Kahuna beta), Spaces, and more. This technical talk presents design and architectural considerations for building interactive AJAX-like sites. See how componentization, network management, accessibility, page composition, and more impact the design and engineering of your Web application. (To find other talks, go to the main Mix06 Sessions Page).
2006/4/26 Gadgets and Cross-Browser DevelopmentWe are working hard to improve the Gadget framework documentation. In the meantime (and as we improve documentation), I am working on a series of short tutorials, tips, and highlights introducing how to use the Gadget framework and the underlying APIs. I am going to start with our compatibility layer. After exploring various third-party gadgets being developed for Live.com, I discovered that many developers are still struggling with the API differences between Firefox and Internet Explorer. Most common, I see various tricks to handle the event model differences where IE uses a global event object and Firefox passes the event object as an argument to your handler. This is not necessary when you build Gadgets. Instead, you should be leveraging the underlying compatibility layer that is part of the overall Gadget framework. As I posted last September, as we develop our properties, almost none of our application logic contains browser specific code. Instead, we develop once to the Internet Explorer API and our code runs without modification in Firefox. This occurs because we download a special script that emulates the most useful IE’isms inside of Firefox and in a few cases, Firefox/W3C’isms in Internet Explorer. In this article I highlight the most useful methods and properties of this layer (I promise we will develop a full reference in the near future). Event Model This is easy – always attach events using attachEvent and detachEvent. Do not assign event handlers using function references (e.g., myElement.onclick = doThis) nor use the addEventListener approach. In your event handlers, don’t worry – you will always get the global event object. For example: function doClick()
{
alert("You clicked on a " + event.srcElement.tagName +
Also, as a general practice (I will cover this more in later articles but this is extremely important), when writing Gadgets, be sure to detach any event handlers in your dispose handler. Otherwise, your Gadget will leak memory due to known browser issues. What can you do with this event object? You can check out the MSDN reference as most properties are exposed. In addition to the standard properties, below are the list of properties we added to Firefox:
We have also gone further and extended Firefox with the very useful mouseenter and mouseleave events. As long as you attach these events using the attachEvent and detachEvent methods, these events fire just as they do in Internet Explorer. These events are very useful for quickly and easily detecting when a mouse enters or leaves a specific element. Again, check out the MSDN reference for more details. We even have a reasonable emulation of mouse capturing. However, this is most useful in the context of an entire web-page not within a simple gadget. This is because mouse capturing in Firefox only fires within the context of the browser client area. Regardless, when using mouse capturing (setCapture and releaseCapture methods), the mouse events fire properly on the correct elements. We also fixed the Firefox onclick event to only fire for the left mouse button (Firefox fired for all mouse buttons). This little difference could cause you grief in your application. (For those of you who noticed that we also accidentally prevented the ability to open pages in new tabs via the middle button, that will be fixed real soon). Useful Element Methods Internet Explorer also supports a number of very helpful methods and properties on every element. These APIs simplify day-to-day programming and are very useful for building your application. Below are the list of element functions we added to Firefox. Again, check out MSDN for the details (linked for each item below) on how they work.
The currentStyle property returns the value actually being applied to the element. We currently support a subset of CSS attributes that we have found useful: border, margin, padding for Top, Left, Right, and Bottom; position; height; width; zIndex; color; and direction. We will most likely extend this list over time. Useful style properties We also extended the properties available on the style object with the extremely useful pixel* properties. These allow you to easily manipulate the dimensions of the element (assuming you are working with pixels). We also added the cssText property which gives you a serialized representation inline style. XPath Expressions When dealing with XML documents the ability to query for specific nodes is especially useful. Trying to decipher the difference between IE and Firefox for querying XML can be extremely painful. So, we provided support for two very straighforward IE methods, selectSingleNode and selectNodes. Creating xmlHttp Objects When you need to create a new XML Http Object, you can now simply use the standard approach, Parsing XML Last, but not least, you have a string that you want to load into an XML DOM - just use the standard DOM Parser object: var dp = new DOMParser(); var xmlDom = dp.parseFromString(yourXMLString); This concludes my very brief and fast introduction to our compatibility layer. We are continually expanding the functionality. For example, we have basic IE filter support (alpha filters assigned via script will also apply in Firefox). I will cover these in later posts. For now, resist the urge in your Gadgets to author code differently for each browser. Instead, take the easy road and let our compatibility layer do all your heavy lifting. Last, since it will inevitably come up, see the following post on why we support or don't support other browsers (while the post talks about start.com it is relevant to all properties on our framework). 2006/2/6 Presentation: Creating Rich Interactive Web Applications Using AjaxAbout 2 weeks ago (on January 25th), I gave a presentation on Creating Rich Interactive Web Applications Using AJAX. I just posted the deck at http://www.weblogging.com/decks/ajax.ppt. The deck is mostly intended for the attendees as the slides by themselves do not convey the full intent of the talk.
For those that missed the talk, I will be giving a similar talk at the Mix06 Conference in March:
Lessons from the Trenches: Engineering Great AJAX Experiences Explore the challenges and lessons learned developing the Windows Live and Gadgets Web client frameworks powering Windows Live, Hotmail (Kahuna beta), Spaces, and more. This technical talk presents design and architectural considerations for building interactive AJAX-like sites. See how componentization, network management, accessibility, page composition, and more impact the design and engineering of your Web application.
The focus of the talk is to look well beyond AJAX to explore challenges in designing and engineering your web application. I believe the paradigm shift is not so much focused on AJAX (which is merely a development pattern) but rather around the ability to remix and mashup the web. The remix concept is fundamental to how we are architecting our experiences across Windows Live. This talk explores the web client technical issues that need to be considered when building a rich (remixable) web-experience.
2006/1/21 I am presenting at the WebGuild user group next weekIf you are in the valley, feel free to join me Wednesday, January 25th, at the WebGuild user group (http://www.webguild.org). I am giving a talk on Building Rich Interactive Web Aapplications using Ajax. I will share design and engineering challenges that should be considered when building AJAX-like sites.
2005/12/15 Mix06 ConferenceI promise I will get back to blogging more real soon :-)
I wanted to point out the Mix06 Conference. If you do anything web-related (e.g., Web 2.0, Ajax, etc) I recommend joining us for a conversation exploring the MIXed up world of the web. I will blog more about this over the next few months. I will be there most likely presenting and joining in on many of the conversations.
2005/11/2 Technology and Windows LiveYesterdays Live.com demonstrations and announcements had a few hiccups. Since I take a long-term perspective, I am sure yesterdays missteps will be quickly forgotton. As we execute moving forward, the commitment to and value of this vision will become even clearer. My focus is on executing and developing the technology to enable the Live.com vision. Over the past nine months, I have been discussing (from a technical perspective) the benefits and value in developing the shared MSN framework and set of programming patterns. If you look at MSN and Live.com's direction, you will start to see the benefits of this investment. Live.com and many MSN.com properties are now built on the same client infrastructure. Having a single framework will enable improved and consistent experiences to be delivered with more stability and efficiency. The model extends to third-party developed Microsoft Gadgets. Microsoft Gadgets use the same programming paradigm used internally to build our properties. Gadgets are built on the same base classes as our native components and have access to the same set of services and functionality. We are going to see lots of other benefits of having a shared framework. Picking on one shortcoming - we currently do not provide adequate integration (actually no integration) with the back button. We will be adding history support into the infrastructure. The benefit to having a shared framework is once functionality is ready, it can be leveraged universally in a consistent manner across all our properties (and even leveraged by third-party Live.com Gadgets). Beyond MSN and Windows Live, the framework shares the same foundation as ASP.net Atlas. Asp.Net Atlas enables you to build and host your own rich applications. This is much broader than a mere AJAX library - this is establishing an entire platform and approach with tools support to building web applications. Technology, experience, customer value, etc. - everything is coming together. Remember, yesterday was a small and important step representing a fundamental shift in direction at Microsoft. It is what comes next that gets me excited... 2005/10/25 XMLHttpRequest - The Ultimate Outliner (Almost)A key part of Web 2.0 focuses around the ability to mash-up or remix the web. Unfortunately, I believe the cross-domain limitations of the xmlhttprequest object are lmiting opportunities. By enabling (at minimum) unauthenticated cross-domain requests much greater innovation can be achieved. For background, I recommend starting with my earlier blog entries: XMLHttpRequest - Eliminating the Middleman, and XMLHttpRequest - Do you trust me?.
So how do I make my point? I build a few 100% client-side demonstrations. In my last article, I enabled multiple search engine querying. This week, I attempt to prototype an "ultimate outliner" that can consume OPML, RSS, Atom, etc. I limit myself to two hours from imagining the idea to posting an implementation. I am confident it is very difficult to recreate these demos as cheaply or easily (especially from a bandwidth and scalability perspective) if I did not request the cross-domain resources from the client.
Where's the demo? See http://weblogging.com/o/. You can enter a RSS, Atom, or OPML feed or pass it in directly via the URL: http://weblogging.com/o/?pathToFeed. Below are a few you can try out (be sure to follow the security instructions if this is your first time using my demonstrations):
Remember that this was developed in 2 hours so be gentle. I know there are quite a few bugs (e.g., Many RDF files will not render and resources that redirect to a new location will not load - the latter issue appears to a problem with the xmlhttprequest object)
A challenge in building this demonstration (and where I spent a fair amount of the development) was writing code to determine the type of resource being requested. This is mostly due to the very ambigious OPML specification (see my previous post). To solve this, I do an extra round trip first requesting the headers. I then map the mime-type to one of the internal renderers. If you examine the code, you will notice it is designed to be extended with custom renderers for any type of XML resource (I took the cheapest approach by examining the root element and know this is not necessary the most semantically correct). While this extra roundtrip is unfortunate, since it is performed client-side, my server does not have to bare the cost of the requests - especially since many servers are extremely slow at returning HEAD requests.
Building these demonstration are quite fun. By eliminating the server component, I do not have to worry about scale or bandwidth constraints allowing me to focus on the scenario. I started with feed-oriented demos so that I can leverage the code to build even better mash-ups even faster in the future.
Now, if there was only way to elminate that pesky cross-domain xmlhttp request issue...
UPDATE: If you visit the link and see gibberish, here is the error message that should have been displayed (I will investigate why the gibberish is occurring):
UPDATE 2: If you still are seeing gibberish, try going directly to the page via http://weblogging.com/o/o.htm. I disabled http compression on my server and I believe that may have fixed the issue. If anyone has any other suggestions (I would like to reenable compression), please let me know. 2005/10/24 OPML - Please enlighten meI am not an Opml expert. This is the results of my observations of a couple Opml feeds. I fail to see how to adequately leverage Opml in the mash-up web world. A few weeks ago, I published a demonstration for searching multiple site's entirely via the web-browser. I was illustrating the value of opening up unauthenticaed cross-domain xmlhttp requests and the opportunities that would create. I planned to build a new demo that can "mash-up" Opml. This demo would take an XML feed (whether RSS, Atom, or Opml) and render it. For Opml lists, I wanted to expand each list item based on type. Opml files (e.g., reading lists) expansion would have been a powerful expression. Loading an Opml file would render the list. Each outline item would be rendered based on type within the page - links to other Opml lists would expand in outline format, links to Rss feeds would expand with the feed in place, links to Mp3 or videos would expand with a media player, html pages could expand with a preview of the page, and so on. This provides a foundation for a a very quick and effective newspaper page. Developing this should have been trivial. The base code was less than a few screenfuls. However, my good intentions quickly fell apart because I discovered that Opml provides no (actually minimal) semantics to understand the items in the list without having to physically request them. Opml apparently has a type attribute. However, this type attribute is not well defined. According to the Opml Guidelines, this merely tells you that the link is an Rss feed or something else. Something else is pretty broad. Having to request the resource to somehow determine its type is a non-starter (I am not downloading a multi-megabyte video just to know its a video). Even worse, different feeds use the url and xmlurl fields differently. I found Opml files that list each type as a "link" and then the url refers to an Rss file. Even in the most recent post dated a week ago, Validating OPML, while the type attribute is considered required, it still appears to distinguish only between Rss and the everything else. I can't understand why isn't type just the mime-type? I know this has been a challenge for others as I found code attempting to determine types via the file extension on the Url. This approach is very unreliable especially with the dynamic nature of many sites (Many times every file, regardless of actually mime-type, will end in extensions such as .aspx, .php, etc.). So... I guess I don't get it. A list is interesting but without knowing what is in the list I fail to see how I can adequately leverage and "mash" it up into a greater experience. Please enlighten me. 2005/10/14 We are Hiring!Are you passionate about the web? Do you want to drive "Web 2.0" and have a big impact on the future of MSN? Do you like to identify and solve big problems? If so, I may have the job for you. We are looking for Technical Program Managers, Senior Developers, and Testers to help drive the shared infrastructure and experiences across the MSN web properties.
Below is one of the engineering openings (more should be posted soon).
If you are interested, please send your resume to scott.isaacs[at]microsoft.com. 2005/10/11 XMLHttpRequest - Eliminating the MiddlemanInspired by Chris Pirillo's recently announced http://gada.be search aggregation and continuing my previous discussion, XMLHttpRequest, Do you trust me?, I created a simple illustration demonstrating the value of unauthenticated cross-domain requests.
I recommend checking out http://gada.be and his blog to learn more about the vision behind the service. Chris created a nifty "tag"-based search engine that can aggregate over 140 search engine results. It is also optimized for easy t9-based access from mobile devices.
However, his site demonstrates the potential shortfalls of not being able to make cross-domain requests on capable clients. The performance of the site is dependent on his ability to query each individual service for each individual request through his server. The first day out, the gada.be service slowed as it was quickly picked up by the blogosphere. I do not know if every query is made live against each service but regardless, to maintain a performant popular service, gada.be most likely will need to build a server farm and deploy some level of intelligent caching to handle the remote requests. Perfecting such implementations add complexity and expense.
While server-based aggregation will be necessary for some thin-devices (a key target for gada.be), if the more capable clients supported accessing services directly, the site could scale much better and have lower infrastructure costs. This is a driving scenario around my thoughts to open up unauthenticated cross-domain xmlhttp access to public data.
To illustrate, I created a client-based search aggregator page. This demonstration page and related files are 100% static with no code executing on the server. My server in this sample does not act as the intermediary to make requests. The implementation is less than 15K (unoptimized!) and it only took me about an hour to implement. New search engines and categories can be added simply by extending an array. Since every service is queried directly from your client, the server scales equally well for 1 service or a 100! This is an extremely efficient both in terms of execution costs and equally important, implementation complexities.
This approach cannot enter the mainstream today because user's must modify their security settings to use pages built this way. Before my search page will work you must customize your security settings using Internet Explorer. Firefox is currently not supported mostly because I could not find sample code for requesting "cross-domain" permissions (if you know how, feel free to send me some sample code and I will update the page including fixing the firefox layout issues).
Moving onto the demo... Visit http://weblogging.com/s. You can send queries via the URL as follows: http://weblogging.com/s/?SearchText. If your security settings are incorrect, you will get instructions on how to update them after making your first query.
This is intended to be a demonstration so I wouldn't be surprised if there are a few bugs or imperfections in the experience (remember, I developed this in under an hour). For example, I do not try to "correct" feeds with parsing errors. 2005/9/28 XMLHttpRequest - Do you trust me?Many web applications that "mash-up" or integrate data from around the web hit the following issue: How do you request data from third party sites in a scalable and cost-effective way? Today, due to the cross-domain restrictions of xmlhttprequest, you must proxy all requests through a server in your domain. Unfortunately, this implementation is very expensive. If you have 20 unique feeds across 10000 users, you are proxying 200,000 unique requests! Refresh even a percentage of those feeds on a schedule and the overhead and costs really start adding up. While mega-services like MSN, Google, Yahoo, etc., may choose to absorb the costs, this level of scale could ruin many smaller developers. Unfortunately, this is the only solution that works transparently (where user's don't have to install or modify settings). This problem arises because the xmlhttprequest object can only communicate back to the originating domain. This restriction greatly limits the potential for building "mash-up" or rich aggregated experiences. While I understand the wisdom behind this restriction, I have begun questioning its value and am sharing some of my thoughts on this. Let's compare xml to scripts. Scripts can be loaded from any server and run in the context of the requesting page. As more sites are building dynamic interfaces, they are also leveraging dynamically generated scripts. These scripts can return meta-data and other information based on the supplied querystring parameters. This is semantically the same as requesting an xml feed - the only difference being the serialization format. The ability to load third-party scripts is a fundamental building block for integration on the web (e.g., Google AdWords require them). Today, RSS and XML have also become a fundamental building block of the web. So why are we treating xmlhttp differently? Much of the cross-domain concern is around phishing attacks - xmlhttp can be used to request any file from another domain (e.g., html interface), While client access to this data can increase the attack vector, I do not believe the risk of this scenario outweighs the benefits. I do not believe Phishing sites will benefit more from cross-domain access - they have been capable enough at stealing passwords by merely just copying the UI. A related and misguided concern is cross-domain xmlhttp request is somehow aligned with XSS (cross-site scripting) exploits. The ability to request a resource from another domain is much different than the ability to execute script in the context of that domain. XSS is a completely different issue, and I am not proposing we remove those restrictions (although I do believe more work can be done to improve that area). Other's claim that cross-domain xmlhttp requests can give the client access to private data. If the cross-domain requests are restricted to the same visibility as the host page (e.g., internet sites cannot access the intranet), then the information being requested is already public. The only potential issue is with a rogue intranet site (requesting authenticated intranet data from another intranet site), but I believe that can be handled via greater controls. Prohibiting client-side cross-domain requests does not entirely protect the user. The moment a server is involved (which means any web-site), any such client internet request can be proxied by the server. Furthermore, there is no way to indicate to the user when the server does the proxying. As a believer in integrated experiences and examining the key scenarios driving the web forward, I would prefer to see xmlhttprequest reenabled by default. We should reconsider supporting cross-domain requests within the same zone or at minimum limiting such data requests to the internet. If we want to focus on enabling basic aggregator-type experiences, further scope this to supporting just http "get" requests (no secure https or "post"ing). Let's stop treating third-party xml any different from a third-party scripts, stylesheets, or images, which can all be requested without restriction. They are all "embeddable" resources. Getting back to the title of this post, Do you trust me? I believe disabling cross-domain xmlhttprequest actually has little relevance to answering this question especially since the server can already proxy these requests. Since the web is an inherently "unmoderated" environment, we need to focus on improving security through better communication. IE7 announced they are investing heavily in anti-phishing features that will highlight suspect web-sites. That coupled with proper user notifications are the critical features that I believe help answer the trust question. For example, any site that requests a script, xml, or other resource file from another domain should have a special indicator (e.g., similar to the privacy indicator). I would even argue that any site making any xmlhttp or other background requests to their own server get a slightly different indicator. User's (and other hueristics) can examine the data requested and choose to prevent the page from executing (and obviously, users should have settings to modify the defaults). Sometimes we should consider reevaluating prior decisions - even if they were made in the name of tighter security. I am interested in hearing other developers and users views on this. Am I misguided in my view that xml should be treated no different than other embeddable resources? Or is requesting xml data inherently different than scripts and is something that should be protected? Also, I just want to be clear before anyone gets overly excited (especially those that may disagree with me), there are no plans that I know of to change browser security models around xmlhttprequest. These are merely my obversations. Technorati Tags: xmlhttprequest | ajax | web 2.0 | javascript 2005/9/20 Talking about MSN DHTML Foundation unveiledMy Scoble video was posted (and I am listed on one of his favorites). This was recorded before the PDC so my demo's of Start.com are already slightly dated :-) [btw - see http://www.start.com/pdc instead of the root page to try out Gadgets, etc] Scoble holding a hand-held video camera in your face is a very interesting experience :-) Quote Scott Isaacs - MSN DHTML Foundation unveiled 2005/9/10 Modernizing Javascript: Namespaces and StyleIn my last Modernizing Javascript article, I introduced how we use namespacing to encapsulate reusable functionality.However, since most of our javascript classes are tightly coupled to the user-interface, how do you also associated the scripts with the appropriate layout.
For example, in MSN Spaces we have the rich text editor (RTE). This RTE is built as a reusable component (e.g., Hotmail is going to use the same editor). The RTE also has a fair amount of complex layout rules. We need to guarantee that any RTE layout does not interact outside the scope of the RTE component.
Traditionally, developers would encapsulate the layout within the scripts. Unfortunately, this approach prescribes a specific look and feel and violates the principals of separating structure, behavior, and presentation. Therefore, the RTE instead defines all its layout and default presentation via CSS. Doing so enables consumers of the component to easily override presentation without having to touch the core code. However, this also requires us to define CSS rules that will not interact with the rest of the page.
CSS has a built-in approach to scoping a style sheet via the CSS selector. We prescribe a pattern that provides uniqueness for defining and applying classes to elements. Looking back at my previous post on namespaces, you will notice that we have a pattern for encapsulating functionality within a namespace. We reuse this exact same pattern to define classes on elements.
For example, we have a Rich Text Editor that may be implemented in the following namespace: Web.UI.Editor = function()
{
// Implementation of the RTE
}
Since we are assuming the namespace and Javascript class are unique, we reuse the same JavaScript class as the class of any structural elements associated with the RTE. <div class="Web_UI_Editor Web_Base_Bindings"> To maintian proper CSS class names, all "." in the namespace hierarchy are replaced with "_". The above div element is a structural element used by the Web.UI.Editor class. Now, to define CSS scoped to the RTE structural elements, we define our rules as follows: .Web_UI_Editor {background: lightgrey}
On the div, we presented two classes. That is a lead into a future article, inheritance. Our RTE inherits from a base class, Web.Base.Bindings. We associate the entire inheritance chain with the element class. This way, when you inherit, you also automatically inherit and base styles.
As you can see, it is important when building you components to take a complete view - not only of your code but your associated styles. By applying a few simple patterns, you can more easily engineer and reuse components. 2005/9/9 Modernizing Javascript: NamespacesAs we head into the PDC next week, I am going to introduce some of our techniques for using JavaScript to modernize the Javascript language. I am going to start with a simple concept, simulating namespaces. Most web-development is very ad-hoc. Global variables and functions are often sprinkled throughout the web-page. In MSN, we are building resuable components. To allow independent teams and developers to leverage and reuse code, we needed a pattern that encapsulates logic to avoid variable and function collisions. Back in March (links provided at the end), I briefly introduced using closures and demonstrated how to create Singletons to encapsulate private variables. Now I am going to take that a step further. In JavaScript it is possible to simulate namespaces by creating object structures. Namespaces are a common pattern in most OO languages that allow you to encapsulate classes, structures, etc. In JavaScript, we create a namespace as follows: var Demo = {} // Create the Demo Namespace
Demo.Dialogs = {} // Create a Dialogs namespace
Now, you can add classes and functions to the different namespaces (e.g., Demo and Demo.Dialogs): Demo.Application = new function()
{
We simplify the namespace creation with a simple registration function, This function generates each component of the namespace as required (e.g., registerNamespace("Demo.Dialogs") will create Demo if necessary, then Dialogs if necessary). Creating the namespace only as required is critical. If you create a namespace, e.g., Demo.Dialogs, and then later in another script someone extends the same Demo namespace by manually creating the namespace, all prior functionality will be destroyed (you are basically reinitializing the Demo object). Within MSN, we designate a namespace for framework infrastructure and generic utility functionality, and each property develops their code in their own respective namespace. This allows us to leverage indepedently developed code without worrying about namespace collisions. A little closing thoughts: My earlier blog entries on Closures: 2005/8/28 Rethinking Web Development - Event HandlersAs I discuss platforms or frameworks in the browser, I continue to emphasize on the value of putting "engineering" principals into the client. One of the biggest issues with much web development is typically the lack any development methodologies. This combined with the flexibility of scripting and DHTML often leads to poorly constructed code. Let's take a quick look at event handlers. When I wrote the DHTML event specification back in 1997, I focused heavily on embracing and extending the simplistic Netscape 3.0 event model. Netscape prescribed that all events were also attributes on the respective elements. With DHTML, we extended this model with many more events and by adding them to every element. To support these new events and meet the 100% backwards compatibility reuqirement at the time, I introduced the concept of automatic bubbling model. Event bubbling not only enabled our compatibility requirements but also provided a very simple but powerful early solution to simulate subclassing of an element's behavior (you could grab an event on the document and override behavior globally). Netscape's original few events focused mostly on enabling control over default behaviors. In DHTML, we had lots of rich rich information with each event (mouse, keyboard, event source, etc). To faciliate this extra information, I created the window.event object. The creation of the event object on the window was an outgrowth of our compatibility requirements. We needed a way to pass rich information to event handlers without modifying (at that time) the signature of the event call. While the event object as a window property is less than ideal (it relied on the single-threaded nature of the browser's script engine), the overall eventing model provided the foundation for enabling very interactive sites. Quickly after IE4 was released, it was recognized that the singular focus of an event handler was a big shortcoming. By only having the ability to assign a function to a handler, it was hard to have multiple listeners to any single event. This issue becomes more prevalent if you planned to write modular, reusable code (how do three independently written functions sync the document onclick event). In the early days, this was solved by building simple event broadcast libraries (or the first "frameworks"). In Internet Explorer 5, this scenario was codified into the attachEvent and detachEvent methods and later standardized as addEventListener and detachEventListener (supported by Firefox and other browsers). So... Why this walk through history? Today, many developers still focus on using the original function assignments for defining event handlers. As you consider engineering your web application, start thinking about how your code may react when dropped into different pages. The ability to properly modularize your code is critical as you consider building reusable code on most frameworks. Unless the element you are referencing is truly private (e.g, creating in the context of your code), assigning directly to an element's event property is asking for trouble. Instead, explore the attach/detachEvent and add/removeEventListener methods for all your event listening needs. Defining event handlers within the HTML as an attribute of the element is equally if not more harmful to reusability and maintainability of your site. While in-line event handlers are convenient, they start comingling your structure and behavior. Just like the old web mantra to separate structure from presentation, you should consider how to separate the behavior from the structure from the presentation. This brief introduction leads into a broader topic that I am going to try and discuss over the next few weeks - how do you properly separate structure, presentation, and behavior to build reusable components. I will close with the following tip: 2005/8/23 When bugs become patterns - A look at CSS HacksWhen asked about developing web applications, I used to joke that it is a black art, mixed with a little bit of illogical reasoning, and brought together under completely unsound engineering principals. Unfortunately, this describes the state of many cross-browser CSS work-arounds. It is well known that each browser has its own slightly unique way of interpreting CSS. These differences create headaches for web-developers. We have all learned how to manipulate the various box models by introducing extra structure into the page. While adding structure can smooth out some of the box-model differences, I never understood how any engineer could then decide to apply their knowledge of bugs and incomplete implementations to create and apply the styles to their page. Below I am going to list a few hacks I found after a very quick search of the web (there are hundreds of documents on the subject). These are mostly to illustrate some of the "state of the art" of cross-browser CSS: from The “Be Mean to Opera” Hack from Tantek's famous box model hacks My favorite hacking mistakes are those that try to leverage unsupported "real" features: The above examples have actually become part of the CSS development "patterns" - and more amazingly, there are many more. While these solutions are very creative, I refuse to explain what they do or why they may be used for a simple reason - they promote the black art of the web instead of pushing sound engineering. I have seen stylesheets mix so many different hacks, all without comments, making it impossible to decypher the intended presentation, and even more impossible to debug. Furthermore, as new browsers are released, how do you know the parsing bug or feature you are relying on will not be removed or modified. Now, I wouldn't be bringing this up if there wasn't a very simple and logical solution to this issue. Let's start by thinking about the problem. In a perfect world, we would create a single CSS stylesheet that would work everywhere. Unfortunately, the browser world is probably about 95% perfect (which I determined in a completely arbitrary and unscientific way) leaving us to find a way to deal with the difference. So... assuming the world of CSS is almost perfect, we focus on building a single style sheet and explicitly targeting any such imperfections. How do we accomplish this? CSS has a built-in mechanism called the class name. Differing class names can be used to generate completely different layouts. We can leverage this approach for browser targeting. I focus on applying a classification scheme onto the <HTML> element either dynamically generated on the server side or injected into the element via client script. This classification can be used generate CSS overrides. Confused? Let me give you a few examples: <html class="firefox m1 d03 mac"> <html class="ie m6 d0 win"> <html class="opera m8 d0 win"> If you haven't figured it out, I specify the browser type, the major version, the minor version, and the platform. This classification scheme can be as simple or as complex as you wish. Now... in my css sheet, let's look a simple few rules: div.Box {margin:5px;width:100px;padding:5px}
html.firefox div.Box {width:95px}
html.opera.m8 div.Box {padding:0px}
Can you guess what the above does? The div element with the class "Box" gets a default width of 100 pixels. For FireFox and Opera V8 we created two targeted overrides: In Firefox, the width is set to 95px. In opera, major version 8, the same element has no padding (and is 100 pixels wide). Why do I like this approach? Anyone familiar with CSS can walk up to the stylesheet and quickly decypher the intent of the stylesheet and the specific browser issues being addressed. No bugs or missing features being leveraged, just good old solid understanding of the CSS model being applied in a reasonable, logical, and sound way. UPDATE: I have seen a few comments (from other blogs) concerned about "coding" in specific versions. This was for illustrative purposes. Typically, you only need generalized overides (e.g., html.opera) with version specific overrides that may exist for legacy versions. This way we are reasonably protected when a new browser is released. If the new browser fixes the issue, we then increase the specificity to use the version. Also, for caching - these are psuedo-dynamic pages and depending on your architecture can serve these cached once you determine the user-agent. The biggest issue occurs if your page is truly static and is intended to be cache by proxies. In this scenario, a server generated approach is not the way to go. For this reason, and since I do not like to burden the server with processing the client can easily handle, I typically use client-based solutions whenever possible. For my scenarios, I am less concerned about users that disable scripting - we are building applications, not web pages - and I view the argument that our applications should be able to run with scripting turned off as academic. I will save a deeper explanation for another post and how to handle the no-scripting case. Also, this approach only needs to recognize browsers of interest and align them to your desired classifications scheme which may be different from using version, etc. If the browser is not recognized, it will get render with "standard" stylesheet, which is a reasonable and perhaps the only possible result. As my closing nugget: 2005/8/15 Why Ajax is so 1999? Part 2Over the next few weeks, I am exploring how the AJAX pattern by itself is inadequate for building truly next-generation web-sites. I suggest starting with my opening post on this subject... One of my favorite topics for building rich interactive sites is how to manage the network pipe. This is essential if you want to build a truly winning experience. Let's start by reviewing how the browser manages individual pages. Today, when you visit a web page, the page processes external sources and starts to deploy them. If you leave the page, all outstanding requests are aborted. This frees up resources and bandwidth for the incoming page. This pattern should be duplicated within your “AJAX” site.
Let's apply this to two different scenarios: In the first example, we described two distinct views. However, it is actually not the view you need to examine, but it is the entire application context. Let’s examine an AJAX e-mail client that supports in-line previewing of messages. As the user is navigating down the list of mail messages, you start requesting the full e-mail message. If you just fire your requests sequentially, you might quickly clog the available connections potentially bringing your application to a halt. Instead, you should be aborting the existing requests as the user changes their “context” freeing the connection to provide an optimal experience. You can’t assume broadband will solve this issue for you. You need to remember current standards define that browsers should only open two simultaneous connections at a time to any single server. Therefore, if you queue many large requests, even with today’s broadband, you could get significant delays. This leads to my second pattern - very rich web sites should efficiently manager their network requests against the current context of the application. And guess what, I am not yet done with network management. There is at least one more issue I plan to discuss on making AJAX requests scale. Stay tuned.
Two closing user-experience related nuggets to think about: In the above example, I referred to data requests. If your requests are updating, creating, or deleting data, the pattern just got a lot more complicated. In these scenarios, you do not want to abort the request. However, you must also take into consideration the user-experience if the user changes views and an out of context operation fails – how do you notify the user, what is the expected recovery? Even more complicated is how to maintain integrity of these requests if the user leaves your page before the operation completes. The switching of views also illustrates one of the biggest experience challenges of an "AJAX"-patterned site. In a traditional page-based web-site, switching views loads a new web-page. Having distinct pages enables the browser's history experience and provides distinct URL's that can be e-mailed or added to your favorites. In web applications, these paradigms are usually completely lost or broken. This loss is avoidable (but the implementation can get complicated). As I continue, I am probably not going to address all my little nuggets. They are there to present (mostly an incomplete list of) related issues that should considered when creating rich web-based applications. 2005/8/11 Why Ajax is so 1999? Part 1Before I jump right in, I want to quickly pre-announce that we are working on two exciting lunch-time talks at the Microsoft PDC about how MSN is building itself. I will be posting more details about these sessions in the coming weeks. Since the PDC is a developer's conference, I am going to write a series of blog posts about web development patterns in MSN as we lead up to the big event. We are going to apply many of these patterns and more during our talks at the PDC.
Now... I know I have said this before - Ajax is nothing new. I am going to state it even more strongly this time - Ajax is a marketing term for a programming pattern around "ancient" (in web-speak) technology. It is not an implementation or even a best practice. I am not sure if a development pattern has even been marketed so well and picked up so broadly outside the development community :-) Interestingly, everything and the kitchen sink is now falling under the "Ajax" moniker. Now, in reality, the best implementations of technology is when the customer does not see or feel the technology. What we build should feel natural - the patterns used, whether "AJAX" another, really should have no relevance to the customer. However, I digress, so getting back to the AJAX pattern.... The AJAX pattern is a fairly logical and obvious one. Rather than refresh entire pages, you expose interfaces on your server that allow you from within a web-page to post and then process xml responses. Some people have proclaimed that the Ajax pattern is bringing in the next generation web. By itself, Ajax is nowhere close to what I would call "next-generation".
I am going to explain why over a series of posts. Each post is going to introduce additional challenges we are addressing that are driving the creation of additional patterns. We are using these patterns across MSN. These patterns are much more interesting, optimal implementations are much more challenging, and the aggregate of AJAX combined with these patterns will better exemplify the broad range of possibilities and opportunities in web-development.
Most current "Ajax" patterned sites are what I consider first-generation or 1.5 generation "DHTML" sites. These sites are almost all what I call a "closed" application. These are applications where all the logic is defined and downloaded up-front. Now let's compare that to what I call an "open" or loosely coupled application. These are applications without known or predefined boundaries. For example, let's look at Start.com. Start.com starts as a closed application - it is an RSS aggregator. However, as you interact with the application it dynamically morphs. New components are downloaded and deployed on demand based on different stimuli.
This is the first step to building the truly next generation web-site. Over time, imagine having hundreds or even thousands of components, each with their own logic, that in any combination or permutation define the "application". Ignoring how you would build these component (that will come later), how does such an application deploy? You would not want to deploy every aspect of the application. This is especially so when you consider most of the time only a small set of components or features are initially required.
In Start.com, the system not only applies the "Ajax" patterns to requesting and loading data, but there is an underlying system that knows how to deploy resources (code and style sheets) on demand. When you add a "Startlet" to your page, the necessary resources are automatically downloaded, attached to the application, and instantiated.
This brings me to my first pattern- very rich web applications require a dynamic system to efficiently deploy resources. This also highlights an entire class of issues just around resource management - how do you efficiently manage and prioritize resource deployment?, how do you proactively control the network pipe to more efficiently manage your application?, etc. Network pipe management is one of my favorite topics and one of the best examples of where the AJAX pattern by itself is completely inadequate (stay tuned)
I will start addressing those and many more issues in the coming weeks. In the meantime, I leave you with one more nugget to think about:
One of the most expensive resources for a browser to download is script. Typically, the client opens two connections per domain for requesting content. However, if you analyze the load patterns of any web-page, you will almost always notice that when a script loads, itis the only resource being processed (scripts are typically loaded serially) - additional downloads do not continue until after the script loads. The serialization of script downloads can easily cost you an additional 10%-15% of time to download the page. This loss is avoidable and is something to think about. 2005/7/27 MSN Frameworks and the new Start.com MSN Blog MapFrom my previous few discussions on MSN and Frameworks, you may have guessed that we have a client framework infrastructure. We are developing a framework to enable us to consistantly implement and integrate rich components.
To demonstrate how the MSN Frameworks will enable us to innovate quickly - I built and shipped (beta quality :-) a new MSN Blog Map component within start.com. The MSN Blog Map maps bloggers from throughout MSN (expect the list to grow over the next few weeks). You can check it out at http://www.start.com/3. After the page loads, add MSN Blog Map from Staff Favorites in the left column.
This component leverages MSN Virtual Earth to create a new component that integrates with Start.com. Having our client framework enables quick experimentation, implementation, and ship of integrated scenarios. For the MSN Blog Map, I added custom logic on top of the Virtual Earth rendering component and integrated with the existing RSS rendering objects of start.com.
Having a strong framework for building and integrating rich, highly interactive components enables MSN to deliver much better (and consistent) user experiences. The Framework provides us with a client-side component model, network stacks, firefox compatibility, and OO language enhancements that allows us to "engineer" rather than ad-hoc script the client.
Many of our goals and work is going to be captured in the Microsoft Atlas effort. Microsoft Atlas, from the ASP.net team, is an upcoming toolset to quickly enable any web-developer to create and build highly-interactive web-sites. 2005/7/1 Frameworks, IE and XMLHttpSo far, I pointed out how we are using our framework to enable compatibility between IE and Firefox. The compatibility layer goes both ways. Firefox has native support for the xml http request object directly off the window object. In IE, this same object is exposed via an ActiveX control.
To resolve these differences, we extend the DOM in IE to establish the standard Firefox compatible way to create the xmlhttp request object. Below is a simple code fragment that should run only in IE:
if (!window.XMLHttpRequest) {
window.XMLHttpRequest = function() { var xmlHttp = null; var ex; try { xmlHttp = new ActiveXObject("Msxml2.XMLHTTP.4.0");} catch (ex) { try { xmlHttp = new ActiveXObject("MSXML2.XMLHTTP");} catch (ex) { try { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");} catch (ex){} } } return xmlHttp; } } Now, whereever we need to use the xmlhttp request object, we merely have to call: var newRequest = new XMLHttpRequest();
This again demonstrates how a framework enables us to develop pages without the typical browser detection.
We also take this approach to extend the basic support of the document DOM. We have found that access to the document's HTML and HEAD element is often very useful. Today the DOM has a body property for accessing the object representing the BODY element. A natural extension would be to add a html and head property. We extend the document via the framework with the following two simple statements:
document.html = document.getElementsByTagName("HTML")[0];
document.head = document.getElementsByTagName("HEAD")[0]; Now we can use those properties as if they were native to the DOM.
Now combine these with standard patterns (e.g., class definitions via closures) and you start to see how we can greatly simplify our approach to web programming.
UPDATE: Better structured the XMLHttpRequest function. |
|
|