Changes between Initial Version and Version 1 of DevNotes/DevGuide/CodingRules


Ignore:
Timestamp:
May 27, 2016 5:17:26 PM (8 years ago)
Author:
wojciech
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • DevNotes/DevGuide/CodingRules

    v1 v1  
     1Sasview Coding Rules 
     2 
     3The coding rules are based on few already existing rules of SasView and other programs available from SINE2020 project (primarily Mantid http://www.mantidproject.org/Coding_Standards). The idea is to implement the coding rules at ESS and then potentially suggest the guideline for future developers within SASView community. 
     4 
     5The following document is divided into subsections (Some of these needs to be written) 
     6 
     7* Golden Rule 
     8     
     9* Coding Standards 
     10        * Docstring 
     11        * Naming 
     12        * Imports 
     13        * Exception Handling 
     14        * Coding Style 
     15 
     16* Testing 
     17 
     18* GIT 
     19 
     20* Code reviews 
     21 
     22* Code Editors (Not sure if we want to include it) 
     23 
     24* GUI guidelines (to be included in the future) 
     25 
     26* API interface (to be included in the future) 
     27 
     28Golden Rule: 
     29 
     30    The committed code should NEVER break the build. 
     31    If you do break the build - the #1 priority is to fix it IMMEDIATELY. 
     32 
     33Coding Standards 
     34Docstring 
     35 
     36When in doubt, the best is to follow PEP 257 (https://www.python.org/dev/peps/pep-0257/). A few rules that are particularly recommended to follow are mentioned below: 
     37 
     38    All modules should normally have docstrings, and all functions and classes exported by a module should also have docstrings. 
     39    For consistency, always use """triple double quotes""" around docstrings. Use r"""raw triple double quotes""" if you use any backslashes in your docstrings. 
     40    There are two forms of docstrings: one-liners and multi-line docstrings. One-liners are for really obvious cases. They should really fit on one line. 
     41    Multi-line docstrings consist of a summary line just like a one-line docstring, followed by a blank line, followed by a more elaborate description. 
     42    The docstring for a module should generally list the classes, exceptions and functions (and any other objects) that are exported by the module, with a one-line summary of each. (These summaries generally give less detail than the summary line in the object's docstring.) The docstring for a package (i.e., the docstring of the package's __init__.py module) should also list the modules and subpackages exported by the package. 
     43    The docstring for a function or method should summarize its behavior and document its arguments, return value(s), side effects, exceptions raised, and restrictions on when it can be called (all if applicable). Optional arguments should be indicated. It should be documented whether keyword arguments are part of the interface. 
     44    The docstring for a class should summarize its behavior and list the public methods and instance variables. If the class is intended to be subclassed, and has an additional interface for subclasses, this interface should be listed separately (in the docstring). The class constructor should be documented in the docstring for its __init__ method. Individual methods should be documented by their own docstring. 
     45      
     46      
     47    Models: when adding a new model the .py file starts with an r (for raw) and three sets of quotes to start the doc string and ends with a second set of 3 quotes. 
     48    Models: wherever possible, try to use images of math functions with Latex equivalents. You can use the live demo Mathjax page ( http://www.mathjax.org/) to make sure the equation looks as expected. Also a lot of the Latex code can be taken from (or edited) from the PDF document created by Paul Kienzle:  http://sasview.org/attachment/wiki/SasModels%20Work%20Package/Equations.docx.pdf. 
     49    Models: don't add/remove the table of parameters which will get autogenerated. 
     50    Models: add non-math figures to the sasmodels/sasmodels/models/img subdirectory and rename them to something sensible. 
     51    Models: figure captions should be indented relative to the ..image:: tag. This allows us to, for example, change the font of the caption through CSS. 
     52    Models: don't add the figure number since this will be generated automatically. 
     53    Models: make sure all references to model parameters are appropriately named, and that the relationship between equation variables and model parameters are obvious. 
     54 
     55Naming 
     56 
     57    Use CamelCase for class names 
     58    Use box_car with underscores separating words for variable and method names. 
     59    Use box_car with underscores for namespaces & directories 
     60    Use _box_car with a leading underscore for non-public methods and _CamelCase with a leading underscore for non-public classes. 
     61    Never use __box_car__ with leading and trailing double underscores 
     62    Avoid one-letter variable names. 
     63 
     64    Models: for adding a new model no capitalization and thus no CamelCase in model names. If necessary use underscore to separate (i.e. barbell not BarBell or broad_peak not BroadPeak) 
     65    Models: Don't add/Remove “model” in/from the name (i.e. barbell not BarBellModel) 
     66    Models: When defining parameters use radius_core, sld_core names not core_radius and core_sld 
     67 
     68Imports 
     69 
     70    Import only one module per line: 
     71    import sascalc 
     72    import sasmodels 
     73    not 
     74    import sasmodels, sascalc 
     75    It is OK to import multiple classes and/or methods from the same module on the same line: 
     76    from sasmodels import barbell, cylinder 
     77    Avoid importing * from any module. This is a typically a waste of time and memory. 
     78 
     79    Imports should be grouped in the following order: 
     80        standard library imports 
     81        related third party imports 
     82        local application/library specific imports 
     83    Put a blank line between each group of imports. 
     84 
     85Exception Handling 
     86 
     87    Use if and try/except block to test for errors that could happen in normal program operation 
     88 
     89    If you catch an exception and all you do is calling pass or print, you have not dealt with the error properly 
     90    Exceptions should not be used for flow control, unless there is a very good reason for it 
     91    Error codes from a method should never be returned - use exceptions 
     92 
     93Coding Style 
     94 
     95When in doubt - follow PEP 8 (https://www.python.org/dev/peps/pep-0008/) 
     96Indentation 
     97 
     98    Use 4 spaces to indent, not tabs. 
     99    Indent 4 spaces per nested level. 
     100 
     101Spaces in Expressions & Statements 
     102 
     103    Do not put spaces around parentheses, brackets, or curly braces. 
     104    Do not put spaces before commas, colons, or semicolons. 
     105    Put one space around operators. 
     106    However one can use no spaces with operators of higher priority, e.g., y = a*x**2 + b*x + c. 
     107 
     108Miscellaneous 
     109 
     110    Limit lines to a maximum of 79 characters. 
     111    Do not put semicolons at the end of lines. 
     112    Avoid using magic numbers 
     113    Use: 
     114         max_bins = 7 
     115         if i < max_bins: 
     116    Not: 
     117        if i < 7 
     118 
     119Comments in the code 
     120 
     121    Comments should usually be complete sentences. 
     122    Use block comments to talk about the code immediately following the comments. 
     123    Use inline comments (sparingly) to clarify confusing lines. 
     124 
     125Testing 
     126 
     127    Unit tests should test one method only. This allows you to easily identify what failed if the test fails. 
     128    Unit tests should not be coupled together, therefore one unit test CANNOT rely on another unit test having completed first. 
     129    Unit tests should use small and simple data sets. 
     130    Tests should be fast, ideally really fast - certainly not more than a few seconds. 
     131    Untestable code is a code-smell, if you can't get the code under test it probably needs refactoring. 
     132    Weight your testing to be destructive rather than demonstrative. Destructive tests are more efficient in finding bugs. 
     133    Use long and descriptive names for testing functions. The reason is testing functions are never called explicitly. square() or even sqr() is ok in running code, but in testing code you would have names such as test_square_of_number_2(),test_square_negative_number(). These function names are displayed when a test fails, and should be as descriptive as possible. 
     134    Attributes of a good test: Fast, Clear, Isolated, Reliable 
     135      
     136    Models: Include at least one test for each model and PLEASE make sure that the answer value is correct (i.e. not a random number). 
     137    Models: Remember to test a model for critical values (e.g. q=0) 
     138 
     139GIT 
     140 
     141    Remember to add files using git add before committing your changes. 
     142    Have a self-explanatory commit message. "Merged with master" is not sufficient. It is a good practice to do a git log before pushing to master and check for the top message. git commit --amend can be used to fix commit message if we are not satisfied with it.   
     143    Using git branches is encouraged when developing new features or implementing significant changes. It is also a good habit to regularly merge you branch with master as well as push it Github (as a backup). 
     144    When merging a branch with multiple commits use --squash or interactively rebase before pushing to master. 
     145 
     146Code Reviews 
     147 
     148    Code reviews by another developer are encouraged for minor functionality and required for major changes 
     149    When developing in the branch it is easy to ask for pull requests. One can also test your code easily by pulling your branch and not messing up with master branch 
     150    Follow the standard practices: 
     151        Review no more than 400 lines of code at a time 
     152        Take your time. Inspection rates should be under 500 LOC per hour 
     153        Don't review code for more than 90 minutes at a time 
     154        Authors should annotate source code before the review. (Annotations guide the reviewer through the changes, showing which files to look at first and defending the reason behind each code modification. Annotations should be directed at other reviewers to ease the process and provide more depth in context) 
     155        Use checklists - they substantially improve results for both authors and reviewers (It's very likely that each person on your team makes the same 10 mistakes over and over. Omissions in particular are the hardest defects to find because it's difficult to review something that isn't there. Checklists are the most effective way to eliminate frequently made errors and to combat the challenges of omission finding) 
     156        Remember to review related unit tests - they are as important as the code. 
     157        Verify that the defects are actually fixed 
     158 
     159Editors 
     160 
     161Tips and tricks of how to make your life easier when developing code with your favorite editor. 
     162 
     163Example editors used in the group are: 
     164 
     165    vi 
     166    PyCharm 
     167    Visual Studio with PTVS 
     168 
     169Both PyCharm and VS allow source level debugging both of self-spawned processes and by attaching to an already running process. 
     170API 
     171 
     172The proposed access to the core functionality should be consistent for all perspectives and straightforward to use. 
     173 
     174    All known input arguments should be set in __init__, during instantiation, with proper checks 
     175    Additional input data can be set directly through the @property decorator 
     176 
     177        Getters: 
     178         @property 
     179               def intensity(self): 
     180                     return self.wave.intensity 
     181 
     182          
     183 
     184        Setters: 
     185          @intensity.setter 
     186               def intensity(self, value): 
     187                    self.wave.set_intensity(intensity) 
     188    All user accessible input/output data should be available through getters 
     189     __getattr__ and __setattr__ should be avoided. 
     190    Main functionality should be exposed as a method with easy to understand name, e.g. calculate() and should return the results object/structure 
     191    When defining the interface, type hints are an important part of the definition. Type hints are described in PEP-484 https://www.python.org/dev/peps/pep-0484 and should be added for all API methods. 
     192 
     193    def fit(self, msg_q=None, q=None, handler=None, curr_thread=None, ftol=1.49012e-8, reset_flag=False): 
     194           # type: (CalcThread.queue, CalcThread.queue, FitHandler, CalcThread, float, bool) -> Union[CalcThread.queue, FResult] 
     195 
     196 
     197    In cases where several pieces of information are calculated at the same time, a list of outputs, a dictionary, or an output object that contains the computed data should be returned 
     198    Error codes from a method should never be returned - use exceptions