More UI Lessons from the Real World (Second Part)

This is the second part of my UI lessons from the real world article. It has more funny examples of what (not) to do with your UIs.

You guessed it, folks. After the huge success of my first article Ten UI Lessons from the Real World, I decided to write the second part with more examples. Again, the idea is to teach UI lessons based on real world images that are funny and interesting for this type of discussion.

Lesson 11 – Don’t redefine concepts

curvedPlease look at the image on the left. Why on earth would someone call a banana a “curved yellow fruit”?! OK, it is curved, it is yellow and it is a fruit, but WTF?

If you don’t know how to call a certain thing, please ask the business analyst. Don’t try to create a name that is meaningful to you but meaningless to the user. Applications should have standardized concepts and the whole team should understand them. FYI: this field of research is called ontology and it is a great domain analysis tool.

Lesson 12 – UIs should never surprise the user

bibleThe UI should never surprise the user. If it does, then the designer has failed to do a good job. One example of this problem is a link that doesn’t look clickable. This is actually conflicting with the idea that UIs should be clear and intuitive. How can something be surprising and intuitive at the same time?

Joel Spolsky has explained this lesson on his bookUser Interface Design for Programmers. Refer to the book if you want to see more examples on this problem.

Lesson 13 – UIs should never scare the user

Users shouldn’t be scared by the UI. If they are, they won’t use the system correctly and you will fail as a software engineer. If something can go wrong, it is your responsibility to create restrictions that will prevent wrong actions (unless the business itself is risky – e.g., trade market).

scary1

Lesson 14 – Don’t ask users to do stupid things

The UI should never indirectly imply that something stupid can be done. You somehow tease the imagination of those people that have low IQ scores and have nothing else to do in life:

stupid2

Lesson 15 – UIs should be easy to read

clockOne of the ideas behind simplicity is that UIs should be understandable and easy to read. The clock on the left is an example of how things can get critical if you must read it immediately. Of course you know the position of the numbers, but imagine different situations where you must read them (e.g., the clock is rotated 90 degrees). Since you need some seconds to calculate the numbers, this will distract (and even disturb) you more than needed. By the way, what time does the clock show right now?

Lesson 16 – Users should never ask “What is this?”

whatWhich animal is this? Is this a cat? A bunny? Some people say it is a small camel! Use your imagination 😛

Users should never ask questions like “What is this?” when it comes to your UI. If they do, the designer has failed to create a good intuitive interface. UAT (User Acceptance Tests) is a great tool to find problems in this sense and you should talk to your team about this. Watch how your friends use the software application and ask them to do certain tasks (e.g., open a new document; create a new invoice, etc). You should also talk to the support team and see what people have been complaining about. You will learn a lot from that, trust me.

Lesson 17 – Don’t distract users with obvious messages

Please look at the next two signs and think. Are they useful in your opinion? What is the chance that you won’t see the stairs, but will see the sign? Or what is the real value of the second sign and its warning?

obvious

Please don’t add obvious messages to your UIs because they will distract (and probably disturb) your users. UIs should guide the user, not force them to look at every detail on the screen. Their eyes should do this job seamlessly.

Lesson 18 – Accessibility should work in practice

disabledWe all know that accessibility features (in general) are used by just a small group of users. But if you decide to implement them, please make sure they are really useful in practice. If you don’t know what I mean, please look at the image on the left.

Look, there are nice toilets on the second floor! Yes, but you need a crane if you are on a wheelchair.

 

Lesson 19 – Know your users

aliensYou can’t create good interfaces if you don’t know your users. Things can get more difficult if they are aliens, but it is always possible to figure out what they really want. Talk to your users (maybe using a translator helmet) and try to understand how the see the world (not only our world, but also their world).

 

Lesson 20 – Creativity Again

The last lesson of my previous article was about creativity and its powerful effects on our brains. I will keep creativity again as the last lesson of this second part because it is really worth doing so. Please look at the AXE marketing signs displayed at shopping centers and malls… they are simple, easy to understand and – most important – have a real marketing message.

axe

Conclusion

This was the second part of my article about user interfaces and their lessons from the real world. What is most fascinating is the fact that we can take lessons from almost anything visual. All we need is to think about our problems and create a bridge to real world signs and objects. Stay tuned for the next articles.

Ten UI Lessons from the Real World

Learn UI concepts from real world pictures. Signs can teach valuable lessons in this regard and you should pay attention to them.

User interface isn’t a subject specific to computers. Every object in the real world has an interface and understanding it is crucial for a correct usage. Some objects are well designed and can offer different types of good reactions when we interact with them. Others aren’t that good and the designer might have missed the point.

Today I am going to teach some UI lessons based on signs and pictures of the real world. If you pay careful attention, you can realize that they do have lessons to be learned and you can use that knowledge to improve your UIs. This is a valid approach because we – as humans – have a common way of looking at things, be it a system UI, a coffee machine, a vacuum cleaner or signs on the roads. Signs on a road are my favorites because they guide the driver pretty much like icons guide users on a system interface. Let’s start our lessons.

Lesson 1 – Review your Icons

cow
Please look carefully at the sign on the left. What is the meaning of that sign? Are there cows that bite and eat cars?!?

Actually, if you add an icon to your application, make sure it is understandable. Don’t try to create your own if you are not prepared for this task. UI designers should handle that. The biggest issue behind this problem is the fact that users have fear of clicking on things they don’t understand. This can get even worse if their money is involved in the action.

dentistaAnother problem related to icons is best explained when we look at the image on the right. At first glance, you might see a dentist with a patient. But if you look closer, you might note a dirty second meaning. Would you let your wife go to that dentist? I don’t think so…

 

Lesson 2 – Unrelated information shouldn’t be displayed together

nohuntingLook at this second example. By placing both signs together, it is inevitable to imagine people hunting children. When the worker placed the second sign, he probably saw the problem, but he didn’t care. He might have thought that the problem was with him, not with other people.

Trust me, this also happens on your UI. Please keep unrelated information clearly separated from other types of information.

 

Lesson 3 – Use the right punctuation or appropriate separators

dieselIsn’t that yummy? This might be good for your cholesterol levels.

Note that a missing separator clearly creates a misleading scenario that can ruin your business. Your interface can also suffer from that if you don’t pay careful attention. If you are not fully convinced, remember that when you read the same sentence several times, your brain starts to ignore or misinterpret it.

Lesson 4 – Redundancy increases complexity

scheduleThis sign is in Portuguese, but I don’t think we need a translation here. The problem is right ahead and it is difficult to understand why people keep repeating the same information again and again. What worries me is the fact that they do that too often.

Redundancy might be important in some cases (especially when it comes to security), but it can be avoided in most situations. Note that when we remove redundancy we improve simplicity.

golf

Another type of redundancy is in the meaning of words. The next sign provides a good example of how bad this can be. Maybe they are really telling the whole truth…

 

 

Lesson 5 – Identify and remove conflicting ideas

Conflicting ideas can be deadly critical. Look at the three pictures below and think about their explanations: an ant that goes to the opposite direction of the sign, police that can’t turn right while normal people can do so, or a land full of poison just to protect living animals. What could be stranger than that?

The same concepts apply to user interfaces. It is very easy to think that you wouldn’t do such mistakes, but people do that and we have to admit. So look carefully at your UIs and search for conflicting ideas.

conflicting

Lesson 6 – Hide unnecessary precision

precisionSometimes too much precision can be useless. Take a closer look at the next sign and let me know if that extra half mile is important to you. Information like that is inappropriate for the situation and only adds noise and clutter. Drivers usually have just a few seconds to read a sign and the more information you add, the worse it will be. The same applies to software UI.

Lesson 7 – Fix typos

Typos happen in every corner of the world (see pictures below) and it is your responsibility to fix them. It is quite common nowadays to have non-native speakers in the development team. So, besides typos, people can simply write wrong words because they don’t master the UI language.

typos

Lesson 8 – Sentences with the right meaning

churchA sentence with a wrong meaning is worse than a typo. That’s the case of our next sign: If your worries aren’t strong enough to kill you, the church can give *them* a hand.

Sentences in the UI can also be misleading, mainly when the system tries to explain more than needed. Your UI – and its sentences – should be simple, small and clear enough to guide the users.

Lesson 9 – Alignment

alignmentAlignment is important because users don’t read text on the UI. They scan it. So, well aligned text and controls can help dividing the screen into digestible pieces of information. Unfortunately this isn’t the case of our next picture. After reading the first sign, I wonder if people hire cats to make burgers with their flesh.

Lesson 10 – Creativity saves the day

creativityAt last, remember that your creativity can connect the user with a whole new experience. Let your imagination fly when you build user interfaces, as it happens with the guys from the last picture. Good interfaces make users forget their computers pretty much like readers forget their books when they read good stories.

 

Conclusion

This article was an attempt to show my different point of view on user interfaces. The idea of showing real signs is just a funny way to teach concepts that can make applications more usable. Remember that everything around us can teach lessons, but only those that really pay attention can take advantage of that. This is a daily exercise that you should execute when you drive or walk on the streets. It is worth trying, trust me.

High-Quality Image Resize with Java

Learn a trick to shrink images using the Java2D API, which creates high-quality image icons for your applications.

Image resize with java isn’t a new topic. What I want to explain here is a technique to create small high-quality images using the Java2D API, since I couldn’t find any reasonable solution on the Internet. The are some solutions available – like this one – but the final quality is low.

You can use this approach for different purposes, but the best example I can think of is the implementation of small avatars on web applications (see Nabble, DZone, etc.) or desktop software (e.g., Skype, MSN, etc.).

In order to show the contribution of this technique, I have to explain image resize from the beginning. We will improve the algorithm as we go and I also assume you have some background with Java2D.

Reading and Writing the Image

Since this is a simple example, I will read an image from the file system, resize it and save it back. The image I am using is below. Note that I am using a JPG file, which is the common format for pictures.

picture

To read this image, we can use the ImageIO class:

BufferedImage image = ImageIO.read(new File("c:\picture.jpg"));

First Attempt

Now we have to find a way to resize this image. Our first attempt is to use the drawImage() method of the Graphics interface:

private static BufferedImage resize(BufferedImage image, int width, int height) {
    BufferedImage resizedImage = new BufferedImage(width, height,
    BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = resizedImage.createGraphics();
    g.drawImage(image, 0, 0, width, height, null);
    g.dispose();
    return resizedImage;
}

With this method, we can create a 24×24 avatar by calling:

Image resized = resize(image, 24, 24);
The last step is to save the image so that we can see the results. The ImageIO class can do this job:

ImageIO.write(resized, “png”, new File(“c:\picture1.png”));
Note that the second parameter is the format of the saved image. I used “png” because it is simpler. If you want to save it as JPG, you will have to use the JPEGImageEncoder class (and the result is the same, trust me).

The result of this method is a low-quality image:

picture1

Pay attention to the details of the image (look closer). There is no anti-alias and the face is distorted. Would you add such algorithm to your web application? I don’t think so. Users could get scared by looking at those images.

Second Attempt

We noticed that the main problem of the resize() method above is the fact that it doesn’t have anti-aliasing. So we could use the Rendering Hints of the Java2D API as an attempt to solve that problem:

private static BufferedImage resize(BufferedImage image, int width, int height) {
    int type = image.getType() == 0? BufferedImage.TYPE_INT_ARGB : image.getType();
    BufferedImage resizedImage = new BufferedImage(width, height, type);
    Graphics2D g = resizedImage.createGraphics();
    g.setComposite(AlphaComposite.Src);

    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
    RenderingHints.VALUE_INTERPOLATION_BILINEAR);

    g.setRenderingHint(RenderingHints.KEY_RENDERING,
    RenderingHints.VALUE_RENDER_QUALITY);

    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
    RenderingHints.VALUE_ANTIALIAS_ON);

    g.drawImage(image, 0, 0, width, height, null);
    g.dispose();
    return resizedImage;
}

The result is below (right image). If you pay attention to the details, it is somewhat better, but still trash:

picture1picture2

Finally, The Trick

Now I will explain how to improve the quality of this image. Basically, the trick is to blur the image before resizing. The code that blurs an image in java is:

public static BufferedImage blurImage(BufferedImage image) {
    float ninth = 1.0f/9.0f;
    float[] blurKernel = {
        ninth, ninth, ninth,
        ninth, ninth, ninth,
        ninth, ninth, ninth
    };

    Map map = new HashMap();

    map.put(RenderingHints.KEY_INTERPOLATION,
    RenderingHints.VALUE_INTERPOLATION_BILINEAR);

    map.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    map.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    RenderingHints hints = new RenderingHints(map);
    BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, blurKernel), ConvolveOp.EDGE_NO_OP, hints);
    return op.filter(image, null);
}

Since the original image is in the JPG format, we can’t blur it directly. We have to create a compatible image first:

private static BufferedImage createCompatibleImage(BufferedImage image) {
    GraphicsConfiguration gc = BufferedImageGraphicsConfig.getConfig(image);
    int w = image.getWidth();
    int h = image.getHeight();
    BufferedImage result = gc.createCompatibleImage(w, h, Transparency.TRANSLUCENT);
    Graphics2D g2 = result.createGraphics();
    g2.drawRenderedImage(image, null);
    g2.dispose();
    return result;
}

Blurring the image before resizing it isn’t the only trick. You have to do this when the width or height of the image is 100px. Since small avatars are usually a square (width = height), you can resize it to 100×100, call the blur() method and resize again to 24×24:

private static BufferedImage resizeTrick(BufferedImage image, int width, int height) {
    image = createCompatibleImage(image);
    image = resize(image, 100, 100);
    image = blurImage(image);
    image = resize(image, width, height);
    return image;
}

(the resize() method is the one described in the second attempt)

Now you can compare the three results:

picture1picture2picture3

Conclusion

This was my contribution to the tough problem of shrinking images using the Java2D API. I would like to remember that this isn’t the ultimate algorithm to achieve that goal, but it is good enough considering its simplicity. If you have comments or feedback, I would like to hear them.

FULL SOURCE

import sun.awt.image.BufferedImageGraphicsConfig;

import javax.imageio.ImageIO;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.AlphaComposite;
import java.awt.GraphicsConfiguration;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.HashMap;

/**
 * High-Quality Image Resize with Java
 * http://www.componenthouse.com/article-20
 *
 * @author Hugo Teixeira
 */
public class ComponentHouseResizer {

	public static void main(String[] args) {
		try {
			BufferedImage image = ImageIO.read(new File("c:\\picture.jpg"));
			ImageIO.write(resizeTrick(image, 24, 24), "png", new File("c:\\picture3.png"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private static BufferedImage resize(BufferedImage image, int width, int height) {
		int type = image.getType() == 0? BufferedImage.TYPE_INT_ARGB : image.getType();
		BufferedImage resizedImage = new BufferedImage(width, height, type);
		Graphics2D g = resizedImage.createGraphics();
		g.setComposite(AlphaComposite.Src);
		g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
		g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g.drawImage(image, 0, 0, width, height, null);
		g.dispose();
		return resizedImage;
	}

	private static BufferedImage resizeTrick(BufferedImage image, int width, int height) {
		image = createCompatibleImage(image);
		image = resize(image, 100, 100);
		image = blurImage(image);
		return resize(image, width, height);
	}

	public static BufferedImage blurImage(BufferedImage image) {
		float ninth = 1.0f/9.0f;
		float[] blurKernel = {
				ninth, ninth, ninth,
				ninth, ninth, ninth,
				ninth, ninth, ninth
		};

		Map<RenderingHints.Key, Object> map = new HashMap<RenderingHints.Key, Object>();
		map.put(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
		map.put(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
		map.put(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
		RenderingHints hints = new RenderingHints(map);
		BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, blurKernel), ConvolveOp.EDGE_NO_OP, hints);
		return op.filter(image, null);
	}

	private static BufferedImage createCompatibleImage(BufferedImage image) {
		GraphicsConfiguration gc = BufferedImageGraphicsConfig.getConfig(image);
		int w = image.getWidth();
		int h = image.getHeight();
		BufferedImage result = gc.createCompatibleImage(w, h, Transparency.TRANSLUCENT);
		Graphics2D g2 = result.createGraphics();
		g2.drawRenderedImage(image, null);
		g2.dispose();
		return result;
	}

}

10 Reasons Against Huge Legacy Systems

Despite our best intentions, many of us don’t always get to work on well organized and loosely coupled systems. In some cases, we may need to make our way around a code base that is old and has been written by another team whose quality criteria are not clear. Here you can find 10 reasons why I hate working on huge badly-developed legacy systems:

1 – The system is always growing. If a feature must be extended, developers tend to create new methods or classes just to avoid touching the existing code, which could impact on other (unknown) functionalities.

2 – It is almost impossible to create a new functionality using pure test-driven development. To successfully create code using such technique you must understand exactly what the code must do. If you only create tests for your new implementations (e.g., you create the test of a new method and then create the new method), you will succeed to some extent. But a good practice in TDD is to create tests that check the states of the system, and this is very difficult to achieve when you work on a system that is bad modularized and tightly coupled.

3 – Third-party components might not be supported anymore. When you try to upgrade the system (e.g., from java 1.4 to version 1.5 or a new Look-and-Feel is available) you will probably find out that some third-party components will start to behave strangely (e.g., bad layout, missing funcionality, etc). This gets even worse when you don’t have the source code and the vendor is not supporting the component anymore.

4 – Unpredictability: when you make a change in the system, you have no clues if that change will affect other parts of the code. This is likely to happen with systems that use, for example, instrospection. To better illustrate this, imagine that you need to rename a method that is invoked through reflection by another part of the system. The time that you will spend to track down the bug caused by this change can take hours or even days.

5 – Long list of frameworks, techniques and approaches used in the development. You have to understand all of them to be able to work with the code. This reminds me of “Jack of all trades is a master of none”. While keeping track of trends and technologies is something doable and recommended by experts, keeping track of their details requires time and dedication that we don’t normally have.

6 – Too much time to understand the system as a whole. After several months working on the system, you are still a child when it comes to code knowledge. Since the productivity of the developers is a direct result of how much code they understand, they will probably be frustated to a certain extent.

7 – It is always difficult to use CASE tools focused on quality and/or productivity. How can you build class or sequence diagrams for your application if the code is an unpredictable mess? Even if you have good intentions and try to refactor the application, chances are that the spaghetti code will prevent you from reaching an acceptable state.

8 – The build time can be too long. There are systems that take more than 30 minutes to compile, run automated tests, deploy and startup. This is really bad to the productivity and leads to context switching, which is an evil in software development. The developer gets distracted because it is almost impossible to keep looking at the build process waiting for it to end.

9 – It is almost impossible to replace one technology concept by another. To better illustrate this, imagine that your monster application doesn’t have a well-defined persistency layer (which is common in huge complex legacy systems) and you want to replace your object-oriented database by a relational database. How many places do you have to change to make things happen? How will you make sure that the change was successful without a test harness (automation)?

10 – The last item is a result of the nine reasons above: The bad productivity forces the developers to work more and they will get stressed and tired. Their motivation will suffer and they will probably start to look for another job unless the company has incredible ideas and benefits to overcome these problems.

I know that there are hundreds of exceptions in the real world regarding the ideas above, but my intention is to have a list with the worst cases. What do you think?

Using JGoodies With Other Frameworks

Learn how to combine JGoodies with other backend frameworks in your desktop application. The main problem is the need to create objects that extend the Model class while other frameworks might consider this a problem, either because they require POJOs or provide other specific rules.

If you create GUIs using the JGoodies Binding library, you will probably have to create bean classes that extend the com.jgoodies.binding.beans.Model class.

If your desktop application also uses a framework for other purposes (e.g., persistency) and you plan to use the same model object from the GUI with this framework, then you will have to make sure you don’t have conflicting requirements.

This problem is reasonably common and happens because java doesn’t allow multiple inheritance. So, any framework that is used in conjunction with JGoodies and has rules for the target object (e.g., it must be a POJO), then the implementation starts to become more complex.

Let’s discuss one possible solution for those cases where the other framework requires the object to be a POJO (e.g., Hibernate, JPA, etc.). In such cases, we can create one class for the POJO (attributes + getters + setters) and another class that wraps this POJO, which has similar methods but has the advantage to execute other actions.

Example of a POJO:

public class Student {
    private String name;
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

The POJO above can be used by the persistency framework without problems. Now we need a class to be used by the Binding library (GUI):

public class StudentModel extends Model {
    private Student student;

    public StudentModel(Student student) { this.student = student; }

    public String getName() { return student.getName(); }

    public void setName(String name) {
        String old = student.getName();
        student.setName(name);
        this.firePropertyChange("name", old, name);
    }
}

This isn’t a perfect solution, but solves the problem. One disadvantage is the maintenance required by the two sets of methods that access the POJO, which could be automated by a small piece of code that uses java reflection.

Advantages of the Presentation Model Pattern

This article explains the advantages of the Presentation Model pattern over the Model-View-Controller and Model-View-Presenter. This will improve your decisions about GUI implementations for desktop.

One of the major challenges in the development of desktop software is the effective use of unit tests that cover the GUI functionalities and its interactions with the remainder of the software. The complexity of this implementation lies in the control of selected items in lists and tables, modal dialogs, clicks and events. In fact, it is extremely difficult to develop good tests on the GUI when the application logic is tightly-coupled to UI components.

You probably have already heard about design patterns that could help in this case, especially those that separate the application logic from UI components. Perhaps the most famous is the Model-View-Controller (MVC), which has been widely used not only for desktop applications but also for web development.

There is a relevant question that we should ask ourselves at this point: Is this separation between logic and UI components enough to reduce the complexity of writing GUI unit tests?

Figure 1 presents the three most important presentation patterns for desktop development. Besides the MVC, there is one called Model-View-Presenter (MVP) that consists of a small variation of the first one (see Martin Fowler’s description of them for more details).

patterns

Figure 1: Patterns for desktop application development.

The important thing to notice in this picture is that both MVC and MVP describe the controller/presenter with a reference to the view. So, to create an instance of the controller inside the test code, we need the view as well. This still makes the development of unit tests difficult.

There is a turnaround to this problem, which is basically to add an interface between the controller and the view to break this dependency and abstract the view’s components. But the idea behind this solution increases the amount of code and does not imply in less complexity and clean organization. In most of the cases, this resolution is not worth the effort when there is a third option such as the Presentation Model pattern.

jQuery: Performance analysis of selectors

In this article jQuery is tested with different selectors in order to find specific elements in the DOM tree. The delay of each selector is precisely calculated and the idea is to find out which one is the fastest for the given goal.

jQuery is one of the best javascript libraries I have ever worked with. It is quite simple and usually reduces the amount of javascript code in web applications. Besides all the advantages it brings to the web community, we have to pay attention to a few details when reusing this library in order to get the best part of it.

I will describe a few tips on how to improve the performance of your javascript code. Most of these tips aren’t a big deal if your pages are small and simple. But if you create complex html pages, you should follow them in order to prevent the browser from locking when the page loads up. Even if you are not concerned with performance at all, learning these things will bring benefits to your overall knowledge about this library.

jQuery has a bunch of different selectors – as you can see from the documentation here – and I won’t consider all of them in this analysis. My idea is to explore different ways of finding a specific element in the html page by using different types of search. Benjamin Sterling has already researched this topic here, but I want to add a different point of view, which is more accurate and provides more alternatives for the developers.

Let me start talking about the test html page, which has over 20,000 elements separated in chuncks of 5,000. Basically, there are 5,000 divs + 5,000 spans+ 5,000 paragraphs and 5,000 small tags with the following characteristics:

<!-- 5000 'div' elements -->
Div 0

 

Div 1

Div 4999

<!– 5000 ‘span’ elements –> <span id=”b-0″ class=”span-0″ row=”b-0″>Span 0</span> <span id=”b-1″ class=”span-1″ row=”b-1″>Span 1</span> … <span id=”b-4999″ class=”span-4999″ row=”b-4999″>Span 4999</span> <!– 5000 ‘p’ elements –> <p id=”c-0″ class=”p-0″ row=”c-0″>Paragraph 0</p> <p id=”c-1″ class=”p-1″ row=”c-1″>Paragraph 1</p> … <p id=”c-4999″ class=”p-4999″ row=”c-4999″>Paragraph 4999</p> <!– 5000 ‘small’ elements –> <small id=”d-0″ class=”small-0″ row=”d-0″>Small 0</small> <small id=”d-1″ class=”small-1″ row=”d-1″>Small 1</small> … <small id=”d-4999″ class=”small-4999″ row=”d-4999″>Small 4999</small>

The 20,000 elements above are generated by javascript. They provide a good laboratory to check the speed of each selector, since we can expect more accurate results in this analysis. The page itself has a few more tags to display information and execute each test, but this shouldn’t affect the final results.

The test page is available here. It takes a few seconds to load because the javascript must create the DOM tree as described above. So please be patient. Note also that each test uses the measure() function, which calculates the delay of the call in milliseconds.

Test 1 – Finding an element by ID

The first test is to find an element by its ID. I decided to get the element whose ID is “d-2642”. We can do this in three different ways:

A – Using the ID selector
$(‘#d-2642’).html()

B – Using attribute search
$(‘[id=”d-2642″]’).html()

C – Using attribute search + tag
$(‘small[id=”d-2642″]’).html()

Running this test for the first time in different browsers, I could reach the results displayed in the following table (in milliseconds). It is clear that the # operator is the most efficient one.

Firefox Opera IE6 IE7 Safari
A 156 0 31 40 0
B 3609 828 2344 841 844
C 578 93 406 210 172

Test 2 – Finding an element by Class

Although CSS classes are intended to be reused among elements, you might create some elements with a unique class name just to identify and retrieve them through javascript. This is exactly what we test in this second test by seaching the element whose class is “p-4781”. We have four alternatives:

A – Using the class selector
$(‘.p-4781’).html()

B – Using the class selector + tag
$(‘p.p-4781’).html()

C – Using attribute search + tag
$(‘p[class=”p-4781″]’).html()

D – Using tag search + filter
$(‘p’).filter(‘.p-4781’).html()

After running this test for the first time in different browsers, I got:

Firefox Opera IE6 IE7 Safari
A 2891 641 1718 631 329
B 453 78 313 180 78
C 422 109 578 201 187
D 203 266 375 210 94

The table above shows case B as the fastest selector for most browsers (except Firefox). It is easy to understand why case A isn’t efficient, since the code has to iterate over all elements of the DOM tree. Case C and D aren’t that bad, but I would say case B should be the preferred one for this goal.

Test 3 – Finding an element by Attribute

The third test is to find elements by a given attribute value. Sometimes this technique is useful and I decided to test it by searching for the element that has “c-3221” as the value of the row attribute. There are four possibilities in this case:

A – Using attribute search
$(‘[row=”c-3221″]’).html()

B – Using attribute search + tag
$(‘p[row=”c-3221″]’).html()

C – Using tag search + filter
$(‘p’).filter(‘[row=”c-3221″]’).html()

D – Using (tag + attribute) search + filter
$(‘p[@row]’).filter(‘[row=”c-3221″]’).html()

Running this test for the first time in different browsers, I could get the following results:

Firefox Opera IE6 IE7 Safari
A 6610 1390 2500 801 1156
B 1250 360 406 200 250
C 1265 968 485 231 281
D 4078 1000 656 320 625

Case B is for sure the best approach to find an element by a specific attribute value.

Conclusions

This experiment was an attempt to find the right and fastest way of finding specific elements in the DOM tree using jQuery. Every jQuery developer should know and understand these details in order to create efficient code. Benjamin Sterling gave the first step in such performance analysis, but I could provide another point of view, which uses a big DOM tree and more alternatives to be checked.