Saturday, January 31, 2009

DBAs, Developers, Complexity, and the Pot Calling the Kettle Black

Gavin Parish's current blog posting Maude, the developers are infighting again... made me smile for two reasons. First, what he said about developers and what is discussed about developers in the referenced link (Brian 'Bex' Huff's Why Do So Many Developers Love Bafflingly Complex Code?) is often true. Second, for a self-confessed DBA to be talking about developers and complexity is the best example I've seen in weeks of the pot calling the kettle black. In this post, I'll look at the many reasons and motivations that explain the prevalence of overly complicated code before describing the anecdotal evidence I've witnessed that prove that some DBAs love their complexity as much as some developers love it.


Reasons (Some) Developers Like Complexity

There seem to be several reasons that developers (including me at times) have created unnecessarily complex code. These include factors discussed in the two just-referenced blog posts. Here is a quick list of some of the prime reasons some developers (maybe all of us at one time or another) seem to generate overly complicated code.

  • Lack of understanding of problem - Code can be more complicated than it should be because the problem is not well understood. I almost always realize after I have completed a piece of code that there are ways I could make it simpler or refactor it. This is often a result of better understanding the problem after working through it.

  • Lack of understanding of technologies - Code can sometimes be more complicated than it needs to be because the developer doesn't realize there is an easier way to apply the same or even an alternative technology to the problem. For example, I have seen (and heard of) projects where developers essentially wrote their own web servers, data stores, and application servers. On a smaller level, it is easy to write complicated code that could be greatly simplified by using established libraries and frameworks.

  • Job Security - I don't think this is as common as some allege, but there is no question that it does happen. If a developer writes code that only he or she can understand, the thinking goes, he or she will become indispensable. I personally find this a little short-sighted and think it typically will only work for short-term security, but that doesn't mean some people don't believe it works for them.

  • Show Off - Ever since Elementary School show-and-tell, many of us have had a desire to show off. This can definitely be a factor in why some code is more complicated than it should be, but it can also be difficult to differentiate this motivation from the next two listed here.

  • Guilty Pleasures - It is sometimes tempting to write complex code just to see if we can. I have classified this as one of the software developer's guilty pleasures. After showing ourselves that we can do it, we might look forward to showing it off to others as well (the previous point)

  • Hell is Paved with Good Intentions - We sometimes bring the complexity upon ourselves by trying too hard. I think of my own early overuse of implementation inheritance when I first learned about object-oriented programming and my similar overuse/abuse of design patterns when I first started looking into them seriously. Unfortunately, it seems that many of us have a tendency to think if a little is good, a lot is great. We are prone to focusing too much on one -ility (especially flexibility) at the cost of other positive features (cannot see the forest for the trees).

  • We Cannot Help Ourselves - Unnecessary complexity is not limited to software developers. One simply needs to look at the United States tax code, at most software licenses, at most warranties, or at many other everyday documents to see how prevalent complexity has become in our daily lives.




(Some) DBAs Love Complexity Too

I enjoyed the previously cited blog posts on developers and complexity because I have seen the things they describe. I have also seen that (some) DBAs seem to love complexity as much as (some) developers. Here are some anecdotal examples.


  • Whereas some developers do seem to love overly complex object hierarchies, I've seen data models that are so complex that they could rival any class diagram in terms of size and complexity.

  • Whereas some developers do seem to love write complex code that is difficult to understand, the most complicated piece of code I can recall ever seeing was a crazy SQL statement with numerous joins and unions. The only person I knew that could understand it was the DBA that wrote it. Even the other DBAs wanted nothing to do with it.

  • It is very easy for we developers to get so enamored with design patterns, best practices, and other rules of thumb that we overly complicate what should have been simple. DBAs seem to have a similar tendency to get carried away in their own chasing of patterns and best practices. I have seen cases where extreme database normalization has led to data models that are difficult to maintain and slow to perform. Database Design ROI discusses some of the costs of overly complex and difficult database design.




Conclusion

It seems like the software development industry (including database administration) is full of unnecessary complexity. This may be for several reasons as discussed above. Because the reasons are so diverse and so cover so many different types of people, I don't see this going away anytime soon.






RMOUG Training Days 2009

Speaking of database administrators and developers, RMOUG Training Days 2009 is just a little over a week away. This conference is an excellent source of information and networking for both developers and administrators. Because I tend to focus on developer-oriented things, this conference is a nice opportunity to see some things from more of a database administrator perspective.

Ann Horton has put together a blog focused on Training Days 2009. This blog already includes several entries including postings on OTN representatives at Training Days (with OTN Greatest Hits 2008 DVDs), why one should attend Training Days, inviting managers and supervisors to Wednesday afternoon events, logistics such as Littleton Light Rail availability and directions and parking, and more.

Tuesday, January 27, 2009

Java Properties in XML

Java properties have been a staple of Java development for many years. Even today, Java properties are used in popular frameworks and tools such as the Spring Framework and Ant. Most of the Java properties that I have seen used frequently follow the tried-and-true name=value paradigm. However, since J2SE 5, it has been easy to load (and save) properties in XML format.

In my experience, the typical properties file looks something like that shown next.

examples.properties


url.blog.dustin=http://marxsoftware.blogspot.com/
url.javaworld=http://www.javaworld.com/
url.coloradosoftwaresummit=http://www.softwaresummit.com/
url.otn=http://www.oracle.com/technology/index.html
url.rmoug=http://www.rmoug.org/


J2SE 5 made it easy to load properties from XML (and store properties to XML). The Javadoc-based API documentation for the Properties class discusses both formats. This documentation shows the DTD used to define the Properties XML grammar:


<?xml version="1.0" encoding="UTF-8"?>
<!-- DTD for properties -->
<!ELEMENT properties ( comment?, entry* ) >
<!ATTLIST properties version CDATA #FIXED "1.0">
<!ELEMENT comment (#PCDATA) >
<!ELEMENT entry (#PCDATA) >
<!ATTLIST entry key CDATA #REQUIRED>


The DTD shows us that properties stored in XML must have <properties> as the root element required of well-formed XML and can have zero or one <comment> elements nested in this root tag. We also learn from this DTD that zero to many elements name <entry> are allowed and that an entry element may contain a data body and a single attribute named key. Based on this DTD, we could write a compatible XML-based properties file by hand, but an even easier way to see one is to read in a traditional properties file of name/value pairs and store it back out in XML format. This is exactly what the next Java class, PropertiesExamples, does.

PropertiesExamples.java


package dustin.properties;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;

public class PropertiesExamples
{
/** No-arguments constructor. */
public PropertiesExamples() {}

/**
* Get traditional properties in name=value format.
*
* @param filePathAndName Path and name of properties file (without the
* .properties extension).
* @return Properties read in from provided file.
*/
public Properties loadTraditionalProperties(
final String filePathAndName)
{
final Properties properties = new Properties();
try
{
final FileInputStream in = new FileInputStream(filePathAndName);
properties.load(in);
in.close();
}
catch (FileNotFoundException fnfEx)
{
System.err.println("Could not read properties from file " + filePathAndName);
}
catch (IOException ioEx)
{
System.err.println(
"IOException encountered while reading from " + filePathAndName);
}
return properties;
}

/**
* Store provided properties in XML format.
*
* @param sourceProperties Properties to be stored in XML format.
* @param out OutputStream to which to write XML formatted properties.
*/
public void storeXmlProperties(
final Properties sourceProperties,
final OutputStream out)
{
try
{
sourceProperties.storeToXML(out, "This is easy!");
}
catch (IOException ioEx)
{
System.err.println("ERROR trying to store properties in XML!");
}
}

/**
* Store provided properties in XML format to provided file.
*
* @param sourceProperties Properties to be stored in XML format.
* @param pathAndFileName Path and name of file to which XML-formatted
* properties will be written.
*/
public void storeXmlPropertiesToFile(
final Properties sourceProperties,
final String pathAndFileName)
{
try
{
FileOutputStream fos = new FileOutputStream(pathAndFileName);
storeXmlProperties(sourceProperties, fos);
fos.close();
}
catch (FileNotFoundException fnfEx)
{
System.err.println("ERROR writing to " + pathAndFileName);
}
catch (IOException ioEx)
{
System.err.println(
"ERROR trying to write XML properties to file " + pathAndFileName);
}
}

/**
* Runs main examples.
*
* @param arguments Command-line arguments; none anticipated.
*/
public static void main(final String[] arguments)
{
final PropertiesExamples me = new PropertiesExamples();
final Properties inputProperties =
me.loadTraditionalProperties("examples.properties");
me.storeXmlPropertiesToFile(inputProperties, "examples-xml.properties");
}
}


The class shown above reads in the properties file listed earlier and then writes it back out in XML format. The actual lines of code doing most of the work are small in number, but the many checked exceptions associated with file input/output make the code base much larger.

When this code is run, the following output is generated:

examples-xml.properties


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>This is easy!</comment>
<entry key="url.coloradosoftwaresummit">http://www.softwaresummit.com/</entry>
<entry key="url.rmoug">http://www.rmoug.org/</entry>
<entry key="url.blog.dustin">http://marxsoftware.blogspot.com/</entry>
<entry key="url.javaworld">http://www.javaworld.com/</entry>
<entry key="url.otn">http://www.oracle.com/technology/index.html</entry>
</properties>


This generated XML file contains the same name/value pairs as the traditional properties file shown earlier, can be read in like the traditional version using the Properties.loadFromXML, and includes the comment that was passed to the Properties.storeToXML method.

Conclusion

It is fairly straightforward to load properties from XML and to store them as XML. However, the XML is essentially limited to the same paradigm of name/value pairs as traditional properties files. Therefore, we are unable to take advantage of XML's hierarchical nature to use relationships more complex than one key (name) to one value. The primary reason one might use Java's support for XML-based properties is if XML was being used for other tools or frameworks and the properties in XML were more accessible to the other tool or framework.

Monday, January 26, 2009

A Java Exception Chaining Reminder

Java 1.4 introduced so many highly useful features that many projects were slow to migrate to J2SE 5 or Java SE 6. Even with all of these great new features, the simple exception chaining mechanism stands out as one of those small features that benefits me in my Java development (and especially maintenance) work on a near-daily basis. Many of us were implementing custom exception chaining work-arounds before this, but the standardized approach was highly welcome.

Although Java exception chaining is simple to apply, this does not mean it is applied uniformly. In his blog post A Pox Upon All of Your getMessage Calls, Ian Darwin (author of Java Cookbook) states that he has run across several Java-based web frameworks that do not provide sufficient exception information in wrapped exceptions. He also points out the superior information provided by passing a causal exception's toString()-based String to the constructor of the wrapping exception rather than passing the causal exception's getMessage()-based String.

Joshua Bloch devotes an entire chapter of Effective Java (Chapter 9 in the Second Edition) to discussion of effective practices related to Java exceptions. Bloch points out the problems associated with ignoring exceptions (item #65 in Second Edition) and recommends throwing exceptions that are appropriate for the particular level of abstraction. With these two concepts in mind, I want to move on to some Java code examples demonstrating the various approaches to re-throwing a new exception based on a causal exception.

For my admittedly contrived example, I will be using a custom exception called UninstantiableClassException. Its source data is shown next:

UninstantiableClassException.java


package dustin;

/**
* Exception class indicating situation in which a class cannot be instantiated.
*/
public class UninstantiableClassException extends RuntimeException
{
/**
* Constructor for this exception.
*/
public UninstantiableClassException(final String newExceptionMessage)
{
super(newExceptionMessage);
}

/**
* Constructor accepting an initial cause.
*/
public UninstantiableClassException(final Throwable cause)
{
super("Provided class cannot be instantiated.", cause);
}
}


The exception defined above has two constructors. One accepts a String argument and one accepts a Throwable. The constructor accepting a Throwable will be used to allow this constructor to completely wrap/chain a causal exception. The other constructor, the one accepting a String, will allow this new exception to be based on any provided arbitrary String.


The AbstractClass that cannot be instantiated is shown next:

AbstractClass.java


package dustin;

public abstract class AbstractClass
{
/** Some integer. */
private int someInt;
}



Finally, the code that executes the three examples is shown next.

ExceptionExamples.java


package dustin;

import java.lang.InstantiationException;

/**
* Class for demonstrating comparison of use of {@code toString()} versus
* {@code getMessage()} in exception translation.
*/
public class ExceptionExamples
{
/**
* Throw nested exceptions with getMessage().
*
* @throws UninstantiableClassException Thrown if class cannot be instantiated.
*/
public static void throwNestedExceptionsWithGetMessage()
{
try
{
final AbstractClass instance = AbstractClass.class.newInstance();
}
catch (InstantiationException instantiationEx)
{
throw new UninstantiableClassException(instantiationEx.getMessage());
}
catch (IllegalAccessException illegalAccessEx)
{
throw new UninstantiableClassException(illegalAccessEx.getMessage());
}
}

/**
* Throw nested exceptions with toString().
*
* @throws UninstantiableClassException Thrown if class cannot be instantiated..
*/
public static void throwNestedExceptionsWithToString()
{
try
{
final AbstractClass instance = AbstractClass.class.newInstance();
}
catch (InstantiationException instantiationEx)
{
throw new UninstantiableClassException(instantiationEx.toString());
}
catch (IllegalAccessException illegalAccessEx)
{
throw new UninstantiableClassException(illegalAccessEx.toString());
}
}

/**
* Throw nested exceptions with exception chaining mechanism.
*
* @throws Illeg
*/
public static void throwNestedExceptionsWithChainedException()
{
try
{
final AbstractClass instance = AbstractClass.class.newInstance();
}
catch (InstantiationException instantiationEx)
{
throw new UninstantiableClassException(instantiationEx);
}
catch (IllegalAccessException illegalAccessEx)
{
throw new UninstantiableClassException(illegalAccessEx);
}
}

/**
* Main function for executing exception examples.
*
* @param arguments Command-line arguments; lack of any argument indicates
* use of the {@code getMessage()} approach, an argument "tostring"
* indicates use of the {@code toString()} approach, and any argument
* other than "tostring" indicates use of exception chaining mechanism.
*/
public static void main(final String[] arguments)
{
if (arguments.length < 1)
{
throwNestedExceptionsWithGetMessage();
}
else if ("TOSTRING".equalsIgnoreCase(arguments[0]))
{
throwNestedExceptionsWithToString();
}
else
{
throwNestedExceptionsWithChainedException();
}
}
}



The main function above executes three methods defined to catch an intentionally thrown checked exception InstantiationException and re-throw it as the unchecked exception UninstantiableClassException defined above.

Each of the three methods constructs the re-thrown exception in a different manner. One approach shown is to use actual exception chaining and provide the causal exception (InstantiationException) as an argument to the constructor of the new exception. The other two approaches both rely on the String-argument constructor of the new exception. Because these approaches don't have access to the original exception, significantly less detail is available in the new exception than that which is available when the original causal exception is provided.

There may be times when one does not want to provide the causal exception to the new exception, but still wants to retain at least the name of the original exception in the next exception. This is where it is important to distinguish between getMessage() and toString. The API documentation for Throwable.toString() clearly indicates that toString prepends the name of the particular exception class to the message associated with the exception. Therefore, as discussed in Darwin's blog post mentioned previously, it seems that a developer should always use toString() rather than getMessage() when providing a String for construction of another (wrapper) exception. Even better yet, it is probably a good idea to generally prefer providing the causal exception itself to the new exception unless there is a reason not to do so.

The screen snapshot shown next shows the differences in results for the three approaches demonstrated by the code above. The approach using full exception chaining provides by far the most detail with a complete stack trace. The two String-based approaches show a similar level of detail with the one significant difference being that the use of toString() on the causal exception rather than getMessage() led to the inclusion of the causal exception in the message of the wrapping exception.





Conclusion

The information covered in this blog posting contains nothing new because Java exception chaining was introduced with Java 1.4. However, I have seen enough cases where exception chaining is not used to its full capabilities to think that it is worth a reminder post about the merits and simplicity of exception chaining.

My first choice is to use true and full exception chaining by passing the causal exception itself into the constructor of the new, wrapping exception whenever possible. When that is not desired for some reason (such as the wrapping exception is out of one's control and only has a String constructor1), then it is beneficial (without any extra effort) to provide the causal exception's message AND name via its toString() method rather than providing only its message (via the getMessage() method).


1The method Throwable.initCause(Throwable) actually can also be used to set the causal Throwable if the wrapping exception does not provide a constructor for this purpose.

Sunday, January 25, 2009

Software Development Communities: Size Matters

When it comes to comparing software development communities, it turns out that size does matter. When comparing two programming languages, most of us focus on things like syntactical differences, supported paradigms (such as object-oriented programming), deployment issues, performance, and many other factors. However, for large enterprise development, and especially for large enterprise development with many unknowns or risk factors, the size of the development community for that particular language can be an important consideration. The same argument can be made for frameworks, libraries, and other development tools.

While newer languages and frameworks with smaller development communities certainly have their advantages, there is no denying that some of their appeal can sometimes be traced to motivating factors such as the Magpie Effect, resume-driven development, Emperor's New Clothes Effect, Lemmings Effect, and other such motivators. Perhaps the most significant downside of working with these newer languages and technologies with smaller development communities is the corresponding lower amount of documentation and assistance that is available. For smaller projects, this is often not all that problematic. For large, long-term projects, however, I sometimes think we developers could be a little more understanding when "they" (management or clients) are somewhat concerned about using the fancy new language, framework, or toolkit. Regardless of whether one likes C, C++, Java, C#, or one of the other such languages, I think we can all understand how management/clients might be more comfortable going with one of these languages on a long-term, large project.

The flavor of the day may be great for a certain type of task for which it was designed. This in no way means that it is best for everything and I understand a manager's or client's hesitation to be one of the first to select a language that has been largely unproven in long-term, enterprise projects. The manager or client knows that any problem encountered with development using something like Java will be able to be dealt with in some way because so many large enterprise projects have used Java already. Furthermore, Java has been around long enough and been used by enough developers that many best practices have been developed. The forums are filled with experience from developers all over the world who have used Java. Even in areas where Java may not be as nice as another language we might compare it to, there are usually well-documented work-arounds for the deficiency.

The significance of size is not limited to programming languages. Most developers and managers are likely to be much more comfortable using the Spring Framework than using a framework that I might start tomorrow. Why? Because whether one likes Spring or not, one understands that Spring is very pervasive in the industry, has been vetted and used by a horde of developers, has significant SpringSource-generated documentation and third-party documentation, and has many forums filled with advice and answers to tough questions.

I'll use Flex as an example of this from my own career. When I began using Flex two years ago, it was new and exciting. The only drawback was that I could not always find the answers I was looking for immediately. I had gotten used to Google searches giving me answers for anything I asked in the Java world and had to get reacquainted with the Google message "Your search ---- did not match any documents" for some of my Flex queries. That was actually part of the excitement as I was able to blog on several tricks and nuances as I discovered them and provide original value for others to use.

Two years later, I still enjoy using Flex, but some of the newness is gone. The Flex development community feels many times larger than it was two years ago. While I was able to easily keep up with at least reading the headlines of any new Flex blog posting or article two years ago, there is no way I can do that now. I rarely see the "Your search ----- did not match any documents message" when Googling on Flex. The positive of all this, of course, is that it is much easier today to find one or more blog postings or articles covering most of the problems one might encounter with Flex. The much larger Flex development community makes it much easier to find answers to Flex questions and problems.

More developers in a given community implies more people to answer questions; more people to write articles, books, and blogs; more people using and testing the software of the given community; more people learning from experience and developing best practices; more people requesting bug fixes and improvements; and more people sharing new ideas. These advantages are especially desirable for large, long-term projects because it is those projects that can least afford to make a bad decision from which retreat is difficult. In these cases, it is understandable that managers and clients feel more comfortable going with a programming language, framework, or toolkit that they know many others have found success with. It doesn't hurt to know that there are developers available with those skills as well.

The size of the community of a particular product is less important when that product is used in such a way that retreat is easy if needed. For example, a toolkit that is only used for a small part of a large project might be easy to justify regardless of its small community because it is easily removed or replaced.

The size of the community is especially important in the open source world. I'm not referring simply to the active developers on the open source project. Rather, I am including all who use the open source product, who write about the open source project, who file bug reports against the open source product, etc. In my opinion, size of the community is especially important to open source because this community size directly relates to many of the advantages associated with open source.

Open source is often touted as advantageous because of advertised benefits such as potentially being tested by more people in more diverse and realistic environments, potentially quicker problem resolution, being subject to potentially greater code review, etc. However, these advertised benefits can only be realized if the community around that open source project is large enough to provide the greater use and testing, greater problem resolution, and greater code review. If I run a one-man open source project and I am the only user of that project, it is doubtful that the product enjoys any of these advantages compared to any serious commercial/proprietary/closed source competitor.

Even programming languages, frameworks, and toolkits with large communities started out with small communities. This reminds us that there is significant merit and potential associated with many products that currently have small communities. I am not saying in this post that we should only use products with large communities. What I am stating is that we should be more understanding when managers or clients prefer products with larger communities and that we should always keep in mind size of the community as one facet of our decision-making process regarding selection of a programming language, toolkit, framework, or other piece of our software development. There are many factors to be considered when selecting a particular product, but size of the community often deserves to be one of them.

My final thoughts are of appreciation for others who do take risks with products in smaller communities to help those communities grow and of my own satisfaction from occasionally playing with these products with smaller communities. While I often understand and even agree with managers or clients that we need to use the safer product with a larger community in our large enterprise projects, I also must admit that there is a thrill from playing with the latest gadget (language, framework, or toolkit). As with so many other parts of the software developer's life, I try to balance these and use them appropriately.

Saturday, January 24, 2009

The Java Community: More Useful Java Resources

My last blog post of 2008 covered Useful Online Java Developer Resources. That posting focused on resources for both learning new things and for finding solutions to specific problems. I found it interesting to compare Ted Neward's recently published list of Essential Java resources to the list in my posting. In this blog posting, I'll emphasize the resources that we mention in common as well as some resources that did not make his list that I think would have fit well (in some cases, they should have made my list as well in retrospect).

Neward lists many of the same web sites with good Java information that I listed in my posting: The Source for Java Developers, DZone, TheServerSide, Java.net, and developerWorks. One site that I have found very useful in learning about Java and wish I had mentioned in my original post after seeing it listed in Neward's article is ONJava.com. However, I think Neward missed a couple important Java sites that I did include: Javaworld and Oracle Technology Network's (OTN's) Java Developer Center.

As its name implies, JavaWorld is (and long has been) an important contributor in the world of Java. Meanwhile, Oracle has become one of the dominant influences and vendors in the Java community as well and has published many Java-related articles and how-tos. I have used articles and references from both sites many times in my career. I also admittedly have a bias toward these sites because I have written articles for both.

I did mention general blogs in my posting on useful general Java resources, but Neward lists three specific Java blogs in his posting that I find to be highly useful as well. Besides the well-known Java blogs such as Java Posse, JavaSpecialists, the Sun employees blogs (including Java Technology Blogs), and the Java.net community weblogs, there are numerous other useful Java-related blogs. Because the Java-related blogging community is so large, the search engines (including blog-specific search engines) can be invaluable. This is also where aggregated blog sites like JW Blogs and community sites such as JavaLobby can be helpful.

I agree wholeheartedly with most of the books on Neward's list of books (I only covered online resources in my previous post), but I do have a few Java-related books I'd add to the list: J2EE Design and Development, Java Cookbook, and Thinking in Java.

It is easy to dismiss the value of the somewhat dated J2EE Design and Development (note the J2EE rather than Java EE in the title), the book is so full of hard-earned experience and knowledge about enterprise application architecture, design, and implementation with a Java focus that it is still one of the best books on the subject. The success of the Spring Framework and the evolution of EJB since the publication of this book are two pieces of evidence for the impact this book has had.

The Java Cookbook is a resource for locating examples of how to do various tasks in Java. While it is particularly useful to someone new to Java, I still find it useful when doing something I have not done before or have not done in a long time. It is sometimes easier to find an example of even things I have done before in this book than it is to find it in my own code samples. Powerful search engines have made it easier to find similar examples online, but there are still times when it is easiest for me to locate the example I need in the printed book.

Older versions of Thinking in Java are currently available online at no charge. The Fourth Edition is the current edition that is available for sale. This book is used by many developers as an introduction to Java while being used by many experienced Java developers as a trusted reference and, along with Effective Java, as a sort of arbiter for Java-related debates.

Neward lists some good Java-related conferences in his article, but I think he may have missed one of the best by not listing the Colorado Software Summit. While I obviously have a reason for bias related to this conference, I not the only one to espouse its virtues. I'd also add Java User Group meetings as well. These regional groups can offer invaluable benefits at little or no cost. Many of these feature top-notch and well-known speakers who live in the local area or even sometimes present while visiting the area.

Conclusion

It is reassuring when the same sites make multiple Java developers' lists of useful sources of information. It is also interesting to see how different developers also have different preferred sources of information. I think that one of Java's biggest advantages is its sizable community and the sizable body of work out there related to Java development. The Java-related resources discussed in my previous blog posting, in Neward's article, and in this blog posting are evidence of the quantity and quality of resources in the Java development community.

Thursday, January 22, 2009

Flex HTTPService: When POST is GET

A relatively infrequently encountered nuance of Flex 3's MXML/ActionScript's HTTPService that one may run into occurs when the HTTPService.method public property is set to "POST", but the server actually receives a GET HTTP method instead of the anticipated POST. As documented in Http Service Get vs Post Issue? IS this a bug? and HttpService Post Shows as Get on Server Logs, this occurs when the HTTPService with the method set to "POST" has its send method invoked without any parameters.

In the unlikely event that it is important to have the POST request treated as POST on the server despite having no parameters to pass, one can use a dummy parameter to cause this to happen. The remainder of this blog posting will focus on code examples of this.

The HTTPService can be declared as an MXML tag as shown next.


<mx:HTTPService id="httpService"
useProxy="false"
resultFormat="object"
url="http://localhost:8080/httpServer"
fault="faultHandler(event)"
result="resultHandler(event)" />


The HTTPService instance shown above can have its method set to HTTP POST and be invoked as shown in the next ActionScript snippet.


httpServiceProxied.method = "POST";
httpServiceProxied.send();


Although the method is clearly set to POST, if no parameters are passed, it will actually be treated like a GET instead of a POST. A dummy object can be added to force the POST to be treated like a POST as shown in the next ActionScript code snippet.


const dummyObject:Object = { "key" : "value" };
httpServiceProxied.method = "POST";
httpServiceProxied.send(dummyObject);


Using the dummy object as shown above will force the POST to be treated as a POST. Note that parameters for an HTTPService invocation can be specified not only in the send() method, but can also be specified in the HTTPService declaration with the <mx:request> element.

While it at first seems a little strange that a POST is treated as a GET if no parameter is supplied, it does not seem nearly as strange when one considers that an HTTP POST is designed to serve as a resource-changing method and a parameter (enclosed entity) will typically be associated with such functionality. Conversely, an HTTP GET is a safe and idempotent method designed for retrieval of data and is probably the more usual HTTP method of the two to be called when no parameter is specified.

Finally, it is worth noting here that when the proxied HTTPService is used (such as with BlazeDS), POST is used when the method is set to POST regardless of whether a parameter is included or not.

Wednesday, January 21, 2009

Using RESTClient with Java's HttpServlet

I previously blogged about using RESTClient with the Sun JVM-provided HTTP Server. As I stated in that blog posting, I intend to use these tools to demonstrate HTTP and REST concepts at Rocky Mountain Oracle Users Group (RMOUG) Training Days 2009. I also intend to use the tried and proven Java HttpServlet in this presentation.

When I started using the Java servlet back in 2000, I read about the HttpServlet methods that correspond to the significant HTTP methods, but I didn't really override any methods in the majority of my servlets other than doGet and doPost. Looking back on the early servlet-focused books and articles, it is not surprising that this was the case because these materials focused on those two methods as well.

Although the Javadoc-based API information for Java EE 5 briefly discusses alternative methods in HttpServlet that can be overridden, many tutorials available even today focus on doGet and doPost. For example, the highly useful Java Servlet API Tutorial has an HTTP Support section that mentions the other methods but focuses on doGet, doPost, doHead. Similarly, the Java EE 5 Tutorial (PDF) also focuses on use of the HttpServlet's doGet method.

Roy Fielding's REST dissertation has been a significant catalyst in motivating many of us to think about HTTP differently. Specifically, we are now more inclined to think about the other methods supplied with HTTP. While many tools and browsers do not provide great support for all the major HTTP methods, the Java servlet has provided this support for some time and is an excellent mechanism for implementing and simulating operations that take advantage of the major HTTP methods.

It is very easy to take advantage of HttpServlet's support for major HTTP methods. This is demonstrated in the next code sample for the Java servlet class SimpleHttpServer.java:

SimpleHttpServer.java


package dustin.flex.rest;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
* Simplistic Java EE server-side application intended for demonstration of
* HTTP methods often use in REST-based applications.
*
* @author Dustin
*/
public class SimpleHttpServer extends HttpServlet
{
/**
* Servlet method responding to HTTP GET methods calls.
*
* @param request HTTP request.
* @param response HTTP response.
*/
@Override
public void doGet( HttpServletRequest request,
HttpServletResponse response ) throws IOException
{
final PrintWriter out = response.getWriter();
out.write("GET method (retrieving data) was invoked!");
}

/**
* Servlet method responding to HTTP POST methods calls.
*
* @param request HTTP request.
* @param response HTTP response.
*/
@Override
public void doPost( HttpServletRequest request,
HttpServletResponse response ) throws IOException
{
final PrintWriter out = response.getWriter();
out.write("POST method (changing data) was invoked!");
}

/**
* Servlet method responding to HTTP PUT methods calls.
*
* @param request HTTP request.
* @param response HTTP response.
*/
@Override
public void doPut( HttpServletRequest request,
HttpServletResponse response ) throws IOException
{
final PrintWriter out = response.getWriter();
out.write("PUT method (inserting data) was invoked!");
}

/**
* Servlet method responding to HTTP DELETE methods calls.
*
* @param request HTTP request.
* @param response HTTP response.
*/
@Override
public void doDelete( HttpServletRequest request,
HttpServletResponse response ) throws IOException
{
final PrintWriter out = response.getWriter();
out.write("DELETE method (removing data) was invoked!");
}

@Override
public String getServletInfo()
{
return "Server-side application demonstrating HTTP methods.";
}
}



This class can be referenced in the Java EE web descriptor file (web.xml) as shown next.

web.xml


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5" xmlns="http://java.sun.com/xml/ns/javaee">

<display-name>Simple Servlet Example Demonstrating Http Method Support</display-name>
<description>Demonstrates HttpServlet Support of HTTP Methods</description>

<servlet>
<servlet-name>SimpleHttpServer</servlet-name>
<servlet-class>dustin.flex.rest.SimpleHttpServer</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>SimpleHttpServer</servlet-name>
<url-pattern>/httpServer</url-pattern>
</servlet-mapping>

</web-app>


If we build the servlet shown above and assemble it with the web.xml file shown above into a WAR file that is deployed to a Java EE web server, we can then have clients contact the simple servlet via one of the four HTTP methods GET, POST, PUT, and DELETE (assuming the client is capable of using these different HTTP methods). In fact, we'll also see later in this blog post that even the HTTP methods TRACE, OPTIONS, and HEAD are supported by the HttpServlet. I did not override them in my servlet above because the default implementations of these methods (doTrace, doOptions, and doHead) typically work well for what we need.

For the example in this blog posting, I am deploying the assembled WAR with the servlet and web.xml file shown above to GlassFish (though any Java EE web/application server will work) using a context of restful. Coupled with the path defined in the web descriptor file and using the default port on GlassFish, my overall URL for accessing my servlet is http://localhost:8080/restful/httpServer. When I place this URL in my web browser, the results appear as shown in the figures below for Firefox and for Google Chrome.





Note that in both cases, the default method used for the browser communication with the servlet was HTTP GET. I will now begin using RESTClient to easily communicate with this servlet with alternative HTTP methods. This tool is provided as an executable JAR and is easily used, but additional instructions on using it are available here and here.

Because the browsers automatically demonstrated use of a client using HTTP GET to communicate with the server, I will begin showing RESTClient examples with GET as well. The following two screen snapshots demonstrate RESTClient showing the headers and then the body of the response. The HTTP response information is shown at the bottom of the UI.

HTTP GET Response Headers



HTTP GET Response Body




The two screen snapshots above use RESTClient to show the headers and body of the HTTP GET response. For POST, PUT, and DELETE, I will only show the bodies.


HTTP POST Response Body




HTTP PUT Response Body




HTTP DELETE Response Body




The response body for the TRACE method is shown next.

HTTP TRACE Response Body




The HTTP HEAD method works like the GET, but intentionally does not include a body. Similarly, the most interesting portion of the response for OPTIONS is also in the header. Because the HEAD's body is empty and the header looks like that for GET, I don't show it here. For OPTIONS, I show the headers rather than the bodies of those responses next. Note that the options provided by the server are shown in the "Allow" header field of this response.


HTTP OPTIONS Response Headers




As the "Allow" header field in the OPTIONS response indicates, the server supports the HTTP methods GET, HEAD, POST, PUT, DELETE, TRACE, and OPTIONS.


Conclusion

Although Java servlets are more than a decade old, they remain a powerful and highly useful technology. While they may not be as trendy as younger and more currently hip technologies, this blog posting serves as a reminder of how relatively easy it is to apply their rich features to modern-day development. Servlets have supported the major HTTP methods for many years and because of the HttpServlet's close association with HTTP, it is not surprising that the HttpServlet was ready for action when REST became a widely popular topic.

Monday, January 19, 2009

AIR-ifying a Flex/BlazeDS/Java EE Application

In my first blog post of 2009, I covered a simple example of applying BlazeDS's object remoting capabilities to associate a Flex client with a Java EE server. In this, my 250th overall blog posting, I intend to demonstrate how simple it is to adapt that Flex+BlazeDS application into an AIR+BlazeDS application.

Adobe Integrated Runtime (AIR) allows developers to apply their web development skills to desktop development. While AIR applications can be built from a starting point of DHTML/Ajax/JavaScript, I will be transitioning the Flex application demonstrated in my earlier blog posting into an AIR application for this example.

Douglas McCarroll provides informative coverage of a transition of a Flex application using BlazeDS remoting to an AIR application using BlazeDS remoting in his blog entry A Simple AIR / BlazeDS / Remoting Example. My posting here is a little different from his because mine does not rely on FlexBuilder, my example uses the same XML-based, statically configured channels used in the Flex example (McCarroll demonstrates dynamic, ActionScript-based configuration in his example), and I include some screen snapshots in this posting. Two other AIR+BlazeDS blog postings include Connecting an AIR Client with BlazeDS Using Spring/Hibernate and Connecting AIR with BlazeDS and Spring.

In my previous blog posting on Flex used in conjunction with BlazeDS object remoting, I had a very simple Flex MXML file that is reproduced here for convenience:

ComplexObjectRemoteClient.mxml (Flex)


<?xml version="1.0" encoding="UTF-8" ?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
width="1100" height="700">

<mx:Script>
import dustin.Person;

/**
* Prepare provided name information and send to server.
*
* @param firstName First name of person.
* @param lastName Last name of person.
*/
public function processAndSubmitName(firstName:String, lastName:String):void
{
const person:Person = new Person(firstName, lastName);
remoteObject.processName(person);
}
</mx:Script>

<!-- Associate client with BlazeDS destination via RemoteObject. -->
<mx:RemoteObject id="remoteObject" destination="HelloWorld" />

<mx:Panel id="mainPanel" title="BlazeDS Remoting Example - Complex Object Mapping">
<mx:Form>
<mx:FormItem label="Your First Name">
<mx:TextInput id="firstNameInput" />
</mx:FormItem>
<mx:FormItem label="Your Last Name">
<mx:TextInput id="lastNameInput" />
</mx:FormItem>
<mx:FormItem>
<mx:Button label="Submit Name!"
click="processAndSubmitName(firstNameInput.text, lastNameInput.text);" />
</mx:FormItem>
<mx:FormItem label="Server's Response">
<mx:Label text="{remoteObject.processName.lastResult}" />
</mx:FormItem>
</mx:Form>
</mx:Panel>
</mx:Application>



Not much is required to convert the above Flex client source file into an AIR client source file. In fact, I can keep the .mxml file extension for the AIR application source file and only need to make minor changes to the Flex source file just shown. The adapted source for AIR is shown next.

ComplexObjectRemotingAirClient.mxml (AIR)


<?xml version="1.0" encoding="UTF-8" ?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
title="Complex Object Remoting Migrated to AIR">

<mx:Script>
import dustin.Person;

/**
* Prepare provided name information and send to server.
*
* @param firstName First name of person.
* @param lastName Last name of person.
*/
public function processAndSubmitName(firstName:String, lastName:String):void
{
const person:Person = new Person(firstName, lastName);
remoteObject.processName(person);
}
</mx:Script>

<!-- Associate client with BlazeDS destination via RemoteObject. -->
<mx:RemoteObject id="remoteObject" destination="HelloWorld" />

<mx:Panel id="mainPanel" title="BlazeDS Remoting Example - Complex Object Mapping">
<mx:Form>
<mx:FormItem label="Your First Name">
<mx:TextInput id="firstNameInput" />
</mx:FormItem>
<mx:FormItem label="Your Last Name">
<mx:TextInput id="lastNameInput" />
</mx:FormItem>
<mx:FormItem>
<mx:Button label="Submit Name!"
click="processAndSubmitName(firstNameInput.text, lastNameInput.text);" />
</mx:FormItem>
<mx:FormItem label="Server's Response">
<mx:Label text="{remoteObject.processName.lastResult}" />
</mx:FormItem>
</mx:Form>
</mx:Panel>
</mx:WindowedApplication>


The most significant change was changing of the root element of the Flex source code (mx:Application) to the root element expected by AIR (mx:WindowedApplication). I also removed the width and height attributes associated with the Flex source code's root tag and replaced them with layout and title tags. The rest of the source file remain unchanged from the Flex version to the AIR version.

With the AIR source code easily in place thanks to the easy migration of Flex source code to AIR source code, I now move onto creating the AIR XML-based descriptor file. It is shown next (you can name it whatever you like as long as you reference it by the same name in the application packaging step shown later):

AIR-ComplexObjectRemoting.xml


<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://ns.adobe.com/air/application/1.5">
<id>blog.dustin.ComplexObjectRemoting</id>
<version>0.01</version>
<filename>ComplexObjectRemotingAirClient</filename>
<initialWindow>
<content>ComplexObjectRemotingAirClient.swf</content>
<visible>true</visible>
<systemChrome>none</systemChrome>
<transparent>true</transparent>
<width>1100</width>
<height>700</height>
</initialWindow>
</application>


It is important to note the AIR namespace used in this XML descriptor file. It is 1.5 because I am using AIR 1.5 and Flash Player 10. If I had 1.0 instead of 1.5 in that XML and was using AIR 1.5 and Flash Player 10, I might see an error message like that shown in the next screen snapshot.



The screen snapshot shown above states "Initial window content SWF version 10 exceeds namespace version http://ns.adobe.com/air/application/1.0" and provides the clue that either the namespace needs to be changed to 1.5 as shown above or the version of AIR and Flash Player needs to be reduced.

The adt command was used in the screen snapshot above that showed the error message when the AIR XML-based descriptor used a different AIR-related namespace than what was expected by the version of AIR and associated Flash Player. Before we can run the adt command as shown above, however, we must first compile our AIR source code into an SWF.

If you already have the Flex 3.2 SDK, you automatically have the AIR 1.5 tools you need. In fact, if you look in the bin subdirectory of your Flex SDK installation, you will see AIR-specific commands such as adt alongside the Flex command-line options such as mxmlc. The AIR command-line compiler, amxmlc, is located in this same directory. While we could run amxmlc directly, it simply is a call to Flex's mxmlc with the option +configname=air provided to the mxmlc compiler. This is discussed in greater detail in Compiling an AIR Application with the amxmlc Compiler.

The command-line syntax to compile the AIR source code shown above is thus:

Compiling AIR MXML Source Code into AIR SWF


mxmlc +configname=air -debug=true -context-root=HelloWorldRemotingServer -services=services-config.xml -output=ComplexObjectRemotingAirClient.swf -- ComplexObjectRemotingAirClient.mxml


With the AIR-based SWF generated, it is time to package up the AIR application. However, before doing that we need to generate a security certificate using adt as shown next:

Generating a Security Certificate


adt –certificate –cn DustinSigned 1024-RSA sampleCertificate.pfx dustinWasHere


The important thing to note for now from the command shown above for certificate generation is the name (sampleCertificate.pfx) and the password (dustinWasHere).

With the Flex MXML source code converted easily to AIR MXML source code and then compiled into an AIR SWF, with the AIR XML descriptor file generated, and with the security certificate generated, we are ready to package it all up into an AIR application with a .air extension. That command is shown next:

Packaging the AIR Application


adt -package -storetype pkcs12 -keystore sampleCertificate.pfx -storepass dustinWasHere ComplexObjectRemotingClient.air AIR-ComplexObjectRemoting.xml ComplexObjectRemotingAirClient.swf


With careful examination of the above command, one can see that adt -package is the basic command for packaging an AIR application and that it allows for the keystore generated earlier to be specified along with the password set up earlier (dustinWasHere). The name of the generated file that is the AIR application is the name ending with an .air extension and the XML descriptor and SWF file that go into that generated AIR file are listed after the generated file's name in the command.

To run the generated AIR application, its name (ComplexObjectRemotingClient.air) can be typed on the command line or the file name can be clicked on in a Window. Two screen snapshots that follow show some of what one sees when running this AIR application for the first time. These snapshots assume previous installation of the AIR runtime.





Assuming that the server-side servlet demonstrated in my earlier Flex blog posting is deployed on GlassFish or other Java EE-compatible web server, the AIR client shown above will go through a cycle that includes the following two screen snapshots.





One final gotcha to mention here in relation to using BlazeDS and transitioning from Flex to AIR is the need to make a minor tweak to the services-config.xml file used in the AIR client. In the Flex client, we got away with using the token {context.root} and having the Flex mxmlc command replace this token with the value specified with the -services option. I found that with the AIR client I needed to replace this context.root token with the actual context name. The reason for this is documented in the Flex Cookbook Beta under How to Configure the services-config.xml for AIR Application to Communicate with BlazeDS.

Conclusion

BlazeDS can be used with AIR and rich desktop applications very similarly to how it is can be used with Flex for rich internet applications. The AIR development model that allows for Flex applications to be easily converted into AIR applications makes it possible for Flex developers to write code that is easily ported between a web browser environment and a desktop environment. Because BlazeDS is useful with both Flex and AIR, Java EE back-ends can provide logic and data to back up rich web applications and rich desktop applications.

Saturday, January 17, 2009

Technical Certifications: The Good, the Bad, and the Ugly

With the current economic slowdown affecting the software development industry, it is likely that developers' interest in technical certifications may increase. Many of us in the software development industry have probably wondered at one time or another about the value of earning a technical certification and if the benefits of such a certification would be worth the effort and cost involved. Because much of the value of a technical certification is in the eye of the beholder, this is not easy to answer.

A significant part of the confusion and controversy surrounding the question of whether it is worth the effort to obtain a technical certification is due to the differences of opinions and perspectives we all have on the value of these certifications. For example, most of the very talented developers that I have worked with are not certified. However, I have worked with some certified developers who are very good while also working with some who aren't nearly so good at development. It is difficult for me to distinguish between the skills of those who are certified and those who are not certified. Indeed, Martin Fowler has articulated something that I have generally observed among software developers as well: "Certification programs are common in the software industry, yet most capable developers I know have very little regard for them" (quoted from Should there be a certification program for agile methods?).

Things can become clearer when one breaks down the decision in terms of personal control and personal benefit versus portions of the decision outside of one's control.



THE GOOD

Learning New Concepts and Skills

I believe that the best reason for earning a technical certification involves the learning of the material in preparation for the certification. While one may choose to earn a certification for more than one reason, I think he or she is most likely to be happy with the results if he or she sees the learning of material as one of the primary benefits and motivations of that process.

One of the reasons that learning the material can be the most beneficial part of the certification process is because it is completely within one's own control. The benefits gained from learning facts and concepts do not depend on the perspective or opinion of anyone else. The only required costs involved with preparation are time and effort. Some may choose to pay a little money to purchase preparation materials such as a book or pay a lot more money to take certification exam preparation courses, but these are not required.

Of course, if one is already strong in the area in which he or she is considering a certification, then the preparation itself may not be as obviously useful. However, my experience has been that reading books such as the SCJP Sun Certified Programmer for Java 6 Exam 310-065 can fill in areas of knowledge even for seasoned Java developers.

Learning new skills and concepts is something that is entirely within our own control and does not depend on anyone else's behavior or perspective.

Differentiation

All else being equal (but this is rarely the case), having a technical certification can differentiate one from other people applying for the same position or trying to win the same project from a prospective client. A person with a certification may not necessarily be selected over a person with a certification if the person without the certification can demonstrate being a better match through other experiences and qualifications, but having a certification is certainly one advantage (of hopefully many) that a person could advertise.

The degree to which a certification differentiates one from another is largely dependent upon the person making the decision. While one hiring manager or potential client may think the certification is a significant differentiator, another might not care much about it either way. In some cases, a particular certification may be required of anyone applying for a particular position. In such cases, the benefit of the certification is huge in terms of even having a shot at the position.

Evidence

An advantage of a certification is that it can be considered evidence of an individual having at least a certain level of knowledge on the subject. Without custom tests or probing interview questions, it can be difficult to distinguish the developer with seven year of Java experience doing the same thing the entire time from the Java developer with seven years of applying Java to a wide set of disparate problems and issues.

As with differentiation, much of the value of a certification as evidence of knowledge or skills depends on the perspective of the person making the judgment. One potential client or hiring manager may think that a certification provides strong evidence of skill while another may think it only provides mild evidence of any useful skill.

Summing up the Good

While a certification can help one differentiate himself or herself from others and while a certification can also be considered evidence of a developer having obtained at least a certain minimum level of competence in an area, these two benefits depend largely on people other than those who are actually certified. If a manager or client does not hold much stock in the value of a certificate for demonstrating competence or for differentiation of a job candidate, these benefits will be minimal. The actual learning of new knowledge and skills, however, can be of tremendous benefit to a developer and make him or her much better at what they do. The control of the degree of benefit for learning new material is in the hands of the person studying for certification and is therefore the most likely to achieve the benefits desired.

It is important to note quickly here that there are other ways to differentiate one self and at the same time provide evidence of one's experience and competence. These include things like presenting at conferences, presenting at user group meetings, writing articles and papers, writing blogs, participating in technical forums, etc. All of these can be cited to provide evidence of one's experience and competence and at the same time prove to be differentiating factors. It is somewhat a matter of taste which of these a person prefers to use to differentiate themselves and provide evidence of what the person has to offer. A certificate certainly appeals to the person who does not want to present or even write publicly. The question is, of course, what does your potential employer or client value most as a differentiator and as an evidence of your experience and skill set?


THE BAD

Perception of Fairness of Standardized Tests

There is some controversy surrounding the fairness of standardized testing, especially for undergraduate and graduate admissions and scholarships. Some of these same controversial issues can be associated with certifications that rely solely or heavily on standardized tests. Again, it is the judgment of the potential client or employer about the significance of a certificate being heavily or solely based on a standardized test that matters most. Whether I think it is fair or not really does not matter unless I am the evaluator.

Quality of Standardized Tests as a Metric

Perhaps even more troublesome for potential clients and employers regarding certifications that are based heavily on standardized tests is a question about how well the applicant's ability to answer (or possibly even guess) answers to multiple choice questions translates to real competence and real capabilities. Again, this question is far more significant in terms of the person evaluating the significance of a certificate than of the person who has the certificate. Even if I think the certification questions did a good job of testing my knowledge, that does not matter a whole lot if potential the potential employer or client does not agree.

In the previously cited post from Martin Fowler, he points out that some skepticism of certification programs directly relates to questioning of the relationship of the certification to competence.

Summing Up the Bad

The nature of a certificate can play a heavy part in influencing peoples' perceptions of the value of that certificate. I admit, for example, that I am more impressed with the Sun Certified Java Developer (SCJD) certificate than I am with the Sun Certified Java Programmer (SCJP) certificate because the Developer certificate involves an essay and a programming assignment while the Programmer certificate only requires a multiple choice evaluation.


THE UGLY

While these are some potential questions and reservations on the part of people regarding standardized tests and their credibility in determining a developer's competence, there are some really ugly things that can be far more damaging to the perceived value of a particular certificate.

Cheating

I maintain that the most valuable part of earning a certificate is (or should be in most cases) the acquiring of the actual knowledge and skills to enable one to pass fulfill the assignments and evaluations involved with that certificate. We have all heard that cheaters never win and that cheating only hurts ourselves. These are only partially true. Cheating on a certificate assignment or exam might actually benefit the cheater, especially in the short-term if he or she then has an unfair advantage over other applicants. While it is true that such cheating often does hurt the applicant in the long term because he or she will often be exposed for not really understanding that information and because he or she may not have the knowledge needed to be successful, it is certainly NOT true that cheating only hurts oneself.

Cheating obviously hurts those who take the same exam or fulfill the same certification requirements without cheating by providing an unfair advantage. However, I think that cheating can be far more damaging to others when it tarnishes the certification itself. Because the other guy's perspective is so important in the value of a certificate beyond the learning of the material, it is undesirable for that perception to be tarnished. If it is learned that mass cheating has reduced the ability to use the certificate as a differentiator or as evidence of knowledge gained, then the certificate becomes less valuable. The more cheating is perceived, the less the certificate is worth.

For a much more thorough discussion of how certification cheating hurts many people including the cheater, those who legitimately earn their certificate, employers (this includes clients), and the certification program itself, see Paul Sorensen's series of brief blog postings on the subject available via links on the conclusion post (Part 7).

Dirty Money

I like money. I wish I had more of it. No, actually I wish I had a lot more of it. That being said, money can cause trouble even with the best of intentions. One thing that just feels "a little dirty" is the convenient manner in which organizations that issue certificates also conveniently provide for-free training to help developers pass their certification requirements. I am not alleging that these organizations necessarily give any unfair advantages to candidates and I am definitely not insinuating that these organizations trade payment for training for a certificate.

I believe that most significant organizations that issue certificates do try to make it something of value to certificate holders. However, it can be a perception issue for the hiring manager or potential client if that person believes that the certificate training/issuance is more about building revenue for the certification organization than about actually demonstrating an applicant's competence. As discussed earlier, the ability of a certificate to actually demonstrate a strong correlation with a competent developer is most important. Whether it is the nature of the standardized exam or concern that the applicant has simply been spoon-fed information from the certificate sponsor, anything that potentially reduces the correlation of a qualified developer to an earned certificate can be dangerous to the value of that certificate.

It is only fair to point out that certificate sponsors are not the only ones who have monetary benefits from providing information to certificate candidates and might be tempted to cross a line to keep satisfied customers who will refer other customers to them. In fact, at least the certificate sponsor has a conflicting monetary interest in keeping the certificate a valuable item by not making it too easily achieved. Diluting the value of the certificate by making it too easy to obtain does not help them in the long term.

Good Intentions

It is not only companies and organizations trying to make a buck that might go too far in providing aids and help in fulfilling certification requirements. Previous certification candidates may have good intentions of helping others out by providing a retrospective on their experience. While this is a laudable goal, it can actually be a disservice to others who have earned the certificate if it goes to far and releases too much information.

Summing Up the Ugly

While there are some nice benefits associated with the certification process for both candidates and for future employers and clients, there is also an ugly side of this that seems to be present in any human endeavor that involves fame and fortune. Cheating and concern over the fox guarding the hen house are key aspects of the uglier side of the certification process.


FINAL THOUGHTS ON TECHNICAL CERTIFICATIONS

Technical certificates can be valuable to many employers and clients. They can provide evidence of potential employees' knowledge and capabilities and can provide candidates with another option for differentiating themselves. Perhaps most importantly, the goal of earning a certificate can provide a valuable goal or target that motivates a person to study for and prepare for fulfilling that certification's requirements.

The value of a particular certificate depends largely on the person. It would be a mistake to assume that just because I think a particular certificate is valuable or worthless means that another person feels the same way. Much of this perceived value of a certificate is out of our own control. The only aspect of the certification process that is entirely within our control is the opportunity to learn new concepts or to solidify our current knowledge.

With these thoughts in mind, I consider the following questions in deciding whether to pursue a certificate or not.

1) Does the certificate cover areas that I am interested in or think potential employers and clients will seek for future work? If so, that is a strong reason to at least start preparing for the certificate requirements.

2) Does the certificate have a good reputation? This is difficult to answer, but one could start to determine this by searching online for discussions regarding the certificate's value, by asking colleagues for their opinions, and possibly even asking prospective employers or clients about their opinions. Obviously, I'd be more apt to pursue the certificate if it was generally regarded as good indicator of a qualified individual. If the certificate itself has a tarnished image, it still may be worth preparing for it simply to learn the information even if it is never officially earned.

It is difficult to think of many negatives of preparing for a certification other than the investment of time and energy. The potential advantage of such preparation is significant, so the ratio of value to cost is very high. When it comes to actually paying for and taking any tests associated with certification, the ratio of value to cost depends on many factors including the certificate itself and the perception others have of that certificate. I believe that the person who earns a certification for his or her own satisfaction (such as learning new concepts or proving one's knowledge to one self) is generally more likely to be happy with the results than the person who primarily wants to be certified to influence others' opinions of him or her (such as employer or client).


Other Resources

Because much of the decision regarding whether to fulfill the certification requirements or not depends on others' perspectives, I attempt to provide a taste of some of these in a general and specific sense with the following links. It is not surprising that the sites selling certifications point out their many advantages. I try to balance these with some alternative views as well. A really thorough source of articles with focus on IT compensation and the value of certifications is Foote Partners in the Press Since 2005.

Hot Tech Certificates in a Cool Job Market

Why Certify? Importance of IT Certification

Certification: Is ANY Certification Worth Pursuing?

Study Shows Downside of IT Certifications

• Martin Fowler: Should there be a certification program for agile methods?

Certification Uncertainty

Java Certification

Oracle Certification Program

Microsoft Certifications Overview

Certain Measures for Uncertain Times

Noncertified IT Pros Earn More than Certified Counterparts

Get Certified

Here's One Major Employer that Requires Its IT Folks to Be Certified

To Certify or Not to Certify: Getting Paid for Your Skills

Oracle Certification: To Certify or Not to Certify?

SpringerLink: To Certify or Not to Certify?

The Hub Certifications: Why Get Certified?

UPDATE (18 January 2009): The following links to related resources have been added since the original post.

• Eli White: Programming Certifications

Java: Why Certify?

Does Certification Really Matter?

Certifications - May I See the Menu?


UPDATE (19 February 2009): The following links to related resources have been added since the original post.

DeMarco on Certification and Licensing of Software Engineers

Do Certifications Matter?


UPDATE (1 May 2010): The following links to related resource were added since the original post.

• "Uncle Bob": Certification Don't Waste Your Time!

Okay, Let's Talk About Certification