Git is Magic
Posted by postfuturist on 2010-07-23 23:45:33

Where I work we've switched our biggest project from Subversion revision control to Git. It is a large code base. I've been using Git for personal projects for awhile, but I've been keeping it pretty simple. For a large project with several contributors, Git is not only adequate, it's pure magic.

First of all, Git is fast. It's really, really, incredibly fast. On this particular code base, just running "svn status" could take 30 seconds. With Git, it never takes more than a second. Even "complex" actions, like merging large changesets, creating and merging branches take anywhere from 0 to 1 seconds. Really, you have to try it out to get a feel for how fast it is. Remember, this is a huge code base. The slowness of Subversion in comparison makes me think of the movie "Me and You and Everyone We Know." In it the foot store clerk, played by John Hawkes, tells the woman, played by Miranda July, when she tries to explain that her foot pain is due to her low ankles, "You think that you deserve that pain, but you don't." Eventually he tells her, "People think that foot pain is a fact of life, but life is actually better than that." If you think you have to wait for Subversion or whatever other source revision control because you have a large code base, you're wrong. You think that you deserve to wait, but you don't. People think that revision control system slowness is a fact of life, but life is actually better than that.

Branching is fast and relatively easy. First of all, everything happens locally. Git is really just a specialized database. Everything gets stored inside the single .git folder. You can create millions of branches with different changes and merge them every which way all without a functioning internet connection. If you have a central repository, just push your changes and pull other's changes at your leisure. So back to branching, I'm about to create a branch and switch to it. The branch I create will be a branch off of whatever branch I happen to be in. Hold your breath.

$ git checkout -b new_branch

Too easy? Just wait. Now let's assume that I changed some things and committed them to that branch, using "git commit". OK, now I want to switch back to the master branch.

$ git checkout master

Wait, that's it? What's in my working copy? The contents of the master branch, unchanged. The "new_branch" branch and it's change set are tucked away in that .git folder. You can then push that branch to the upstream repository like this:

$ git push origin new_branch

OK, so let's say someone wants to bring that branch into the master branch later. All they have to do is this:

$ git checkout master # make sure you are in the master branch
$ git pull origin new_branch # pulls in the branch to their repository
$ git merge new_branch # merges the changes into the master branch
$ git push origin master # pushes these changes to the master branch upstream

There are a lot of different workflows with Git. This is just assuming a "centralized" upstream repository. Even with the centralized model, there is a lot of flexibility. All of these operations are very, very fast.

With such prolific, easy branching, we now develop against reality not fantasy. With Subversion, we would just commit changes to the main branch, and our changesets would stack up on each other. Eventually, we had a backlog of changes that were all depending on each other, none of which had actually been merged into the production branch. It was a nightmare. Perhaps we could have had a better workflow with Subversion, but nothing seemed natural. With Git, the master branch is now in sync with the production site. We develop features against the site, as it exists, put them into a branch, and that branch gets merged with the master branch when the feature goes live.

We could have done something similar with Subversion but you have to merge changesets manually by revision number, and Subversion doesn't track these merges for you, so you have to be very careful not to reapply patches more than once. It's a big mess. Basically Subversion fails dramatically. Git. Just. Works.

One reason that Git does branch merging so much better is that branches aren't different folders with shared ancestry. Branches are just pointers to nodes in a directed acyclic graph of commits. Changes in one branch don't have to be recreated to be merged in another branch. Those changes have the same identification (a SHA1 hash), so they will not be applied twice. Here's a situation: you have three branches, A B and C. You make changes in all three branches. In branch A you merge in changes from branch B ("git merge B") and in branch C you merge in branch A, well you get branch B for free. If you try to merge in branch B into C at this point, Git already sees that each of the commits in that branch have already propagated to branch C, so nothing happens. That's what you want.

Commits are cheap, and have an identity. Every commit has a hashed id. If you want a single commit from a different branch, just cherry-pick it by id. If you merge that branch later, it already knows you've gotten that one part, so it won't re-add it. Smart, huh?

OK, Git isn't really magic. It's just computer science--which is nice. People in the subversion crowd are trying to keep it going, but I don't see the point. Continuing to use Subversion and other outdated revision control systems is masochism. Oh yeah, I've used a few others like CVS, Perforce, and Visual SourceSafe. Same crap, different name. If you haven't, do yourself a favor and try Git. Your whole life could be better. Just starting today.

Spammed Again By LinuxQuestions.org
Posted by postfuturist on 2010-07-19 14:10:53

Not only does LinuxQuestions.org spam users relentlessly, force you to log in to stop the spam, and generally have the crappiest forum software coded by lower primates, unchecking the "Receive Community Bulletins" checkbox in the account options page does not remove their spam from your inbox. Here is an open letter to the idiots who run LinuxQuestions.org:

You suck. Please read The CAN-SPAM Act.
Beginner Python Program Example
Posted by postfuturist on 2010-07-18 19:03:21

I'm currently teaching a sort of introduction to programming class using Python. It's a fantastic beginner's programming language because it is very approachable. There is no minimum boilerplate code, like having to create a class in Java just to print "hello, world". There are no projects and IDE's to learn. There's just the interactive shell that lets you try things out without consequence. In any event I've been trying to come up with a simple enough program that the students could understand that seems, at least, potentially useful. The limitations are that the program has to run on Windows or OS X machines with the default Python install and it can't involve any advanced topics. Since I'll be discussing Python dictionaries in the next class, I thought a small shell-like program that allows the user to enter arbitrary data (build a dictionary), save it to a file (using pickle) or load from a file would be a good starting point. Here is the code: (Python 3)

import io
import pickle

data = {}

while True:
    command = input("Command: ")
    if command == "" or command == "help":
        print("Valid commands are: show, add, save, load, quit")
    elif command == "show":
        print(data)
    elif command == "add":
        key = input("Key: ")
        value = input("Value: ")
        if(key != ""):
            data[key] = value
            print("Assigned %s to key %s" % (value, key))
        else:
            print("Error: empty key.")
    elif command == "save":
        filename = input("Filename: ")
        f = io.open(filename, "wb")
        pickle.dump(data, f)
        f.close()
        print("Saved data to %s" % filename)
    elif command == "load":
        filename = input("Filename: ")
        f = io.open(filename, "rb")
        data = pickle.load(f)
        f.close()
        print("Loaded data from %s" % filename)
    elif command == "quit":
        break
    else:
        print("Unknown command.")

print("Goodbye.")

So, the program is only 30+ lines long but it usable, for some value of usable. Everything the program is missing are things that could be added by students. Maybe we will not add exception handling right away. But we could add a few "commands" to the list, like "new" or "remove". It could check if a file already exists and ask permission to overwrite it. It could remember the last file saved and have a "save" and a "save as" command.

Follow-up To Anti-IDE Rant
Posted by postfuturist on 2010-07-09 01:07:52

OK, I wrote an anti-IDE rant some days ago, dissing NetBeans and its ilk and extolling the virtues of Vim as my primary code editor. Read that here, if you are curious. I took some liberties with the English language, for which I sincerely apologize to the queen of England. Somebody posted it on Reddit and it got tweeted and linked on Code Project. I found a bunch of comments needing moderation. Some were thoughtful, some vitriolic. However, one comment was absolutely hilarious:

Writing code in vim makes me hate life. I've written a large perl/bash/php system in it and wanted to kill myself nightly. Your article, while very accurate for some people, makes other developers throw up in their mouth. IDE's features like code-folding and boilerplate generation are there to help developers develop more rapidly, which is something that is very valuable in todays market. Sure, Java sucks, but when you don't have a choice, what are you gonna do? Write C# in notepad? I dont think so. If I had to write all my code in vim, and meet deadlines, I would blow my brains out. I love my Visual Studio. And for the record, no crashes, no instability, no hate. You may call me names, and say I'm not a real developer, but for RAD theres nothing like a well balanced IDE. That being said, Netbeans sucks donkey dong. Im a VS user.

Firstly, I took no offense at this comment. In fact, I loved it. Now, I think the commenter missed a couple points. I'm not suggesting people write C# in notepad. To be fair, I've spent years using Visual Studio as my professional, get-things-done IDE. It is pretty stable, and useful if you are developing Windows apps. I'm not developing Windows apps. Thank God. That would make me want to blow my brains out.

Admittedly, Vim just ain't for every developer. I've flirted with using it for all my work, but usually went crawling back to the big IDE's because of something I couldn't do without. Usually, I just didn't know how to do it right in Vim. But this time, the conversion is permanent. Yeah, it kind of sucks at first, but I just stuck with it until my proficiency surpassed what I could do in any pointy-clicky IDE. It didn't take as long as you might think.

All I am arguing for is choice and exploration. There are reasons that I don't develop in Java or C#, I don't want to. I work in a non-corporate setting and I don't write enterprisey code. I like it that way. It's not for everyone. Some folks like the grey cubicles, memos, meetings, harassment prevention classes, ID cards, office politics, etc. I've been there, done that. Life is too short. Pick the tools you want. However, know that a good number of software developers in the world use Vim or Emacs, not because they don't know about big, fancy IDE's, but because they can do more, faster with those tools. You can be a fantastic developer writing C# in Visual Studio or Java in Eclipse. You can also be a fantastic developer writing R on napkins or Fortran on punch cards for all I care.

Just know this, I close tickets. I write unit tests. I ship good, clean, unit-tested code. Yeah, I know, unit tests aren't perfect. If you have to pick a religion, you could do worse. I don't pair-program. God help me, I'll never understand how two people and one keyboard are more productive than two people and two keyboards, unless you can't motivate either of them to work otherwise. But, hey, if that's what you need to get through the day, find a consenting partner and pair-program to your heart's content.

LCD replacement on a Gateway LT2032u, etc
Posted by postfuturist on 2010-07-01 21:35:08

5 days ago, I ordered a replacement LCD screen for Megan's netbook, a run-of-the-mill Gateway LT2032u machine. The screen had cracked due to an unfortunate fall. I was able to install the replacement in less than an hour, and it works perfectly. The netbook originally cost about $300 and the replacement screen was only $50. Small victories.

In other news, Opera 10.60 was released officially today. Opera is truly an awesome engineering feat. The supported operating system list is impressive: Windows, OS X, Linux (i386, x86-64, and PowerPC), FreeBSD (i386 and x86-64), and Solaris (SPARC and Intel). The FreeBSD'ers must be rejoicing. Not only is basically every modern operating system supported, but it is the fastest browser, even faster than Google's Chrome. I didn't believe it either, until I ran some benchmarks myself. It's got WebM video. Now that Firefox is getting beaten badly by 3 browsers in the speed category, the folks at Mozilla need to do some soul-searching. If the current Mozilla JavaScript engine (SpiderMonkey), which is descended directly from the first ever JavaScript interpreter created by Brendan Eich at Netscape, can't keep up, it should be replaced. Heck, Mozilla could grab V8, it's open source. It certainly wouldn't be a trivial task, maybe infeasible due to how deeply embedded in the code the current one is. But they have to do something.

The release of yet another super-fast browser is a big win for everyone. Internet Explorer is losing market share fast enough to make Microsoft actually want to compete, though IE 8 was such a spectacular failure that I have little faith in IE 9. The web is everything. Windows is still the dominant desktop OS, because that's what you get when you buy a computer. It doesn't much matter now, though. You could put someone in front of an Ubuntu desktop, they'll click the Firefox icon and be off and surfing in no time. The web is the great equalizer. Between Firefox, Chrome, and Opera, the operating system has become a commodity. Add Open Office and Google Docs into the mix and there is no reason that anyone couldn't use any operating system. Now, I prefer Linux as the perfect balance between usability and power. If I was a hardcore gamer, I would probably use Windows since it is the PC gaming operating system. I've even dabbled with Windows 7. It's not that bad--much better than Vista and finally an evolutionary step past XP.

Some people love OS X and I understand why. It is the smoothest, sexiest operating system with enough Unix cred to be cool for the developer crowd. I'm willing to trade in that sexiness for paying 1/3 as much for a computer and having a slightly more powerful, configurable operating system. OS X is also a bit too mouse-oriented for my taste.

Enough about operating systems. I want my Arm-powered Linux netbook already. When do I get that? Lenovo's got one in the works, called the Skylight, but it looks to be a bit pricey.

My .vimrc
Posted by postfuturist on 2010-06-28 13:37:00
This is mostly for my own benefit, so I can copy/paste it when I'm setting up a new system:
set nocompatible
set tabstop=4
set shiftwidth=4
set smarttab
set expandtab
set softtabstop=4
set autoindent
set smartindent

set showcmd
set hlsearch
set incsearch
set ruler
set visualbell t_vb=
set nobackup
set ignorecase
set ttyfast
set sm
syntax on
set background=dark
set virtualedit=all
Notes On Running Ubuntu Linux on an Old Computer
Posted by postfuturist on 2010-06-27 17:42:55

These are some packages that I found useful running Ubuntu 10.04 on a 10+ year old laptop. This laptop is so awesome it has a CDROM and a floppy drive built-in! It's maxed out at 384 MB of RAM which is pretty nice considering it shipped with 64. It's a perfectly capable machine, as long as you pick the right software.

  • Window Manager: Fluxbox
  • Wireless: install wicd and remove network-manager
  • Terminal: rxvt-unicode
  • PDF Reader: epdfview
  • Web Browser: epiphany
  • Text Editing: vim
  • Video Game: nethack
So long and fare well to the IDE
Posted by postfuturist on 2010-06-26 00:58:11

Netbeans crashed. Again. For the last time.

I'm normally a patient man, but an IDE has only one thing it has to do. It has to allow me to edit text files. An IDE that crashes is worse at facilitating coding than a piece of paper. I've used them and I'm done with them: Visual Studio, Code Warrior, Eclipse, Delphi, NetBeans and a few others.

Somewhere in the last 13 or so years of fooling about with Linux, I found myself editing text files with a strange, and at first confusing tool known as Vim. Now, I'm not a gun nut, but when I reached a certain age, my father decided it was time for me to learn how to fire a real gun. The first time I held it in my hand, I was immediately frightened by the terrible weight of the device. It was a revolver with a long barrel like something out of a Western. I nearly dropped it. It took quite a bit of effort to hold steady at arm's length.

Vim is a grown-up text editing tool. It's no cap-gun, or BB rifle. It's dense and dangerous and powerful. Vim is keyboard driven and minimalistic, allowing the maximal editing power with the fewest keystrokes. As a programmer, it's all I need. Vim has never crashed on me. Not once. It has some of the sugar that the big IDE's have, like syntax highlighting, but it's lightning fast and stable and powerful. Some IDE's have code folding where you can hide parts of the code and expand them with clicks of the mouse. Why?

Click click click is for surfing the web. The keyboard is a much more powerful input tool than the mouse. The mouse is for lazy consumers. Now, I can be a lazy consumer at times. I watch the television. I click and read, click and read, click and watch. But when I'm working, the only click and clack you here is from the keys on the keyboard.

I don't like being a code generator. I don't like typing up boilerplate. I hate copying and pasting. I like small code files, with long names, and a handful of short, declarative functions. I don't like wasting time. Here's the typical way to complete a piece of web functionality in PHP. Create a script, write some SQL code to extract some data from a database, blast some HTML out to the browser. Lather, rinse, repeat. It's boring. It's inane. It begs for a higher level of abstraction.

IDE's are made for human code generators. Oh, you need to write a class that implements some Java interface? Well clickity click here, type a class name, clickity clack there and the IDE has generated a bunch boilerplate: a class definition with a bunch of stubbed methods, curly braces, semicolons. Don't want to look at all that ugly boilerplate? Just hide it by clicking on the code folding mechanism. Now you don't have to look at it anymore. What the hell? Java sucks. IDE's suck.

The job of a software developer is to solve problems where a computer be used to provide the solution. The solution almost always involves the internet and a little thing called HTTP. The goal is the solution, not the journey. The journey should be short, and never should the same path taken more than once.

Everything changes when you take one step back from the human as code-generator and apply your programming skill to solve the problem of having to generate a lot of boilerplate code. I did this at my current job. I saw that I basically did the same thing every time I wrote code to pull some rows out of a database, or update values in a database, or delete rows. So, I wrote a bunch of code that would generate the SQL on the fly and encapsulate all the database calling mechanisms. All it needed was a succinct definition of a database table to generate all that repetitive SQL and perform all the repetitive data munging.

That was a good step for me to take. It instantly made me a more efficient programmer than all my coworkers. There were some limitations to this meta-level programming. I had created a tool to create functionality quicker, but it had some warts. So, I wrote a better version of that code. It became a better tool for rapid development.

After some time, I realized that I was still doing double duty. I would write a database table definition for the database engine in SQL and then another definition in PHP that my other code would use to automate retrieving and storing data in the database. So, I wrote a piece of code that queries the database and generates the PHP table definition.

So when I write code, I can treat arbitrary rows in the database like native PHP objects. Of course, anyone using a framework like Rails or Django already does this, so it's nothing new, but it was for me.

So, back to NetBeans crashing. It crashed. I did a quick analysis in brain of what I got from the IDE in exchange for random instability, and the price was too high. IDE's help you generate code the slow way, by hand. IDE's constantly remind you about the names of classes and functions and help generate scaffolding that you can later populate with meaningful code. What a terrible waste.

I've decided to write as little code as possible from here on out. If I have to do anything more than once, I will generalize it. If some API is difficult and complex, and requires IDE hints to use properly, I don't want to program against it directly. I will wrap it up in a simple, memorable class that has the absolute simplest interface possible to solve the problem.

In the past couple weeks I've written code to make the creation of administrative interfaces with a few lines of declarative code. I wrote an HTML form class to encapsulate, standardize, and simplify form generation, validation, and security. I realized that rock-star coders like the people behind Rails and Django were just coders who didn't allow themselves to become code generators. Instead, they kept building higher and higher level abstractions until they were no longer repeating themselves. With Ruby on Rails, you can create a complete, functional web application by typing in a few lines in the terminal.

In this context, code becomes rarefied and powerful. It is no longer soupy gibberish or half-man, half-machine generated blub. So I don't need the IDE any more. I build abstractions that are easily understandable. I could go sit in the park and design code in a notebook, then go sit down and type it out, carefully, with unit tests and finish in a fraction of the time. Big, ugly languages like PHP, Java, C++ and C# coupled with big, gaudy IDE's do not encourage this style of development. Most of this realization came from spending about a month trying earnestly to learn Common LISP and then a couple weeks messing about with Django.

Kindle For PC Beta works on Linux
Posted by postfuturist on 2010-06-17 00:08:22
The latest versions of Kindle For PC don't run using Wine in Linux, but a few forum posts explain that the old beta does, so long as Wine is configured to run in Windows 98 mode. It took me awhile to track down a live link for the beta version, so I thought I would post it on my blog for future seekers. Download the Kindle For PC Beta here!
JavaScript Benchmark: Opera 10.60 vs. Google Chrome 5.0.375
Posted by postfuturist on 2010-06-14 14:49:09

I ran the SunSpider JavaScript benchmark of the latest Opera 10.60 64 bit Linux build from here. Apparently, the JavaScript engine not only rivals but looks to be a little faster than Chrome, at least for 64 bit Linux. The tests ran in 411 ms on Opera and 477 ms in Chrome.

TEST                   COMPARISON            FROM                 TO             DETAILS

=============================================================================

** TOTAL **:           1.16x as fast     477.2ms +/- 4.9%   411.2ms +/- 3.1%     significant

=============================================================================

  3d:                  1.57x as fast      86.0ms +/- 21.5%    54.8ms +/- 8.7%     significant
    cube:              2.06x as fast      31.8ms +/- 12.8%    15.4ms +/- 15.7%     significant
    morph:             1.58x as fast      31.2ms +/- 24.0%    19.8ms +/- 6.9%     significant
    raytrace:          -                  23.0ms +/- 35.2%    19.6ms +/- 24.0% 

  access:              *1.11x as slow*    47.2ms +/- 7.1%    52.6ms +/- 2.1%     significant
    binary-trees:      *2.36x as slow*     2.8ms +/- 19.9%     6.6ms +/- 21.5%     significant
    fannkuch:          *1.28x as slow*    18.4ms +/- 12.3%    23.6ms +/- 6.0%     significant
    nbody:             1.41x as fast      20.0ms +/- 6.2%    14.2ms +/- 19.0%     significant
    nsieve:            ??                  6.0ms +/- 41.4%     8.2ms +/- 29.2%     not conclusive: might be *1.37x as slow*

  bitops:              1.75x as fast      37.4ms +/- 9.6%    21.4ms +/- 9.7%     significant
    3bit-bits-in-byte: 2.20x as fast       4.4ms +/- 37.9%     2.0ms +/- 0.0%     significant
    bits-in-byte:      1.68x as fast       9.4ms +/- 24.0%     5.6ms +/- 19.9%     significant
    bitwise-and:       5.92x as fast      14.2ms +/- 13.0%     2.4ms +/- 28.4%     significant
    nsieve-bits:       ??                  9.4ms +/- 22.1%    11.4ms +/- 9.8%     not conclusive: might be *1.21x as slow*

  controlflow:         ??                  4.8ms +/- 33.8%     6.0ms +/- 14.7%     not conclusive: might be *1.25x as slow*
    recursive:         ??                  4.8ms +/- 33.8%     6.0ms +/- 14.7%     not conclusive: might be *1.25x as slow*

  crypto:              *1.15x as slow*    26.2ms +/- 10.3%    30.0ms +/- 11.7%     significant
    aes:               *1.28x as slow*    13.8ms +/- 11.7%    17.6ms +/- 14.6%     significant
    md5:               ??                  6.8ms +/- 43.7%     7.4ms +/- 19.2%     not conclusive: might be *1.09x as slow*
    sha1:              -                   5.6ms +/- 25.3%     5.0ms +/- 0.0% 

  date:                1.55x as fast      80.8ms +/- 6.4%    52.2ms +/- 12.2%     significant
    format-tofte:      -                  29.2ms +/- 16.6%    25.6ms +/- 14.4% 
    format-xparb:      1.94x as fast      51.6ms +/- 17.2%    26.6ms +/- 15.4%     significant

  math:                1.55x as fast      63.0ms +/- 8.3%    40.6ms +/- 4.1%     significant
    cordic:            2.19x as fast      22.8ms +/- 18.7%    10.4ms +/- 21.7%     significant
    partial-sums:      1.35x as fast      28.0ms +/- 9.4%    20.8ms +/- 13.0%     significant
    spectral-norm:     1.30x as fast      12.2ms +/- 19.6%     9.4ms +/- 11.8%     significant

  regexp:              *1.32x as slow*    14.2ms +/- 11.4%    18.8ms +/- 11.8%     significant
    dna:               *1.32x as slow*    14.2ms +/- 11.4%    18.8ms +/- 11.8%     significant

  string:              *1.15x as slow*   117.6ms +/- 4.6%   134.8ms +/- 2.0%     significant
    base64:            ??                 14.8ms +/- 16.2%    16.6ms +/- 10.0%     not conclusive: might be *1.12x as slow*
    fasta:             *1.15x as slow*    20.8ms +/- 9.8%    24.0ms +/- 8.2%     significant
    tagcloud:          *1.40x as slow*    27.6ms +/- 5.1%    38.6ms +/- 5.4%     significant
    unpack-code:       1.19x as fast      33.6ms +/- 5.0%    28.2ms +/- 3.7%     significant
    validate-input:    *1.32x as slow*    20.8ms +/- 10.7%    27.4ms +/- 4.1%     significant