|
| 1 | +.. SPDX-License-Identifier: GPL-2.0 |
| 2 | +
|
| 3 | +bcachefs coding style |
| 4 | +===================== |
| 5 | + |
| 6 | +Good development is like gardening, and codebases are our gardens. Tend to them |
| 7 | +every day; look for little things that are out of place or in need of tidying. |
| 8 | +A little weeding here and there goes a long way; don't wait until things have |
| 9 | +spiraled out of control. |
| 10 | + |
| 11 | +Things don't always have to be perfect - nitpicking often does more harm than |
| 12 | +good. But appreciate beauty when you see it - and let people know. |
| 13 | + |
| 14 | +The code that you are afraid to touch is the code most in need of refactoring. |
| 15 | + |
| 16 | +A little organizing here and there goes a long way. |
| 17 | + |
| 18 | +Put real thought into how you organize things. |
| 19 | + |
| 20 | +Good code is readable code, where the structure is simple and leaves nowhere |
| 21 | +for bugs to hide. |
| 22 | + |
| 23 | +Assertions are one of our most important tools for writing reliable code. If in |
| 24 | +the course of writing a patchset you encounter a condition that shouldn't |
| 25 | +happen (and will have unpredictable or undefined behaviour if it does), or |
| 26 | +you're not sure if it can happen and not sure how to handle it yet - make it a |
| 27 | +BUG_ON(). Don't leave undefined or unspecified behavior lurking in the codebase. |
| 28 | + |
| 29 | +By the time you finish the patchset, you should understand better which |
| 30 | +assertions need to be handled and turned into checks with error paths, and |
| 31 | +which should be logically impossible. Leave the BUG_ON()s in for the ones which |
| 32 | +are logically impossible. (Or, make them debug mode assertions if they're |
| 33 | +expensive - but don't turn everything into a debug mode assertion, so that |
| 34 | +we're not stuck debugging undefined behaviour should it turn out that you were |
| 35 | +wrong). |
| 36 | + |
| 37 | +Assertions are documentation that can't go out of date. Good assertions are |
| 38 | +wonderful. |
| 39 | + |
| 40 | +Good assertions drastically and dramatically reduce the amount of testing |
| 41 | +required to shake out bugs. |
| 42 | + |
| 43 | +Good assertions are based on state, not logic. To write good assertions, you |
| 44 | +have to think about what the invariants on your state are. |
| 45 | + |
| 46 | +Good invariants and assertions will hold everywhere in your codebase. This |
| 47 | +means that you can run them in only a few places in the checked in version, but |
| 48 | +should you need to debug something that caused the assertion to fail, you can |
| 49 | +quickly shotgun them everywhere to find the codepath that broke the invariant. |
| 50 | + |
| 51 | +A good assertion checks something that the compiler could check for us, and |
| 52 | +elide - if we were working in a language with embedded correctness proofs that |
| 53 | +the compiler could check. This is something that exists today, but it'll likely |
| 54 | +still be a few decades before it comes to systems programming languages. But we |
| 55 | +can still incorporate that kind of thinking into our code and document the |
| 56 | +invariants with runtime checks - much like the way people working in |
| 57 | +dynamically typed languages may add type annotations, gradually making their |
| 58 | +code statically typed. |
| 59 | + |
| 60 | +Looking for ways to make your assertions simpler - and higher level - will |
| 61 | +often nudge you towards making the entire system simpler and more robust. |
| 62 | + |
| 63 | +Good code is code where you can poke around and see what it's doing - |
| 64 | +introspection. We can't debug anything if we can't see what's going on. |
| 65 | + |
| 66 | +Whenever we're debugging, and the solution isn't immediately obvious, if the |
| 67 | +issue is that we don't know where the issue is because we can't see what's |
| 68 | +going on - fix that first. |
| 69 | + |
| 70 | +We have the tools to make anything visible at runtime, efficiently - RCU and |
| 71 | +percpu data structures among them. Don't let things stay hidden. |
| 72 | + |
| 73 | +The most important tool for introspection is the humble pretty printer - in |
| 74 | +bcachefs, this means `*_to_text()` functions, which output to printbufs. |
| 75 | + |
| 76 | +Pretty printers are wonderful, because they compose and you can use them |
| 77 | +everywhere. Having functions to print whatever object you're working with will |
| 78 | +make your error messages much easier to write (therefore they will actually |
| 79 | +exist) and much more informative. And they can be used from sysfs/debugfs, as |
| 80 | +well as tracepoints. |
| 81 | + |
| 82 | +Runtime info and debugging tools should come with clear descriptions and |
| 83 | +labels, and good structure - we don't want files with a list of bare integers, |
| 84 | +like in procfs. Part of the job of the debugging tools is to educate users and |
| 85 | +new developers as to how the system works. |
| 86 | + |
| 87 | +Error messages should, whenever possible, tell you everything you need to debug |
| 88 | +the issue. It's worth putting effort into them. |
| 89 | + |
| 90 | +Tracepoints shouldn't be the first thing you reach for. They're an important |
| 91 | +tool, but always look for more immediate ways to make things visible. When we |
| 92 | +have to rely on tracing, we have to know which tracepoints we're looking for, |
| 93 | +and then we have to run the troublesome workload, and then we have to sift |
| 94 | +through logs. This is a lot of steps to go through when a user is hitting |
| 95 | +something, and if it's intermittent it may not even be possible. |
| 96 | + |
| 97 | +The humble counter is an incredibly useful tool. They're cheap and simple to |
| 98 | +use, and many complicated internal operations with lots of things that can |
| 99 | +behave weirdly (anything involving memory reclaim, for example) become |
| 100 | +shockingly easy to debug once you have counters on every distinct codepath. |
| 101 | + |
| 102 | +Persistent counters are even better. |
| 103 | + |
| 104 | +When debugging, try to get the most out of every bug you come across; don't |
| 105 | +rush to fix the initial issue. Look for things that will make related bugs |
| 106 | +easier the next time around - introspection, new assertions, better error |
| 107 | +messages, new debug tools, and do those first. Look for ways to make the system |
| 108 | +better behaved; often one bug will uncover several other bugs through |
| 109 | +downstream effects. |
| 110 | + |
| 111 | +Fix all that first, and then the original bug last - even if that means keeping |
| 112 | +a user waiting. They'll thank you in the long run, and when they understand |
| 113 | +what you're doing you'll be amazed at how patient they're happy to be. Users |
| 114 | +like to help - otherwise they wouldn't be reporting the bug in the first place. |
| 115 | + |
| 116 | +Talk to your users. Don't isolate yourself. |
| 117 | + |
| 118 | +Users notice all sorts of interesting things, and by just talking to them and |
| 119 | +interacting with them you can benefit from their experience. |
| 120 | + |
| 121 | +Spend time doing support and helpdesk stuff. Don't just write code - code isn't |
| 122 | +finished until it's being used trouble free. |
| 123 | + |
| 124 | +This will also motivate you to make your debugging tools as good as possible, |
| 125 | +and perhaps even your documentation, too. Like anything else in life, the more |
| 126 | +time you spend at it the better you'll get, and you the developer are the |
| 127 | +person most able to improve the tools to make debugging quick and easy. |
| 128 | + |
| 129 | +Be wary of how you take on and commit to big projects. Don't let development |
| 130 | +become product-manager focused. Often time an idea is a good one but needs to |
| 131 | +wait for its proper time - but you won't know if it's the proper time for an |
| 132 | +idea until you start writing code. |
| 133 | + |
| 134 | +Expect to throw a lot of things away, or leave them half finished for later. |
| 135 | +Nobody writes all perfect code that all gets shipped, and you'll be much more |
| 136 | +productive in the long run if you notice this early and shift to something |
| 137 | +else. The experience gained and lessons learned will be valuable for all the |
| 138 | +other work you do. |
| 139 | + |
| 140 | +But don't be afraid to tackle projects that require significant rework of |
| 141 | +existing code. Sometimes these can be the best projects, because they can lead |
| 142 | +us to make existing code more general, more flexible, more multipurpose and |
| 143 | +perhaps more robust. Just don't hesitate to abandon the idea if it looks like |
| 144 | +it's going to make a mess of things. |
| 145 | + |
| 146 | +Complicated features can often be done as a series of refactorings, with the |
| 147 | +final change that actually implements the feature as a quite small patch at the |
| 148 | +end. It's wonderful when this happens, especially when those refactorings are |
| 149 | +things that improve the codebase in their own right. When that happens there's |
| 150 | +much less risk of wasted effort if the feature you were going for doesn't work |
| 151 | +out. |
| 152 | + |
| 153 | +Always strive to work incrementally. Always strive to turn the big projects |
| 154 | +into little bite sized projects that can prove their own merits. |
| 155 | + |
| 156 | +Instead of always tackling those big projects, look for little things that |
| 157 | +will be useful, and make the big projects easier. |
| 158 | + |
| 159 | +The question of what's likely to be useful is where junior developers most |
| 160 | +often go astray - doing something because it seems like it'll be useful often |
| 161 | +leads to overengineering. Knowing what's useful comes from many years of |
| 162 | +experience, or talking with people who have that experience - or from simply |
| 163 | +reading lots of code and looking for common patterns and issues. Don't be |
| 164 | +afraid to throw things away and do something simpler. |
| 165 | + |
| 166 | +Talk about your ideas with your fellow developers; often times the best things |
| 167 | +come from relaxed conversations where people aren't afraid to say "what if?". |
| 168 | + |
| 169 | +Don't neglect your tools. |
| 170 | + |
| 171 | +The most important tools (besides the compiler and our text editor) are the |
| 172 | +tools we use for testing. The shortest possible edit/test/debug cycle is |
| 173 | +essential for working productively. We learn, gain experience, and discover the |
| 174 | +errors in our thinking by running our code and seeing what happens. If your |
| 175 | +time is being wasted because your tools are bad or too slow - don't accept it, |
| 176 | +fix it. |
| 177 | + |
| 178 | +Put effort into your documentation, commmit messages, and code comments - but |
| 179 | +don't go overboard. A good commit message is wonderful - but if the information |
| 180 | +was important enough to go in a commit message, ask yourself if it would be |
| 181 | +even better as a code comment. |
| 182 | + |
| 183 | +A good code comment is wonderful, but even better is the comment that didn't |
| 184 | +need to exist because the code was so straightforward as to be obvious; |
| 185 | +organized into small clean and tidy modules, with clear and descriptive names |
| 186 | +for functions and variable, where every line of code has a clear purpose. |
0 commit comments