Every line of code is always documented
mislav.uniqpath.com
mislav.uniqpath.com
Code like this is extremely brittle with or without that git history, don't rely on it like a crutch as it makes the code obscure, and updating a line somewhere may leave other similar lines updated or not. If you wanted to update the triggerLayout function, you would have to go through the git commit log for every .clientLeft line to see if that one was or wasn't used for triggering layout...
Should these things happen? No. Do they happen? All the freaking time.
Aye, and with intention revealing names!
You were right, however, that the post was never about code quality or code comments. It was only about "history's great, yo; here's what you can do with it".
Having a detailed code history isn't in any way an excuse to leave obscure code as is. If you have time to document it, you have time to make the code right.
In short, maintaining a clean code base has always higher priority than maintaining a clean log.
http://lsolum.typepad.com/legal_theory_lexicon/2003/09/legal...
this article is about recommendations of what to do ex post once a comment-less line of code has been committed in the past that you need to understand. arguments about ex ante things such as how it got there in the first place and how to prevent it from happening is completely orthogonal to the point of the article.
https://github.com/madrobby/zepto/commit/3d92f20966aa02dee82...
Which means the OP genuinely thinks that commits like this one are good practice, and the purpose of the article is to show how to deal with it.
Yet as it was argued above, commits like that should never happen in the first place.
Notice the code comment. I took it out for the example in the blog post to illustrate how we would deal if there was never a code comment in the first place.
I think the article as a whole is great in that it taught me some things you can do with git that I didn't know before (well, stuff I figured was possible, but didn't know the magical incantations). But it's hard to start reading it and really appreciate all that when the initial premise for explaining all that stuff was... well, someone having a severely bad day when it comes to writing clear code.
From my experiences in the real world and from reading comments here, I think there are a lot of people that disagree with that assertion, and it kind of makes me wish I worked in a field where I don't feel like I'm going insane on such a regular basis.
I think the overall point of the article rings very true: great VCS habits pay dividends over time regardless of how well-crafted the code itself is.
// This triggers layout. Needed for some browsers.
But agreed that you shouldn't require relying on history for this context. It's bad news. Yes code happens, but it should be obvious what it does (via clear code) and why (via comments as needed).
The example in the original post relies heavily on out of band documentation. Your suggestion of an intention revealing function name puts the same info in-band.
One should always ask themselves: Does my code depend on out of band information? If so, can we correct this?
Digging through version control comments seems to me a last-ditch effort to figure out what some code is doing. If the project had any significant history you could be digging through hundreds of commit messages. Why not just put a 1-liner comment above that line and save every subsequent developer the hassle of wondering what the heck that seemingly useless line does..?
Probably the same people think that well-written code does not need comments at all. That may be so, but well-written code is hard to come by. While this rock-star macho attitude is aplenty.
Not only that, but I speculate that those holding such opinions are usually young, well above average programmers who therefore work exclusively on brand new projects - many of them have literally never experienced the nightmare of maintaining and extending some crap code written in the most clever and obscure way possible by someone similar to themselves. Hell, a lot of them likely don't stick around long enough to make major modifications to their own code.
I usually want to see (1) what the code does (2) what the code is intended to do and (3) why the code is intended to work that way. Usually only the first can elegantly and most easily be expressed in code.
For instance, I read a performance-critical function that would stop processing data and return early in an obscure corner case, but performed better than the best way I could think of to handle the obscure corner case. There were at least 3 possibilities: (1) the author made a mistake (2) for reasons I couldn't see, the corner case was impossible or (3) for reasons I couldn't see, the consequences of mishandling the corner case were never as bad as I thought they could be and the performance gain was worth it. I had to look up the revision history, call up the author and ask him which it was. It turns out the author had missed the corner case, but I try to as rarely as possible assume I'm smarter/more insightful than the original author.
So I think that is a good mentality in as much as it keeps you thinking and writing clean code. But, I think it's also rather presumptuous to assume everything will be clear to others. Also as you say - once you've had to stick around and maintain a few applications, you really appreciate a thoughtful programmer who put in some comments that saved you a few hours. And you start to loath the rock-star who came in for 6 months and wrote a bunch of code using the fad-of-the-moment design pattern without commenting anything.
Why on earth wouldn't you place this explanation in a comment preceding the line of code itself?
One of the best things I ever learned in programming is that you shouldn't write code to be executed -- you should write code to be read and understood by other people.
It's going to take me forever to read your file and understand what's going on if I have to do a git blame on every other line.
Just use short purpose-based commit messages (fixes a bug where..., so now...), and then put the actual why behind the implementation in the source code comments itself!
My problem is that usually the people who neglect to write a comment in the code, also neglect to write meaningful commit messages. Usually it's just "fixed the layout bug" or something like this, along with a bunch of other unrelated changes all squeezed into one commit.
I've worked in enterprise. If your team relies on a centrally administered source control, then you can be in a world of pain if the central team decides to switch tools (and when this happens moving your revision history comments to the new system will never be considered important, if even possible).
Keep important things in the code. That's my experience.
I'm not sure what MPW Projector is, but the rest are pretty mainstream.
It's amazing how many proprietary revision control systems there are, and how much worse they are than the free ones.
RCS clearly wasn't good enough for a team (distributed or not) or concurrent development, but CVS was good enough, with incremental improvements by SVN & Git.
The proprietary systems usually offer integration with a but tracker (mandatory ticket ID on check-in/commit) to lure the ignorant who don't know about commit triggers. Otherwise, they tend to be very slow, frequently time-out their licenses / login-sessions, and/or have a very deficient command line interface making it difficult to script a build system.
// Hack to trigger layout change in latest Mozilla
Then, whoever interested in the hack can read the full explanation from the commit message.Basically, for simple code with unclear purpose, I'd go with short comment in the code plus full explanation in the commit message. For hard-to-read code with complicated logic, I'd go with long comment in the code. Or refactoring.
Ticket description, commit message, code comment, and the code itself are all necessary to keep the codebase "documented".
It's not like we're conserving paper. And syntax highlighters helpfully give comments different colors so you can skip over them while reading.
Personally, I've never once wished that a particular piece of code were less commented, but there are hundreds if not thousands of times I've wished that there was more explanation, or any at all.
You don't want to make someone who is editing code stop to think about how it affects the comments.
What's the point of comments then if your general rule is that it should be fine to edit code without changing the comments?
Not without changing the comments. Without stopping to ponder how two paragraphs of comments fit into the code changes. The comments (aside from API documentation) should annotate the code, not the other way around.
Spelunking through commit history shouldn't be necessary learn the intentions behind those kinds of actions.
If you do need to go git spelunking to figure out what's going on, you'd have to be insane to not add a comment afterwards.
Either way, "shoulda coulda woulda". If the code doesn't have a comment, it doesn't have a comment. These things happen, and you can't change the past. But with git, you can relive it.
A project’s history is its most valuable documentation. (...) The quality of this documentation, however, relies heavily on the diligence of the people involved while writing commit messages.
Requiring such diligence when writing commit messages, while at the same time allowing the same people to write opaque code as shown in the example, would be absurd.
Apart from that, to rigorously apply it would break the author's own advice or common sense source control practise - suppose I make 4 changes in separate files to fix a bug. Do I check them in separately so that I can put my pseudo code comments into the revision history? Now I have broken the atomicity of my revision history. If I check them in all together do I type a whole essay into the revision history about why each change was made in each file? It'll quickly all fall apart.
It also relies on the reader recognizing that they need to be curious about the code here. What it if didn't look so curious? It could easily get cleaned up or modified without a comment to alert the reader.
For people and projects in specific contexts it can work but there are plenty of situations where this is a terrible idea.
I suggest we take a step back and ask if modern version control is the best way to store historical information. Modern version control systems (git, mercurial, etc.) were built within the last decade or so but they were built with the same constraints as the original version control systems of the 1980’s. They are optimized to be disk efficient (and don’t get me started about their command line interfaces). This is crazy!
We should store much more about the programming process than the data gathered if and when a developer chooses to commit. We should record it all- every keystroke. No human generated source of data is ever going to fill up our hard drives or the cloud. Don’t optimize for the disk!
This data can be used to replay programming sessions so that others can learn exactly how the code evolved. Developers could then comment on the evolution of their code. Think of this as a modern commit message. I am working on a project that attempts to do this:
I agree that we could benefit from saving more (e.g. relevant exploratory sessions, though those tend to happen in the REPL, not in the code editor), but I disagree with an indiscriminate approach.
While the process for filtering out dumb decisions and irrelevant debugging is a little convoluted at present, filtering out misspellings is really easy if they're made within X seconds (where X is defined by you). Because Storyteller currently only supports IDEs (specifically Eclipse, hopefully with support for Visual Studio soon) you should be able to notice those quickly.
As for processing out dumb decisions, you don't really know they're dumb until after you've made them, and someone new to a part of the project might also have the same idea you had when made those decisions, and seeing that you made them, hopefully coupled with some comments on what went wrong with those choices could push them in a different direction, or help them fill in a piece you were missing. Watching those past decisions could also help you in the future when you come back to some code and can't remember what you did before or why.
Exploratory sessions only happen in REPLs when the language has a REPL. Considering that Storyteller's written in Java, has support only for an IDE that was initially built for Java, and has been written by a bunch of college students and one professor at a college where most CS courses use C++ or Java, REPLs aren't really things most of us use (I want to change that, but there's only so much you can do through an extracurricular organization).
Plus, we're developers. Why store only some data when you can store ALL THE DATA!
1. How is that different than functionizing things? And, is it better? Especially because in wart it looks like your snippets can only be used once.
2. Does this bring you any advantages that well commented code doesn't? From my admittedly limited point of view (I haven't run it, just looked at your two examples) it looks like following the flow of control is a little more difficult, because it looks like your snippets are, when compiled, just placed where their comments are. Because variables are accessible and manipulable in your snippets there isn't any containment like you get with functions.
Again, this is from me only looking at your two examples.
I don't think it's controversial that functions have limitations. For example, OO in many ways was an attempt to work around the limitations of functions. But what OO discovered, I think, was that any sort of modularity mechanism when baked into the language brings in its own constraints, which limit the situations where it can be used. The classic example is all the constraints on C prototypes that make any sort of refactoring of include files an NP-hard problem, dooming lots of codebases to never get the reorganization they need to free them from historical baggage. So I've gradually, grudgingly started to focus on more language-independent, tool-based approaches that can overlay an 'untyped' layer atop even the most rigid language.
"Because variables are accessible and manipulable in your snippets there isn't any containment like you get with functions."
My claim (http://akkartik.name/post/readable-bad) is that in seeking local properties like containment/encapsulation we deemphasize global understanding. Both are useful, certainly, but they're often in tension and our contemporary rhetoric ignores the tension. The pendulum has swung so much in favor of local rules for 'good style' that it's worth temporarily undoing some of that work to see what we're giving up, what the benefits of playing fast and loose with local structure might be.
"..following the flow of control is a little more difficult.."
Yeah that's a valid concern. I think literate programming failed to catch on partly because we need at times to see the entire flow of control in a function. Like when we're debugging. I have a vague vision that programmers of the future will work with the expository and 'tangled' views of a program side by side. (In addition to perhaps a view of the runtime execution of a single unit test: http://akkartik.name/post/tracing-tests.)
Your point about reusing snippets is also a good one. That's the benefit of naming fragments in literate programming, isn't it? I hadn't considered that; the examples I've seen never mention it. But emacs org-mode and http://leoeditor.com certainly seem to find reuse useful. Hmm. I haven't encountered the need for reusing snippets so far. That might change, and we can probably come up with some syntax to support it if so. I suspect, however, that our languages already have plenty of primitives for enabling reuse. We don't need any extra tool or meta-linguistic support.
---
Clicking through to your profile I ended up at http://essays.kuntz.co/you-re-probably-not-for-hackers, which suggests we have kindred sensibilities about these questions! (Compare http://akkartik.name/about)
The easiest way to alleviate this, in my opinion, is to focus on building smaller programs which focus on doing one thing well, and combining those together to create larger applications, with preferably a minimum of glue code. In my mind this leads to even more containment as each domain is now accessible only through the specified API.
This could lead to similar problems that you have with the deemphasis of global understanding, because it's still compartmentalizing things, and at each higher level the programmer is just trusting that the lower levels have implemented what they said they would, just like in a huge, single program.
The idea of being T-shaped specifically when it comes to the overall knowledge of the projects you work on seems to be the best way to work on those applications: have a general understanding of the whole project, and a really good understanding of your specific domain (and perhaps an intermediate understanding of those around yours).
, two = "bar"
, three = "baz"
Agree with the author that this is easier to change, and in JS it will keep you from accidentally leaving a trailing comma. That being said, I find it to be very unreadable(which is where most your time will be spent) and most text editors/IDE's make it a burden to work with. var one = "foo";
var two = "bar";
var three = "baz";What he didn't point out though is that he was actually the one that contributed that code in the first place.
https://github.com/madrobby/zepto/pull/586
https://github.com/madrobby/zepto/commit/3d92f20966aa02dee82...
As others have commented, long explanations like this have no place in commit messages. Comments should always be used to explain what you're doing and why you're doing it. Commit messages should simply summarize what you did.
A better commit message would have simply been:
fix animate() for elements just added to DOM
See included comments for explanation.
But if you're going to do this trick and you use a code compiler of any sort, you'll need to assign the value of that clientLeft somewhere. Otherwise your compiler will notice it not doing anything and helpfully optimize it away. So your users in production will see your layout bug and you'll never be able to reproduce it in development.
JavaScript is awesome.
As to the article itself, I'd prefer to see a comment on a line as wacky as this one. It's one well-intentioned lop away from vanishing from that git blame entirely, and then six hours of debugging and research away from finding its way back into place.
Trying to sift through file history to understand what's going on is hard enough on code I wrote myself only a year ago. I wouldn't want to rely on it as the only way of digging into a large shared code base. Yikes.
This optimization is only possible if the compiler is able to deduce this as a useless function call. In order to do that, the compiler has to deduce (i) that the result is not used, and (ii) that the function has no side effects. (ii) can be very, very hard to deduce.
And you avoid having to write your comments when you commit. You'd do it in the code when you are more focused on the change.
Even better would be detecting when you are changing code and prompting for the comment or let you select from recent comments.
Then on the SCM side when you commit, each comment could be handled as a separate commit.
Any IDEs already doing some or all?
Others have mentioned the "no comments" culture. To them I say: each file/class and each function/method/subroutine should have a summary comment, so I can know to skip over the irrelevant modules when I am looking for how to do something. I don't want 80 to 100 character identifiers (getMatrixResultButNotCornerCaseANorCornerCaseB or some such ridiculous name), but I do want a bit more summary than the name, contained within a statement of purpose comment.
DVCSs are designed to overcome this problem, and there are bridges between various DVCSs, but sadly this still happens.
So, while mastering '<yourvcs> blame' is certainly useful, you shouldn't rely too much on it, and write readable and well documented code.
gem install stefon
If I can't understand from the commit message, what the change is trying to achieve, I won't even look at the code. Instead I'll ask to clarify the commit message first.
Good luck there.
If you remove the line you should end up with a failing test.
whilst i'm a big fan of making code good enough to read - and learning to read code properly - its easier to not have to do both
Yeah, I know that's blasphemy, but it's also true: Javascript works just fine WITHOUT all the extra semicolons. The semicolons are only needed in the minds of those who have been misled to believe that they are. One should learn what JS thinks are complete statements -- where to wrap longer statements without causing an error -- as Javascript WILL end statements without semicolons. Better to just never use semicolons in the first place.
And this is all off-topic...