Statistics
| Branch: | Tag: | Revision:

root / doc / dev-codestyle.rst @ 16b85a3c

History | View | Annotate | Download (17.8 kB)

1
Code style guide
2
================
3

    
4
Python
5
------
6

    
7
.. highlight:: python
8

    
9
These are a few guidelines for Ganeti code and documentation.
10

    
11
In simple terms: try to stay consistent with the existing code. `PEP 8`_ says:
12

    
13
.. _PEP 8: http://www.python.org/dev/peps/pep-0008/
14

    
15
  A style guide is about consistency. Consistency with this style guide is
16
  important. Consistency within a project is more important. Consistency
17
  within one module or function is most important.
18

    
19
.. note::
20

    
21
  You might also want to take a look at the `Google style guide`_, since we
22
  have some things in common with it.
23

    
24
.. _Google style guide: http://google-styleguide.googlecode.com/svn/trunk/pyguide.html
25

    
26
Indentation
27
~~~~~~~~~~~
28
In general, always indent using two (2) spaces and don't use tabs.
29

    
30
The two spaces should always be relative to the previous level of indentation,
31
even if this means that the final number of spaces is not a multiple of 2.
32

    
33
When going on a new line inside an open parenthesis, align with the content of
34
the parenthesis on the previous line.
35

    
36
Valid example::
37

    
38
  v = (somevalue,
39
       a_function([
40
         list_elem, # 7 spaces, but 2 from the previous indentation level
41
         another_elem,
42
       ]))
43

    
44
Formatting strings
45
~~~~~~~~~~~~~~~~~~
46
Always use double quotes (``""``), never single quotes (``''``), except for
47
existing code. Examples for formatting strings::
48

    
49
  var = "value"
50

    
51
  # Note: The space character is always on the second line
52
  var = ("The quick brown fox jumps over the lazy dog. The quick brown fox"
53
         " jumps over the lazy dog. The quick brown fox jumps over the lazy"
54
         " dog.")
55

    
56
  fn("The quick brown fox jumps over the lazy dog. The quick brown fox jumps"
57
     " over the lazy dog.")
58

    
59
  fn(constants.CONFIG_VERSION,
60
     ("The quick brown fox jumps over the lazy dog. The quick brown fox"
61
      " jumps over the lazy dog. The quick brown fox jumps over the lazy"
62
      " dog."))
63

    
64
Don't format strings like this::
65

    
66
  # Don't use single quotes
67
  var = 'value'
68

    
69
  # Don't use backslash for line continuation
70
  var = "The quick brown fox jumps over the lazy dog. The quick brown fox"\
71
        " jumps over the lazy dog."
72

    
73
  # Space character goes to the beginning of a new line
74
  var = ("The quick brown fox jumps over the lazy dog. The quick brown fox "
75
         "jumps over the lazy dog. The quick brown fox jumps over the lazy "
76
         "dog.")
77

    
78
Formatting sequences
79
~~~~~~~~~~~~~~~~~~~~
80
Built-in sequence types are list (``[]``), tuple (``()``) and dict (``{}``).
81
When splitting to multiple lines, each item should be on its own line and a
82
comma must be added on the last line. Don't write multiline dictionaries in
83
function calls, except when it's the only parameter. Always indent items by
84
two spaces.
85

    
86
::
87

    
88
  # Short lists
89
  var = ["foo", "bar"]
90
  var = ("foo", "bar")
91

    
92
  # Longer sequences and dictionary
93
  var = [
94
    constants.XYZ_FILENAME_EXTENSION,
95
    constants.FOO_BAR_BAZ,
96
    ]
97
  var = {
98
    "key": func(),
99
    "otherkey": None,
100
    }
101

    
102
  # Multiline tuples as dictionary values
103
  var = {
104
    "key":
105
      ("long value taking the whole line, requiring you to go to a new one",
106
       other_value),
107
  }
108

    
109
  # Function calls
110
  var = frozenset([1, 2, 3])
111
  var = F({
112
    "xyz": constants.XYZ,
113
    "abc": constants.ABC,
114
    })
115

    
116
  # Wrong
117
  F(123, "Hello World",
118
    { "xyz": constants.XYZ })
119

    
120
We consider tuples as data structures, not containers. So in general please
121
use lists when dealing with a sequence of homogeneous items, and tuples when
122
dealing with heterogeneous items.
123

    
124
Passing arguments
125
~~~~~~~~~~~~~~~~~
126
Positional arguments must be passed as positional arguments, keyword arguments
127
must be passed as keyword arguments. Everything else will be difficult to
128
maintain.
129

    
130
::
131

    
132
  # Function signature
133
  def F(data, key, salt=None, key_selector=None):
134
    pass
135

    
136
  # Yes
137
  F("The quick brown fox", "123456")
138
  F("The quick brown fox", "123456", salt="abc")
139
  F("The quick brown fox", "123456", key_selector="xyz")
140
  F("The quick brown fox", "123456", salt="foo", key_selector="xyz")
141

    
142
  # No: Passing keyword arguments as positional argument
143
  F("The quick brown fox", "123456", "xyz", "bar")
144

    
145
  # No: Passing positional arguments as keyword argument
146
  F(salt="xyz", data="The quick brown fox", key="123456", key_selector="xyz")
147

    
148
Docstrings
149
~~~~~~~~~~
150

    
151
.. note::
152

    
153
  `PEP 257`_ is the canonical document, unless epydoc overrules it (e.g. in how
154
  to document the type of an argument).
155

    
156
For docstrings, the recommended format is epytext_, to be processed via
157
epydoc_. There is an ``apidoc`` target that builds the documentation and puts it
158
into the doc/api subdir. Note that we currently use epydoc version 3.0.
159

    
160
.. _PEP 257: http://www.python.org/dev/peps/pep-0257/
161
.. _epytext: http://epydoc.sourceforge.net/manual-epytext.html
162
.. _epydoc: http://epydoc.sourceforge.net/
163

    
164
Note that one-line docstrings are only accepted in the unittests.
165

    
166
Rules for writing the docstrings (mostly standard Python rules):
167

    
168
* the docstring should start with a sentence, with punctuation at the end,
169
  summarizing the the aim of what is being described. This sentence cannot be
170
  longer than one line
171
* the second line should be blank
172
* afterwards the rest of the docstring
173
* special epytext tags should come at the end
174
* multi-line docstrings must finish with an empty line
175
* do not try to make a table using lots of whitespace
176
* use ``L{}`` and ``C{}`` where appropriate
177

    
178
Here's an example::
179

    
180
  def fn(foo, bar):
181
    """Compute the sum of foo and bar.
182

    
183
    This functions builds the sum of foo and bar. It's a simple function.
184

    
185
    @type foo: int
186
    @param foo: First parameter.
187
    @type bar: float
188
    @param bar: The second parameter. This line is longer
189
      to show wrapping.
190
    @rtype: float
191
    @return: the sum of the two numbers
192

    
193
    """
194
    return foo + bar
195

    
196
Some rules of thumb which should be applied with good judgement on a case-to-
197
case basis:
198

    
199
* If the meaning of parameters is already obvious given its name and the
200
  methods description, don't document it again. Just add a ``@type`` tag.
201
* Refer to the base methods documentation when overwriting methods. Only
202
  document more if it applies to the current subclass only, or if you want to
203
  clarify on the meaning of parameters for the special subclass.
204

    
205
Rules for classes and modules
206
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
207
As `PEP 257`_ says, the docstrings of classes should document their attributes
208
and the docstrings of modules should shortly document the exported
209
functions/variables/etc.
210

    
211
See for example the pydoc output for the ``os`` or ``ConfigParser`` standard
212
modules.
213

    
214
Haskell
215
-------
216

    
217
.. highlight:: haskell
218

    
219
The most important consideration is, as usual, to stay consistent with the
220
existing code.
221

    
222
As there's no "canonical" style guide for Haskell, this code style has been
223
inspired from a few online resources, including the style guide for the
224
`Snap framework`_, `this style guide`_ and `this other style guide`_.
225

    
226
.. _Snap framework: http://snapframework.com/docs/style-guide
227
.. _this style guide: https://github.com/tibbe/haskell-style-guide/blob/master/haskell-style.md
228
.. _this other style guide: http://www.cs.caltech.edu/courses/cs11/material/haskell/misc/haskell_style_guide.html
229

    
230
Files
231
~~~~~
232
Use ordinary, non-`literate`_ Haskell ``.hs`` files.
233

    
234
.. _literate: http://www.haskell.org/haskellwiki/Literate_programming
235

    
236
Use proper copyright headers, and proper Haddock style documentation headers::
237

    
238
  {-| Short module summary.
239

    
240
  Longer module description.
241

    
242
  -}
243

    
244
  {-
245

    
246
  Copyright (C) ...
247

    
248
  This program is free software ...
249

    
250
  -}
251

    
252
If there are module-level pragmas add them right at the top, before the short
253
summary.
254

    
255
Imports
256
~~~~~~~
257
Imports should be grouped into the following groups and inside each group they
258
should be sorted alphabetically:
259

    
260
1. standard library imports
261
2. third-party imports
262
3. local imports
263

    
264
It is allowed to use qualified imports with short names for:
265

    
266
* standard library (e.g. ``import qualified Data.Map as M``)
267
* local imports (e.g. ``import qualified Ganeti.Constants as C``), although
268
  this form should be kept to a minimum
269

    
270
Indentation
271
~~~~~~~~~~~
272
Use only spaces, never tabs. Indentation level is 2 characters. For Emacs,
273
this means setting the variable ``haskell-indent-offset`` to 2.
274

    
275
Line length should be at most 78 chars, and 72 chars inside comments.
276

    
277
Use indentation-based structure, and not braces/semicolons.
278

    
279
.. note::
280

    
281
  Special indendation of if/then/else construct
282

    
283
  For the ``do`` notation, the ``if-then-else`` construct has a non-intuitive
284
  behaviour. As such, the indentation of ``if-then-else`` (both in ``do``
285
  blocks and in normal blocks) should be as follows::
286

    
287
    if condition
288
      then expr1
289
      else expr2
290

    
291
  i.e. indent the then/else lines with another level. This can be accomplished
292
  in Emacs by setting the variable ``haskell-indent-thenelse`` to 2 (from the
293
  default of zero).
294

    
295
If you have more than one line of code please newline/indent after the "=". Do
296
`not` do::
297

    
298
  f x = let y = x + 1
299
        in  y
300

    
301
Instead do::
302

    
303
  f x =
304
    let y = x + 1
305
    in  y
306

    
307
or if it is just one line::
308

    
309
  f x = x + 1
310

    
311
Multiline strings
312
~~~~~~~~~~~~~~~~~
313
Multiline strings are created by closing a line with a backslash and starting
314
the following line with a backslash, keeping the indentation level constant.
315
Whitespaces go on the new line, right after the backslash.
316

    
317
::
318

    
319
  longString :: String
320
  longString = "This is a very very very long string that\
321
               \ needs to be split in two lines"
322

    
323
Data declarations
324
~~~~~~~~~~~~~~~~~
325
.. warning::
326
  Note that this is different from the Python style!
327

    
328
When declaring either data types, or using list literals, etc., the columns
329
should be aligned, and for lists use a comma at the start of the line, not at
330
the end. Examples::
331

    
332
  data OpCode = OpStartupInstance ...
333
              | OpShutdownInstance ...
334
              | ...
335

    
336
  data Node = Node { name :: String
337
                   , ip   :: String
338
                   , ...
339
                   }
340

    
341
  myList = [ value1
342
           , value2
343
           , value3
344
           ]
345

    
346
The choice of whether to wrap the first element or not is up to you; the
347
following is also allowed::
348

    
349
  myList =
350
    [ value1
351
    , value2
352
    ]
353

    
354
For records, always add spaces around the braces and the equality sign.
355
::
356

    
357
  foo = Foo { fBar = "bar", fBaz = 4711 }
358

    
359
  foo' = Foo { fBar = "bar 2"
360
             , fBaz = 4712
361
             }
362

    
363
  node' = node { ip = "127.0.0.1" }
364

    
365

    
366
White space
367
~~~~~~~~~~~
368
Like in Python, surround binary operators with one space on either side. Do no
369
insert a space after a lamda::
370

    
371
  -- bad
372
  map (\ n -> ...) lst
373
  -- good
374
  foldl (\x y -> ...) ...
375

    
376
Use a blank line between top-level definitions, but no blank lines between
377
either the comment and the type signature or between the type signature and
378
the actual function definition.
379

    
380
.. note::
381
  Ideally it would be two blank lines between top-level definitions, but the
382
  code only has one now.
383

    
384
As always, no trailing spaces. Ever.
385

    
386
Spaces after comma
387
******************
388

    
389
Instead of::
390

    
391
  ("a","b")
392

    
393
write::
394

    
395
  ("a", "b")
396

    
397
Naming
398
~~~~~~
399
Functions should be named in mixedCase style, and types in CamelCase. Function
400
arguments and local variables should be mixedCase.
401

    
402
When using acronyms, ones longer than 2 characters should be typed capitalised,
403
not fully upper-cased (e.g. ``Http``, not ``HTTP``).
404

    
405
For variable names, use descriptive names; it is only allowed to use very
406
short names (e.g. ``a``, ``b``, ``i``, ``j``, etc.) when:
407

    
408
* the function is trivial, e.g.::
409

    
410
    sum x y = x + y
411

    
412
* we talk about some very specific cases, e.g.
413
  iterators or accumulators in folds::
414

    
415
    map (\v -> v + 1) lst
416

    
417
* using ``x:xs`` for list elements and lists, etc.
418

    
419
In general, short/one-letter names are allowed when we deal with polymorphic
420
values; for example the standard map definition from Prelude::
421

    
422
  map :: (a -> b) -> [a] -> [b]
423
  map _ []     = []
424
  map f (x:xs) = f x : map f xs
425

    
426
In this example, neither the ``a`` nor ``b`` types are known to the map
427
function, so we cannot give them more explicit names. Since the body of the
428
function is trivial, the variables used are longer.
429

    
430
However, if we deal with explicit types or values, their names should be
431
descriptive.
432

    
433
.. todo: add a nice example here.
434

    
435
Finally, the naming should look familiar to people who just read the
436
Prelude/standard libraries.
437

    
438
Naming for updated values
439
*************************
440

    
441
.. highlight:: python
442

    
443
Since one cannot update a value in Haskell, this presents a particular problem
444
on the naming of new versions of the same value. For example, the following
445
code in Python::
446

    
447
  def failover(pri, sec, inst):
448
    pri.removePrimary(inst)
449
    pri.addSecondary(inst)
450
    sec.removeSecondary(inst)
451
    sec.addPrimary(inst)
452

    
453
.. highlight:: haskell
454

    
455
becomes in Haskell something like the following::
456

    
457
  failover pri sec inst =
458
    let pri'  = removePrimary pri inst
459
        pri'' = addSecondary pri' inst
460
        sec'  = removeSecondary sec inst
461
        sec'' = addPrimary sec' inst
462
    in (pri'', sec'')
463

    
464
When updating values, one should add single quotes to the name for up to three
465
new names (e.g. ``inst``, ``inst'``, ``inst''``, ``inst'''``) and otherwise
466
use numeric suffixes (``inst1``, ``inst2``, ``inst3``, ..., ``inst8``), but
467
that many updates is already bad style and thus should be avoided.
468

    
469
Type signatures
470
~~~~~~~~~~~~~~~
471

    
472
Always declare types for functions (and any other top-level bindings).
473

    
474
If in doubt, feel free to declare the type of the variables/bindings in a
475
complex expression; this usually means the expression is too complex, however.
476

    
477
Similarly, provide Haddock-style comments for top-level definitions.
478

    
479
Use sum types instead of exceptions
480
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
481

    
482
Exceptions make it hard to write functional code, as alternative
483
control flows need to be considered and compiler support is limited.
484
Therefore, Ganeti functions should never allow exceptions to escape.
485
Function that can fail should report failure by returning an appropriate
486
sum type (``Either`` or one of its glorified variants like ``Maybe`` or
487
``Result``); the preferred sum type for reporting errors is ``Result``.
488

    
489
As other Ganeti functions also follow these guide lines, they can safely
490
be composed. However, be careful when using functions from other libraries;
491
if they can raise exceptions, catch them, preferably as close to their
492
origin as reasonably possible.
493

    
494
Parentheses, point free style
495
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
496

    
497
Prefer the so-called `point-free`_ style style when declaring functions, if
498
applicable::
499

    
500
  -- bad
501
  let a x = f (g (h x))
502
  -- good
503
  let a = f . g . h
504

    
505
Also use function composition in a similar manner in expressions to avoid extra
506
parentheses::
507

    
508
  -- bad
509
  f (g (h x))
510
  -- better
511
  f $ g $ h x
512
  -- best
513
  f . g . h $ x
514

    
515
.. _`point-free`: http://www.haskell.org/haskellwiki/Pointfree
516

    
517
Language features
518
~~~~~~~~~~~~~~~~~
519

    
520
Extensions
521
**********
522

    
523
It is recommended to keep the use of extensions to a minimum, so that the code
524
can be understood even if one is familiar with just Haskel98/Haskell2010. That
525
said, some extensions are very common and useful, so they are recommended:
526

    
527
* `Bang patterns`_: useful when you want to enforce strict evaluation (and better
528
  than repeated use of ``seq``)
529
* CPP: a few modules need this in order to account for configure-time options;
530
  don't overuse it, since it breaks multi-line strings
531
* `Template Haskell`_: we use this for automatically deriving JSON instances and
532
  other similar boiler-plate
533

    
534
.. _Bang patterns: http://www.haskell.org/ghc/docs/latest/html/users_guide/bang-patterns.html
535
.. _Template Haskell: http://www.haskell.org/ghc/docs/latest/html/users_guide/template-haskell.html
536

    
537
Such extensions should be declared using the ``Language`` pragma::
538

    
539
  {-# Language BangPatterns #-}
540

    
541
  {-| This is a small module... -}
542

    
543
Comments
544
********
545

    
546
Always use proper sentences; start with a capital letter and use punctuation
547
in top level comments::
548

    
549
  -- | A function that does something.
550
  f :: ...
551

    
552
For inline comments, start with a capital letter but no ending punctuation.
553
Furthermore, align the comments together with a 2-space width from the end of
554
the item being commented::
555

    
556
  data Maybe a = Nothing  -- ^ Represents empty container
557
               | Just a   -- ^ Represents a single value
558

    
559
The comments should be clear enough so that one doesn't need to look at the
560
code to understand what the item does/is.
561

    
562
Use ``-- |`` to write doc strings rather than bare comment with ``--``.
563

    
564
Tools
565
*****
566

    
567
We generate the API documentation via Haddock, and as such the comments should
568
be correct (syntax-wise) for it. Use markup, but sparingly.
569

    
570
We use hlint_ as a lint checker; the code is currently lint-clean, so you must
571
not add any warnings/errors.
572

    
573
.. _hlint: http://community.haskell.org/~ndm/darcs/hlint/hlint.htm
574

    
575
Use these two commands during development::
576

    
577
  make hs-apidoc
578
  make hlint
579

    
580
QuickCheck best practices
581
*************************
582

    
583
If you have big type that takes time to generate and several properties to
584
test on that, by default 500 of those big instances are generated for each
585
property. In many cases, it would be sufficient to only generate those 500
586
instances once and test all properties on those. To do this, create a property
587
that uses ``conjoin`` to combine several properties into one. Use
588
``printTestCase`` to add expressive error messages. For example::
589

    
590
  prop_myMegaProp :: myBigType -> Property
591
  prop_myMegaProp b =
592
    conjoin
593
      [ printTestCase
594
          ("Something failed horribly here: " ++ show b) (subProperty1 b)
595
      , printTestCase
596
          ("Something else failed horribly here: " ++ show b)
597
          (subProperty2 b)
598
      , -- more properties here ...
599
      ]
600

    
601
  subProperty1 :: myBigType -> Bool
602
  subProperty1 b = ...
603

    
604
  subProperty2 :: myBigType -> Property
605
  subProperty2 b = ...
606

    
607
  ...
608

    
609
Maybe Generation
610
''''''''''''''''
611

    
612
Use ``genMaybe genSomething`` to create ``Maybe`` instances of something
613
including some ``Nothing`` instances.
614

    
615
Use ``Just <$> genSomething`` to generate only ``Just`` instances of
616
something.
617

    
618
String Generation
619
'''''''''''''''''
620

    
621
To generate strings, consider using ``genName`` instead of ``arbitrary``.
622
``arbitrary`` has the tendency to generate strings that are too long.