summaryrefslogtreecommitdiff
path: root/trunk/HACKING
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/HACKING')
-rw-r--r--trunk/HACKING173
1 files changed, 173 insertions, 0 deletions
diff --git a/trunk/HACKING b/trunk/HACKING
new file mode 100644
index 0000000..cafab29
--- /dev/null
+++ b/trunk/HACKING
@@ -0,0 +1,173 @@
+HACKING Dimbola for fun and very little profit
+==============================================
+
+
+Introduction
+------------
+
+This file has some notes about how Dimbola should be developed.
+
+All the generally accepted good Python coding stuff applies: PEP8
+formatting, using only spaces and no tabs for indentation, etc. We
+cover here only things specific to the Dimbola project.
+
+
+Overview of the code base
+-------------------------
+
+* dimbola-gtk -- the main program; this is intended to be a one-liner
+
+* dimbola/*.py -- Python package with the core of the app
+
+* dimbola/plugins/*_plugin.py -- plugins that come with the core app;
+ as much as possible is put into plugins
+
+* dimbola/ui.ui and dimbola/plugins/*.ui -- glade/GtkBuilder files; these
+ are loaded automatically
+
+* dimbola/*_tests.py and dimbola/plugins/*_tests.py -- unit tests for
+ the corresponding files
+
+
+Development priorities
+----------------------
+
+The main priority should always be to fix bugs. Each release should
+fix all bugs, if at all possible. It is obvious that this is not
+always possible, but it is the goal anyway. Better to attempt something
+really good and almost get it than to play it safe.
+
+
+Version numbering
+-----------------
+
+The canonical location of the version number is in dimbola/__init__.py
+as the version variable. setup.py will extract it from there. ui.py will
+use dimbola.version to set the version number in the Help/About dialog
+box.
+
+Version number until 1.0 will be as follows:
+
+ 0.0.x pre-alpha versions, not intended to be usable at all
+ 0.x.0 alpha and beta versions; these are intended to be usable,
+ though they are probably really buggy
+ 1.0.0 first release intended to be usable by a non-hacker
+
+Eventually, a ROADMAP file will be written to specify what 1.0.0 should
+contain.
+
+
+Writing plugins
+---------------
+
+To write a plugin, import the dimbola package, and subclass dimbola.Plugin.
+The initializer MUST have the following signature:
+
+ def __init__(self, mwc):
+
+To use the plugin, put it in a file in dimbola/plugins/foo_plugin.py.
+
+Plugins may access the MainWindowController's attributes and methods.
+
+When a Plugin subclass is instantiated, it MUST NOT cause any side
+effects: it must not modify the user interface, connect to signals,
+or whatever. All of that must be done in the enable() method, and
+un-done in the disable() method. This is necessary so that the
+user may enable and disable any installed plugin.
+
+Plugins may add new items to menus via MWC.add_to_menu. The UI file
+needs to specify a name for the menu widget, and this name is used
+with add_to_menu. Additionally, the menu may have separators whose
+names begin with prepend_separator or append_separator, and add_to_menu
+will put the new menu item before or after such a separator.
+
+To remove the menu item (when the plugin is disabled), the
+MWC.remove_from_menu method may be used.
+
+Similarily for sidebar sections: see MWC.add_to_sidebar and
+MWC.remove_from_sidebar.
+
+Plugins may have their own user interface definition files. For
+a plugin named foo_plugin.py, the file foo.ui is loaded automatically,
+if it exists. The plugin may access the widgets via
+MainWindowController.widgets.
+
+
+Signals and hooks
+-----------------
+
+We try use GObject signals for communicating between parts of
+the code. This decouples different modules, which is a good thing.
+For example, the thumbnail grid is implemented using
+model/view/controller. When the list of photos in the model
+changes, the view must redraw itself. Rather than having the model
+call a method on the view, the view connects to a signal in the
+model. Thus, the model need not know anything about the view.
+Indeed, other things than the view can make use of the same
+signal.
+
+In order to connect to a signal, you need to know the object the
+signal applies to. This is awkward when a plugin provides the
+object and the signal. We work around this by adding the signal
+to a well-known object, the MainWindowController, using the
+new_hook method.
+
+Thus, in Dimbola, a hook is a custom signal added to MWC.
+
+
+Unit tests and coverage
+-----------------------
+
+The goal is to make Dimbola a very good program. Part of that is to make
+it very reliable, and the way to get there is to have an automated unit test
+suite with very good coverage.
+
+Currently, there is abysmal coverage. The current code was written in haste,
+to get a proof-of-concept prototype done very quickly. Writing tests would
+have slowed things down.
+
+The strategy to get to good coverage is as follows: all of the current
+GUI code exists in dimbola/db.py and dimbola/ui.py. db.py may get some
+unit tests later on, but ui.py is going to be test-less. However, as
+much code as possible will be broken out of it, into other modules, and
+those modules will have unit tests. The goal is to have those other
+modules have 100% statement coverage.
+
+Almost all the code will be called in response to GTK+ events and signals,
+from callback functions. The general design principle here, as far as
+testing is concerned, is that the actual callback function will be not
+be tested, but it will be as simple as possible and call functions
+elsewhere to do the actual work. Those functions will be unit tested.
+
+
+Using Glade
+-----------
+
+The UI is defined using Glade and GtkBuilder. Everything that can
+reasonably be done in Glade shall be done in Glade.
+
+Widgets in the .glade file and their signal callbacks will be
+connected automatically based on a naming convention. For a widget
+named foo, and its signal named bar, a callback will be connected
+automatically if the code has a method called on_foo_bar in a relevant
+controller object.
+
+This means the .glade file should not have any signal handlers defined.
+
+Widgets that do not have callbacks can use whatever name Glade gives
+them by default (e.g., "textview123"). If a callback is needed, the
+widget should be renamed in a sensible way that indicates its use
+(e.g., "photo_tags_textview").
+
+See dimbola/gtkapp.py for details on the magic.
+
+
+Background processing
+---------------------
+
+Threads are evil, at least in the context of Python and GTK+. We do not
+use (explicit) threads in Dimbola. Instead, we use glib.idle_add and
+the Python standard library module multiprocessing. The latter is wrapped
+inside the BackgroundManager and BackgroundJob classes; see the
+dimbola/bgjobs.py module.
+