Editor Project Review/Discussion
Lecture Notes for CS 190
Spring 2016
John Ousterhout
- Biggest overall issue: classes aware of too much information
- Combine unrelated things
- Specialized for particular uses
- Examples:
- Text management also implements undo mechanism
- Single object represents both selection and cursor
- Cursor is one end of selection, or
- If selection empty, then it's a cursor
- A selection class that also handles insertions, deletions,
notifications
- APIs for text are modeled on GUI operations:
- Text modifications done via a "selection"
- Text has "delete 1 char forward" and "delete 1 char backward"
- A "range" class that is named "Selection": over-specialized
- Problems this creates:
- Complexity: have to keep more information in your mind at once
- Dependencies: can't understand one piece of code without another
- Key idea: make classes focused and generic
- If it's natural to think about 2 ideas independently,
then separate them.
- Text is only text, not text+undo or text+selection
- Keep the selection and cursor separate
- Try to keep each class as generic as possible:
- Don't incorporate your knowledge of how it will be used
- Imagine a broad range of usage
- Define general-purpose operations that many uses will need:
"delete range of characters" rather than
"delete 1 character backwards"
- Specialize at a higher level (e.g. GUI maps selection to
positions, Delete to "delete 1 character backwards"
- Apply these same ideas even within a class:
- Minimize the amount of information that must be known at
each point in the code
- For Project 2: separate text management and undo, implement each
in a generic way.
- Basic undo mechanism must be totally generic: can undo and redo
anything
- But, it must be extensible, so higher levels can implement
specific kinds of undoable operations.
- Implement undoing for text and for the selection separately.
- Simple and generic text: knows nothing about selections, GUI
operations, etc.
- Second problem: trying to separate things that are intimately related
- See Example 1: Scrollbar AdjustmentListener
- User interface divided into 2 classes: TextWindow, TextController
- But TextController knows almost everything about TextWindow's internals
- See Example 2: undo actions
- Thin classes (InsertCommand, DeleteCommand, etc.) just hold data
- Code associated with actions is in a separate class
- Pass-through methods are a red flag
- See Example 3: TextDocument class acts as intermediary between RWTextArea
and TextEditor
- One method just calls another with similar name and arguments
- Results in thin class: lots of interface, not much functionality
- Dependencies make code hard to read
- Can I look at a piece of code in isolation and see easily
that it works?
- Or, do I need to look at lots of other code also
(e.g. this code only solves part of the problem)?
- See Example 4: event handler for Delete
- Tactical vs. strategic programming:
- Tactical: "I just need to make this work"
- Don't worry about architecture
- A little bit of incremental complexity isn't that bad?
- Strategic: "How can I get the best architecture?"
- Each bug and problem is a potential red flag:
"does this bug indicate a problem with the APIs?"
- Fix architecture problems when they are encountered
- Don't accept incremental complexity.
- Challenge for undo: how to manage event grouping?
- Collect related actions (e.g. consecutive backspaces) into a single
undoable action
- Complex: lots of dependencies
- Separate actions; single undo command may undo many actions.
How to decide when to stop undoing?
- Ask action: each action knows which other actions it should
be grouped with.
- Creates dependencies between actions: to add new action,
may need to find and modify many existing actions.
- Requires more action types (e.g. "insert single character"
vs. "insert string")
- Centralized code that knows about all actions and which can be
grouped
- Probably more manageable than having each action decide.
- Introduce fences in the undo mechanism; undo/redo all actions
up to the next fence.
- Who adds fences and when? Requires extra code in event handlers.
- But, code is locally understandable: no dependencies.
- Design challenge: how to refer to the position of a character in the text?
- Use Java Point object
- Separate coordinates
x
and y
- Separate line and character variables
Position
class
- How do you handle nonexistent positions?
- Can they arise?
- Who fixes them? When?
- Documentation issues:
- Example 5: documentation duplicates code
- Example 6
- Example 7: documentation to rewrite
- Exception handling: generally sloppy
- Doing something expedient, vs. figuring out how a problem
eventually needs to be handled.
- See Example 8.
- Sometimes OK to swallow errors (Example 9)
- How did you arrange for all windows to be redisplayed after
text has changed?
- Example 11: class definitions embedded in methods are hard to read.
Only use for trivial cases.