├── .gitmessage ├── Extension Intentions.md ├── Learning Path.md ├── Migrating from V1 to V2.md ├── Movement Branches.md ├── README.md └── v1 ├── Extension Intentions.md ├── Learning Path.md └── index.md /.gitmessage: -------------------------------------------------------------------------------- 1 | 2 | #@ F Enable snarzle bifurcation 3 | # \ \ \ 4 | # \ \ Commit message 5 | # \ Change Type 6 | # Risk Level 7 | # 8 | # .----------------------------------------. 9 | # | Risk-Aware Commit Notation Cheat Sheet | 10 | # '----------------------------------------' 11 | # 12 | # For details, see 13 | # https://github.com/RefactoringCombos/ArlosCommitNotation 14 | # 15 | # .---.-------------------.--------------------------------------. 16 | # | | Risk Level | Meaning | 17 | # |---|-------------------|--------------------------------------| 18 | # | . | (Proven) Safe | Addresses all known & unknown risks | 19 | # | ^ | Validated | Addresses all known risks | 20 | # | ! | Risky | Some known risks remain unverified | 21 | # | @ | (Probably) Broken | No risk attestation | 22 | # '---'-------------------'--------------------------------------' 23 | # 24 | # .---.---------------.------------------------------------------. 25 | # | | Change Type | Meaning | 26 | # |---|---------------|------------------------------------------| 27 | # | F | Feature | Change or extend one aspect of program | 28 | # | | | behavior without altering others. | 29 | # |---|---------------|------------------------------------------| 30 | # | B | Bugfix | Repair one existing, undesirable program | 31 | # | | | behavior without altering any others. | 32 | # |---|---------------|------------------------------------------| 33 | # | r | Refactoring | Change implementation without changing | 34 | # | | | program behavior. | 35 | # |---|---------------|------------------------------------------| 36 | # | d | Documentation | Change something which communicates to | 37 | # | | | team members and does not impact | 38 | # | | | program behavior. | 39 | # '---'---------------'------------------------------------------' 40 | # 41 | # Change type casing can have several meanings based on your preference. 42 | # Refer to the full docs for details. 43 | -------------------------------------------------------------------------------- /Extension Intentions.md: -------------------------------------------------------------------------------- 1 | # Extension Intentions 2 | 3 | Each project can define a set of extension intentions. Each project should define which extension codes it uses. It is up to each project to define the approaches for each of the 4 risk levels. 4 | 5 | These are some common intentions, each used in several projects. Each also lists alternatives used in projects that don't use the code. 6 | 7 | | Prefix | Name | Intention | Alternatives | 8 | | --- | --- | --- | --- | 9 | | `m` | Merge | Merge branches.
Set risk level based on maximum for any individual commit in the branch. | Use `F`, `B`, or `r`, based on the primary intention of the branch. Optionally leave blank for merge from `main` to a feature branch. | 10 | | `t` | Test-only | Alter automated tests without altering functionality. May include code-generating code that just throws a `NotImplementedException` or similar approaches. | Use `F` or `B`, depending on which kind of work this test is going to validate. Use `r` if this is a refactoring purely within test code. It is a `.` risk level unless you also change product code. | 11 | | `e` | Environment | Environment (non-code) changes that affect development setup, and other tooling changes that don't affect program behavior (e.g. linting) | Consider the environment to be a product where the users are team members, and code it accordingly. | 12 | | `a` | Auto | Automatic formatting, code generation, or similar tasks. | Use the intention that matches the reason you are performing the action, almost-certainly as a lower-case level of risk. For example, code cleanup would be `r`, and generating code to make a test for a new feature compile would be `t` or `F`. | 13 | | `c` | Comment | Changes comments only. Does not include comments that are visible to doc-generation tools. | Use `d`. | 14 | | `C` | Content | Changes user-visible content, such as website copy. | Use `F`. | 15 | | `p` | Process | Changes some team process or working agreement. | Any of: | 16 | | `s` | Spec | Changes the spec or design. Used when team does formal specs or design reviews and keeps all such documents in the main product source, perhaps in the product code itself. | Any of: | 17 | | `n` | NOP | A commit with no changes (`--allow-empty`) | Use `r`. | 18 | | `@` | Unknown / multiple | Made a bunch of changes and are just getting it checked in. No real way to validate safety, and may not even compile. Usually used at the highest risk level (`@ @`). | Don't allow this. Require each commit to do exactly one intention and document itself accordingly. | 19 | -------------------------------------------------------------------------------- /Learning Path.md: -------------------------------------------------------------------------------- 1 | # Incremental learning and adoption path 2 | 3 | For a team that has never tried disciplined refactoring there is a steep learning curve to adopt this system. 4 | 5 | To reduce that challenge, here we describe the tiniest increments to learning and adopting the Risk-Aware Commit Notation. This way you can get used to one idea before getting overwhelmed by the next idea, and get a quicker return on the learning investment. 6 | 7 | Expect some disagreement and confusion in the team throughout this process, as people shift their thinking. As you find agreement, write down your new norms in your team agreements. 8 | 9 | Hint: this all goes much more smoothly with Mob/Ensemble Programming ([Promiscuious Pairing](https://csis.pace.edu/~grossman/dcs/XR4-PromiscuousPairing.pdf) is also pretty good) to share knowledge, increase "insights per hour", and shift norms more quickly. 10 | 11 | Hint: a good technical coach can be a huge help for your team to learn and adopt these skills. 12 | 13 | ## 1. Working in a short-lived branch 14 | 15 | While Trunk-Based Development directly in `main` is good for keeping everyone's work in sync and reducing merges, a short-lived branch lets you document the steps in your development process, telling a story to reviewers and future readers of your changes. 1 day is a good maximum lifetime for a branch (shorter is better), enabling incremental commits without incurring most of the risks of long-lived branches. 16 | 17 | If you're in a context where code review is part of the flow of work, teach reviewers how to look at the individual branch commits as an option that may be easier than viewing the whole change all at once. Mention this option in the description of the final Merge Request, e.g. "see the individual commits in the branch for more details". 18 | 19 | Depending on your VCS solution, you will need to find a way to keep these details visible after merging to main, such as `rebase` + `merge --no-ff`. 20 | 21 | ### Example commit history 22 | 23 | ``` 24 | Implement automatic log-off 25 | Clean up the login module 26 | ``` 27 | 28 | One benefit of working this way is that it's easier to provide rich, detailed descriptions for the smaller increments in a branch than for the whole ball of changes. 29 | 30 | In legacy code, we often see code that looks "weird" but we don't know if was deliberately made this way for a subtle reason, or the dev just didn't get around to cleaning it up. Incremental work with rich descriptions can be really helpful for future readers trying to understand why the code ended up like this. 31 | 32 | ## 2. Tag refactorings with `@ r` 33 | 34 | If a change contains only refactoring, indicate that by prefixing the change description with `@ r `. 35 | 36 | The refactoring need not be especially disciplined. This is just about separating refactoring from non-refactoring in your commit history. 37 | 38 | Folks on your team probably have [multiple working defintions of refactoring](https://jay.bazuzi.com/DefinitionsOfRefactoring/), and this is an invitation to examine those defintions and find a shared understanding. 39 | 40 | Refactorings often have a large diff even though they don't change behavior and are out of proportion with the conceptual size of the change. For example "rename A to B" is one small idea but every line that references `A` will be affected. Combining refactorings with deliberate behavior changes makes reading the total diff difficult. Separating refactorings into their own commits will make code review easier. You should be able to scan the commit history and easily see which are refactorings and which are not. 41 | 42 | ### Example commit history 43 | 44 | ``` 45 | Implement automatic log-off 46 | @ r Remove duplication in login module 47 | @ r Rename a bunch of stuff for clarity 48 | ``` 49 | 50 | A future reader of the code trying to understand how the code got this way, if you're looking for a deliberate behavior change you know you can ignore `@ r` changes; if you see a behavior change in a commit marked `@ r` you know it was accidental. 51 | 52 | ## 3. Pick up easy wins 53 | 54 | Once the team has learned the above practices, the following tags are easy to adopt. 55 | 56 | - `. t` for test-only changes 57 | - `. a` for auto-formatting 58 | - `! r` for named refactorings 59 | 60 | ### Example commit history 61 | 62 | ``` 63 | . t fill in missing tests for existing login code 64 | ! r Extract Method 65 | . a autoformat with prettier 66 | ``` 67 | 68 | If you haven't already, this is a good time to add automatic code formatting to your CI checks, and bring all existing code in to compliance with that formatting. 69 | 70 | ## 4. Tag Features and Bug Fixes with `@ F` and `@ B`. 71 | 72 | Make a team agreement to categorize commits and tag with one of the above. 73 | 74 | It may be a good idea to allow `@ @` (uncategorized) in certain contexts. One example is "checkpointing", where you have some in-progress experimental changes on one machine and want to try them on another machine or share them with a coworker. 75 | 76 | At this point you can considering adopting a regex check to ensure that all commits are tagged. See https://github.com/RefactoringCombos/ArlosCommitNotation/issues/29. 77 | 78 | ### Example commit history 79 | 80 | ``` 81 | @ F Implement automatic log-off 82 | @ r Remove duplication in login module 83 | ! r Several renames for clarity 84 | ``` 85 | 86 | ## 5. Refactor to prepare code for behavior change 87 | 88 | > Make the change easy (warning: this may be hard), then make the easy change. -- Kent Beck 89 | 90 | The team makes the following behavior change: 91 | 92 | * **When** about to start a feature or bug fix, 93 | * **We used to** attempt to fit this behavior change to fit in to the current design. 94 | * **Now we** 95 | 1. identify what design would make it really easy to implement this feature in a natural way, and 96 | 2. what small refactorings would get from here to there. 97 | 98 | You're looking for `! r`-style, single named refactorings. Commit histories will start to look like a series of refactorings followed by a deliberate behavior change. 99 | 100 | ### Example commit history 101 | 102 | ``` 103 | @ F Automatically log-off when idle 104 | ! r Introduce parameter 105 | ! r Import nodatime 106 | ! r Merge duplicate code 107 | ! r Extract Method 108 | ``` 109 | 110 | This also gives you the option of merging to `main` before your feature or bug fix is complete. For example, on one day you might do a bunch of `! r` refactorings, get them approved and merged quickly thanks to the above practices, then continue towards your feature or bug fix the next day. 111 | 112 | ## 6. Safe Refactoring 113 | 114 | Can your IDE safely execute a refactoring? If so, you can use `. r`. This is great for code review, as reviewers can now skim some changes instead of examining them carefully for correctness issues. This means means you can get your code review results back even more quickly. 115 | 116 | Where your IDE is unable to provide the required level of safety, look at [recipe-based refactorings](https://github.com/InnovatingTeams/provable-refactorings). 117 | 118 | Once your team has gotten comfortable with `. r`, consider changing your code review and delivery protocols to allow `.` (safe) changes to skip some/most/all of those requirements. This has several benefits, including creating an incentive for developers to work in this safe way. 119 | 120 | Note that this level of safety is hard to get in dynamic languages. If that's your context, you may need to instead make the investment in comprehensive test coverage to unlock `^ r`. 121 | 122 | ### Example commit history 123 | 124 | ``` 125 | . r Merge identical methods 126 | . r Rename local variables 127 | . r Extract Method 128 | ``` 129 | 130 | ## 7. Small features and bug fixes 131 | 132 | Once you get familiar with refactoring in preparation for a feature, you can further reduce risk by refactoring to the point where a feature or bug fix only requires a small code change. That unlocks `^ F` and `^ B`. 133 | 134 | ### Example commit history 135 | 136 | ``` 137 | 138 | ^ F Automatically log-off when idle 139 | . r 140 | . t 141 | . r 142 | . r 143 | ! r 144 | . r 145 | . t 146 | . r 147 | ! r 148 | . r Merge duplicate code 149 | . r Extract Method 150 | ``` 151 | 152 | # TDD with RACN 153 | 154 | In a strict Test-Driven Development cycle almost all commits are either a new test or a refactoring. When using RACN: 155 | 156 | 1. Write a new failing test (Red) 157 | * (optional) Negate the assertion or mark the test as expected to fail and commit with `. t ` 158 | 1. Make it pass (Green) 159 | 1. Commit with `. f` or `. F`. 160 | 1. Refactor. 161 | 1. Commit each refactoring. 162 | - If the refactoring is executed with a known safe tool or recipe, use `. r`. 163 | - If this is new, un-called code and you have been doing TDD since the start, you probably have the test coverage to use `^ r`. 164 | - If you are "triangulating", converting special-case code to a generalized algorithm, use may need to use `@ r`. 165 | 166 | ### Example commit history 167 | 168 | ``` 169 | ^ r replace algorithm 170 | ^ F FizzBuzz of 3 is "Fizz" 171 | ^ F FizzBuzz of 2 is "2" 172 | . r rename parameter 173 | ^ F FizzBuzz of 1 is "1" 174 | ``` 175 | 176 | # Alternatives 177 | 178 | ## All-at-once 179 | 180 | If working as an ensemble with a highly skilled and capable technical coach, then bring in all of the practices at once and let the coach guide the team to use them as the work requires. 181 | 182 | ## Safety First 183 | 184 | Start by introducing `. r` and suggesting incremental work in a branch. Allow these kinds of changes a fast track through review and release. Build from there. 185 | 186 | ## Categorize first 187 | 188 | This approach scales up to larger multi-team organizations where there's not enough hands-on coaching capacity to do it all at once. 189 | 190 | Make the requirement that all changes must be categorized in to one of Feature (`@ F`), Bug Fix (`@ B`), or Refactoring (`@ r`) and tagged as such. No other change to developer behavior is required. `@ @` is an escape valve, e.g. for checkpointing work to move it to another machine. 191 | 192 | If a change contains both feature and bug fix work, use `@ F`. 193 | 194 | If a change contains both refactoring and non-refactoring work, use the appropriate non-refactoring tag. 195 | 196 | Invite developers/pairs/ensembles to use other risk and intent annotations as they see fit, and praise when that is done, but don't require it at first. 197 | 198 | Roll out in these increments: 199 | 200 | 1. Categorize (`@ F` / `@ B` / `@ r` / `@ @`) 201 | 2. Corral Risk (`! F`, `! B` / `! r`) 202 | 3. Validated (`^ F` / `^ B` / `^ r`) 203 | 4. Safe (`. r`) 204 | -------------------------------------------------------------------------------- /Migrating from V1 to V2.md: -------------------------------------------------------------------------------- 1 | # Migrating from V1 to V2 2 | 3 | Where `x`/`X` is an intention code: 4 | 5 | | V1 | V2 | 6 | |--------|-------| 7 | | `x - ` | `. X` | 8 | | `X - ` | `^ X` | 9 | | `X!!` | `! X` | 10 | | `X**` | `@ X` | 11 | 12 | ## Notes 13 | 14 | - We now split risk and intention into 2 different characters. 15 | - The new system uses consistent casing for the intention. 16 | * The old system's lower case becomes `.` and upper case becomes `^` (or higher). 17 | - Risk is always before intention 18 | - Risk is a single character 19 | - `*` becomes `@` 20 | - There are no more doubled characters, so we avoid shell interactions (old `!!`) and the appearance of cursing (old `**`). 21 | -------------------------------------------------------------------------------- /Movement Branches.md: -------------------------------------------------------------------------------- 1 | # Movement-Oriented Branches 2 | 3 | This branch model is designed to clarify intention and speed up code review. It also improves safety by separating goals. 4 | 5 | Consider our code history like a piece of classical music. It is long, but there are themes. It explores one idea for a period of time, then moves on to the next idea. These ideas are called movements in classical music. In code, we convey them using branches. 6 | 7 | We convey movements by using the following behaviors. 8 | 9 | 1. Make a new branch for each idea. Keep the ideas small. 10 | 2. Use the Risk-Aware Commit Notation on the branch. 11 | 3. Use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) in the merge commit. Convey the core idea for the movement. 12 | 13 | There are also optional behaviors: 14 | 15 | * (optional) Indicate risky commits in the merge commit, using a `Risky changes:` commit trailer. 16 | * (optional) Use rebase + a no-fast-forward merge, to make the side branch visible in history 17 | 18 | ## Example 19 | 20 | Commit history looking at main with side branches collapsed (`git log --oneline --merges --first-parent` to only show merge commits): 21 | ``` 22 | feat: authenticate with multiple social auth providers. 23 | feat: calculate sales tax using third-party service 24 | chore: update dependencies 25 | refactor: isolate payment processing from checkout flow 26 | ``` 27 | 28 | Merge commit details: 29 | ``` 30 | feat: authenticate with multiple social auth providers. 31 | 32 | Authorization now prompts the user in two phases. First we ask for 33 | their username or email, which we use to find the right provider. 34 | Then we send them through that provider's auth mechanism. 35 | 36 | Risky changes: 37 | a5de73: ! r Switched algorithm for email categorization. 38 | e67c8e: ! F Split login UX into 2 steps. 39 | ``` 40 | 41 | Commit history for a side branch (`git log --oneline --graph`): 42 | ``` 43 | * feat: authenticate with multiple social auth providers. 44 | | \ 45 | | * ^ F Add Github and Facebook OAuth providers 46 | | * ^ F Add Microsft OAuth provider 47 | | * ^ F Allow / require the user to choose which provider to use when creating a new account - still only one option. 48 | | * . r convert 1 to many-of-one for providers 49 | | * ! r Switched algorithm for email categorization 50 | | * . t add tests for email categorization 51 | | * . r extract method 52 | | * . r rename 53 | | * . r extract method 54 | | * ! F Split login UX into 2 steps. 55 | | * . t test account creation failure 56 | | * . t test account creation success 57 | | * . t test login failure 58 | | * . t test login success 59 | | * . f LocalMemoryAuthenticator allows easy testing for code that uses auth providers (simulator) 60 | | * . t extract commonalities to test providers through an interface 61 | | * . t test the default provider (Google). Add these to the platform test suite. 62 | | * . r extract method; move method 63 | | * . r extract method; move method 64 | | * . r introduce parameter object (oauth provider) 65 | | * . r extract method 66 | | * . r extract method 67 | |/ 68 | * feat: calculate sales tax using third-party service 69 | ... 70 | ``` 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Risk-Aware Commit Notation 2 | 3 |

(aka Arlo's Commit Notation)

4 | 5 | This commit notation allows developers to convey 2 critical pieces of metadata about each commit: 6 | 7 | 1. How risky is it? What has the original author done to mitigate risk? 8 | 2. What was the intention? When the original author changed the code, what was s/he attempting to accomplish? 9 | 10 | This information is conveyed in the first 3 characters of the commit summary line. That way a receiving developer can quickly scan the commit log in order to determine risk and intent for any incoming change set. 11 | 12 | This is particularly useful when: 13 | 14 | 1. As a reviewer, deciding whether to approve a pull request 15 | 2. As a developer, getting your pull request approved faster and more easily 16 | 4. Reading `main` — just the pull request commit summaries to understand the history of changes for a release. 17 | 18 | ## The Four Risk Levels 19 | 20 | We divide all behaviors of the system into 3 sets. The change is intended to alter the *Intended Change* while not altering any of the *Invariants*. The *Risk Levels* are based on correctness guarantees: which invariants can this commit guarantee did not change, and can this commit guarantee that it changed the intended change in the way the authors intended? 21 | 22 | | Risk Level | Code | Example | Meaning | Correctness Guarantees | 23 | |-----------------------|------|--------------------------------------------|----------------------------------------|-------------------------------------------------------| 24 | | **(Proven) Safe** | `.` | `. r Extract method` | Addresses all known and unknown risks. | Intended Change, Known Invariants, Unknown Invariants | 25 | | **Validated** | `^` | `^ r Extract method` | Addresses all known risks. | Intended Change, Known Invariants | 26 | | **Risky** | `!` | `! r Extract method` | Some known risks remain unverified. | Intended Change | 27 | | **(Probably) Broken** | `@` | `@ r Start extracting method with no name` | No risk attestation. | | 28 | 29 | Behavior categories: 30 | 31 | * **Intended Change:** The 0 or 1 behavior change intended in the commit. Could be verified by one test assertion. By default, a commit with more than 1 behavior change cannot be represented at any risk level better than *Probably Broken*. 32 | * **Known Invariants:** All behaviors known to the development team at the time the change was made. Automated tests can greatly increase the size of this set, thus enhancing safety when commits are at a risk level that guarantees correctness for Known Invariants. However, this set also includes behaviors that are known but not tested. 33 | * **Unknown Invariants:** All behaviors not known to the development team at the time the change was made, including behaviors that were once known but have been forgotten. These behaviors are guaranteed to be untested and untestable, as the development team does not know they exist. 34 | 35 | Risk levels: 36 | 37 | * **Safe:** Developer performed the task in a way that prevents all potential risks, even to invariants that developer is not aware of. 38 | * **Validated:** Developer performed the task in some way that includes validation for the intended change and all invarants the developer thought of. The most common technique is developer-written automated tests. 39 | * **Risky:** Developer is aware of risks and attempted to mitigate them as much as possible, but only the intended change is formally verified. Commonly this includes a manual change that the developer could not fully verify. 40 | * **Broken:** Either known to be broken, or developer couldn't even check to see if it works. May not compile. Used when the developer cannot see the results of the work without checking in, or as a savepoint when the developer is about to switch tasks or direction. 41 | 42 | ## Core Intentions 43 | 44 | These developer intentions exist on every project. They are always allowed in commits that use this notation. 45 | 46 | Each intention can appear at any of the 4 risk levels. Each intention's full details section includes the potential risks inherent in that kind of change, as well as common approaches to attain each risk level. 47 | 48 | | Prefix | Name | Intention | 49 | |------------|---------------|-------------------------------------------------------------------------------------------| 50 | | `F` or `f` | Feature | Change or extend one aspect of program behavior without altering others. | 51 | | `B` or `b` | Bugfix | Repair one existing, undesirable program behavior without altering any others. | 52 | | `R` or `r` | Refactoring | Change implementation without changing program behavior. | 53 | | `D` or `d` | Documentation | Change something which communicates to team members and does not impact program behavior. | 54 | 55 | ### Casing 56 | 57 | Each intention may be expressed in UPPERCASE or lowercase. The team uses this distinction to mean roughly "pay more attention to the ones in uppercase". Teams commonly use this for one of 2 different meanings. 58 | 59 | * **Intended behavior change**. UPPERCASE means the commit intended to change 1 behavior; lowercase means it intended to change 0 behaviors. With this approach, functionality changes would always be `F`, bugfixes `B`, refactorings `r`, and documentation `d`. 60 | * **User-visibility**. UPPERCASE means the commit altered something user-visible. It should appear in the changelog or other documentation (perhaps in summarized for combined with other uppercase changes); lowercase means the behavior change is entirely internal. With this approach all letters can have both forms. Even a refactoring could be `R` if, for example, it adds to an internal API and you want to communicate that to other development teams. 61 | 62 | ### Feature or Functionality 63 | 64 | **Intended Change:** 1 behavior. Could be described by a single unit test assertion. 65 | 66 | **Known Risks** 67 | 68 | * May alter unrelated feature (spooky action at a distance). 69 | * May alter a piece of this feature that you intended to remain unchanged. 70 | * May implement the intended change in a way different than intended. 71 | 72 | | Code | Known Approaches | 73 | |-------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 74 | | `. F` | Meets all criteria for `^ F` and developers are the only users of the feature. For example, extends build tooling for your own build or adds debug logging. | 75 | | `^ F` | Meets all of:
  • Change is <= 8 LoC[5]
  • Feature was fully unit tested prior to this change.
  • Change includes new or changed unit tests to match intended behavior alteration.
| 76 | | `! F` | Change includes unit tests for new behavior. | 77 | | `@ F` | No automatic tests, or unfinished implementation. | 78 | 79 | ### Bugfix 80 | 81 | A bugfix is a lot like a feature. However, the intention is to change an undesired — and usually unintentional — behavior of the current system. The risk profile is similar but the intention is different, so there are often more operational risks. 82 | 83 | **Intended Change:** 1 behavior. Could be described by a single unit test assertion. 84 | 85 | **Known Risks** 86 | 87 | * Intended change may have unintended consequences in the market. For example, customers may be depending on the bug. 88 | * May alter unrelated feature (spooky action at a distance). 89 | * May alter a piece of this feature that you intended to remain unchanged. 90 | * May implement the intended change in a way different than intended. 91 | 92 | | Code | Known Approaches | 93 | |-------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 94 | | `. B` | Meets all criteria for `^ B` and developers are the only users of the changed functionality. For example, fixes build tooling for your own build or corrects debug logging format. | 95 | | `^ B` | Meets all of:
  • Reviewed current and new behavior with customer representative.
  • Change is <= 8 LoC[5]
  • Bug's original (buggy) behavior was captured in a unit test prior to this change.
  • Change includes 1 changed unit test, matching intended behavior alteration.
| 96 | | `! B` | Change includes unit tests for new behavior. | 97 | | `@ B` | No automatic tests, or unfinished implementation. | 98 | 99 | ### Refactoring or Remodeling 100 | 101 | A Refactoring or Remodeling intends to alter the program in some way without changing any behavior. The risk levels indicate the probability of the commit living up to that intention, based on how the code change was executed. 102 | 103 | **Intended Change:** 0 runtime behaviors; 1 code structure. 104 | 105 | **Known Risks** 106 | 107 | * May cause a bug. 108 | * May fix a bug. 109 | * May change a behavior in a way that doesn't impact a user. 110 | * May force a test update. 111 | 112 | | Code | Known Approaches | 113 | |-------|----------------------------------------------------------------------------------------------------------------------------------------------------| 114 | | `. r` | One of:
  • Provable refactoring[2]
  • Test-supported Procedural Refactoring[3] entirely within test code
| 115 | | `^ r` | Test-supported Procedural Refactoring[3] | 116 | | `! r` | Identified single, named refactoring, but executed by editing code or without whole-project test coverage. | 117 | | `@ r` | Remodeled by editing code, even in small chunks. | 118 | 119 | ### Documentation 120 | 121 | **Intended Change:** 0 behaviors. 122 | 123 | Changes that don't impact the code, but do change documentation around the code. The team should decide whether end-user documentation changes are `D` or `F`[1]. 124 | 125 | **Known Risks** 126 | 127 | * May mislead future developers. 128 | * May mislead other stakeholders. 129 | * May alter team processes in ways that have unintended consequences. 130 | 131 | | Code | Known Approaches in source files | Known Approaches in other files | 132 | |-------|----------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| 133 | | `. d` | Developer-visible documentation verified to generate byte-identical compilation. | Any developer-visible documentation that does not change a process | 134 | | `^ d` | Verified by running tests, or things like changing text on a dev-only screen. | Dev-impacting only, but changes compilation or process. E.g. changes code-review checklist. | 135 | | `! d` | Verified only by compiling and launching the application. | Alters an important process. | 136 | | `@ d` | Not verified. | Trying out a process change that is intended to gain info, not to necessarily work. | 137 | 138 | ## Extension Intentions 139 | 140 | The basic intention annotations are comprehensive to describe any kind of change, but it may be useful to extend the notation to your project to provide additional detail that is useful in your context. Read more about [Extension Intensions](Extension%20Intentions.md). 141 | 142 | # Provable Refactorings 143 | [2]:#provable-refactorings 144 | 145 | If you can get a series of commits that is all lowercase commits, you can deploy without the need for Regression Testing or lengthy conversations about accepting the pull request to trunk. 146 | 147 | A provable refactoring requires a burden of proof. The main methods of proof are 148 | * automated refactoring via tool, with knowledge of tool bugs. 149 | * scripted manual refactoring, using the compiler to verify each step. [Recipes Here](https://github.com/InnovatingTeams/provable-refactorings) 150 | * use formal methods to prove the before state and after state are equal. 151 | 152 | With discipline these can prove bug-for-bug compatibility. They demonstrate safety for unknown bugs, even guaranteeing that you do not accidentally fix a bug you don't know exists (but your customers may be depending on). 153 | 154 | All of these recipes use static analysis to demonstrate safety. As such, they work equally well on code that lacks tests. They can be a good way to make code testable. Their downside is that they are language-specific. 155 | 156 | # Test-supported Procedural Refactorings 157 | [3]:#test-supported-procedural-refactorings 158 | 159 | These are refactorings with a lower standard of proof: 160 | 1. Commit contains only a single refactoring. 161 | 2. Refactoring is named and published (e.g., in [Fowler's refactoring catalog](https://refactoring.com/catalog/)). 162 | 3. Either: 163 | 1. Your entire product is very highly tested, or 164 | 2. you are working on new code that is not yet called. 165 | 4. You followed the published steps, including running full-suite test runs when indicated. 166 | 167 | Note that this cannot prove bug-for-bug compatibility. It can only demonstrate that you didn't cause any problems that have been thought of before; it does not demonstrate safety for novel bugs. 168 | 169 | Requirement 3 is there because many refactorings can have non-local effects. It is not sufficient to have great tests on the code you are changing. You also need great tests on the code that you are not intending to change, to demonstrate that you didn't. Therefore, until your entire codebase is very highly tested, you will only be able to use the `.` risk level on new code that is uncalled by your product. 170 | 171 | # End-User Documentation 172 | [1]:#end-user-documentation 173 | 174 | Changing end user documentation changes behaviors, so can be considered a feature, bugfix, or refactoring, depending on its nature. Most teams use those codes (including levels of risk) accordingly. 175 | 176 | However, teams that use case to distinguish user-visible and user-invisible behavior changes may wish to use `D` for end user documentation changes instead. This loses the ability to see the full intention of the change, but highlights that it was focused on documentation. Do whatever is most expressive for that commit. 177 | 178 | # Small Features and Bug Fixes 179 | [4]:#small-features-and-bug-fixes 180 | 181 | Features and bug fixes intentionally change behavior. This makes them much riskier than refactorings. It is not possible to prove that they have only the intended effect. However, small changes are much lower risk for three reasons: 182 | 183 | 1. It's easy to see the possible side effects of small chunks of code. 184 | 2. It's easy to code review, so you are likely to get good reviews. 185 | 3. It's only possible when the code is well-organized already. 186 | 187 | Therefore, we treat any feature or bug fix as high risk if it changes more than 8 lines of code in one commit. This includes test changes. 188 | 189 | One good approach to enable small features is to refactor until the feature change is easy. Then add the feature one piece at a time, with a test for each. 190 | 191 | # Tool Support 192 | ## Git CLI 193 | Git allows you to specify a user-specific commit message template that shows up 194 | when you run `git commit`. [`.gitmessage`](./.gitmessage) contains a plaintext 195 | version of this document formatted for use as a git commit template. You can use 196 | it by following these steps: 197 | 198 | 1. Download `.gitmessage` 199 | 2. Move `.gitmessage` to your home directory (`mv path/to/your/Downloads/.gitmessage ~/.gitmessage`) 200 | 3. Configure `git` to look for this message: `git config --global commit.template ~/.gitmessage` 201 | 4. Try it out -- in any git repo, make some change, stage it, then run `git 202 | commit`. You'll know it's working if you see the contents of `.gitmessage` in 203 | your commit message editor. 204 | 205 | Note that you won't see this template when you are `--amend`ing a commit, when 206 | you provide `-m` to `git commit`, during interactive rebases, and any other time 207 | where the commit message already exists or is provided by another tool. 208 | 209 | # Living Documentation 210 | 211 | We invite you to submit pull requests to help evolve this notation and methodology. 212 | 213 |
LoC: Lines of Code 214 | 215 | [5]:#lines-of-code 216 | -------------------------------------------------------------------------------- /v1/Extension Intentions.md: -------------------------------------------------------------------------------- 1 | ## Extension Intentions 2 | 3 | Each project can define a set of extension intentions. Each project should define which extension codes it uses. It is up to each project to define the approaches for each of the 4 risk levels. 4 | 5 | These are some common intentions, each used in several projects. Each also lists alternatives used in projects that don't use the code. 6 | 7 | | Prefix | Name | Intention | Alternatives | 8 | | --- | --- | --- | --- | 9 | | M | Merge | Merge branches | Use `F`, `B`, or `R`, based on the main intention of the branch, with risk level based on maximum for any individual commit in the branch. Optionally leave blank for merge from main to a feature branch. | 10 | | T | Test-only | Alter automated tests without altering functionality. May include code-generating code that just throws a `NotImplementedException` or similar approaches. | Use `f` or `b`, depending on which kind of work this test is going to validate. Use `r` if this is a refactoring purely within test code. It is a lower-case letter unless you also change product code. | 11 | | E | Environment | Environment (non-code) changes that affect development setup, and other tooling changes that don't affect program behavior (e.g. linting) | Consider the environment to be a product where the users are team members, and code it accordingly. | 12 | | A | Auto | Automatic formatting, code generation, or similar tasks. | Use the intention that matches the reason you are performing the action, almost-certainly as a lower-case level of risk. For example, code cleanup would be `r`, and generating code to make a test for a new feature compile would be `t` or `f`. | 13 | | C | Comment | Changes comments only. Does not include comments that are visible to doc-generation tools. | Use `D`. | 14 | | P | Process | Changes some team process or working agreement. | Any of:
  • Use a tacit, informal process.
  • Use `D`.
  • Keep your process definition outside of source control.
| 15 | | S | Spec | Changes the spec or design. Used when team does formal specs or design reviews and keeps all such documents in the main product source, perhaps in the product code itself. | Any of:
  • Use informal specs.
  • Use `D`.
  • Use your test suite as your only spec.
  • Keep your spec / design outside of source control.
| 16 | | * | Unknown / multiple | Made a bunch of changes and are just getting it checked in. No real way to validate safety, and may not even compile. Usually used at the highest risk level (`***`). | Don't allow this. Require each commit to do exactly one intention and document itself accordingly. | 17 | -------------------------------------------------------------------------------- /v1/Learning Path.md: -------------------------------------------------------------------------------- 1 | # Incremental learning and adoption path 2 | 3 | For a team that has never tried disciplined refactoring there is a steep learning curve to adopt this system. 4 | 5 | To reduce that challenge, here we describe the tiniest increments to learning and adopting Arlo's Commit Notation. This way you can get used to one idea before getting overwhelmed by the next idea, and get a quicker return on the learning investment. 6 | 7 | Expect some disagreement and confusion in the team throughout this process, as people shift their thinking. As you find agreement, write down your new norms in your team agreements. Give feedback to Arlo's Commit Notation about how it could be been clearer for you. 8 | 9 | Hint: this all goes much more smoothly with Mob/Ensemble Programming ([Promiscuious Pairing](https://csis.pace.edu/~grossman/dcs/XR4-PromiscuousPairing.pdf) is also pretty good) to share knowledge, increase "insights per hour", and shift norms more quickly. 10 | 11 | Hint: a good technical coach can be a huge help for your team to learn and adopt these skills. 12 | 13 | ## 1. Working in a short-lived branch 14 | 15 | While Trunk-Based Development directly in `main` is good for keeping everyone's work in sync and reducing merges, a short-lived branch lets you document the steps in your development process, telling a story to reviewers and future readers of your changes. 1 day is a good maximum lifetime for a branch (shorter is better), enabling incremental commits without incurring most of the risks of long-lived branches. 16 | 17 | If you're in a context where code review is part of the flow of work, teach reviewers how to look at the individual branch commits as an option that may be easier than viewing the whole change all at once. Mention this option in the description of the final Merge Request, e.g. "see the individual commits in the branch for more details". 18 | 19 | Depending on your VCS solution, you will need to find a way to keep these details visible after merging to main, such as `rebase` + `merge --no-ff`. 20 | 21 | ### Example commit history 22 | 23 | ``` 24 | Implement automatic log-off 25 | Clean up the login module 26 | ``` 27 | 28 | One benefit of working this way is that it's easier to provide rich, detailed descriptions for the smaller increments in a branch than for the whole ball of changes. 29 | 30 | In legacy code, we often see code that looks "weird" but we don't know if was deliberately made this way for a subtle reason, or the dev just didn't get around to cleaning it up. Incremental work with rich descriptions can be really helpful for future readers trying to understand why the code ended up like this. 31 | 32 | ## 2. Tag refactorings with `R**` 33 | 34 | If a change contains only refactoring, indicate that by prefixing the change description with `R** `. 35 | 36 | The refactoring need not be especially disciplined. This is just about separating refactoring from non-refactoring in your commit history. 37 | 38 | Folks on your team probably have [multiple working defintions of refactoring](https://jay.bazuzi.com/DefinitionsOfRefactoring/), and this is an invitation to examine those defintions and find a shared understanding. 39 | 40 | Refactorings often have a large diff even though they don't change behavior and are out of proportion with the conceptual size of the change. For example "rename A to B" is one small idea but every line that references `A` will be affected. If combined with deliberate behavior changes that will make reading the total diff difficult. Separating refactorings into their own commits will make code review easier. You should be able to scan the commit history and easily see which are refactorings and which are not. 41 | 42 | ### Example commit history 43 | 44 | ``` 45 | Implement automatic log-off 46 | R** Remove duplication in login module 47 | R** Rename a bunch of stuff for clarity 48 | ``` 49 | 50 | For a future reader of the code trying to understand how the code got this way, if you're looking for a deliberate behavior change you know you can ignore `R**` changes; if you see a behavior change in a commit marked `R**` you know it was accidental. 51 | 52 | ## 3. Pick up easy wins 53 | 54 | Once the team has learned the above practices, the following tags are easy to adopt. 55 | 56 | - `t` for test-only changes 57 | - `a` for auto-formatting 58 | - `R!!` for named refactorings 59 | 60 | ### Example commit history 61 | 62 | ``` 63 | t - fill in missing tests for existing login code 64 | R!! Extract Method 65 | a - autoformat with prettier 66 | ``` 67 | 68 | If you haven't already, this is a good time to add automatic code formatting to your CI checks, and bring all existing code in to compliance with that formatting. 69 | 70 | ## 4. Tag Features and Bug Fixes with `F**` and `B**`. 71 | 72 | Make a team agreement to categorize commits and tag with one of the above. 73 | 74 | It may be a good idea to allow `***` (uncategorized) in certain contexts. One example is "checkpointing", where you have some in-progress experimental changes on one machine and want to try them on another machine or share them with a coworker. 75 | 76 | At this point you can considering adopting a regex check to ensure that all commits are tagged. See https://github.com/RefactoringCombos/ArlosCommitNotation/issues/29. 77 | 78 | ### Example commit history 79 | 80 | ``` 81 | F** Implement automatic log-off 82 | R** Remove duplication in login module 83 | R** Rename a bunch of stuff for clarity 84 | ``` 85 | 86 | ## 5. Refactor to prepare code for behavior change 87 | 88 | > Make the change easy (warning: this may be hard), then make the easy change. -- Kent Beck 89 | 90 | For each feature or bug fix, practice replacing "how can I get this behavior change to fit in to the current design?" with "what design would make it really easy to implement this feature in a natural way?" and "what small refactorings would it take to get from here to there?". You're looking for `R!!`-style, single named refactorings. Commit histories will start to look like a series of refactorings followed by a deliberate behavior change. 91 | 92 | ### Example commit history 93 | 94 | ``` 95 | F** Automatically log-off when idle 96 | R!! Introduce parameter 97 | R!! Import nodatime 98 | R!! Merge duplicate code 99 | R!! Extract Method 100 | ``` 101 | 102 | This also gives you the option of merging to `main` before your feature or bug fix is complete. For example, on one day you might do a bunch of `R!!` refactorings, get them approved and merged quickly thanks to the above practices, then continue towards your feature or bug fix the next day. 103 | 104 | ## 6. Safe Refactoring 105 | 106 | Can your IDE safely execute a refactoring? If so, you can use `r`. This is great for code review, as reviewers can now skim some changes instead of examining them carefully for correctness issues. This means means you can get your code review results back even more quickly. 107 | 108 | Where your IDE is unable to provide the required level of safety, look at [recipe-based refactorings](https://github.com/InnovatingTeams/provable-refactorings). 109 | 110 | Once your team has gotten comfortable with `r`, consider changing your code review and delivery protocols to allow lower-case (safe) changes to skip some/most/all of those requirements. This has several benefits, including creating an incentive for developers to work in this safe way. 111 | 112 | Note that this level of safety is hard to get in dynamic languages. If that's your context, you may need to instead make the investment in comprehensive test coverage to unlock `R`. 113 | 114 | ### Example commit history 115 | 116 | ``` 117 | r - Merge identical methods 118 | r - Rename local variables 119 | r - Extract Method 120 | ``` 121 | 122 | ## 7. Small features and bug fixes 123 | 124 | Once you get in familiar with refactoring in preparation for a feature, you can further reduce risk by refactoring to the point where a feature or bug fix only requires a small code change. That unlocks `F` and `B`. 125 | 126 | ### Example commit history 127 | 128 | ``` 129 | 130 | F - Automatically log-off when idle 131 | r - 132 | t - 133 | r - 134 | r - 135 | R!! 136 | r - 137 | t - 138 | r - 139 | R!! 140 | r - Merge duplicate code 141 | r - Extract Method 142 | ``` 143 | 144 | # TDD with ACN 145 | 146 | In a strict Test-Driven Development cycle almost all commits are either a new test or a refactoring. When using ACN: 147 | 148 | 1. Write a new failing test (Red) 149 | 1. Make it pass (Green) 150 | 1. Commit with `F - `. 151 | 1. Refactor. 152 | 1. Commit each refactoring. 153 | - If the refactoring is executed with a known safe tool or recipe, use `r`. 154 | - If this is new, un-called code and you have been doing TDD since the start, you probably have the test coverage to use `R`. 155 | - If you are "triangulating", converting special-case code to a generalized algorithm, use may need to use `R**`. 156 | 157 | ### Example commit history 158 | 159 | ``` 160 | R - replace algorithm 161 | F - FizzBuzz of 3 is "Fizz" 162 | F - FizzBuzz of 2 is "2" 163 | r - rename parameter 164 | F - FizzBuzz of 1 is "1" 165 | ``` 166 | 167 | # Alternatives 168 | 169 | ## All-at-once 170 | 171 | If working as an ensemble with a highly skilled and capable technical coach, then bring in all of the practices at once and let the coach guide the team to use them as the work requires. 172 | 173 | ## Categorize first 174 | 175 | This approach scales up to larger multi-team organizations where there's not enough hands-on coaching capacity to do it all at once. 176 | 177 | Make the requirement that all changes must be categorized in to one of Feature (`F**`), Bug Fix (`B**`), or Refactoring (`R**`) and tagged as such. No other change to developer behavior is required. `***` is an escape valve, e.g. for checkpointing work to move it to another machine. 178 | 179 | If a change contains both feature and bug fix work, use `F**`. 180 | 181 | If a change contains both refactoring and non-refactoring work, use the appropriate non-refactoring tag. 182 | 183 | Invite developers/pairs/ensembles to use other risk and intent annotations as they see fit, and praise when that is done, but don't require it at first. 184 | 185 | Roll out in these increments: 186 | 187 | 1. Categorize (`F**` / `B**` / `R**` / `***`) 188 | 2. Corral Risk (`F!!`, `B!!` / `R!!`) 189 | 3. Validated (`F` / `B` / `R`) 190 | 4. Safe (`f` / `b` / `r`) 191 | 192 | ## Safety First 193 | 194 | Start by introducing `r` an suggesting incremental work in a branch. Allow these kinds of changes a fast track through review and release. Build from there. 195 | -------------------------------------------------------------------------------- /v1/index.md: -------------------------------------------------------------------------------- 1 | # Arlo's Commit Notation 2 | 3 | This commit notation allows developers to convey 2 critical pieces of metadata about each commit: 4 | 5 | 1. How risky is it? What has the original author done to mitigate risk? 6 | 2. What was the intention? When the original author changed the code, what was s/he attempting to accomplish? 7 | 8 | This information is conveyed in the first 3 characters of the commit summary line. That way a receiving developer can quickly scan the commit log in order to determine risk and intent for any incoming change set. 9 | 10 | This is particularly useful when: 11 | 12 | 1. As a reviewer, deciding whether to approve a pull request 13 | 2. As a developer, getting your pull request approved faster and more easily 14 | 4. Reading `main` — just the pull request commit summaries to understand the history of changes for a release. 15 | 16 | ## The Four Risk Levels 17 | 18 | | Risk Level | Code | Example | Meaning | 19 | | --- | --- | --- | --- | 20 | | **Known safe** | lowercase letter | `r - Extract method Applesauce` | Addresses all known and unknown risks. | 21 | | **Validated** | uppercase letter | `R - Extract method Applesauce` | Addresses all known risks. | 22 | | **Risky** | uppercase followed by 2 bangs | `R!! Extract method Applesauce` | Known risks remain unverified. | 23 | | **(Probably) Broken** | uppercase followed by 2 stars | `R** Start extracting method with no name` | No risk attestation. | 24 | 25 | * **Known safe:** Developer performed the task in a way that prevents the potential risks, even for situations that developer is not aware of. 26 | * **Validated:** Developer performed the task in some way that includes validation for all risks the developer thought of. The most common technique is developer-written automated tests. 27 | * **Risky:** Developer is aware of risks and attempted to mitigate them as much as possible, but there is no formal verification. Commonly this includes a manual change that the developer could not fully verify. 28 | * **Broken:** Either known to be broken, or developer couldn't even check to see if it works. May not compile. Used when the developer cannot see the results of the work without checking in, or as a savepoint when the developer is about to switch tasks or direction. 29 | 30 | ## Core Intentions 31 | 32 | These developer intentions exist on every project. They are always allowed in commits that use this notation. 33 | 34 | Each intention can appear at any of the 4 risk levels. Each intention's full details section includes the potential risks inherent in that kind of change, as well as common approaches to attain each risk level. 35 | 36 | | Prefix | Name | Intention | 37 | | --- | --- | --- | 38 | | F | Feature | Change or extend one aspect of program behavior without altering others. | 39 | | B | Bugfix | Repair one existing, undesirable program behavior without altering any others. | 40 | | R | Refactoring | Change implementation without changing program behavior. | 41 | | D | Documentation | Change something which communicates to team members and does not impact program behavior. | 42 | 43 | ### Feature 44 | 45 | **Known Risks** 46 | 47 | * May alter unrelated feature (spooky action at a distance). 48 | * May alter a piece of this feature that you intended to remain unchanged. 49 | * May implement the intended change in a way different than intended. 50 | 51 | | Code | Known Approaches | 52 | | --- | --- | 53 | | `f - ` | None known | 54 | | `F - ` | Meets all of:
  • Change is <= 8 LoC[5]
  • Feature was fully unit tested prior to this change.
  • Change includes new or changed unit tests to match intended behavior alteration.
| 55 | | `F!!` | Change includes unit tests for new behavior. | 56 | | `F**` | No automatic tests, or unfinished implementation. | 57 | 58 | ### Bugfix 59 | 60 | A bugfix is a lot like a feature. However, the intention is to change an undesired — and usually unintentional — behavior of the current system. The risk profile is similar but the intention is different, so there are often more operational risks. 61 | 62 | **Known Risks** 63 | 64 | * Intended change may have unintended consequences in the market. For example, customers may be depending on the bug. 65 | * May alter unrelated feature (spooky action at a distance). 66 | * May alter a piece of this feature that you intended to remain unchanged. 67 | * May implement the intended change in a way different than intended. 68 | 69 | | Code | Known Approaches | 70 | | --- | --- | 71 | | `b - ` | None known | 72 | | `B - ` | Meets all of:
  • Reviewed current and new behavior with customer representative.
  • Change is <= 8 LoC[5]
  • Bug's original (buggy) behavior was captured in a unit test prior to this change.
  • Change includes 1 changed unit test, matching intended behavior alteration.
| 73 | | `B!!` | Change includes unit tests for new behavior. | 74 | | `B**` | No automatic tests, or unfinished implementation. | 75 | 76 | ### Refactoring or Remodeling 77 | 78 | A Refactoring or Remodeling intends to alter the program in some way without changing any behavior. The risk levels indicate the probability of the commit living up to that intention, based on how the code change was executed. 79 | 80 | **Known Risks** 81 | 82 | * May cause a bug. 83 | * May fix a bug. 84 | * May change a behavior in a way that doesn't impact a user. 85 | * May force a test update. 86 | 87 | | Code | Known Approaches | 88 | | --- | --- | 89 | | `r - ` | One of:
  • Provable refactoring[2]
  • Test-supported Procedural Refactoring[3] entirely within test code
| 90 | | `R - ` | Test-supported Procedural Refactoring[3] | 91 | | `R!!` | Identified single, named refactoring, but executed by editing code or without whole-project test coverage. | 92 | | `R**` | Remodeled by editing code, even in small chunks. | 93 | 94 | ### Documentation 95 | 96 | Changes that don't impact the code, but do change documentation around the code. Note that this does not include end-user documentation[1]. 97 | 98 | **Known Risks** 99 | 100 | * May mislead future developers. 101 | * May mislead other stakeholders. 102 | * May alter team processes in ways that have unintended consequences. 103 | 104 | | Code | Known Approaches | 105 | | --- | --- | 106 | | `d - ` | Developer-visible documentation, not in a source file, or verified to generate byte-identical compilation. | 107 | | `D - ` | Dev-impacting only, but changes compilation or process. E.g., changing text on a dev-only screen, or changes code-review checklist. | 108 | | `D!!` | Alters an important process. | 109 | | `D**` | Trying out a process change that is intended to gain info, not to work. | 110 | 111 | ## Extension Intentions 112 | 113 | The basic intention annotations are comprehensive to describe any kind of change, but it may be useful to extend the notation to your project to provide additional detail that is useful in your context. Read more about [Extension Intensions](Extension%20Intentions.md). 114 | 115 | # Provable Refactorings 116 | [2]:#provable-refactorings 117 | 118 | If you can get a series of commits that is all lowercase commits, you can deploy without the need for Regression Testing, or lengthy conversations about accepting the pull request to trunk. 119 | 120 | A provable refactoring requires a burden of proof. The main methods of proof are 121 | * automated refactoring via tool, with knowledge of tool bugs. 122 | * Scripted manual refactoring, using the compiler to verify each step. [Recipes Here](https://github.com/InnovatingTeams/provable-refactorings) 123 | 124 | With discipline these can prove bug-for-bug compatibility. They demonstrate safety for unknown bugs, even guaranteeing that you do not accidentally fix a bug you don't know exists (but your customers may be depending on). 125 | 126 | All of these recipes use static analysis to demonstrate safety. As such, they work equally well on code that lacks tests. They can be a good way to make code testable. Their downside is that they are language-specific. 127 | 128 | # Test-supported Procedural Refactorings 129 | [3]:#test-supported-procedural-refactorings 130 | 131 | These are refactorings with a lower standard of proof: 132 | 1. Commit contains only a single refactoring. 133 | 2. Refactoring is named and published (e.g., in [Fowler's refactoring catalog](https://refactoring.com/catalog/)). 134 | 3. Either: 135 | 1. Your entire product is very highly tested, or 136 | 2. you are working on new code that is not yet called. 137 | 4. You followed the published steps, including running full-suite test runs when indicated. 138 | 139 | Note that this can not prove bug-for-bug compatibility. It can only demonstrate that you didn't cause any problems that have been thought of before; it does not demonstrate safety for novel bugs. 140 | 141 | Requirement 3 is there because many refactorings can have non-local effects. It is not sufficient to have great tests on the code you are changing. You also need great tests on the code that you are not intending to change, to demonstrate that you didn't. Therefore, until your entire codebase is very highly tested, you will only be able to use the `R` commit designation on new code that is uncalled by your product. 142 | 143 | # End-User Documentation 144 | [1]:#end-user-documentation 145 | 146 | End user documentation is a feature, bugfix, or refactoring, depending on its nature. Use those codes (including levels of risk) accordingly. 147 | 148 | # Small Features and Bug Fixes 149 | [4]:#small-features-and-bug-fixes 150 | 151 | Features and bug fixes intentionally change behavior. This makes them much riskier than refactorings. It is not possible to prove that they have only the intended effect. However, small changes are much lower risk for three reasons: 152 | 153 | 1. It's only possible when the code is well-organized already. 154 | 2. It's easy to see the possible side effects of small chunks of code. 155 | 3. It's easy to code review, so you are likely to get good reviews. 156 | 157 | Therefore, we treat any feature or bug fix as high risk if it changes more than 8 lines of code in one commit. This includes test changes. 158 | 159 | One good approach to enable small features is to refactor until the feature change is easy, then add it. Then add the feature one piece at a time, with a test for each. 160 | 161 | # Living Documentation 162 | 163 | We invite you to submit pull requests to help evolve this notation and methodology. 164 | 165 |
LoC: Lines of Code 166 | 167 | [5]:#lines-of-code 168 | --------------------------------------------------------------------------------