Development/CodingStyle

Darcs code can be a little hostile. —Florent

How can we fix that?

New habits

  • haddock

    • type signatures for top level functions! this used to be enforced by -Werror and now it's to be enforced by nagging from the Review Team
    • API-style comments (not just relying on the interspersed user-manual for implicit documentation)
  • When using explicit lists in code, for example for options, use one entry per line as it makes it easy to write small and clean patches if a list entry gets changed later
  • Write tests! Tests are the easiest way to convince others that your code does what you intend it to do.
  • Send in QuickCheck properties for things you write.
  • Use tools like hlint to improve the style of your patches

Reforms to old habits

Changes to old code we would welcome:

  • avoid cryptically short function names (gcau, wspr)
  • favour camelCase for top level functions (if you want to use underscores, you'd better have a reason, not just taste)
  • If you study existing code to understand it, add haddocks summarizing what you learned. This will help others save time in the future.

Minor stylistic details

  • no trailing whitespace
  • avoid needless parens? (for example when using ++)
  • use fmap to simplify returning a result in a monad (e.g lines `fmap` readFile foo)
  • avoid long lines if possible. A rule of thumb is 65 lines (+10, under special circumstances) just as the fmt(1) command suggests
  • if your patch fixes issueXYZ, then start the patch name with "resolve isssueXYZ: my comments"

Grievances

New developers (and old developpers alike), state here your griefs against the code, and your proposed solution to them, for the community to turn them into new good habits. Help the darcs readability revolution!

Please be positive in your comments: no finger-pointing, and as much references to concrete code as possible. Have a nice Catharsis!

  • Functions which output a message to the user (such as "do you want to record this patch?") should have the message in a comment near them, so that they can be found by grepping. Ideally (?) these functions should be in the Darcs.Command.* modules, and Darcs.Internal.* should only have non-interactive functions.
  • When a module A reexports a function f from another module B, in a module C which needs f, import it from B rather than A, so as to avoid too many indirections when looking for f.

    • Would the exception here be unless we are trying to get some kind of encapsulation going, as with Darcs.Patch and Darcs.Repository?
    • Of course, on the other hand, using that exception might also be a hint that there might be some over-encapsultation (aka YAGNI) going on. Its probably something that's not worth actually chasing in existing code, but it's a good question to ask oneself before writing new code. Especially module A (the reexporter) in my example above.
  • unsafeCoerceP should not be used except in the core. smart_diff is a similarly dangerous function and should be carefully used.

Wolfgang's Feedback

Experiences from grapefruit GraphicalInterface hackers

  • currently the terminal-based user interface code of darcs and the actual application logic are too much intermixed.
  • code documentation was lacking and code was sometimes a bit hard to understand.
  • The code often isn’t split in many small bits but that it often consists of huge function definitions.

Iago's Feedback

These mostly come from a discussion that happened on irc: http://irclog.perlgeek.de/darcs/2010-12-09

  • Order of definitions in a file makes a big difference. If definition A depends on B, then we should try to define B near A, not 500 lines away.
  • Write less code and be more clear when you write it.
  • Documentation matters.
  • Type witnesses are hard to read for newcomers.
  • cleverCommute could be documented so I can read "it makes use of this clever trick"
  • First time you read commuteFiledir you ask, what are the cases does it not handle?
  • tests that call things identity when they really aren't

More feedback: http://irclog.perlgeek.de/darcs/2010-12-15#i_3089249

  • patch-pair generator for commutation tests only produces 4-7% useful cases
  • calling things identity things that are not identity
  • someone decided that arbitraryTree should produce empty trees 40% of times, but not justified (performance?)