-
Notifications
You must be signed in to change notification settings - Fork 34
Design Guidelines
Chris Meyer edited this page Nov 26, 2024
·
13 revisions
This gives design guidelines for the software.
- Target users are offline (laptop, desktop) and on microscope (powerful desktop with trackball).
- Offline configurations are a laptop with a touchpad and 1920x1080 screen, desktop with larger screen and two button mouse.
- Microscope configurations are a powerful desktop (dozens+ CPU cores), a large monitor, two button mouse, and trackball.
- Avoid making assumptions specific to a microscope, i.e. supporting trackball is ok, but should not be required.
- Attempt to use industry standard mouse tracking concepts and keyboard overloads, i.e. use Adobe PhotoShop, Inkscape, Figma, Word, etc. as examples when possible.
- Prefer minimal changes to avoid changing customer workflow too much and to limit scope at the same time.
- Application should be self-contained.
- Configuration files should auto-generate and have a graphical editor within the application.
- External programs should not be required, including using a browser for help files.
- No extra processes (i.e. command line binary) should be required.
- External access is acceptable for specific use cases, i.e. integration with iPython notebook.
- Prefer to use declarative over the older widgets. May require expanding widget library in some cases.
- An exception (for now) is the inspector.
- Canvas items are used for UI within the workspace area; there is no canvas item for editing text.
- Widgets (declarative) are used for panels and dialogs; they include a text editing widget.
-
DrawingContext
is low level drawing for canvas items. - As much as possible, create standalone drawing functions that do not depend on other objects.
- Anything running in periodic (including async tasks) should complete quickly (< 10ms, preferably faster).
- Move long running code to threads.
- Do not use spin loops. Use other threading primitives instead. Loops are ok with a sleep.
- Encapsulate user actions into
Action
objects. - Actions get decorated with titles, icons, key overloads, etc.
- Support undo. Prefer "undo log" over "undoable command" when possible.
- For key handling in a context (e.g. raster image), use Window to translate key to action.
- Prefer to make changes to model using actions rather than directly.
- Allows for configurable key mapping, recording, encapsulation, etc.
- Handle keys in panels and dialogs traditionally; but use actions where possible.
- Action icons should have an SVG source (in artwork directory) and be rendered to 64x48 PNG for high resolution displays.
- Prefer abstract
Model
(e.g.DisplayLayer
) over explicit classes (e.g.DisplayItem
). - The
Model
technique supports easier maintenance going forward.
- Nearly all computation should be relocated to
niondata
. - Ok to access properties of NumPy arrays, but keep computations in
niondata
if possible. - Avoid using Python tricks - keep code simple and translatable to other programming languages.
- Use specific type annotations in all possible cases. Use
mypy
for type checking.
- Keep microscopy-specific code in packages.
- The
nionswift
project is meant to be general data processing; not specific to a particular field. - Some exceptions still exist.
- Use dockable panels for UI where user needs the information to be constantly available when in use and when there is only a single instance needed.
- Use floating panels for UI where the user needs the information intermittently (such as during editing) or when there may be more than one instance needed.
The cursor position is an example of a dockable panel.
The computation editor is an example of a floating panel.
- In libraries and other public API, try to keep existing functions working for backwards compatibility.
- Adding arguments with default values to end of parameter list or keyword only parameters is usually ok.
- For callbacks, prefer to always define
**kwargs
to allow for additional future arguments. - Use
dict
with aversion
key to introduce strong separation between modules instead of importing modules. - If using classes and it is not possible to maintain backwards compatibility...
- Migrate to new API using code like
from nion.data import ABC2 as ABC
orfrom nion.data2 import ABC
- Write tests for any non-obvious code. Tests not only provide regression tests, but also code explanation.
- New code or bugs can be tested by writing failing test, adding feature/fixing bug, and ensuring test passes with new code.
- Before commit, it is useful to confirm test fails with old code and succeeds with new code.
- Try to write initial tests to confirm main functionality; write additional tests only when a problem is discovered.
- Using this test strategy minimizes the initial effort and avoids the almost-impossible "test every possible case" scenario.
- Do not use random numbers in tests. If required for some reason, seed the random number generator for repeatability.
- Minor releases should not change file formats or deprecate API
- Minor releases can extend API
- Major releases can change file formats, but must seamlessly load old versions
- Use file format transformations (example here) if possible to ease migration.
- Used file formats: profile, project, data item
- Data item format defines metadata but not storage mechanism, which can be ndata, hdf5, etc.
- Plug-in components.
- Color themes.
- Notifications.
- Architectural decision records.