Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

When making changes to a block of code or block of text, I frequently just comment out the code and rewrite it anew. I might copy-paste existing code (just to avoid stupid transcription errors). If its too large to see both what I'm writing, and the old code, at the same time, I just use two windows on the same file.

This is relevant to writing fiction or non-fiction as well.

For example, I didn't like this, so I commented out:

>though his companions jogged just behind him, he would have barely seen them at all had he look. They ran, with their heads down, attentive only to their feet slapping the muddy earth, tracking the path they followed, their breath ragged.

and wrote this, using the commented-out text as a reference:

The fog was now so dense that he could see nothing ahead of him. He ran with his head down, breath ragged, attentive only to his feet slapping the muddy earth, tracking their path. His companions followed close behind.



I do the same - both commenting out and viewing the file in parallel at different spots - vim vertical splits are great for that. In fact, one of my colleagues remarked that he never thought to view the same file alongside itself when he saw me do that when we were pairing.


As an aside, I think I wouldn't mind if a programming language would include two commenting syntaxes, one for ordinary comments, and another for commenting out. These are two very different use-cases, and distinguishing them syntactically might facilitate certain kinds of work-flows.


A common code style rule for C# is // for comments and //// for commented out code (/// is reserved for documentation generation). StyleCop analyzers can enforce this during code analysis passes.

While this isn’t a language construct (a comment is a comment after all), Visual Studio can key off these stylistic differences to show code comments vs commented code differently. I find it to be a neat trick to improve code readability.


Cool.

I've never touched C#. But that seems like an approach applicable pretty generally. I like it!


I thought //// was psuedo reserved for documentation. and then // was for general comments. I usually use block comments for commenting out code or I just use VS hotkeys which I think are //


It’s actually /// (3 slashes) that reserved for pseudo-documentation use.

There’s a StyleCop rule to enforce this as well:

https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/ma...


I've never seen this in C# code! How common is this? Do you have any references? Sounds like a useful convention (it's nigh impossible to google). VS only distinguishes between `///` (docblock) and all other (double, quadruple,quintuple, /*/). But maybe there's an extension.


Here’s more about commenting style:

https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/ma...

StyleCop is used for analyzing code style in C# code.

Specifically:

> If the comment is being used to comment out a line of code, begin the comment with four forward slashes rather than two.

StyleCop relies on this to tell the difference between commented code and code comments. If you use ReSharper, it can do some nifty transformation to strike these out in the IDE which is kinda cool too.

I’m a big fan of StyleCop to enforce consistent code styles. (Even if it’s not always what I may aesthetically prefer.)


Perl and Ruby have this. In Perl it's kind of an abuse of the perldoc system, like this:

    print "foo"
    =pod
    print "won't run"
    =cut
Ruby basically copied it, although I don't think these have documentation uses:

    puts "foo"
    =begin
    puts "won't run"
    =end
When I get to choose, I prefer sticking to // in C code so that I can use /* ... */ for hiding large blocks of code . . . although #if false ... #endif work too.


In C, you can wrap the 'commented' code with #if 0 ... #endif


Or indeed if rewriting a block of code:

  #if 1
    ....new code...
  #else
    ....old code...
  #endif
Esp. for tricky stuff, it's then possible to just flip the 1/0 to easily test/compare/profile the new/old code.

Some IDE's will even work out which block of code to colour and which to dim.


Why have I never thought of that?


I do the same, even in languages without a preprocessor.

You can just use a life if-else, most compilers will optimize the test-on-a-constant away. Even when the code is kept in, I doubt it will have a major performance impact during testing in most cases.


I would do a bit more by

   #if !defined(this_works_but_it_suck_memory_too_hard)
   ....
   #else
   ....
   #endif
That should give me a clue why I "disabled" it when I come back to it 5 minutes later.


I usually just do this with a comment behind the #if false. Yes, nobody is probably ever going to define that particular identifier, but comments are also less restrictive (you can write normal text).


In languages with multiline comments like /* and single-line comments like //, you can do:

    //*
    old_code();
    /*/
    new_code();
    //*/ 
And remove the first slash from the first line to switch between blocks.


Yes! Just today I was wishing that I could have syntax highlighting on commented code that I was refactoring. Just dim it a bit instead of turning it all grey.


It's not a formal distinction, but in C++ code where all the ordinary comments use //, it can be handy to use /* ... */ to comment out a block.

(Of course, if there's a stray /* ... */ comment already in the area to be commented out, this will fail. But an editor with appropriate syntax colouring can make that immediately apparent.)


I like to put a space following the // if it's written text comments, but no space if it is commented-out code.

I think the space looks nicer for text comments, but when I select a block of code and hit Ctrl+/ to comment it out, my IDE does not add a space. So it works out very conveniently for me.


I'll sometimes use:

    version (all)
    {
        ... new version ...
    }
    else
    {
        ... old version ...
    }
and change `all` to `none` to try the other branch.


Scheme has #; which comments out a single expression. This covers most but not all use-cases. (It doesn’t help for commenting-out subsequences, like if you wanted to remove the top half of a begin block.)


Sometimes I do stuff like

   // FIXME try new way mm/dd/yy
   if(1)
   {
     ... new way ...
   }
   else
   {
      ... old way ...
   }


Hrm, but it's obvious if somethingis commented out code vs an actual comment. I'm probably missing something here.


I use this workflow a lot and while I’m still figuring out how I want to implement something. I’ll often just do the whole thing in one file, commenting, and rewriting and restructuring code as I go with multiple open windows to different parts of the file. I only break it up when I’m happy with the abstractions, and I know where the natural fault lines run between functions, classes and concepts.

Doing this too early feels wrong; like I’m prematurely committing to a division of responsibility that’s going to subtly drive me to a bad design.


> one of my colleagues remarked that he never thought to view the same file alongside itself

I do this all the time in Emacs, usually to see two parts of the file that normally are too far apart to be visible at the same time. Collapsible sections can do similar, but to me it's quicker, more natural and more flexible to just split the window.


Another good trick in emacs (if using git and magit) is `magit-find-file HEAD <file>`, then you can edit in one window and see the old version in the other


It actually never occurred to me to do this. Perhaps because I tend to use command-line git, even when using an IDE. I haven't learned magit yet, and I know people swear by it. But this does look like a pretty good way to go about it, at least if your commits have a fine enough granularity.


I think this workflow comes particularly naturally in Emacs, since anytime you split the window (e.g. C-x 3) the current buffer sn already duplicated in the new window. You have to change the buffer in the new window if that is what you want. You can do this in your IDEs too (like Pycharm) but the option to do so doesn't exactly leap off the screen at you.


Vim does a similar thing to Emacs here: the `:sp` and `:vs` commands take an optional argument that, if given, loads a file in the new window. Otherwise the new window just contains the same buffer.


This is exactly what I do. Vim split of the same file, one side for editing and the other for context. Works great!


Commenting is the answer. It stays until I'm certain I no longer need it.


This is the one thing above all else which has kept me off Go. Tentatively comment out a line or two and the whole compilation process may come crashing down because now you have a declared but unused variable, and mere warnings apparently aren't Gestapo enough in this particular universe. You then find and comment out the offending declaration, only for the compilation to die in flames again because now you reference a never declared variable. It gets tiresome after a while.


Are unused variables really compiler errors in Go? That does seem very harsh, and very counter productive while developing. -Werror is all well and good, but while I’m in the middle of writing the code, it’s a bit much.


The theory is that given enough code, any antipattern that compiles will make its way into real use, and therefore the only way to make people stop using an antipattern is to refuse to compile it. Go trades inconvenience in the short term for removing an entire class of bugs and raising the readability floor of bad code.


That's an insane approach, eslint solves this just fine and is fully configurable for almost any style preference.


All Go code everywhere never has unused variables, never has unused imports, and is formatted similarly. But, when you're debugging a function, you can't leave unused variables or imports lying around.

It's a tradeoff. I don't think either side of the tradeoff is insane.


You can do underscore import and local variable to workaround this limitation and I have seen that in the code.


Sounds like a good argument for a --relax-im-just-trying-something flag for the go compiler, and taint the resulting code with it so if anyone else tries to use the code without the same flag, then the compiler/linker will complain.


They were, last time I looked. Which was admittedly a while ago.


Even worse if you include something that isn't used, that's also a fatal error.


Golang is impossible to use without an IDE like VSCode. Tried it with Sublime Text without a language server and it was a nightmare like you described. Less problematic with VSCode cause it'll add/remove imports automatically on save and have big red underlining for anything that will cause it to not compile.


My approach is similar to this, except for whole functions/classes I tend to just create a new one with a version number. e.g. DataContext => DataContext2.

When I'm satisfied that DataContext2 does everything that DataContext does, I delete old one and rename DataContext2 => DataContext.

The risk here, is that sometimes it's not possible to migrate everything to the new version and you end up with multiple old versions lying around, i.e. technical debt.


I do the same, but the opposite way, hehe - I rename e.g. "DataContext" to "DataContextOLD1", then I write the new "DataContext" (from scratch or by copying the original one and then modifying it), this way I'm sure that all calls to DataContext always use the new version.


I do this too! A big benefit is gradual migration - for example, if I'm injecting DataContext into a bunch of different places, I can implement part of the functionality of DataContext. Once I have just enough functionality implemented to support one of the places it's injected, I update that place to take DataContext2. Then I can test, and move on to the next place.

If you're using a language with strong typing and good refactoring support (right now that's C#/Visual Studio for me), the eventual rename from DataContext2 to DataContext is a non-event.


I do the same. Many people comment about commiting frequently but that doesn't work for me: delete code + commit => I don't see the code anymore and my brain magically forgets about it. I need the quick feedback loop: commented code + uncommented code (all in one screen) => new code is going to look like a mix of both. If I have to use git to see commented code then the feedback loop is broken.


Commiting frequently also has a substantial cost of needing to think of a commit message.

If you don't think of a commit message, you'll never be able to find this version again. If you think up a message every 2 minutes, you'll quickly find you spend more time thinking of commit messages than writing code.

I wish there was some kind of auto generated commit message. Things like:

"Added function xyz()" or "Adjusted constant FOO to 27" or "Made lots of changes in file a.c,, b.c and c.c".

These could be auto generated, and then commits could happen in the background every time the code is compiled.

It would be nice for git to have some kind of "commit of commits" which allows a hierarchical representation of commits. Ie. the "Add new printscreen feature" could have as subcommits "Create print renderer" and "Hook up print UI".


> I wish there was some kind of auto generated commit message. Things like:

> "Added function xyz()" or "Adjusted constant FOO to 27" or "Made lots of changes in file a.c,, b.c and c.c".

I would argue that these are not good commit messages as they do not add information not already provided by the diff itself. Commit messages should communicate the intended effect of a change that has been made, rather than being a lossy compression of a sequence of keystrokes.


In which case I want a lossy summary of the diff... And it would be great if a tool could generate those for me...


Try `git log -p <path(s)>`, which will show the sequence of diffs for only the specified set of files.


> It would be nice for git to have some kind of "commit of commits" which allows a hierarchical representation of commits. Ie. the "Add new printscreen feature" could have as subcommits "Create print renderer" and "Hook up print UI".

These are usually called feature branches.

> "Added function xyz()" or "Adjusted constant FOO to 27" or "Made lots of changes in file a.c,, b.c and c.c".

These are very poor commit messages that don't add anything of value; any diff viewer will tell you the same immediately, so you might as well leave it blank.

> Commiting frequently also has a substantial cost of needing to think of a commit message.

In larger, private feature branches I'll use loads of "asdf" commits that I will later squash together. These are my "ok, so far so good" points to make figuring out where I broke something easier.


People are getting way to hung up about their commit history in most cases. If you're just experimenting, even "asdf" can be a totally fine commit message. And it shouldn't be hard to come up with something at least a little more descriptive in <20 seconds. Remember that in some situations, what you get from git is basically a glorified backup system. And that's valuable!

You can edit the history later when it's required by somebody else working on the code.

Or you can just not care. 99% of the value of your git repo should be in the most recent commit.


Looking at other people's code I vastly prefer a feature branch with a summary name of the feature "new-checkout-flow" or whatever and then the commits as they where without squashing/rebasing. Mine tend to have quite a few commits cycling through:

  - Stub in [classes/models/etc] for checkout flow
  - Add basic test coverage
  - Fix my API for easier testing
  - Decouple foo from bar in new flow
  - New checkout flow mostly tested
  - New flow UI cleanup and add comments
  - Fix nasty [N+1/O(n^2)/etc] performance bug in new flow
  - New flow feedback from acceptance testing
  - New flow ready to merge
  - [And often enough/honestly] "WIP to share with..." or just 
 "WIP" for work in progress, "Fixing bug in" or whatever reality there was.
Going back at `git blame` etc 5 years later i can see from the branch names linked to the commit the why it was added and from the commit messages I can see something of at what point in the mental processing of designing/implementing that exact line made it it.


On the other side of the coin I hate looking at git blame to find a bunch of now irrelevant stuff, like fixes to code that were only ever in your branch. I don’t generally care about the discoveries you made along the way (at least not in commit form) unless I’m doing the review for it to go in the main branch, and even then it’s more of a curiosity than anything particularly relevant to software quality.


I wanted "squash merge" to work for me to handle this. Full history in the feature branch for detailed git blaming and a single 1000-line merge commit in main with "New Checkout Flow" but i never fully groked getting it to work when you are merging upstream branches into you feature... You end up taking credit/blame for the upstream commits on main and I feel like you could overwrite the real history of that.


I agree. I also think commit messages get more detailed the further along the process is, and the less code you change.

“Added unit tests and stub out api” (50 files) vs “fix bug when files are added too quickly” (1 file, 3 lines)


If you don't already know the commit message before you start writing the code, maybe you should wait to write the code.


What's to stop you doing all these commits locally with uninformative messages, then squashing them when you push/PR with a better message?


Putting low-effort comments into temporary commits is OK. The one can use interactive rebase (git rebase -i) to squash and edit it into a coherent and clean history, when things get closer to finished.


You don't need to think about good commit messages. Just something that works for you and then rebase before pushing. That works for me at least


I use GitKraken (or insert your favourite git GUI) and I don't have this problem. If I ever have a "wtf did I do 10 minutes ago?" moment I can just look at GitKraken real quick and feel like a stenographer reading back notes.

I typically have it open beside my IDE so I can keep an eye on the progress in the file tree view. I can drag-select a set of lines, right-click and stage them, when I'm basically locking those in, then keep going.

It also auto-fetches every minute or so, so I have great visibility on what coworkers are doing in the commit graph. Lets me react to what they do pretty quickly, and I can implicitly review what they do and I can poke them if I notice something weird.


I also use my git GUI to quickly review what changed before making the commit. That way not only I filter out irrelevant chunks/files, but I also compare the new lines to the old ones.


I get this for tracking down a bug or working on speeding a block up. But why does the unused code need to be committed? Yes it helps you with your one problem but it clutters the document with extra information for others. So I guess I phrased my question a little accusatory, commented out code is a pet-peeve of mine, but I'm still genuinely interested why the two different blocks need to be committed. Or i guess more importantly, if they need to be pushed to the mainline for others to recieve


Maybe I misread the parent, but I don't think it was stated that the commented out code is committed.

FWIW, I also sometimes work this way; however I delete the commented out block when I'm finished. This is also a pet peeve of mine, the only time commented out blocks of code are acceptable is if the obvious way to write something introduces a bug or ignores an edge case. In that case, I also leave a note explaining not to refactor this section and explain why.

But especially while refactoring or fixing certain issues, I really find it helpful to have the prior version still present to compare against. If I have to commit while that commented code is still present, invariably my last commit message is along the lines of "removed commented code" or "cleaned comments for function XYZ". Especially since for these cases I also typically end up writing a comment once finished anyway. If there was something tricky enough happening that I was comparing against older code, likely there is something confusing enough happening that whoever is in the file next could also use some additional explanation that can only really be written once finished.


> When making changes to a block of code or block of text, I frequently just comment out the code and rewrite it anew.

This is the comment I came here for. (see what I did there?)

I also sometimes keep multiple versions of the same line in comments, such as when I'm trying to a tricky regex work. For example, I might have code that looks like:

  # x = regex1 # Original line
  # x = regex2 # Doesn't work
  # x = regex3 # Nope
  # x = regex4 # Also nope
  x = regex5 # Currently testing this
That gives me the way to see which approaches I've tried while solving the problem, and ensures I don't actually use the same exact regex twice.

When I get a working solution, I comment out all but the line that works and commit that.


In this case, keeping those in the commit might be worth it, if you come back and find that the regex wasn't right after all. That way you can make sure you (or others) don't repeat your mistakes. The comment could go in the commit message instead I guess, though I tend to keep those brief.


> I frequently just comment out the code and rewrite it anew

That still doesn't give you easy access to the state of the code _halfway through the rewrite_, which is what the article mentions.


I do this, though it can get messy when I'm experimenting with multiple changes.

As an experiment recently I've taken to keeping snapshots of active work areas using rsync every minute that there are changes present - an automated full-tree version of "keeping copies of the file" that works for everything (images, word processor docs, ...) not just my code editor, avoids an accidental change when doing undo-redo "breaking" the redo buffer, and it survives explicit file closes which undo/redo buffers usually do not. There are two significant caveats: it only works at all if I save regularly while tinkering (or the editor auto-saves regularly), and it doesn't work for files mmap-ed or otherwise open-locked by the editing process. Not terribly efficient IO wise, and still wouldn't be with the improvements I know I could make but haven't got around to, but it has proven helpful at times and takes very little space for several days of snapshots most of the time (identical versions of the same file in each snapshot are hard-linked not duplicated).


Shouldn't it be "had he looked."? Also the second rendition makes doesn't include what the rest of the joggers are doing, yet the first one does. Not sure if intentional.

At first I gasped at your practice, because I never do that, but I see the point now. Mastery of language.


Yes, I had a typo. I was editing in place, and then decided that I had made some poor choices and needed to start over. I didn't bother to fix the typo.

Yes, there is a shift in point of view between the two versions. But the story is mostly written in third-person limited, and so my first version deviated from that.

But I rewrite everything every time I read it, so who knows what will happen tomorrow.


> Also the second rendition makes doesn't include what the rest of the joggers are doing ...

Something is amiss here.


Karma/backlash for my rude post. I will leave it unedited, but s/makes// in case it is not clear.


I didn't take it as rude. Should I have?


I used to work like that. Now I don't. (And I would advise against it.)

Use version control, do lots of small of commits, use diff. Have a fast edit, build, test/run cycle. If you don't have it then spend the time setting it up.


<sarcasm>My employer told me a 23-step code submission process, across five tools, that takes four days to run all the tests is fast enough. Is that fast enough?</sarcasm>


Exactly. Lots of comments. People afraid of doing changes. Or removing old unused code. Not fully understanding what is going on. All signs of a broken development setup. Spend the time and do it right. You will be paid in multiples.


Huh, I thought your first example was much more poetic. The vaguely run-on sentence does a much better job of evoking what's happening in the scene.


Thanks. I'll think about it.


For the record, I think the second version is a clear improvement.


Out of curiosity, do you do much creative writing? I agree that the second version is clearer and more grammatically sensible, but the first version bends the normal usage of syntax to evoke emotion, although a word here or there could be adjusted.

Here's an example of a similar update; would you say you like the second version more?

"Halting, stuttering, his words slurred, his eyes watery, his knees trembling, he thrust forth the knife, and with a cry the blow was struck-"

vs.

"His knees trembled, his eyes were watery, and spoke in a steady stream of unintelligible nonsense. With a cry, he thrust forth the knife, and the blow was struck."


In both, the aloneness of "him" is the focus. In the first, his companions are the subject of both sentences. In the second, The fog and "he" are the focus, with his companions only mentioned as an afterthought.


When editing lab notebooks, it's customary to finely cross a line through data or notes you wish to discount without affecting their legibility. It's also expected that any edits or annotations be circled, dated, and initialed.

The point is that data is never destroyed, and this is one of the many causes for the unflagging preference for tangible records over ELNs.


How do you comment things out in the "English fiction/non-fiction" programming language?


I'm writing in markdown. I use the quoting > character, instead of the more verbose [comment]: #(my comment) syntax. Emacs markdown mode changes the color of the text, and that is enough for me. I use the [comment]: $(my comment) syntax for actual commentary on the text.


I do the exact same i was thinking this article was silly..




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: