Shotwell Coding Guidelines

As with all Yorba projects, Shotwell source should conform to the Yorba coding conventions. The following coding guidelines were developed specifically for Shotwell, but may be adopted by other Yorba projects:

  • Use assert() for sanity checking as well as parameter checking. Do not use assertions to check user input; this must be checked at run-time and either reported back to the user or silently corrected. Don't go crazy with assertions. Vala's generated C code does null checking automatically, for example.
  • Use Vala's logging functions rather than stdout/stderr.printf(). Logged messages can be captured or suppressed later, if necessary. Note that calling the error() log function will terminate the application. Other logging, debugging, and error functions can be found at the bottom of the  valadocs.org GLib page.
  • The app's database and caches and various other files are maintained in a hidden directory in the user's home directory. We assume that these files will not be deleted or modified directly by the user at run-time, so no error recovery should be performed. However, basic sanity checking should be done at start time to ensure the application can execute.
  • Although some configuration may be maintained outside the hidden data directory, external config changes won't be recognized after program initialization.
  • Data files external to the app (in particular, the user's photo files) may be altered, moved, or deleted by the user at any time. Because they don't "belong" to Shotwell, we must be account for the various possibilities.
  • For SQLite, use assert() on prepare_v2(), as a failure there indicates malformed SQL, which is a programming bug.
  • Also use assert() on the SQLite bind_*() calls, as all error conditions indicate programming errors as well.
  • For SQLite's step(), there are two non-error return code possibilities: Sqlite.DONE, which means no more rows can be found, and Sqlite.ROW, which means a row has been loaded and may be examined. There are two error return codes we must handle as well: Sqlite.CONSTRAINT, which means a value is out of bounds, most likely one that was passed in as an argument. An error code should be propagated for this. Sqlite.ERROR indicates a run-time error, which can be handled with an error() call.
  • If the database cannot be opened, use error().
  • Use SQLite's errmsg() in log functions.