paritybit.ca

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit ccc428acff52af5ae49c20f076950adcafe33945
parent 8564bc206b2f80af1ab6e21990acf4d5060efae8
Author: Jake Bauer <jbauer@paritybit.ca>
Date:   Fri, 24 Feb 2023 16:17:05 -0500

*

Diffstat:
Mcontent/garden/arboretum/book-wishlist.md | 1+
Mcontent/garden/arboretum/index.md | 10+++++++---
Acontent/garden/arboretum/kitchen-equipment.md | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontent/garden/arboretum/programming-style.md | 558+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rcontent/garden/arboretum/finished-list.md -> content/garden/arboretum/reading-list.md | 0
Dcontent/garden/arboretum/style.md | 12------------
6 files changed, 638 insertions(+), 15 deletions(-)

diff --git a/content/garden/arboretum/book-wishlist.md b/content/garden/arboretum/book-wishlist.md @@ -8,6 +8,7 @@ Summary: Book Wishlist A list of books I am considering acquiring. I do not necessarily aim to get every book on this list. +* _The Elements of Programming Style_ by Kernighan and Plauger * _Extraordinary Popular Delusions and the Madness of Crowds_ by Charles Mackay * _The Wisdom of Crowds: Why the Many Are Smarter Than the Few and How Collective Wisdom Shapes Business, Economies, Societies and Nations_ by James Surowiecki * _Introduction to Programming Languages_ by Arvind Kumar Bansal diff --git a/content/garden/arboretum/index.md b/content/garden/arboretum/index.md @@ -34,8 +34,8 @@ The Arboretum is the place for long-lived concepts. Here you can find my opinion ## 📚 Books -* [List of books I want](book-wishlist.html) -* [Books I've finished](finished-list.html). +* [Wishlist](book-wishlist.html) +* [Reading List](reading-list.html). Notes on: @@ -74,7 +74,11 @@ I have categorized my opinions to make them easier to find: ## 💾 Programming -* General: [Style](style.html), [General Programming Tips and Advice](general-programming-tips-advice.html), [Programming Philosophy](programming-philosophy.html), [Bad Assumptions Made By User/Profile Systems](user-profile-systems-bad-assumptions.html) +* General: + * [Some Notes on Programming Style and Composition](programming-style.html) + * [General Programming Tips and Advice](general-programming-tips-advice.html) + * [Programming Philosophy](programming-philosophy.html) + * [Bad Assumptions Made By User/Profile Systems](user-profile-systems-bad-assumptions.html) * Programming languages: [C](c.html), [Raku](raku.html), [LaTeX](latex.html) * Tools: [git](git.html), [Vim](vim.html) diff --git a/content/garden/arboretum/kitchen-equipment.md b/content/garden/arboretum/kitchen-equipment.md @@ -0,0 +1,72 @@ +Title: Kitchen Equipment +Summary: Kitchen Equipment + +# [%title] + +What I consider to be essential kitchen equipment. A good shopping list for +either determining what to get when you've moved or what to keep when you're +downsizing. + +Much like Alton Brown, I despise single-purpose kitchen gadgets that are only +designed to waste your money and your time. I try to buy things that are +durable, easily recyclable or compostable, and versatile. + +These are the things I consider essential: + +* [Knife](#knife) (cai dao) +* [Cutting Board](#cutting-board) (wood, any size) +* Mortar and Pestle (large, granite, rough inside) +* Scissors (simple, japanese nigiri are good) +* Peeler (Y-shaped) +* Cast Iron Skillet (with pouring spouts and comfortable handle) +* Cast Iron Dutch Oven (at least 5qt) +* Baking Sheet +* Prep Bowls (one large, one medium, one small) +* Wooden Rolling Pin (one solid piece, no separate handles) +* Wooden Utensiles (shallow spoon, ladle, spatula, slotted spoon, long chopsticks) +* Board Wax (for conditioning cutting board and wooden utensils) +* Textiles (tea towels, dish towels, cleaning cloths) + +And, of course, to eat food you could get away with just bowls and chopsticks +if you're being really minimal, but a set of two forks, knives, spoons, mugs, +plates, and bowls per person is the most versatile. + +Some nice-to-haves include a blender/food processor, more baking sheets/cake +pans/pie pans/etc., a whisk, a handmixer, an immersion blender, a large stock +pot, and a pressure cooker. + +### Knife + +Get a _Cai Dao_ (Chinese Chef Knife). They are versatile, often inexpensive, +and easy to take care of. They are perfect for everything from thinly slicing +veggies with precision to rough-chopping produce that'll be thrown in a soup. +The large, flat blade also doubles as a bench scraper allowing you to chop and +transfer with ease. + +I'm a fan of the CCK1303, but there are plenty of other models out there. +Whichever knife you choose, do some research +([r/chefknives](https://old.reddit.com/r/chefknives) is great for this) before +you buy. This is a tool you're likely going to use every day and if it +frustrates you then cooking becomes a chore instead of something fun. + +### Cutting Board + +Avoid materials other than wood or bamboo. Wood is not less sanitary than +rubber or plastic and is better for the environment; pretty much everything +else (e.g. glass) destroys the edge on your knife. Some people think that there +is a difference between hardwood (e.g. maple, oak) and softer woods (e.g. pine) +in terms of being better for your knife's edge, but there is no conclusive +testing and the effect is likely insignificant. + +In terms of size: get whatever fits your space and is comfortable for you. +A very large butcher block is great for prepping a lot of things at once but +smaller ones can be picked up and moved around more easily. It's entirely up to +preference. + +#### References + +* [Comparative studies on hygienic qualities of wood and plastic cutting boards in a laboratory](https://www.semanticscholar.org/paper/GERMAN-STUDY-WOOD-vs-PLASTIC-CUTTING-BOARDS-STUDIES-Kleiner-Lampe/24585ce7610d5e3daf3b21e91989c0b634dafbcd) +* [Plastic and wooden cutting boards](https://pubmed.ncbi.nlm.nih.gov/31113021/)) +* [Cutting Boards of Plastic and Wood Contaminated Experimentally with Bacteria](https://www.sciencedirect.com/science/article/pii/S0362028X22020920) +* [Hygienic aspects of using wooden and plastic cutting boards, assessed in laboratory and small gastronomy units](https://link.springer.com/article/10.1007/s00003-015-0949-5) + diff --git a/content/garden/arboretum/programming-style.md b/content/garden/arboretum/programming-style.md @@ -0,0 +1,558 @@ +Title: Some Notes on Programming Style and Composition +Summary: Some Notes on Programming Style and Composition + +# [%title] + +[← Back](./) + +This document describes my guidelines and philosophies for programming style +and composition. Even in languages which enforce a certain style, there are +still many mistakes one can make which can lead to programs being hard to read +and less maintainable. + +Keep in mind that no programming style should be treated as "high gospel". It +is ridiculous to get into flame wars over where to place braces and what kind +of indentation to use. There are demonstrable pros and cons to different +styles and people will choose what they like best. As long as it doesn't +produce objectively ugly, unreadable code, it is acceptable. + +My overarching philosophy is that one should write programs for humans to +read, not computers to execute. Code that is cleverly written is code that is +poorly written (unless you're doing it for a competition or for fun). + +Where possible, use common sense to make your program as readable as it can be. +When working on a codebase that is not your own, follow the existing style (if +there is one). If a programming language has a standardized style (e.g. Go's +gofmt or Python's PEP 8), abide by that style. + +<ul> + <li><a href="#dependencies">Dependencies</a></li> + <li><a href="#comments">Comments</a></li> + <li><a href="#complexity-and-optimization">Complexity and Optimization</a></li> + <li><a href="#naming">Naming</a></li> + <li><a href="#braces-and-parentheses">Braces and Parentheses</a></li> + <li><a href="#line-length">Line Length</a></li> + <li><a href="#indentation-spacing-and-alignment">Indentation, Spacing and Alignment</a></li> + <li><a href="#language-specifics">Language Specifics</a></li> +</ul> + + +## Dependencies + +Limit the use of external dependencies as much as possible. In order of +preference: + +1. Write bespoke libraries for your purpose +2. Clone an existing library and merge it into your codebase so that you + maintain it alongside your code (vendor it) +3. Depend on an external library + +While it is reasonable to expect some amount of dependency on external things +(unless you write your own computing stack from the ground-up), limiting that +dependency as much as possible ensures that you are less likely to be hit by +things like [breakages due to an incompetent or malicious open source +maintainer](https://en.wikipedia.org/wiki/Npm_(software)#Notable_breakages) or +breakages caused by an unexpected update to a library you're using. It gives +your programs the best chance of being usable far into the future instead of +suffering from [code rot](https://en.wikipedia.org/wiki/Software_rot) within +a few years. + +The trend in JavaScript (npm), Python (pip), Rust (cargo), and Go (it's +de-facto dependencies on Google and GitHub) is very concerning for the future +of programs written in these languages. (And, in fact, I have run into issues +getting older Python programs to run due to packages no longer being +available.) + +## Comments + +Comments should only exist in code to express why something is being done +a certain way or to clarify a particularly tricky bit of code that is hard to +express in any other way. Comments like the following are completely useless +and should not exist: + +``` +struct Node *np = &node /* Create a pointer to the node */ +``` + +Comments should also not have annoyingly large banners, and big blocks of +comments should be avoided. The "doxygen-style" of commenting before a function +and at the top of a file are quite useless and end up being like the above +example in practice. Although they can be helpful for generating the skeleton +of some API documentation, it requires so much additional work and information +to be useful that you're better off leaving your code clean and just writing +the documentation separately. I have mainly seen these kinds of comments used +as an excuse to not write good documentation ("Look, we have doxygen-generated +documentations; we documented this code!") more than I have seen it be useful. + +Great uses of comments include: + +* Pointing to external documentation or another file as a guide or explanation +* TODO or FIXME markers +* Blocks before the declaration of a particularly complex data structure +* Explaining the quirks of a particular algorithm (e.g. working around a hardware limitation) + +## Complexity and Optimization + +Try to minimize complexity as much as possible. Complexity **does not +necessarily refer to lines of code**. Complexity often arises from complicated +program logic, bad program design, "cleverly-written" code designed to be +optimized for speed, and excessive reliance on external dependencies, where +lines of code is just a symptom of these diseases. + +The more code a program has, the more bugs your program can have. The more +features your code has, the more ways those features can interact in unexpected +ways and result in bugs. The more clever a program is written, the harder it is +to spot bugs or debug. + +Also, simple algorithms and data structures are often preferable over fancy +ones—even though fancy ones may be theoretically faster for large +inputs—because inputs are _usually_ small enough where the real effect is not +significant. For example, the [Schönhage-Strassen +algorithm](https://en.wikipedia.org/wiki/Sch%C3%B6nhage%E2%80%93Strassen_algorithm) +for multiplying integers together is significantly faster than older, simpler +algorithms such as the [Karatsuba +algorithm](https://en.wikipedia.org/wiki/Karatsuba_algorithm), but only for +integers that are 10,000 to 40,000 or so decimal digits large. If you're +implementing your own multiplication algorithm for whatever reason and you +don't expect to be operating on numbers that large then it's counterproductive +to implement the more complex algorithm because it will perform worse and be +harder to understand. Fancier algorithms and data structures are often not only +buggier, but also harder to debug than their simpler counterparts. + +Finally, this is one point that I wish was hammered into every programmer's +head: **measure, don't assume** the performance characteristics of your +program. Too many programs are written in convoluted or confusing ways in an +attempt to chase perceived performance gains without any actual benchmarking or +measurement. Only tune once you understand how your program behaves. Beyond +this, there is no point tuning a program for marginal improvements in overall +speed unless you are specifically targeting a performance metric. + +## Naming + +Names should be descriptive and clear in context, but not redundant or +excessive. In general, procedures should be named based on what they do and +functions should be named based on what they return and variables and types +should be nouns (e.g. `num_cakes` or `Parser`). + +``` +x = compute_length(x); +if (valid_length(x)) +``` + +is better than: + +``` +x = length_computer(x); +if (check_length(x)) +``` + +Names like `maximumValueUntilOverflow` or `EntertainmentProviderViewController` +are bad. They are excessive and make it harder to see what the program is +actually doing. Also, the latter example is annoyingly vague and indirect. +`maxval` and `TelevisionRemoteControl` are far better, clearer names. + +Types, classes, structs or other similar programming structures should be +written in capitalised `CamelCase`, variables and functions in `snake_case`, +and constants in `ALL_CAPS`. If the components of a variable name are short, +there are a maximum of two, and they are distinct, it is often more readable to +write the name in all lowercase as opposed to snake case. For example, `maxval` +over `max_val`, but not `percenttrue` over `percent_true`. + +Furthermore, it is acceptable to use short names where the meaning is +immediately clear from the context. For example, `np` is better than +`node_pointer` or `nodepointer` as long as you are consistent and it is obvious +what the variable refers to in a given context (e.g. you created it like: +`struct Node *np = &node;`). + +Finally, if two variables are related in some way, they should have consistent +naming. For example, if you have a variable representing the maximum and +minimum physical address in memory, choose names like `max_phys_addr` and +`min_phys_addr`, not `max_phys_addr` and `lowest_address`. + +### Worse + +``` +ComputeResult(initial_value, new_value, modifier, even) + +FileName = "file.txt" +coordinate_pair updatedcoordinate = (ComputeX(x), y) +``` + +### Better + +``` +compute_result(initialValue, newValue, modifier, is_even) + +filename = "this-is-a-file.txt" +CoordinatePair updated_coordinate = (compute_x(x), y) +``` + +If variables represent a certain magnitude (e.g. milliseconds or kilometers), +this should be reflected in its name: + +### Worse + +``` +time = 5000 +distance = 5 +``` + +### Better + +``` +time_ms = 5000 +distance_km = 5 +``` + +The above is also why `snake_case` is preferable to `camelCase` for variables. +`timeMs` or `timeMS` looks worse than `time_ms`. + +Single-letter names are acceptable only in contexts in which they are obvious +(e.g. `x` and `y` in mathematics) or a well-understood convention (e.g. `i` and +`j` for loop iterator variables). + +## Braces and Parentheses + +Braces and parentheses should be used liberally to make code easy to follow. + +In general, single-line control blocks like so: + +``` +if (condition) + do_stuff(); +``` + +should have surrounding braces. Although it can seem excessive, especially +paired with my other preferences, it eliminates a class of bugs that arises +when one adds code to a control block but forgets to also add the braces: + +``` +if (condition) + do_stuff(); + do_more_stuff(); <- this is not in the if block! +``` + +(Although whitespace-indented languages such as Python do not have to deal with +this issue, that property brings along other issues with code readability due +to blocks not being as clearly delineated. Like I said, there is no One True +Style.) + +Furthermore, in if/else statements, this style: + +``` +if (condition) +{ + do(); + things(); +} +else +{ + other(); + stuff(); +} +``` + +is preferable to: + +``` +if (condition) { + do(); + things(); +} else { + other(); + stuff(); +} +``` + +because it is much easier to select the else statement (for deletion, copying, +etc.) if it is not on the same line as the closing brace of the if statement. +This is not only helpful in vim's visual mode, but also when selecting code +with a mouse as one can be less precise when selecting the block of code. It +is also easier to read this way, regardless of how you feel about what I am +about to say: + +Although many have unfortunately settled on the following brace style for +functions, control statements, and the like: + +``` +if (condition) { + do_some_stuff(); + and_some_more(); +} +``` + +it is far more readable in general to put opening braces on a new line ([Allman +Style](https://en.wikipedia.org/wiki/Indentation_style#Allman_style)): + +``` +if (condition) +{ + do_some_stuff() + and_some_more(); +} +``` + +While this might appear excessive for such a trivial statement, the superiority +of this style for readability quickly becomes evident when blocks get longer or +more complex. For example: + +``` +if (is_logged_in(client) + && client->assignedAddress + && strncmp(client->username, "admin", sizeof("admin")) == 0 + && authenticate(client->password, password) +{ + render_admin_panel(); +} +``` + +is far better than: + +``` +if (is_logged_in(client) + && client->assignedAddress + && strncmp(client->username, "admin", sizeof("admin")) == 0 + && authenticate(client->password, password) { + render_admin_panel(); +} +``` + +Similarly: + +``` +if (abs(hpos[0] - tpos[0]) > 1 || abs(hpos[1] - tpos[1]) > 1) +{ + if (hpos[0] > tpos[0] && hpos[1] < tpos[1]) + { + tpos[1]--; + tpos[0]++; + } + else if (hpos[0] > tpos[0] && hpos[1] > tpos[1]) + { + tpos[1]++; + tpos[0]++; + } + else if (hpos[0] < tpos[0] && hpos[1] < tpos[1]) + { + tpos[1]--; + tpos[0]--; + } + else if (hpos[0] < tpos[0] && hpos[1] > tpos[1]) + { + tpos[1]++; + tpos[0]--; + } + else if (hpos[0] > tpos[0]) + { + tpos[0]++; + } + else if (hpos[0] < tpos[0]) + { + tpos[0]--; + } + else if (hpos[1] > tpos[1]) + { + tpos[1]++; + } + else if (hpos[1] < tpos[1]) + { + tpos[1]--; + } +} +``` + +is generally more readable than: + +``` +if (abs(hpos[0] - tpos[0]) > 1 || abs(hpos[1] - tpos[1]) > 1) { + if (hpos[0] > tpos[0] && hpos[1] < tpos[1]) { + tpos[1]--; + tpos[0]++; + } else if (hpos[0] > tpos[0] && hpos[1] > tpos[1]) { + tpos[1]++; + tpos[0]++; + } else if (hpos[0] < tpos[0] && hpos[1] < tpos[1]) { + tpos[1]--; + tpos[0]--; + } else if (hpos[0] < tpos[0] && hpos[1] > tpos[1]) { + tpos[1]++; + tpos[0]--; + } + else if (hpos[0] > tpos[0]) { + tpos[0]++; + } + else if (hpos[0] < tpos[0]) { + tpos[0]--; + } + else if (hpos[1] > tpos[1]) { + tpos[1]++; + } + else if (hpos[1] < tpos[1]) { + tpos[1]--; + } +} +``` + +because the additional vertical whitespace afforded by the opening brace being +on a new line helps to visually separate distinct blocks of code, and it is +much easier to find matching braces since the opening and closing braces +visually line up. + +With this style, it is much easier to keep track of block boundaries when the +braces are distinctly on their own lines. It also means that, should the +conditions in an `if` statement or the arguments to a function grow too long to +fit comfortably on one line, there is still meaningful separation between the +function's declaration and its body without an additional level of indentation. + +While some might denounce this style because it's not as compact and one can't +fit as many lines of meaningful code onto the screen at once, note that, just +like the line length argument, this has been largely irrelevant since the 90's, +if not earlier. Speaking of which... + +## Line Length + +Hard limits on line length are outmoded and poorly reasoned. Unless you are +literally programming with punched cards or using an extremely limited display +(e.g. you're programming for a retro computer), there is no reason to set +a hard limit on the length of lines. + +However, one should strive to keep lines within a reasonable length, such that +one does not have to scroll a reasonably-sized editor to see the ends of +a line. Smaller line lengths are also easier for people to read since long +lines make it harder to find the beginning of the next line. While this mostly +applies to prose, it also applies to code in some circumstances (e.g. code +comments or dense blocks of code that are awkward to split up). Plus, limiting +the length of your lines to something reasonable allows one to have two or +three windows side-by-side without needing to scroll. + +Avoid excessively long lines, but don't stress about a line that is 81 or even +90 characters instead of a perfect 80. Use common sense. If your code is more +readable wrapped to smaller lines, then do that. If wrapping would make your +statement look awkward, then don't. + +### Worse + +``` +int +this_is_a_function_with_a_long_name(int param1, int param2, int param3, int param4, int param5, int param6, int param7, int param8) +{ + return CONSTANT + max(param1, param2, param3, param4, param5, param6, param7, + param8); +} +``` + +### Better + +``` +int +this_is_a_function_with_a_long_name(int param1, int param2, int param3, + int param4, int param5, int param6, int param7, int param8) +{ + return CONSTANT + max(param1, param2, param3, param4, param5, param6, param7, param8); +} +``` + +## Indentation, Spacing and Alignment + +Before touching on the hot-button topic a few notes about other aspects: + +In general, if you find your code being heavily nested, this should be a sign +to refactor or reconsider your approach. An oft-repeated adage (originating +from Linus Torvalds) is that "if you need more than 3 levels of indentation, +you’re screwed anyway, and should fix your program." While this is not +a hard-and-fast rule, especially for programming languages which have functions +inside of class definitions and so on, it is a decent guideline for writing the +logic of your code, since excessive levels of indentation probably indicates +inefficient checking of conditions or heavily-nested loops which tend to be +quite slow. + +There should be spaces between binary or trinary operators (but not unary +operators) and their operands as well as between elements in a list: + +``` +array = [1, 2, 3, 4]; +result = (input + (CONSTANT / intermediate)); +``` + +not + +``` +array=[1,2,3,4]; +result=(input+(CONSTANT/intermediate)) +``` + +Also, it is acceptable to use spaces to visually align your code if it makes it +easier to read. Once again, use your judgement. Oftentimes no alignment is +really needed (plus, it makes no difference if you like to program with +a variable-width font). + +Now, onto The Debate™... + +There is little difference between spaces and tabs for indentation. Although +some people might cry "accessibility!" as an argument for tabs over spaces, +there is no significant evidence to support this assertion and I have seen +accessibility anecdotes for both. Unless someone does an actual study on this, +I will continue to assert that there is little meaningful difference. + +That being said, I prefer tabs wherever supported for the following reasons: + +* The tab character is one character, whereas spaces are multiple characters + and result in larger files +* It is possible to configure how wide a tab appears, so a programmer can + choose the width of indentation they prefer +* Semantically, one tab character equals one level of indentation + +On the first point, although disk space is quite plentiful today, bandwidth +still isn't. Even on files that are only a couple of hundreds of lines long, +using spaces instead of tabs to indent increases file size by a significant +amount. If you're trying to optimize the size of assets you're delivering over +the wire (e.g. HTML, CSS, and JS files), this becomes significant. For example, +this page as a tab-indented HTML file takes up XXXX bytes, but it takes up XXXX +bytes if indented with four spaces. + +On the second point, if a programmer prefers to see a lot of whitespace to +indicate levels of indentation (as I do), they can choose to leave tabs at +their default width of 8 columns. If a programmer likes their code to be +a little more compact, they can choose to display the width of a tab at 4 or +even 2 columns. Using tabs separates the representation of indentation from the +actual content of the file and allows a programmer to view the file based on +their preferences. + +Regardless of any other points, nobody should be using mixed indentation or two +spaces for indentation. Mixed indentation makes it difficult to follow blocks +of code (please don't indent your braces two spaces and the body of a block +four spaces) and two spaces is harder to read than four because of the lack of +whitespace to differentiate indentation levels. + +Given that there is no inherent advantage to spaces over tabs aside from the +fact that a space takes up the same width for every programmer (not that this +is important given my previous points about levels of indentation and line +lengths), it is easy to see why tabs are preferred. + +### References + +* [Tabs versus spaces—what is the proper indentation character for everything, in every situation, ever?](https://softwareengineering.stackexchange.com/questions/57) + +## Language Specifics + +Different programming languages have different conventions or best-practices +that are dependent on the syntax and usage of that language. Here are some +notes on various languages: + +[This section needs work] + +### C + +C functions should be named in `snake_case` because of the convention that +internal functions are preceded by two underscores and "namespacing" your +functions by prepending a category, or type is more readable with underscores. + +There is no performance difference between `++i` and `i++` for in modern +compilers. + +* [C Programming in Plan 9 from Bell Labs](http://doc.cat-v.org/plan_9/programming/c_programming_in_plan_9) +* [Notes on Programming in C by Rob Pike](http://doc.cat-v.org/bell_labs/pikestyle) + +### Python + +* [Composition (of Python Programs)](https://cs61a.org/articles/composition/) diff --git a/content/garden/arboretum/finished-list.md b/content/garden/arboretum/reading-list.md diff --git a/content/garden/arboretum/style.md b/content/garden/arboretum/style.md @@ -1,12 +0,0 @@ -Title: Style -Summary: Style - -# [%title] - -[← Back](./) - - -This document describes my preferred programming style. - -[https://cs61a.org/articles/composition/](https://cs61a.org/articles/composition/) -