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.