It's on the front page, but at the bottom. DAS is a small one-man business, so I did the design myself (and I'm not a good designer). Sorry about that. :)
HN user
garybernhardt
It's a joke. Relax.
I like the sliced screencasts because they're so repeatable. I practice my talks a lot, and I can get the timing down perfectly because it's always the same. Highly recommended. :)
No, it's more subtle than that. By wrapping in parenthesis, you're making it an expression. When you just say "{}+[]" in e.g. Chrome, the first {} is parsed as a block. So what you see printed is the result of "+[]", which is 0. This is why {}+[] is not equal to {}+[] without parens. This may also be why Node gives different results; I'm not sure.
I didn't mention any of this in the talk (it would've killed the flow ;). Instead, I glossed over it and interpreted the syntax as any sane programmer would.
There's no laugh track; that's the audience.
It's Keynote. I recorded those sessions as screencasts, then sliced them into tiny pieces so I can advance them perfectly with my talking. There are 37 slides in that four-minute talk. In some cases, the slices are only two or three frames long.
I could port it to Python if you want? ;) I probably wouldn't have done this when Python was my main language, though. That community has a much harder time laughing at itself than Ruby's does.
I was tempted to leave the disclaimer off, both in the README and the blog post. But I think there's a strong enough chance of someone actually using it as it is... ;)
You can just create a new branch before you start the rebase, which achieves exactly the effect you ask for. Rebase is how you "create a new branch with only the clean commits".
But, most of us don't bother copying before rebasing. The reflog makes that pointless from a safety perspective and, without the safety need, there's not much reason to copy before rebasing.
I don't rebase everything. Merges still have their place.
An early draft of this post talked about the relationship between rebase and bisect, but I cut it out to focus on one topic. The tl;dr is that heavy merging makes it harder to reason about bisect (and, of course the history in general).
This is my personal list of RSS feeds, which I've been curating for many years, so I knew exactly what data was coming. It was a one-time hack: it got my RSS feed list into the database, and was never excuted again. It was also only for local testing purposes.
I think that it would be pretty crazy to import simplejson on the Python side, write extra code to dump the data to JSON, look up how to do it in Ruby (because I don't know off the top of my head), and add the code to load it from JSON. That effort would not change the outcome by a single bit. For other theoretical data sets, it would, but this is not other data sets.
If this code were ever going to be used again, sure, I'd transfer it in a safe way. But this is the equivalent of `grep`ing and `cut`ing at the Unix shell – the goal is to get data from point A to point B, never to be revisited. I reject the idea that, in this particular case, extra effort to serialize and deserialize JSON data is superior to adding five characters of str().
JSON syntax is Python/Ruby primitive syntax for lists and strings (although the reverse isn't quite true). Why add a library import and additional code on each side just to emit and consume what is effectively the same data? :)
I considered using Vim at the time. The nice thing about doing it all on the command line is that it's repeatable and persistent. I have a huge shell history, and that command will now be in my history for months. I rely so heavily on my history that I'll often remember a related command from a month ago, find it, then modify it for my current use. :)
I don't think that Google Reader can export as JSON... ?
Also, MQ's "qdel" command is the one that led to the data loss mentioned in the original blog post. So it doesn't really answer my concerns. :)
I often do it multiple times per minute. That wouldn't fly if each required a clone. :) (See another post I made in this thread for what I'm doing that involves so much history mutation.)
Yep – and I did it all, using those tools, for a couple of years. :) Now, when I go back to Mercurial (which I know better than Git, mind you), I get frustrated. Those tools are much more blunt than their Git equivalents.
Git gives me everything I needed MQ for, but with the complete safety of the reflog. There is no such thing as a change I can't undo. The fact that patch management is "special" in Mercurial is the problem!
With respect to history modification:
First, I rebase a couple dozen times per day. I'm on a team that doesn't use merges unless we have a reason to (this makes it easier to bisect and think about history). I also create, destroy, and rebase many of my own branches every day.
Second, I amend commits a lot. I'll often spike some little piece of code I don't understand, then start amending the commit as I rewrite it with TDD, until the commit no longer contains any traces of the original spiked version. For more complex spikes and TDD rewrites, I'll do it over many commits, rebasing the spike over the rewritten version until the spike commit is empty and gets skipped by the rebase. Doing that in Mercurial would be... arduous. I can easily do multiple history rewrites per minute while doing this.
Third, I amend commit messages a lot, usually with "git rebase -i". Maybe I forgot the ticket number, or maybe the meaning of the commit changed (see the next point).
Fourth, I sometimes do drastic commit rearranging. This is harder to explain, but it usually involves splitting commits (in the simple case) or moving sets of related changes from one commit to another (in the complex case). These are sometimes at the file level, sometimes at the hunk level, and sometimes within a hunk. This is rarer than the others; I probably do it once or twice per week.
Fifth, I "git reset <ref>" a lot. It took me longer to start doing this, but it's useful in a lot of situations. For example, "oops, I accidentally created a merge bubble."
Did you read the end? ;)
""" I'm sorry for recommending software with a confusing interface. But you'll be spending a lot of time with it; it's worth getting over the initial hurdle of confusion. """
Note that I call it the "initial hurdle". I know both systems very well, and Mercurial gets in my way far, far more than Git.
The command that lost data was hg qdel. Strip won't lose data; it dumps bundles (although they're a pain in the ass to restore from). Like I said, I used Mercurial for three years. And not "I play with it sometimes at night" kind of used, but rather "it was my main version controls system all day, every day" kind of used. I was using MQ for most of that time.
The fact that so many people consider "hg strip" an advanced command is part of the problem. Modifying history should not be considered advanced. Being able to recover from ANY command, including destructive ones, should not be considered optional.
Augie, I understand what you're saying, and I don't buy it. Git, when taken as a full DVCS capable of rewriting history, is safer than Mercurial, when taken as a full DVCS capable of rewriting history.
A DVCS that is incapable of rewriting history is, for me, a nonstarter, so I'm not interested in talking about "well, if you turn off the interesting parts of Mercurial, it's perfectly safe!"
You can either use Mercurial in a mode where it's not at all equivalent to Git, but safe (extensions off), or you can use it in a mode where it's somewhat equivalent to Git, but might lose your data.
With Git, I can mutate history without the slightest bit of fear, often just to see what will happen. Does this giant branch I discarded two months ago rebase cleanly over master? Try it. If the rebase completes but I don't like it, I "git reset mybranch@{1}" and everything is good. And that safety net is always there.
In Mercurial, I have to stop and think every time. Even if the command does dump a bundle, restoring from it is a special case, and I'm going to have to go dig up the bundle file, and in some cases it might not be there and I'll be screwed. In Git, there are no special cases, I always know exactly how to recover, and the recovery mechanism is always there.
Once more, to be clear: In Git, it is always there. Always there!
I'll think about it. With the awful response from Reddit [1], I'm not sure that I want to make another go at it. :) We'll see.
To respond to your example, I'd almost certainly go with something like your Count_Xs_in_Row path, or some similar subset of the problem. I'd probably first drive out the "win" concept by saying "if there's a row full of Xs, X wins; if a row full of Os, O wins." I don't actually need to be able to count rows for that; I can pass something fake in (probably a stub). Once I'd done that, I'd drive out the row counting, possibly backporting that into the "win" tests, but probably leaving them totally isolated.
In this example, the key insight is that the concept of winning (a full row) can be independent of the process of counting rows. The tests would push you toward that separation naturally, because it would be too hard to think about testing the "X wins" directly based upon a full board.
This is still a bit overwrought, as it's still a toy example. Toy examples make TDD sound silly, which is a big part of its perception problem. I still don't know how to fix that other than pairing with a person and/or talking directly to them in person for a couple hours. :(
[1] http://www.reddit.com/r/programming/comments/a2yhe/im_not_su...
This post was aimed at the person who is interested in TDD, but hasn't had their first big insight into how it works. It's about "do the simplest thing", not about a full TDD process to build a working production system. As I said to someone else in this thread, such a blog post would be huge. No one would read it. We wouldn't be here talking about it. :)
The thing preventing infinite implementation is a combination of (1) the rules of simple design and (2) the definition of "simple". I write about those in the follow-up to this post: http://blog.extracheese.org/2009/11/the_limits_of_tdd.html
I've said this several times across several forums since publishing this post, but my goal was to write a very brief example of "doing the simplest thing". It's not about doing the entire TDD process on a real-life software problem, because that post would be so long that no one would read it! :) I don't think TDD can't be adequately demystified in any short example.