Ehh... nice in principle (and I do small deploys all the time for work), but too many artificially-small changes can easily cause you to "miss the forest for the trees". Each change is small and LGTM-able, but they can add up to a misbehaving system unless you have full context (which, because they're small, <i>does not exist</i> in the diffs).<p>If it's conceptually a single unit, keep it a single unit. Pushing dead code in small pieces that waits for a small master switch doesn't give you additional safety (though it can give you easier merges).<p>><i>Reviews for large diffs are closed with a single “lgtm,” or miss big-picture problems for the weeds.</i><p>That means you have bad reviews. If it can't be figured out, how was it written? Take the time and do it right. Yes, it's a large commitment - is it larger than the value being created? If no, why does it exist?
Um, no. Keeping diff sizes smaller is nice, but asking for "a few dozen lines" most of the time is too doctrinaire. In many codebases, especially those that are older and larger, even a fairly straightforward enhancement can require a few dozen lines of new code plus even more modifying callers or hooking things together in other ways. Oops, already over the limit. Breaking up patches can even make them less coherent as context for each one is lost, and can slow things down if all the pieces have to be pushed separately through a slow CI pipeline.<p>Keeping patch sizes to a minimum is good, but it's a minimum of <i>what's feasible</i> based on other concerns. If "few dozen lines" works for you that's great, but don't overgeneralize from that.
This strikes a chord with me, but I'm coming at it from a different angle.<p>Does anyone else encounter very large diffs as standard operating procedure in golang codebases? Here I'm considering "very large" to mean 500+ lines changed - however github computes lines changed.<p>I mean, I'm looking at this from the perspective of someone who contributes primarily to Ruby codebases. It's understandable that there would be a difference when comparing ruby/go, but the magnitude of the difference is what I'm getting at.<p>The difference I'm observing in the average size of a PR in a plain old Rails codebase compared to the average size of a PR in a golang codebase is dramatic - roughly an order of magnitude. In some cases it's even more extreme.<p>Is that anyone else's observation, or am I just doing it wrong?
Paraphrasing "as simple as possible but no simpler than that": ship as small diffs as you can but no smaller than that which makes sense.<p>Individual commits don't necessarily make sense in the whole. Submit diffs which make up a logical, conceptual block of new changes. Don't mix formatting changes, whitespace cleanups, or rearranging changes into diffs with real meat. Ship new prerequisite tools and new changes to utility functions or libraries first, then the meat: i.e. split general codebase upgrades and distinct features into different shipments.<p>Make it so that "git log" will produce a list of sensible steps if someone else reads the listing. Remember, 90% of programming is writing good code and the other 90% of programming is communication to others.
Generally, I like the middle ground of reasonably small branch sizes and small, well-organized, well-written commits.<p>Walking through a half dozen or so commits in a PR is still manageable.<p>Too many small things deployed over time can be a pain to roll back too.<p>On the flip side, huge change-the-world deploys are bad too.<p>It's a balancing act of managing the initial feature size, getting it out, layering on more in subsequent releases.<p>Where tiny deploys work really well is when deploying refactorings, little housekeeping chores like upgrading libs. If, while working on a feature or bug, I need to add a missing test, refactor, or upgrade a lib, I extract those commits out and deploy them ahead of time when possible. That way the resulting feature branch is very focused on the feature at hand.
This is nonsense. The number of lines of change of code has absolutely nothing to do with the amount of risk.<p>A single line change can easily break an entire system. Applying this size fallacy, however is just as dangerous. Certain classes of changes should be grouped together so they can be reviewed with the context required.<p>I've had the unfortunate task of working in environments where I've been forced to artificially break up my PR's to suit some arbitrary rule, no doubt because an article like this got read at some point.<p>What ends up happening is instead of having everything related to a specific changeset or feature in a single PR/commit, you now have it strewn across multiple PR's/commits, non-nonsensically, and with artificial borders most of the time. This makes review more difficult and creates additional work to support the partial implementation working at each slice.<p>Process should not replace thinking. If a feature warrants it, who cares if the PR is 2,000 lines or 12. Not every task is small and not every task is large. As long as the scope is well defined, many times it does make sense to do tasks in whole rather than as a sum of parts.
> <i>You don’t need elaborate Git release rituals. Ceremony such as tagging releases gets to feel like a waste of time once you are releasing many times per day.</i><p>What happens when you ship bugged code and need to roll back?
We're pushing fairly large changes once a week from multiple team members. What has really helped is having comprehensive unit, integration and end-to-end tests. We run first 2 on every check-in into main branch. Then run all 3 after moving from QA to Staging. And finally do smoke tests in Staging. The only problem with this approach is of course spending ungodly amount of time writing tests and infrastructure/tooling to support automated tests especially end-to-end. But this hasn't failed once yet.
>> Building a web application is a young and poorly-understood activity.<p>Sorry, no. People have been shipping, and understanding how to ship web applications for... what, 10, 15, 20 years now?
Continuous Deployment is scary at first but once you have good test coverage it is safer than big releases.<p>If a developer is creating one bug per day. Is it better to release it every day or is it better to wait 1 month and release 30 bugs all at once?<p>Continuous improvements are also highly motivational. The difference is between saying "We can fix that at the next release" and losing the motivation to fix it later and saying "Just shipped the fix" and feeling great.
Release early, release often?<p><a href="https://en.wikipedia.org/wiki/Release_early,_release_often" rel="nofollow">https://en.wikipedia.org/wiki/Release_early,_release_often</a><p>What's old is new again.
Birth defects are forever. If the design has a problem, "small diffs" won't fix it. That's the trouble with the "continuous hacking and integration" approach.
This is something I've had a lot of problems with. I understand the benefit of small diffs, but I can't seem to find a way to really apply this for any actually meaningful changes. In my experience I would spend some time coming up with a system of multiple abstractions that are interdependent and then getting single logical commit for proof of concept would require hundreds of lines. Splitting the abstractions into separate commits would be confusing so I don't think that's good. Maybe I should stub functions a lot more aggressively and truly aim for minimal. The other problem is when you are replacing an abstraction in an already large code base, the raw number of changes required could easily be in the hundreds or even thousands of lines.
> PR’s of GitHub branches are great. But git diff | gist -optdiff also works reasonably if we are talking about a dozen lines of code.<p>So, he just sends a gist link to his teammates? why not create a small pull request and then asking them to look over it?
A better goal might be to "design interfaces and implementations in such a way as to tend to reduce the sizes of diffs for likely future changes".