root / doc / dev-codestyle.rst @ 0565f862
History | View | Annotate | Download (17.8 kB)
1 | a41a1eec | Santi Raffa | Code style guide |
---|---|---|---|
2 | a41a1eec | Santi Raffa | ================ |
3 | a41a1eec | Santi Raffa | |
4 | a41a1eec | Santi Raffa | Python |
5 | a41a1eec | Santi Raffa | ------ |
6 | a41a1eec | Santi Raffa | |
7 | a41a1eec | Santi Raffa | .. highlight:: python |
8 | a41a1eec | Santi Raffa | |
9 | a41a1eec | Santi Raffa | These are a few guidelines for Ganeti code and documentation. |
10 | a41a1eec | Santi Raffa | |
11 | a41a1eec | Santi Raffa | In simple terms: try to stay consistent with the existing code. `PEP 8`_ says: |
12 | a41a1eec | Santi Raffa | |
13 | a41a1eec | Santi Raffa | .. _PEP 8: http://www.python.org/dev/peps/pep-0008/ |
14 | a41a1eec | Santi Raffa | |
15 | a41a1eec | Santi Raffa | A style guide is about consistency. Consistency with this style guide is |
16 | a41a1eec | Santi Raffa | important. Consistency within a project is more important. Consistency |
17 | a41a1eec | Santi Raffa | within one module or function is most important. |
18 | a41a1eec | Santi Raffa | |
19 | a41a1eec | Santi Raffa | .. note:: |
20 | a41a1eec | Santi Raffa | |
21 | a41a1eec | Santi Raffa | You might also want to take a look at the `Google style guide`_, since we |
22 | a41a1eec | Santi Raffa | have some things in common with it. |
23 | a41a1eec | Santi Raffa | |
24 | a41a1eec | Santi Raffa | .. _Google style guide: http://google-styleguide.googlecode.com/svn/trunk/pyguide.html |
25 | a41a1eec | Santi Raffa | |
26 | a41a1eec | Santi Raffa | Indentation |
27 | a41a1eec | Santi Raffa | ~~~~~~~~~~~ |
28 | a41a1eec | Santi Raffa | In general, always indent using two (2) spaces and don't use tabs. |
29 | a41a1eec | Santi Raffa | |
30 | a41a1eec | Santi Raffa | The two spaces should always be relative to the previous level of indentation, |
31 | a41a1eec | Santi Raffa | even if this means that the final number of spaces is not a multiple of 2. |
32 | a41a1eec | Santi Raffa | |
33 | a41a1eec | Santi Raffa | When going on a new line inside an open parenthesis, align with the content of |
34 | a41a1eec | Santi Raffa | the parenthesis on the previous line. |
35 | a41a1eec | Santi Raffa | |
36 | a41a1eec | Santi Raffa | Valid example:: |
37 | a41a1eec | Santi Raffa | |
38 | a41a1eec | Santi Raffa | v = (somevalue, |
39 | a41a1eec | Santi Raffa | a_function([ |
40 | a41a1eec | Santi Raffa | list_elem, # 7 spaces, but 2 from the previous indentation level |
41 | a41a1eec | Santi Raffa | another_elem, |
42 | a41a1eec | Santi Raffa | ])) |
43 | a41a1eec | Santi Raffa | |
44 | a41a1eec | Santi Raffa | Formatting strings |
45 | a41a1eec | Santi Raffa | ~~~~~~~~~~~~~~~~~~ |
46 | a41a1eec | Santi Raffa | Always use double quotes (``""``), never single quotes (``''``), except for |
47 | a41a1eec | Santi Raffa | existing code. Examples for formatting strings:: |
48 | a41a1eec | Santi Raffa | |
49 | a41a1eec | Santi Raffa | var = "value" |
50 | a41a1eec | Santi Raffa | |
51 | a41a1eec | Santi Raffa | # Note: The space character is always on the second line |
52 | a41a1eec | Santi Raffa | var = ("The quick brown fox jumps over the lazy dog. The quick brown fox" |
53 | a41a1eec | Santi Raffa | " jumps over the lazy dog. The quick brown fox jumps over the lazy" |
54 | a41a1eec | Santi Raffa | " dog.") |
55 | a41a1eec | Santi Raffa | |
56 | a41a1eec | Santi Raffa | fn("The quick brown fox jumps over the lazy dog. The quick brown fox jumps" |
57 | a41a1eec | Santi Raffa | " over the lazy dog.") |
58 | a41a1eec | Santi Raffa | |
59 | a41a1eec | Santi Raffa | fn(constants.CONFIG_VERSION, |
60 | a41a1eec | Santi Raffa | ("The quick brown fox jumps over the lazy dog. The quick brown fox" |
61 | a41a1eec | Santi Raffa | " jumps over the lazy dog. The quick brown fox jumps over the lazy" |
62 | a41a1eec | Santi Raffa | " dog.")) |
63 | a41a1eec | Santi Raffa | |
64 | a41a1eec | Santi Raffa | Don't format strings like this:: |
65 | a41a1eec | Santi Raffa | |
66 | a41a1eec | Santi Raffa | # Don't use single quotes |
67 | a41a1eec | Santi Raffa | var = 'value' |
68 | a41a1eec | Santi Raffa | |
69 | a41a1eec | Santi Raffa | # Don't use backslash for line continuation |
70 | a41a1eec | Santi Raffa | var = "The quick brown fox jumps over the lazy dog. The quick brown fox"\ |
71 | a41a1eec | Santi Raffa | " jumps over the lazy dog." |
72 | a41a1eec | Santi Raffa | |
73 | a41a1eec | Santi Raffa | # Space character goes to the beginning of a new line |
74 | a41a1eec | Santi Raffa | var = ("The quick brown fox jumps over the lazy dog. The quick brown fox " |
75 | a41a1eec | Santi Raffa | "jumps over the lazy dog. The quick brown fox jumps over the lazy " |
76 | a41a1eec | Santi Raffa | "dog.") |
77 | a41a1eec | Santi Raffa | |
78 | a41a1eec | Santi Raffa | Formatting sequences |
79 | a41a1eec | Santi Raffa | ~~~~~~~~~~~~~~~~~~~~ |
80 | a41a1eec | Santi Raffa | Built-in sequence types are list (``[]``), tuple (``()``) and dict (``{}``). |
81 | a41a1eec | Santi Raffa | When splitting to multiple lines, each item should be on its own line and a |
82 | a41a1eec | Santi Raffa | comma must be added on the last line. Don't write multiline dictionaries in |
83 | a41a1eec | Santi Raffa | function calls, except when it's the only parameter. Always indent items by |
84 | a41a1eec | Santi Raffa | two spaces. |
85 | a41a1eec | Santi Raffa | |
86 | a41a1eec | Santi Raffa | :: |
87 | a41a1eec | Santi Raffa | |
88 | a41a1eec | Santi Raffa | # Short lists |
89 | a41a1eec | Santi Raffa | var = ["foo", "bar"] |
90 | a41a1eec | Santi Raffa | var = ("foo", "bar") |
91 | a41a1eec | Santi Raffa | |
92 | a41a1eec | Santi Raffa | # Longer sequences and dictionary |
93 | a41a1eec | Santi Raffa | var = [ |
94 | a41a1eec | Santi Raffa | constants.XYZ_FILENAME_EXTENSION, |
95 | a41a1eec | Santi Raffa | constants.FOO_BAR_BAZ, |
96 | a41a1eec | Santi Raffa | ] |
97 | a41a1eec | Santi Raffa | var = { |
98 | a41a1eec | Santi Raffa | "key": func(), |
99 | a41a1eec | Santi Raffa | "otherkey": None, |
100 | a41a1eec | Santi Raffa | } |
101 | a41a1eec | Santi Raffa | |
102 | a41a1eec | Santi Raffa | # Multiline tuples as dictionary values |
103 | a41a1eec | Santi Raffa | var = { |
104 | a41a1eec | Santi Raffa | "key": |
105 | a41a1eec | Santi Raffa | ("long value taking the whole line, requiring you to go to a new one", |
106 | a41a1eec | Santi Raffa | other_value), |
107 | a41a1eec | Santi Raffa | } |
108 | a41a1eec | Santi Raffa | |
109 | a41a1eec | Santi Raffa | # Function calls |
110 | a41a1eec | Santi Raffa | var = frozenset([1, 2, 3]) |
111 | a41a1eec | Santi Raffa | var = F({ |
112 | a41a1eec | Santi Raffa | "xyz": constants.XYZ, |
113 | a41a1eec | Santi Raffa | "abc": constants.ABC, |
114 | a41a1eec | Santi Raffa | }) |
115 | a41a1eec | Santi Raffa | |
116 | a41a1eec | Santi Raffa | # Wrong |
117 | a41a1eec | Santi Raffa | F(123, "Hello World", |
118 | a41a1eec | Santi Raffa | { "xyz": constants.XYZ }) |
119 | a41a1eec | Santi Raffa | |
120 | a41a1eec | Santi Raffa | We consider tuples as data structures, not containers. So in general please |
121 | a41a1eec | Santi Raffa | use lists when dealing with a sequence of homogeneous items, and tuples when |
122 | a41a1eec | Santi Raffa | dealing with heterogeneous items. |
123 | a41a1eec | Santi Raffa | |
124 | a41a1eec | Santi Raffa | Passing arguments |
125 | a41a1eec | Santi Raffa | ~~~~~~~~~~~~~~~~~ |
126 | a41a1eec | Santi Raffa | Positional arguments must be passed as positional arguments, keyword arguments |
127 | a41a1eec | Santi Raffa | must be passed as keyword arguments. Everything else will be difficult to |
128 | a41a1eec | Santi Raffa | maintain. |
129 | a41a1eec | Santi Raffa | |
130 | a41a1eec | Santi Raffa | :: |
131 | a41a1eec | Santi Raffa | |
132 | a41a1eec | Santi Raffa | # Function signature |
133 | a41a1eec | Santi Raffa | def F(data, key, salt=None, key_selector=None): |
134 | a41a1eec | Santi Raffa | pass |
135 | a41a1eec | Santi Raffa | |
136 | a41a1eec | Santi Raffa | # Yes |
137 | a41a1eec | Santi Raffa | F("The quick brown fox", "123456") |
138 | a41a1eec | Santi Raffa | F("The quick brown fox", "123456", salt="abc") |
139 | a41a1eec | Santi Raffa | F("The quick brown fox", "123456", key_selector="xyz") |
140 | a41a1eec | Santi Raffa | F("The quick brown fox", "123456", salt="foo", key_selector="xyz") |
141 | a41a1eec | Santi Raffa | |
142 | a41a1eec | Santi Raffa | # No: Passing keyword arguments as positional argument |
143 | a41a1eec | Santi Raffa | F("The quick brown fox", "123456", "xyz", "bar") |
144 | a41a1eec | Santi Raffa | |
145 | a41a1eec | Santi Raffa | # No: Passing positional arguments as keyword argument |
146 | a41a1eec | Santi Raffa | F(salt="xyz", data="The quick brown fox", key="123456", key_selector="xyz") |
147 | a41a1eec | Santi Raffa | |
148 | a41a1eec | Santi Raffa | Docstrings |
149 | a41a1eec | Santi Raffa | ~~~~~~~~~~ |
150 | a41a1eec | Santi Raffa | |
151 | a41a1eec | Santi Raffa | .. note:: |
152 | a41a1eec | Santi Raffa | |
153 | a41a1eec | Santi Raffa | `PEP 257`_ is the canonical document, unless epydoc overrules it (e.g. in how |
154 | a41a1eec | Santi Raffa | to document the type of an argument). |
155 | a41a1eec | Santi Raffa | |
156 | a41a1eec | Santi Raffa | For docstrings, the recommended format is epytext_, to be processed via |
157 | a41a1eec | Santi Raffa | epydoc_. There is an ``apidoc`` target that builds the documentation and puts it |
158 | a41a1eec | Santi Raffa | into the doc/api subdir. Note that we currently use epydoc version 3.0. |
159 | a41a1eec | Santi Raffa | |
160 | a41a1eec | Santi Raffa | .. _PEP 257: http://www.python.org/dev/peps/pep-0257/ |
161 | a41a1eec | Santi Raffa | .. _epytext: http://epydoc.sourceforge.net/manual-epytext.html |
162 | a41a1eec | Santi Raffa | .. _epydoc: http://epydoc.sourceforge.net/ |
163 | a41a1eec | Santi Raffa | |
164 | a41a1eec | Santi Raffa | Note that one-line docstrings are only accepted in the unittests. |
165 | a41a1eec | Santi Raffa | |
166 | a41a1eec | Santi Raffa | Rules for writing the docstrings (mostly standard Python rules): |
167 | a41a1eec | Santi Raffa | |
168 | a41a1eec | Santi Raffa | * the docstring should start with a sentence, with punctuation at the end, |
169 | a41a1eec | Santi Raffa | summarizing the the aim of what is being described. This sentence cannot be |
170 | a41a1eec | Santi Raffa | longer than one line |
171 | a41a1eec | Santi Raffa | * the second line should be blank |
172 | a41a1eec | Santi Raffa | * afterwards the rest of the docstring |
173 | a41a1eec | Santi Raffa | * special epytext tags should come at the end |
174 | a41a1eec | Santi Raffa | * multi-line docstrings must finish with an empty line |
175 | a41a1eec | Santi Raffa | * do not try to make a table using lots of whitespace |
176 | a41a1eec | Santi Raffa | * use ``L{}`` and ``C{}`` where appropriate |
177 | a41a1eec | Santi Raffa | |
178 | a41a1eec | Santi Raffa | Here's an example:: |
179 | a41a1eec | Santi Raffa | |
180 | a41a1eec | Santi Raffa | def fn(foo, bar): |
181 | a41a1eec | Santi Raffa | """Compute the sum of foo and bar. |
182 | a41a1eec | Santi Raffa | |
183 | a41a1eec | Santi Raffa | This functions builds the sum of foo and bar. It's a simple function. |
184 | a41a1eec | Santi Raffa | |
185 | a41a1eec | Santi Raffa | @type foo: int |
186 | a41a1eec | Santi Raffa | @param foo: First parameter. |
187 | a41a1eec | Santi Raffa | @type bar: float |
188 | a41a1eec | Santi Raffa | @param bar: The second parameter. This line is longer |
189 | a41a1eec | Santi Raffa | to show wrapping. |
190 | a41a1eec | Santi Raffa | @rtype: float |
191 | a41a1eec | Santi Raffa | @return: the sum of the two numbers |
192 | a41a1eec | Santi Raffa | |
193 | a41a1eec | Santi Raffa | """ |
194 | a41a1eec | Santi Raffa | return foo + bar |
195 | a41a1eec | Santi Raffa | |
196 | a41a1eec | Santi Raffa | Some rules of thumb which should be applied with good judgement on a case-to- |
197 | a41a1eec | Santi Raffa | case basis: |
198 | a41a1eec | Santi Raffa | |
199 | a41a1eec | Santi Raffa | * If the meaning of parameters is already obvious given its name and the |
200 | a41a1eec | Santi Raffa | methods description, don't document it again. Just add a ``@type`` tag. |
201 | a41a1eec | Santi Raffa | * Refer to the base methods documentation when overwriting methods. Only |
202 | a41a1eec | Santi Raffa | document more if it applies to the current subclass only, or if you want to |
203 | a41a1eec | Santi Raffa | clarify on the meaning of parameters for the special subclass. |
204 | a41a1eec | Santi Raffa | |
205 | a41a1eec | Santi Raffa | Rules for classes and modules |
206 | a41a1eec | Santi Raffa | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
207 | a41a1eec | Santi Raffa | As `PEP 257`_ says, the docstrings of classes should document their attributes |
208 | a41a1eec | Santi Raffa | and the docstrings of modules should shortly document the exported |
209 | a41a1eec | Santi Raffa | functions/variables/etc. |
210 | a41a1eec | Santi Raffa | |
211 | a41a1eec | Santi Raffa | See for example the pydoc output for the ``os`` or ``ConfigParser`` standard |
212 | a41a1eec | Santi Raffa | modules. |
213 | a41a1eec | Santi Raffa | |
214 | a41a1eec | Santi Raffa | Haskell |
215 | a41a1eec | Santi Raffa | ------- |
216 | a41a1eec | Santi Raffa | |
217 | a41a1eec | Santi Raffa | .. highlight:: haskell |
218 | a41a1eec | Santi Raffa | |
219 | a41a1eec | Santi Raffa | The most important consideration is, as usual, to stay consistent with the |
220 | a41a1eec | Santi Raffa | existing code. |
221 | a41a1eec | Santi Raffa | |
222 | a41a1eec | Santi Raffa | As there's no "canonical" style guide for Haskell, this code style has been |
223 | a41a1eec | Santi Raffa | inspired from a few online resources, including the style guide for the |
224 | a41a1eec | Santi Raffa | `Snap framework`_, `this style guide`_ and `this other style guide`_. |
225 | a41a1eec | Santi Raffa | |
226 | a41a1eec | Santi Raffa | .. _Snap framework: http://snapframework.com/docs/style-guide |
227 | a41a1eec | Santi Raffa | .. _this style guide: https://github.com/tibbe/haskell-style-guide/blob/master/haskell-style.md |
228 | a41a1eec | Santi Raffa | .. _this other style guide: http://www.cs.caltech.edu/courses/cs11/material/haskell/misc/haskell_style_guide.html |
229 | a41a1eec | Santi Raffa | |
230 | a41a1eec | Santi Raffa | Files |
231 | a41a1eec | Santi Raffa | ~~~~~ |
232 | a41a1eec | Santi Raffa | Use ordinary, non-`literate`_ Haskell ``.hs`` files. |
233 | a41a1eec | Santi Raffa | |
234 | a41a1eec | Santi Raffa | .. _literate: http://www.haskell.org/haskellwiki/Literate_programming |
235 | a41a1eec | Santi Raffa | |
236 | a41a1eec | Santi Raffa | Use proper copyright headers, and proper Haddock style documentation headers:: |
237 | a41a1eec | Santi Raffa | |
238 | a41a1eec | Santi Raffa | {-| Short module summary. |
239 | a41a1eec | Santi Raffa | |
240 | a41a1eec | Santi Raffa | Longer module description. |
241 | a41a1eec | Santi Raffa | |
242 | a41a1eec | Santi Raffa | -} |
243 | a41a1eec | Santi Raffa | |
244 | a41a1eec | Santi Raffa | {- |
245 | a41a1eec | Santi Raffa | |
246 | a41a1eec | Santi Raffa | Copyright (C) ... |
247 | a41a1eec | Santi Raffa | |
248 | a41a1eec | Santi Raffa | This program is free software ... |
249 | a41a1eec | Santi Raffa | |
250 | a41a1eec | Santi Raffa | -} |
251 | a41a1eec | Santi Raffa | |
252 | a41a1eec | Santi Raffa | If there are module-level pragmas add them right at the top, before the short |
253 | a41a1eec | Santi Raffa | summary. |
254 | a41a1eec | Santi Raffa | |
255 | a41a1eec | Santi Raffa | Imports |
256 | a41a1eec | Santi Raffa | ~~~~~~~ |
257 | a41a1eec | Santi Raffa | Imports should be grouped into the following groups and inside each group they |
258 | a41a1eec | Santi Raffa | should be sorted alphabetically: |
259 | a41a1eec | Santi Raffa | |
260 | a41a1eec | Santi Raffa | 1. standard library imports |
261 | a41a1eec | Santi Raffa | 2. third-party imports |
262 | a41a1eec | Santi Raffa | 3. local imports |
263 | a41a1eec | Santi Raffa | |
264 | a41a1eec | Santi Raffa | It is allowed to use qualified imports with short names for: |
265 | a41a1eec | Santi Raffa | |
266 | a41a1eec | Santi Raffa | * standard library (e.g. ``import qualified Data.Map as M``) |
267 | a41a1eec | Santi Raffa | * local imports (e.g. ``import qualified Ganeti.Constants as C``), although |
268 | a41a1eec | Santi Raffa | this form should be kept to a minimum |
269 | a41a1eec | Santi Raffa | |
270 | a41a1eec | Santi Raffa | Indentation |
271 | a41a1eec | Santi Raffa | ~~~~~~~~~~~ |
272 | a41a1eec | Santi Raffa | Use only spaces, never tabs. Indentation level is 2 characters. For Emacs, |
273 | a41a1eec | Santi Raffa | this means setting the variable ``haskell-indent-offset`` to 2. |
274 | a41a1eec | Santi Raffa | |
275 | a41a1eec | Santi Raffa | Line length should be at most 78 chars, and 72 chars inside comments. |
276 | a41a1eec | Santi Raffa | |
277 | a41a1eec | Santi Raffa | Use indentation-based structure, and not braces/semicolons. |
278 | a41a1eec | Santi Raffa | |
279 | a41a1eec | Santi Raffa | .. note:: |
280 | a41a1eec | Santi Raffa | |
281 | a41a1eec | Santi Raffa | Special indendation of if/then/else construct |
282 | a41a1eec | Santi Raffa | |
283 | a41a1eec | Santi Raffa | For the ``do`` notation, the ``if-then-else`` construct has a non-intuitive |
284 | a41a1eec | Santi Raffa | behaviour. As such, the indentation of ``if-then-else`` (both in ``do`` |
285 | a41a1eec | Santi Raffa | blocks and in normal blocks) should be as follows:: |
286 | a41a1eec | Santi Raffa | |
287 | a41a1eec | Santi Raffa | if condition |
288 | a41a1eec | Santi Raffa | then expr1 |
289 | a41a1eec | Santi Raffa | else expr2 |
290 | a41a1eec | Santi Raffa | |
291 | a41a1eec | Santi Raffa | i.e. indent the then/else lines with another level. This can be accomplished |
292 | a41a1eec | Santi Raffa | in Emacs by setting the variable ``haskell-indent-thenelse`` to 2 (from the |
293 | a41a1eec | Santi Raffa | default of zero). |
294 | a41a1eec | Santi Raffa | |
295 | a41a1eec | Santi Raffa | If you have more than one line of code please newline/indent after the "=". Do |
296 | a41a1eec | Santi Raffa | `not` do:: |
297 | a41a1eec | Santi Raffa | |
298 | a41a1eec | Santi Raffa | f x = let y = x + 1 |
299 | a41a1eec | Santi Raffa | in y |
300 | a41a1eec | Santi Raffa | |
301 | a41a1eec | Santi Raffa | Instead do:: |
302 | a41a1eec | Santi Raffa | |
303 | a41a1eec | Santi Raffa | f x = |
304 | a41a1eec | Santi Raffa | let y = x + 1 |
305 | a41a1eec | Santi Raffa | in y |
306 | a41a1eec | Santi Raffa | |
307 | a41a1eec | Santi Raffa | or if it is just one line:: |
308 | a41a1eec | Santi Raffa | |
309 | a41a1eec | Santi Raffa | f x = x + 1 |
310 | a41a1eec | Santi Raffa | |
311 | a41a1eec | Santi Raffa | Multiline strings |
312 | a41a1eec | Santi Raffa | ~~~~~~~~~~~~~~~~~ |
313 | a41a1eec | Santi Raffa | Multiline strings are created by closing a line with a backslash and starting |
314 | a41a1eec | Santi Raffa | the following line with a backslash, keeping the indentation level constant. |
315 | a41a1eec | Santi Raffa | Whitespaces go on the new line, right after the backslash. |
316 | a41a1eec | Santi Raffa | |
317 | a41a1eec | Santi Raffa | :: |
318 | a41a1eec | Santi Raffa | |
319 | a41a1eec | Santi Raffa | longString :: String |
320 | a41a1eec | Santi Raffa | longString = "This is a very very very long string that\ |
321 | a41a1eec | Santi Raffa | \ needs to be split in two lines" |
322 | a41a1eec | Santi Raffa | |
323 | a41a1eec | Santi Raffa | Data declarations |
324 | a41a1eec | Santi Raffa | ~~~~~~~~~~~~~~~~~ |
325 | a41a1eec | Santi Raffa | .. warning:: |
326 | a41a1eec | Santi Raffa | Note that this is different from the Python style! |
327 | a41a1eec | Santi Raffa | |
328 | a41a1eec | Santi Raffa | When declaring either data types, or using list literals, etc., the columns |
329 | a41a1eec | Santi Raffa | should be aligned, and for lists use a comma at the start of the line, not at |
330 | a41a1eec | Santi Raffa | the end. Examples:: |
331 | a41a1eec | Santi Raffa | |
332 | a41a1eec | Santi Raffa | data OpCode = OpStartupInstance ... |
333 | a41a1eec | Santi Raffa | | OpShutdownInstance ... |
334 | a41a1eec | Santi Raffa | | ... |
335 | a41a1eec | Santi Raffa | |
336 | a41a1eec | Santi Raffa | data Node = Node { name :: String |
337 | a41a1eec | Santi Raffa | , ip :: String |
338 | a41a1eec | Santi Raffa | , ... |
339 | a41a1eec | Santi Raffa | } |
340 | a41a1eec | Santi Raffa | |
341 | a41a1eec | Santi Raffa | myList = [ value1 |
342 | a41a1eec | Santi Raffa | , value2 |
343 | a41a1eec | Santi Raffa | , value3 |
344 | a41a1eec | Santi Raffa | ] |
345 | a41a1eec | Santi Raffa | |
346 | a41a1eec | Santi Raffa | The choice of whether to wrap the first element or not is up to you; the |
347 | a41a1eec | Santi Raffa | following is also allowed:: |
348 | a41a1eec | Santi Raffa | |
349 | a41a1eec | Santi Raffa | myList = |
350 | a41a1eec | Santi Raffa | [ value1 |
351 | a41a1eec | Santi Raffa | , value2 |
352 | a41a1eec | Santi Raffa | ] |
353 | a41a1eec | Santi Raffa | |
354 | b10df4de | Klaus Aehlig | For records, always add spaces around the braces and the equality sign. |
355 | b10df4de | Klaus Aehlig | :: |
356 | b10df4de | Klaus Aehlig | |
357 | b10df4de | Klaus Aehlig | foo = Foo { fBar = "bar", fBaz = 4711 } |
358 | b10df4de | Klaus Aehlig | |
359 | b10df4de | Klaus Aehlig | foo' = Foo { fBar = "bar 2" |
360 | b10df4de | Klaus Aehlig | , fBaz = 4712 |
361 | b10df4de | Klaus Aehlig | } |
362 | b10df4de | Klaus Aehlig | |
363 | b10df4de | Klaus Aehlig | node' = node { ip = "127.0.0.1" } |
364 | b10df4de | Klaus Aehlig | |
365 | b10df4de | Klaus Aehlig | |
366 | a41a1eec | Santi Raffa | White space |
367 | a41a1eec | Santi Raffa | ~~~~~~~~~~~ |
368 | a41a1eec | Santi Raffa | Like in Python, surround binary operators with one space on either side. Do no |
369 | a41a1eec | Santi Raffa | insert a space after a lamda:: |
370 | a41a1eec | Santi Raffa | |
371 | a41a1eec | Santi Raffa | -- bad |
372 | a41a1eec | Santi Raffa | map (\ n -> ...) lst |
373 | a41a1eec | Santi Raffa | -- good |
374 | a41a1eec | Santi Raffa | foldl (\x y -> ...) ... |
375 | a41a1eec | Santi Raffa | |
376 | a41a1eec | Santi Raffa | Use a blank line between top-level definitions, but no blank lines between |
377 | a41a1eec | Santi Raffa | either the comment and the type signature or between the type signature and |
378 | a41a1eec | Santi Raffa | the actual function definition. |
379 | a41a1eec | Santi Raffa | |
380 | a41a1eec | Santi Raffa | .. note:: |
381 | a41a1eec | Santi Raffa | Ideally it would be two blank lines between top-level definitions, but the |
382 | a41a1eec | Santi Raffa | code only has one now. |
383 | a41a1eec | Santi Raffa | |
384 | a41a1eec | Santi Raffa | As always, no trailing spaces. Ever. |
385 | a41a1eec | Santi Raffa | |
386 | a41a1eec | Santi Raffa | Spaces after comma |
387 | a41a1eec | Santi Raffa | ****************** |
388 | a41a1eec | Santi Raffa | |
389 | a41a1eec | Santi Raffa | Instead of:: |
390 | a41a1eec | Santi Raffa | |
391 | a41a1eec | Santi Raffa | ("a","b") |
392 | a41a1eec | Santi Raffa | |
393 | a41a1eec | Santi Raffa | write:: |
394 | a41a1eec | Santi Raffa | |
395 | a41a1eec | Santi Raffa | ("a", "b") |
396 | a41a1eec | Santi Raffa | |
397 | a41a1eec | Santi Raffa | Naming |
398 | a41a1eec | Santi Raffa | ~~~~~~ |
399 | a41a1eec | Santi Raffa | Functions should be named in mixedCase style, and types in CamelCase. Function |
400 | a41a1eec | Santi Raffa | arguments and local variables should be mixedCase. |
401 | a41a1eec | Santi Raffa | |
402 | a41a1eec | Santi Raffa | When using acronyms, ones longer than 2 characters should be typed capitalised, |
403 | a41a1eec | Santi Raffa | not fully upper-cased (e.g. ``Http``, not ``HTTP``). |
404 | a41a1eec | Santi Raffa | |
405 | a41a1eec | Santi Raffa | For variable names, use descriptive names; it is only allowed to use very |
406 | a41a1eec | Santi Raffa | short names (e.g. ``a``, ``b``, ``i``, ``j``, etc.) when: |
407 | a41a1eec | Santi Raffa | |
408 | a41a1eec | Santi Raffa | * the function is trivial, e.g.:: |
409 | a41a1eec | Santi Raffa | |
410 | a41a1eec | Santi Raffa | sum x y = x + y |
411 | a41a1eec | Santi Raffa | |
412 | a41a1eec | Santi Raffa | * we talk about some very specific cases, e.g. |
413 | a41a1eec | Santi Raffa | iterators or accumulators in folds:: |
414 | a41a1eec | Santi Raffa | |
415 | a41a1eec | Santi Raffa | map (\v -> v + 1) lst |
416 | a41a1eec | Santi Raffa | |
417 | a41a1eec | Santi Raffa | * using ``x:xs`` for list elements and lists, etc. |
418 | a41a1eec | Santi Raffa | |
419 | a41a1eec | Santi Raffa | In general, short/one-letter names are allowed when we deal with polymorphic |
420 | a41a1eec | Santi Raffa | values; for example the standard map definition from Prelude:: |
421 | a41a1eec | Santi Raffa | |
422 | a41a1eec | Santi Raffa | map :: (a -> b) -> [a] -> [b] |
423 | a41a1eec | Santi Raffa | map _ [] = [] |
424 | a41a1eec | Santi Raffa | map f (x:xs) = f x : map f xs |
425 | a41a1eec | Santi Raffa | |
426 | a41a1eec | Santi Raffa | In this example, neither the ``a`` nor ``b`` types are known to the map |
427 | a41a1eec | Santi Raffa | function, so we cannot give them more explicit names. Since the body of the |
428 | a41a1eec | Santi Raffa | function is trivial, the variables used are longer. |
429 | a41a1eec | Santi Raffa | |
430 | a41a1eec | Santi Raffa | However, if we deal with explicit types or values, their names should be |
431 | a41a1eec | Santi Raffa | descriptive. |
432 | a41a1eec | Santi Raffa | |
433 | a41a1eec | Santi Raffa | .. todo: add a nice example here. |
434 | a41a1eec | Santi Raffa | |
435 | a41a1eec | Santi Raffa | Finally, the naming should look familiar to people who just read the |
436 | a41a1eec | Santi Raffa | Prelude/standard libraries. |
437 | a41a1eec | Santi Raffa | |
438 | a41a1eec | Santi Raffa | Naming for updated values |
439 | a41a1eec | Santi Raffa | ************************* |
440 | a41a1eec | Santi Raffa | |
441 | a41a1eec | Santi Raffa | .. highlight:: python |
442 | a41a1eec | Santi Raffa | |
443 | a41a1eec | Santi Raffa | Since one cannot update a value in Haskell, this presents a particular problem |
444 | a41a1eec | Santi Raffa | on the naming of new versions of the same value. For example, the following |
445 | a41a1eec | Santi Raffa | code in Python:: |
446 | a41a1eec | Santi Raffa | |
447 | a41a1eec | Santi Raffa | def failover(pri, sec, inst): |
448 | a41a1eec | Santi Raffa | pri.removePrimary(inst) |
449 | a41a1eec | Santi Raffa | pri.addSecondary(inst) |
450 | a41a1eec | Santi Raffa | sec.removeSecondary(inst) |
451 | a41a1eec | Santi Raffa | sec.addPrimary(inst) |
452 | a41a1eec | Santi Raffa | |
453 | a41a1eec | Santi Raffa | .. highlight:: haskell |
454 | a41a1eec | Santi Raffa | |
455 | a41a1eec | Santi Raffa | becomes in Haskell something like the following:: |
456 | a41a1eec | Santi Raffa | |
457 | a41a1eec | Santi Raffa | failover pri sec inst = |
458 | a41a1eec | Santi Raffa | let pri' = removePrimary pri inst |
459 | a41a1eec | Santi Raffa | pri'' = addSecondary pri' inst |
460 | a41a1eec | Santi Raffa | sec' = removeSecondary sec inst |
461 | a41a1eec | Santi Raffa | sec'' = addPrimary sec' inst |
462 | a41a1eec | Santi Raffa | in (pri'', sec'') |
463 | a41a1eec | Santi Raffa | |
464 | a41a1eec | Santi Raffa | When updating values, one should add single quotes to the name for up to three |
465 | a41a1eec | Santi Raffa | new names (e.g. ``inst``, ``inst'``, ``inst''``, ``inst'''``) and otherwise |
466 | a41a1eec | Santi Raffa | use numeric suffixes (``inst1``, ``inst2``, ``inst3``, ..., ``inst8``), but |
467 | a41a1eec | Santi Raffa | that many updates is already bad style and thus should be avoided. |
468 | a41a1eec | Santi Raffa | |
469 | a41a1eec | Santi Raffa | Type signatures |
470 | a41a1eec | Santi Raffa | ~~~~~~~~~~~~~~~ |
471 | a41a1eec | Santi Raffa | |
472 | a41a1eec | Santi Raffa | Always declare types for functions (and any other top-level bindings). |
473 | a41a1eec | Santi Raffa | |
474 | a41a1eec | Santi Raffa | If in doubt, feel free to declare the type of the variables/bindings in a |
475 | a41a1eec | Santi Raffa | complex expression; this usually means the expression is too complex, however. |
476 | a41a1eec | Santi Raffa | |
477 | a41a1eec | Santi Raffa | Similarly, provide Haddock-style comments for top-level definitions. |
478 | a41a1eec | Santi Raffa | |
479 | 16b85a3c | Klaus Aehlig | Use sum types instead of exceptions |
480 | 16b85a3c | Klaus Aehlig | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
481 | 16b85a3c | Klaus Aehlig | |
482 | 16b85a3c | Klaus Aehlig | Exceptions make it hard to write functional code, as alternative |
483 | 16b85a3c | Klaus Aehlig | control flows need to be considered and compiler support is limited. |
484 | 16b85a3c | Klaus Aehlig | Therefore, Ganeti functions should never allow exceptions to escape. |
485 | 16b85a3c | Klaus Aehlig | Function that can fail should report failure by returning an appropriate |
486 | 16b85a3c | Klaus Aehlig | sum type (``Either`` or one of its glorified variants like ``Maybe`` or |
487 | 16b85a3c | Klaus Aehlig | ``Result``); the preferred sum type for reporting errors is ``Result``. |
488 | 16b85a3c | Klaus Aehlig | |
489 | 16b85a3c | Klaus Aehlig | As other Ganeti functions also follow these guide lines, they can safely |
490 | 16b85a3c | Klaus Aehlig | be composed. However, be careful when using functions from other libraries; |
491 | 16b85a3c | Klaus Aehlig | if they can raise exceptions, catch them, preferably as close to their |
492 | 16b85a3c | Klaus Aehlig | origin as reasonably possible. |
493 | 16b85a3c | Klaus Aehlig | |
494 | a41a1eec | Santi Raffa | Parentheses, point free style |
495 | a41a1eec | Santi Raffa | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
496 | a41a1eec | Santi Raffa | |
497 | 7bd8ce44 | Petr Pudlak | Prefer the so-called `point-free`_ style style when declaring functions, if |
498 | 7bd8ce44 | Petr Pudlak | applicable:: |
499 | a41a1eec | Santi Raffa | |
500 | a41a1eec | Santi Raffa | -- bad |
501 | 7bd8ce44 | Petr Pudlak | let a x = f (g (h x)) |
502 | 7bd8ce44 | Petr Pudlak | -- good |
503 | 7bd8ce44 | Petr Pudlak | let a = f . g . h |
504 | 7bd8ce44 | Petr Pudlak | |
505 | 7bd8ce44 | Petr Pudlak | Also use function composition in a similar manner in expressions to avoid extra |
506 | 7bd8ce44 | Petr Pudlak | parentheses:: |
507 | 7bd8ce44 | Petr Pudlak | |
508 | 7bd8ce44 | Petr Pudlak | -- bad |
509 | 7bd8ce44 | Petr Pudlak | f (g (h x)) |
510 | a41a1eec | Santi Raffa | -- better |
511 | 7bd8ce44 | Petr Pudlak | f $ g $ h x |
512 | a41a1eec | Santi Raffa | -- best |
513 | 7bd8ce44 | Petr Pudlak | f . g . h $ x |
514 | 7bd8ce44 | Petr Pudlak | |
515 | 7bd8ce44 | Petr Pudlak | .. _`point-free`: http://www.haskell.org/haskellwiki/Pointfree |
516 | a41a1eec | Santi Raffa | |
517 | a41a1eec | Santi Raffa | Language features |
518 | a41a1eec | Santi Raffa | ~~~~~~~~~~~~~~~~~ |
519 | a41a1eec | Santi Raffa | |
520 | a41a1eec | Santi Raffa | Extensions |
521 | a41a1eec | Santi Raffa | ********** |
522 | a41a1eec | Santi Raffa | |
523 | a41a1eec | Santi Raffa | It is recommended to keep the use of extensions to a minimum, so that the code |
524 | a41a1eec | Santi Raffa | can be understood even if one is familiar with just Haskel98/Haskell2010. That |
525 | a41a1eec | Santi Raffa | said, some extensions are very common and useful, so they are recommended: |
526 | a41a1eec | Santi Raffa | |
527 | a41a1eec | Santi Raffa | * `Bang patterns`_: useful when you want to enforce strict evaluation (and better |
528 | a41a1eec | Santi Raffa | than repeated use of ``seq``) |
529 | a41a1eec | Santi Raffa | * CPP: a few modules need this in order to account for configure-time options; |
530 | a41a1eec | Santi Raffa | don't overuse it, since it breaks multi-line strings |
531 | a41a1eec | Santi Raffa | * `Template Haskell`_: we use this for automatically deriving JSON instances and |
532 | a41a1eec | Santi Raffa | other similar boiler-plate |
533 | a41a1eec | Santi Raffa | |
534 | a41a1eec | Santi Raffa | .. _Bang patterns: http://www.haskell.org/ghc/docs/latest/html/users_guide/bang-patterns.html |
535 | a41a1eec | Santi Raffa | .. _Template Haskell: http://www.haskell.org/ghc/docs/latest/html/users_guide/template-haskell.html |
536 | a41a1eec | Santi Raffa | |
537 | a41a1eec | Santi Raffa | Such extensions should be declared using the ``Language`` pragma:: |
538 | a41a1eec | Santi Raffa | |
539 | a41a1eec | Santi Raffa | {-# Language BangPatterns #-} |
540 | a41a1eec | Santi Raffa | |
541 | a41a1eec | Santi Raffa | {-| This is a small module... -} |
542 | a41a1eec | Santi Raffa | |
543 | a41a1eec | Santi Raffa | Comments |
544 | a41a1eec | Santi Raffa | ******** |
545 | a41a1eec | Santi Raffa | |
546 | a41a1eec | Santi Raffa | Always use proper sentences; start with a capital letter and use punctuation |
547 | a41a1eec | Santi Raffa | in top level comments:: |
548 | a41a1eec | Santi Raffa | |
549 | a41a1eec | Santi Raffa | -- | A function that does something. |
550 | a41a1eec | Santi Raffa | f :: ... |
551 | a41a1eec | Santi Raffa | |
552 | a41a1eec | Santi Raffa | For inline comments, start with a capital letter but no ending punctuation. |
553 | a41a1eec | Santi Raffa | Furthermore, align the comments together with a 2-space width from the end of |
554 | a41a1eec | Santi Raffa | the item being commented:: |
555 | a41a1eec | Santi Raffa | |
556 | a41a1eec | Santi Raffa | data Maybe a = Nothing -- ^ Represents empty container |
557 | a41a1eec | Santi Raffa | | Just a -- ^ Represents a single value |
558 | a41a1eec | Santi Raffa | |
559 | a41a1eec | Santi Raffa | The comments should be clear enough so that one doesn't need to look at the |
560 | a41a1eec | Santi Raffa | code to understand what the item does/is. |
561 | a41a1eec | Santi Raffa | |
562 | a41a1eec | Santi Raffa | Use ``-- |`` to write doc strings rather than bare comment with ``--``. |
563 | a41a1eec | Santi Raffa | |
564 | a41a1eec | Santi Raffa | Tools |
565 | a41a1eec | Santi Raffa | ***** |
566 | a41a1eec | Santi Raffa | |
567 | a41a1eec | Santi Raffa | We generate the API documentation via Haddock, and as such the comments should |
568 | a41a1eec | Santi Raffa | be correct (syntax-wise) for it. Use markup, but sparingly. |
569 | a41a1eec | Santi Raffa | |
570 | a41a1eec | Santi Raffa | We use hlint_ as a lint checker; the code is currently lint-clean, so you must |
571 | a41a1eec | Santi Raffa | not add any warnings/errors. |
572 | a41a1eec | Santi Raffa | |
573 | a41a1eec | Santi Raffa | .. _hlint: http://community.haskell.org/~ndm/darcs/hlint/hlint.htm |
574 | a41a1eec | Santi Raffa | |
575 | a41a1eec | Santi Raffa | Use these two commands during development:: |
576 | a41a1eec | Santi Raffa | |
577 | a41a1eec | Santi Raffa | make hs-apidoc |
578 | a41a1eec | Santi Raffa | make hlint |
579 | a41a1eec | Santi Raffa | |
580 | a41a1eec | Santi Raffa | QuickCheck best practices |
581 | a41a1eec | Santi Raffa | ************************* |
582 | a41a1eec | Santi Raffa | |
583 | a41a1eec | Santi Raffa | If you have big type that takes time to generate and several properties to |
584 | a41a1eec | Santi Raffa | test on that, by default 500 of those big instances are generated for each |
585 | a41a1eec | Santi Raffa | property. In many cases, it would be sufficient to only generate those 500 |
586 | a41a1eec | Santi Raffa | instances once and test all properties on those. To do this, create a property |
587 | a41a1eec | Santi Raffa | that uses ``conjoin`` to combine several properties into one. Use |
588 | a41a1eec | Santi Raffa | ``printTestCase`` to add expressive error messages. For example:: |
589 | a41a1eec | Santi Raffa | |
590 | a41a1eec | Santi Raffa | prop_myMegaProp :: myBigType -> Property |
591 | a41a1eec | Santi Raffa | prop_myMegaProp b = |
592 | a41a1eec | Santi Raffa | conjoin |
593 | a41a1eec | Santi Raffa | [ printTestCase |
594 | a41a1eec | Santi Raffa | ("Something failed horribly here: " ++ show b) (subProperty1 b) |
595 | a41a1eec | Santi Raffa | , printTestCase |
596 | a41a1eec | Santi Raffa | ("Something else failed horribly here: " ++ show b) |
597 | a41a1eec | Santi Raffa | (subProperty2 b) |
598 | a41a1eec | Santi Raffa | , -- more properties here ... |
599 | a41a1eec | Santi Raffa | ] |
600 | a41a1eec | Santi Raffa | |
601 | a41a1eec | Santi Raffa | subProperty1 :: myBigType -> Bool |
602 | a41a1eec | Santi Raffa | subProperty1 b = ... |
603 | a41a1eec | Santi Raffa | |
604 | a41a1eec | Santi Raffa | subProperty2 :: myBigType -> Property |
605 | a41a1eec | Santi Raffa | subProperty2 b = ... |
606 | a41a1eec | Santi Raffa | |
607 | a41a1eec | Santi Raffa | ... |
608 | a41a1eec | Santi Raffa | |
609 | a41a1eec | Santi Raffa | Maybe Generation |
610 | a41a1eec | Santi Raffa | '''''''''''''''' |
611 | a41a1eec | Santi Raffa | |
612 | a41a1eec | Santi Raffa | Use ``genMaybe genSomething`` to create ``Maybe`` instances of something |
613 | a41a1eec | Santi Raffa | including some ``Nothing`` instances. |
614 | a41a1eec | Santi Raffa | |
615 | a41a1eec | Santi Raffa | Use ``Just <$> genSomething`` to generate only ``Just`` instances of |
616 | a41a1eec | Santi Raffa | something. |
617 | a41a1eec | Santi Raffa | |
618 | a41a1eec | Santi Raffa | String Generation |
619 | a41a1eec | Santi Raffa | ''''''''''''''''' |
620 | a41a1eec | Santi Raffa | |
621 | a41a1eec | Santi Raffa | To generate strings, consider using ``genName`` instead of ``arbitrary``. |
622 | a41a1eec | Santi Raffa | ``arbitrary`` has the tendency to generate strings that are too long. |