About This Blog

Hi, I'm Ben Pryor. This blog contains my thoughts about general software engineering topics, and occasionally specifics that I find interesting. If you see something here that sparks your interest, please feel free to comment on a post or send me an email at ben at benpryor.com.

17 March 2006 - 14:15Technical Books

Every professional software developer that wants to take responsibility for their own career should be buying their own technical books on a regular basis. Buying your own technical books is the most efficient way (financially speaking) to grow as a developer. Compared to attending conferences, taking certification exams, being in college courses, and other forms of professional training, you simply can’t beat the value of a buying and reading a tech book.

A system that works well is to buy three new technical books each month. This will average out to around $100 per month, or around $1200 annually for 36 new books in your personal tech book library each year. Three books each month is a fair amount of reading, and it works best if you read a little bit every day, perhaps a chapter or two.

When buying your three books each month, it’s often nice to have them fit into a theme of some kind. For example, one month I might decide I’d like to learn more about transaction processing concepts. I might buy this book, this one, and this one for about $110. Or I might decide to investigate the Ruby language and buy this book , this one, and this one for about $71. It’s important to not buy the same kinds of books each month - the idea is to stretch yourself, not to reinforce your currently held views and opinions (more on this later).

A good way of keeping track of the books you’d like to buy is to create an Amazon.com wish list. Keep a queue of books ready, and each month when it’s time to buy the three books you can select them directly from your queue. Every time you come across a book that sounds like it might be a good read, add it to the wish list. Then every so often prune your wish list down by reading reviews and removing books that don’t seem useful to read. Using an Amazon wish list is also nice because you can add not-yet-released books when you first hear about them, and buy them after they’re released.

Previewing books in a local bookstore is also a nice way to see if a book is worth buying and adding to your collection. However, using this approach exclusively will slant your library so that it favors books that are popular and selling well right now, and will miss a lot of valuable books. Make sure to also consider books that were written ten, fifteen, or even thirty-five years ago that you likely won’t find on the shelf at your local bookstore.

Perhaps the biggest objection to this system is that $1200 annually may seem like a lot of money to be spending on tech books. If it does, go take a look at the website for Sun’s JavaOne conference. This year, the conference prices start at $1600, and go up to $2700. That’s for a 4-day conference, during which you would likely learn a lot of neat things, but also would have to filter out lots of vendor-driven marketeering material too. A much better value for a tech conference is the No Fluff Just Stuff series at $800 for a 3 day conference (no vendors allowed), but even that conference still doesn’t come close to the value of buying your own books.

If you can’t afford to set aside $100 each month to spend on becoming a better developer, then start by canceling any cable TV / satellite / Netflix subscriptions. Then give away your TV. Seriously. You (and your family/friends) will love the extra time you’ll gain, and you’ll have some more time and money to spend on professional development.

Some developers are lucky enough to be working at a company that regularly spends money on adding to an internal technical book library. For a developer in this enviable situation, it’s tempting to decide not to purchase your own technical books. However, in this case it’s even more important to buy your own books. Your tech reading should be covering different topics and concepts than those you work with on a day-to-day basis. It’s the same reason that learning a language like Lisp will make you a better Java programmer. It’s all about forcing yourself to constantly enlarge the box you think in.

In the same vein, don’t purchase many tutorial or reference style tech books. These books usually contain information you can easily find on the Internet for free, and the information is often out of date by the time the book is published. If you really need such a book to do your job, then get your employer to purchase it so your whole team can share the book. For instance, buying this 1000-page tome might be useful for a short time, but you’ll probably not treasure it on your bookshelf for years to come.

It’s also important to make sure that all of your reading doesn’t involve technical materials, or you’ll have a very one-natured view of the world. In addition to your tech reading each month, it’s vital to include some other materials. Public libraries are great for this kind of reading - often you will want to read books that aren’t very useful to own, so borrowing them for a few weeks to read is perfect. By throwing in a couple of works of fiction, some history books, and some books on current events, you’ll nicely round out your reading mix for the month.

If your job involves being mostly on the development side of the fence, make sure to include some business-related readings each month. I once received some great advice from a former manager of mine who was very involved in the business activities of the company. His advice was that if you’re a software developer who wants to get a better understanding of business, then get a subscription to Forbes, Money, or some other business magazine, and read it through each month. Some parts may seem boring or use some unfamiliar terms, but after some time, you’ll become more familiar with the lingo of business, and even find it interesting. This will make you a more valuable developer and provide some additional context and insight to your day-to-day tasks.

Finally, a note on ebooks: electronic versions of books are great. They’re nice because you can quickly search through them when looking for a piece of information, and for this reason they’re very appropriate for the reference or tutorial-style books I mentioned above. Tech publishers like Apress and The Pragmatic Programmers often offer a large discount on an ebook if you buy the printed version, and a lot of times it’s worth it to pay a little more for a portable, searchable version of the book in addition to the paper copy. Having said all that, the bulk of your tech book library should still be dead-tree versions of books. A paper version of a book is uniquely yours - you can mark it up, bookmark pages, add notes in the margin, and customize it in any way you like.

No Comments | Tags: Uncategorized

16 March 2006 - 10:46Variations on Publish / Subscribe

Introduction

The publish / subscribe pattern, also known as the observer pattern, is one of the most widely used of the originally cataloged design patterns. It’s a pattern that decouples an object that generates events (the subject) from objects interested in reacting to those events (observers or listeners).

The observer pattern is used more often in client-side GUI applications that other types of programs, but it is a generally applicable pattern. The reason it’s used more in GUI apps is that these kinds of programs tend to be externally event driven, so modeling the internals of the application with an event-driven approach feels very natural and intuitive. Another common use of this pattern is to decouple different logical layers of a program from each other, in order to support different functionality or even different applications that reuse a common base layer.

Even though the observer pattern is widely known and used, there are lots of innovative variations on the pattern that don’t appear as often. I’m going to catalog a few of these variations, but the following list is by no means comprehensive. There are lots of permutations of publish / subscribe out there.

All the variations I’m about to describe have one thing in common: they encapsulate the logic needed to store a collection of listeners and send events to them, so the code that does this doesn’t need to be duplicated throughout an application. I call this code a multicaster. So when you see the term multicaster used in the discussion below, it’s equivalent to “the code that manages a collection of listeners and fires events to them”. I call it a multicaster because the subject (event generator) uses the multicaster to push an event out to a collection of listeners for that event.

Making a Multicaster Look Like a Listener

Consider a very simple interface for a listener object that receives an event:

public interface MyEventListener
{
	public void onEvent(MyEvent event);
}

One interesting multicaster implementation is to have the multicaster itself implement the listener interface. The “fire” method simply sends the event to any listeners being managed by the multicaster. With this implementation, the multicaster presents the illusion that there is only one listener, and that the event is being sent once to that listener.

There are two basic ways to implement this variation. You can either hard-code the relevant listener interfaces to your multicaster implementation, or the multicaster implementation can be made more general-purpose by using a runtime proxy approach like Java dynamic proxies.

For an example of the first (non-proxy) approach, take a look at the class java.awt.AWTEventMulticaster that ships with the Java standard library. This is a multicaster implementation that looks like a listener - it directly implements 17 different AWT listener interfaces.

Probably the biggest downside of the multicaster-as-listener approach is that a general purpose multicaster must use runtime proxies (since the Listener type isn’t known at design time), and is always going to be slower because of the runtime proxy generation and overhead. However, this performance hit is often acceptable to many systems, and with techniques such as byte code manipulation, the overhead of runtime proxies can be greatly reduced.

You can find a good example of this approach on the following web site: http://www.t-deli.com/listeners.html. This general-purpose Multicaster implementation generates a runtime proxy that implements a Listener interface. The implementation uses either Java dynamic proxies or (optionally) a 3rd party library to create proxies by bytecode generation.

Managing Lots of Event Types

When designing part of a system that uses the publish / subscribe pattern, it’s common to get to the point where you have more than a handful of individual event types, and it can become tedious to write multicasting code for each event type (even if much of that code is reused in some way).

A nice solution to this problem is a multicaster API that has the same level of complexity whether you have 1 or 100 different event types. For instance, consider the following multicaster API:

public interface Multicaster
{
	public void registerEventType(Class eventType, boolean hierarchical);
	public void registerListener(Object listener);
	public void fireEvent(Object event);
} 

In my current project, we’ve written a multicaster implementation with a very similar API to the one above. The multicaster makes a few assumptions about the signature of listener methods: namely, each listener method is a void method that takes a single parameter of an event type. This Multicaster works through reflection. Before you can begin doing real work with it, you need to tell it what events look like. This is done by registering event types (or event base classes if your event types have a hierarchy). Once the multicaster knows which types are valid events, it can reflectively examine each listener added to it to see if the listener can accept any of the known event types. The registered listeners are categorized according to the event types they can receive, and when an event is fired on the multicaster it broadcasts the event to the appropriate listeners.

The big win with a multicaster implementation like this one is that adding new events to the system is trivial and safe - none of the eventing infrastructure needs to be modified in order to support a new event type. Listener interfaces are optional with this design (since “listenability” is dynamically determined) but we still use them for clarity.

Dealing with Concurrency

Here’s what a simple implementation of a multicaster could look like:

public class Multicaster
{
	private Set listeners = new HashSet();

	public synchronized void addListener(Listener listener) { listeners.add(listener); }
	public synchronized void removeListener(Listener listener) { listeners.remove(listener); }
	public synchronized void fireEvent(Event event) 
	{
		for (Iterator it = listeners.iterator(); it.hasNext(); )
		{
			((Listener) it.next()).recieveEvent(event);
		}
         }
}

Note that all the methods use the synchronized keyword to ensure the class works correctly while being used by multiple threads. This implementation is correct, but has potentially poor performance and isn’t appropriate for a general-purpose Multicaster implementation. The reason is that when the Multicaster fires an event on a listener, it is effectively yielding control to that listener for some unknown amount of time - during which the event firing thread holds the lock on the Multicaster object. This approach forces other threads that simply want to subscribe or unsubscribe a listener to wait for the firing thread.

A common solution to this performance problem is to create a copy of the collection of listeners before firing an event on them. The Multicaster lock is held only long enough to make the copy, and then released while the event is being fired. The fireEvent method above would change to look like this:

public void fireEvent(Event event)
{
	Set copy;
	synchronized(this)
	{
		copy = new HashSet(listeners);
	}

	for (Iterator it = copy.iterator(); it.hasNext(); )
	{
		((Listener) it.next()).recieveEvent(event);
	}
}

This solution is nice because it narrows the window of time during which the lock is held by an event firing thread. This implementation can be improved further by keeping the copy of the collection around, and only re-creating the copy when the real collection has been changed. For many uses of publish / subscribe, the ratio of publication to subscription is high, so only copying when necessary can yield a large performance gain.

In his newest book, Allen Holub presents a very elegant solution to the concurrency problem with publish / subscribe. He manages to come up with a Multicaster implementation that has good performance under high concurrency, and doesn’t suffer from the “copying the listeners too often” problem. In fact, Holub’s implementation doesn’t use the synchronized keyword at all. Instead, the synchronization is “built into” the data structure he used.

The implementation stores the listeners in a linked list, adding new listeners to the head of the list. Events are fired by walking down the list and firing on each listener. If another thread comes in and adds a new listener, it will be able to immediately modify the head of the list without impacting the thread already walking the list to fire listeners. The remove listener case is a little more complicated, and involves making a new copy of the section of the linked list up to the point where the listener to be removed is. The remove case can also happen at the same time that a firing thread is walking down the original list.

This implementation demonstrates an important principle: instead of using synchronization keywords and primitives as a band-aid approach, applied externally to protect access to a data structure, it’s much better to design the data structure to be concurrent in the first place. The code comprising Holub’s Multicaster implementation is short, concise, and easy to understand, while at the same time working correctly under concurrent access.

Conclusion

There are probably lots of interesting variations on publish / subscribe that I failed to mention. If I come across notable implementations in the future, perhaps I’ll do another entry on the subject.

The most important aspect of any of these variations on the publish / subscribe pattern is that they encapsulate the eventing logic itself. This helps keep the application code clean and DRY.

No Comments | Tags: Uncategorized

8 March 2006 - 9:19Implementing Active Objects with Java Dynamic Proxies

Introduction
The Active Object pattern is a pattern for writing services that deal with the issue of concurrency in an unorthodox and elegant way. The simple definition of an active object is that it’s an object that is responsible for managing its own execution context instead of using the execution contexts of objects that call methods on it. Active objects are different from passive objects (normal objects) because passive objects re-use the execution context of other objects who call methods on them.

To make the distinction clearer, consider a normal Java object. When a second object calls a method on it, that method executes inside the same JVM process and thread as the caller method. Many times the object being called will have some concurrency requirements - access to that object may not be thread-safe so it must be serialized, or perhaps internally the called object serializes access to some data. On the other hand, when a method is called on an active object, control returns immediately to the caller, and the active object executes the method in some execution context that it manages. The active object may keep an internal worker thread (or pool of threads) to perform execution. A more advanced active object may delegate execution to a different process or a different computer.

For a much more detailed description of the Active Object pattern, see a University of Washington paper by Lavender and Schmidt. This paper discusses the motivation behind the active object pattern, shows a sophisticated implementation of the pattern, and explains some of the disadvantages of the pattern.

If you’re thinking to yourself at this point that the active object pattern doesn’t seem terribly complicated, you’re right. However, now that the free lunch is over, patterns like this one are going to become increasingly important as a means of improving the concurrency of programs and taking advantage of newer hardware.

Advantages of Active Objects
The cool thing about an active object is that is relieves clients of that object from having to deal with concurrency. It’s a much more elegant solution to concurrency problems than using something like the synchronized keyword which can block the caller’s execution context. An active object elegantly separates method invocation from method calling, and allows different strategies for method invocation to be used without having to modify calling code.

In addition, when active objects are realized using the proxy approach (which I’ll discuss below), they also relieve the service object from having to deal with concurrency. Active objects are so elegant because they wrap up all the concurrency handling in such a way that neither caller nor callee need to be written in any special way to deal with concurrent access.

Disadvantages of Active Objects
Active objects have a few disadvantages, of course. The main disadvantage is that all interactions with an active object happen asynchronously, and this style of method calling is not the most natural. Any method that returns a value cannot be used with the active object pattern. Instead, code must be written in an asynchronous style, where active methods take callback objects as parameters and notify their callers when execution has finished. While this style of programming isn’t as natural, it usually doesn’t take much effort to convert an interaction that’s written synchronously to be asynchronous.

As a side note, I believe the asynchronous style of programming is going to become more and more common as programming languages and libraries attempt to exploit high concurrency hardware to a greater degree. It makes sense to become familiar with this pattern now, as it’s very possible that in the future most method invocations will be written this way.

Another disadvantage of active objects is that they introduce a level of complexity and indirection that makes debugging difficult. Using a debugger to step through a call to an active method isn’t terribly useful, since the call returns immediately and the actual work of the method happens in another execution context.

Java Implementation
Now that I’ve introduced active objects and explained what’s good (and bad) about them, the rest of this entry is going to discuss a simple active object implementation in Java. The pattern itself could be implemented in any programming language, but Java has one particular feature that makes implementing active objects very easy.

A common way of implementing an active object is to use the proxy pattern. When implemented this way, both the service implementation and the client can be written in such a way as to have no concurrency concerns at all. A third actor, the proxy, wraps the service implementation and exposes the service interface to callers. The proxy object is responsible for managing an execution context and (eventually) invoking the service methods on the actual service object.

Java dynamic proxies are a perfect fit for implementing active objects in this way. In case you’re not familiar with dynamic proxies in Java, I’ll give a very quick description of them, and for more detail you can check out the official documentation. In a way, dynamic proxies are the opposite of reflection. Reflection allows you to generate method calls at runtime, and dynamic proxies allow you to generate method responses at runtime. Dynamic proxies allow you to “manufacture” an implementation of any interface at runtime by supplying a callback object that will get invoked for any interface method call. The most common use of dynamic proxies is to wrap some real implementation of an interface with some other service. For example, I could implement a very simple profiler by writing a dynamic proxy that wrapped a real service object, and kept track of the amount of time spent inside each method.

Writing a dynamic proxy to implement an active object is pretty simple. The proxy’s InvocationHandler keeps an internal worker thread. As methods are invoked on the proxy, the java.lang.reflect.Method objects and arguments are added to a queue, and control returns immediately to the caller. The internal worker thread pulls methods off of the queue and invokes them on the wrapped service object.

It’s easy to imagine a more advanced active object that spreads the work out over a pool of worker threads, or perhaps uses RMI to send work to other computers to spread out the computation load. The great thing about using dynamic proxies for this is that the original service implementation doesn’t need to know anything about what the active object proxy is doing. The only restriction is that the original service interface must be written in terms of asynchronous methods for this to work.

The following code demonstrates an implementation of the active object pattern using dynamic proxies. The first class is an InvocationHandler that implements a generic active object proxy. The second class is a test harness with a trivial service that adds two integers. If you run the code, note that all the calls to the adder service finish long before the results are done being computed (an artificial delay was put in the adder service to illustrate this point better).

public class ActiveObjectProxy implements InvocationHandler
{
    private List callQueue = new ArrayList();
    private Object serviceObject;

    public ActiveObjectProxy(Object serviceObject)
    {
        this.serviceObject = serviceObject;
        new WorkerThread().start();
    }

    private synchronized void put(Invokable invokable)
    {
        callQueue.add(invokable);
        notifyAll();
    }

    private synchronized Invokable get()
    {
        while (callQueue.size() == 0)
        {
            try
            {
                wait();
            }
            catch (InterruptedException e) {}
        }

        return (Invokable) callQueue.remove(0);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    {
        Invokable invokable = new Invokable();
        invokable.method = method;
        invokable.args = args;
        put(invokable);
        return null;
    }

    private class WorkerThread extends Thread
    {

        public void run()
        {
            while (true)
            {
                Invokable invokable = get();
                try
                {
                    invokable.method.invoke(serviceObject, invokable.args);
                }
                catch (Throwable t) {}
            }
        }
    }

    private static class Invokable
    {
        public Method method;
        public Object[] args;
    }
}
public class ActiveObjectTest
{
    public static void main(String[] args)
    {
        AddService addService = (AddService) 
            Proxy.newProxyInstance(
                ActiveObjectTest.class.getClassLoader(), 
                new Class[] {AddService.class}, 
                new ActiveObjectProxy(new Adder()));

        AddResultsCallback callback = new AddResultsCallback()
        {
            public void addResultsComputed(int x, int y, int sum)
            {
                System.out.println(x + ” + ” + y + ” = ” + sum);
            }
        };

        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 60; i++)
        {
            addService.add(2  i, 3  i, callback);
        }
        long elapsed = System.currentTimeMillis() - startTime;

        System.out.println(”All calls finished: ” + elapsed + ” ms elapsed”);
    }


    private static interface AddService
    {
        public void add(int x, int y, AddResultsCallback callback);
    }

    private static interface AddResultsCallback
    {
        public void addResultsComputed(int x, int y, int sum);
    }

    private static class Adder implements AddService
    {
        public void add(int x, int y, AddResultsCallback callback)
        {
            int sum = x + y;
            try
            {
                Thread.sleep(1000);
            }
            catch (InterruptedException e) { }
            callback.addResultsComputed(x, y, sum);
        }        
    }
}

No Comments | Tags: Uncategorized

6 March 2006 - 15:22Book: Freakonomics


Over last weekend I read the book Freakonomics by Steven D. Levitt and Stephen J. Dubner. It was a quick, interesting read, and I highly recommend the book for anyone developing software. While the book doesn’t discuss any software development topics directly, the underlying themes of the book are very applicable to anyone programming computers.

If I were to summarize the book in an equation, it would be:

interesting questions + statistical data = surprising conclusions

The book asks a number of interesting, sometimes off-beat questions, and then proceeds to answer them by using statistics and economics. The answers are often surprising because they are counter-intuitive at first glance. It’s a fun read just for the conclusions it draws in areas of life such as homelessness, racial tensions, real estate, baby names, and lots others.

One premise of the book is that conventional wisdom is often wrong. Freakonomics explains that conventional wisdom often is formed from ideas that have the following two properties:

1) The idea is easy to understand and explain to others
2) The idea aligns closely with self-interest

In other words, if an idea is simple enough to be internalized by many people, and that idea seems to be in the self-interest of the average person, then that idea often becomes conventional wisdom, whether it’s true or not. Of course, the point is not that all conventional wisdom is wrong, but simply that conventional wisdom needs to be scrutinized and not accepted at face value.

Another theme of the book is that when statistics are collected and analyzed, the results are often surprising and contradictory of intuition. This principle resonated with me as a software developer, as it is the reason why premature optimization hardly ever works. Relying on intuition instead of measurements is usually wrong - but often seems attractive.

My main takeaway from this book was a reminder to always measure and look at data before drawing conclusions. Reading it was a good encouragement to question conventional wisdom, whether in social issues or software development.

No Comments | Tags: Uncategorized

3 March 2006 - 13:38Top 10 Tips For New Eclipse Users

I’ve used Eclipse professionally since the 2.1 release, and over time I’ve learned many tips and tricks to make using the IDE more enjoyable (and to make me more productive). In this entry, I’m going to share my top 10 list of basic Eclipse tips. These are very simple tips, but I’ve noticed that for some reason many people using Eclipse for the first time end up learning these tips the hard way (through discovery). The following 10 tips should be known by anyone using Eclipse on a day to day basis. In future entries I’ll share some advanced tips - but first the basics.

1 Use Code Assist

Code assist (also known as auto-complete) is the kind of feature that becomes almost completely automatic after a very short time. Most modern IDEs have a similar feature - for instance, Visual Studio calls it Intellisense.

The concept is simple - just press the code assist key combination (by default ctrl-space) and the IDE will either fill in where you’ve started typing or display a menu to allow you to choose an auto-completion from several possibilities.

This is the feature you will use the most in Eclipse. I just noticed that I can type ctrl-space without moving my fingers from the home position at all :).

2 Navigate Through Code By ctrl-Clicking

This is another feature that you stop consciously thinking about once you’ve gotten in the habit. While editing, you can move to a field, method, or class by holding down the ctrl key and clicking on the identifier you’re interested in. This makes navigation dead simple.

When looking through unfamiliar code, this feature is great. If you are wondering what a class is, or what the implementation of a method looks like, it’s as easy as ctrl-clicking it.

3 Quickly Open Classes and Resources by Name

There are two ways to open a class or resource in an editor: the slow way and the fast way :). Don’t use the slow way - there’s no good reason to.

To open a Java class, press ctrl-shift-T. This will display a dialog box that allows you to type in a class name. To open a non-Java resource (a .txt file for instance) use the ctrl-shift-R shortcut. These open boxes support wildcards, partial names, and even camel case names (try typing ctrl-shift-T, AIOOBE to see camel case search in action).

There is hardly ever a reason to use the Package Explorer view to manually pick out a class to open if you know its name.

4 Know the Keyboard Shortcuts

Eclipse has extremely good keyboard shortcut support. Most of the common operations have an associated keyboard shortcut, and learning these keyboard shortcuts is the most effective productivity boost you can give your Eclipse experience.

There are too many keyboard shortcuts to enumerate them all here, and the previous tip already mentioned two of the most useful shortcuts. However, I will list the shortcuts I think are most useful:

ctrl-shift-G: searches for references to a highlighted class, method, field, or variable
ctrl-shift-F4: closes all open editor windows
ctrl-o: outline popup - very useful for quickly jumping to a method in a large class
F4: shows the hierarchy viewer for a class (ctrl-T shows similar data in a popup version)
ctrl-m: toggle maximize of the current editor or view
ctrl-F11: run the last launched configuration

There’s even a keyboard shortcut you can press that will show you all available keyboard shortcuts in the current context: that’s ctrl-shift-L.

It’s worth noting that the keyboard shortcuts can be customized. However, I don’t recommend you do this. It makes pair programming and team collaboration harder because each machine may have a different set of keyboard shortcuts. The shortcuts Eclipse ships with are good defaults - I recommend leaving them that way.

5 Set the Heap Size

Eclipse is a large, complex, Java-based IDE. It needs lots of memory to perform well. In fact, if you’re using Eclipse to do daily development, you should configure your machine so that Eclipse can use RAM in preference to any other processes.

When starting Eclipse, you should always specify a large maximum heap size. The default Eclipse uses is far too small for normal use. There are lots of ways to specify this when starting Eclipse (see Google). The easiest way is to use the -vmargs parameter with the Eclipse native launcher executable:

eclipse -vmargs -Xmx1024M

That syntax will work only on Sun’s JVMs, by the way. And, yes, I do give my IDE 1GB of RAM to work with. My development box has 4GBs so I have plenty to spare :).

6 Configure Eclipse To Use a JDK, not a JRE

Eclipse comes with its own Java compiler, so technically you don’t need to install a Java Development Kit (JDK) from Sun to develop Java programs with Eclipse - a Java Runtime Environment (JRE) works just fine.

However, you’re going to want to install a JDK and configure Eclipse to use it. The reason is that this is the easiest way to get the Java source code into your development environment. Doing this will allow you do set browse into and set breakpoints in Java classes, as well as giving you Javadoc support in the IDE for all the standard library classes and methods.

To configure Eclipse to use a JDK, first make sure you’ve installed a JDK on your machine. Then in Eclipse, go to Window -> Preference -> Java -> Installed JREs, and make sure that the default (checked) JRE points to your JDK installation.

7 Use the Eclipse’s Refactoring Support and Code Generation

Eclipse originally became popular because of its support for various kinds of refactorings
of Java classes. These refactorings are still some of the best of any IDE available today.

Many of the refactorings are somewhat hidden and will show up when performing other operations, but you can get started with refactorings by right-clicking in the Package Explorer and looking at the Refactor and Source menus.

Eclipse also has extensive support for code generation. If you’re writing constructors, getters, or setters by hand then learning to use code generation for this will be a huge time saver. Looking at the Source menu mentioned above will get you started with code generation.

8 Use Multiple Workspaces Effectively

Eclipse supports a concept called workspaces. A workspace is a container of projects that has its own set of preferences and metadata. An installation of Eclipse can work with multiple workspaces - you can tell Eclipse which workspace to use when starting up.

Why are multiple workspaces useful? Many developers create an Eclipse workspace for each version of an application, so doing maintenance work and new development don’t conflict. This maps very naturally to branches in a source control system. Multiple workspaces are also good for separating different projects you may be working on at the same time.

The easiest way to specify which workspace Eclipse uses is to use the -data and -showlocation parameters with the launcher:

eclipse -data c:\myworkspace -showlocation

The -data parameter directs Eclipse to use the “c:\myworkspace” directory on the local machine as the workspace directory. The -showlocation parameter shows the workspace location in the Eclipse title bar - very helpful when running multiple Eclipse instances at the same time.

One note - don’t waste time setting your preferences in each workspace you create. Simply use the Import and Export options under the file menu to export preference from one workspace you’ve already set up into new workspaces you create.

9 Use Templates

Eclipse has two different concepts of templates. I’m not going to talk much about Code Templates, which control what generated code looks like. Instead, I’d like to point your attention to Editor Templates, which are a bit like macros.

For instance, open a Java class in an editor, type in “sysout” and press ctrl-space. An editor template automatically expands that to “System.out.println()” and positions your cursor in the right place. This is probably the simplest example of templates, but they can be much more complex than that.

Get comfortable with templates, and learn the template for each piece of boilerplate code like loops, casts, try/catch blocks, etc. You should never have to write these things by hand if you are comfortable with the templates. Even better, you can create your own parameterized templates for commonly used code constructs.

10 Set Type Filters

You can filter the types that Eclipse uses for auto-completion and when searching for classes. For example, there are two classes called List in Java’s standard library - java.util.List and java.awt.List. If you’re not a Swing, developer, you probably don’t care about java.awt.List and almost always want Eclipse to prefer java.util.List. To do this, you can filter out java.awt.List (even better, java.awt.*).

Filters are configured through Window -> Preferences -> Java -> Appearance -> Type Filters. If you’re seeing classes show up at the top of your search you know you’re not interested in, filter them out for faster searching.

No Comments | Tags: Uncategorized

2 March 2006 - 15:17User Simulators

Writing a user simulator is an interesting way to solve a few different kinds of problems that come up during the development or maintenance of an application. A user simulator is a program that exercises your application in ways similar to how a real user would interact with it.

A user simulator follows a simple pattern:

1) Start up. Initialize the application and create some starting state.
2) Randomly choose one action from a set of actions that are valid for the current state.
3) Execute the action, which will exercise some application function and modify state.
4) If no errors occurred, go to step 2. Otherwise report errors and finish.

Simulators are handy for solving problems that occur intermittently - you just let the simulator run until it produces some desired error. The simulator keeps an audit trail as it works, so it’s easy to see what sequence of actions led to an error. Today I wrote such a simulator to try to track down an intermittent connection problem with a client / server application. I can start the simulator, let it run for a couple of hours, and it will have performed thousands of operations. If the simulator detects that the problem I’m interested in happened, it stops and shows what steps it took to get there.

A user simulator can also help when there are a large number of possible states the application could be in, and some problem occurs in a small subset of those states. I wrote such a simulator at a previous job. We had a very complex UI for displaying the results of a report in a web browser. This UI included paging through a result set, sorting, adding and removing columns, etc. There was some complicated state that was stored on the server to facilitate all this. I used a simulator to help find corner cases where things broke when just the right sequence of actions was performed.

When writing user simulators, it helps to think of the application as a large state machine, and write the simulator to move the application between its states. The payoff of using a simulator is that a computer program can transition the application through states much more quickly than a human can, and the simulator doesn’t get bored :).

User simulators are a bit like acceptance tests, and a bit like fuzz testing, although they’re not quite either of those. Unlike an acceptance test, a user simulator doesn’t need to manipulate the UI of the application because the purpose of the simulator isn’t to test the UI - it’s to exercise the same application code that the UI exercises. For this reason, every time I’ve written a user simulator, it’s ended up being a console program that depended on the same layer of the application that the UI depended on. Unlike fuzz testing, a user simulator doesn’t feed the application completely random input data, but attempts to model real-world usage.

Next time you’re trying to test a complicated UI, or attempting to reproduce an intermittent bug, think about creating a user simulator to do the tedious work for you.

No Comments | Tags: Uncategorized

1 March 2006 - 14:57Welcome

Welcome to my blog.

I intend to use this space to talk mostly about software development issues that I find interesting. Java is the language I’m using right now at my day job, so I’ll probably post a lot of entries that discuss Java programming. I also have a fascination with the bigger issues of software development that span languages and programming models, so I’ll likely have plenty of general development topics too.

I chose the title of this blog (”simply complex”) to correspond to what is a huge issue in software development right now: the forces of simplicity and complexity. You don’t have to look hard to see the tension between these forces - in the large, look at the introduction of the Ruby on Rails framework and the backlash in the J2EE community. However, the more interesting examples of simplicity and complexity happen in the small - every non-trivial design is a showcase of tradeoffs made between the two. I’ll likely have a lot to say about such tradeoffs.

Finally a quote to finish my first entry (attributed to many different people):

Good judgment comes from experience. Experience comes from bad judgment.

No Comments | Tags: Uncategorized