Related
I am trying to learn how to use BDD for our development process and I sometimes end-up writing things that implies a UI design, so for brand new development or new features, the UI does not always exists.
For example, if I say this in a scenario "When a column header is clicked" it implies that this feature is based on some sort of table or grid, but at this point we are still just writing user-stories so there is no UI yet.
That gets me confused to know at what point in the process do we come up with a UI design ?
Keep in mind, I only have read articles about BDD and I think it would help our team a lot but still very new at this! Thx!
If you write your scenarios with a focus on the capabilities of the system, you'll be able to refactor the underlying steps within those scenarios more easily. It keeps them flexible. So I'd ask - what does clicking the column get for you? Are you selecting something? What are you going to do with the selection? Are you searching for something and sorting by a value?
I like to see scenarios which say things like:
When I look for the entry
When I go to the diary for January
When I look at the newest entries
When I look at the same T-shirt in black
These could all involve clicking on a column header, but the implementation detail doesn't matter. It's the capability of the system.
Beneath these high-level scenarios and steps I like to create a screen or page with the smaller steps like clicking buttons in it. This makes it easy to refactor.
I wrote this in a DSL rather than English, but it works with the same idea - you can't tell from the steps whether it's a GUI or a web page, and some of the steps involve multiple UI actions:
http://code.google.com/p/wipflash/source/browse/Example.PetShop.Scenarios/PetRegistrationAndPurchase.cs
Hope you find it interesting and maybe it helps. Good luck!
I guess you can write around that by saying "when I sort the information by X, then..." But then you would have to adjust your scenario to remove any mention of the data being displayed in a grid format, which could lead to some rather obtuse writing.
I think it's a good idea to start with UI design as soon as you possibly can. In the case you mentioned above, I think it would be perfectly valid to augment the user story with sketch of the relevant UI as you would imagine it, and then refine it as you go along. A pencil sketch on a piece of paper should be fine. Or you could use a tablet and SketchBook Pro if you want something all digital.
My point is that I don't see a real reason for the UI design to be left out of user stories. You probably already know that you're going to build a Windows, WPF, or Web application. And it's safe to assume that when you want to display tabular data, you'll be using a grid. Keeping these assumptions out of the requirements obfuscates them without adding any real value.
User stories benefit from the fact, that you describe concrete interactions and once you know concrete data and behaviour of the system for it, you might as well add more information about the way you interact. This allows you to use some tools like Cucumber, which with Selenium enables you to translate a story to a test. You might go even further and e.g. for web apps capture all pages you start concrete story at and collect all interactions with that page resulting in some sort of information architecture you might use for documentation or prototyping and later UI testing.
On the other hand, this makes your stories somewhat brittle when it comes to UI changes. I think the agile way of thinking about this is same as when it comes to design changes - do not design for the future, do the simplest possible thing, in the future you might need to change it anyway.
If you stripped your user stories of all concrete things (even inputs) you will end up with use cases(at least in their simplest format, depends on how you write your stories). Use cases are in this respect not brittle at all, they specify only goals. This makes them resistant to change, but its harder to transfer information automatically using tools.
As for the process, RUP/UP derives UI from use cases, but I think agile is in its nature incremental (I will not say iterative, this would exclude agile methods like FDD and Kanban). This means, as you implement new story, you add to your UI what is necessary. This only makes adding UI specifics in stories more reasonable. The problem is, that this is not a very good way to create UI or more generally UX(user experience). This is exactly what one might call a weakpoint of agile. The Agile manifesto concentrates on functional software, but that is it. There are as far as I know no agile techniques for designing UI or UX.
I think you just need to step back a bit.
BAD: When I click the column header, the rows get sorted by the column I clicked.
GOOD: Then I sort the rows by name, or sometimes by ZIP code if the name is very common, like "Smith".
A user story / workflow is a sequence of what the user wants to achieve, not a sequence of actions how he achieves that. You are collecting the What's so you can determine the best How's for all users and use cases.
Looking at a singular aspect of your post:
if I say this in a scenario "When a column header is clicked" it implies that this feature is based on some sort of table or grid, but at this point we are still just writing user-stories so there is no UI yet.
If this came from a user, not from you, it would show a hidden expectation that there actually is a table or grid with column headers. Even coming from you it's not entirely without value, as you might be a user, too. It might be short-sighted, thinking of a grid just because it comes from an SQL query, or it might be spot-on because it's the presentation you expect the data in. A creative UI isnÄt a bad thing as such, but ignoring user expectations is.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
The community reviewed whether to reopen this question 4 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I've always been interested in the data structures involved in an RPG (Role-Playing Game). In particular, I'm curious about dialogue and events based actions.
For example: If I approach an NPC at point x in the game, with items y and quests z, how would I work out what the NPC needs to say? Branching dialogue and responding to player input seems as trivial as having a defined script, and user input causes the script reader to jump to a particular line in the script, which has a corresponding set of response lines (much like a choose your own adventure)
However, tying in logic to work out if the player has certain items, and completed certain quests seems to really ruin this script based model.
I'm looking for ideas (not necessarily programming language examples) of how to approach all of this dialogue and logic, and separate it out so that it's very easy to add new branching content, without delving into too much code.
This is really an open question. I don't believe there's a single solution, but it'd be good to get the ball rolling with some ideas. As more of a designer than a programmer, I'm always interested in ways to separate content and code.
For example: If I approach an NPC at
point x in the game, with items y and
quests z, how would I work out what
the NPC needs to say? Branching
dialogue and responding to player
input seems as trivial as having a
defined script, and user input causes
the script reader to jump to a
particular line in the script, which
has a corresponding set of response
lines (much like a choose your own
adventure)
However, tying in logic to work out if
the player has certain items, and
completed certain quests seems to
really ruin this script based model.
Not at all. You simply factor the conditionals into the data.
Let's say you have your list of dialogues, numbered 1 to 400 or whatever like the Choose Your Own Adventure book examples. I assume each dialogue may consist of the text spoken by the NPC, followed by a list of responses available to the player.
So the next step is to add the conditionals in there, by simply attaching conditions to each response. The easiest way is to do this with a scripting language, so you have a short and simple piece of code that returns True if this response is available to the player and False if it is not.
eg. (XML format, but could be anything)
<dialogue id='1'>
<text>
Couldst thou venture forth and kill me 10 rats, perchance?
</text>
<response condition="True" nextDialogue='2'>
Verily! Naught could be better than slaying thy verminous foes. Ten ratty
carcasses shall I bring unto thee.
</text>
<response condition="rats_left_in_world() < 10" nextDialogue='3'>
Nay, brother! Had thou but ten rats remaining, my sword would be thine,
but tis not to be.
</response>
</dialogue>
In your scripting language, you'd need a 'rats_left_in_world' function that you can call to retrieve the value in question.
What if you have no scripting language? Well, you could have the programmer code an individual condition for each situation in your dialogue - a bit tedious, not all that difficult if your dialogue is written up-front. Then just refer to a condition by name in the conversation script.
A more advanced scheme, still not requiring a scripting language, might use a tag for each condition, like so:
<response>
<condition type='min_level' value='50'/>
Sadly squire, my time is too valuable for the likes of thee. Get thyself a
farm hand or stable boy to do thy bidding!
</response>
You can add as many conditions in there as you need, as long as they can be easily specified with one or two values. If all conditions are met, the response is available.
It's interesting, there's seems to be a core idea being missed here. We're having a discussion that relates to a programmer performing the task. Indeed, the code examples above are coupled to code, not content.
In game development, it's the content developers that we programmers want to empower. They will not (this is very important) look at code. Period. Now and again you get a technical artist or technical designer, and they're wonderful and don't mind it; but, the majority of content authors are not technically inclined.
I understand the question is for your own edification; but, it should be pointed out that, in industry, when we solve these types of problems our end users (the people utilizing the technology we're developing) are not engineers.
A system like this (branching dialogue) requires a representation in a tool that is relatively intuitive to use. For example, Unreal's Kismet visual scripting system could be utilized.
Essentially, the data structures (more than likely a branching tree as it's easy to represent/debug/etc.) would be crafted by a programmer, as would the nodes that represent the object in script. The system with its ability to link to world objects (more than likely also represented by nodes in visual scripting), etc. would then be crafted and the whole kitten caboodle linked together in some glorious bit of elegant code.
After all of that, a designer would actually be able to build a visual representation of the dialogue branching in the visual scripting language. This would be map-encounter specific, more than likely. Of course, you could procedurally generate these; but, that's more of a programmer desire than a designer's.
Just thought I'd add that bit of knowledge and insight.
EDIT: Noticed there's an XML example. I'm not sure what other designers/artists/etc. feel about it; but, the ones I've worked with cringe at the idea of touching a text file.
I'd venture to say that most modern games (be they RPGs, action games, anything above basic card/board games) generally consist of several components: The display engine, the core data structures, and typically a secondary scripting engine. One example which was popular for a time (and may still be; I haven't even spoken to a game developer in years) was Lua.
The decision-making you're talking about (events, conversation branches, etc) is typically handled by the secondary scripting engine, as the scripting languages are more flexible and typically easier to use for the game's designers. Again, most of the real story-driven or game-driving logic will actually happen here, where it can be swapped out and changed relatively easily. (At least, compared to running a full build of all the code!)
The primary game engine combines the data structures related to the world (geometry, etc), the data structures related to the player(s) and other actor(s) needed, and the scripts to drive the encounters, and uses all of that to display the final, integrated environment.
You can certainly use a scripting language to handle dialogue. Basically a script might look like this:
ShowMessage("Hello " + hero.name + ", how can I help you?")
choices = { "Open the door for me", "Tell me about yourself", "Nevermind" }
chosen = ShowChoices(choices)
if chosen == 0
if hero.inventory["gold key"] > 0
ShowMessage("You have the key! I'll open the door for you!")
isGateOpen = true
else
ShowMessage("I'm sorry, but you need the gold key")
end if
else if chosen == 1
if isGateOpen
ShowMessage("I'm the gate keeper, and the gate is open")
else
ShowMessage("I'm the gate keeper and you need gold key to pass")
end if
else
ShowMessage("Okay, tell me if you need anything")
end if
This is fine for most games. The scripting language can be simple and you can write more complicated logical branches. Your engine will have some representation of the world that is exposed to the scripting language. In this example, this means the name of the hero and the items in the inventory, but you could expose anything you like. You also define functions that could be called by scripts to do things like show a message or play some sound effect. You need to keep track of some global data that is shared between scripts, such as whether a door is open or a quest is done (perhaps as part of the map and quest classes).
In some games however, scripting could get tedious, especially if the dialogue is more dynamic and depends on many conditions (say, character mood and stats, npc knowledge, weather, items, etc.) Here it is possible to store your dialogue tree in some format that allows easily specifying preconditions and outcomes. I don't know if this is the way to do it, but I've once asked a question about storing game logic in XML files. I've found this approach to be effective for my game (in which dialogue is heavily dependent on many factors). In particular, in the future I could easily make a simple dialogue editor that doesn't require much scripting and allow you to simply define dialogue and branches with a graphical user interface.
I recently had to develop something for this, and opted for a very basic text file structure. You can see the resulting code and text format at:
https://github.com/scottbw/dialoguejs
There is a tradeoff between sophistication of scripting and ease of editing for non-programmers.
I've opted for a very simple solution for the dialogue, and handle triggering of related game events separately in a secondary scripting language.
Eventually I might add some way of adding "stage directions" to the text dialogue format that are used to trigger events in the secondary scripting engine, but again without needing to put anything that looks like code in the dialogue file itself.
That's an excellent questions. I had to solve that a few times for clients. We started with an XML structure quite similar to yours, and now we use JSON. You can see an example here: http://www.branchtrack.com/projects/on029pq6.json or https://dl.dropboxusercontent.com/u/11433463/branchtrack/on029pq6.json (prettify it for readability).
Full disclosure: the link above is generated in BranchTrack, an online editor for branching dialogues, and I am the CEO. Feel free to ask anything.
I recently tackled a problem like this while making Chat Mapper. What I do is graphically plot out the dialogues as nodes in a tree and then each node has a condition and a script associated with them. As you traverse through the tree and hit a node, you check the condition to see whether or not that node is valid, and if it is, you execute the script associated with that node. It's a fairly simple idea but seems to work well from our testing. We are using a .NET Lua interpreter for the scripts.
For my solution I developed a custom text file format consisting of seven lines of text per node. Each line can be a strided list or just a text line. Each node has a position number. The last digit of the number is a type, so there are 10 different types of nodes, such as fresh questions, confirmations, repeating actions based on prior results, etc.
Each dialog activation begins with a select query to the data store whose results can be compared against members of a strided list, to match up with the appropriate node. This is more brutal than an if/then but it makes the text config file smaller since you don't need any syntax besides the stride separator. I use a system of wildcards to allow for select query results to be able to be inserted into the speech of the NPC.
Lastly there are API hooks to allow custom scripts to interface in, in case the easy config file is not enough. I plan to make a web app gui in nodejs to allow people to visually script the config files :D
I've seen a few mentions of this on Stack Overflow, but staring at Wikipedia (the relevant page has since been deleted) and at an MFC dynamic dialog demo did nothing to enlighten me. Can someone please explain this? Learning a fundamentally different concept sounds nice.
Based on the answers: I think I'm getting a better feel for it. I guess I just didn't look at the source code carefully enough the first time. I have mixed feelings about differential execution at this point. On the one hand, it can make certain tasks considerably easier. On the other hand, getting it up and running (that is, setting it up in your language of choice) is not easy (I'm sure it would be if I understood it better)...though I guess the toolbox for it need only be made once, then expanded as necessary. I think in order to really understand it, I'll probably need to try implementing it in another language.
Gee, Brian, I wish I had seen your question sooner. Since it's pretty much my
"invention" (for better or worse), I might be able to help.
Inserted: The shortest possible
explanation I can make is that if
normal execution is like throwing a
ball in the air and catching it, then
differential execution is like
juggling.
#windfinder's explanation is different from mine, and that's OK. This technique is not easy to wrap one's head around, and it's taken me some 20 years (off and on) to find explanations that work. Let me give it another shot here:
What is it?
We all understand the simple idea of a computer stepping along through a program, taking conditional branches based on the input data, and doing things. (Assume we are dealing only with simple structured goto-less, return-less code.) That code contains sequences of statements, basic structured conditionals, simple loops, and subroutine calls. (Forget about functions returning values for now.)
Now imagine two computers executing that same code in lock-step with each other, and able to compare notes. Computer 1 runs with input data A, and Computer 2 runs with input data B. They run step-by-step side by side. If they come to a conditional statement like IF(test) .... ENDIF, and if they have a difference of opinion on whether the test is true, then the one who says the test if false skips to the ENDIF and waits around for its sister to catch up. (This is why the code is structured, so we know the sister will eventually get to the ENDIF.)
Since the two computers can talk to each other, they can compare notes and give a detailed explanation of how the two sets of input data, and execution histories, are different.
Of course, in differential execution (DE) it is done with one computer, simulating two.
NOW, suppose you only have one set of input data, but you want to see how it has changed from time 1 to time 2. Suppose the program you're executing is a serializer/deserializer. As you execute, you both serialize (write out) the current data and deserialize (read in) the past data (which was written the last time you did this). Now you can easily see what the differences are between what the data was last time, and what it is this time.
The file you are writing to, and the old file you are reading from, taken together constitute a queue or FIFO (first-in-first-out), but that's not a very deep concept.
What is it good for?
It occurred to me while I was working on a graphics project, where the user could construct little display-processor routines called "symbols" that could be assembled into larger routines to paint things like diagrams of pipes, tanks, valves, stuff like that. We wanted to have the diagrams be "dynamic" in the sense that they could incrementally update themselves without having to redraw the entire diagram. (The hardware was slow by today's standards.) I realized that (for example) a routine to draw a bar of a bar-chart could remember its old height and just incrementally update itself.
This sounds like OOP, doesn't it? However, rather than "make" an "object", I could take advantage of the predictability of the execution sequence of the diagram procedure. I could write the bar's height in a sequential byte-stream. Then to update the image, I could just run the procedure in a mode where it sequentially reads its old parameters while it writes the new parameters so as to be ready for the next update pass.
This seems stupidly obvious and would seem to break as soon as the procedure contains a conditional, because then the new stream and the old stream would get out of sync. But then it dawned on me that if they also serialized the boolean value of the conditional test, they could get back in sync.
It took a while to convince myself, and then to prove, that this would always work, provided a simple rule (the "erase mode rule") is followed.
The net result is that the user could design these "dynamic symbols" and assemble them into larger diagrams, without ever having to worry about how they would dynamically update, no matter how complex or structurally variable the display would be.
In those days, I did have to worry about interference between visual objects, so that erasing one would not damage others. However, now I use the technique with Windows controls, and I let Windows take care of rendering issues.
So what does it achieve? It means I can build a dialog by writing a procedure to paint the controls, and I do not have to worry about actually remembering the control objects or dealing with incrementally updating them, or making them appear/disappear/move as conditions warrant. The result is much smaller and simpler dialog source code, by about an order of magnitude, and things like dynamic layout or altering the number of controls or having arrays or grids of controls are trivial. In addition, a control such as an Edit field can be trivially bound to the application data it is editing, and it will always be provably correct, and I never have to deal with its events. Putting in an edit field for an application string variable is a one-line edit.
Why is it hard to understand?
What I have found hardest to explain is that it requires thinking differently about software. Programmers are so firmly wedded to the object-action view of software that they want to know what are the objects, what are the classes, how do they "build" the display, and how do they handle the events, that it takes a cherry bomb to blast them out of it. What I try to convey is that what really matters is what do you need to say? Imagine you are building a domain-specific language (DSL) where all you need to do is tell it "I want to edit variable A here, variable B there, and variable C down there" and it would magically take care of it for you. For example, in Win32 there is this "resource language" for defining dialogs. It is a perfectly good DSL, except it doesn't go far enough. It doesn't "live in" the main procedural language, or handle events for you, or contain loops/conditionals/subroutines. But it means well, and Dynamic Dialogs tries to finish the job.
So, the different mode of thinking is: to write a program, you first find (or invent) an appropriate DSL, and code as much of your program in that as possible. Let it deal with all the objects and actions that only exist for implementation's sake.
If you want to really understand differential execution and use it, there are a couple of tricky issues that can trip you up. I once coded it in Lisp macros, where these tricky bits could be handled for you, but in "normal" languages it requires some programmer discipline to avoid the pitfalls.
Sorry to be so long-winded. If I haven't made sense, I'd appreciate it if you'd point it out and I can try and fix it.
Added:
In Java Swing, there is an example program called TextInputDemo. It is a static dialog, taking 270 lines (not counting the list of 50 states). In Dynamic Dialogs (in MFC) it is about 60 lines:
#define NSTATE (sizeof(states)/sizeof(states[0]))
CString sStreet;
CString sCity;
int iState;
CString sZip;
CString sWholeAddress;
void SetAddress(){
CString sTemp = states[iState];
int len = sTemp.GetLength();
sWholeAddress.Format("%s\r\n%s %s %s", sStreet, sCity, sTemp.Mid(len-3, 2), sZip);
}
void ClearAddress(){
sWholeAddress = sStreet = sCity = sZip = "";
}
void CDDDemoDlg::deContentsTextInputDemo(){
int gy0 = P(gy);
P(www = Width()*2/3);
deStartHorizontal();
deStatic(100, 20, "Street Address:");
deEdit(www - 100, 20, &sStreet);
deEndHorizontal(20);
deStartHorizontal();
deStatic(100, 20, "City:");
deEdit(www - 100, 20, &sCity);
deEndHorizontal(20);
deStartHorizontal();
deStatic(100, 20, "State:");
deStatic(www - 100 - 20 - 20, 20, states[iState]);
if (deButton(20, 20, "<")){
iState = (iState+NSTATE - 1) % NSTATE;
DD_THROW;
}
if (deButton(20, 20, ">")){
iState = (iState+NSTATE + 1) % NSTATE;
DD_THROW;
}
deEndHorizontal(20);
deStartHorizontal();
deStatic(100, 20, "Zip:");
deEdit(www - 100, 20, &sZip);
deEndHorizontal(20);
deStartHorizontal();
P(gx += 100);
if (deButton((www-100)/2, 20, "Set Address")){
SetAddress();
DD_THROW;
}
if (deButton((www-100)/2, 20, "Clear Address")){
ClearAddress();
DD_THROW;
}
deEndHorizontal(20);
P((gx = www, gy = gy0));
deStatic(P(Width() - gx), 20*5, (sWholeAddress != "" ? sWholeAddress : "No address set."));
}
Added:
Here's example code to edit an array of hospital patients in about 40 lines of code. Lines 1-6 define the "database". Lines 10-23 define the overall contents of the UI. Lines 30-48 define the controls for editing a single patient's record. Note the form of the program takes almost no notice of events in time, as if all it had to do was create the display once. Then, if subjects are added or removed or other structural changes take place, it is simply re-executed, as if it were being re-created from scratch, except that DE causes incremental update to take place instead. The advantage is that you the programmer do not have to give any attention or write any code to make the incremental updates of the UI happen, and they are guaranteed correct. It might seem that this re-execution would be a performance problem, but it is not, since updating controls that do not need to be changed takes on the order of tens of nanoseconds.
1 class Patient {public:
2 String name;
3 double age;
4 bool smoker; // smoker only relevant if age >= 50
5 };
6 vector< Patient* > patients;
10 void deContents(){ int i;
11 // First, have a label
12 deLabel(200, 20, “Patient name, age, smoker:”);
13 // For each patient, have a row of controls
14 FOR(i=0, i<patients.Count(), i++)
15 deEditOnePatient( P( patients[i] ) );
16 END
17 // Have a button to add a patient
18 if (deButton(50, 20, “Add”)){
19 // When the button is clicked add the patient
20 patients.Add(new Patient);
21 DD_THROW;
22 }
23 }
30 void deEditOnePatient(Patient* p){
31 // Determine field widths
32 int w = (Width()-50)/3;
33 // Controls are laid out horizontally
34 deStartHorizontal();
35 // Have a button to remove this patient
36 if (deButton(50, 20, “Remove”)){
37 patients.Remove(p);
37 DD_THROW;
39 }
40 // Edit fields for name and age
41 deEdit(w, 20, P(&p->name));
42 deEdit(w, 20, P(&p->age));
43 // If age >= 50 have a checkbox for smoker boolean
44 IF(p->age >= 50)
45 deCheckBox(w, 20, “Smoker?”, P(&p->smoker));
46 END
47 deEndHorizontal(20);
48 }
Added: Brian asked a good question, and I thought the answer belonged in the main text here:
#Mike: I'm not clear on what the "if (deButton(50, 20, “Add”)){" statement is actually doing. What does the deButton function do? Also, are your FOR/END loops using some sort of macro or something? – Brian.
#Brian: Yes, the FOR/END and IF statements are macros. The SourceForge project has a complete implementation. deButton maintains a button control. When any user input action takes place, the code is run in "control event" mode, in which deButton detects that it was pressed and signifies that it was pressed by returning TRUE. Thus, the "if(deButton(...)){... action code ...} is a way of attaching action code to the button, without having to create a closure or write an event handler. The DD_THROW is a way of terminating the pass when the action is taken because the action may have modified application data, so it is invalid to continue the "control event" pass through the routine. If you compare this to writing event handlers, it saves you writing those, and it lets you have any number of controls.
Added: Sorry, I should explain what I mean by the word "maintains". When the procedure is first executed (in SHOW mode), deButton creates a button control and remembers its id in the FIFO. On subsequent passes (in UPDATE mode), deButton gets the id from the FIFO, modifies it if necessary, and puts it back in the FIFO. In ERASE mode, it reads it from the FIFO, destroys it, and does not put it back, thereby "garbage collecting" it. So the deButton call manages the entire lifetime of the control, keeping it in agreement with application data, which is why I say it "maintains" it.
The fourth mode is EVENT (or CONTROL). When the user types a character or clicks a button, that event is caught and recorded, and then the deContents procedure is executed in EVENT mode. deButton gets the id of its button control from the FIFO and askes if this is the control that was clicked. If it was, it returns TRUE so the action code can be executed. If not, it just returns FALSE. On the other hand, deEdit(..., &myStringVar) detects if the event was meant for it, and if so passes it to the edit control, and then copies the contents of the edit control to myStringVar. Between this and normal UPDATE processing, myStringVar always equals the contents of the edit control. That is how "binding" is done. The same idea applies to scroll bars, list boxes, combo boxes, any kind of control that lets you edit application data.
Here's a link to my Wikipedia edit: http://en.wikipedia.org/wiki/User:MikeDunlavey/Difex_Article
Differential execution is a strategy for changing the flow of your code based on external events. This is usually done by manipulating a data structure of some kind to chronicle the changes. This is mostly used in graphical user interfaces, but is also used for things like serialization, where you are merging changes into an existing "state."
The basic flow is as follows:
Start loop:
for each element in the datastructure:
if element has changed from oldDatastructure:
copy element from datastructure to oldDatastructure
execute corresponding subroutine (display the new button in your GUI, for example)
End loop:
Allow the states of the datastructure to change (such as having the user do some input in the GUI)
The advantages of this are a few. One, it is separation
of the execution of your changes, and the actual
manipulation of the supporting data. Which is nice for
multiple processors. Two, it provides a low bandwidth method
of communicating changes in your program.
Think of how a monitor works:
It is updated at 60 Hz -- 60 times a second. Flicker flicker flicker 60 times, but your eyes are slow and can't really tell. The monitor shows whatever is in the output buffer; it just drags this data out every 1/60th of a second no matter what you do.
Now why would you want your program to update the whole buffer 60 times a second if the image shouldn't change that often? What if you only change one pixel of the image, should you rewrite the entire buffer?
This is an abstraction of the basic idea: you want to change the output buffer based on what information you want displayed on the screen. You want to save as much CPU time and buffer write time as possible, so you don't edit parts of the buffer that need not be changed for the next screen pull.
The monitor is separate from your computer and logic (programs). It reads from the output buffer at whatever rate it updates the screen. We want our computer to stop synchronizing and redrawing unnecessarily. We can solve this by changing how we work with the buffer, which can be done in a variety of ways. His technique implements a FIFO queue that is on delay -- it holds what we just sent to the buffer. The delayed FIFO queue does not hold pixel data, it holds "shape primitives" (which might be pixels in your application, but it could also be lines, rectangles, easy-to-draw things because they are just shapes, no unnecessary data is allowed).
So you want to draw/erase things from the screen? No problem. Based on the contents of the FIFO queue I know what the monitor looks like at the moment. I compare my desired output (to erase or draw new primitives) with the FIFO queue and only change values that need to be changed/updated. This is the step which gives it the name Differential Evaluation.
Two distinct ways in which I appreciate this:
The First:
Mike Dunlavey uses a conditional-statement extension. The FIFO queue contains a lot of information (the "previous state" or the current stuff on monitor or time-based polling device). All you have to add to this is the state you want to appear on screen next.
A conditional bit is added to every slot that can hold a primitive in the FIFO queue.
0 means erase
1 means draw
However, we have previous state:
Was 0, now 0: don't do anything;
Was 0, now 1: add it to the buffer (draw it);
Was 1, now 1: don't do anything;
Was 1, now 0: erase it from the buffer (erase it from the screen);
This is elegant, because when you update something you really only need to know what primitives you want to draw to the screen -- this comparison will find out if it should erase a primitive or add/keep it to/in the buffer.
The Second:
This is just one example, and I think that what Mike is really getting at is something that should be fundamental in design for all projects: Reduce the (computational) complexity of design by writing your most computationally intense operations as computerbrain-food or as close as you can get. Respect the natural timing of devices.
A redraw method to draw the entire screen is incredibly costly, and there are other applications where this insight is incredibly valuable.
We are never "moving" objects around the screen. "Moving" is a costly operation if we are going to mimic the physical action of "moving" when we design code for something like a computer monitor. Instead, objects basically just flicker on and off with the monitor. Every time an object moves, it's now a new set of primitives and the old set of primitives flickers off.
Every time the monitor pulls from the buffer we have entries that look like
Draw bit primitive_description
0 Rect(0,0,5,5);
1 Circ(0,0,2);
1 Line(0,1,2,5);
Never does an object interact with the screen (or time-sensitive polling device). We can handle it more intelligently than an object will when it greedily asks to update the whole screen just to show a change specific to only itself.
Say we have a list of all possible graphical primitives our program is capable of generating, and that we tie each primitive to a set of conditional statements
if (iWantGreenCircle && iWantBigCircle && iWantOutlineOnMyCircle) ...
Of course, this is an abstraction and, really, the set of conditionals that represents a particular primitive being on/off could be large (perhaps hundreds of flags that must all evaluate to true).
If we run the program, we can draw to the screen at essentially the same rate at which we can evaluate all these conditionals. (Worst case: how long it takes to evaluate the largest set of conditional statements.)
Now, for any state in the program, we can simply evaluate all the conditionals and output to the screen lightning-quick! (We know our shape primitives and their dependent if-statements.)
This would be like buying a graphically-intense game. Only instead of installing it to your HDD and running it through your processor, you buy a brand-new board that holds the entirety of the game and takes as input: mouse, keyboard, and takes as output: monitor. Incredibly condensed conditional evaluation (as the most fundamental form of a conditional is logic gates on circuit boards). This would, naturally, be very responsive, but it offers almost no support in fixing bugs, as the whole board design changes when you make a tiny design change (because the "design" is so far-removed from the nature of the circuit board). At the expense of flexibility and clarity in how we represent data internally we have gained significant "responsiveness" because we are no longer doing "thinking" in the computer; it is all just reflex for the circuit board based on the inputs.
The lesson, as I understand it, is to divide labor such that you give each part of the system (not necessarily just computer and monitor) something it can do well. The "computer thinking" can be done in terms of concepts like objects... The computer brain will gladly try and think this all through for you, but you can simplify the task a great deal if you are able to let the computer think in terms of data_update and conditional_evals. Our human abstractions of concepts into code are idealistic, and in the case of internal program draw methods a little overly idealistic. When all you want is a result (array of pixels with correct color values) and you have a machine that can easily spit out an array that big every 1/60th of a second, try and eliminate as much flowery thinking from the computer brain as possible so that you can focus on what you really want: to synchronize your graphical updates with your (fast) inputs and the natural behavior of the monitor.
How does this map to other applications?
I'd like to hear of other examples, but I'm sure there are many. I think anything that provides a real-time "window" into the state of your information (variable state or something like a database... a monitor is just a window into your display buffer) can benefit from these insights.
I find this concept very similar to the state machines of classic digital electronics. Specially the ones which remember their previous output.
A machine whose next output depends on current input and previous output according to (YOUR CODE HERE). This current input is nothing but previous output + (USER, INTERACT HERE).
Fill up a surface with such machines, and it will be user interactive and at the same time represent a layer of changeable data. But at this stage it will still be dumb, just reflecting user interaction to underlying data.
Next, interconnect the machines on your surface, let them share notes, according to (YOUR CODE HERE), and now we make it intelligent. It will become an interactive computing system.
So you just have to provide your logic at two places in the above model; the rest is taken care of by the machine design itself. That's what good about it.
I need to let end users specify a time range, to be stored and used internally as a starting date/time and ending date/time. The range could be minutes or it could be days.
Has anyone discovered an interactive control that can handle this elegantly?
Most GUI toolkits have a calendar control, so I could specify "start" with a calendar for the day and a text field for the time...and the same for "end".
I could also replace the "end" controls with a single text field or slider that simply describes how many seconds/minutes/hours after start "end" is.
What I don't like about these ideas is how much clicking, typing, and more clicking is required to describe such a simple concept. Also I have to slap the user's hand if a time is typed in that isn't recognizable as a time.
Is there a cleaner implementation that I'm overlooking?
I tend to look at common design patterns for inspiration when I'm pondering problems such as this.
The Yahoo Pattern Library offers some potential solutions.
The UI Patterns site also give some suggestions, and is worth a browse.
For good measure, here's another solution at the Welie pattern library.
Another source of inspiration might be other sites and applications. For example, think of all the use-cases where recording short and long time time durations is required. As an example, company TimeSheet recording, company car mileage log software, task recording software, stopwatch applications, calendaring apps, etc. Then see how they've handled the GUI controls for capturing time ranges.
I haven't personally found a favourite solution for picking date and time. But, I think I'd want something like this.
User clicks to show calendar popup
Popup shows 2 side-by-side calendars (start date/time and end date/time)
Calendar 1 shows todays date, and the other also shows todays date.
Calendar controls allow usual navigation and selection of day month year.
Below each calendar is a hh:mm box, which defaults to the current time.
User can edit value in this time box using up/down arrows or by typing.
Alternatively, show an analogue clock below each calendar. It takes 2 mouse clicks to set time( click 1 for hour and click 2 for minutes).
Hope this helps
I am a fan of an old control I saw used WAY back in the 90's with Inventor (and later Open Inventor) on SGI machines (and then on PCs, etc): an infinite dial.
Some screenshots, a little on the small side, are here. Course, its been done on a variety of platforms since, including similar things on the iphone.
I think a date/time picker would work well with two dials, each representing an order of date/time magnitude. In ASCII art, with each dial between [square brackets] it might look like:
[20 Oct | 21 OCT | 22 Oct ] [11:15 .. 11:30 .. 11:45..]
or with 3:
[20 Oct | 21 OCT | 22 Oct ] [11 .. 12 .. 1pm] [12:31 .. 12:32 .. 12:33]
There are a number of variations you could try (vertical/horizontal, date/time, date/hour/minute, etc).
Dials, though somewhat rarely used, are a natural device for humans to interact with, and their infinite rotation option (unlike a slide which must always stop) suits dates/times well.
FWIW
User interface design is heavily application dependent. "Best" implies some kind of metric that can measure solutions. In UI design such a metric can be "home many clicks/key-presses does it take to complete the task?" where a smaller number is better. So once you've defined your metric you can start to sort solutions into good, better and best.
You also want to reduce cognitive burden for the user. If the user has to enter the final day on which a product can be exchanged based on a 90-day return policy then asking for start and end date would force them to do date math which is no fun. In this example a start date with a "delta" of x days would place less of a burden on the user.
Depending on you application you could consider and approach like the Google Finance time range selector on their charts: http://finance.google.com/finance?q=.dji
There is no single answer, it depends on the context. For many places good text controls are enough. Of course such things can still help by supporting pasting and some increase/decrease actions. Maybe it can even do some validation for the value.
Then there are places that need something more. Calendar can be really helpful for entering dates and some kind of slider could be used for time. (Lotus Notes calendar has a slider.)
My advise is:
Think what you need. Don't put complicated widgets to a less used dialog.
If you need these nice helpful widgets, check if there are ready made in the library you are using and take some time to see how others have done these.
Always have the text controls with support for pasting.
Check out the VisualHint date control. It can be configured a multitude of ways including a timespan. This would allow you to use one control instance to show the start time and another to set the timespan until the period is complete. The control also supports an extensible base framework so you could possibly combine both start/end or start/span into a single control.
Here are also some solutions: http://quince.infragistics.com/html/PatternView.aspx?name=Date+Time+Range+Input
Unless there is a more advanced time control in your GUI toolkit of choice, two calendar controls representing start and end is the most straightforward. Also, you need to decide how you want to use the information. For example, if you used a start date and an interval to increment that date, changing the start date wouldn't change the meaning of the interval. It really depends on what you're wanting to do.
One way I've seen work very well is using a gantt chart:
http://en.wikipedia.org/wiki/Gantt_chart
You can create a single line chart and then you can scale it across months, days, hours and minutes depending on how wide or zoomed in you make the control. The problem is I don't know of any control out there right now that does just one line, so you may need to create a custom one. You could possibly look for a gantt chart control and just do one task/item.
Observe what people are doing with your time range control. Then write it so that it's most suited towards doing what the people want to achieve with it. For instance, leave away past dates if inputting future dates only makes sense.
Jonathan Leighton has made a nice date inputter -element in jquery that I've found very nice for inputting dates. This is beneficial in a way that user can both input the date by clicking or type it in directly. The user also directly gets the hint about typing it into the box. If you couple this with some kind of timeline -object, you may actually go far afar. Just avoid making UI elements that are confusing or angering!
This comes in late, and it's not a control per se. I read this idea on a blog I can't find anymore (in fact, I found this post while trying to find it). The idea is to use the metaphor of a wall clock. Here's what I implemented for the fun of it. It's not a functional control. You could use something like this as a starting point for capturing times naturally. Three clicks at most, two most of the time. Only dials come close.
http://www.viridium.ro/clock-sample/
Use a HTML5-aware browser; that is, Chrome.
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
What are some key UI design tips that every developer should know?
While there are a number of UI resources for developers (for example, Joel Spolsky's User Interface Design for Programmers), I'm interested in more of a bullet list that can be communicated in 1 to 2 pages.
I'm interested in more tactical, day-to-day UI tips, as opposed to overarching UI design goals that would be covered in a UI design meeting (presumably attended by at least one person with a good UI sense). A collection of these tips might cover about 80% of the cases that an everyday programmer would come across.
use a standard menubar (amateur GUI designers seem to like to chart their own course here for some reason). Make sure the first items are File, Edit and View, and the last one is Help
don't worry about color themes or skins; stick to a standard look that is consistent with your platform
use the default system font
use menu accelerators that are consistent with your platform
stick to the tried and true layout with a menubar on top, a status bar on the bottom, and if required, a navigation pane on the left
never do a system-wide grab
If you have a choice, make all windows resizable.
use groups of radiobuttons for "choose exactly one". Always make sure one of them is selected by default. If you want the user to be able to not choose any, add another radiobutton for "no choice"
use groups of checkbuttons for "choose zero or more"
constrain input if necessary (ie: simply ignore non-digits in a numeric input field) rather than waiting for a user to enter data, submit, then throw up a dialog saying "hey, letters aren't allowed!". If they aren't allowed, don't accept them in the first place.
be liberal in what you accept as input. For goodness sake, don't throw a fit for a SSN field if they leave out the hyphens, or put then in when you don't want them. The computer is smart, let it figure out that xxxxxxxxx and xxx xx xxxx and xxx-xx-xxxx are all valid social security numbers.
always allow spaces in long fields such as serial numbers and whatnot. Data quality goes way up if a user is allowed to group numbers in sets of three or four. If your data model can't handle the spaces you can remove them before saving the data.
Avoid pop-up dialogs like the plague. Never display one unless you absolutely must. If you decide you must, stop and rethink your design before continuing. There are times when they are necessary, but those times are considerably less frequent than you might imagine.
pay attention to keyboard traversal. Most toolkits make an attempt to get it right, but always double-check. A use should be able to use the tab key to traverse the widgets in a logical manner.
All of these rules can, of course, be broken. But only break it if you are breaking it for a justifiable reason.
Remember, the software is there to aid the user, it should be doing what they want, rather than making them do what it wants.
When you are about to perform an action that will change or delete information, don't ask 'are you sure' - users will learn to click the button as part of the action. Try to allow for an 'Undo' in the system design.
Make the default choice the one most users would be happy with.
Always give your user a "way out" from wherever they are that does not require the use of the back button.
The best example:
If an error occurs, give them a link back to where they were (or at least to where they can start over).
Use tool tips as much as possible. It is amazing how these little guys can add a large amount of help to the end user and they are unobtrusive to the application itself.
When designing a UI make it as simple as possible, but no simpler.
ask the user, don't just make things up
simplify - remove a step, eliminate clicks, etc.
get familiar with the principles of usability
I think that this link would be a good starting point, from Microsoft's "Windows Vista User Experience Guidelines:
http://msdn.microsoft.com/en-us/library/aa511328.aspx
And this might be very close to the two page bullet point list you are looking for: "Top Violations":
http://msdn.microsoft.com/en-us/library/aa511331.aspx
Very down to earth tips like: "Set a minimum window size if there is a size below which the content is no longer usable."
Correct tab-stops are a must.
Do not increase "discoverability" at the cost of basic clarity and usability.
Find the thing the user will do the most often, and then make that the easiest thing to do.
For example: I have a long running personal gripe with microwave design.
Many require you to set a clock you never use for anything prior to using the microwave, and it forgets everytime it loses power AND requires 10 key-presses on those hard-to-use button pads to do so.
A simple usability test would realize the most common cook time used on microwaves is the standard 'minute' and multiples thereof. An Ideal microwave should thus be able to cook an product for 1 minute on high power in 3 or less actions.
For times outside a minute, but within 5 minutes of the golden "1" minute, there should be slightly more steps, but not significantly so, and only significant numbers of actions required for cook times > 5 minutes. ( which are rather rare )
2 examples of great microwave design
1. 4 parts. Door, temperature dial, time dial, time-lighting sequence
Temperature dial is analogue and persists from previous setting, with a varying sliding range.
Time dial is digital, but simulated analogue, turning dial clockwise increases clock time( shown by a lighting sequence under the dial). Turning dial counter clockwise decreases clock time. Cooking decreases clock time.
Door being closed and time being on clock starts cooking. Door opening pauses cooking.
standard operation: open door, load, turn time dial, close door ( or optionally, close door first, and cooking starts as soon as >1s is on clock )
2. 6 Parts, Door, Dial, Power Button, Start Button, Clear Button, Digital Time Display
Start button with no time chosen starts cooking for 1 minute on high power.
Start button while cooking adds 1 minute to time.
Time dial persists between sessions. Turning dial causes the time stored on the dials position being copied to the digital timer.
Pressing "power" prior to starting cooking will
in the event the dial has not been turned, copy the current time stored on the dails position to the digital timer.
in the event the dial has been turned, decrements the choice of power level by 1, or if on lowest power level, return to highest.
Pressing power while cooking decrements the power level on the fly.
standard operation:
1 minute high = press start.
1 minute medium high = press start, press power.
2 minutes high = press start twice.
<anytime> on high = turn dial until happy, press start.
<anytime> on <anypower> turn dial until happy, press power until happy, press start.
<previously chosen time> on high = press power, press start
<previously chosen time + 1 minute> on high = press power, press start twice.
As you can see here, adding a small amount of extra buttons, can add a great degree of expressive and functional design.
Any design with a numeric keypad for time specification, tends to fail my criteria for good design.
Its noted that these designs may, for some people have a higher learning curve, but once learned, muscle memory makes it instinctive. As opposed to more ( obvious? ) but overly complicated designs which even a learned user will repeatedly have to spend tedious amounts of time performing tedious arbitrary operations, simply to attain common goals.
Do some hallway usability testing (in the same way you would do code reviews).
Even a really quick "Hey! try this" usability test (if you can call it that) with the guy next to you will make a big difference. The main thing is to have somebody other than yourself try the bit of UI you've just built.
It's amazing how many times other people get stuck using your new UI, and it only takes a couple of minutes (usually) to find the biggest problems.
If you do use a popup from an editor, make sure to return your insertion point or state to whatever it was before the popup. Too many programs just leave you "hanging" and having to find your way back.
Instead of the arbitrary "OK" and "Cancel" buttons, which, given context, can be ambiguous, and users blindly click one, the buttons should contain a brief description of what they do.
[Ok, Please Cancel my subscription ], [ Please do not cancel my subscription ]
is far better than
Cancel my subscription?
[ OK ] [ Cancel ]
( these sort of failures often surface on the dailywtf )
Minimize number of clicks
Uniform look(text size, buttons.. and other controls )
Minimize free edits... (ex: in an address entry... provide states in a dropdown...etc etc)
In a drop down for country list... list the residing country first...(how many of you frustrated with USA being listed at the bottom and you have to scroll down?)
General drop downs can be ordered as the users choice
No Spelling msitake ;) at all
Pay attention to labeling text: for email address (have the caption as email... believe me... i have seen it as e_mail address:)
Currency symbol for amounts. uniform digit display in amount.. ex:
$12.15 ==> $12.15
$10.9 ==> $10.90
9.Progress/Status bar
Buddy label to indicate the error field before the user clicks OK/Save button(ex: for an email address if there is no "#" there is no need to wait until user clicks OK then tell them invalid email Address)
Avoid repeated inputs... (ex: remember me option in login screen)
global application option to let the user continue from where left off in the previous instance)
when showing data on a grid... excel style filter options
default values for inputs.
Folks...feel free to flush down any of the point above with the valid reasons!!!
Grandmaw Testing.
This is my term for the conceptual question, "Can your grandma, who's never used a computer beyond email and checking www.cutecats.com, use it?(Assuming that she has the real-world knowledge to use that particular app)".
Everything common should be obvious; nothing should be black box magic with side effects. Uncommon things should be accessible in a common format that the user has used before.
Clear labeling, clear route to a help file, clear actions with clear effects.
If Grandma can't use your Paint program, you need to really think about your UI.
My basic rule of UI design is to have each "page" do one task and one task only. It keeps pages simple, which keeps design clean and makes the application more understandable.
This type of design is called Inductive User Interface. Here is a document that Microsoft put out in 2001 on the topic. The text may be a little dated, but the principles are generally pretty good. The only caveat is that there is a balance to be found in designing like this. If you oversimplify too much users will have to navigate all over the place to accomplish simple tasks, and the gains in understandability will be lost to underproductivity.
Some simple tips for daily user interface web design and application design:
Use simple static sketches to begin preliminary web app development plans.
-Dont allow users too many choices. instead, use cater design to send users down a path they'll benefit from.
-Define key user groups and the journeys they made
-Practice iterative design as a part of UI to ensure ROI
I like to follow these guidlines:
Standard - follow known standards/patterns, reuse ideas from all products you respect
Simple - keep your solutions simple and easy to change (if needed)
Elegant - use less to accomplish more