For those of you that don’t subscribe to the YUI calendar or YUILibrary.com forum, the next installment of YUI: Open Hours will be this Friday the 3rd.
The topic of this week’s call will be performance. How and what to measure in your module code, and techniques and tools for measuring various aspects of site performance.
On deck this week are Ryan Grove, Satyen Desai, and Philip Tellis. Satyen will be demoing dynaTrace Ajax edition, Philip will be introducing a new YSlow plugin he’s working on, and Ryan will cover some of the tools in YUI 3 that you can use in your development to move the needle.
So bring your slow or ailing code (or fast code if you want to show off) and participate in the conversation.
As usual, we’ll be online from 10am to 12pm PDT. The connection details are the same as usual.
Here’s the forum thread for this Open Hours. I’ll post some of the interesting takeaways after the call and we’ll be recording the call for those that can’t make it for the entire time.
Follow @yuilibrary on Twitter for the latest updates on Open Hours and other YUI interestingness.
Hope to see you there!
* – If Skype is not an option, email me for a local number.
This is a guest post by Owen Barton, partner and director of engineering at CivicActions. Owen has been working with Google's “Make the Web Faster” project team and the Drupal community to make improvements in Drupal 7 front-end performance. This is a condensed version of a more in-depth post over at the CivicActions blog.
Drupal is a popular free and open source publishing platform, powering high profile sites such as The White House, The New York Observer and Amnesty International. The Drupal community has long understood the importance of good front-end performance to successful web sites, being ahead of the game in many ways. This post highlights some of the improvements developed for the upcoming Drupal 7 release, several of which can save an additional second or more of page load times.
Drupal 7 has made its caching system more easily pluggable - to allow for easier memcache integration, for example. It has also enabled caching HTTP headers to be set so that logged out users can cache entire pages locally as well as improve compatibility with reverse proxies and content distribution networks (CDNs). There is also a patch waiting which reduces both the response size and the time taken to generate 404 responses for inlined page assets. Depending on the type of 404 (CSS have a larger effect than images, for example) the slower 404s were adding 0.5 to 1 second to the calling page load times.
Drupal currently has the ability to aggregate multiple CSS and JavaScript files by concatenating them into a smaller number of files to reduce the number of HTTP requests. There is a patch in the queue for Drupal 7 that could allow aggregation to be enabled by default, which is great because the large number of individual files can add anything from 0-1.5 seconds to page loads.
One issue that has become apparent with the Drupal 6 aggregation system is that users can end up downloading aggregate files that include a large amount of duplicate code. On one page the aggregate may contain files a, b and c, whilst on a second page the aggregate may contain files a, b and d - the “c” and “d” files being added conditionally on specific pages. This breaks the benefits of browser caching and slows down subsequent page loads. Benchmarking on core alone shows that avoiding duplicate aggregates can save over a second across 5 page loads. A patch has already been committed that means files need to be explicitly added to the aggregate, and fix Drupal core to add appropriate files to the aggregate unconditionally.
Drupal has supported gzip compression of HTML output for a long time, however for CSS and JavaScript, the files are delivered directly by the webserver, so Drupal has less control. There are webserver based compressors such as Apache’s mod_deflate, but these are not always available. A patch is in the queue that stores compressed versions of aggregated files on write and uses rewrite and header directives in .htaccess that allow these files to be served correctly. Benchmarks show that this patch can make initial page views 20-60% faster, saving anything from 0.3 to 3 seconds total.
The Drupal 7 release promises some real improvements from a front-end performance point of view. Other performance optimizations will no doubt continue to appear and be refined in contributed modules and themes, as well as in site building best practices and documentation. In Drupal 8 we will hopefully see further improvements in the CSS/JS file aggregation system, increased high-level caching effectiveness and hopefully more tools to help site builders reduce file sizes. If you have yet to try Drupal, download it now and give it a try and tell us in the comments if your site performance improves!
Satyam (a.k.a Daniel Barreiro) is a long-time YUI contributor and one of the most prolific, generous experts in the YUI forums. He is also the author of a new book on YUI 2.8.0, YUI 2.8.0: Learning the Library. This article in the “Ask Satyam” series was suggested by JoeDev. While its focus (like the focus of the new book) is mostly on YUI 2, many of the practices described here are applicable to YUI 3 as well — and to frontend development in general, regardless of your library of choice.
Before posting a question in the YUI Library forums, there are plenty of things you can do by yourself and, if you have your tools handy, you may find your answer all by yourself in no time. Besides, clean code is robust code, much less likely to break when subjected to stress. Good practices not only avoid fatal errors (the kind that drive you to the IRC channel or forums in search of help), but they surface warnings about minor errors and help you stay away from the fatal edge.
In this article, I’m going to take a look at some of those best practices. Some of these are specific to developing with YUI, but the vast majority apply to frontend development regardless of your choice of Ajax library.
JSLint
A trip through JSLint is part of the build process for YUI. JSLint, itself fully written in JavaScript, is like a compiler but without code generation. It will, however, produce many of the useful error messages and warnings that a compiler would. A browser’s JavaScript interpreter forgives many errors and assumes defaults you might be unaware of; JSLint forgives little, and it points you to better choices in your program. JSLint is available in many formats; the YUI Builder tool uses it as a standalone command line application, but you can also integrate it into Eclipse or whatever IDE or more-or-less capable editor you use — there is even a Yahoo! Widget for JSLint.
If the zillion lines of code in the YUI library can go through JSLint with no errors and few warnings (it can’t avoid a few things), so should your code. I find JSLint very helpful when I’m tired. Bean counting in the late evening is a waste of time; you are likely to miss the most obvious errors. JSLint doesn’t care what time of the day it is and will point you straight to that mismatched curly bracket or misspelled variable that’s at the root of the problem.
JSLint is most helpful if you keep your code clean from the start. If you’ve never used JSLint before and try it out on an application that is already hundreds of lines long, it will flood you with so many warnings that it will feel that it hampers your job more than it helps. However, that only happens the first few times. Once you learn to stay away from bad coding practices, JSLint diagnostics will be few and straight to the point; your real error, the one that’s driving you nuts, will clearly stand out. In the meantime, JSLint will teach you to make your code safe and robust.
So, don’t wait for a tough error to show up. If you have never used JSLint, try it with what you believe to be good code, it might not be as good as you assumed. As Douglas Crockford (author of JSLint) says, “JSLint will hurt your feelings.” But that’s a small price to pay for better code.
Global and unused variables
One of the things JSLint will warn you about is the use of global variables. There should be no global variables except those you know about, such as the ones created automatically like window or document and those for the libraries you are using such as YAHOO (in YUI 2) or YUI (in YUI 3). You may also want to create a single global for your own namespace.
Global variables are dangerous, and there are usually more of them than you’d expect; moreover, “extras” such as mashups and banners might add more of them. Since the window HTML DOM namespace can be omitted from compound names, window.name, window.length and window.location become the global variables name, length and location. Have you never used such variable names in your code? I don’t mean in their HTML DOM sense but as everyday field names in a table — like the name of a person, the length of an object or the location of a book on the shelf. What if you use those variables without declaring them? You might assume that length is initially undefined but, in fact, if you don’t declare your own local copy of it (and initialize it), length will be a reference to window.length. And if you assign something to location, you might accidentally cause your user to navigate away from the current page. Here, I am just giving examples of possible collisions with the browser’s built-in variables, but if you start adding libraries from other sources, the chance for collisions increases. The JavaScript syntax highlighter used in YUI’s examples uses the global variable dp as its root and the number of global variables any Google script might add when you insert a map or other tool in your page is impolite, to say the least.
It’s not merely that you want to step lightly with respect to other people’s variables — by staying out of the global namespace, you reduce the risk that they will step on yours (or that you’ll step on your own). With asynchronous threads weaving themselves around each other, as is often the case in modern JavaScript applications, you can’t really be sure the order in which your various pieces of code will execute and what global variable will be left at what value by whom. The only sane approach is to avoid them whenever possible.
Global variables might also point to a typo. If you have a global variable you didn’t mean to have and you have an unused variable with a similar name, you might have misspelled one of them: that is, you may have declared it with one name and used it with another different spelling. It can also mean that you have declared it after you have used it, which means that at execution time you might find your variable not initialized as you would have expected.
Using this
Using this is often troublesome for beginners because it’s easy to lose track of where we are in the scope chain. Until we get some practice, keeping track of scope can be an issue. Also, developing a coding style and a structure for the application helps greatly; after all, it’s all about knowing where you place things. If you learn to organize your code consistently and store state in logical places (this points to one such place), information in your program will be easy find. Any debugger will show you what this points to at each step. It’s always a good thing to check first if this is referencing the object you expect. A lot of times when we have a bug, it’s be because this is pointing to window. There are several situations that can produce this result.
If we have a method with an inner function, when we call that inner function it won’t get the scope of the caller but rather that of window. This example shows that the inner function doesn’t share the scope of the method within which it is contained:
var someObject = { outerFunction: function () { console.log(‘outer’,this); // prints outer Object {} var innerFunction = function () { console.log(‘inner’,this);// prints inner Window }; innerFunction(); } }; someObject.outerFunction();
There are a couple of ways to fix this. In this example, we ask JavaScript to correct the scope using call():
var someObject = { outerFunction: function () { console.log(‘outer’,this); // prints outer Object {} var innerFunction = function () { console.log(‘inner’,this); // prints inner Object {} }; innerFunction.call(this); } }; someObject.outerFunction();
In the next example, we take advantage of the ability for inner functions to share the variables of containing functions. We create a variable self which we initialize to the value of this in the outer function. We can then use self in the inner function to refer to the outer function:
var someObject = { outerFunction: function () { console.log(‘outer’,this); // prints outer Object {} var self = this; var innerFunction = function () { console.log(‘inner’,self); // prints inner Object {} }; innerFunction(); } }; someObject.outerFunction();
Finally, with events, the scope of the listener is that of the element to which the listener is attached:
var someObject = { outerFunction: function () { console.log(‘outer’,this); // prints outer Object {} YAHOO.util.Event.on(‘button’,'click’,function () { console.log(‘inner’,this); // prints inner <button id="button"> }); } }; someObject.outerFunction();
Unless we adjust the scope of the listener when setting it up
var someObject = { outerFunction: function () { console.log(‘outer’,this); // prints outer Object {} YAHOO.util.Event.on(‘button’,'click’,function () { console.log(‘inner’,this); // prints inner Object {} },this,true); } }; someObject.outerFunction();
This also applies to YUI components. If we listen to a click event on a DataTable cell, a TreeView node or a MenuItem, the scope of the listeners will be those of the YUI component instance that owns the event — unless it is explicitly set otherwise.
Sandboxes for applications
Another good way to keep your code clean is to start with a clean skeleton. The style of coding JavaScript applications has changed over time. Nowadays, most developers use two different styles: one for applications and one for library components. Most YUI 2 examples reflect the old style, where we used YAHOO.namespace to create a namespace for our own code.
Nowadays, for our applications, we mostly use a single sandbox declared within the scope of an anonymous function that executes onDOMReady:
YAHOO.util.Event.onDOMReady(function() { var Dom = YAHOO.util.Dom, Event = YAHOO.util.Event, Lang = YAHOO.lang; var yourVariable = initialValue, moreOfTheSame = otherInitialValue; var myFunction1 = function ( …) { // body of function; }; var myFunction2 = function (… ) { // body of function; }; … });
This technique has several benefits.
We define our functions. We can do this with the var statement, as I did above or the function statement; there is a subtle difference but it is mostly irrelevant. I use the var statement to highlight that they are just as accessible as the other variables: we can access them anywhere in the sandbox.
Of course this relies on the ability of JavaScript to allow us to define functions within functions and on the fact that the inner functions have access to all the variables defined in the outer function. Basically, each function you define creates a new local environment accessible to any further functions within.
Sandboxing is the standard way of doing things in YUI 3:
YUI().use(‘module1′, … , function (Y) { // This is the sandbox });
Namespaces for libraries
While the sandboxing technique is great for final applications, it’s not good for libraries. What happens in the sandbox stays in the sandbox, completely invisible to the outside world. However, when you define a library utility or component of your own, you want to re-use it, so it needs to be globally accessible (which is not the same as being purely global). Anything you define under YAHOO.example — e.g., YAHOO.example.myUtility — is globally accessible. You can access it by its full name once it has been defined. myUtility, as a member of the global YAHOO, is not global but it is globally accessible.
When we build libraries, we usually use the sandbox for our code and namespacing for sharing, like this:
(function () { var MyClass = function () { // this would be the constructor }; MyClass.prototype = { // properties and methods }; YAHOO.namespace('MyLibrary'); YAHOO.MyLibrary.MyClass = MyClass })();
We create a sandbox by defining everything within an anonymous function, which we immediately execute (see all those parenthesis there?, they mean 'take the result of defining this function and execute it'). Here, we don't wait for the DOM to be ready; libraries seldom do, since the application that uses them is responsible to check that everything is in place. Within the sandbox, we have the same advantages as with the previous sandbox. We can define short names for anything we use often, even for the class we are defining: none of them will be visible outside. Then, to make it globally accessible, we create a namespace of our own and place our recently created class in it.
YUI Logger
Let's say we have our code nice and clean, with no JSLint errors or warnings, but we still have problems to debug. YUI can be helpful in telling us what's wrong. For production code, we will usually load the minified versions of the YUI components, but there are also two other versions. The -debug.js version is the one that can help us uncover problems. For example, we might be using Dom Collection's method setStyle to, lets say, change the color of a block of text. The change doesn't happen and we can't find what's wrong. The file dom-debug.js has this helpful line, which is deleted in the -min version:
YAHOO.log('element ' + el + ' is undefined', 'error', 'Dom');
This is executed when setStyle tries to locate the element to be styled and does not find it. The error message will probably show a misspelled element id or some such error that is so hard to pick after a long day of staring at the same code.
It's easy to get the logger up and running; you just need to include its files:
<link type="text/css" rel="stylesheet" href="http://yui.yahooapis.com/2.8.1/build/logger/assets/skins/sam/logger.css"> <script src="http://yui.yahooapis.com/2.8.1/build/yahoo-dom-event/yahoo-dom-event.js"></script> <script src="http://yui.yahooapis.com/2.8.1/build/dragdrop/dragdrop-min.js"></script> <script src="http://yui.yahooapis.com/2.8.1/build/logger/logger-min.js"></script>
The basic yahoo-dom-event aggregate is most likely to be there already while the Drag & Drop optional dependency is handy to move the logger window out of the way. Then, just add:
var myLogReader = new YAHOO.widget.LogReader();
Then, it's a matter of loading the -debug versions of the component files and all the messages they produce will be shown. The amount of information can be overwhelming so, it is wise not to load all -debug versions at once. The Logger can also filter the information it displays and you may uncheck the Info category of messages to concentrate on Warn and Fail. The filters do not affect what is logged, only what is shown; Logger logs all messages, regardless of whether the LogReader displays them or not. There is only one message queue per application and logging will start as soon as the Logger component file is loaded, it doesn't matter whether it is shown or not.
Another power-user strategy for YUI debugging with the Logger Control is to take advantage of Logger's ability to leverage the browser's console (in supported browsers):
YAHOO.widget.Logger.enableBrowserConsole();With this line of code, you can pipe all Logger messages to the browser console, which is a natural part of your workflow in development in any case.
The only tedious thing about the Logger is remembering to change the component files from the minified, aggregates and combos to the -debug versions. In this, as always, the Dependency Configurator is a great help; click on the -debug button on the top left and it will produce the correct list of files.
And, now that I've mentioned it:
Check your dependencies
It's a good idea when you start with YUI to pick an example that closely resembles what you want to do and modify it. As you add more features, you take bits and pieces from other examples and incorporate them into your developing application. One frequent source of problems are the dependencies. Many people paste the dependency files of each and every example into their application, duplicating some of them over and over again. Missing, duplicate or out of order dependencies might produce unexpected errors. Not having the YAHOO Global Object loaded before anything else is most certainly going to be fatal. At any rate, loading something twice will certainly increase the time it takes your page to load.
Finally, if you are using your own servers to load the YUI library, you might have the base path for your copy of the library wrong. If you have Firebug, go to the Net tab and check that there are no lines in red. Those would mean that a requested resource could not be found.
Debugging
The Firebug add-on for Firefox is still the best debugger around, plus it is free. By default, when the debugger is activated the "Break on all errors" option is on, which means that Firebug will stop at the point where it finds an error and show the error message and source code. Some of those errors will be the same that JSLint would have diagnosed, so JSLint is still the first place to start — especially because Firebug can only signal one error on each run while JSLint can signal them all at once. Some errors will only show up at runtime, so the debugger is the only option. Whenever you get to such a break, the first thing to check is this, a four-letter word of the trickiest sort.
When using a sandbox, debuggers will usually show local variables and arguments, but they will not normally offer to show the variables in containing functions, such as those declared in the sandbox and used from within the inner functions. The debugger will be able to show their value if you explicitly ask for them by name, but it will not show them automatically. Another alternative is to make them globally accessible. For example, since YAHOO.example is always available (when YUI 2 is on the page), if you want to keep an eye on a certain component at all times you can simply copy it there:
var myTree = new YAHOO.widget.TreeView('tree-container'); YAHOO.example.myTree = myTree;
We add the last assignment while debugging so we can keep an eye on the TreeView instance while debugging since myTree would normally be within the sandbox and invisible elsewhere.
Don't use members starting with underscore
Many people use the debugger to look for the names of variables or properties holding the information they need. Sometimes that information is stored in properties starting with an underscore, like _nodes. By convention, those are private properties, not for general use. JavaScript enforces no true concept of private or protected members; thus the leading underscore is the conventional way to signal the intent of the class developer to keep that property private. These properties can present a temptation (after all, you can see them there in the debugger), but there are a couple of good reasons why it is not wise to use them in your programs.
First, only public interfaces are supported. Since you are not supposed to use a property starting with an underscore, the class developer is free to change it at any time. The developer should have provided some public mechanism to access this same value; for example, a _nodes private property might have a getNodes() method or a nodes configuration attribute. Either of these would be the public interface to that same value. The second reason not to use properties with leading underscores is that their accessors might need to produce a secondary effect which accessing the private property would completely bypass. The component would then be left in an inconsistent, fragile state.
So, if you are using the debugger to look for a value and you find it in a property starting with a leading underscore, don't use it. Go instead to the API docs and look in the Methods index for some getXxxx() method with a similar name or in the Configuration Attributes index. Avoid using private variables.
Stack Traces
The YUI library is robust and reliable. If the debugger breaks within the YUI library, it's more likely that it is because of an error induced by your code that by some failure in YUI itself. JavaScript was designed to carry on, always coping with errors as best as possible. The YUI library does likewise. The -debug versions will have extra checks and will emit diagnostic messages, but they are all stripped out in the minified versions. If you see an error in a YUI file it is likely that it got there out of pure stubbornness, but don't try to find the error there. When the debugger stops it is not because it has found the cause of the error but because the JavaScript interpreter can no longer carry on.
Breaks in minified files are not helpful, if you get a message such as...
F is not an object in line 7 of dom-min.js
...it is pointless to ask in the forum about it. First of all, F is an alias generated by YUI Compressor to replace a longer, descriptive variable name in the original uncompressed file; secondly, the first few lines of a component file are usually taken by the copyright notice, which the YUI Compressor always respects. And since the YUI Compressor also deletes all new-line characters, as it does with other white space, all the executable code in dom-min.js is in lines 7, 8 and 9 — so the line number doesn't say much either.
That is when the Stack Trace tab in the right sub-panel of the Script tab of Firebug (or wherever you can find the stack trace in your debugger) comes handy. It tells you how you got there. Here is a screen capture from Firebug:
The item on top of the right panel, createEvent(), is the name of the function where the current statement is; the one below is the place where createEvent() was called; the one below that the function that called the previous one; and so on. Most debuggers will let you select any of those trace points and see how you got to where you are. Firebug also lets you check the value of the variables at each of the trace points. We can see in the left subpanel the yellow arrow pointing to createEvent(). We got lucky this time, as it will always point to the line containing the offending code, but that code might be anywhere within that line; fortunately, createEvent()happens to be at the beginning of the line. See the variables and arguments? B, G, L...there is no guessing what the original names could have been, as this is the YUI Compressor at work. However, note that YAHOO is untouched and the copyright notices are preserved.
You might not recognize many of the names in the stack trace, as they might be functions within functions within the YUI library itself. Eventually, you might see function names you recognize. In this image, I know showAlbums, which calls the constructor for the REDT class (which is code I wrote). I don't have a clue about anything else. That's where I will go looking...to the ones I know.
If you are not sure, you can go through the full list. If you see compressed code (assuming you have not compressed your own yet), simply ignore it, or switch to the non-minified version of the YUI source files. But focus primarily on those names you recognize that belong to your own code. Note that Firebug uses (?)() for traces it cannot name. Usually, your code in the sandbox will be signaled that way since the sandbox is contained in an anonymous function. At any such point in your trace, check the values of the variables you provided as arguments; some of them might not be what you assumed. Check them against the API docs to see if it is a valid argument value.
If the argument and variable values you see are inconclusive, at least you can place a breakpoint right before your code calls the YUI component. You might then be able to see how you got into the mess.
Stack traces are often ignored by developers but with JavaScript's tendency to keep digging itself into an ever deeper hole as it tries to carry on, it is good to be able to come up to the surface to look around. As with all debugging techniques, it might not always work, but it is nice to know it is there. Let's be honest, if you have read this far, you know what desperation is.
Asynchronous calls
A lot of the interactivity that characterizes Web2.0 apps is based on the ability to handle asynchronous events. In contrast with the original style of web applications, where every interaction involved waiting for a new page to be delivered from the server, the modern interactive applications involve setting things up and listening for any of several possible events to happen...and then responding to those events. We set listeners for clicks or keystrokes and or other programmatic events; these are usually intuitive. Asynchronous calls and their callbacks, however, often are harder to understand.
The most common error I see in implementations on the forums is to place code right after an asynchronous call such as Connection Manager's asyncRequest()or DataSource's sendRequest() methods, assuming that such code will be executed when the operation is completed. When you call such a function, you are just priming the operation, not executing it in full. No data will be available after the call to the async method. Only the request for such data would have been produced so far. The server must receive it and process it, and the reply (if it ever comes) is still off in the future. That is why for such asynchronous operations we use callback functions.
A callback is like the function we assign as a listener for an event such as a click on a button in a form; when the user clicks, the listener gets called. The callback on a asynchronous event is very much like this; just as we send a form for a user to fill in, we send a request message to the server, and just as we wait for the filled-in form to be submitted back to our program, we wait for the reply sent by the server to come back to us. We cannot know when the user will submit the form or the server send the reply; that's why we set what for a user action we call an event listener and for an asynchronous event we call a callback function. It might seem the server reply is fast if not instantaneous, but it means ages in CPU time.
Debugging asynchronous calls
Sometimes there is no alternative but to single-step through the code. Be careful when you get to asynchronous calls such as Connection Manager's asyncRequest() method, DataSource's sendRequest() or DOM's window.setTimeout(). These start an asynchronous request for data against the server or delay some action a given time and their callbacks get called when the data has been received or the time has elapsed. There are two issues to consider; first, the debugger won't step into the callback automatically. If you want to catch up with the reply, you have to put a breakpoint inside the callback function. Lots of people reach the point of calling the asynchronous method and expect the single-stepping to resume within the callback when the async operation is finished. This will not happen; the thread of execution does not flow automatically into the callback, and the debugger cannot be expected to figure that one out.
Second, when you reach the line with the asynchronous call, put the breakpoint in the callback and then let the application run. Usually, whatever goes after the async call is not really important; in fact, the async call is normally at the end of a function, since there isn't much to do until the reply arrives. Don't single-step over the async call, because the debugger will keep the JavaScript interpreter on hold and, when the reply arrives or the time lapses, it will be missed since the interpreter was frozen and unable to handle it. So, if you were clicking on Step Over, when you get to the async call, make sure you have the breakpoint in the callback and then click Run so the JavaScript interpreter is active and able to handle the reply.
For repetitive events such as callbacks to window.setInterval() or other time-critical operations, it is better not to put breakpoints in them. While you are on hold, many events will be missed. It is usually better to use console.log or the YUI Logger to simply signal that the event is happening and show a few critical values. Don't use window.alert() for the same reason; it puts a hold on the browser and the events you care about will be missed.
Conclusion
There are many tools to help us find out what is happening in our programs. With the proper tools at hand, we can find an error in less time than what it takes us to write a question in the forums. The first step, however, is to write good and reliable code and make JSLint an integral part of your development process.
We’re making Search more intuitive by taking user context and applying it to the search experience. Today we are introducing an enhanced Yahoo! Search Assist, providing suggestions geographically closer to you as you type your query.
Sitting here in our Yahoo! headquarters at Sunnyvale, if I type “santa” from Yahoo! headquarters in Sunnyvale, California, I get “santa clara county” as the first suggestion.
If I type the same query from my friend’s place in Santa Barbara, I get “santa barbara” as the first suggestion.
Here’s another example that commuters in the New York and Pittsburgh metropolitan areas will appreciate: As I type “port au” from the New York area, I get “port authority bus terminal” and suggestions prioritized for New York’s Port Authority.
But if I’m in the Pittsburgh area, I’ll see more locally relevant suggestions like “pittsburgh port authority” and “port authority of allegheny county.”
Yahoo! Search Assist helps you find what you need with fewer keystrokes by taking into account the location from which you’re searching.
Give this new feature a try and let us know what you think about geo-sensitive search suggestions in the comments section below.
Vivian Lin Dufour
Product Manager, Yahoo! Search
They say the first bite is taken with the eye. If so, these appetizing restaurant websites succeed in whetting our appetites, inviting us to a savoury next bite. In these designs, color scheme and introductory copy show vastly different aspects of the restaurant experience. Moody warm tones create atmosphere, vibrant greens underscore freshness, and earthy colors communicate a relaxed, friendly attitude.
Because customers are increasingly using mobile browsers to make decisions on the spot, restaurant websites are doing a better job of communicating core information quickly. Similarly, full Flash websites with no mobile alternatives are seeing some decline. Especially interesting is how these businesses are improving their online menus by replacing PDF-only downloads with Web-optimized alternatives that are more readable and easier to navigate.
Posted by randfish
It's been a wild few weeks at the mozplex. Today wrapped up the amazing mozinar with our half-day tools training just in time to launch the new version of SEOmoz. Should we slow down this crazy pace? Nah.
If you're feeling a sense of deja vu, don't worry; it's perfectly normal. We're the same old moz, but with a new look, faster loading pages and a surprising amount of new functionality. Let's walk through it together, shall we?
Big Improvements to PRO MembershipIt's a good day to be PRO; we've just released:
• A brand new PRO Dashboard, that's designed to be the center of everything you can do with your membership, including access to your web app campaigns, tools and tool reports, webinars, Q+A, discount store, etc. If it's part of PRO, you'll find it in the Dashboard.
• The web app has made some big improvements and we're now announcing a full public beta - campaigns should be faster, more accurate and dramatically less buggy. There's also some cool new functionality I'll cover below.
• The dramatically upgraded SEO Tools page, which will likely show off plenty of tools you may not have seen/heard about until now.
• Slide decks from our PRO Tools Training are now downloadable. We had a highly interactive, terrificly valuable day sharing tips, tricks and applications for the data and resources and wanted to give you a small taste of that experience by making those slides available.
If you've been curious about what's in PRO membership, there's a new PRO Tour section that gives you a more complete look at the features and functionality. Also - the last chance to get PRO at $79/month and be locked into the rate before it rises to $99 is now - after Friday, the price change goes into effect.
Zoinks! A New SEOmoz WebsiteRub your eyes a bit and have a look around. We've done a considerable amount of work to make pages load faster, let the design highlight the content in a cleaner fashion and added a few fun bits, too. Big changes include:
• A new home to Learn SEO. I've recorded an "Intro to SEO" video and we've made all of our learning-focused content available through that page (nearly all of it is entirely FREE!)
• A renewed focus on YOUmoz and the Blog (both of which are featured more prominently on the homepage). We've re-designed all of these to help make them more useful and usable, as well as focusing on the content itself with a less-intrusive design. As always, we've kept a strong focus on comments and participation and we're planning to do even more with it in the future.
• More accessibility to our SEO tools, including a free sneak peek at our LDA Labs tool (more about that in my next post)
There's lots more coming soon (a new about section, upgrades to the marketplace, more free information in the Learn SEO section, etc.) so keep an eye out.
The Web App is Now in Public BetaOur private beta launch to PRO members had more than 2,000 folks create thousands of campaigns. While the feedback has been phenomenal (your very kind tweets really helped keep our engineers pushing through sleepless nights and crates of pizza), we know there were a lot of bugs and missing functionality in the early release. Starting today, the app is far more stable, speedy and powerful. Crawls should come back consistently, rankings should more consistent and accurate and issues/recommendations are rocking.
We've also added a brand new feature - one of our most requested - exportable PDF reports for rankings (with crawl diagnostics and on-page reports coming very soon). As Adam Feldstein, our head of Product, discussed today in his roadmap presentation at the tools training, next on the list is additional crawl issues, Google Analytics integration and exciting new functionality for competitive comparisons in the link analysis tab.
As always, we welcome feedback - your messages have been instrumental in helping us improve, and while we're feeling good about this wider launch, the web app is likely staying in beta for another few months as we add features and continue to tweak, bug fix and get better.
Still Ironing Out Some KinksThere's a few known issues with the new site that should be cleaned up in the next 12-24 hours. These include a bit of CSS oddness on the Beginner's Guide and the Keyword Difficulty tool (though both still function), the thumbs highlighting being a bit softer than intended (for thumbs up/down you've already left), some headline/text font sizes and spacing, etc. Sadly, we've also temporarily broken the long beloved functionality of highlighting "new" comments in a post - that should be back soon.
I also noted that we had some issues with Domain Authority in our last push of the Linkscape update. Amazingly, thanks to the hard work of our engineering team, we're expecting to have new scores up in the next few days (rather than taking a full 2 weeks). We still need to run some tests, but we're hoping to fix many of the odd outlier issues.
We Love Your FeedbackIf you see anything you love, hate or think might be an error, we'd love to hear from you. Every page on the site now has a "Feedback" button on the far left-hand side and we read those obsessively! Of course, you can also leave us comments on this post.
Thanks so much for joining in the adventure that is SEOmoz. In the weeks and months to come, well.... let's just say you ain't seen nothing yet :-)
Today we are glad to release iCandies Icon Set, a set with 60 high quality icons in 64×64px, 48×48px and 32×32px, available in .EPS, .AI and .PNG. The set is designed by the talented folks from IconEden on a sole purpose of giving your projects a sleek and geeky style or provide crisp, attractive icons for your modern and fashionable-looking interfaces. All the icons in this pack — 60 icons in total — are designed in Round Rectangle shape.
You can use the set for all of your projects for free and without any restrictions. You can freely use it for both your private and commercial projects, including software, online services, templates and themes. The set may not be resold, sublicensed or rented. Please link to this article if you want to spread the word.
In celebrating the merits of free software and the excitement over this radical networked production method, an important truth is left unspoken. Networked collaboration shines in the low levels of network protocols, server software and memory allocation, but user interface has consistently been a point of failure. How come the networked collaboration that transformed code production and encyclopedia-writing fails to translate to graphic and interface design?
The following is an investigation into the difficulties of extending the open-source collaboration model from coding to its next logical step: interface design. While we'll dive deep into the practical difference between these two professional fields, the article might also serve as a note of caution to think before rushing to declare the rise of "open-source architecture," "open-source university," "open-source democracy" and so on.
Posted by Dana Lookadoo
This post was originally in YOUmoz, and was promoted to the main blog because it provides great value and interest to our community. The author's views are entirely his or her own and may not reflect the views of SEOmoz, Inc.
I’m going to speed through the 2nd half of the 1st day at the SEOmoz Pro Training Race Track. Recall that 9 speakers raced through topics covering clicks to conversions.The following are highlights of the end of the race for Day 1.
Presentation Off
Insights distilled also included the business side of pitching SEO. Will Critchlow and Rand Fishkin dueled it out for their "Presentation Off" to determine who could give the best advice for “How to Pitch SEO.” This marked the first time they “faced off” in battle on US Soil. Will held the winning title to date. Bottom line, both of them presented valuable insights about pitching and when not to pitch (or bother).
Takeaways from Will Critchlow, The Champion:
Download Distilled’s SEO Traffic Model spreadsheet. http://dis.tl/dk6N59 <nice!>
Takeaways from Rand Fishkin, The Challenger:
Rand focused on the emotional side and winning minds of the in-house SEO
Rand showed graphs and slides on how to show value based off ROI - showing the value of their traffic:
<If you're taking notes, you can see how this would fit into a spreasheet...>
Then explain search growth over time - meaning, search is growing, period! If they are not adding 20% budget to SEO, then they are falling back.
“Every day, there are more than a billion searches for information on Google. These people have specific intents. If you’re not adding 20% to your SEO budget this year, you’re falling behind the average."
Show prospective clients which competitors are winning for their keywords:
And the winner of the Presentation Off is ... Rand Fishkin, who edged over the finish line just in front of Will.
OK, let’s catch the replay highlights of the rest of the search marketing race.
Joanna Lord drove the fastest car, “The End of Analysis Paralysis.”
She explained it’s time to get serious with metrics and conversions:
1. What is your website trying to do?
2. If one metric could identify that you are succeeding or failing, what would it be? How would you know you are gaining or losing ground?
3. What is the biggest threat to your success?
You should only have 3 or 4 metrics, no more than 5. (Focus)
Joanna then sped around Google Analytics advanced filter fun, including:
Joanna was stopped in her tracks when she polled the Mozzers to find out how many were using Multiple Custom Variables - 2 hands raised.
MCV is the ability for us to tag visitors for any number of interactions on our site. It goes beyond the single user-defined variable _setVar() and replaced it with _setCustomVar().
Multiple Custom Variables give us the ability for us to tag visitors for any number of sessions to enable “first touch” attribution rather than Google Analytics default “last touch.”
Resource: How to do First Touch Tracking in Google Analytics
Joanna then screeched around the corner to present her Advanced Analytics Checklist:
Whew... surely it was time to full-up again after that session, but no... more typing at high speeds:
Marshall Simmonds - Site Architecture & Best Practices for Big Site SEO
Marshall Simmonds is a seasoned Enterprise-level SEO and works with the NY Times, previously with About.com. Working on large sites requires triage and prioritization. (Race car drivers overlook a chip in the paint when the carburator blows out.) Any level of SEO can view the following triage tips for their own site to determine where to best spend their time:
High Priority Tactics:
Low Priority Tactics:
Focus on best practices for the long term. Marshall often recommends you don't budget for an SEO project. Putting a dollar amount to it turns it into a a project with an end point. SEO doesn't have an end point.
Marshall proceeded to explain that the NY Times is a duplicate content factory and has some SEO challenges. As a news property, they dramatically see the importance of the following principle:
Optimize all assets!
Ask: Are there any assets that you are not optimizing? If not, then competition is beating.
Key takeaways for all of us in the SEO race:
Bottom line, add as many analytics packages that you can afford, optimize, track and prioritize.
Tom Critchlow
Keyword Research & Targeting Tom Critchlow of Distilled explained that you need to group all keywords:
Keyword harvesting tools:
The following is a shot of how to use Mozinda to review tags on Delicious.com. (You can look at Delicious tags without using Mozinda.)
Discount code that applies to full pro plan: seomoz20 (Valid till Sep 15th 2010.)
Build an SEO friendly CMS:
Below is a wireframe template for an ideal CMS that pulls data in:
Discussion raced through use of APIs for scraping content from the Web and incorporating on your pages to include additional keywords. The boxes on the right represent ideas for pulling in the following:
The Mozzers had lots of questions from the audience about this CMS concept, and Tom’s answer was:
It’s not that hard! <sigh> Tom then gave away a proof of concept Google doc that scrapes Google suggest and Google search.
Thank you, Tom!
Lindsay Wassell - Constructing Effective SEO Audits
Lindsay Wassell got deep under the hood like no one else has done at a conference to show her approach and outline of SEO Audits, starting with her daily schedule. I especially liked that she set a schedule to focus on one client in one day and allow time for lunch to ponder your findings and approach.
Tip: Allow ponder time & 6 weeks or more to deliver an audit. Give it enough time.
The following SEO Audit Outline lays out a suggested framework:
She incorporates a Scorecard for rating issues with a 1-5 rating scale:
Some Scores are site-wide and some scores are finding-specific.
She placed importance on showing visuals and also providing an actionable Executive Summary. SEOs realize that a 40-page audit is likely to set on someone’s desk for weeks or months. Give them takeaways they can begin working on now.
Tim Ash – 7 Deadly Sins of Landing Page Optimization
The final race of the day focused on after the click – conversions. Discussion included importance of considering what you do with all that SEO & PPC traffic after they arrive at the site.
Tim Ash did a poll at the end of the race day to see how many Mozzers were doing Conversion Rate Optimization (CRO). Almost 1/2 of the room raised their hand.
Tim starts with insults – You are ignorant and blind. He then asked:
How many of you have talked to the end user in the last quarter? Well, only a few admitted to talking to website users ...
Tim showed us how to avoid the following 7 Deadly Sins of Landing Page Design:
We all left the SEOmoz Raceway convinced that our baby is ugly and tips to optimize and beautify our website babies.
The US Open is heating up on Yahoo! Search. This week we are launching the US Open Shortcut to help you find the information you want when you search for the championships.
Whether you’re a dedicated fan or just want to check out Maria Sharapova’s outfit, simply search for ‘US Open’ or your favorite player. You will find real-time scores and schedule of the day, news, photos and tweets. Did you know many tennis players love to tweet?
This is an exciting time for tennis fans: for the number one seed Rafael Nadal, who has never won the US open title, this can be finally his year. Or could the winner be Roger Federer, who won last week in Cincinati, his first title in seven months?
No matter who you’re rooting for, we hope you’ll use our Shortcut to follow coverage of the US Open.
Yuko Kamae
Yahoo! Search
It’s summertime and the livin’ is easy, but at Yahoo! Search we’ve been busy fielding queries about everything from Kermit the Frog to Zsa Zsa Gabor.
Early in the month US users showed interest in Ramadan, the month of fasting which began on the evening of the 10th. Searchers looked for the meaning of Ramadan, activities for children, and even “Ramadan text messages.” Searchers on Yahoo! also looked for biography, commercials for Ben Quayle, son of former VP Dan, as he takes the GOP congressional primary in Arizona.
Celebrities (and their children) continued to fascinate searchers throughout August, and we saw spikes in queries about Montana Fishburne’s adventures in adult entertainment, Tiger and Elin Woods’ pricey divorce, and the on-again-off-again relationship of Bristol Palin and Levi Johnson. Also on users’ radar were Lindsay Lohan’s release from rehab and singer Fantasia’s tumultuous personal life.
Human drama around the globe captured the attention of the many Yahoo! users who wanted more information about the catastrophic floods in Pakistan and the plight of the trapped Chilean miners. Searches for “map of Chile” jumped 60 percent in the last week of August, and searches for “trapped miner update” continue to spike through the past two weeks.
Drama of another kind was also popular as shown by the surge in searches for the McNugget rage video and for information about JetBlue flight attendant Steven Slater, whose show-stopping exit from flight 1052 may lead to a whole new career in reality television.
Yahoo! Mobile Searchers were busy this month, too, tapping in queries about topics ranging from floppy haired teen favorite Justin Bieber and the NFL preseason to more serious subjects including California’s Proposition 8 and the 14th Amendment of the US constitution.
As August ended, we saw searches about the 5th anniversary of Hurricane Katrina as well as in the upcoming hurricane season. Searches on Kermit the Frog spiked with the announcement that the original puppet will be displayed at the Smithsonian – proving that it is easy being green! And users who couldn’t wait for fall were already inquiring about back to school searches like lunch box recipes and costume ideas for Halloween. It’s not too early to plan for Halloween, even for the tiniest trick-or-treaters: searches for “baby Halloween costumes” spiked over 720% in August.
Can’t wait for our monthly recap? You can check out the weekly Yahoo! Trends segment on ABC News. This week, Yahoo!s Pamela Woon dishes on popular search topics like Puppy Tweet and the Emmys.
Check back often at the Yahoo! Search Blog’s Search Trends section to find out what’s buzzing on the web.
Mireille Majoor
Yahoo! Search Blog
Posted by Dana Lookadoo
This post was originally in YOUmoz, and was promoted to the main blog because it provides great value and interest to our community. The author's views are entirely his or her own and may not reflect the views of SEOmoz, Inc.
Day 1 of SEOmoz Pro Training was like being at a race track. The course careened from clicks to conversions and from search results to landing pages. The audience watched 9 speakers drive their search marketing race cars at speeds faster than fingers can type. Given the finger-breaking speeds, it was fortunate all SEO fans were well fueled - beginning with a healthy breakfast buffet, mid-morning energy bars, lunch (more all-you-can-eat) and a scrumptious mid-afternoon pit stop with fresh cookies and treats. After everyone was fed each time, it was off to the races.
Todd Freisen was in the sports booth service as emcee, host of ceremonies, referee, judge and time keeper. The event was like a well-oiled machine. Maybe that's why they call Todd, "Oilman."
When I said "yes" to attending the Mozinar on a Press Pass, I didn't realize I was going to be covering a sporting event. GoodNewsCowboy asked me how I was going to recap and condense this "wild ride." I realized there was a lot of horsepower on-stage and that we were at the SEOmoz Training Raceway.
Mozinar fans experienced exhilaration and gleaned insights as we watched performance race car drivers present their seminar presentations. The following race highlights are condensed from 32 pages of notes. I strongly suggest you buy the Pro Seminar DVD when it's produced so you can see under the hood for yourself.
From Clicks to Conversions with Local, Social, Analytics and SEO in Between
1st up: Rand Fishkin had pole position and drove a car with a most unusual name, "It's a Mad, Mad, Mad, Mad SERP."
The results we are seeing in blended search results are even more unusual, starting with changes of the past 2 weeks. For those who attend SEO races regularly and are watching Google, this may be old news. For others, brace yourself. A branded search can have more than 2 results. Rand explained:
Changes to Image SEO was next, and guess what? Google has a new image search interface.
The image below results from clicking on one of the images for the artist "manet" and clicking on an image
Tip: Write some JavaScript that breaks the overlay to avoid having the image overlay. Not only does it produce the longest, ugliest URL, but "it’s just an invite to right click and steal this image."
Rand covered 10 Tips for Image Rankings. (Since we are in race synopsis mode, we'll speed through this.) One quick takeaway was the minimum image size:
Image Pixel Size - If you go smaller than 400x300 pixels your chances to show in image search are dramatically decreased.
So you don't have to remember any formulas, basic on-page SEO factors for image SEO include page title and surrounding text.
Video SERPs
It’s or easier to get into video SERPs than to get into the regular SERPS. There is lower competition than ordinary results (most of the time), so take the opportunity. Follow this inclusion process to enter your video race for top ranking:
Step #1: Embed Video Content on Your Pages
Step #2: Create Thumbnail Images for Videos
Step #3: Build a Video XML Sitemap & Submit
Step #4: PROFIT $$$
See Google Webmaster Tools for Video to learn more.
Rand's foot stayed pedal-to-the-metal as he showed how to produce Rich Snippets in the SERPs. Why is this important? This is where you get most of your clicks. His closing remarks were retweeted with fervor:
"If you can stay on top of this, you will have a big win. It demands full-time SEO."
2nd up: David Mihm was full-speed as he raced through "Ranking in Competitive Local Results." He explained:
Straight from Google’s mouth:
Local intent is 20% of total search volume (April 2010)
And who would imagine that local results could equal 100% of page 1? Try a search for "dentist chicago." (If it's not 100%, it's close.)
Google organic results are not, however, the dominate factor for local search. Neither are results from Yahoo! or Bing. Local search is now:
Understand that local requires a different mindset from traditional SEO, because the ecosystems vary:
Takeaway:
"It is essential to have a holistic local search marketing strategy."
"Even if all your boss cares about is that friggin' 7-pack!"
Resources to claim your listings:
"The Big Three" major data providers:
Citations - David recommended a new citation finder tool by Darren Shaw & Garrett French: Whitespark.ca Citation Finder
Find local SEO resources on GetListed.org.
3rd up to race: Dan Zarrella racing in the "Science of Twitter" car. Dan warned us he talked fast. Pro Seminar attendees listened attentively, but given the subject was Twitter ... many tweeted insights into how one can get clicks and retweets.
Dan's takeaways were in 140. Below are my fave top three:
Takeaway: Don’t talk about yourself so much.
Paraphrased: If you want more followers, stop talking about yourself!
Takeaway: Try to stay positive.
If you want to get bummed out, people can go on the News. Even if talking about the oil spill, stay hopeful.
Takeaway: If you want people to click your links, Tweet slower.
Don't "go Oprah" on your Twitter account, moderate.
Improve your "retweetability" factor by including a combination of the following Top 20 Most Retweetable Words:
Timing for retweets:
Links posted on the weekend and at the end of the week have a higher click through rate.
Tip: Want to see how well a bit.ly link is doing, CTR?
Alright ... one more Twitter insight before we close ...
He had noted that women follow a lot more people and tend to tweet more. They are more social. (We already knew women talk and socialize more, but now Dan's numbers confirm it.)
Dan covered a lot of geeky ground focused on the science and study of social media, use of FourSquare and more.. I have 5+ pages of notes from Dan's presentation alone. But I'm concerned this blog post will get too long to be readable.
Check out Dan's set of social media tools.
4th up and last race of the morning was the "Presentation Off" between Will Critchlow and Rand Fishkin.
I'll expand on that race in a follow-up post. Do you want to guess who won this year? Will went into the race with a 2-year winning streak.
Desktop wallpapers can serve as an excellent source of inspiration. However, if you use some specific wallpaper for a long period of time, it becomes harder to draw inspiration out of it. That’s why we have decided to supply you with smashing wallpapers over 12 months. And to make them a little bit more distinctive from the usual crowd, we’ve decided to embed calendars for the upcoming month. So if you need to look up some date, isn’t it better to show off a nice wallpaper with a nice calendar instead of launching some default time application?
This post features 75 free desktop wallpapers, created by designers across the globe. Both versions with a calendar and without a calendar can be downloaded for free.
Please notice:
So what wallpapers have we received for September 2010?