My ideal process ([1]) is...tedious. I <i>never</i> actually do it to that level, but my level of released bugs is low enough that what I <i>actually</i> do is good enough.<p>But what it <i>does</i> give me is a template to follow and adjust as the circumstances require.<p>So I always start with requirements. Requirements are my goals, and they are always in my mind throughout the rest of the process.<p>Then I design. I design the UI, UX, implementation, and tests, and I <i>iterate</i> between them until I get to a fixed point where everything is in a great local maximum.<p>If I encounter a local maximum that is bad or merely good, I throw out the design and start again from scratch and repeat as necessary. This is less necessary as the project ages because my intuition for the project increases.<p>After I have a design in hand, I do <i>not</i> start coding the feature. Instead, I figure out what technical debt the codebase now has.<p>That may not make sense, so let me explain.<p>Designing first means that I have a good idea of what needs to change in the codebase before the feature can be implemented easily. Before I wanted to implement the feature, the codebase had zero, or near zero, technical debt. But the <i>intention</i> to add the feature means that the codebase now has technical debt <i>relative to where it should be for the feature</i>.<p>So before I implement the feature, I tackle this new technical debt first, and when I am done, I use my full test suite, which has extremely high line, branch, and path coverage, to ensure that the refactor did not introduce new bugs.<p>Once I am satisfied with that, I implement the feature and add its tests. This includes adding as many asserts as I can to test the assumptions the code is making, both for documentation purposes and for quickly finding bugs with the test suite.<p>Then I get the tests passing.<p>Then I fuzz with AFL++, with the asserts turned on so that it will be as crash-happy as possible. This means that bugs are more easily found by AFL++, and it's easier for me to notice them too.<p>I fix the crashes found by AFL++ (most of them failing asserts), add the formerly crashing test cases to my test suite, and repeat.<p>Once AFL++ runs to "completion" (not finding any more test cases after having gone through basically all of the ones it found) without crashing, I have great confidence that the feature is robust.<p>But then I still run static analysis on it.<p>Then I add the feature to my NEWS.md file, increment the version appropriately, and put out a release.<p>However, woven throughout all of the steps is documentation. I document the requirements. I document the design. I document the new code, including a full Doxygen comment for every new function and type, as well as updated doc comments for any existing code that changed. I also comment the actual code heavily, using [2] as a model. I'll write down things that future contributors, including myself, may need to know about that feature, especially its implementation.<p>Missing documentation is technical debt, and I have near zero technical debt.<p>Of course, you may take issue with my assertion that I have zero or near zero technical debt, but this is basically true.<p>The reason is that I'm a perfectionist with my code. When I go to make changes, I would struggle if I did not fix any imperfections I see. For an example, see [3]. So I do actually remove <i>everything</i> I see before getting to coding.<p>This can be annoying and discouraging at times; I have phases where I stop programming for a few days or a week because I'm not looking forward to a refactor that I need to do, but I can't continue without it because I'm a perfectionist. But it does mean that I have very little technical debt.<p>It turns out that a lack of technical debt is a superpower; it makes features easy to add and keeps velocity high. So once I'm done struggling through removing the technical debt, it's great!<p>This process is special, and it really can only work for someone that is as much of a perfectionist as me, and if someone does, they will have to be used to not implementing as many features because while velocity is high, I still spend copious amounts of time on refactoring and on tests, although that does increase velocity too by making it easy to do large refactors without fear.<p>This process also means that I cannot work with other people; I actually can't keep a job in the industry. So don't adopt this process if you <i>do</i> work in industry.<p>[1]: <a href="https://gavinhoward.com/uploads/process.md" rel="nofollow">https://gavinhoward.com/uploads/process.md</a><p>[2]: <a href="http://antirez.com/news/124" rel="nofollow">http://antirez.com/news/124</a><p>[3]: <a href="https://git.yzena.com/gavin/bc/commit/eb0cd870b91f3ad2a834f224cc077e6adcd4ce89" rel="nofollow">https://git.yzena.com/gavin/bc/commit/eb0cd870b91f3ad2a834f2...</a>