There are a few things to keep in mind when starting to design and develop a user interface. First, and most importantly, has anyone from the user community contributed to the interface you are working on; ideas, use cases/user stories, business rules? Next, has the user community reviewed any ideas and UI mock ups before starting any heavy coding? Have you taken time to design the user interface before adding complex business rules or worrying about concurrency and threading? These things affect time and resources which impacts how quickly they can be done correctly.
User Community Initial Input - User Stories or Use Cases
The essential question to basically everything we do may be: Why am I doing this? The user community, which a developer could possibly be a member, knows their domain or business. In many cases, they don't know how to get that result out of a user interface or possible ways the experience can be better until they are shown, but they know what data goes in and what data should come out; roughly at a minimum.
This is where requirements gathering comes into play. These have to start some where. The initial user stories (interchange with use cases) will be broad statements of what the users want to do. Users need to be coached into breaking those broad statements down into some very discreet ones which collectively would allow them to achive the one which is more broad. In project management terms, this starts to form what is known as a work breakdown structure.
The above is the top tier of the work breakdown structure or the work to be performed which allows the application and project to fulfill its purpose. A developer should be able to take this information and create those portions of the application. If the user stories are refined enough, developers should be able to understand them, and in turn, create tasks which will guide the development of their source code.
The tasks the developers create will become the lower tiers of the WBS. If the developers have a hard time deriving tasks from the refined user stories, they need to push back on the users until the stories are refined enough to allow this to happen. To the point. This represents why you are doing the thing you are doing. In this case, and more specifically, why the user interface will work the way it does.
User Contributions to The User Interface - User Interface Mock Ups
The advantage to iterative development, or in construction speak - design build, is direction can change more easily as development progresses. As the system gradually grows, replacing the whole becomes a more and more expensive proposition. If additions are built incrementally or in baby steps, they can be corrected within an iteration or two. Getting feedback from users ahead of time through UI mock ups helps with this as it relates to user interface design.
A UI mock up should be as simple as possible while expressing and displaying enough of the UI layout along with functionality to the assumed user community, or at least a narrowed test group of the user community. Various tools can be used to perform this work.
In some cases, a simple graphics application with annotated screen shots can be extremely useful. This is good when minor improvements or tweaks are added to existing functionality. This can be useful less the screen shots as well; imagine a simple form is thought to be all that is needed. Image applications can be useful for creating general layout examples along with rudimentary form objects. There are tools designed specifically for creating these type UI mock ups too, but many of the image manipulation programs one uses often work well.
In other cases, more developer oriented tools are better suited. With developer oriented tools, such as the NetBeans IDE and its UI designer, a partially functional representation can be created complete with real UI form components and windows and dialogs. Executable JAR files can be given to users which when run allow the user to play with an actual UI and get a feel for the ideas being presented.
Along with the above, branch development provides yet another option. In a branch of the source code, parts of the UI changes can be worked into an existing and running application. Though the parts will not be complete, remember this is a mock up, they give the user a glimpse of exactly how those pieces will fit into the current system. The whole thing need not be working or a large amount of work done to achieve the desired result. If the UI is acceptable, then the rest of the UI work can take place inside the branch taking advantage of the work which went into the mock up; some refactoring will certainly be required, but at least much of the UI components will be in place even if simply copied and pasted.
In some other cases, it may be best to create some kind of a functional prototype as mentioned above along with taking screen shots and then annotating them. It is often going to be much easier to create certain graphical effects in an image manipulation program than to write logic or source code from scratch to work those effects into an application; even if it is a prototype. The user can then take the functionality you can give them quickly, examine it, take the screen shots into consideration, and then make a determination as to whether such a feature adds value.
All features should be evaluated as to which of the above will work best. Remember: mock ups should show the user the intent and give them a glimpse of possibilities as quickly as possible to allow the team to change course if needed. If too much code and time goes into the mock up, then it may not provide as many advantages. But, there are times where a more in depth prototype will be required. It simply depends on whether users really understand what they are being shown or not, so always remember that communication is the best tool.
Incrementally Add Complexity
Possibly the best designed user interface will have as little business logic in the UI components as possible. The UI components should merely be a vessel for retrieving information from the user and displaying it to them. Initially this will be to get and set information intentionally not adding progress updates and background threading possibly long processes.
Progress updates and background operations will be determined by the data being set and retrieved per user operations and the processes required to get it. If taken into consideration in the user interface from the start, the user interface components are more likely to require changes often and in multiple places as use cases and operations evolve per user feedback. Minimise this until absolutely necessary. If the interface, along with data models - which probably differ from the data, capture the business rules correctly, then adding progress updates and threading at the end should require less work than reworking them.
In general an MVC pattern should be used. Data models, general utilities, controller logic, and the UI classes should be built into separate classes and files allowing them to be tested independently. This will also reduce the size of the individual files of the project. It will probably help produce a better design, and definitely with better separation.
UI components should know how to take a data model and display it or convert it from a model into something the user sees through the lens of the component. Data models should be able to take a set of data and expose it through a particular programming interface which various logic can access. Often models will have selected values, data, and fire events upon certain changes or at least allow a domain to tell it when to fire such an event through something like a fireXEvent() method call.
UI components should expose setters and getters or mechanisms to set and retrieve data the users actions have modified. These can expose data or models. These components should also allow various listeners to be added, removed, and retrieved. User actions, even if pressing a single button in some complex UI component, should generally be exposed through listeners and cause nothing to necessarily change in the UI unless it is purely related to the UI state.
The controller should attach listeners and act upon such actions, and the logic which enables, disables, or changes various features of the user interface, such as setting a new model or updating an existing one which was a result of the action, should be built into the controller. The controller should contain the business logic. Other extraneous logic which seems fairly generic in the process should go into some possibly shareable utility class and not pollute the controller.
A simple example of an MVC would be a file search utility. Suppose the UI of this utility has a single text field called searchTerm. Next, there is a button to the right of searchTerm called searchButton with a magnifying glass on it. The UI contains a tree table below called searchResults. The searchResults displays a model called searchModel of the type SearchModel (which is just an interface). The component has a property inSearch which when true searchButton has a magnifying glass which moves slowing in a circle, and searchTerm is disabled. When false, searchButton has its default still graphic, and searchTerm is enabled.
Let's simply state that searchModel has a method called getFile which accepts an integer as the row in the model as well as one called getSize. It doesn't provide any filtering or anything. This is done by the controller by way of the searchTerm. The UI component knows how to take a model and show its files represented in a tree structure by way of getFile(ndx).getParent(), and that is all this component knows of this model.
The UI component allows add/remove/getSearchButtonActionListener(s), get/setSearchTerm which sets and gets searchTerms text, set/getSearchModel, and set/isInSearch. The controller uses these exposed attributes of the UI component to do all the work and tell the UI how to look. It hooks in a searchButton listener, when searchButton is clicked, it sets inSearch to true, performs its background work, retrieves data, creates a model, which may be empty, sets the model, and finally sets inSearch to false. All the UI component did was fire an event, handle the button animation, and get and display information from and to the user.
As it relates to incrementally adding complexity, there are a couple things which would have been done last in the above example. They are probably obvious, but they are 1) animating the searchButton, and 2) background work of the search. The actual functionality is the most important part. Once that works correctly, then backgrounding some logic and animating a button can be done. Those are not very high risk items on an agenda. It is safe to say that once one has done such a thing a couple times they will be able to do it in various situations over and over; static from a pure human memory perspective. The domain/business logic is the higher priority and most difficult and dynamic piece.