Not So Much

November 13, 2007

My Keynote/Subversion Solution

Filed under: groovy, keynote, mac, subverison — breidenr @ 8:50 pm

Having moved over to Macland earlier this year, I have been slowly adopting Mac applications. One app that I have become found of is Keynote. However, my one show stopper for moving all my presentations over to Keynote is the fact that it does not work well with Subversion. Specifically, because Keynote stores it’s files as a Mac bundle (a directory of files rather than one file) any .svn directories that exist within a bundle’s directory get blown away when you save a Keynote file.

This problem is not unique to me. I have seem numerous work arounds for this issue, none of which have satisfied me. The most common solution is to create an archive of the directory and check that into Subversion. I don’t like this for a few reasons:

  1. I prefer to commit many small files rather than one big file.
  2. Checking in one big binary reduces the chances that Subversion can commit a delta rather than an entire file.
  3. It just feels wrong!

So, like any good developer… I reinvented the wheel and wrote my own script. My approach was to create two directories - one working directory that I edit with Keynote and a versioned directory that I do not touch but commit to Subversion. My script (written in Groovy) syncs the changes from the working directory to the versioned directory, including Subversion adds (for new files) and Subversion deletes (for obsolete files).

I have only been using this script for a week or so, but I have been pleased. I am not sure that this approach is best, but I do like the fact that I can commit incrementally. If you also like this approach, feel free to use this code. And if you see any improvements (or fixes), please let me know.


workDir = new File(args[0])
svnDir = new File(args[1])

println "Syncing [$workDir.absolutePath] with [$svnDir.absolutePath]."

syncDeletions(workDir, svnDir)
syncAddsAndUpdates(workDir, svnDir)

void syncDeletions(workDir, svnDir)
{
    svnDir.eachFile { svnFile ->

        // skip Subversion meta directories
        if (svnFile.name == ".svn")
            return

        workFile = new File(workDir, svnFile.name)

        if (!workFile.exists())
            svn("delete $svnFile.path")
        else if (svnFile.isDirectory())
            syncDeletions(workFile, svnFile)
    }
}

void syncAddsAndUpdates(File workDir, File svnDir)
{
    workDir.eachFile { workFile ->
        if (!workFile.directory)
            addOrUpdateFile(workFile, svnDir)
        else {
            svnSubDir = new File(svnDir, workFile.name)
            if (svnSubDir.exists())
                syncAddsAndUpdates(workFile, svnSubDir)
            else {
                copyDir(workFile, svnDir)
                svn("add $svnDir.path")
            }
        }
    }
}

void addOrUpdateFile(File workFile, File svnDir)
{
    svnFile = new File(svnDir, workFile.name)
    boolean add = !svnFile.exists()
    copyFile(workFile, svnFile)
    if (add)
        svn("add $svnFile.path")
}

void copyDir(File workDir, File svnDir)
{
    svnDir.mkdir()
}

void copyFile(File workFile, File svnFile)
{
    reader = workFile.newReader()
    svnFile.withWriter { writer ->
        writer << reader
    }
    reader.close()
}

void svn(String command)
{
    command = "svn $command"
    p = "$command".execute()
    p.waitFor()
    if (p.exitValue())
        println "Failed to execute $command successfully."
}

August 21, 2007

TDD - Test Driven Design

Filed under: design, tech — breidenr @ 7:40 pm

A recent blog post on TDD has sparked an interesting discussion at TheServerSide. (Oddly enough, one of the voices of reason belongs to a JBosser. Historically, JBoss contributions to TSS have been fake posts, Spring bashing, or just general jerkiness.)

Anyway, the thread got me reflecting on how TDD has influenced me. Obviously, TDD changed the way I write code. As the premise of the original blog post states, TDD is an approach to developing software. So by definition, adopting TDD changed my development practices. But it goes deeper than simply writing my tests before my code.

TDD has greatly influenced how I design software. Hence, TDD carries a double meaning for me. Granted, the design I am seeing in the code I write with TDD isn’t revolutionary. I am applying tried-and-true OO design principles. But I think in the days prior to writing tests firsts, I made some assumptions about what my code should do. I would then base the initial design on these assumptions - which were often not true - only to discover the appropriate design later, after the code evolved.

With TDD, I can avoid these assumptions because they don’t exist. I know what my code should do because my tests tell me exactly that, no assumptions needed. And at least for me, this has lead to…

More immutable classes. Writing tests first puts the focus directly on the behavior of the class under test. So when this class is developed to satisfy the test, attributes are only added to hold state when needed. Additionally, getters/setters for these attributes are created on an as-needed basis as well. I am finding more and more that many of my class’s attributes can be set at construction time and remain immutable. And this immutability has benefits - less opportunity for an object to be in an invalid state, can be shared across objects/threads, etc.

And while this discovery could easily be made without TDD, having tests drive out implementations ensures no superfluous code. Don’t write that setter until you need it!

More cohesive classes. Typically, my class under test will depend on many of its collaborators through interfaces. These interfaces are then mocked in my unit tests. Whether I am rolling my own mocks (for simple cases) or using a framework like EasyMock, too much mocking becomes a code smell. If I find myself mocking several interfaces or mocking complex call paths, my class under test is probably violating the Single Responsibility Principle. This over-mocking is an alarm, alerting me it is time to refactor my design so that my class has a single, cohesive purpose.

The Law of Demeter being upheld. This is sort of a corollary to the previous point. In addition to creating mocks, I also find the need to stub out objects to use in the class under test (often with Object Mother). Typically, these objects are to be passed in as parameters to methods on the class I am testing. Like the over-mocking smell, there is also a code smell associated with over stubbing. When I find myself creating overly-complex objects to use as parameters, it is likely that my class under test knows too much about what is being passed in.

The Law of Demeter says that objects should only talk to their immediate friends. So if my class is poking around deep into another object’s hierarchy to do its job, then it knows too much. Much of the information it is searching for by poking and prodding should be attainable simply by asking. In other words, some responsibility needs to be moved from the class I am testing to elsewhere in the system.

Again, all of these design elements can be achieved without TDD. However, for me TDD helps me find (and fix) these design flaws faster. So, yes, TDD is most certainly an approach to developing software.

One that I don’t want to code without.

June 25, 2007

Another Mac convert

Filed under: mac, tech — breidenr @ 8:29 pm

So last week I started my new job at Semantra. As one of the nice perks, I received my new development machine - a 17″ MacBook Pro with 3G of RAM. Niiiiice.

Up until a couple of weeks ago, I was a 100% Windows user. Weeks before I switched jobs I was in the process of creating a dual-boot machine with XP and Ubuntu. Let’s just say that the conversion did not go smoothly. Linux still has a ways to go in the ease of use department.

Other than having witnessed the deluge of Mac commercials and drooling over some colleagues’ MacBooks, my Mac experience was nil. I didn’t know what I was missing. And let me tell you, I quickly discovered that I was missing a lot. (To be fair, I had a decent idea what I was missing, but the Mac cost was my main deterrent - I’m a cheap bastard).

The overarching theme over the last two weeks is that my Mac is pleasant to use. Part of that is it is just wicked fast, and the hardware has a lot to do with that. Also, I don’t have all of the crappy, corporate paranoia, Windowsy crap running - virus protection, file encryption, remote desktop management. But most of it is that the Mac experience is snappy, elegant and stable. And I haven’t found any incompatibilities (yet…).

I have had a few hiccups, most of which amounted to being new to the environment. I miss my Alt+ menu bar shortcuts, but QuickSilver is “quickly” easing that pain. I have a dual monitor set up at work, and it is annoying that I can’t duplicate the menu bar across both screens (since the application menu bars are attached there and not the application’s window - another minor annoyance). But those are small things that I am (usually) overcoming or just learning to live with.

Now if I can only get the company to spring for an iPhone…

Powered by WordPress