├── .github └── workflows │ └── validate.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md └── principles ├── avoid-double-negative-logic.md ├── avoid-mental-mapping.md ├── be-constructive-not-destructive.md ├── build-up-your-understanding-of-a-problem-individually-once-done-share-that-understanding-together.md ├── code-an-off-swtich.md ├── code-should-work-but-does-not-have-to-be-efficient.md ├── compute-properties-when-possible.md ├── consistent-code-automatically-enforced.md ├── core-logic-separate-from-framework.md ├── dependency-inversion-principle.md ├── documentation-close-to-code.md ├── documentation-easy-to-amend.md ├── dont-add-unneeded-context.md ├── elon-musk-requirement-principle-requirements-belong-to-individuals-not-teams.md ├── ensure-ui-components-can-be-loaded-separately-from-an-application.md ├── explicit-dependencies-principle.md ├── figure-out-the-problem-before-the-technology.md ├── function-arguments-ideally-use-2-or-fewer.md ├── function-names-should-say-what-they-do.md ├── functions-should-do-one-thing.md ├── go-wide-then-refine.md ├── holywood-principle.md ├── invisible-visible.md ├── iterate-in-thens.md ├── keep-it-simple-stupid-kiss.md ├── learn-in-public.md ├── logic-in-positive.md ├── many-minds-better-problem-solving.md ├── model-all-state-in-an-application.md ├── murphys-law.md ├── openclosed-principle.md ├── principle-of-evolvability.md ├── reduce-a-problem-to-its-lowest-sensible-abstraction.md ├── relatedness-pattern.md ├── single-responsibility-principle.md ├── single-source-of-truth.md ├── software-should-be-easy-to-debug.md ├── test-models-thoroughly-test-everything-else-less.md ├── treat-things-like-cattle-not-pets.md ├── try-to-delete-the-part-or-process.md ├── use-default-arguments-instead-of-short-circuiting-or-conditionals.md ├── use-explanatory-variables.md ├── use-meaningful-and-pronounceable-variable-names.md ├── use-searchable-names.md ├── use-the-same-vocabulary-for-the-same-type-of-variable.md └── where-you-know-you-arent-aligned-resolve-early.md /.github/workflows/validate.yml: -------------------------------------------------------------------------------- 1 | name: Validate CI 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | validate: 7 | runs-on: ubuntu-20.04 8 | 9 | steps: 10 | - uses: actions/checkout@v1 11 | - uses: jitterbit/get-changed-files@v1 12 | id: files 13 | - name: Changed files 14 | run: | 15 | echo "Changed files detected: ${{ steps.files.outputs.all }}" 16 | for changed_file in ${{ steps.files.outputs.added_modified }}; do 17 | if [[ $changed_file == *.md ]] && [[ $changed_file != README.md ]]; then 18 | echo "Do something with this ${changed_file}." 19 | output="$(cat $changed_file)" 20 | curlOutput=$(curl --location -w '\n\nStatusCode:%{http_code}' --request PUT 'https://t1h8ftxrq4.execute-api.eu-west-2.amazonaws.com/default/validator-prod' --header 'Content-Type: text/plain' --data-raw "${output}") 21 | statusCode=${curlOutput:(-3)} 22 | 23 | if [[ $statusCode == "200" ]]; then 24 | echo "VALID: ${changed_file}" 25 | else 26 | echo "FAILED Validation: ${changed_file}: >>> ${curlOutput%StatusCode*} <<<" 27 | exit 1 28 | fi 29 | fi 30 | done 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributor Covenant Code of Conduct 3 | 4 | ## Our Pledge 5 | 6 | We as members, contributors, and leaders pledge to make participation in our 7 | community a harassment-free experience for everyone, regardless of age, body 8 | size, visible or invisible disability, ethnicity, sex characteristics, gender 9 | identity and expression, level of experience, education, socio-economic status, 10 | nationality, personal appearance, race, caste, color, religion, or sexual 11 | identity and orientation. 12 | 13 | We pledge to act and interact in ways that contribute to an open, welcoming, 14 | diverse, inclusive, and healthy community. 15 | 16 | ## Our Standards 17 | 18 | Examples of behavior that contributes to a positive environment for our 19 | community include: 20 | 21 | * Demonstrating empathy and kindness toward other people 22 | * Being respectful of differing opinions, viewpoints, and experiences 23 | * Giving and gracefully accepting constructive feedback 24 | * Accepting responsibility and apologizing to those affected by our mistakes, 25 | and learning from the experience 26 | * Focusing on what is best not just for us as individuals, but for the overall 27 | community 28 | 29 | Examples of unacceptable behavior include: 30 | 31 | * The use of sexualized language or imagery, and sexual attention or advances of 32 | any kind 33 | * Trolling, insulting or derogatory comments, and personal or political attacks 34 | * Public or private harassment 35 | * Publishing others' private information, such as a physical or email address, 36 | without their explicit permission 37 | * Other conduct which could reasonably be considered inappropriate in a 38 | professional setting 39 | 40 | ## Enforcement Responsibilities 41 | 42 | Community leaders are responsible for clarifying and enforcing our standards of 43 | acceptable behavior and will take appropriate and fair corrective action in 44 | response to any behavior that they deem inappropriate, threatening, offensive, 45 | or harmful. 46 | 47 | Community leaders have the right and responsibility to remove, edit, or reject 48 | comments, commits, code, wiki edits, issues, and other contributions that are 49 | not aligned to this Code of Conduct, and will communicate reasons for moderation 50 | decisions when appropriate. 51 | 52 | ## Scope 53 | 54 | This Code of Conduct applies within all community spaces, and also applies when 55 | an individual is officially representing the community in public spaces. 56 | Examples of representing our community include using an official e-mail address, 57 | posting via an official social media account, or acting as an appointed 58 | representative at an online or offline event. 59 | 60 | ## Enforcement 61 | 62 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 63 | reported to the community leaders responsible for enforcement at https://principles.dev/contact/. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series of 86 | actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or permanent 93 | ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within the 113 | community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.1, available at 119 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 120 | 121 | Community Impact Guidelines were inspired by 122 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 123 | 124 | For answers to common questions about this code of conduct, see the FAQ at 125 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at 126 | [https://www.contributor-covenant.org/translations][translations]. 127 | 128 | [homepage]: https://www.contributor-covenant.org 129 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 130 | [Mozilla CoC]: https://github.com/mozilla/diversity 131 | [FAQ]: https://www.contributor-covenant.org/faq 132 | [translations]: https://www.contributor-covenant.org/translations 133 | 134 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Thank you for being interested in making Software Engineering better for everybody 2 | 3 | 4 | # Contributing 5 | 6 | There are many ways to contribute to the project, from simple to most rewarding: 7 | 8 | * **Correct mistakes** - This could be spelling, grammar or improving writing to allow the point to be communicated more clearly. 9 | * **Enrich a principle** - All principles can be improved by adding more information or better reasoning. 10 | * **Copy an existing principle to here** - Derive a principle from elsewhere. Make sure it has a permissible license (e.g., MIT, CC BY-SA). 11 | * **Create a principle** - Do you want to communicate an idea of your own to the world? You can create it on principles.dev. Principles.dev has friendly SEO options to prevent duplicate content if you want to publish it elsewhere (e.g. your blog) 12 | 13 | If you're creating or copying an exisiting principle. Before you begin, you should at least read through the [how to write a principle](https://principles.dev/documentation/) quickstart section. Looking at existing principles on the site will help you understand what's required. 14 | 15 | ## How it works 16 | 17 | 1. This repository is the source of truth for principles.dev. Once a build is merged back to the release branch, it will appear on the live website at principles.dev 18 | 2. To submit a principle, you must create a pull request/fork the repo with the merge target set to **release** branch. 19 | 3. Optionally create an account (you can use github) on principles.dev. Doing so will acreate an account page to track the principles you create. It looks like this: https://principles.dev/u/AdamCraven/ . 20 | 4. To credit your principles to your principles.dev account, you must write your github username (case-sensitive) in the authors or contributors field at the top of any created or edited principle. 21 | 22 | 23 | ## Will my principle be accepted? 24 | 25 | Creating a principle is an intentionally high-friction process to deter low-quality principles. If you are reading these words, it is unlikely your principle will fall into the low quality category. Principles are generally approved if the requirement for a [basic principle](https://principles.dev/documentation/#quickstart-writing-your-first-principle) is met. 26 | 27 | The reasons for lack of approval are: 28 | 29 | * Low quality - The principle cannot change someone's behavior or capability because it's missing crucial information or context. 30 | * Not containing *the what* and *the why* 31 | * The principle is offensive, inflammatory, or generally targeted at hostility towards a different group (e.g., don't use X language, X technology, etc.) 32 | * Grammar or spelling mistakes (which are easily correctable) 33 | 34 | If you need clarification, it's ok to open an issue on this repository to discuss a principle and get some general pointers. If you create a pull request and any of the above problems exist, the maintainers will point them out, and you'll have opportunities to correct them. Please make sure you've read the documentation beforehand. The more time you've spent on understanding, the more maintainers will gladly invest their time in helping you. 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | ![open-source-principles](https://user-images.githubusercontent.com/610638/230180036-35fed7c7-6655-4b2a-ab68-4fcb8f924bcd.png) 6 | 7 | 8 | 9 | 10 | Open-source principles to align engineering and leadership teams. Build is published onto principles.dev. Contributors welcome. 11 |

12 | 13 | 14 | 15 |
16 |
17 | (*) Principle licensing may vary, read below for more info 18 | 19 | 20 |
21 | 22 | 23 | 24 | ## Contributing 25 | 26 | We are a group of contributors with a goal to make software engineering and leadership behaviors visible, to make software better for everyone. 27 | 28 | You can create your principle by using the [Editor](https://principles.dev/editor/), reading the [how to write a principle](https://principles.dev/documentation/#how-to-write-a-principle_1) and, of course, the Contributing.md. Once done you can submit a pull request back to this repo. 29 | 30 |

31 | 32 | 33 | 34 | ![editor3](https://user-images.githubusercontent.com/610638/230163658-ec553cb4-ad91-42d2-8021-5b33ffe1441e.png) 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | ## Keeping in touch 46 | 47 | 1. Sign up for an account at https://principles.dev where you can save your principles drafts (for submitting to this repo) and organising your favourite principles in your profile. 48 | 2. Follow [@principles_dev](https://twitter.com/principles_dev) to hear more about principles. 49 | 3. There's also a mailing list on the website with infrequent emails about principles. 50 | 51 | ## Licensing 52 | 53 | Principles are generally licensed under Creative Commons Attribution-ShareAlike 4.0 International. But may be licensed under other creative commons license. Refer to the individual principle meta-data file for license claims - you can find this at the top of every principles file. 54 | 55 | e.g. ```license = "CC BY-SA 4.0"``` 56 | 57 | Principles may also be licensed under a dual GPLv3.0 license to allow software distribution under the same terms. Refer to the individual principle meta data for license claims - you can find this at the top of every principles file. 58 | 59 | e.g. ```allow_dual_licensing_to_GPLv3 = true``` 60 | 61 | For more information on licensing, read here: https://principles.dev/license/ 62 | 63 | 64 |
65 |

66 | 67 | 68 | 69 |

70 |
71 | 72 | -------------------------------------------------------------------------------- /principles/avoid-double-negative-logic.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Avoid double negative logic" 3 | summary = "Conditional logic should avoid double negatives." 4 | tags = ["logic", "code", "practices"] 5 | license = "CC BY-SA 4.0" 6 | allow_dual_licensing_to_GPLv3 = true 7 | authors= [] 8 | contributors = ["AdamCraven"] 9 | uid = "rose-crab-celine" 10 | +++ 11 | 12 | Conditional logic should avoid double negatives. e.g., "Is this not not true?" 13 | 14 | ## Why 15 | 16 | - Double negatives are hard to comprehend. 17 | 18 | ## How 19 | 20 | - Write logic that asks: Is this true. Instead of: Is this not not true? 21 | 22 | ## Example 23 | 24 | A double negative conditional, which is hard to understand: 25 | 26 | ```js 27 | if (!isNotSelected) { 28 | ... 29 | ``` 30 | 31 | Then written in the positive: 32 | 33 | ```js 34 | if (isSelected) { 35 | ... 36 | ``` 37 | 38 | ## References 39 | 40 | - https://derickbailey.com/2014/03/27/double-negatives-in-code-dont-not-avoid-double-negative-boolean-logic/ 41 | - https://refactoring.com/catalog/removeDoubleNegative.html 42 | - https://principles.dev/p/logic-in-positive/ 43 | -------------------------------------------------------------------------------- /principles/avoid-mental-mapping.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Avoid Mental Mapping" 3 | tags = ["variables", "code", "rule", "code review", "clean code"] 4 | summary = "Avoid using shorter replacement variables that aren't explicit" 5 | authors = [] 6 | contributors = ["AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source = "https://github.com/ryanmcdermott/clean-code-javascript" 10 | original_source_is_canonical = false 11 | crystalized = false 12 | uid = "819b59e2-27ae-4c15-a7fe-b87ccd9a91a3" 13 | +++ 14 | Avoid using shorter replacement variables that aren't explicit 15 | 16 | Bad: 17 | 18 | ```js 19 | const locations = ["Austin", "New York", "San Francisco"]; 20 | locations.forEach(l => { 21 | doStuff(); 22 | doSomeOtherStuff(); 23 | // ... 24 | // ... 25 | // ... 26 | // Wait, what is `l` for again? 27 | dispatch(l); 28 | }); 29 | ``` 30 | 31 | Good: 32 | 33 | ```js 34 | const locations = ["Austin", "New York", "San Francisco"]; 35 | locations.forEach(location => { 36 | doStuff(); 37 | doSomeOtherStuff(); 38 | // ... 39 | // ... 40 | // ... 41 | dispatch(location); 42 | }); 43 | ``` 44 | 45 | ## Why 46 | 47 | * Lowers cognitive load due to not having to remember variables 48 | 49 | 50 | ## Derivative work 51 | 52 | > This work is a derivative of "clean-code-javascript" by Ryan Mcdermott, originally licensed under MIT. The original version can be found [here](https://github.com/ryanmcdermott/clean-code-javascript/tree/3ff9eba6d460f31db8146762bade4fcc32626762). -------------------------------------------------------------------------------- /principles/be-constructive-not-destructive.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Be constructive, not destructive." 3 | tags = ["leadership", "medium", "practice", "team"] 4 | summary = "" 5 | authors = ["nickyhannaway"] 6 | contributors = ["AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "1e4becc9-9622-49f8-93eb-db0e5b5c582c" 12 | +++ 13 | When you are a participant in collaborative decision making, communicate and convey your ideas in a constructive manner. 14 | Doing this enhances the clarity of your ideas, makes them more impactful and makes other team members more likely to align to your thoughts and suggestions. 15 | 16 | Destructive behaviours such as talking over people, not considering other viewpoints and clinging onto your own ideas regardless of collective opinion and value can damage team morale. 17 | This skews team alignment as personal divides begin to manifest which can lead to a deterioration in the team's collective decision making ability. 18 | Being constructive, individually and collectively means arriving at the best and most practical proposed solution based on the solution's individual merits and not allowing external factors 19 | such as personal opinions and relationships with others to influence the value and merit of any proposed solution. 20 | 21 | ## Why 22 | We always want to have a team that is aligned, where morale is good and where we arrive at the right decisions, for the right reasons. This makes sure the team is effective at adding value to the business and embodies a positive environment where people feel happy in their work. This also fosters a collaborative culture where any potential gaps in the decision-making process are filled by team members feeling empowered to influence 23 | decision making in the most positive and constructive way. Being constructive, not destructive leads to better aligned teams, greater engagement from team members, less stress and an environment where people feel more valued. All of the above also helps make discussions and decision making ceremonies more efficient, less fraught and from experience, arrival at the desired outcome much quicker. 24 | 25 | ## When to apply 26 | * When you have thoughts, ideas or potential solutions that you have reflected are viable and carry as much, preferably greater weight than those currently being proposed. 27 | * When the team are in a state of deadlock and are struggling to come up with any potential solutions to a problem. 28 | * In the above scenario it can be useful to set the ball rolling for collaborative decision making by simply pitching a solution. 29 | 30 | ## When not to apply 31 | * When you feel your potential solution is less effective than those already being discussed and introducing it could simply muddy the waters of the collaborative decision making process. 32 | * When you don't have a good or full understanding of the problem the team is collectively trying to solve. 33 | * When personally, in any given moment your mood is not conducive to constructive behaviours and you feel this mood or external factors could influence detrimentally your ability to convey your thoughts 34 | and any potential misgivings constructively. In this scenario you should feel comfortable enough to ask the team if they could reconvene when you are feeling better. -------------------------------------------------------------------------------- /principles/build-up-your-understanding-of-a-problem-individually-once-done-share-that-understanding-together.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Understand a problem individually, then share it." 3 | tags = ["process", "comprehension", "remote-work", "team", "medium"] 4 | summary = "Capture your understandings separately to the team and then come together to align" 5 | authors = ["russmiles", "AdamCraven"] 6 | contributors = [] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "d6ade315-4b4d-494f-8142-a911cf7ab7d3" 12 | +++ 13 | 14 | When you are in a situation when people are communicating concepts or ideas to you (e.g., in a meeting), you should capture your understandings (e.g., as notes or sketches) separately to the team and then come together to compare what you have understood. 15 | 16 | ## Why 17 | 18 | * You will discover misunderstandings rapidly. Comparing your understandings with the rest of the team will allow you to correct and align on misconceptions. 19 | * Engagement and focus will be very high. Everyone is responsible for capturing their ideas, so everyone is focused on the meeting. 20 | * Much less room for hidden misalignment. Everyone has to explain what they understand, which can be shown afterward to align. 21 | 22 | 23 | ## How 24 | 25 | Some ideas of how you might use this: 26 | 27 | * In a discovery meeting with a client, if an expert is explaining an architecture to your team. The whole team should individually draw up that architecture on their own. At different points, they should align their drawings to see how closely they understood the architecture and clarify any misunderstandings. 28 | * When having a meeting about new features with a client and they know the UX well, instead of asking to see the designs, ask them to explain it to you and draw it. You can then refer to the designs to see how closely they align. 29 | 30 | #### In practice: 31 | 32 | We named a process after this principle, called a "wash-up". It was a 10-minute session reserved at the end of specific meetings (usually ones that involved a lot of design, creativity, or were information-dense) where people could share what they had understood. 33 | -------------------------------------------------------------------------------- /principles/code-an-off-swtich.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Code an off-switch" 3 | tags = ["feature flag", "feature toggle", "off switch", "practices", "team", "medium"] 4 | summary = "Always plan for a way to switch your work off" 5 | authors = ["kealanparr"] 6 | contributors = [] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "d06dd439-634a-40f2-b2b4-bcb583c1bba8" 12 | +++ 13 | When you're in the planning stage of introducing a major piece of software into your system, from the beginning, ensure there's an off switch. 14 | 15 | This is normally done via **Feature Flags** (AKA **Feature Toggles**) 16 | 17 | Giving yourself an easy way out if something goes wrong on site, pays you back tenfold for the time you do need it, alongside reducing risk on your site. 18 | 19 | It helps ensure: 20 | 21 | * You plan out your work in a modular way, to ensure your work can simply be "removed" and it falls back into an alternate state. 22 | * Provides a smooth release path for you to deploy your code. 23 | * Gives your on-call developers a very simple resolution if they get woken up at 1am to fix it. 24 | * It also will make it easier to configure your different features for different geolocations for example - Italian users shouldn't see this, but everyone else should. 25 | 26 | If there is a large cognitive overhead of having too many flags in your system, you can always remove the flag once your feature is bedded in. 27 | -------------------------------------------------------------------------------- /principles/code-should-work-but-does-not-have-to-be-efficient.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Code should work, but does not have to be efficient." 3 | tags = ["code", "team", "medium", "performance", "phase", "sdlc", "mvp"] 4 | summary = "" 5 | authors = ["AdamCraven"] 6 | contributors = [""] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "3b4014e3-9da4-4059-9659-76fdd6505f68" 12 | +++ 13 | Don't worry about optimizing code. Rely on the computer to do the work. Compute or derive values when possible. When you have a small user base, a small amount of data and huge amounts of CPU available, performance isn't a concern. Why? Performant code tends to be much more complicated code and will slow down delivery. 14 | 15 | ## Phase 16 | This principle is useful for early phases of the Software Development Life Cycle (SDLC) such an MVP. 17 | -------------------------------------------------------------------------------- /principles/compute-properties-when-possible.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Compute properties when possible" 3 | summary = "" 4 | tags = ["bug free", "practices"] 5 | authors = ["AdamCraven"] 6 | contributors = [] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | uid = "blue-tiger-odette" 10 | +++ 11 | 12 | Computed (or Derived) properties are properties that don't store values in memory, but return values when they are called by reading values from other properties or functions. 13 | 14 | ## Why 15 | 16 | - Computed properties are easy to reason about. The relationships between properties are explicit and the ‘recipe’ for creating the property can be seen in the code where its method exists. 17 | - There are less properties to set, so no bugs are created as a consequence of forgetting to do that. 18 | - Computed properties lend themselves well to unit testing by having pre-defined inputs, which increases confidence in the code. 19 | - When upstream data changes, dependent downstream computed data will automatically be set into the correct state. 20 | 21 | ## How 22 | 23 | The following properties can be converted to computed properties: 24 | 25 | ### Properties that rely on bringing together more than one property to return a value. 26 | 27 | In this example, the 'fullName' property relies on firstName and lastName to return a value. 28 | 29 | ```js 30 | class User { 31 | constructor(firstName, lastName) { 32 | this.firstName = firstName; 33 | this.lastName = lastName; 34 | this.fullName = `${firstName} ${lastName}`; 35 | } 36 | } 37 | ``` 38 | 39 | Which should be computed to produce an output: 40 | 41 | ```js 42 | class User { 43 | constructor(firstName, lastName) { 44 | this.firstName = firstName; 45 | this.lastName = lastName; 46 | } 47 | get fullName() { 48 | // Computed property 49 | return `${this.firstname} ${this.lastName}`; 50 | } 51 | } 52 | ``` 53 | 54 | ### Properties that are transformed before they are saved 55 | 56 | Properties that are adjusted before they are saved on a write: 57 | 58 | ```js 59 | class Product { 60 | setWeight(weightInGrams) { 61 | this.weightInGrams = weightInGrams; 62 | this.weightInKg = convertToKg(weightInGrams); 63 | this.weightInPounds = convertToPounds(weightInGrams); 64 | } 65 | } 66 | ``` 67 | 68 | Should instead become properties that are computed on read: 69 | 70 | ```js 71 | class Product { 72 | setWeight(weightInGrams) { 73 | this.weightInGrams = weightInGrams; 74 | } 75 | get weightInKg() { 76 | return convertToKg(this.weightInGrams); 77 | } 78 | get weightInPounds() { 79 | return convertToPounds(this.weightInGrams); 80 | } 81 | } 82 | ``` 83 | 84 | ## Exceptions 85 | 86 | - **When performance is critical**. Computed properties are slower to access than values directly stored in memory. 87 | 88 | ## Resources 89 | 90 | - Swift implementation of computed properties: https://docs.swift.org/swift-book/LanguageGuide/Properties.html#ID259 91 | - VueJS explanation https://vuejs.org/v2/guide/computed.html 92 | -------------------------------------------------------------------------------- /principles/consistent-code-automatically-enforced.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Use consistent coding conventions, automatically enforced" 3 | summary = "Code should be formatted the same way and enforced automatically using tools." 4 | tags = ["strategic", "team", "full-stack", "practices"] 5 | authors = ["AdamCraven"] 6 | contributors = [] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | uid = "ivory-hornet-dolley" 10 | +++ 11 | 12 | Code should be formatted the same way and enforced automatically using tools. 13 | 14 | ## Why 15 | 16 | - Code is read much more often than it is written. The more familiar the conventions the less time is spent on code reviews, visual parsing and code comprehension. 17 | - Code conventions are learned quickly. Automatic enforcement exposes the developer repeatedly to the same errors making learning comfortable and at their own pace. 18 | - Less mistakes. Code errors are raised straight away. In some cases they are fixed automatically. 19 | - Constrains choices. More focus on engineering problems rather than distracted by inconsistent code or uncommon language features. 20 | - Reduces conflict. Minor decisions, such as spacing and formatting, no longer need to be debated. 21 | 22 | ## How 23 | 24 | - Use a static language to prevent errors. 25 | - Use a linter (e.g. eslint, python) or formatter (e.g. gofmt) to enforce standards. 26 | - Adhere to common language conventions or standards (e.g. Python's pep8). 27 | - In languages where a common convention hasn't been decided. Opt for popular third party configurations. There will be a higher chance that this will make third party libraries easier to read and the rules can be reduced to suit the teams preferences. 28 | - Link tools to IDE/Editor for rapid feedback. 29 | 30 | [//]: # "## Article" 31 | [//]: # "Code is read much more often than it is written. So it should be that care it taken " 32 | [//]: # "Consistent code helps everyone on the team by reducing. " 33 | [//]: # "1. Show autofixing functionlity is eslint." 34 | [//]: # "It is significantly harder as a team to decide on possibly unknown individual rules from scratch and build your own standard." 35 | [//]: # "Gofmt's style is no one's favorite, yet gofmt is everyone's favorite." 36 | 37 | ## References 38 | 39 | https://www.python.org/dev/peps/pep-0008/ 40 | -------------------------------------------------------------------------------- /principles/core-logic-separate-from-framework.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Separate core logic from the framework" 3 | summary = "Core logic that is related to solving a business or domain problem should exist outside of a framework." 4 | tags = ["organization", "strategic", "architecture", "full-stack", "practices"] 5 | authors = ["AdamCraven"] 6 | contributors = [] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | crystalized = false 10 | uid = "lavender-pinniped-wanids" 11 | +++ 12 | 13 | Core logic that is related to solving a business or domain problem should exist outside of a framework. 14 | 15 | ## Why 16 | 17 | - Core logic is the most valuable asset of the business. A framework change with the core logic integrated results in a loss of that asset. Separation from the framework keeps the asset whilst allowing the framework to change. 18 | - Separating core logic lets you use your own principles instead of the frameworks. Frameworks provide structure and useful abstractions that make engineering easier. Yet, using a framework often means using its principles at the expense of your own. 19 | - You can solve your business problem better. Because a framework is not created to solve your particular problem, it cannot know the best way to solve it. 20 | - Code is easier to read. You only need to understand the programming language, not the framework. 21 | - Code is easier to test. It is not wrapped in a framework's abstractions. 22 | ## How 23 | 24 | * Abstract code that is wrapped inside the framework to separate files 25 | * Use software engineering concepts such as domain-driven design to structure code based on business requirements. 26 | * Use principles to give the team confidence and create autonomy to design a system. 27 | * Use design patterns and principles when designing a system. e.g. repository pattern, inversion of control, solid principles, etc. 28 | 29 | ## Article 30 | 31 | One of the most costly decisions I've come across in Software Engineering that must cost billions in lost value is building business logic entirely inside the confines of a framework. 32 | 33 | Business logic wrapped entirely inside a framework is a bit like living in a house and nailing all your items in place. You can't take anything with you when you leave except your memories. Moving house means all your precious items get left behind. 34 | 35 | This analogy often happens with frameworks; instead of using the framework as a tool, all business logic is put inside and becomes inseparable. 36 | 37 | Changing the framework means losing that asset. 38 | 39 | ### It takes experience 40 | 41 | It is the dividing line between an experienced software engineer and a junior: *Juniors rely on frameworks - senior ones use frameworks as tools.* 42 | 43 | It is why experienced software engineers are more valuable to businesses in the long run. 44 | 45 | It also applies to teams: *Unaligned teams **have** to rely on frameworks - aligned ones can use frameworks as tools.* 46 | 47 | It is why principles are so helpful - they align teams. 48 | 49 | ## Basic example of abstracting code from a framework 50 | 51 | The below example is from a redux framework in which a reducer - a redux concept - adds a todo item into the application: 52 | 53 | ```js 54 | function nextTodoId(todos) { 55 | const maxId = todos.reduce((maxId, todo) => Math.max(todo.id, maxId), -1); 56 | return maxId + 1; 57 | } 58 | 59 | function todosReducer(state = initialState, action) { 60 | switch (action.type) { 61 | case "todos/todoAdded": { 62 | return [ 63 | ...state, 64 | // Core logic start 65 | { 66 | id: nextTodoId(state), 67 | text: action.payload, 68 | completed: false, 69 | }, 70 | // Core logic end 71 | ]; 72 | } 73 | } 74 | } 75 | ``` 76 | 77 | Extracting the core logic, the framework code now looks like this: 78 | 79 | ```js 80 | import { todoAdd } from "./todo"; 81 | 82 | function todosReducer(state = initialState, action) { 83 | switch (action.type) { 84 | case "todos/todoAdded": { 85 | return todoAdd(state, action.payload); 86 | } 87 | } 88 | } 89 | ``` 90 | 91 | Core logic is then moved into a new file. Separate from the framework. 92 | 93 | ```js 94 | function nextTodoId(todos) { 95 | const maxId = todos.reduce((maxId, todo) => Math.max(todo.id, maxId), -1); 96 | return maxId + 1; 97 | } 98 | 99 | function todoAdd(todos, text) { 100 | const nextId = nextTodoId(todos); 101 | const newToDoEntry = { 102 | id: nextId, 103 | text: text, 104 | completed: false, 105 | }; 106 | return { ...todos, newToDoEntry }; 107 | } 108 | ``` 109 | 110 | ## Exceptions 111 | 112 | - If your core logic is trivial or has limited business value. 113 | -------------------------------------------------------------------------------- /principles/dependency-inversion-principle.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Dependency Inversion Principle" 3 | tags = ["solid", "practices", "code", "team", "organization", "rdt"] 4 | summary = "high level modules should not depend on low level modules; both should depend on abstractions." 5 | authors = [] 6 | contributors = ["AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "c50cbafb-e53a-479a-9e66-1d74d9526099" 12 | +++ 13 | The Dependency Inversion Principle (DIP) states that _** high-level modules should not depend on low-level modules; both should depend on abstractions. Abstractions should not depend on details. Details should depend upon abstractions**_. 14 | 15 | It's extremely common when writing software to implement it such that each module or method refers explicitly to its collaborators, which does the same. This type of programming typically lacks sufficient layers of abstraction and results in a very tightly coupled system, since every module directly references lower-level modules. 16 | 17 | **Example 1** 18 | 19 | Consider a user interface form with a button. When the button is clicked, an event is fired. A new instance of a Business Logic Layer (BLL) class is created within the event, and one of its methods is called. Within the BLL class's method, a new instance of a Data Access Layer (DAL) class is created, and one of its methods is called. This method in turn, makes a database query. 20 | 21 | The result of this approach is that everything in the system is tightly coupled to the database. The dependency tree goes UI -> BLL -> DAL -> DB, and these dependencies are transitive. These classes and methods are all tightly coupled together because of the direct instantiation that is occurring (Remember: [New is Glue](http://ardalis.com/new-is-glue)), though you will also see this behavior if you use static method calls. The way to correct this design problem is to apply the Dependency Inversion Principle, which typically begins with introducing new interfaces. 22 | 23 | **Example 2** 24 | 25 | Consider a user interface form with a button. When the button is clicked, an event is fired. In response to the event, a private member of the form, whose type is simply an interface, has one of its methods called. The 'new' keyword is nowhere to be found in the click event handler. The interface implementation is provided when the form is created through a process known as Dependency Injection. Likewise, suppose this method provides key business logic and requires access to the system's persistence layer. In that case, it, too may specify (explicitly in its constructor) one or more interfaces that it depends on, which may include implementations of the Repository pattern. No static method calls or 'new' keywords will exist in the business logic class's method, either. 26 | 27 | [Shifting from traditional, data-centric N-Tier architecture to a more domain-centric N-Tier architecture](http://www.pluralsight.com/courses/n-tier-apps-part1) and potentially to the full application of [Domain-Driven Design](http://bit.ly/PS-DDD) can yield great maintainability benefits for projects. The end result is a system that is loosely coupled, modular, and easily tested. 28 | 29 | ## See Also 30 | 31 | * [Explicit Dependencies Principle](/p/explicit-dependencies-principle) 32 | * [Hollywood Principle](/p/hollywood-principle) 33 | 34 | ## References 35 | 36 | * [New is Glue](http://ardalis.com/new-is-glue) 37 | * [Architecting N-Tier Solutions in C#](http://www.pluralsight.com/courses/n-tier-apps-part1) (Pluralsight) 38 | * [SOLID Principles of Object Oriented Design](https://www.pluralsight.com/courses/principles-oo-design) (Pluralsight) 39 | * [Domain-Driven Design Fundamentals](http://bit.ly/PS-DDD) (Pluralsight) 40 | 41 | ## Derivative work 42 | 43 | > This work is a derivative of "Dependency Inversion Principle" by deviq, originally licensed under MIT. The original version can be found [here](https://deviq.com/principles/dependency-inversion-principle). -------------------------------------------------------------------------------- /principles/documentation-close-to-code.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Documentation should be close to the code" 3 | summary = "Documentation, in all forms, should be as close as it can be to the code." 4 | tags = ["documentation", "code", "practices"] 5 | license = "CC BY-SA 4.0" 6 | allow_dual_licensing_to_GPLv3 = true 7 | authors= ["AdamCraven"] 8 | contributors = [] 9 | uid = "teal-beaver-sandye" 10 | +++ 11 | Documentation, in all forms, should be as close as it can be to the code. 12 | 13 | ## Why 14 | 15 | - You will use the documentation. Less _friction_ equals more use. The further away documentation is, the less likely you will use it. 16 | - Higher accuracy. As it is readily accessible for developers to edit. 17 | - Up to date. Documentation checked in with the code will be applicable for that version of the code. 18 | 19 | ## How 20 | 21 | - Keep the documentation with the source code. 22 | - Use tools to generate external documentation from within the project rather than creating external wikis. 23 | 24 | ## Article 25 | 26 | The goal is to bring documentation as close to the code as possible while maintaining a grouping that makes sense. 27 | 28 | Below are specific examples of how this can be achieved in each area, starting close to the code and getting further away. 29 | 30 | ### Your Editor - Use IDE features 31 | 32 | Use an editor with code completion, parameter info, quick info, and member lists. It provides the closest documentation by assisting a developer during the writing of code. 33 | 34 | An example is Visual Studio Code's Intellisense: https://code.visualstudio.com/docs/editor/intellisense 35 | 36 | ### Comments - Next to the code 37 | 38 | Commented code is a natural application of this principle that most developers naturally do. 39 | 40 | You can **generate accurate documentation** from commented code. It means there will be no need for separate files to document the API. Additionally, it will more often be seen, referred to, and monitored (e.g., during code review), increasing the chance someone will keep it to date. 41 | 42 | ### Unit tests - Next to the code files 43 | 44 | Unit tests are not just tests, but documentation, some of the best forms of documentation. Your tests should be next to the source code file. It also provides an additional benefit of being able to see which files have already got tests. 45 | 46 | ### Isolated components - Next to the component 47 | 48 | 49 | Isolated components are components that are loaded separately from an application. They are clear examples of how you can use components. As with unit tests, they act as some of the best documentation available. It explicitly shows the dependencies, how the component works and what options are available for configuring the component. 50 | 51 | Put them in the same folder as the component, don't separate them. Using a library like https://storybook.js.org/ 52 | 53 | ### Integration tests - Within the module or application 54 | 55 | Integration tests (http://softwaretestingfundamentals.com/integration-testing/), test the interaction of more than one module, often using a tool such as selenium or cypress. Integration tests related to a single module should exist next to that module if the module can be run standalone. Integration tests more commonly test the interaction of multiple modules interacting together and should be grouped with the application folder. 56 | 57 | ### General documentation - Within the codebase 58 | 59 | General documentation should be next to the code. A typical implementation is README.md files in markdown format. They should exist within the applicable logical grouping within a codebase (e.g., a module or app folder that is most relevant). It is common to see README.md files at the top level of a project, but they can exist at any level. The top-level README.md can act as an index which references or links to other README.md files within folders below. 60 | 61 | ### External documentation - generated from the project 62 | 63 | External documentation - used for communicating to people external of your team - should exist within a codebase where possible and then exported to an external wiki or a generated web page rather than an external wiki edited away from the codebase. 64 | -------------------------------------------------------------------------------- /principles/documentation-easy-to-amend.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Ensure documentation is easy to amend" 3 | summary = "When encountering documentation, it should be easy to make changes." 4 | tags = ["documentation", "code", "practices"] 5 | license = "CC BY-SA 4.0" 6 | allow_dual_licensing_to_GPLv3 = true 7 | authors= ["AdamCraven"] 8 | contributors = [] 9 | uid = "brown-sawfish-neala" 10 | +++ 11 | 12 | When encountering documentation, it should be easy to make changes. 13 | 14 | ## Why 15 | 16 | - Increases the chances that the documentation will be correct. 17 | - Increase productivity through accurate documentation. 18 | 19 | ## How 20 | 21 | - Prioritize write access to the code base for all members, especially new members of the team. It's often the time they are most likely to find errors and update, but usually have the least access to do so. 22 | - Encourage developers to update any inaccurate documentation. 23 | -------------------------------------------------------------------------------- /principles/dont-add-unneeded-context.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Don't add unneeded context" 3 | tags = ["variables", "code", "rule", "code review", "clean code"] 4 | summary = "Don't add the class/object names to properties" 5 | authors = [] 6 | contributors = ["AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source = "https://github.com/ryanmcdermott/clean-code-javascript" 10 | original_source_is_canonical = false 11 | crystalized = false 12 | uid = "0977e551-cf55-4497-acc7-91fd8f291eef" 13 | +++ 14 | 15 | If your class/object name tells you something, don't repeat that in your variable name. 16 | 17 | Bad: 18 | ```js 19 | const Car = { 20 | carMake: "Honda", 21 | carModel: "Accord", 22 | carColor: "Blue" 23 | }; 24 | 25 | function paintCar(car, color) { 26 | car.carColor = color; 27 | } 28 | ``` 29 | 30 | Good: 31 | ```js 32 | const Car = { 33 | make: "Honda", 34 | model: "Accord", 35 | color: "Blue" 36 | }; 37 | 38 | function paintCar(car, color) { 39 | car.color = color; 40 | } 41 | ``` 42 | 43 | ## Why 44 | 45 | * Context is already understood. You know that if you are in a class/object, adjusting the properties relate to that class/object. 46 | 47 | ## Derivative work 48 | 49 | > This work is a derivative of "clean-code-javascript" by Ryan Mcdermott, originally licensed under MIT. The original version can be found [here](https://github.com/ryanmcdermott/clean-code-javascript/tree/3ff9eba6d460f31db8146762bade4fcc32626762). -------------------------------------------------------------------------------- /principles/elon-musk-requirement-principle-requirements-belong-to-individuals-not-teams.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Musk requirement principle" 3 | tags = ["organization", "leadership", "epic", "strategic"] 4 | summary = "Requirements belong to individuals, not teams" 5 | authors = ["Elon Musk"] 6 | contributors = ["AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "70cdf57a-a79d-492e-bbfc-4245804ebcb2" 12 | +++ 13 | Requirements must belong to an individual, not a team or department. The person putting forward the requirement or constraint must agree that they must take responsibility for that requirement. 14 | 15 | ## Why 16 | 17 | - You may build something that isn't needed - If it doesn't belong to an individual, there's no one to understand why the requirement is essential. 18 | - You may build something that nobody wants - If an individual isn't assigned and leaves the team, it can get lost in project backlogs and end up being made, even though no one wants it. 19 | - Individuals can take ownership because they may be the only person that understands. When building a complicated thing (e.g. a space rocket or software engineering project), there are often many hyper-specialised people who have profound knowledge about the individual characteristics of a part of that project. That knowledge may be impossible for the team to know and answer questions; thus, the individual should own it. 20 | 21 | ---- 22 | 23 | The principle originated from Elon Musk, during his Starbase Tour: [https://www.youtube.com/watch?v=t705r8ICkRw&t=958s](https://www.youtube.com/watch?v=t705r8ICkRw&t=958s) 24 | 25 | Here's the transcript: 26 | 27 | "Whatever requirement or constraint you have, it must come with a name, not a department. " 28 | 29 | "Cause you can't ask the departments, you have to ask a person and that person who's putting forward the requirement or constraint must agree that they must take responsibility for that requirement." 30 | 31 | "Otherwise you could have a requirement that basically an intern two years ago randomly came up, off the cuff, and they're not even at the company anymore. " 32 | 33 | "But it came from the, let's say, Aero[dynamic] loads department. They're like, actually, there's no one in our department that actually agrees with that." 34 | 35 | "This has happened several times. And actually, there's no one at the department that currently agrees with that." 36 | -------------------------------------------------------------------------------- /principles/ensure-ui-components-can-be-loaded-separately-from-an-application.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Ensure UI components can be loaded separately from an application" 3 | tags = ["front-end", "bug free", "practices"] 4 | summary = "" 5 | authors = ["AdamCraven"] 6 | contributors = [] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "3bebda8d-9857-43e4-bcee-eb4962f58213" 12 | +++ 13 | A component, which could be something as simple as a button or more complex - such as a video player - must load without the rest of the application. The most well-known versions of this concept are in the form of style guides or component libraries. 14 | 15 | A couple of examples: 16 | 17 | * [Lonely Planets Styleguide](https://rizzo.lonelyplanet.com/styleguide/ui-components/alerts) 18 | * [Bootstrap](https://getbootstrap.com/docs/5.1/components/accordion/) 19 | 20 | ## Why 21 | 22 | 1. Encourages separation of concerns. Loading the component without loading the application ensures explicit dependencies and encourages good separation of concerns. 23 | 2. Interaction tests (e.g., using Selenium/Cypress) can be run on a component individually. The interaction tests are less brittle and can focus on the component rather than load the application and force it into the desired state before the tests run. 24 | 3. It allows quick discovery of unspecified states missed in the design specification. Toggling controls can view all states of the component, either with a debug UI such as [tweakpane](https://cocopon.github.io/tweakpane/) or a custom made one. It allows the discovery of unspecified states and is a quick way to test a component. 25 | 4. It speeds up development. You can do all initial development without having to load the rest of the application. The component can be loaded quickly, and the desired state can be configured or toggled. Compare this to the more common alternative: load up the whole app, navigate to that component and test each of its states by interacting with the application in pre-determined ways - which is much slower. 26 | 5. It provides excellent documentation. Having working examples of the component shows exactly how to load, use and configure the component. Combined with a debug UI, which exposes all of the component's intended configurations, it is the best documentation possible. 27 | 28 | ## How 29 | 30 | * Use a library like https://storybook.js.org/ to load your components 31 | * Create a separate bootstrapping (start-up script) HTML file where you can load up your component outside the application 32 | 33 | ## When to use 34 | 35 | It's not always necessary to have a complete style guide. They are helpful in larger UI projects with larger respective budgets. What is essential is the ability to load the component independently without loading the rest of the application. 36 | -------------------------------------------------------------------------------- /principles/explicit-dependencies-principle.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Explicit Dependencies Principle" 3 | tags = ["code", "team", "organization", "rdt"] 4 | summary = "Methods and classes should explicitly require any collaborating objects they need in order to function correctly" 5 | authors = [] 6 | contributors = ["AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "8aae10ca-79eb-46ea-946b-fe2d594b9701" 12 | +++ 13 | Methods and classes should explicitly require (typically through method parameters or constructor parameters) any collaborating objects they need in order to function correctly. 14 | 15 | If your classes require other classes to perform their operations, these other classes are dependencies. These dependencies are implicit if they exist only in the code within your class, and not in its public interface. Explicit dependencies appear most often in an object's constructor, for class-level dependencies, or in a particular method's parameter list, for more local dependencies. 16 | 17 | Classes with implicit dependencies cost more to maintain than those with explicit dependencies. They are more challenging to test because they are more tightly coupled to their collaborators. They are more challenging to analyze for side effects, because the entire class's codebase must be searched for object instantiations or calls to static methods. They are more brittle and more tightly coupled to their collaborators, resulting in more rigid and brittle designs. 18 | 19 | Classes with explicit dependencies are more honest. They state very clearly what they require in order to perform their particular function. They tend to follow the [Principle of Least Surprise](http://en.wikipedia.org/wiki/Principle_of_least_astonishment) by not affecting parts of the application they didn't explicitly demonstrate they needed to affect. Explicit dependencies can easily be swapped out with other implementations, whether in production or during testing or debugging. This makes them much easier to maintain and far more open to change. 20 | 21 | The Explicit Dependencies Principle is closely related to the [Dependency Inversion Principle](/p/dependency-inversion-principle) and the [Hollywood Principle](/p/hollywood-principle). 22 | 23 | Consider the PersonalizedResponse class in this Gist, which can be constructed without any dependencies: 24 | 25 | ## Implicit Dependencies Example 26 | 27 | ```java 28 | using System; 29 | using System.IO; 30 | using System.Linq; 31 | 32 | namespace ImplicitDependencies 33 | { 34 | class Program 35 | { 36 | static void Main(string[] args) 37 | { 38 | var customer = new Customer() 39 | { 40 | FavoriteColor = "Blue", 41 | Title = "Mr.", 42 | Fullname = "Steve Smith" 43 | }; 44 | Context.CurrentCustomer = customer; 45 | 46 | var response = new PersonalizedResponse(); 47 | 48 | Console.WriteLine(response.GetResponse()); 49 | Console.ReadLine(); 50 | } 51 | } 52 | 53 | public static class Context 54 | { 55 | public static Customer CurrentCustomer { get; set; } 56 | 57 | public static void Log(string message) 58 | { 59 | using (StreamWriter logFile = new StreamWriter( 60 | Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), 61 | "logfile.txt"))) 62 | { 63 | logFile.WriteLine(message); 64 | } 65 | } 66 | } 67 | 68 | public class Customer 69 | { 70 | public string FavoriteColor { get; set; } 71 | public string Title { get; set; } 72 | public string Fullname { get; set; } 73 | } 74 | 75 | public class PersonalizedResponse 76 | { 77 | public string GetResponse() 78 | { 79 | Context.Log("Generating personalized response."); 80 | string formatString = "Good {0}, {1} {2}! Would you like a {3} widget today?"; 81 | string timeOfDay = "afternoon"; 82 | if (DateTime.Now.Hour < 12) 83 | { 84 | timeOfDay = "morning"; 85 | } 86 | if (DateTime.Now.Hour > 17) 87 | { 88 | timeOfDay = "evening"; 89 | } 90 | return String.Format(formatString, timeOfDay, 91 | Context.CurrentCustomer.Title, 92 | Context.CurrentCustomer.Fullname, 93 | Context.CurrentCustomer.FavoriteColor); 94 | } 95 | } 96 | } 97 | ``` 98 | 99 | This class is clearly tightly coupled to the file system and the system clock, as well as a particular customer instance via the global Context class. If we were to refactor this class to make its dependencies explicit, it might look something like this: 100 | 101 | ## Explicit Dependencies Example 102 | 103 | ```java 104 | using System; 105 | using System.IO; 106 | using System.Linq; 107 | 108 | namespace ExplicitDependencies 109 | { 110 | class Program 111 | { 112 | static void Main(string[] args) 113 | { 114 | var customer = new Customer() 115 | { 116 | FavoriteColor = "Blue", 117 | Title = "Mr.", 118 | Fullname = "Steve Smith" 119 | }; 120 | 121 | var response = new PersonalizedResponse(new SimpleFileLogger(), new SystemDateTime()); 122 | 123 | Console.WriteLine(response.GetResponse(customer)); 124 | Console.ReadLine(); 125 | } 126 | } 127 | 128 | public interface ILogger 129 | { 130 | void Log(string message); 131 | } 132 | 133 | public class SimpleFileLogger : ILogger 134 | { 135 | public void Log(string message) 136 | { 137 | using (StreamWriter logFile = new StreamWriter( 138 | Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), 139 | "logfile.txt"))) 140 | { 141 | logFile.WriteLine(message); 142 | } 143 | } 144 | } 145 | 146 | public interface IDateTime 147 | { 148 | DateTime Now { get; } 149 | } 150 | 151 | public class SystemDateTime : IDateTime 152 | { 153 | public DateTime Now 154 | { 155 | get 156 | { 157 | return DateTime.Now; 158 | } 159 | } 160 | } 161 | 162 | public class Customer 163 | { 164 | public string FavoriteColor { get; set; } 165 | public string Title { get; set; } 166 | public string Fullname { get; set; } 167 | } 168 | 169 | public class PersonalizedResponse 170 | { 171 | private readonly ILogger _logger; 172 | 173 | private readonly IDateTime _dateTime; 174 | 175 | public PersonalizedResponse(ILogger logger, 176 | IDateTime dateTime) 177 | { 178 | this._dateTime = dateTime; 179 | this._logger = logger; 180 | } 181 | 182 | public string GetResponse(Customer customer) 183 | { 184 | _logger.Log("Generating personalized response."); 185 | string formatString = "Good {0}, {1} {2}! Would you like a {3} widget today?"; 186 | string timeOfDay = "afternoon"; 187 | if (_dateTime.Now.Hour < 12) 188 | { 189 | timeOfDay = "morning"; 190 | } 191 | if (_dateTime.Now.Hour > 17) 192 | { 193 | timeOfDay = "evening"; 194 | } 195 | return String.Format(formatString, timeOfDay, 196 | customer.Title, 197 | customer.Fullname, 198 | customer.FavoriteColor); 199 | } 200 | } 201 | } 202 | ``` 203 | 204 | In this case, the logging and time dependencies have been pulled into constructor parameters, while the customer being acted upon has been pulled into a method parameter. The end result is code that can only be used when the things it needs have been provided for it (and whether you scope dependencies at the class or method level will depend on how the class uses them, how many methods reference the item in question, etc. - both options are shown here even though in this case everything could simply have been provided as method parameters). 205 | 206 | ## See Also 207 | 208 | * [Dependency Inversion Principle](/p/dependency-inversion-principle/) 209 | 210 | ## References 211 | 212 | * [New Is Glue](http://ardalis.com/new-is-glue) 213 | 214 | ## Derivative work 215 | 216 | > This work is a derivative of "Explicit Dependencies Principle" by deviq, originally licensed under MIT. The original version can be found [here](https://deviq.com/principles/explicit-dependencies-principle). -------------------------------------------------------------------------------- /principles/figure-out-the-problem-before-the-technology.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Figure out the problem, before the technology" 3 | tags = ["organisation", "problem-solving", "team"] 4 | summary = "Understand the problem first, then choose the appropriate technology to solve it." 5 | authors = ["AdamCraven"] 6 | contributors = [""] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "8d0d0a58-b85e-4837-820d-28acf80bbd7b" 12 | +++ 13 | Understand the problem first, then choose the appropriate technology to solve it. 14 | 15 | Choosing a technology before understanding the problem can lead to - at worst - disastrous business ending results. For example, your business needs to accept card payments from users. A small team might build a multi-cloud microservice architecture aiming for 99.9999% uptime (2.6s of downtime a month), that can scale to millions of users on thousands of machines written in the latest high-performance language. But the problem is accepting card payments for *a few thousand users*, not millions. A single integrated service that runs on 1 or 2 machines, with 99.9% uptime (43m 28s of downtime a month), would be more than adequate, be ready a year or two earlier, and at a lower level of complexity. Those missed card payments due to downtime will amount to a tiny proportion compared to the millions spent for the first over-engineered solution that may never release. Later on, once the app is running, you can evolve towards towards whatever the optimal solution may be. 16 | 17 | Why does this happen in the first place? Technology is concrete, whilst problems are often abstract. It's much easier, and often more fun, to choose a technology and get direct feedback straight away rather than spend more effort on the initial cognitively demanding task of figuring out a problem (inevitably, wrong technology choices increase the cognitive load later on). Also, many teams are incentivised to learn a new technology rather than solve the problem (i.e. improve your CV). 18 | 19 | ## Why 20 | 21 | * You build the application that is fitted to the problem from the beginning. 22 | * It potentially allows the business to reduce its costs, earn millions in revenue, and billions in increased valuation - if you are incentivised appropriately, this is win-win. 23 | * Avoids a prolonged development time, where you are getting no feedback. 24 | 25 | ## How 26 | 27 | * Align incentives in the business to ensure that engineers benefit from the app being released. Without these incentives, engineers can be more aligned to improving their skillset rather than achieving business goals. 28 | * Apply root-cause analysis methods like the [Many Whys](https://manywhys.org) to figure out your problem. 29 | * Spend time upfront sketching out your application's business needs, working on the domain and ignoring the technology. 30 | * [Reduce a problem to its lowest sensible abstraction](https://principles.dev/p/reduce-a-problem-to-its-lowest-sensible-abstraction/) from the beginning. 31 | 32 | 33 | ## Key Takeaways 34 | 35 | * Understand the problem before choosing the technology. 36 | * Overly complex solutions often stem from prioritising technology over the problem. 37 | * Proper understanding avoids unnecessary costs, prolonged development time, and misalignment with business needs. 38 | * Aligned incentives shift the focus from learning new technologies to solving problems. -------------------------------------------------------------------------------- /principles/function-arguments-ideally-use-2-or-fewer.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Function arguments, ideally use 2 or fewer" 3 | tags = ["functions", "code", "rule", "code review", "javascript", "clean code"] 4 | summary = "" 5 | authors = [] 6 | contributors = ["AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source = "https://github.com/ryanmcdermott/clean-code-javascript" 10 | original_source_is_canonical = false 11 | crystalized = false 12 | uid = "23ca8406-6aec-4cd0-894d-04f3f9b84f99" 13 | +++ 14 | Limiting the number of function parameters is incredibly important because it makes testing your function easier. Having more than three leads to a combinatorial explosion where you have to test tons of different cases with each separate argument. 15 | 16 | One or two arguments is the ideal case, and you should avoid three if possible. You should consolidate anything more than that. Usually, if you have more than two arguments, then your function is trying to do too much. In cases where it's not, a higher-level object will suffice as an argument most of the time. 17 | 18 | Since JavaScript allows you to make objects on the fly without a lot of class boilerplate, you can use an object if you are finding yourself needing a lot of arguments. 19 | 20 | To make it obvious what properties the function expects, you can use the ES2015/ES6 destructuring syntax. This has a few advantages: 21 | 22 | 1. When someone looks at the function signature, it's immediately apparent what properties you are using. 23 | 2. You can use it to simulate named parameters. 24 | 3. Destructuring also clones the specified primitive values of the argument object passed into the function. This can help prevent side effects. Note: objects and arrays that are destructured from the argument object are NOT cloned. 25 | 4. Linters can warn you about unused properties, which would be impossible without destructuring. 26 | 27 | 28 | Bad: 29 | ```js 30 | function createMenu(title, body, buttonText, cancellable) { 31 | // ... 32 | } 33 | 34 | createMenu("Foo", "Bar", "Baz", true); 35 | ``` 36 | 37 | Good: 38 | ```js 39 | function createMenu({ title, body, buttonText, cancellable }) { 40 | // ... 41 | } 42 | 43 | createMenu({ 44 | title: "Foo", 45 | body: "Bar", 46 | buttonText: "Baz", 47 | cancellable: true 48 | }); 49 | ``` 50 | 51 | ## Derivative work 52 | 53 | > This work is a derivative of "clean-code-javascript" by Ryan Mcdermott, originally licensed under MIT. The original version can be found [here](https://github.com/ryanmcdermott/clean-code-javascript/tree/3ff9eba6d460f31db8146762bade4fcc32626762). -------------------------------------------------------------------------------- /principles/function-names-should-say-what-they-do.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Function names should say what they do" 3 | tags = ["functions", "code", "rule", "code review", "clean code"] 4 | summary = "" 5 | authors = [] 6 | contributors = ["AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source = "https://github.com/ryanmcdermott/clean-code-javascript" 10 | original_source_is_canonical = false 11 | crystalized = false 12 | uid = "b943e48e-0b1b-4874-9877-d3773e23a8c9" 13 | +++ 14 | --- 15 | 16 | Bad: 17 | ```js 18 | function addToDate(date, month) { 19 | // ... 20 | } 21 | 22 | const date = new Date(); 23 | 24 | // It's hard to tell from the function name what is added 25 | addToDate(date, 1); 26 | ``` 27 | 28 | Good: 29 | ```js 30 | function addMonthToDate(month, date) { 31 | // ... 32 | } 33 | 34 | const date = new Date(); 35 | addMonthToDate(1, date); 36 | ``` 37 | 38 | ## Why 39 | 40 | * It aids rapid understanding of what a function does without reading all the source code or referring to tests. 41 | 42 | ## Derivative work 43 | 44 | > This work is a derivative of "clean-code-javascript" by Ryan Mcdermott, originally licensed under MIT. The original version can be found [here](https://github.com/ryanmcdermott/clean-code-javascript/tree/3ff9eba6d460f31db8146762bade4fcc32626762). -------------------------------------------------------------------------------- /principles/functions-should-do-one-thing.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Functions should do one thing" 3 | tags = ["functions", "code", "rule", "code review", "javascript", "clean code"] 4 | summary = "" 5 | authors = [] 6 | contributors = ["AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source = "https://github.com/ryanmcdermott/clean-code-javascript" 10 | original_source_is_canonical = false 11 | crystalized = false 12 | uid = "6e66534f-2d05-41f5-853f-5d16067077ad" 13 | +++ 14 | When functions do more than one thing, they are harder to compose, test, and reason about. When you can isolate a function to just one action, it can be refactored easily and your code will read much cleaner. 15 | 16 | Bad: 17 | ```js 18 | function emailClients(clients) { 19 | clients.forEach(client => { 20 | const clientRecord = database.lookup(client); 21 | if (clientRecord.isActive()) { 22 | email(client); 23 | } 24 | }); 25 | } 26 | ``` 27 | 28 | Good: 29 | ```js 30 | function emailActiveClients(clients) { 31 | clients.filter(isActiveClient).forEach(email); 32 | } 33 | 34 | function isActiveClient(client) { 35 | const clientRecord = database.lookup(client); 36 | return clientRecord.isActive(); 37 | } 38 | ``` 39 | 40 | ## Derivative work 41 | 42 | > This work is a derivative of "clean-code-javascript" by Ryan Mcdermott, originally licensed under MIT. The original version can be found [here](https://github.com/ryanmcdermott/clean-code-javascript/tree/3ff9eba6d460f31db8146762bade4fcc32626762). -------------------------------------------------------------------------------- /principles/go-wide-then-refine.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Go wide, then refine" 3 | tags = ["team", "domain", "ddd", "practices", "medium", "epic", "leadership"] 4 | summary = "When creating something, it is better to understand the picture - at a high level - instead of focusing on the thing you need to create immediately." 5 | authors = ["AdamCraven"] 6 | contributors = [""] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "75e2631b-e8c6-44be-bd3a-237744d0e735" 12 | +++ 13 | 14 | Focus on the big picture from the beginning and then refine the detail once you have a grasp of the high-level conceptually. Keeping iterating to build a wider picture as necessary. 15 | 16 | When creating something, it is better to understand the picture - at a high level - instead of focusing on the thing you need to create immediately. 17 | 18 | 19 | Suppose a species evolves in a limited environment, such as a cold pool of water. The species will naturally adapt and optimize to that environment. That species when exposed to more varied environments (e.g. jungles, forests, etc.) would take many more generations to adapt to the new environment, than if it had access to those environments from the beginning. 20 | 21 | The analogy applies to designing any system. If you focus on a small part of it from the beginning, not noticing upcoming direction, then change is significantly harder. 22 | 23 | ## Why 24 | 25 | 26 | * Software designed with the known future in mind will be adaptable to future change, it allows a team to see the overall picture and to design a system that can anticipate future change. 27 | * Lightly designing a system from the beginning allows you to peer into the future and see what you're going to need and what you known unknowns you will need to understand. 28 | * It allows other parts of the team or organisation to figure out conceptually what you need to iterate on before it is built. 29 | * The team will make better decisions because they know where they are going. 30 | 31 | 32 | -------------------------------------------------------------------------------- /principles/holywood-principle.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Hollywood Principle" 3 | tags = ["code", "team", "organization", "rdt"] 4 | summary = "Write code to respond to external events, such as from an existing framework" 5 | authors = [] 6 | contributors = ["AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "303fedf2-ab40-4bae-9cc4-cd7d1b184229" 12 | +++ 13 | The Hollywood Principle states, "Don't Call Us, We'll Call You." It's closely related to the [Dependency Inversion Principle](/p/dependency-inversion-principle), and illustrates a different way of writing software from the more traditional form of programming in which one's own code dictates the flow of control. When following the Hollywood Principle, code is written to respond to external events, such as from an existing framework. 14 | 15 | By way of an example, a typical ASP.NET Web Form might have in its codebehind page event handlers to respond to Page_Load and Button_Click events. An ASP.NET developer writes code to respond to these external framework events, instead of owning the execution of the web server and making all decisions and method calls accordingly. Plug-in and extension models for applications frequently must take advantage of the Hollywood Principle in their design, exposing events and similar "hooks" for plug-in modules to use, allowing the overall program to call into the plug-in whenever needed, while avoiding the having the plug-in code take over control of the execution of the entire application. 16 | 17 | ## See Also 18 | 19 | * [Dependency Inversion Principle](/p/dependency-inversion-principle) 20 | 21 | ## References 22 | 23 | * [Inversion of Control](http://martinfowler.com/bliki/InversionOfControl.html) by Martin Fowler 24 | 25 | ## Derivative work 26 | 27 | > This work is a derivative of "Hollywood Principle" by deviq, originally licensed under MIT. The original version can be found [here](https://deviq.com/principles/hollywood-principle). -------------------------------------------------------------------------------- /principles/invisible-visible.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Make the invisible, visible" 3 | summary = "Make relevant information visible so things can be clearly understood" 4 | tags = ["epic", "leadership", "organization", "team", "individual", "strategic", "transparency", "understanding", "relevancy" ] 5 | license = "CC BY-SA 4.0" 6 | allow_dual_licensing_to_GPLv3 = true 7 | authors= ["AdamCraven"] 8 | contributors = [] 9 | uid = "plum-swordfish-binni" 10 | +++ 11 | 12 | "Make the invisible, visible" means revealing the hidden but relevant information so we can understand things clearly. This principle is, in fact, at the root of understanding all things. 13 | 14 | Having access to the relevant details helps us to understand things better so we can work more effectively. It means better behaviours, problem-solving, and results. When the relevant information is invisible, there’s naturally a deficit in understanding. How can you understand anything properly — whether it’s a team, an organization or a code base — if there’s a knowledge gap due to invisible relevant information? 15 | 16 | 17 | ## How to determine relevancy 18 | 19 | In any system you’ll always find more details that are irrelevant than relevant, so it is crucial to be able to determine what is relevant. Let's take a coin as an example of this phenomenon. A coin has two sides, often with the date it was minted on one side and the currency value on the other. Its many other properties include: weight, mass, electrical conductivity, melting point, metallic composition, etc. Focusing on just one of those properties, such as the metallic composition, reveals an even higher number of possible attributes, such as a mixture of numerous elements. Within those elements are various atoms and within the atoms; quarks. Most of those properties are invisible and usually irrelevant, but depending on your perspective, some are relevant but - unfortunately - invisible. To make the invisible visible, we first need to find what information is relevant and then make it visible. 20 | 21 | Two related questions can help you determine relevancy: 22 | 23 | 1. **What information would be helpful for me to understand that I currently don't have?** - This will generate many answers while ignoring your existing limitations. 24 | 2. **What information would be helpful for others to understand that they currently don't have?** - This will help you think about your users and other perspectives. 25 | 26 | Going back to our coin example, you and I probably only care about the monetary value of a coin. But what if you were a precious metal dealer? Now, what is relevant to you about coins is different - we care about what the coin is worth. To know its worth, we need to know the type of precious metal, its quantity, and its purity. 27 | 28 | 29 | 30 | This sixpence is a precious coin, but it wouldn't make a good coin for precious metal dealing as its relevant properties are invisible. We need to find out what it's made from, the weight of that material, and its purity. To make those properties visible, you would need to test the metal to determine its properties or rely on documentation elsewhere. 31 | 32 | 33 | 34 | 35 | 36 | The relevant properties of the Britannia on the other hand, are visible. The coin is made of gold, 1oz of it, with a purity of 999.9 (24 carats). If the sixpence was going to be used in the trading of precious metals, we’d need to make the invisible visible and display its properties in a new design similar to the Britannia. 37 | 38 | 39 | Unfortunately, relevant information is obscured in most systems, limiting our understanding. Behaviours are a widespread example of relevant information being invisible. Hidden behaviours result in teams that are not properly aligned, as well as dysfunctional organizations, and overly complex code bases. Because those behaviours are known in our minds (consciously or not), they’re often not made visible. From a leadership perspective, it means that people don't know how to act. From a coding perspective, engineers don't know why the code is written in the form it is. Problematic hidden behaviours can be addressed by establishing principles that create visible, sharable behaviour which others can interrogate and align to. Making the invisible visible is why we even define principles in the first place. 40 | 41 | 42 | ## Examples 43 | 44 | Further examples of making relevant information visible. 45 | 46 | Data 47 | 48 | * Create visualizations that provide insight.. 49 | * Convert data into visualizations that are easier to understand. (e.g., grafana, splunk) 50 | * Run calculations on the data to understand the content (e.g., average price, top sales) 51 | * Use analytics within a system to increase feedback cycles. 52 | * Reveal hidden patterns through data mining. 53 | 54 | Code 55 | 56 | * Use diagrams. Represent code in less abstract, more concrete ways, such as drawing diagrams of a system using pen and paper or graphics design programs. 57 | * Log and visualize the results of a running application or process. 58 | * Utilize debuggers to peer inside a system and view changes over time rather than the black-box method, which views results from only the input and outputs of the system. 59 | * Use performance tools like flame graphs to visualize the stages of a program. 60 | 61 | Teams 62 | 63 | * Use principles to communicate and build mental models that everyone in the team can share. 64 | * Ask questions that seek to understand and illuminate. 65 | * Ensure all members are able to access information in a coordinated way e.g., what gaps could exist between the technical customer service team and engineers? 66 | * Use personality assessment tools to build alignments within the team of how members prefer to process information, which can be used to create tailored best practices 67 | 68 | 69 | Individuals 70 | 71 | * Identify and share your knowledge, codifying your approach into clear actions and principles. 72 | * Query your assumptions and blind spots to find new ways of identifying relevant information 73 | -------------------------------------------------------------------------------- /principles/iterate-in-thens.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Iterate in Thens" 3 | summary = "You should iterate sequentially on a focused chunk of work at a time." 4 | tags = ["process", "individual", "medium", "full-stack"] 5 | license = "CC BY-SA 4.0" 6 | allow_dual_licensing_to_GPLv3 = true 7 | authors= ["AdamCraven"] 8 | contributors = [] 9 | uid = "red-blackbird-junina" 10 | +++ 11 | 12 | You should iterate sequentially on a focused chunk of work at a time. Once that chunk has been completed THEN start on the next chunk of work. This is opposed to doing multiple chunks of different of work in parallel. 13 | 14 | ## Why 15 | 16 | - No context switching. Sequential working increases the chance that all relevant context associated with a chunk of work be kept in mind. 17 | - Reduced possible errors. Focusing on one change at a time, means the possible outcomes (e.g. bugs, regressions) from that change are much smaller than if many changes are made at the same time. 18 | 19 | ## How 20 | 21 | - Define tasks in a sequential way. 22 | - When working, focus on a single task and capture additional tasks as a separate items. 23 | 24 | ## Article 25 | 26 | Iterating on tasks by focusing on one chunk of work is better than trying to do too many things at once. 27 | 28 | A example task is to upgrade 3 cores libraries that 10 applications use. Here are 3 approaches below: 29 | 30 | ### Iterating with an "ANDs" approach (not recommended): 31 | 32 | 1. Go to the first application 33 | 2. update library 1 **AND** 2 **AND** 3 at the same time 34 | 3. **THEN** move on to the next application 35 | 36 | The complexity arises through having to work with lots of different changes which can look like as follows: 37 | 38 | - Steps required to update 3 libraries. 39 | - Bugs arising from changing 3 libraries. 40 | - The complex interactions that may arise from changing 3 libraries at the same time. 41 | - Identifying which library a bug came from. 42 | 43 | There is much to keep in mind with this approach. 44 | 45 | ### Iterating in "THENs" approach: 46 | 47 | 1. Go to the first application 48 | 2. update library 1 49 | 3. **THEN** move onto to the next application 50 | 51 | This approach greatly focuses the context on an individual library and all the associated bugs or changes required. 52 | 53 | The complexity is reduced to: 54 | 55 | - steps required to update a single library. 56 | - bugs arising from changing a library. 57 | 58 | ### Iterating in "THENs" in parallel: 59 | 60 | Iterating in thens also allows working in parallel. The parallel task should done sequentially with the task being mostly the same for each. 61 | 62 | 1. With all the 10 applications search for the old library version 63 | 2. **THEN** replace with the new version 64 | 3. search for the old library method that is deprecated 65 | 4. **THEN** replace with the new supported method. 66 | 5. etc.. 67 | 68 | ## Definitions 69 | 70 | - Chunk of work - Work that is divided up into related sections. 71 | -------------------------------------------------------------------------------- /principles/keep-it-simple-stupid-kiss.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Keep It Simple Stupid (KISS)" 3 | tags = ["epic", "code", "team"] 4 | summary = "A simple solution is better than a complex one." 5 | authors = [] 6 | contributors = ["crehn", "AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "8d4e4689-caf8-4da8-a4fb-66da2fee4e54" 12 | +++ 13 | A simple solution is better than a complex one. 14 | 15 | The KISS principle prioritizes clarity over cleverness. A solution may look dull or even "stupid," but understandable and straightforward. It claims there is no value in a solution being "clever" when a simpler solution would suffice. 16 | 17 | It is easy to create sophisticated solutions for various problems in software, as modern programming languages, frameworks, and APIs have powerful features that enabled engineers to write "clever" solutions. The KISS principle states that a solution is better when simpler, so it uses less inheritance, less polymorphism, fewer classes, etc. 18 | 19 | It does not mean that complex features should not be used, they should only be used when necessary, or there is a substantial advantage to be gained. 20 | 21 | ## Why 22 | 23 | Simpler solutions are easier to maintain. This includes increased readability, understandability, and changeability. Furthermore, writing simple code is less error-prone. 24 | 25 | The advantage of simplicity is even more significant when the person who maintains the software is not the one who wrote it. The maintainer might also be less familiar with sophisticated programming language features. So simple and stupid programs are easier to maintain because the maintainer needs less time to understand them and is less likely to introduce further defects. 26 | 27 | One reason to create more complex code is to make it more flexible to accommodate further requirements. But you may not know what those future requirements are or if they will exist as envisioned. 28 | 29 | > "When you make your code more flexible or sophisticated than it needs to be, you over-engineer it. Some do this because they believe they know their system's future requirements. The reason that it's best to make a design more flexible or sophisticated today is to accommodate the needs of tomorrow. That sounds reasonable, if you happen to be a psychic." - Refactoring to Patterns - Joshua Kerievsky. 30 | 31 | 32 | ## How 33 | 34 | KISS is a very general principle to this principle, mainly depending on the given design problem: 35 | 36 | * Avoid inheritance, polymorphism, dynamic binding, and other complicated OOP concepts. Use delegation and simple if-constructs instead. 37 | * Avoid low-level optimization of algorithms, especially when involving Assembler, bit-operations, and pointers. Slower implementations will work just fine. 38 | * Use simple brute-force solutions instead of complicated algorithms. Slower algorithms will work in the first place. 39 | * Avoid numerous classes and methods as well as large code blocks 40 | * For slightly unrelated but smaller pieces of functionality, use private methods or functions instead of an additional class. 41 | * Avoid general solutions needing parameterization. A specific solution will suffice. 42 | 43 | 44 | ## History 45 | 46 | American engineer Kelly Johnson coined the principle referring to the requirement that a military aircraft should be repairable with a limited set of tools under combat conditions. 47 | 48 | ## Derivative work 49 | 50 | > This work is a derivative of "Keep It Simple Stupid (KISS)" by Christian Rehn, originally licensed under CC BY 4.0. The original version can be found [here](http://principles-wiki.net/principles:keep_it_simple_stupid?rev=1630269194). -------------------------------------------------------------------------------- /principles/learn-in-public.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Learn in Public" 3 | tags = ["learning", "knowledge management", "personal growth", "individual", "epic"] 4 | summary = "Instead of keeping what you learn to yourself, share it as you go, for accountability, feedback, and networking." 5 | authors = ["sw-yx"] 6 | contributors = [] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source = "https://swyx.io/LIP" 10 | original_source_is_canonical = true 11 | crystalized = true 12 | uid = "d801de31-b996-47b5-8a27-754b6a6a85bb" 13 | +++ 14 | 15 | You already know that you will never be done learning. But most people "learn in private", and lurk. They consume content without creating any themselves. Again, that's fine, but we're here to talk about being in the top quintile. What you do here is to have **a habit of creating learning exhaust**: 16 | 17 | - Write blogs and tutorials and cheatsheets. 18 | - Speak at meetups and conferences. 19 | - Ask and answer things on Stackoverflow or Reddit. **Avoid** the walled gardens like Slack and Discord, they're not public. 20 | - Make Youtube videos or Twitch streams. 21 | - Start a newsletter. 22 | - Draw cartoons ([people](https://code-cartoons.com/) [loooove](https://wizardzines.com/) [cartoons](https://arkwright.github.io/scaling-react-server-side-rendering.html)!). 23 | 24 | Whatever your thing is, **make the thing you wish you had found** when you were learning. **Don't judge** your results by "claps" or retweets or stars or upvotes - just talk to yourself from 3 months ago. I keep an almost-daily dev blog written for no one else but me. 25 | 26 | Guess what? It's not about reaching as many people as possible with your content. If you can do that, great, remember me when you're famous. But chances are that _by far_ the biggest beneficiary of you trying to help past you is _future you_. If others benefit, that's icing. 27 | 28 | Oh you think you're done? Don't stop there: 29 | 30 | - Enjoyed a coding video? Reach out to the speaker/instructor and thank them, and ask questions. 31 | - Make PR's to libraries you use. 32 | - Make your own libraries no one will ever use. 33 | - **Clone stuff you like, from scratch, to see how they work**. 34 | - Teach workshops. 35 | - Go to conferences and summarize what you learned. 36 | 37 | If you're tired of creating one-off things, start building a persistent knowledge base that grows over time. [Open Source your Knowledge](https://www.swyx.io/speaking/open-source-knowledge/)! At every step of the way: _Document what you did and the problems you solved._ 38 | 39 | The subheading under this rule would be: **Try your best to be right, but don't worry when you're wrong.** Repeatedly. If you feel uncomfortable, or like an impostor, good. You're pushing yourself. Don't assume you know everything, but try your best anyway, and let the internet correct you when you are inevitably wrong. Wear your noobyness on your sleeve. 40 | 41 | **People think you suck?** Good. You agree. Ask them to explain, in detail, why you suck. You want to just feel good or you want to **be** good? No objections, no hurt feelings. Then go away and prove them wrong. Of course, if they get abusive block them. 42 | 43 | Did I mention that teaching is the best way to learn? **Talk while you code**. It can be stressful and I haven't done it all that much but my best technical interviews have been where I ended up talking like I teach instead of desperately trying to prove myself. We're animals, we're attracted to confidence and can smell desperation. 44 | 45 | At some point you'll get some support behind you. People notice genuine learners. They'll want to help you. Don't tell them, but they just became your mentors. **This is very important: [Pick up what they put down](https://www.swyx.io/writing/learn-in-public-hack)**. Think of them as offering up quests for you to complete. When they say "Anyone willing to help with **\_\_** **\_\_**?" you're that kid in the first row with your hand already raised. These are senior engineers, some of the most in-demand people in tech. They'll spend time with you, 1 on 1, if you help them out (p.s. and there's always something they want help on). You can't pay for this stuff. They'll teach you for free. Most people don't see what's right in front of them. But not you. 46 | 47 | "With so many junior devs out there, why will they help _me_?", you ask. 48 | 49 | **Because you learn in public.** By teaching you, they teach many. You amplify them. You have one thing they don't: a beginner's mind. You see how this works? 50 | 51 | At some point people will start asking you for help because of all the stuff you put out. 80% of developers are "dark", they dont write or speak or participate in public tech discourse. But you do. You must be an expert, right? Don't tell them you aren't. Answer best as you can, and when you're stuck or wrong pass it up to your mentors. 52 | 53 | Eventually you run out of mentors, and just solve things on your own. You're still putting out content though. You see how this works? 54 | 55 | Learn in public. 56 | 57 | p.s. Eventually, they'll want to pay you for your help too. A lot more than you think. 58 | 59 | --- 60 | 61 | 62 | > Author's Note: I have written an expanded version of this essay and its related canon (below) in [The Coding Career Handbook](http://learninpublic.org/?from=swyxdotio-LIP). 63 | -------------------------------------------------------------------------------- /principles/logic-in-positive.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Logic should be in the positive" 3 | summary = "Logic should ask, \"Is this true?\" instead of \"Is this not true?\"" 4 | tags = ["code", "comprehension", "cognitive", "individual", "focused","style", "practices"] 5 | license = "CC BY-SA 4.0" 6 | allow_dual_licensing_to_GPLv3 = true 7 | authors= ["AdamCraven"] 8 | contributors = ["streamer45", "AndrewCraven"] 9 | uid = "amber-finch-jordain" 10 | +++ 11 | 12 | Logic should ask, "Is this true?" instead of "Is this not true?" 13 | 14 | ## Why 15 | 16 | People can comprehend logic written in a positive form more quickly. It takes longer to process negative sentences than positive ones (Clark & Chase, 1972; Just & Carpenter, 1971, 1976; Carpenter & Just, 1975) and only worsens when multiple negative statements exist. 17 | 18 | ## How 19 | 20 | - [Write logic that asks: Is this true?](#write-logic-that-asks-is-this-true) 21 | - [Avoid the word "Not"](#avoid-the-word-not) 22 | - [When using negative statements, put them as a value - after the variable](#when-using-negative-statements-put-them-as-a-value-after-the-variable) 23 | - [Avoid double-negative logic by using additional variables](#avoid-double-negative-logic-by-using-additional-variables) 24 | 25 | ### Write logic that asks: Is this true? 26 | 27 | The first statement is written in the negative: 28 | 29 | ```js 30 | function isBlackOrWhite(black, white) { 31 | if (!black && !white) { 32 | return false; 33 | } 34 | return true; 35 | } 36 | ``` 37 | 38 | The statement's logic in plain English is: "not black and not white". These are two negative statements, which further increases the difficulty in understanding. 39 | 40 | We can write this in the positive form, and the meaning becomes far clearer: 41 | 42 | ```js 43 | function isBlackOrWhite(black, white) { 44 | if (black || white) { 45 | return true; 46 | } 47 | return false; 48 | } 49 | ``` 50 | 51 | ### Avoid the word "Not" 52 | 53 | Not creates an inversion that is harder to understand. You should avoid using not and instead use words that are more precise in their meaning. 54 | 55 | `isNotValid` -> `isInvalid`
56 | `isDeliveryNotOnTime` -> `isDeliveryLate`
57 | `isUserNotAdmin` -> `isUserNonAdmin` or `isUserUnprivileged`
58 | 59 | ### When using negative statements, put them as a value - after the variable 60 | 61 | You cannot avoid negative statements, as logic is often about exclusion. Variables also need to be defined in a way that meets your needs. Instead, you can move the negative logic to after the variable definition (the value): 62 | 63 | `variable = !value`
64 | 65 | Do this: 66 | 67 | ```python 68 | invalid = not self.is_valid() 69 | 70 | if invalid: 71 | return 72 | ``` 73 | 74 | Or do this: 75 | 76 | ```python 77 | valid = self.is_valid() 78 | invalid = not valid 79 | 80 | if invalid: 81 | return 82 | ``` 83 | 84 | But don't do this: 85 | 86 | ```python 87 | valid = self.is_valid() 88 | 89 | if not valid: 90 | return 91 | ``` 92 | 93 | ### Avoid double-negative logic by using additional variables. 94 | 95 | Moving negative logic after the variable definition can create double-negative logic. You can avoid double negative logic by first writing the logic in the positive, then inverting the result to a negative with an additional variable. 96 | 97 | `variable1 = value && value`
98 | `variable2 = !variable1`
99 | 100 | Do this: 101 | 102 | ```python 103 | valid = self.is_valid() and self.is_valid_in_external_validator() # two positive statements 104 | invalid = not valid # A single negative statement 105 | 106 | if invalid: 107 | return 108 | 109 | ``` 110 | 111 | Don't do this: 112 | 113 | ```python 114 | invalid = not self.is_valid() or not self.is_valid_in_external_validator() # double-negative statement 115 | 116 | if invalid: 117 | return 118 | 119 | ``` 120 | -------------------------------------------------------------------------------- /principles/many-minds-better-problem-solving.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Many minds, better problem-solving" 3 | tags = ["practices", "team", "medium", "problem-solving"] 4 | summary = "The greater the number of people who can work on a problem, the higher the probability of an optimal solution." 5 | authors = ["AdamCraven"] 6 | contributors = [""] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "8c6346dc-08cd-4625-a5e6-f72d20bd8c27" 12 | +++ 13 | The greater the number of people who can work on a problem, the higher the probability of an optimal solution. 14 | 15 | ## Why? 16 | 17 | A larger group of people inevitably allows you to access a broader range of different experiences and increases the "human compute time" the group can use to figure out a solution. It also reduces complexity, as transparency in problem-solving requires you to think and state your problems in clear terms. 18 | 19 | 20 | ## Article 21 | 22 | No matter how smart you are, you cannot repeatedly beat a group of people at solving an individual problem because each person brings their differing knowledge, unique life experiences and ways of thinking. Which, when pooled together, creates better overall problem-solving abilities. 23 | 24 | Combined with the [Make the invisible, visible](/p/make-the-invisible-visible/) principle, your overall goal should be to allow people to *be able to* interrogate your problems so you can work on things together. 25 | 26 | You can solve a problem together or either individually. Individuals often make great insights in solitude, which they bring back to the group to iterate on their ideas. In contrast, group problem solving allows interactive feedback and live iteration but brings with it many group dynamic considerations that are beyond the scope of this principle (but a good start is here: [Be constructive, not destructive](/p/be-constructive-not-destructive/)) 27 | 28 | ### Example 29 | 30 | You've been tasked to create a new domain model for an application. Whilst you are competent with the domain modelling process, someone else is the domain expert. Working on this problem in isolation would be foolish. 31 | 32 | Instead, you gather the minds of the domain expert and then at least one other person to validate your domain model. 33 | 34 | As your final step, you send the finished domain model to the wider team and business for validation. Using other individuals' "human compute time" to get feedback and solve problems you missed, resulting in a better domain model. 35 | 36 | ## When not to apply 37 | 38 | Time is finite; you cannot use more and more "human compute time" of individuals to solve your problems, as they have their own priorities and commitments. 39 | -------------------------------------------------------------------------------- /principles/model-all-state-in-an-application.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Model all state in an application" 3 | tags = ["front-end", "bug free", "practices"] 4 | summary = "Create a structured representation of the system's state" 5 | authors = ["AdamCraven"] 6 | contributors = [] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "9c0353fe-47f3-4e72-946e-833d090aeab2" 12 | +++ 13 | Create a structured representation of the system's state, usually as encapsulated objects, which humans can conceptually understand. 14 | 15 | In a Model-View-Controller (MVC) application, the model is responsible for the application's state and non-UI-specific behavior. 16 | 17 | A model (the M in MVC) holds the state, logic, and rules of an application, it exists independently of the UI. You could replace React with Vue, replace the DOM with an iPhone UI, and the application's logic would be untouched. 18 | 19 | *Everything should be modeled.* There should be no state that exists within an application that goes un-modeled. Because when data is modeled, it creates structure in application. You can inspect, query, and interrogate it. When you view the model, you should be able to determine the structure and state of your application. 20 | 21 | Modeling requires thought to design and a basic understanding of the domain of the application. 22 | 23 | Depending on the framework used, the model may look very different from what is above, but the concept will always exist. An example of this is Redux, the React framework. There is no model in the classic sense, but it exists with the combination of the reducer, store, and state. 24 | 25 | 26 | ## Example 27 | 28 | ```js 29 | // A basic User model in vanilla JS 30 | class User { 31 | constructor(firstName, lastName) { 32 | this.firstName = firstName; 33 | this.lastName = lastName; 34 | } 35 | setFirstName (firstName) { 36 | this.firstName = firstName; 37 | } 38 | setLastName (lastName) { 39 | this.lastName = lastName; 40 | } 41 | } 42 | ``` 43 | 44 | Or with a more functional approach: 45 | ```js 46 | function setFirstName(userObject, firstName) { 47 | userObject.firstName = firstName; 48 | return userObject; 49 | } 50 | ``` 51 | 52 | 53 | Some examples of the model concept in other languages and frameworks: 54 | 55 | * [Django Models](https://docs.djangoproject.com/en/2.1/topics/db/models/) 56 | * [Rails Active Record](https://guides.rubyonrails.org/active_record_basics.html) 57 | [Simple Java Model](http://www.javapractices.com/topic/TopicAction.do?Id=187) 58 | [Backbone JavaScript](http://backbonejs.org/#Model) 59 | 60 | ## Exceptions 61 | 62 | * Avoiding time-based states, such as animations, can be a good idea. As this can add a lot of complexity. 63 | 64 | ## Further reading: 65 | 66 | * [Types of Models](https://deviq.com/kinds-of-models/) - Types of modelling. 67 | * [MVC, MVP, MVVM Design Pattern](https://medium.com/@ankit.sinhal/mvc-mvp-and-mvvm-design-pattern-6e169567bbad) - Different patterns used in UI, not an exhaustive list. 68 | * [ngWhatever - a Better Module structure for Angular](/a-better-module-structure-for-angular/) - An implementation of an advanced MVC design in classic angular. -------------------------------------------------------------------------------- /principles/murphys-law.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Murphy's law" 3 | tags = ["epic", "strategic"] 4 | summary = "Whatever can go wrong will go wrong. So a solution is better the fewer possibilities there are for something to go wrong." 5 | authors = [] 6 | contributors = ["crehn", "AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source = "http://principles-wiki.net/principles:murphy_s_law" 10 | original_source_is_canonical = false 11 | crystalized = false 12 | uid = "4473624c-9eba-499f-9967-f9caeaaef302" 13 | +++ 14 | Whatever can go wrong will go wrong. So a solution is better the fewer possibilities there are for something to go wrong. 15 | 16 | ## Why 17 | 18 | Systems are built and used by humans. And humans inevitably make mistakes. So if a mistake is possible, eventually, it will occur. 19 | 20 | As mistakes are undesirable - you should design a system in a way that reduces them. The fewer possibilities there are to make mistakes, the fewer there will be and a greater chance of producing higher-quality software. 21 | 22 | This also applies to system design, implementation, verification, maintenance, and use. Because all these tasks are (partly) carried out by humans. 23 | 24 | 25 | ## Description 26 | 27 | Although often cited as a fatalistic comment, Murphy's Law is not stating "that life is unfair". Instead, it is (or at least can be seen as) engineering advice to design everything in a way that avoids incorrect usage. The Law applies to everything engineered, including all kinds of modules, [user] interfaces, and systems. 28 | 29 | Ideally, incorrect usage should be impossible. For example, this is the case when the compiler will stop when detecting a mistake. And in the case of user interface design, a design is better when the user cannot make incorrect inputs as the given controls won't let them. 30 | 31 | It is not always possible to design a system without mistakes. But as humans build and use systems, one should strive for such "fool-proof" designs. 32 | 33 | Note that Murphy's Law also applies to every chunk of code. According to the Law, the programmer will make mistakes while implementing the system. So it is better to implement a simple design, as this will have fewer possibilities to make implementation mistakes. Furthermore, bug fixes will be necessary as current functionality is changed or enhanced as code is maintained. A design is better the fewer possibilities there are to introduce faults while doing maintenance work. 34 | 35 | 36 | ## How 37 | 38 | This is a very general principle, so there is a large variety of possible strategies to adhere more to this principle, mainly depending on the given design problem: 39 | 40 | * Make use of static typing so that the compiler will report faults 41 | * Make the design simple, so there will be fewer implementation defects 42 | * Use automatic testing to find defects 43 | * Avoid duplication and manual tasks, so you don't forget necessary changes. 44 | * Use polymorphism instead of repeated switch statements 45 | * Use consistent naming throughout the design 46 | 47 | 48 | ## History 49 | 50 | The exact wording and who exactly coined the term remains unknown. Nevertheless, it is stated that its origin is from an experiment with a rocket sled conducted by Edward A. Murphy and John Paul Stapp. During this experiment, a technician had wired some sensors incorrectly. Murphy - on recognizing the error - cursed the technician responsible and said, "If there is any way to do it wrong, he'll find it.". [^1] 51 | 52 | 53 | ## Further reading 54 | 55 | * http://wiki.c2.com/?MurphysLaw 56 | * https://en.wikipedia.org/wiki/Murphy%27s_law 57 | 58 | 59 | 60 | [^1]: [Murphy's law origins](http://www.murphys-laws.com/murphy/murphy-true.html) 61 | 62 | 63 | ## Derivative work 64 | 65 | > This work is a derivative of "Murphy's Law (ML)" by Christian Rehn, originally licensed under CC BY 4.0. The original version can be found [here](http://principles-wiki.net/principles:murphy_s_law?rev=1620763937). -------------------------------------------------------------------------------- /principles/openclosed-principle.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Open–closed principle" 3 | tags = ["solid", "practices", "code", "team"] 4 | summary = "Software entities should be open for extension, but closed for modification." 5 | authors = ["Bertrand Meyer", "Robert C. Martin"] 6 | contributors = ["AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source = "https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle" 10 | original_source_is_canonical = false 11 | crystalized = false 12 | uid = "db3f244b-8abd-4827-bc1a-34b6a62cbf73" 13 | +++ 14 | In object-oriented programming, the open–closed principle states "software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification"; that is, such an entity can allow its behavior to be extended without modifying its source code. 15 | 16 | The benefit to this is that it creates a layer of abstraction so implementations don't have to share the same code and encourages loose coupling. 17 | 18 | ## Meyer's open–closed principle 19 | 20 | Bertrand Meyer is generally credited for having originated the term open–closed principle, which appeared in his 1988 book Object Oriented Software Construction. 21 | 22 | A module will be said to be open if it is still available for extension. For example, it should be possible to add fields to the data structures it contains, or new elements to the set of functions it performs. 23 | A module will be said to be closed if it is available for use by other modules. This assumes that the module has been given a well-defined, stable description (the interface in the sense of information hiding). 24 | 25 | At the time Meyer was writing, adding fields or functions to a library inevitably required changes to any programs depending on that library. Meyer's proposed solution to this dilemma relied on the notion of object-oriented inheritance (specifically implementation inheritance): 26 | 27 | A class is closed, since it may be compiled, stored in a library, baselined, and used by client classes. But it is also open, since any new class may use it as parent, adding new features. When a descendant class is defined, there is no need to change the original or to disturb its clients. 28 | 29 | ## Polymorphic open–closed principle 30 | 31 | During the 1990s, the open–closed principle became popularly redefined to refer to the use of abstracted interfaces, where the implementations can be changed and multiple implementations could be created and polymorphically substituted for each other. 32 | 33 | In contrast to Meyer's usage, this definition advocates inheritance from abstract base classes. Interface specifications can be reused through inheritance but implementation need not be. The existing interface is closed to modifications and new implementations must, at a minimum, implement that interface. 34 | 35 | Robert C. Martin's 1996 article "The Open-Closed Principle" was one of the seminal writings to take this approach. In 2001 Craig Larman related the open–closed principle to the pattern by Alistair Cockburn called Protected Variations, and to the David Parnas discussion of information hiding. -------------------------------------------------------------------------------- /principles/principle-of-evolvability.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Principle of evolvability" 3 | tags = ["epic", "mental model", "basic", "core"] 4 | summary = "Systems which can evolve quicker are better than those which cannot." 5 | authors = ["AdamCraven"] 6 | contributors = [""] 7 | license = "CC BY-NC-ND 4.0" 8 | allow_dual_licensing_to_GPLv3 = false 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "436f6957-4313-4580-b0d6-373508759f89" 12 | +++ 13 | Systems which can evolve quicker are better than those which cannot. 14 | 15 | Systems which have the quality of evolvability can rapidly adapt to their environment and change direction quickly, without being encumbered by previous evolutions. It allows the maximum amount of change with the minimum amount of effort. 16 | 17 | #### Definitions 18 | Evolvability is defined as the capacity of a system for adaptive evolution. -------------------------------------------------------------------------------- /principles/reduce-a-problem-to-its-lowest-sensible-abstraction.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Reduce a problem to its lowest sensible abstraction" 3 | tags = ["process"] 4 | summary = "Framing a problem in its lowest sensible abstraction helps you understand and develop accurate solutions to a problem." 5 | authors = ["AdamCraven"] 6 | contributors = [] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "fb28478b-005a-4348-9bbf-0d7e3da4429f" 12 | +++ 13 | 14 | Framing a problem in its lowest sensible abstraction to help you understand and develop accurate solutions to a problem. 15 | 16 | For example, for a business issue: I want to book an appointment rapidly on a website. 17 | 18 | You can frame the problem in many different ways. From higher to lower abstractions: 19 | 20 | I need to... 21 | 22 | * click buttons on my mouse and move it to the right point across my screen very fast. 23 | * click buttons on this website and fill out forms fast. 24 | * parse the DOM to access the website and submit the forms. 25 | * parse HTML forms and submit them via post requests. 26 | * parse an HTTP response, submit an HTTP response 27 | * parse TCP packets, submit a TCP response 28 | * parse the electrical signals and submit an electrical response. 29 | 30 | ## Why 31 | 32 | * Greatly increases chances of project success, as you're working at the optimum level to solve the problem. 33 | * It helps you understand what capabilities are required to solve a problem. The team required to parse computer electrical signals would be very different from the team required to click buttons on a website. 34 | 35 | 36 | ---- 37 | 38 | When working on building a performance-critical web scraper, the problem in my mind was, "I need to click buttons on this website and fill out forms fast." 39 | 40 | To solve that problem, I decided that the best way to solve that problem was using an automated headless browser, controlled by [Puppeteer](https://developers.google.com/web/tools/puppeteer). 41 | 42 | However, I soon found out it wasn't fast enough, and scaling would require a lot of computational resources. 43 | 44 | Because I thought of the problem in terms of clicking buttons, I became stuck. My thought process revolved around solving the problem I thought I had. "What is faster than headless chrome?" "Years of development had gone into it. How could I possibly make it run faster?" 45 | 46 | After a while, I realized the problem was not clicking buttons on a website; it was: "I just need to parse HTML forms and submit them via post requests.". It over-simplified the problem. But I'd found the lowest sensible abstraction. 47 | 48 | After I'd stated the problem correctly, I realized I didn't need to use a browser at all. I re-built the scraper in Go, then parsed the HTML and submitted the forms via post requests. Without the complexity of the browser, I moved page processing down from around 50ms to 0.5ms - A 100x improvement. 49 | 50 | If I'd stated the problem at the correct abstraction initially, I would have saved myself weeks of work. 51 | 52 | Throughout my career, I've seen large projects based upon the wrong framing of a problem. 53 | 54 | If someone at the beginning had sat down and stated the problem more accurately, the project would have developed in a completely different and more successful direction. It's also why having many experts with diverse backgrounds will often provide better results with this principle. 55 | -------------------------------------------------------------------------------- /principles/relatedness-pattern.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Relatedness pattern" 3 | tags = ["cognitive", "code", "comprehension", "individual", "focused"] 4 | summary = "Things that are related to one another and ordered logically do not increase cognitive complexity" 5 | authors = ["AdamCraven"] 6 | contributors = [""] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "60f225ff-3110-4c4c-bf1c-677aa2c2b602" 12 | +++ 13 | 14 | Cognitive complexity is not increased with things that have high relatedness. Meaning your mind doesn't have to work any harder with highly related items (e.g. code, methods in a class, configuration, etc.), even if there are many of them. This cognitive principle reduces complexity by taking advantage of the one of the best features of our brains: Pattern recognition. 15 | 16 | 17 | For example: You could have many Spotlights defined next to each other without the code becoming complex: 18 | ```js 19 | [ 20 | new Spotlight({ visible: false, x: -2, color: 'red' }), 21 | new Spotlight({ visible: true, x: 0, color: 'white' }), 22 | new Spotlight({ visible: false, x: 2, color: 'blue' }), 23 | 24 | ] 25 | ``` 26 | 27 | But very few of these: 28 | 29 | ```js 30 | [ 31 | new Spotlight({ visible: false, x: -6, color: 'green' }), 32 | new Window({ width:3, false, y: -4, height: 8, }), 33 | new HttpRequester(), 34 | new Floor({ opacity:0.7, width:40, height: 40, x:4, texture: 'marble-floor-2048x2048.png' }), 35 | new Bootstrapper(6), 36 | ] 37 | ``` 38 | 39 | To have high relatedness, it must have these properties: 40 | 41 | 1. Similar things should be next to each other 42 | 2. Those things should be used in a consistent way 43 | 3. They should be logically ordered or grouped 44 | 45 | ## Why 46 | 47 | Humans are good with patterns [1](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4141622/). If the mind recognises a consistent pattern, we intuitively understand that it will apply elsewhere. 48 | 49 | ## Examples 50 | ### High relatedness example 51 | 52 | ```js 53 | [ 54 | new Spotlight({ visible: false, x: -2, color: 'red' }), 55 | new Spotlight({ visible: true, x: 0, color: 'white' }), 56 | new Spotlight({ visible: false, x: 2, color: 'blue' }), 57 | new Spotlight({ visible: false, x: 4, color: 'orange' }), 58 | ] 59 | ``` 60 | Adding another `Spotlight` would not increase complexity because: 61 | 62 | 1. Spotlights are all next to each other 63 | 2. The spotlights are used in a consistent way by having the same arguments defined. 64 | 3. The spotlights are logically ordered. In this case, by their x value. 65 | 66 | 67 | ### Low relatedness example 68 | 69 | ```js 70 | [ 71 | new Spotlight({ visible: false, x: -6, color: 'green' }), 72 | new Window({ width:3, false, y: -4, height: 8, }), 73 | new HttpRequester(), 74 | new Floor({ opacity:0.7, width:40, height: 40, x:4, texture: 'marble-floor-2048x2048.png' }), 75 | new Spotlight({ y: 2, color: 'blue' }), 76 | new Spotlight({ visible: false, z: 4, color: 'orange' }), 77 | new Spotlight({ beam: false, x: 6, color: 'pink' }), 78 | new Bootstrapper(6), 79 | new Light(), 80 | ] 81 | ``` 82 | Adding another object will increase complexity because: 83 | 84 | 1. Many objects, some completely unrelated, are next to each other. 85 | 2. Even related objects (spotlights) are used inconsistently due to variations in arguments. 86 | 3. There is no logical ordering - or grouping 87 | 88 | ### Non-coding example 89 | 90 | A real-life example would be in the back of a textbook that contains an index. That index includes a list of words. Those words reference a location - usually a page number. You will experience no increase in cognitive complexity if an additional word with page numbers is added to the index. Because: 91 | 92 | 1. The words are next to each other. 93 | 2. They follow the format: word, location(s) 94 | 3. They are ordered alphabetically, and indexes use indentation to group sub-words. 95 | 96 | 97 | [TOC] 98 | 99 | ## Article 100 | 101 | This principle will change the way you code day to day. It will help you structure your code and reduce cognitive load by increasing relatedness. Let's take you through some examples: 102 | 103 | ### Related objects with unrelated arguments 104 | 105 | How to handle objects with varying arguments: 106 | 107 | #### High relatedness 108 | 109 | ```js 110 | [ 111 | new Spotlight({ visible: false, x: -6, color: 'green' }), 112 | new Spotlight({ visible: false, x: -4, color: 'yellow' }), 113 | new Spotlight({ visible: false, x: -2, color: 'red' }), 114 | new Spotlight({ visible: true, x: 0, color: 'white' }), 115 | new Spotlight({ visible: false, x: 2, color: 'blue' }), 116 | new Spotlight({ visible: false, x: 4, color: 'orange' }), 117 | new Spotlight({ visible: false, x: 6, color: 'pink' }), 118 | ], 119 | 120 | ``` 121 | The code is highly related. It has a consistent pattern and organization. Adding another object using the same pattern would create no additional cognitive complexity. 122 | 123 | 124 | #### Decreasing relatedness 125 | ```js 126 | [ 127 | new Spotlight({ visible: false, x: -6, color: 'green' }), 128 | new Spotlight({ visible: false, x: -4, color: 'yellow' }), 129 | new Spotlight({ visible: false, x: -2, color: 'red' }), 130 | new Spotlight({ showBeamHousing: false, y: 9, color: 'white' }), 131 | new Spotlight({ visible: false, x: 2 }), 132 | new Spotlight(), 133 | new Spotlight({ visible: false, x: 6, color: 'pink' }), 134 | ], 135 | ``` 136 | The code has lost some of its relatedness. The objects are all related, but the arguments vary. This variation makes it much harder to scan the code because the pattern has been lost. 137 | 138 | #### Bringing back high relatedness 139 | 140 | 141 | ```js 142 | [ 143 | new Spotlight({ showBeamHousing: true, visible: false, x: -6, y: 0, color: 'green' }), 144 | new Spotlight({ showBeamHousing: true, visible: false, x: -4, y: 0, color: 'yellow' }), 145 | new Spotlight({ showBeamHousing: true, visible: false, x: -2, y: 0, color: 'red' }), 146 | new Spotlight({ showBeamHousing: false, visible: true, x: 0, y: 9, color: 'white' }), 147 | new Spotlight({ showBeamHousing: true, visible: false, x: 2, y: 0, color: 'white' }), 148 | new Spotlight({ showBeamHousing: true, visible: false, x: 4, y: 0, color: 'orange' }), 149 | new Spotlight({ showBeamHousing: true, visible: false, x: 6, y: 0, color: 'pink' }), 150 | ], 151 | ``` 152 | Relatedness has been brought back to high levels by defining all possible arguments. This explicitness adds verbosity to the code, but the verbosity increases relatedness. 153 | 154 | 155 | ```js 156 | [ 157 | new Spotlight(SpotlightOpts1), 158 | new Spotlight(SpotlightOpts2), 159 | ... 160 | ], 161 | ``` 162 | 163 | Alternatively, you could also define the arguments away from the new object. This code will be highly related at the potential expense of making it less so elsewhere. 164 | 165 | 166 | ### Variable objects 167 | 168 | How to handle objects that are unrelated: 169 | 170 | #### Poor relatedness 171 | 172 | ```js 173 | [ 174 | new Spotlight({ visible: false, x: -6, color: 'green' }), 175 | new Window({ visible: false, y: -4, height: '80' }), 176 | new Spotlight({ visible: false, x: -2, color: 'red' }), 177 | new Floor({ visible: true, width:4, height: 4, x:4 }), 178 | new Spotlight({ visible: false, x: 2, color: 'blue' }), 179 | new Spotlight({ visible: false, x: 4, color: 'orange' }), 180 | new Spotlight({ visible: false, x: 6, color: 'pink' }), 181 | ], 182 | ``` 183 | Relatedness is low due to different types of objects with different arguments. 184 | 185 | #### Conditional relatedness 186 | 187 | ```js 188 | [ 189 | new Spotlight(), 190 | new Window(), 191 | new Spotlight(), 192 | new Floor(), 193 | new Spotlight(), 194 | new Ceiling(), 195 | new Spotlight(), 196 | ], 197 | ``` 198 | 199 | **If** you can recognize these are 3d objects being added to a scene, then you will view it as related. If you cannot, you would say it is unrelated. 200 | 201 | ```js 202 | const objectsToAddTo3dScene = [ 203 | new Spotlight(), 204 | new Window(), 205 | new Spotlight(), 206 | new Floor(), 207 | new Spotlight(), 208 | new Ceiling(), 209 | new Spotlight(), 210 | ], 211 | ``` 212 | 213 | We can help with the relatedness by creating a variable - `const objectsToAddTo3dScene` - which informs you of the pattern. 214 | 215 | 216 | ```js 217 | [ 218 | new Floor(), 219 | new Ceiling(), 220 | new Window(), 221 | new Spotlight(), 222 | new Spotlight(), 223 | new Spotlight(), 224 | new Spotlight(), 225 | ], 226 | ``` 227 | 228 | The logical ordering used here is: parts of the building first, then lighting after. However, it is hard to enforce that ordering. 229 | 230 | #### High relatedness 231 | 232 | ```js 233 | 234 | const building = [ 235 | new Floor(), 236 | new Ceiling(), 237 | new Window(), 238 | new Window(), 239 | ] 240 | 241 | 242 | const lighting = [ 243 | new Spotlight(), 244 | new Spotlight(), 245 | new Spotlight(), 246 | new Spotlight(), 247 | new Pointlight(), 248 | ] 249 | 250 | ``` 251 | 252 | If we group the objects - So the building objects and lighting objects go together - we are back to high relatedness. No additional complexity is created by adding another object to either one of those arrays. 253 | 254 | ### Indexes 255 | 256 | How to handle indexes: 257 | 258 | #### High relatedness 259 | 260 | ```python 261 | path("about/", loadPage("pages/about.html")), 262 | path("contact/", loadPage("pages/contact.html")) 263 | path("home/", loadPage("pages/home.html")) 264 | path("license/", loadPage("pages/license.html") ), 265 | path("terms-of-service/", loadPage("pages/tos.html")), 266 | 267 | ``` 268 | 269 | A highly related index of paths ordered alphabetically. 270 | 271 | 272 | #### Relatedness Lost 273 | 274 | ```python 275 | path("license/", loadPage("pages/license.html"), searchEngineCache=False, cachePage="10 seconds", ), 276 | path("about/", loadPage("pages/about.html"), alwaysReload=True,), 277 | path("terms-of-service/", loadPage("pages/tos.html")), 278 | path("principles/", loadPageDynamicPage("principle/index.html", view('principle.index'))) 279 | path("home/", loadPage("pages/home.html")) 280 | path("contact/", loadPage("pages/contact.html")) 281 | path("blog/", loadPageDynamicPage("blog/blog.html", view('blog.index'))) 282 | 283 | ``` 284 | The paths are related, but relatedness has been lost by: dynamic loading mixed with static loading of files, different arguments passed in and no order. The file will get very overwhelming in future. 285 | 286 | #### Relatedness regained 287 | 288 | ```python 289 | group('static', 290 | path("about/", loadPage("pages/about.html"), searchEngineCache=True, cachePage="0 seconds"), 291 | path("contact/", loadPage("pages/contact.html"), searchEngineCache=True, cachePage="10 seconds",) 292 | path("home/", loadPage("pages/home.html"), searchEngineCache=True, cachePage="60 seconds",) 293 | path("license/", loadPage("pages/license.html"), searchEngineCache=False, cachePage="60 seconds", ), 294 | path("terms-of-service/", loadPage("pages/tos.html"), searchEngineCache=True, cachePage="60 seconds"), 295 | ), 296 | group('dynamic', 297 | path("principles/", loadPageDynamicPage("principle/index.html", view('principle.index'))), 298 | path("blog/", loadPageDynamicPage("blog/blog.html", view('blog.index'))) 299 | ) 300 | 301 | ``` 302 | 303 | We've grouped the paths. So that the groups are related (static + dynamic) and options that are relevant to those groups are all defined explicitly. 304 | 305 | 306 | ### Methods in a class 307 | 308 | How to handle methods in a class: 309 | 310 | #### High unrelatedness 311 | 312 | 313 | Tip: If you are unfamiliar with Go, it may read easier if you ignore the `(pm *Page)` after the `func` definition. In Go it just means something belongs to that object. 314 | ```go 315 | 316 | type Page struct { 317 | comms comms.HttpComms 318 | appointmentTime time.Time 319 | } 320 | 321 | func NewPage(comms comms.HttpComms, appointmentTime string) *Page {} 322 | 323 | func (pm *Page) GetFirstPage() {} 324 | 325 | func (pm *Page) Next() {} 326 | 327 | func (pm *Page) markTimer(str string) {} 328 | 329 | func (pm *Page) NextFast() {} 330 | 331 | func WriteFile(page PageMain, html []byte) {} 332 | 333 | func (pm *Page) NextWithPageCheckFast(nextPageSelector string) bool {} 334 | 335 | func (pm *Page) NextWithPageCheck(nextPageSelector string) bool {} 336 | 337 | func (pm *Page) DoPrelogin(username string, password string) {} 338 | 339 | func (pm *Page) DoTransit(transit []map[string]interface{}) {} 340 | 341 | func (pm *Page) DoPrepareForBooking(timeStr string) {} 342 | 343 | func (pm *Page) DoBook(selectSlot int, transit map[string]interface{}) error {} 344 | 345 | ``` 346 | 347 | The methods are unrelated to each other. It's tough to figure out what the file is doing. 348 | 349 | 350 | #### Better relatedness 351 | 352 | ```go 353 | 354 | type Page struct { 355 | comms comms.HttpComms 356 | appointmentTime time.Time 357 | 358 | } 359 | 360 | func NewPage(comms comms.HttpComms, appointmentTime string) *Page {} 361 | 362 | 363 | func (pm *Page) PreLogin() error {} 364 | 365 | func (pm *Page) AttemptLogin(username string, password string) error {} 366 | 367 | func (pm *Page) PrepareForBooking(transit []map[string]interface{}) error {} 368 | 369 | func (pm *Page) AttemptBooking(selectSlot int, transit map[string]interface{}) error {} 370 | 371 | ``` 372 | 373 | All unrelated methods have been removed where possible, which has increased clarity. This clarity should make it easier for you to guess what the application may do- It's a file that performs a booking. The methods are all related - they perform similar actions: Load web pages, transition between pages and attempt to perform actions upon them. It's ordered by what happens first to last. However, we can still there is some unrelatedness in arguments. That is sometimes unavoidable, but in this case we can fix it 374 | 375 | 376 | #### High relatedness between the methods 377 | 378 | ```go 379 | 380 | type Page struct { 381 | comms comms.HttpComms 382 | appointmentTime time.Time 383 | username: string 384 | password: string 385 | transit: []map[string]interface{} 386 | selectSlot: int 387 | } 388 | 389 | func NewPage(comms comms.HttpComms, appointmentTime string, selectSlot int, username string, password string) *Page {} 390 | 391 | 392 | func (pm *Page) PreLogin() error {} 393 | 394 | func (pm *Page) AttemptLogin() error {} 395 | 396 | func (pm *Page) PrepareForBooking() error {} 397 | 398 | func (pm *Page) AttemptBooking() error {} 399 | 400 | ``` 401 | 402 | We've moved out all the arguments into the object definition. This code is now easy to parse. Adding additional methods of the same type would not increase complexity. 403 | 404 | #### Method and functions 405 | 406 | How to handle relatedness within executing code: 407 | 408 | ```js 409 | class MessageManipulator { 410 | constructor() {} 411 | 412 | // Creates empty data object with uuid. 413 | create() { 414 | return { 415 | id: uuid(), 416 | title: "", 417 | message: "", 418 | }; 419 | } 420 | 421 | // Merges new data with previous data, if valid 422 | update(newData, previousData) { 423 | if (checkData(newData)) { 424 | return { ...previousData, ...newData }; 425 | } 426 | return previousData; 427 | } 428 | 429 | // Updates data on server 430 | async updateOnServer(newData, previousData) { 431 | const data = this.update(newData, previousData); 432 | const result = await http.updateData(data); 433 | if (result.success) { 434 | return result.data; 435 | } 436 | return previousData; 437 | } 438 | 439 | // deletes data 440 | remove(newData, previousData) { 441 | if (checkData(newData)) { 442 | return { 443 | uuid: previousData.uuid, 444 | _tombstoneFlag: true, 445 | }; 446 | } 447 | return previousData; 448 | 449 | } 450 | } 451 | ``` 452 | 453 | The ` updateOnServer` method is the odd method out - it is an asynchronous method that calls the server. The previous simple pattern of: a data manipulator with sanity checking has been destroyed. It adds additional complexity and prevents the engineer from trusting that everything in the file is related to another. As the file grows larger, the destruction of the relatedness will cause the engineer a higher cognitive workload. It's lost its index-like nature and will continue to break down over time. To fix this, remove the asynchronous functionality. 454 | 455 | 456 | ```js 457 | class MessageManipulator { 458 | constructor() {} 459 | 460 | // Creates empty data object with uuid. 461 | create() { 462 | return { 463 | id: uuid(), 464 | title: "", 465 | message: "", 466 | tombstoneFlag: false, 467 | }; 468 | } 469 | 470 | // Merges new data with previous data, if valid 471 | update(newData, previousData) { 472 | if (checkData(newData)) { 473 | return { ...previousData, ...newData }; 474 | } 475 | return previousData; 476 | } 477 | 478 | // deletes data 479 | remove(newData, previousData) { 480 | if (checkData(newData)) { 481 | return { 482 | uuid: previousData.uuid, 483 | tombstoneFlag: true, 484 | }; 485 | } 486 | return previousData; 487 | 488 | } 489 | } 490 | ``` 491 | 492 | It won't always be possible to have highly related methods within executing code - but doing so will reduce cognitive complexity. 493 | 494 | ## Related principles 495 | 496 | This principle complements: 497 | 498 | [single-responsibility principle](https://principles.dev/p/single-responsibility-principle/) - which states that files should do one thing. 499 | 500 | "Explicit is better than implicit" - Being explicit often increases relatedness. 501 | 502 | 503 | ## Exceptions 504 | 505 | Reducing cognitive load locally (i.e. in the file) has to be balanced with increasing complexity non-locally (e.g. within the module). As following this principle strictly may lead to over-abstraction. Instead of opting for over-abstraction, you can increase complexity locally as long as every other method follows a similar pattern. 506 | -------------------------------------------------------------------------------- /principles/single-responsibility-principle.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Single-Responsibility Principle" 3 | tags = ["solid", "practices", "code", "team", "organization"] 4 | summary = "Every module, class or function in a computer program should have responsibility over a single part of that program's functionality, and it should encapsulate that part" 5 | authors = ["Robert C. Martin"] 6 | contributors = ["AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "fcd54e0e-4fb2-4dfc-a15e-c1772f9cfa92" 12 | +++ 13 | 14 | The single-responsibility principle is a computer-programming principle that states that every module, class or function in a computer program should have responsibility over a single part of that program's functionality, and it should encapsulate that part. All of that module, class or function's services should be narrowly aligned with that responsibility. 15 | 16 | Robert C. Martin, the originator of the term, expresses the principle as, "A class should have only one reason to change," although, because of confusion around the word "reason" he also stated "This principle is about people." 17 | 18 | In some of his talks, he also argues that the principle is, in particular, about roles or actors. For example, while they might be the same person, the role of an accountant is different from a database administrator. Hence, each module should be responsible for each role. 19 | 20 | ## History 21 | The term was introduced by Robert C. Martin in an article by the same name as part of his "Principles of Object Oriented Design" made popular by his 2003 book "Agile Software Development, Principles, Patterns, and Practices". Martin described it as being based on the principle of cohesion, as described by Tom DeMarco in his book "Structured Analysis and System Specification" and Meilir Page-Jones in "The Practical Guide to Structured Systems Design" In 2014 Martin wrote a blog post entitled [The Single Responsibility Principle](https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html) with a goal to clarify what was meant by the phrase "reason for change." 22 | 23 | 24 | ## Example 25 | 26 | Martin defines a responsibility as a reason to change, and concludes that a class or module should have one, and only one, reason to be changed (e.g. rewritten). 27 | 28 | As an example, consider a module that compiles and prints a report. Imagine such a module can be changed for two reasons. First, the content of the report could change. Second, the format of the report could change. These two things change for different causes. The single-responsibility principle says that these two aspects of the problem are really two separate responsibilities, and should, therefore, be in separate classes or modules. It would be a bad design to couple two things that change for different reasons at different times. 29 | 30 | The reason it is important to keep a class focused on a single concern is that it makes the class more robust. Continuing with the foregoing example, if there is a change to the report compilation process, there is a greater danger that the printing code will break if it is part of the same class. 31 | 32 | ## Derivative work 33 | 34 | > This work is a derivative of "Single-responsibility principle" by multiple authors, originally licensed under CC BY SA 3.0. The original version can be found [here](https://en.wikipedia.org/wiki/Single-responsibility_principle2). -------------------------------------------------------------------------------- /principles/single-source-of-truth.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "One single source of truth" 3 | summary = "Data should be held in one location, duplicates of that data should be by reference only." 4 | tags = ["data", "full-stack", "practices","medium", "team"] 5 | license = "CC BY-SA 4.0" 6 | allow_dual_licensing_to_GPLv3 = true 7 | authors= [] 8 | contributors = ["AdamCraven"] 9 | uid = "violet-primate-gertruda" 10 | +++ 11 | 12 | Data should be held in one location, duplicates of that data should be by reference only. 13 | 14 | ## Why 15 | 16 | - Changes to data are always propagated to the rest of the system. 17 | - Mutations to the data need only happen in one place. 18 | - Single source of truth means no data will be out of sync or fail to be updated. 19 | 20 | ## How 21 | 22 | Only allow data writes to happen in one location. Whether that be a call to a rest API, system call or other write actions. 23 | 24 | Don't allow data to be stored anywhere but the single source of truth. 25 | 26 | ## Exceptions 27 | 28 | **Highly distributed systems** Some systems rely on data consistency to be reached eventually or may never need to have accurate data. 29 | 30 | 31 | 32 | ## References 33 | 34 | Further reading: 35 | https://en.wikipedia.org/wiki/Single_source_of_truth 36 | -------------------------------------------------------------------------------- /principles/software-should-be-easy-to-debug.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Software should be easy to debug" 3 | summary = "When software behaves unexpectedly, it should be easy to understand what is causing the problem." 4 | tags = ["practices", "medium", "errors", "debugging", "logs", "environment setup", "language choice", "productivity"] 5 | license= "CC BY-SA 4.0" 6 | allow_dual_licensing_to_GPLv3= true 7 | authors= ["AdamCraven"] 8 | contributors = [] 9 | uid = "yellow-yak-costanza" 10 | +++ 11 | 12 | When software behaves unexpectedly, it should be easy to understand what is causing the problem. 13 | 14 | ## Why 15 | 16 | - Time is reduced in fixing a problem. A problem that can be understood without difficulty allows the developer to fix it rapidly, which increases developer productivity. 17 | - Frustration is reduced. _Friction_ caused by not understanding a problem leads to frustration for the developer. 18 | 19 | ## How 20 | 21 | - Ensure code has good metrics around them, such as logging, stack traces and error messages. 22 | - Ensure the code can be easily debugged. 23 | 24 | ## Article 25 | 26 | One of the largest unaccounted for time sinks in engineering is figuring out unexpected problems. Bad debugging tools, poor error messages and bad logs increase the time taken to resolve an issue. 27 | 28 | If an engineers environment is not setup in a way that can be used to easily pin down a problem, it takes longer than necessary to figure out the problem. Each time another issue occurs the inefficiency is compounded. Therefore, it is a productive use of time to ensure engineers environments are easy to debug. 29 | 30 | This principle applies to every environment from a local machine to production. The easier it is to debug, the more productive a team can be. 31 | 32 | ### Examples 33 | 34 | Specific ideas on how to implement this principle: 35 | 36 | - Stacks traces 37 | - Should: Be accurate and detailed 38 | - Should: Work across asyncronous, parallel and concurrent code. 39 | - Should: Error reporting of line numbers should be accurate (e.g. when using sourcemaps) 40 | - Debugger - Easy to use. 41 | - Should: Be attachable to a live runtime 42 | - Should: Be able to be stepped through 43 | - Should: show real-time states of properties and values. 44 | - Errors messages - Be clear and concise 45 | - Should Not: Be swallowed or hidden 46 | - Should Not: Be generic or un-descriptive 47 | - Logs 48 | - Should: All key interactions of a system should be recorded, especially user interactions. 49 | - Should: Be captured by an external system that is easily searchable. 50 | 51 | Some programming languages maybe less desirable for use with teams than others, due to not having these features. 52 | -------------------------------------------------------------------------------- /principles/test-models-thoroughly-test-everything-else-less.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Test models thoroughly, test everything else less" 3 | tags = ["front-end", "bug free", "practices"] 4 | summary = "" 5 | authors = ["AdamCraven"] 6 | contributors = [] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "b2bc1159-640c-403c-8c1c-613888efa4a6" 12 | +++ 13 | Testing is the foundation to bug free code. It reduces complexity by both codifying logic at a point in time when the logic is understood and allowing the engineer to trust the complexity has been captured. Additionally, they act as documentation of the code and as a safety net to changes. 14 | 15 | One of the biggest problems with UI testing comes from not knowing where to draw the line between the different types of tests. Following these principles, it becomes simple: 16 | 17 | * unit level: models and utility methods should aim to have near 100% code coverage because they are the core of the application you are building. 18 | * component level: testing a group of components will have a few tests because the core logic has been tested, and confidence will be high. 19 | * automated interaction tests (e.g., Selenium/Cypress) will lightly test the whole application and the component. 20 | 21 | Why so little testing above the models and utility methods? Because if the application is entirely model-based, there will be very little logic outside of the models, most of it will be glue code, and it will be self-evident when it doesn't work and caught quickly in interaction tests. 22 | 23 | ```js 24 | isValidUser() { 25 | this.isFirstNameValid() 26 | && this.isLastNameValid() 27 | && this.isEmailAddressValid() 28 | && this.isDateOfBirthValid() 29 | && this.isAllRequiredFieldsPresent(); 30 | } 31 | ``` 32 | 33 | To test the example code above, test the individual methods thoroughly (e.g. isFirstNameValid method) and then test the computed method (e.g., isValidUser) with a single test for each fail state of the method. You will have drastically increased confidence in the code as the complexity is encoded in the tests and the expected behavior for the code is explicitly written down. 34 | 35 | 36 | ## Dependent principles 37 | 38 | * [Model all state in an application](https://principles.dev/p/model-all-state-in-an-application/) - This principle is dependent upon using this principle. -------------------------------------------------------------------------------- /principles/treat-things-like-cattle-not-pets.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Treat things like cattle, not pets" 3 | tags = ["infrastructure", "team", "organization"] 4 | summary = "Build your infrastructure as something disposable that can be destroyed if it fails (cattle) rather than something precious that has to be looked after (pets)" 5 | authors = ["Randy Bias"] 6 | contributors = ["AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source = "http://cloudscaling.com/blog/cloud-computing/the-history-of-pets-vs-cattle/" 10 | original_source_is_canonical = false 11 | crystalized = false 12 | uid = "e566485a-2f17-40f9-9f6f-8db0a928592d" 13 | +++ 14 | The "Pets vs Cattle" idea, created by Randy Bias, suggests that infrastructure should be disposable. Servers and other infrastructure can be viewed as either "pets" or "cattle", with pets being unique and indispensable that are manually created, managed and cared for - which is bad. In contrast to cattle which are automatically built, designed for failure, and dispensable - which is good. 15 | 16 | > In the old way of doing things, we treat our servers like pets, for example Bob the mail server. If Bob goes down, it’s all hands on deck. The CEO can’t get his email and it’s the end of the world. In the new way, servers are numbered, like cattle in a herd. For example, www001 to www100. When one server goes down, it’s taken out back, shot, and replaced on the line. - Randy Bias 17 | 18 | Read more from Randy: http://cloudscaling.com/blog/cloud-computing/the-history-of-pets-vs-cattle/ -------------------------------------------------------------------------------- /principles/try-to-delete-the-part-or-process.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Try to delete the part or process." 3 | tags = ["organization", "leadership", "epic", "strategic"] 4 | summary = "Try to delete the feature or process to build things that are required." 5 | authors = ["Elon Musk"] 6 | contributors = ["AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "278c8f32-4a98-4cd6-91f2-a881194f1dc7" 12 | +++ 13 | 14 | Actively attempt to remove features or processes to reduce bloat and build things that are required, instead of adding things which prevent you from reaching the projects goals. Or as Musk says "if you don't run at tight margins, you're going to get nothing to orbit." 15 | 16 | This principle originated from building spaceships but is generally applicable to building anything complicated. 17 | 18 | ## Why 19 | 20 | * Build what you need - It is easy to add unnecessary features to solve problems because you can make arguments to rationalize every use case. Instead of attempting to make existing features cover the work. 21 | * It reduces complexity - A reduction in complexity means fewer chances of something going wrong, which is especially important if you're launching things into space 🚀 22 | * Ship faster - Running with fewer features means you reach your deadlines quicker. 23 | * Reduces bloat - Forcing an evaluation of a feature means you will ensure the feature is still valuable to you as the project progresses. 24 | 25 | ## Article 26 | 27 | The principle originated from Elon Musk, during his Starbase Tour: https://youtu.be/t705r8ICkRw?t=837 28 | 29 | Here's the transcript: 30 | 31 | "If you're not occasionally adding things back in 10% of the time, you're clearly not deleting enough." 32 | 33 | "The bias tends to be very strongly towards let us add this part or the process step in case we need it." 34 | 35 | "But you can basically make [just] in-case arguments for so many things. And for a rocket that is trying to be the first fully reusable rocket. - There's never been a fully reusable rocket. This is the holy grail of rocketry". 36 | 37 | "So you really need to run at tight margins. Because if you don't run at tight margins, you're going to get nothing to orbit." 38 | 39 | "So you've got to delete the part or process and you can't hedge your bets." 40 | 41 | "That's why the grid fins, for example, do not fold down. Because that's a whole extra mechanism that we don't need. As long as the grid fins basically follow the flow, they are not really disturbing the flow. It's really neither here nor there. As long as they don't have a high angle of attack, it doesn't matter. " 42 | 43 | "But in any case, it's the thing we could add later. So now these grid fins are humongous. We will go see them. But they're like, I mean, a dinosaur bear trap." 44 | 45 | "And if you have a whole mechanism for folding them, that's clearly a part you don't need. So this is clearly a good design decision. That actually I didn't come up with, and it was like, great. 46 | But it followed the principle of delete the part, delete the process." 47 | 48 | "I was like, great, good idea, let's not fold them. Why are we folding them anyway?" 49 | 50 | ## Related principles 51 | 52 | * [Keep It Simple Stupid (KISS)](https://principles.dev/p/keep-it-simple-stupid-kiss/) 53 | -------------------------------------------------------------------------------- /principles/use-default-arguments-instead-of-short-circuiting-or-conditionals.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Use default arguments instead of short circuiting or conditionals" 3 | tags = ["variables", "code", "rule", "code review", "clean code", "clean code"] 4 | summary = "" 5 | authors = [] 6 | contributors = ["AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source = "https://github.com/ryanmcdermott/clean-code-javascript" 10 | original_source_is_canonical = false 11 | crystalized = false 12 | uid = "f54b8b0f-f446-4cc9-9f98-50fe0bc844c2" 13 | +++ 14 | Default arguments are often cleaner than short-circuiting. Be aware that if you use them, your function will only provide default values for undefined arguments. Other "falsy" values such as '', "", false, null, 0, and NaN, will not be replaced by a default value. 15 | 16 | Bad: 17 | ```js 18 | function createMicrobrewery(name) { 19 | const breweryName = name || "Hipster Brew Co."; 20 | // ... 21 | } 22 | ``` 23 | 24 | Good: 25 | ```js 26 | function createMicrobrewery(name = "Hipster Brew Co.") { 27 | // ... 28 | } 29 | ``` 30 | 31 | ## Derivative work 32 | 33 | > This work is a derivative of "clean-code-javascript" by Ryan Mcdermott, originally licensed under MIT. The original version can be found [here](https://github.com/ryanmcdermott/clean-code-javascript/tree/3ff9eba6d460f31db8146762bade4fcc32626762). -------------------------------------------------------------------------------- /principles/use-explanatory-variables.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Use explanatory variables" 3 | tags = ["variables", "code", "rule", "code review", "clean code"] 4 | summary = "Create variables to add meaning" 5 | authors = [] 6 | contributors = ["AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source = "https://github.com/ryanmcdermott/clean-code-javascript" 10 | original_source_is_canonical = false 11 | crystalized = false 12 | uid = "7576c44f-53cb-4c8a-a884-f174851f7ba4" 13 | +++ 14 | 15 | Create variables to add meaning 16 | 17 | Bad: 18 | 19 | ```js 20 | const address = "One Infinite Loop, Cupertino 95014"; 21 | const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/; 22 | saveCityZipCode( 23 | address.match(cityZipCodeRegex)[1], 24 | address.match(cityZipCodeRegex)[2] 25 | ); 26 | ``` 27 | 28 | Good: 29 | 30 | ```js 31 | const address = "One Infinite Loop, Cupertino 95014"; 32 | const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/; 33 | const [_, city, zipCode] = address.match(cityZipCodeRegex) || []; 34 | saveCityZipCode(city, zipCode); 35 | ``` 36 | 37 | ## Why 38 | 39 | * Increases understanding 40 | * Lowers cognitive load 41 | 42 | 43 | ## Derivative work 44 | 45 | > This work is a derivative of "clean-code-javascript" by Ryan Mcdermott, originally licensed under MIT. The original version can be found [here](https://github.com/ryanmcdermott/clean-code-javascript/tree/3ff9eba6d460f31db8146762bade4fcc32626762). -------------------------------------------------------------------------------- /principles/use-meaningful-and-pronounceable-variable-names.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Use meaningful and pronounceable variable names" 3 | tags = ["variables", "code", "team", "code review", "clean code"] 4 | summary = "" 5 | authors = [] 6 | contributors = ["AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source = "https://github.com/ryanmcdermott/clean-code-javascript#use-meaningful-and-pronounceable-variable-names" 10 | original_source_is_canonical = false 11 | crystalized = false 12 | uid = "c028bb1b-d37b-48f3-a7cb-926e107df80c" 13 | +++ 14 | ---- 15 | Bad: 16 | 17 | ```js 18 | const yyyymmdstr = moment().format("YYYY/MM/DD"); 19 | ``` 20 | 21 | Good: 22 | ```js 23 | const currentDate = moment().format("YYYY/MM/DD"); 24 | ``` 25 | 26 | ## Why 27 | 28 | * Increases understanding 29 | * Lowers cognitive load 30 | 31 | ## Derivative work 32 | 33 | > This work is a derivative of "clean-code-javascript" by Ryan Mcdermott, originally licensed under MIT. The original version can be found [here](https://github.com/ryanmcdermott/clean-code-javascript/tree/3ff9eba6d460f31db8146762bade4fcc32626762?#use-meaningful-and-pronounceable-variable-names). -------------------------------------------------------------------------------- /principles/use-searchable-names.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Use searchable names" 3 | tags = ["variables", "code", "rule", "code review", "clean code"] 4 | summary = "" 5 | authors = [] 6 | contributors = ["AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source = "https://github.com/ryanmcdermott/clean-code-javascript" 10 | original_source_is_canonical = false 11 | crystalized = false 12 | uid = "ef272889-c247-4879-882e-efd199ca9f53" 13 | +++ 14 | We will read more code than we will ever write. It's important that the code we do write is readable and searchable. By not naming variables that end up being meaningful for understanding our program, we hurt our readers. Make your names searchable. 15 | 16 | Bad: 17 | ```js 18 | // What the heck is 86400000 for? 19 | setTimeout(blastOff, 86400000); 20 | ``` 21 | 22 | Good: 23 | 24 | ```js 25 | // Declare them as capitalized named constants. 26 | const MILLISECONDS_PER_DAY = 60 * 60 * 24 * 1000; //86400000; 27 | 28 | setTimeout(blastOff, MILLISECONDS_PER_DAY); 29 | ``` 30 | ## Derivative work 31 | 32 | > This work is a derivative of "clean-code-javascript" by Ryan Mcdermott, originally licensed under MIT. The original version can be found [here](https://github.com/ryanmcdermott/clean-code-javascript/tree/3ff9eba6d460f31db8146762bade4fcc32626762). -------------------------------------------------------------------------------- /principles/use-the-same-vocabulary-for-the-same-type-of-variable.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "Use the same vocabulary for the same type of variable" 3 | tags = ["variables", "code", "rule", "code review", "clean code"] 4 | summary = "" 5 | authors = [] 6 | contributors = ["AdamCraven"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source = "https://github.com/ryanmcdermott/clean-code-javascript" 10 | original_source_is_canonical = false 11 | crystalized = false 12 | uid = "ecad0aa7-3006-4244-9e9d-961e32652db4" 13 | +++ 14 | ---- 15 | 16 | Bad: 17 | ```js 18 | getUserInfo(); 19 | getClientData(); 20 | getCustomerRecord(); 21 | getPersonDateOfBirth(); 22 | ``` 23 | Good: 24 | ```js 25 | getUser(); 26 | getUserDateOfBirth(); 27 | ``` 28 | 29 | ## Why 30 | 31 | * Using the same vocabulary creates clarity and understanding 32 | * Reduces confusion 33 | 34 | ## Derivative work 35 | 36 | > This work is a derivative of "clean-code-javascript" by Ryan Mcdermott, originally licensed under MIT. The original version can be found [here](https://github.com/ryanmcdermott/clean-code-javascript/tree/3ff9eba6d460f31db8146762bade4fcc32626762). -------------------------------------------------------------------------------- /principles/where-you-know-you-arent-aligned-resolve-early.md: -------------------------------------------------------------------------------- 1 | +++ 2 | principle = "When you know you aren’t aligned, resolve early." 3 | tags = ["team", "leadership", "medium", "practices"] 4 | summary = "Act on unalignment rapidly to ensure happy teams" 5 | authors = ["AdamCraven"] 6 | contributors = ["nickyhannaway"] 7 | license = "CC BY-SA 4.0" 8 | allow_dual_licensing_to_GPLv3 = true 9 | original_source_is_canonical = false 10 | crystalized = false 11 | uid = "07c9acab-108d-4920-af4b-e7e4e52b682f" 12 | +++ 13 | 14 | When you notice you aren't aligned and realise that will cause problems in the future, resolve them with the team early. 15 | 16 | Lack of alignment does not disappear or resolve itself automatically, it takes communication. The longer it takes for that communication to happen, the more [conflict](https://principles.dev/behavioral-interactions-teams/#conflict) is created and the slower the team runs. 17 | 18 | ## Why? 19 | 20 | We handle disagreements early because it's more expensive to resolve issues later, both in time, the energy required to resolve and team happiness is reduced if there is more conflict. 21 | 22 | ## When to apply? 23 | 24 | * When you know or feel that the team may object to your implementation. 25 | * When you don't know how others are thinking. You haven't fully understood what your team members may think. 26 | 27 | ## When not to apply? 28 | 29 | If you haven't developed a good understanding of what you think or haven't developed ideas far enough, or if your proposal isn't compelling/valuable enough versus the alternatives. For example, you may feel that you will be unaligned on something you are building but aren't clear about what it might look like, yet. You'll know this to be true when you can't articulate the what and the why of what you are doing. 30 | 31 | ### Rules of engagement as a leader: 32 | 33 | * Not everyone must be 100% aligned, but an overall majority is important. It is helpful to use principles to back up decision-making so others can fully understand and help convince them. If the rejecting parties do not have rational counter principles, they will be unlikely to be able to change minds. Allow the rejecting party to go away and gather their thoughts if time allows. 34 | * If the lack of alignment tends to be the same group of people each time, a leader should find out the reasons for this to help them find a solution. There are many reasons this could be the case; some include: A need isn't being met, the dynamics in the group have split and team-building efforts are required. 35 | * If someone is not spending time to align and uses a process - such as code review - to force their views. You can always use a secondary story to correct the problem and/or attempt to open more engaging lines of communication, such as getting on a call with them. Whilst it will be more work, team cohesion will break down rapidly if someone is enforcing their will upon everyone and is allowed to continue the behaviour. 36 | 37 | 38 | ### Examples: 39 | 40 | * Concerns noticed in grooming sessions - Bring them to the team in the conversation. 41 | * Concerns noticed when examining the story - Bring it to the team in chat. 42 | * Concerns spotted whilst doing the story - Bring it to the team in chat or with tech lead/ba/manager, who will bring it back to the team if necessary. 43 | * Concerns spotted in draft PRs - Have the team look at draft PRs. 44 | * Big design problems spotted in code review - Not ideal. Code reviews are meant to capture slight mistakes or make small adjustments, not overall design decisions or omissions in functionality. It is often better to create a corrective story to fix. 45 | * Concerns spotted in implementation - too late; it will require much rework. --------------------------------------------------------------------------------