5 ms·
Slightly off topic. What is this deal about commit small and often? I usually work on problems that requires a lot of thought, a lot of back and forth between
by siscia 6y ago
Slightly off topic.
What is this deal about commit small and often?
I usually work on problems that requires a lot of thought, a lot of back and forth between solutions, a lot of a reach this state where stuff kinda work but it is not what I need yet and I am not sure it is gonna be in the final version.
Eventually I reach the final version and I commit all together, but the commit is rather big.
Do you guys come back and fix everything after? Like re-code the solution from scratch committing at the right moment.
Do you just add pieces related from the final version in multiple small commits?
And how do you make sure that each commit is correct? Do you re-run the test suite after each commit? While developing?
I must say that in smaller and simpler codebase than the one I usually work with it might be possible. But if you work in complex stuff that have a test suite that take hours, the approach of commit small and fast seems wrong.
- mr_isomies 6y agoI think that the overall sentiment is "break code in intelligible chunks"? I also used to work on big commits but at some point switched more to branching and merging a lot, which to be honest feels a lot more natural in git. My branches are very topical, don't need to be stable, only run a subset of tests/build tasks etc. Then I squash them back into the main branch. Now for me, big commits are sort of like file blobs, where vcs are the wrong tools for that. But it's funny that when I first started using vcs (and any tooling, really) I was like, trying to get them to bend to my workflow instead of bending my workflow to the tools. Like, the tools have inherent qualities that makes certain task easier, and going against this _natural_ grain just made my life harder.
- yomly 6y agoThere are a lot of different approaches here. Some of it stylistic. If you've ever played an Elderscrolls game: do you repeatedly mash quicksave save every milestone save every x minutes of play I'm sure amongst the people who code and play RPGs this will surface the different attitudes to this. From a workflow perspective there are commits per feature/story, or commits per working unit of code (maybe TDD influenced), commit per decision, commit per unit time (commit at lunch or end of day) Interestingly, with git you can kind of have your cake and eat it and achieve a mixture of all of those through rebasing. From a professional point of view your git history is a valuable artifact of your development so having a clear and well documented history is a good working practice as some teams like git being a source of truth for a project. Small and tasteful commits can be valuable in taking a newcomer through a codebase as some people like to read a codebase from its git history as it can be quite a useful contextual annotation of the evolution of the codebase - HEAD is only a projection of the final state of that and loses a lot of the journey. So there are git commits for the reader and there are git commits for the writer. The workflows may not always be the same but they also don't necessarily need to extremely tightly coupled. Of course if you can find a happy medium of the two then you're winning. EDIT In the case of a hiring code test, the projects are (hopefully) small so sometimes the commits may feel a little contrived, but so is the whole exercise of a coding test. That said if you personally value clean git history as something in your own ideals of code quality, it is worth communicating that through smaller commits in your code test for your candidate employer. Much like unit testing or documentation are signals of quality outside of the code itself. These are part of the day job as much as slinging code or churning out features are (depending on the role)
- l0b0 6y agoTDD makes small and frequent commits the natural way to work: figure out the smallest non-trivial step in the right direction, write a single test, verify that it (not the entire test suite) fails for the right reason, implement the simplest code which makes the test pass, simplify the implementation while making sure the test passes, commit. This way each code change typically amounts to a single new path through the code which is known to be tested. Asking people to use TDD for a coding test is probably a bit much since it takes a long time to learn the ins and outs, but small commits give a little bit of the advantage and can tell you a lot: Does the candidate know how to break the problem into atomic changes? Do they commit only reachable code? Do they create simple, fast, and orthogonal tests?
- bgdam 6y ago> Asking people to use TDD for a coding test is probably a bit much since it takes a long time to learn the ins and outs, This hits close to home for me, I was very recently rejected at an interview (a 1 hour pair programming session), because my approach to fixing the algorithm was 'not TDD enough'. I think that it's really dumb to expect people to go full on TDD in an interview session, where the purpose would ostensibly be too demonstrate analytical and programming ability. Couple that with the fact that they didn't even tell me that there was going to be an emphasis on TDD, it basically amounted to wasting about 3 days of my time for the entire interview process. It is unfair that companies can unilaterally make such demands on your time, while themselves not spending more than a few hours.
- atomicity 6y agoThe problem is that OP is dealing with work where design is the hard problem. They need to do prototyping without considering all of the faults of their programming language, all of the concurrency bugs they could make, and all of the logical errors they could make. TDD falls apart here because TDD helps you write code that does what you think it does. When you don't even know whether it's possible to implement what you want to implement, TDD doesn't help. I think the TDD model of implementation is a lot better than most sloppy dev workflows I've seen, but I agree with OP that small commits don't work out in this case. When you aren't sure whether something is possible, you need to stay less detail-oriented. To do so, you switch from TDD mode to prototyping mode. Personally, I have so little faith in my prototype code that I always rewrite it.
- mxcrossb 6y agoAnother issue for me: if I’m commiting often, the interviewer gets a sense of how long it took me to do each task. This turns it into a timed test I’m supposed to do with all the distractions of home in my free time... Of course, one can always rewrite the git history to lie about your process...
- mjfisher 6y agoI commit frequently and rebase to make it nice afterwards - which seems to be a common pattern. For commits that I know at the time need revisiting (partially complete feature/tests don't work/solution works but needs heavy refactoring) I'll prefix the commit message with "WIP" so I have a hint when I come back to it. When the problem is finished, I go back and neaten up the history into a smaller number of logical commits that would make as much sense as possible to someone reading the history. Tests (in my opinion) need to run continuously during development. I usually have tests run on file change - either in a terminal window or IDE. They also run on each commit when each branch is pushed. If you have no option other than to run a test suite that takes hours, that needs fixing. You don't need to run all your tests during development, but pragmatically you need to run enough of them to give you some confidence that you haven't broken things. Some options you might have: * Separate fast and slow tests (e.g. unit tests and integration tests). Run the fast tests frequently as you develop, and use the slow tests to sanity check what you're doing from time to time * If there are no fast tests (e.g. everything is almost an end to end or full integration test), write some faster tests just for the feature you're working on and run those. It doesn't need to be perfect; just lay down a start that you and your team can improve on * If all your tests are fast, but there are just a lot of them and they're so abstracted from the layer of code you're working at you can't tell which are relevant, you can add tracing statements to define a subset of tests that hit the codepaths you're changing. Run the small subset regularly. * Spilt up your codebase - this doesn't have to be into trendy microservices if your problem domain doesn't support the use case. But you'll almost certainly be able to pull out modules or libraries into separate repos that have their own tests. Version them semantically. As a discipline, we work across a huge range of problems and I'm wary of making assumptions about yours; but slow tests have a massive impact on how quickly you can deliver in my experience.
- ensiferum 6y agoIMHO that's exactly the skill differentiator between experienced and skilled developers vs. the novices. The skilled developer is able to take a big/difficult/complex problem and break it down to small steps that translate to simple sub-problems and their solutions and map ideally nearly 1 to 1 in commits. How far you need to continue this recursive process of breaking things down depends on how big the problem is but basically you'd do it until your commits and steps are single cohesive steps. Certainly this might mean that you end up committing functionality that is not used at that point in time but will only be used by later commits. Some people might disagree with this approach and prefer to squash this but I find that this approach keeps things simpler. For example if I'm working on adding a new feature X in my application I need to think about how to support that feature given the current components/APIs/classes/whatnot that I have in my system. Let's say that in order to implement X I need to add a new API functionality in components Z and W and then implement the new feature in a new component X. High level this is already 3 steps. Maybe doing the actual changes for Z and W are still too large and further need to be broken down. Then there'd be more than 3 steps and subsequently also more commits. Now often what I end up doing when I don't really quite know yet how to best go about implementing something I do all the changes at once and once it all works and I've found my way I spend a moment of reflecting what I actually did (and if there are indeed alternative ways). Once I decide to finalize the work I then go back to my changes and do the commits in steps using git chunks. It's all about looking a head, working out mentally the roadmap in simple steps from current state to the next state and then taking those steps. I find that in my career learning this mental model and the ability to break things down has taken the longest.
- finnthehuman 6y ago>I usually work on problems that requires a lot of thought, a lot of back and forth between solutions, a lot of a reach this state where stuff kinda work but it is not what I need yet and I am not sure it is gonna be in the final version. How do you manage this without source control? The back and forth? Trying an experiment and then throw it away? Sounds like the perfect use case for private branches. >I must say that in smaller and simpler codebase than the one I usually work with it might be possible. On the other hand, if I'm working a large and complicated changeset I don't know how I'd keep the WIP organized if I couldn't use source control privately in the process of iterating on that changeset. Doing the work in a private branch means I can frequently rebase on master so merging at the end is a cakewalk, I can also switch back to master to start a new branch to work on something else. >reach the final version and I commit all together >Do you guys come back and fix everything after? I make incremental commits on a private branch as I'm working. As I go it might not look like much more than an "undo" history, maybe a few abandoned branches. When I want to merge I'll do an interactive rebase. Reorder the commits to group similar work, in their implementation dependency order, then squash them into a set of logical commits and write some decent commit messages. It doesn't take too long, I do it as part of reviewing my code changes before sending them to the whole team. For example, my backburner task right now has 78 commits made over ~2 weeks, and will be squashed to about ~4 commits when I'm ready to merge. My style is loosely based on the kernel patch series guidelines, https://www.kernel.org/doc/html/v4.17/process/submitting-patches.html#separate-your-changes https://www.kernel.org/doc/html/v4.17/process/submitting-pat...