sigs.k8s.io/kubebuilder/v3@v3.14.0/DESIGN.md (about)

     1  # Kubebuilder Design Principles
     2  
     3  This lays out some of the guiding design principles behind the Kubebuilder
     4  project and its various components.
     5  
     6  ## Overarching
     7  
     8  * **Libraries Over Code Generation**: Generated code is messy to maintain,
     9    hard for humans to change and understand, and hard to update.  Library
    10    code is easy to update (just increase your dependency version), easier
    11    to version using existing mechanisms, and more concise.
    12  
    13  * **Copy-pasting is bad**: Copy-pasted code suffers from similar problems
    14    as code generation, except more acutely.  Copy-pasted code is nearly
    15    impossible to easy update, and frequently suffers from bugs and
    16    misunderstandings.  If something is being copy-pasted, it should
    17    refactored into a library component or remote
    18    [kustomize](https://sigs.k8s.io/kustomize) base.
    19  
    20  * **Common Cases Should Be Easy**: The 80-90% common cases should be
    21    simple and easy for users to understand.
    22  
    23  * **Uncommon Cases Should Be Possible**: There shouldn't be situations
    24    where it's downright impossible to do something within
    25    controller-runtime or controller-tools. It may take extra digging or
    26    coding, and it may involve interoperating with lower-level components,
    27    but it should be possible without unreasonable friction.
    28  
    29  ## Kubebuilder
    30  
    31  * **Kubebuilder Has Opinions**: Kubebuilder exists as an opinionated
    32    project generator.  It should strive to give users a reasonable project
    33    layout that's simple enough to understand when getting started, but
    34    provides room to grow.  It might not match everyone's opinions, but it
    35    should strive to be useful to most.
    36  
    37  * **Batteries Included**: Kubebuilder projects should contain enough
    38    deployment information to reasonably develop and run the scaffolded
    39    project.  This includes testing, deployment files, and development
    40    infrastructure to go from code to running containers.
    41  
    42  ## controller-tools and controller-runtime
    43  
    44  * **Sufficient But Composable**: controller-tools and controller-runtime
    45    should be sufficient for building a custom controller by hand.  While
    46    scaffolding and additional libraries may make life easier, building
    47    without should be as painless as possible.  That being said, they should
    48    strive to be usable as building blocks for higher-level libraries as
    49    well.
    50  
    51  * **Self-Sufficient Docs**: controller-tools and controller-runtime should
    52    strive to have self-sufficient docs (i.e. documentation that doesn't
    53    require reading other libraries' documentation for common use cases).
    54    Examples should be plentiful.
    55  
    56  * **Contained Arcana**: Developers should not need to be experts in
    57    Kubernetes API machinery to develop controllers, but those familiar with
    58    Kubernetes API machinery should not feel out of place.  Abstractions
    59    should be intuitive to new users but feel familiar to experienced ones.
    60    Abstractions should embrace the concepts of Kubernetes (e.g. declarative
    61    idempotent reconcilers) while simplifying the details.
    62  
    63  ## controller-runtime
    64  
    65  * **Abstractions Should Be Layered**: Abstractions should be built on top
    66    of lower layers, such that advanced users can write custom logic while
    67    still working within the existing model.  For instance, the controller
    68    builder is built on top of the event, source, and handler helpers, which
    69    are in turn built for use with the event, source, and handler
    70    interfaces.
    71  
    72  * **Repetitive Stress Injuries Are Bad**:
    73    When possible, commonly used pieces should be exposed in a way that
    74    enables clear, concise code.  This includes aliasing groups of
    75    functionality under "alias" or "prelude" packages to avoid having 40
    76    lines of imports, including common idioms as flexible helpers, and
    77    infering resource information from the user's object types in client
    78    code.
    79  
    80  * **A Little Bit of Magic Goes a Long Way**: In absence of generics,
    81    reflection is acceptable, especially when it leads to clearer, conciser
    82    code.  However, when possible interfaces that use reflection should be
    83    designed to avoid requiring the end-developer to use type assertions,
    84    string splitting, which are error-prone and repetitive.  These should be
    85    dealt with inside controller-runtime internals.
    86  
    87  * **Defaults Over Constructors**: When not a huge performance impact,
    88    favor auto-defaulting and `Options` structs over constructors.
    89    Constructors quickly become unclear due to lack of names associated
    90    with values, and don't work well with optional values.
    91  
    92  ## Development
    93  
    94  * **Words Are Better Than Letters**: Don't abbreviate variable names
    95    unless it's blindingly obvious what they are (e.g. `ctx` for `Context`).
    96    Single- and double-letter method receivers are acceptable, but single-
    97    and double-letter variables quickly become confusing the longer a code
    98    block gets.
    99  
   100  * **Well-commented code**: Code should be commented and given Godocs, even
   101    private methods and functions. It may *seem* obvious what they do at the
   102    time and why, but you might forget, and others will certainly come along.
   103  
   104  * **Test Behaviors**: Test cases should be comprehensible as sets of
   105    expected behaviors.  Test cases read without code (e.g. just using `It`,
   106    `Describe`, `Context`, and `By` lines) should still be able to explain
   107    what's required of the tested interface. Testing behaviors makes
   108    internal refactors easier, and makes reading tests easier.
   109  
   110  * **Real Components Over Mocks**: Avoid mocks and recording actions. Mocks
   111    tend to be brittle and gradually become more complicated over time (e.g.
   112    fake client implementations tend to grow into poorly-written, incomplete
   113    API servers).  Recording of actions tends to lead to brittle tests that
   114    requires changes during refactors.  Instead, test that the end desired
   115    state is correct.  Test the way the world should be, without caring how
   116    it got there, and provide easy ways to set up the real components so
   117    that mocks aren't required.