RSS

Monthly Archives: May 2011

Judging XINS: The Good, the Bad and the Ugly

Looking Back

Back in 2002 or 2003, while working at an internet service provider (Wanadoo Netherlands, now called Online), we were constantly integrating frontend applications created by one team with backend applications created by another. To improve integration, our development team created a technology that would evolve into the contract-first development tool now known as XINS. It worked like a charm for the people involved (architects, developers, IT opeations, management and testers), getting nothing but praise.

But that is a while ago, and the landscape has changed; so how does XINS fare after about 8 years? Looking back, what is arguably good, bad and ugly about it?

The Good

  • The contract first approach really pays off in terms of quality and productivity. Once the contract is agreed upon by the involved developers and/or development teams, there’s suddenly a lot less room for discussion. And it’s fail fast; the contract is validated at both sides (client and server). This approach makes XINS unique and a real productivity monster. Developers are able to focus on the actual implementation code and hardly have to deal with after-the-implementation-discussions on integration issues;
  • Strong operational excellence (like failover, load balancing, error handling, logging, etc.) increases productivity and improves overall quality of these aspects. Part of the functionality is built into the framework, the rest is generated from the specifications.
  • From specifications, test forms can be generated. This is not only great for developers testing their own stuff, but also for other development teams, for testers and operations. It’s easy to peek at XINS-based applications.
  • Performance has always been very good, with automated performance tests in place to detect regressions. The overhead of the XINS runtime is typically less than a millisecond.
  • As long as it goes over HTTP, XINS supports various transport protocols, like JSON, XML-RPC, SOAP and the default: a simple browser-friendly protocol (HTTP GET/POST in, XML out).

The Bad

  • XINS still uses DTDs for validation of the specification files, instead of using the much more powerful XML Schema standard (or even RelaxNG).
  • The XML-based specification files use custom file name extensions, like .fnc, for function definitions, .typ for types, etc. This typically confuses editors and disables syntax highlighting.
  • Unit testing of function implementation classes is hard, they they require generated code (their superclasses). Nowadays, such classes would normally be POJOs.
  • The default protocol has some quirks: e.g. it requires XML support in the browser (which Safari does not offer), it is impossible to send empty strings (because these are interpreted as nulls) and errors are returned using the 200 OK status, which is not in accordance with the HTML spec, etc.
  • XINS 2.3 still uses various non-standard data type classes; this will be fixed in XINS 3.0. Examples of such data types include the PropertyReader (will become Map<String,String> in XINS 3) and the Element class (XINS 3 will use the W3C DOM API instead).

The Ugly

  • XINS tries to be too much at once; it not only generates stuff (code, documentation and test forms), but it also compiles compiles Java code, generates Javadoc, produces a WAR file, enforces an approach to application configurations, etc.
  • As a tool, XINS does not fit in well in the current ecosystem of (Java) build tools and IDEs. It has its own source directory structure, it has its own build system, it does not integrate directly with Maven, etc.
  • All transport protocols are supported, as long as it is HTTP. Local calls are supported, but then everything needs to be wrapped in HttpServletRequest and HttpServletResponse objects. Especially for binary data, this introduces a lot of overhead: binary data is converted to an inefficient format (Base64 or hex), transported in the inefficient format (overhead!) and then converted back to the binary format. Note that this involves storing the data in memory (more than) twice on the server side!
  • XINS hardly evolves: the community is minimal and development is slow.

Crowning the Successor

Overall, XINS is a productivity monster that addresses a topic no other tool appears to cover as good. But it has its share of issues; and integration with other processes and tools makes it less developer-friendly.

There is definitely room for an improved contract-first technology, especially if it would offer the following properties and features:

  1. Strong generation of code, documentation and browser-accessible test forms, similar to XINS.
  2. A runtime environment (client- and server-side) that provides strong operational excellence, similar to XINS.
  3. No attempt to be a one-size-fits-all; instead, make it easy to integrate this technology in existing contexts (tools, processes and technologies).
  4. Easy to pick up for current Java developers; this requires easy integration with modern build tools and IDEs.
  5. Transport-independence, supporting local calls, HTTP (including browser compatibility and efficient binary data handling), as well as other transports, with solid data type conversion.
  6. Strong integration with an existing component technology, such as Jigsaw or OSGi.
  7. Reusing an existing specification technology, such as WebIDL.

Conclusion

There is plenty of room for improving XINS, especially when it comes to adaptation to the current Java ecosystem. Still, in its current form, XINS is a mature technology that really shines when it comes to productivity and operational excellence.

Advertisements
 

Clean CSS with Server-Side Browser Detection (2/2)

In the first article of this duo I explained the use case for server-side browser detection. In this second post I will give a practical example, including some sample Java, HTML and CSS code.

Practical Use Case

Let’s create a simple download page with three variants:

  • an EXE file for Windows users;
  • a DMG file for Mac OS X users;
  • and a TAR GZ file for Linux users.

When the operating system of the visitor is either of these three, then the appropriate download should be highlighted.

Here’s what the result HTML5 should resemble:

<!doctype html>
<html lang="en" class="BrowserOS-Windows">
<head>
  <meta charset="utf-8">
  <title>Downloads</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>Downloads</h1>
    <ul class="DownloadLinks">
      <li><a class="Windows" href="/install.exe">Windows installer (EXE)</a></li>
      <li><a class="Mac"     href="/install.dmg">Mac OS X installer (DMG)</a></li>
      <li><a class="Linux"   href="/install.tgz">Linux installer (TAR GZ)</a></li>
    </ul>
</body>
</html>

Then this is the CSS:

body {background:white;}
h1 {color:green;}

.DownloadLinks a {border:1px solid white;}

.BrowserOS-Windows .DownloadLinks a.Windows,
.BrowserOS-MacOS   .DownloadLinks a.Mac,
.BrowserOS-Linux   .DownloadLinks a.Linux {border-color: green; font-weight:bold;}

The Java Library ‘uasniffer’

When using Java, you can use the uasniffer library I wrote. It takes an agent string and transforms it to what can be used as CSS class names. For example, the following agent string:

Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)

is transformed to the following names:

Device-Desktop
Device-NoPhone
Browser-MSIE
Browser-DesktopMSIE
Browser-DesktopMSIE-7
Browser-DesktopMSIE-7-0
Browser-DesktopMSIE-7-0-0
BrowserEngine-Trident
BrowserOS-Windows
BrowserOS-Windows-NT
BrowserOS-Windows-NT-6
BrowserOS-Windows-NT-6-0
BrowserOS-Windows-Vista

Compiling the Library

To use this library, you need to get it from the Git version control system first:

git clone https://github.com/znerd/uasniffer.git

This will create a uasniffer directory. Then go to that directory and compile it using Maven. E.g., from the command line:

mvn package

Implementation With a JSP

A JSP that would use this library could be written as follows:

<%@ page import="org.znerd.uasniffer.*" %><%
String agentString = request.getHeader("user-agent");
String uaClasses = AgentSniffer.analyze(agentString).getNamesAsString();
%><!doctype html>
<html lang="en" class="<%=uaClasses%>">
<head>
  <meta charset="utf-8">
  <title>Downloads</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>Downloads</h1>
    <ul class="DownloadLinks">
      <li><a class="Windows" href="/install.exe">Windows installer (EXE)</a></li>
      <li><a class="Mac"     href="/install.dmg">Mac OS X installer (DMG)</a></li>
      <li><a class="Linux"   href="/install.tgz">Linux installer (TAR GZ)</a></li>
    </ul>
</body>
</html>

Conclusion

In general, avoid browser sniffing. When you do need it, the uasniffer library makes server-side browser sniffing extremely easy.

If this was helpful on your project, let me know.

 
Leave a comment

Posted by on 13 May 2011 in Geen categorie

 

Clean CSS with Server-Side Browser Detection (1/2)

Why?!

We all know that browser detection is bad, but let us look at some situations in which it may actually make sense; consider the following use cases:

  1. A specific (old?) browser needs special CSS styles to make things look/work acceptably.
    For example, Firefox 3.0 needs a negative margin on an INPUT field, to correct a bug.
  2. Certain content should be highlighted to give a visual clue that this content appears most appropriate for the visitor’s context, like browser and OS.
    For example, on a download page, you want to highlight a download for Mac OS X 10.6, because that is what the visitor appears to use.

Alternative Solutions

Typical solutions for these problems are:

  1. Use CSS hacks.
    Downsides: Unreliable, cumbersome and very hard to maintain.
  2. Use conditional comments.
    Downside: IE-only.
  3. Use feature detection. Various client-side frameworks support this, e.g., Modernizr or jQuery’s $.support.
    Downsides: Only works when JavaScript is enabled, only on more recent, capable browsers and may impact performance negatively on less capable devices.
  4. Use client-side browser detection. This has the advantage of being able to use more than only agent string; using navigator.vendor gives more reliable results.
    Downside: Works only when JavaScript is enabled and impacts client-side performance.

The Case for a Different Path

Excluding the first one, the mentioned solutions have their applications in modern web development. However, they certainly do not cover all ground. An alternative solution for the specified use cases would be welcome if it would comply with all or most of the following requirements:

  1. Reliable, e.g. should automatically pick up new browser versions.
  2. Easy to apply.
  3. Easy to maintain, i.e., no hacks like html>/**/body {}.
  4. Generally applicable, i.e., not specific to IE.
  5. Supports Progressive Enhancement, i.e., does not require JavaScript.
  6. Supports older and less capable browsers as well as more recent and capable ones.
  7. High performance, no time lost detecting features client-side on a limited CPU.

Server-Side Detection

An alternative solution is to have a server-side algorithm add some CSS classes to an element on the HTML document. For example, an iPad agent string could result in the following BODY tag being generated:

<BODY class="Device-Tablet Browser-Safari BrowserEngine-WebKit BrowserOS-iOS">

Let’s look at what such an approach has to bring to the table in terms of requirements coverage:

  1. Reliability: Fair, but not very good, since it relies on the agent string which is easy to spoof. On the other hand, newer browser versions are typically picked up either automatically or with a small update of the detection algorithm.
  2. Easy to apply: Yes, definitely: BODY.BrowserOS-MacOS .MacDownload {border: 1px solid green;}
  3. Easy to maintain: Yes, you only deal with (readable!) CSS.
  4. Generally applicable: Yes, only limited by what user agents offer (of course) and what the algorithm detects; but the algorithm can be extended.
  5. Supports Progressive Enhancement: Yes, perfectly. Works without a single line of JavaScript.
  6. Supports older and less capable browsers: Yes, the detection is done server-side, independent of the browser.
  7. High performance: Yes, server-side algorithm should take (way) less than 10 ms.

What’s Next?

Does it sound like there is a valid use case for server-side browser detection? Let me know in the comments! In a followup article, I will give some code samples.

 
Leave a comment

Posted by on 12 May 2011 in Web Development