| ... | ... | @@ -496,7 +496,7 @@ outline the exceptions to the rules discussed here. | 
| 496 | 496 |  
 | 
| 497 | 497 |  .. _contributing_public_api_surface:
 | 
| 498 | 498 |  
 | 
| 499 |  | -Public API Surface
 | 
|  | 499 | +Public API surface
 | 
| 500 | 500 |  ~~~~~~~~~~~~~~~~~~
 | 
| 501 | 501 |  BuildStream exposes what we call a *"Public API Surface"* which is stable
 | 
| 502 | 502 |  and unchanging. This is for the sake of stability of the interfaces which
 | 
| ... | ... | @@ -546,6 +546,28 @@ prefixed with a single underscore, and are not imported in BuildStream's the mas | 
| 546 | 546 |  
 | 
| 547 | 547 |     In this case, the *"API Private"* functions are prefixed with a single underscore.
 | 
| 548 | 548 |  
 | 
|  | 549 | +Any objects which are a part of the *"Public API Surface"* should be exposed via the
 | 
|  | 550 | +toplevel ``__init__.py`` of the ``buildstream`` package.
 | 
|  | 551 | +
 | 
|  | 552 | +
 | 
|  | 553 | +File naming convention
 | 
|  | 554 | +~~~~~~~~~~~~~~~~~~~~~~
 | 
|  | 555 | +With the exception of a few helper objects and data structures, we structure
 | 
|  | 556 | +the code in BuildStream such that every filename is named after the object it
 | 
|  | 557 | +implements. E.g. The ``Project`` object is implemented in ``_project.py``, the
 | 
|  | 558 | +``Context`` object in ``_context.py``, the base ``Element`` class in ``element.py``,
 | 
|  | 559 | +etc.
 | 
|  | 560 | +
 | 
|  | 561 | +As mentioned in the previous section, objects which are not a part of the
 | 
|  | 562 | +:ref:`public, plugin facing API surface <contributing_public_api_surface>` have their
 | 
|  | 563 | +filenames prefixed with a leading underscore (like ``_context.py`` and ``_project.py``
 | 
|  | 564 | +in the examples above).
 | 
|  | 565 | +
 | 
|  | 566 | +When an object name has multiple words in it, e.g. ``ArtifactCache``, then the
 | 
|  | 567 | +resulting file is named all in lower case without any underscore to separate
 | 
|  | 568 | +words. In the case of ``ArtifactCache``, the filename implementing this object
 | 
|  | 569 | +is found at ``_artifactcache/artifactcache.py``.
 | 
|  | 570 | +
 | 
| 549 | 571 |  
 | 
| 550 | 572 |  Imports
 | 
| 551 | 573 |  ~~~~~~~
 | 
| ... | ... | @@ -553,11 +575,11 @@ Module imports inside BuildStream are done with relative ``.`` notation | 
| 553 | 575 |  
 | 
| 554 | 576 |  **Good**::
 | 
| 555 | 577 |  
 | 
| 556 |  | -  from .context import Context
 | 
|  | 578 | +  from ._context import Context
 | 
| 557 | 579 |  
 | 
| 558 | 580 |  **Bad**::
 | 
| 559 | 581 |  
 | 
| 560 |  | -  from buildstream.context import Context
 | 
|  | 582 | +  from buildstream._context import Context
 | 
| 561 | 583 |  
 | 
| 562 | 584 |  The exception to the above rule is when authoring plugins,
 | 
| 563 | 585 |  plugins do not reside in the same namespace so they must
 | 
| ... | ... | @@ -576,7 +598,9 @@ This makes things clear when reading code that said functions | 
| 576 | 598 |  are not defined in the same file but come from utils.py for example.
 | 
| 577 | 599 |  
 | 
| 578 | 600 |  
 | 
| 579 |  | -Instance Variables
 | 
|  | 601 | +.. _contributing_instance_variables:
 | 
|  | 602 | +
 | 
|  | 603 | +Instance variables
 | 
| 580 | 604 |  ~~~~~~~~~~~~~~~~~~
 | 
| 581 | 605 |  It is preferred that all instance state variables be declared as :ref:`private symbols
 | 
| 582 | 606 |  <contributing_public_and_private>`, however in some cases, especially when the state
 | 
| ... | ... | @@ -607,7 +631,7 @@ variable. | 
| 607 | 631 |  
 | 
| 608 | 632 |  .. _contributing_accessor_mutator:
 | 
| 609 | 633 |  
 | 
| 610 |  | -Accessors and Mutators
 | 
|  | 634 | +Accessors and mutators
 | 
| 611 | 635 |  ~~~~~~~~~~~~~~~~~~~~~~
 | 
| 612 | 636 |  An accessor and mutator, are methods defined on the object class to access (get)
 | 
| 613 | 637 |  or mutate (set) a value owned by the declaring class, respectively.
 | 
| ... | ... | @@ -667,7 +691,7 @@ respectively, e.g.:: | 
| 667 | 691 |  
 | 
| 668 | 692 |  .. _contributing_abstract_methods:
 | 
| 669 | 693 |  
 | 
| 670 |  | -Abstract Methods
 | 
|  | 694 | +Abstract methods
 | 
| 671 | 695 |  ~~~~~~~~~~~~~~~~
 | 
| 672 | 696 |  In BuildStream, an *"Abstract Method"* is a bit of a misnomer and does
 | 
| 673 | 697 |  not match up to how Python defines abstract methods, we need to seek out
 | 
| ... | ... | @@ -695,7 +719,7 @@ to do so, and outlined the API contract for this purpose. No surprises | 
| 695 | 719 |  are allowed.
 | 
| 696 | 720 |  
 | 
| 697 | 721 |  
 | 
| 698 |  | -Error Handling
 | 
|  | 722 | +Error handling
 | 
| 699 | 723 |  ~~~~~~~~~~~~~~
 | 
| 700 | 724 |  In BuildStream, all non recoverable errors are expressed via
 | 
| 701 | 725 |  subclasses of the ``BstError`` exception.
 | 
| ... | ... | @@ -704,7 +728,7 @@ This exception is handled deep in the core in a few places, and | 
| 704 | 728 |  it is rarely necessary to handle a ``BstError``.
 | 
| 705 | 729 |  
 | 
| 706 | 730 |  
 | 
| 707 |  | -Raising Exceptions
 | 
|  | 731 | +Raising exceptions
 | 
| 708 | 732 |  ''''''''''''''''''
 | 
| 709 | 733 |  When writing code in the BuildStream core, ensure that all system
 | 
| 710 | 734 |  calls and third party library calls are wrapped in a ``try:`` block,
 | 
| ... | ... | @@ -721,7 +745,7 @@ original call trace, example:: | 
| 721 | 745 |        raise ArtifactError("Attempt to access unavailable artifact: {}".format(e)) from e
 | 
| 722 | 746 |  
 | 
| 723 | 747 |  
 | 
| 724 |  | -Enhancing Exceptions
 | 
|  | 748 | +Enhancing exceptions
 | 
| 725 | 749 |  ''''''''''''''''''''
 | 
| 726 | 750 |  Sometimes the ``BstError`` originates from a lower level component,
 | 
| 727 | 751 |  and the code segment which raised the exception did not have enough context
 | 
| ... | ... | @@ -913,7 +937,7 @@ if the developer does not take special care of ensuring this does not | 
| 913 | 937 |  happen.
 | 
| 914 | 938 |  
 | 
| 915 | 939 |  
 | 
| 916 |  | -Use less arguments in methods
 | 
|  | 940 | +Minimize arguments in methods
 | 
| 917 | 941 |  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
| 918 | 942 |  When creating an object, or adding a new API method to an existing
 | 
| 919 | 943 |  object, always strive to keep as much context as possible on the
 | 
| ... | ... | @@ -926,6 +950,48 @@ that value or object should be passed in the constructor instead of | 
| 926 | 950 |  via a method call.
 | 
| 927 | 951 |  
 | 
| 928 | 952 |  
 | 
|  | 953 | +Minimize API surfaces
 | 
|  | 954 | +~~~~~~~~~~~~~~~~~~~~~
 | 
|  | 955 | +When creating an object, or adding new functionality in any way,
 | 
|  | 956 | +try to keep the number of :ref:`public, outward facing <contributing_public_and_private>`
 | 
|  | 957 | +symbols to a minimum, this is important for both
 | 
|  | 958 | +:ref:`internal and public, plugin facing API surfaces <contributing_public_api_surface>`.
 | 
|  | 959 | +
 | 
|  | 960 | +When anyone visits a file, there are two levels of comprehension:
 | 
|  | 961 | +
 | 
|  | 962 | +* What do I need to know in order to *use* this object
 | 
|  | 963 | +
 | 
|  | 964 | +* What do I need to know in order to *modify* this object
 | 
|  | 965 | +
 | 
|  | 966 | +For the former, we want the reader to understand with as little effort
 | 
|  | 967 | +as possible, what the public API contract is for a given object and consequently,
 | 
|  | 968 | +how it is expected to be used. This is also why we
 | 
|  | 969 | +:ref:`order the symbols of a class <contributing_class_order>` in such a way
 | 
|  | 970 | +as to keep all outward facing public API surfaces at the top of the file, so that the
 | 
|  | 971 | +reader never needs to dig deep into the bottom of the file to find something they
 | 
|  | 972 | +might need to use.
 | 
|  | 973 | +
 | 
|  | 974 | +For the latter, when it comes to having to modify the file or add functionality,
 | 
|  | 975 | +you want to retain as much freedom as possible to modify internals, while
 | 
|  | 976 | +being sure that nothing external will be affected by internal modifications.
 | 
|  | 977 | +Less client facing API means that you have less surrounding code to modify
 | 
|  | 978 | +when your API changes. Further, ensuring that there is minimal outward facing
 | 
|  | 979 | +API for any module minimizes the complexity for the developer working on
 | 
|  | 980 | +that module, by limiting the considerations needed regarding external side
 | 
|  | 981 | +effects of their modifications to the module.
 | 
|  | 982 | +
 | 
|  | 983 | +When modifying a file, one should not have to understand or think too
 | 
|  | 984 | +much about external side effects, when the API surface of the file is
 | 
|  | 985 | +well documented and minimal.
 | 
|  | 986 | +
 | 
|  | 987 | +When adding new API to a given object for a new purpose, consider whether
 | 
|  | 988 | +the new API is in any way redundant with other API (should this value now
 | 
|  | 989 | +go into the constructor, since we use it more than once ? could this
 | 
|  | 990 | +value be passed along with another function, and the other function renamed,
 | 
|  | 991 | +to better suit the new purposes of this module/object ?) and repurpose
 | 
|  | 992 | +the outward facing API of an object as a whole every time.
 | 
|  | 993 | +
 | 
|  | 994 | +
 | 
| 929 | 995 |  Avoid transient state on instances
 | 
| 930 | 996 |  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
| 931 | 997 |  At times, it can be tempting to store transient state that is
 |