In Commentary on
10 March 2010 tagged cars, statistics with no comments
Robert Wright breaks down the numbers on Toyota’s safety record given all of the recent reports of uncontrolled acceleration:
My back-of-the-envelope calculations (explained in a footnote below) suggest that if you drive one of the Toyotas recalled for acceleration problems and don’t bother to comply with the recall, your chances of being involved in a fatal accident over the next two years because of the unfixed problem are a bit worse than one in a million — 2.8 in a million, to be more exact. Meanwhile, your chances of being killed in a car accident during the next two years just by virtue of being an American are one in 5,244.
This is the article I’ve been looking for since the mass hysteria about acceleration problems began. It strikes me as undoubtable that a Toyota purchased today is significantly safer than most of the cars I’ve driven over the course of my life. I used to own a 1977 Ford pickup truck that caught on fire under the hood more than once.
Update: It’s also worth mentioning that if the accelerator sticks on your cars, there are several ways to stop.
In Commentary on
9 March 2010 tagged JavaScript, jQuery, Web services with no comments
About a month ago I asked what people would use to build a new Web service from scratch, without providing any real details on what the application would do. People seemed to all agree that basing the service on JSON was the best way to go, and that’s the route I took, so I thought I’d write it up.
In this case, I have a PHP front end talking to a Java back end that uses Spring and Hibernate. The application in question is the administrative console for a test harness for a SOAP Web service. We use a third party SOAP service and needed the ability to provide responses that are guaranteed to always be the same for the purpose of creating tests. So my test harness stands in for the third party service, requiring only a URL change, and returns the data managed via the client application to which my question referred.
The application itself is very simple — it’s a single table with a lookup mechanism. The client enables users to find and edit individual records from the table. I needed four basic operations:
- Search for records
- Retrieve a single record
- Update a record
- Create a record
- Delete a record
The Server
This is a Java application that uses Spring and Spring MVC. I use Spring’s Web Services support for the SOAP stuff, but it wasn’t worth it to bother with that for the administrative client. So instead I mapped every URL ending in .json to a Spring DispatcherServlet. Like all sensible Java developers who’ve worked in Rails, I hate configuration in general and XML configuration files in particular. So I used Spring’s ControllerClassNameHandlerMapping, which extracts the path from the URL and maps it to a Spring controller.
So a path like /myapp/responses/search.json calls the search() method in the ResponsesController class. Simple.
I won’t go into the boring details of my implementation, other than to talk about how I’m passing the messages back and forth. The client uses standard form submission (name and value pairs) to submit the data, and expects to get JSON back. So in the case of search, I extract the field name and query value, go to the database and run a query to retrieve the records in question, and then package them up and encode them using JSON to be sent back to the client.
The JSON encoding is handled by Google’s GSON library, and it’s ridiculously simple. It accepts a plain Java object, and serializes it and all of its children using reflection. Any properties that are null are omitted. So for my application, I created a wrapper object that was well-suited to being encoded using GSON. It includes a hash for error messages, a property for a single response object, and a collection of response objects for search results.
Then I created a view for Spring called SimpleGsonView, which accepts a wrapper (or any object), encodes it using GSON, and then sends the results to the client. Here’s the whole thing:
@Override
protected void renderMergedOutputModel(Map aMap,
HttpServletRequest aRequest,
HttpServletResponse aResponse) throws Exception
{
Object wrapper = aMap.get("wrapper");
Gson gson = new Gson();
aResponse.setContentType("application/json");
ServletOutputStream out = aResponse.getOutputStream();
out.print(gson.toJson(wrapper).replaceAll("\\\\n", ""));
logger.debug(gson.toJson(wrapper));
out.flush();
}
One thing you may notice is that I do a search and replace on the JSON. It removes all occurrences of \n from the encoded data. That’s a hack to get around a client side bug that I got tired of trying to fix. I’ll talk about that later.
So for this application, to add new functionality, I just add a new method to my controller, process the input parameters and put the correct results in the wrapper, and then pass that to the view I created. Very simple. I added an autocomplete feature to the search page, and this is all I had to do to add support for it on the back end:
public ModelAndView complete(HttpServletRequest aRequest,
HttpServletResponse aResponse)
{
String searchField = aRequest.getParameter("field");
String searchQuery = aRequest.getParameter("query");
List<String> results = Collections.emptyList();
if (searchField.equals(FIRST_NAME))
{
results = getFirstNameCompletions(searchQuery);
}
else if (searchField.equals(LAST_NAME))
{
results = getLastNameCompletions(searchQuery);
}
else if (searchField.equals(KEY))
{
results = getKeyCompletions(searchQuery);
}
else if (searchField.equals(ZIP))
{
results = getZipCompletions(searchQuery);
}
return new ModelAndView(new SimpleGsonView(), "wrapper",
results);
}
The methods to retrieve the data are in another class, but I removed the reference to it for simplicity.
So that’s the server piece. I could have done more to make it RESTful but since the service is just for me, I went with the simplest possible approach.
The Client
For legacy reasons the client is a PHP application, and I decided to use jQuery and a little PHP to implement the client features. Here’s how each operation is implemented:
Search: The search feature is pure jQuery. The home page for the client has a search form on it with a pulldown of fields that can be searched and a text box for the search terms. I used the autocomplete feature from jQuery UI to make the search form a bit friendlier. I catch the submission of the search from (or the selection of an item in the list provided by autocomplete) and submit the results to the server using jQuery’s getJSON() method. Then I create a table on the page with the search results in it.
Retrieve a single record: This is the only place I used PHP to connect to the server. I decided that I wanted each item to have its own URL, and although I could have written the code to pull the key for the item in the URL, fetch it, and build the page in JavaScript, I opted to use PHP instead. To do so, I grabbed a copy of the Services_JSON library and included that in my app. PHP supports JSON natively starting with version 5.2, but my server is running PHP 5.1. I chose Services_JSON because it’s a single file. So when you go to the edit or show page, I use PHP to fetch the JSON for the key in the URL from the server and put it on the detail page or in the edit form. This is where the bug comes in. My service returns XML documents (encoded as a value in a JSON hash), and sometimes Services_JSON won’t decode the data properly. When I started stripping \n from the XML, it worked, so I went with it.
Create a record: This form uses jQuery’s post() method to submit the contents of the form to the server. If the request returns a successful result, it redirects the user to the detail page for the new item. If it doesn’t, it displays the errors included in the result.
Update a record: This form works just like the create form.
Delete a record: This is the simplest operation of all. It submits the key to be deleted, and the server simply returns true or false.
Upshot
This was just about the easiest implementation of an application and accompanying Web service I’ve ever done, in spite of the fact that I’m a pretty terrible JavaScript developer. The server side was much easier to implement than I’d anticipated, it took less code in Java than it would have in PHP, and not much more code than it would have taken in Ruby. This is the application that really convinced me that there’s essentially no development overhead involved with using AJAX rather than traditional server-side request processing when building Web applications, at least if you bring libraries like jQuery and GSON to the party to make things easier.
In Commentary on
6 March 2010 tagged advertising with 16 comments
ArsTechnica explains why they ran an experiment Friday that hid their content for people running ad blocking software. It’s a very grown up and pragmatic explanation, and it’s almost too obvious to even quote. The point I found interesting was the discussion of the advertising death spiral — when advertising impressions go down, sites have to take on ads that pay more per impression — those are the ads that take over the whole page, hide the links you want to click on, and so forth. Those ads are awful for users and many publications are running them on the front page. If I ran an advertising-funded site, and I could increase (or maintain) revenue by either shutting down ad blockers or presenting more obnoxious ads to the people who aren’t running ad blockers, the decision would be a no-brainer. I’d prefer to inconvenience the people who think they should get my content for free every time.
In quotable on
5 March 2010 tagged business, ethics, Wal-Mart with 2 comments
Meeting social and environmental standards is not optional. I firmly believe that a company that cheats on overtime and on the age of its labor, that dumps its scraps and its chemicals in our rivers, that does not pay its taxes or honor its contracts will ultimately cheat on the quality of its products. And cheating on the quality of products is the same as cheating on customers. We will not tolerate that at Wal-Mart.
Wal-Mart CEO Lee Scott at a conference for suppliers in China. I’m not the world’s biggest fan of Wal-Mart, but I can’t argue with Scott’s logic or principles in this case.
In Commentary on
4 March 2010 tagged design with 2 comments
In yesterday’s post about URL literacy a little debate broke out in the comments about whether it’s worth it to add usability features for novices if they make life more difficult for experts. On that note, last month’s Dwell had an article on universal design, a school which argues that designers should be trying to create designs that work for everyone, regardless of their level of experience or capabilities. This is the position I was arguing in the comments, and is an approach I’m fond of. I generally reject the notion that experts and novices require wildly different interfaces or devices, although obviously there are outliers in any group whose tastes may differ.
In Commentary on
3 March 2010 tagged Ignite with 2 comments
It’s Global Ignite Week, with more than 50 Ignite events taking place all over the world. The second Ignite Raleigh was held tonight, and there were lots of entertaining and informative speakers. If you get a chance, you should definitely attend your own local Ignite event if you can.
I was one of the speakers at the previous Ignite Raleigh, last August, and wrote up the experience. If you’re going to be speaking at Ignite, it’s probably worth checking out:
In Commentary on
3 March 2010 tagged Constitution, terrorism with no comments
Glenn Greenwald has an important blog post on the latest smear campaign by the terrorist-loving right:
As I noted yesterday, the group run by Liz Cheney and Bill Kristol released what is certainly one of the more repugnant political ads of the last decade, if not the most repugnant. It’s the type of McCarthyite act which would, if we had any minimal standards in our political culture, result in the shunning of Cheney and Kristol by all decent people (instead, it will likely land the Vice President’s daughter on multiple Sunday talk shows where she can pose as an expert on national security).
Some Republicans launched a smear campaign against the lawyers now employed by the Justice Department who once represented detainees at Guantanamo. This is the product of a deep cynicism that compels them to try to gain political power by capitalizing on people’s fear of terrorism.
What they’re really attacking is the Constitution, which guarantees everyone a fair trial. They’re not arguing a principle — they’re just trying to destroy people through insinuation. The bottom line is that this sort of garbage is always going to be persuasive to a certain type of idiot. Don’t be an idiot.
Oh, and the reason I say they love terrorists is that without the terrorists to use as a foil, they would have no path back to the positions of influence they so desperately crave. They want Americans to embrace unlimited Presidential power, expansion of the wars in Iraq and Afghanistan, and if they’re really lucky, a new war with Iran. What they need for more people to agree with them is more, increasingly spectacular terrorist attacks. And don’t think that in their black hearts, they don’t wish for that at some level.
In Commentary on
2 March 2010 tagged patents with no comments
Other than a few sleazy actors like Intellectual Ventures there’s an understanding in the innovative side of the tech business that you don’t file aggressive patent lawsuits. You write a lot of patents, you file defensive lawsuits and countersuits, but in general you don’t use your patent portfolio as a big club to try to destroy competitors. Apple’s taking a big crap on that detente.
Nelson Minar on Apple’s patent lawsuit against Android handset maker HTC.
Update: ArsTechnica lists the patents in the suit. They’re all software patents. You disappoint me, Apple.
In Commentary on
2 March 2010 tagged browsers, user experience with 7 comments
Jono from Mozilla makes a great point that most people (including me) have completely overlooked when it comes to the Web —
most people don’t really understand URLs:
So what this mess teaches us is that there are lots of people out there who don’t know how to read a URL. The URL in the location bar, if they notice it at all, must appear to them as nothing but a bunch of computer gibberish.
Think about it from their point of view. They knew that Googling “facebook login” and then clicking the first link took them to their Facebook login. I wouldn’t call it the best way of getting to Facebook, but it was obviously working for these poor souls. Until one day, they saw something they didn’t expect. If you don’t know how URLs work, then all you know is that your expected Facebook login page has somehow been replaced with… something else.
The whole blog post is really thought provoking and worth reading for anyone who designs or develops software. For those of us who have completely internalized URLs, it’s hard to empathize with people who see getting to Web sites as a series of steps they follow. At this point it doesn’t matter whether people access all the Web sites they use through Google or some other search engine, other than to figure out how to make things better for people who use the Web that way.
I wonder whether browsers could display URLs in a way that makes things easier for users. The most important thing about a URL, especially in terms of preventing fraud, is the domain name — the real one, not the fake one that’s included to defraud people. Maybe it should be highlighted in some way with the owner of the domain displayed as well.
Via Simon Willison.