[Notes] [Git][BuildStream/buildstream][master] 4 commits: CONTRIBUTING.rst: Added section about minimizing API surfaces



Title: GitLab

Tristan Van Berkom pushed to branch master at BuildStream / buildstream

Commits:

1 changed file:

Changes:

  • CONTRIBUTING.rst
    ... ... @@ -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
    



  • [Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]