Archive for the General Category

Session 3: Build In Enterprise, Ant, Maven, Dependency Management


  • Better builds with Maven has misled a lot of developers, it encouraged bad practice of using child modules. It was suggested that the book should be renamed to ‘Broken builds with Maven.’ There’s a new Maven book being written about using Maven the right way.
  • Good thing about Maven is that it encapsulates procedural steps in a declarative manner.
  • Teams that use Ant successfully tend to employ a certain level of standard and convention.
  • Easy Ant - Ant with standards.
  • If Ant works for you, there is no reason for adopting Maven.
  • It’s always easier to figure out a Maven POM rather than trying to understand an Ant build script.
  • Build is never easy, it looks easy, but it’s not.
  • You want everyone in your team to be able to modify code, but you don’t want everyone to modify build.
  • You shouldn’t avoid maintaining build script, the technical debt will be too much at the end.
  • The quality of artifacts available from Maven central repository can be improved by enforcing tests to be part of the development culture, a la Perl testing and CPAN.
  • Maven central repository needs to improve metadata quality, lots of broken POM.
  • There’s an opportunity for an open quality dashboard system in continuous integration marketplace.
  • How you build your product is often part of the audit process, specially when another company wants to acquire your product.
  • Sonar is handy to calculate your technical debt.
  • Crap4j measures code quality using an algorithm.
  • Avoid setting latest/SNAPSHOT as a dependency to avoid crap release creeping in to your build, use version or version range.

Session 4: Continuous Integration Tools

  • The pricing of CI tools can be roughly grouped into developer budget (i.e. free ones like Hudson, CruiseControl, Luntbuild, Buildbot), manager budget (i.e. not free but not expensive like Atlassian Bamboo), and director++ budget (e.g. Anthill Pro, IBM Rational BuildForge).
  • The price gap between manager budget and director budget is pretty wide, this is because you can’t sell moderately expensive software.
  • Interestingly, AnthillPro finds projects which already use Hudson to be a good starting point to migrate from.
  • Deployment should be scripted, use the same script for all environments, use the script as early as possible (in dev environment).
  • When you have any doubt about Hudson scalability, add more slaves.
  • You’ll be surprised at how there are still projects out there without any proper build script.
  • Git bisection is handy to identify point of failure and rollback.

Session 5: Continuous Deployment

  • IMVU deploys to production fifty times a day.
  • Flickr deploys 10+ times per day.
  • When you deploy to production on each commit, you care less about zero defect, but you care more about having really good tests. And if there’s a defect, you handle each defect exactly once by adding more tests around the defect.
  • Deploy on commit allows developer to concentrate on changes in small, more manageable, chunks.
  • Feature flags give you the opportunity to push bug fixes to production with half-baked new features disabled. You can then enable those features in the future when they’re ready.
  • Feature flag is also handy for doing A/B testing
  • Deploy straight to production requires more care when there are database changes involved, specially on backward patch.
  • Continuous deployment is not to be confused with cowboy development. Cowboy development is not about the frequency, but more on the lack of quality. Continuous deployment care about having good tests.
  • Large corporate culture of having management signing off every little change can be a blocker to employing continuous deployment. One solution to this is to have the management sign off the process, instead of the change itself.
  • Continuous deployment is not for all projects. It won’t work for legacy system lacking good tests. It won’t work for projects with large data that requires time-consuming post-deployment processing.
  • It’s questionable how well the concept of continuous deployment is going to work in finance industry where a single error can have a legal implication.

Day 2 ended with a retrospective session where many of us highlighted how well the open space format worked, and how good the quality of the discussions is. My favourite sessions were the ‘Evolution of Agile and Continuous Integration’ talk facilitated by Jeff, and ‘Continuous Deployment’ talk facilitated by Nigel McNie. I learned a great deal from those discussions, I had my a-ha moments, and there were a number of ideas I could pass on to others in my organisation/team.

I believe that the main reason why open space worked really well was the participants, everyone who was there, they were there because they cared, and somehow the level of passion was higher compared to other events I attended in the past. CITCON rocked!

Day 2 started at 9am with the early attendees ‘refactoring’ the talks to fit into the schedule, this involved spreading the most voted talks into larger rooms, combining talks around similar topics, and at the same time making sure that no facilitator ended up with multiple sessions running on the same time period. There were about 30 proposed talks with 20 time slots, 4 sessions running in parallel per time period.



Refactoring session.


It was raining all day, a typical Wellington weather I was told.

And here are some short notes from the sessions I attended:

Session 1: ATDD and BDD


  • A good way to make developers realise the value of BDD is by involving them in a project they’re not familiar with, that already have well defined tests/behaviours. Some open source projects can be a good example.
  • BDD can be seen as a subset of ATDD, ATDD involves implementing requirements into executables.
  • FitNesse works really well for some teams, others totally dislike it.
  • 100% control of large test data (e.g. in finance industry) is often not possible, specially when the data can’t be easily copied (e.g. due to legacy system restriction), or when there are multiple teams utilising the same set of data.
  • Some people strongly believe that web testing should be about testing the presentation layer only and hence can be made minimal, time is better spent on heavily testing the data/model. Others disagree and believe that a complete end to end web testing is always needed, nothing can replace humans.

Session 2: Evolution of Agile and Continuous Integration

  • Check out Rapid Development by Steve McConnell, published in 1996, you’ll soon realise that there are still many companies which development practices are only 15 years behind.
  • Pre & post chasm diagram, having started employing CI in 2002/3, did that make me an early adopter?
  • At the beginning, most people identified agile as XP “Yea, we do XP!” Now, most people are able to differentiate between Scrum and XP.
  • Use CI Maturity Model to identify where your organisation is at in terms of CI practices.
  • That maturity model is also an excellent resource to convince others in your organisation that some existing policies need to be updated to allow transition to the next level.
  • Back then, only developers adopted agile practices. By now, QA is already involved. Next up is operations and infrastructures. My personal take is that it will be 3-5 years from now.
  • Nowadays agile is _understood_ by development team and QA, the problem is with governance.
  • Jeff emphasized that the future will be in lean management. The key to lean is to reduce cycle time.
  • Sometimes a rubber chicken is all that’s needed to do continuous integration.
  • Would be nice to have a push-button deployment to production.
  • Someone from operations group must be brought into the team, be involved in the iterations/cycles/sprints, just like QA/testing is now.
  • Broken builds often get ignored, this is where team must figure out what works for them, whether it be lava lamps, flashing light, IRC notification, or other feedback mechanisms.
  • The main problem with CI in enterprise is when it gets centralized and development teams suddenly lose visibility. Instead of teams running their own CI tools (e.g. a build server under someone’s desk), it’s now the build engineers who control those tools and often restricting access.
  • When operations team is against the idea of transitioning CI to the next step, start with empathy and try to look at the situation from their point of view. Try showing them the business value behind the transition, involve someone from higher up in management.
  • The culture of an organization is often a blocker to further transition in the maturity model.
  • Know when to stop. When the culture resists further transition and you can’t change the culture, stop, you’re fighting a losing battle.

Continue reading CITCON Australia/New Zealand 2010 - Day 2 (Part 2).

I attended CITCON A/NZ 2010 in Wellington, New Zealand. CITCON is an unconference on Continuous Integration and Testing, it uses an open space format (which worked really really well), and CITCON rocked! (more about this later)




CITCON breaks Wellington :)

My flight arrived at 3.30pm, and day 1 activities started at 6.30pm. Paul Julius and Jeffrey Fredrick kicked-off the show by introducing what CITCON was about and how it was going to work, the rest was then up to us, the attendees.




PJ and Jeff.

The attendees then suggested the topics they would like to facilitate and voted on the ones they would like to attend. Given that it was my first open space conference, I wasn’t sure how open space could possibly work out. I read about how it’s _supposed_ to work, but I still wondered “really?”




I was introduced to the awesomeness of Sharpie.

The voting then continued during social hour at Foxglove. I had a chance to talk to Bruce Chapman who suggested an informal Hudson BOF session on the topic of the pain and pleasure of using Hudson plugins. In summary we agreed that Hudson core is solid, but there’s a need for better orchestration on those myriad of plugins, the question is who’s going to do it because clearly leaving it to the plugin maintainers haven’t really worked out (myself included, guilty).

Does a plugin need to have five features when most people only need one? Should a plugin do one thing only and leave it to the users to combine the plugins? There’s also clearly a need for better plugin information/metadata, it’s currently hard to find out which plugins to use if you need to do certain things. Perhaps a set of Hudson recipes need to be documented and shared on the wiki. Those were the questions and ideas that I would like to raise with others in Hudson community.

That’s it for day 1, we basically prepared the topics followed by some informal discussions over drinks.
Continue reading CITCON Australia/New Zealand 2010 - Day 2 (Part 1)

This is a short one, but we’ve had to do it a couple of times so I thought I’d put it up.

As you may be aware, Rails 2.2 introduced a new format for test names. Where you once might have had:

def test_should_do_stuff
  ...
end

You can now have:

test 'should do stuff' do
  ...
end

We’ve found this much easier to read and type - especially when your test names start to get big, or would be more readable if they contained characters that aren’t valid in Ruby method names.

However, if you’ve got lots of existing tests and want to shift them across to this format, it can be a pain to do it manually. Unless you’ve got a Ruby script, of course:

directory = 'unit'
Dir.mkdir("#{directory}.new")
Dir.new(directory).entries.each do |entry|
  original_filename = "#{directory}/#{entry}"
  File.open("#{directory}.new/#{entry}", 'w+') do |new_file|
    File.open(original_filename).readlines.each do |line|
      new_file.puts(line.gsub(/def test_*(.*)/) do |match|
          "test '#{$1.gsub('_', ' ')}' do"
        end)
    end
  end unless File.directory?(original_filename)
end

..which you’ll also find in this gist.

If you go into your ‘test’ folder and run this script, it’ll create a new directory called ‘unit.new’, that contains copies of all of your original unit tests, converted to the new format. Change ‘unit’ to ‘functional’, and it’ll do the same for your functional tests. Note that this will not do tests in subdirectories. YMMV. Feel free to steal and modify as you see fit.

I don’t understand why you’d use Interface Builder to create a UI for an iPhone application.

When I started building my first iPhone application at Shine, my colleagues advised me to avoid using Interface Builder. They’d tried using it when they were first starting out, but found that it just got in the way and made the learning curve steeper than it needed to be.

The problem for me was that many of the available books and tutorials for iPhone development used Interface Builder. Many of the sample apps on Apple’s site use it as well. I was having trouble figuring out how to not use it, so I took a deep breath and gave it a go.

I got confused pretty quickly. After thrashing around for a day or so, a colleague took pity on me and showed me how to bootstrap an iPhone user interface in code. I ditched Interface Builder and never looked back.

Sure, I probably would have figured it out, but why make life harder than it needs to be? As a new iPhone developer, I was already trying to get my head around Objective-C, Cocoa and XCode. Why add Interface Builder and NIB files to the list, for very little apparent benefit?

My Theory

Perhaps all the iPhone books and tutorials have been written by people who already had experience developing with Interface Builder and Nibs for Mac OS X.

Don’t get me wrong - I don’t have a problem with Interface Builder. It’s just that I wonder whether Interface Builder is more suited to it’s original purpose: building complex user interfaces that are to be used on a desktop computer.

iPhone applications, on the other hand, have a very limited set of widgets and layouts to choose from. Furthermore, there’s a limited amount of stuff you should put on a single screen.

Consequently it seems like overkill to crack out Interface Builder for an iPhone application.

More controversially, in my experience with GUI builders I’ve found that as soon as you try and build anything non-trivial, you’re going to have to code it by hand anyway. Furthermore, if an interface is so simple that you could build it with a GUI builder, I’ve found that it’s probably quicker to code it yourself. I’m not sure that Interface Builder is any exception to this observation.

To support these assertions, I’d like to point out that one of the more complex (and useful) sample iPhone applications that Apple provide - ‘TheElements‘ (which navigates the periodic table) - doesn’t use NIB files.

How to do it

So how does one bootstrap an iPhone interface without a NIB file? It turns out that it’s very easy to do, but there aren’t many examples out there on how to do it. So for the sake of knowledge-dissemination, here’s how you write a main.c that does it:

#import <UIKit/UIKit.h>

int main(int argc, char *argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, @"MyAppDelegate");
    [pool release];
    return retVal;
}

The key part is that you provide the name of the AppDelegate you want to use to the UIApplicationMain method, instead of leaving it as nil.

You’d then just code your AppDelegate to bootstrap the UI however you see fit:

#import "MyAppDelegate.h"

@implementation MyAppDelegate

- (void)applicationDidFinishLaunching:(UIApplication *)application {
	UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
	...
              Setup your controllers and views in here.
        ...
	[window addSubview:myViews];
	[window makeKeyAndVisible];
}

Finally, remove the property with the key ‘Main nib file base name’ (the raw key name is ‘NSMainNibFile’) from your Info.plist file.

What do you think?

Of course, as a newby to iPhone development, perhaps I’m missing something here.
If you’re new to iPhone development, have you found Interface Builder useful? If so, I’d like to hear about it. I can only speak from my own experiences (and those of my colleagues), so would be interested in hearing about the experiences of others.

A while back Mark expressed interest to me in using git and git-svn for version control on his own machine, against a remote Subversion repository. However, when I followed up with him recently, he admitted that in the small amount of time he’d spent looking at it, he hadn’t really got his head around how it was all going to hang together.

I can relate. I found Git to have a steep learning curve. It took me a while - and some assistance (thanks Tom) - to figure out the magical incantations to accomplish what I wanted. But now that I know them, I’ve found Git very useful for local version control.

I was going to walk Mark through my rough git-svn workflow, figuring it’d either get him started or scare him off for good ;) Then I decided I might as well share it with the world.

I’ve covered my motivations for using git for local version control in a previous post, so I won’t repeat them here. Nor am I going to provide a tutorial on git and git-svn - there’s plenty of those out there already. Instead, I’m going to run through an example taken from my day-to-day work to try and show how I use git and git-svn in real-life.

The Basics

  1. The first step is something I normally only do very occasionally: create a local Git clone of my remote Subversion repository. So say that I want to create a git clone of the ‘remote_maintenance’ project on the Shine Subversion repository:
    git svn clone svn+ssh://subversion.shinetech.com/home/svn/remote_maintenance/trunk remote_maintenance

    This checks out the contents of the ‘trunk’ branch into a local directory called ‘remote_maintenance’. This local checkout is known as a ‘working tree’.

    The most significant thing I can say about ‘git svn clone’ is that it will take a while if your SVN repository has a big history, as git will create an entire replica of this history. This might sound like a drag but can be very useful later if you’re working offline.

  2. Having cloned the repository, I merrily jump into the code in the working tree and start modifying, adding, deleting and moving files. Note that if I want to move a file and have git track a move, I use ‘git mv’. For example, to rename the ‘README’ file to ‘README.txt’, I’d do:
    bent:remote_maintenance bent$ git mv README README.txt

    I could just move it using ‘mv’, but git wouldn’t be able to track the change.

  3. When I’m curious to know what my changes to the working tree have been since my last commit, I use ‘git status’. For example, having renamed a file and added a new file, I’d get the following output:
    bent:remote_maintenance bent$ git status
    # On branch master
    # Changes to be committed:
    # (use “git reset HEAD …” to unstage)
    #
    # renamed: README -> README.txt
    #
    # Untracked files:
    # (use “git add …” to include in what will be committed)
    #
    # LICENCE.txt

    If I want to look at my changes in more detail, I run:

    git diff

    Which gives me a line-by-line diff.

  4. When I’m ready to commit my changes to git, I first run:
    git add .

    This will add any new files to the local index. I’ll cover what this means in more detail in the next step. After I’ve done run this command, running ‘git status’ again will yield the following:

    bent:remote_maintenance bent$ git status
    # On branch master
    # Changes to be committed:
    # (use “git reset HEAD …” to unstage)
    #
    # new file: LICENCE.txt
    # renamed: README -> README.txt
    #
  5. Next, I commit all my changes by running:
    git commit -a -m ‘Miscellaneous changes’

    The ‘-a’ means that git will automatically add any changed files to the local index before doing the commit. For git newbies, git differs from Subversion in that shepherding changes into a git repository is a two-stage process - first you add a changed file to a local index, then you commit the changes to the repository itself. ‘git commit -a’ is a convenient way of combining these two steps into one.

    Unfortunately, if I have added brand new files to my working tree, ‘git commit -a’ won’t pick them up. Thus the need to explicitly add them to the repository using ‘git add’ in the previous step.

  6. Having done my commit, I can return to step 2 and repeat as often as I want: make changes to my working tree, add them to the local index, and commit them.

Branching

  1. So what if I want to branch? Well firstly, let’s examine the history of my commits by using ‘git log’:
    bent:remote_maintenance bent$ git log
    commit 76b1ebf06586843e990a29423df39f2def2492b5
    Author: Ben Teese
    Date: Tue Jan 6 12:04:49 2009 +1100

    Miscellaneous changes

    commit 21873ad305a06b97504c0c2270549a9a20238596
    Author: Ben Teese
    Date: Wed Jan 7 16:09:34 2009 +1100

    Made it that ground server binds TCP server to provided IP address only, not all network interface

    commit 69b5b7421bc989538689711198510702f129d8f6
    Author: Ben Teese
    Date: Wed Jan 7 14:06:05 2009 +1100

    Made it that transfer service TCP server only binds to IP address provided. Added logging.

  2. To see what branches we’ve got at the moment, we use ‘git branch’:
    bent:remote_maintenance bent$ git branch
    * master

    We see that we currently only have one branch called ‘master’ - the default one that you get when you create a new repository.

  3. Say that I want to try an alternate approach to the change I just committed. To do that, I’d create a create a local branch from the previous commit and check it out. I can do this in one step using:
    git checkout -b new_branch 21873ad305a06b97504c0c2270549a9a20238596

    The long string is a SHA that represents the commit we want to branch from. There are other, shorter, ways to refer to commits, but I find it just as easy to copy the SHA from the output of ‘git log’ directly into the ‘git checkout’ command.

  4. Now let’s use ‘git branch’ to see what branches we’ve now got:
    bent:remote_maintenance bent$ git branch
    master
    * new_branch

    We see that out new branch appears and that it has an asterisk next to it. This means it is the currently checked-out branch.

  5. Now, if I do a ‘git log’:
    commit 21873ad305a06b97504c0c2270549a9a20238596
    Author: Ben Teese
    Date: Wed Jan 7 16:09:34 2009 +1100

    Made it that ground server binds TCP server to provided IP address only, not all network interface

    commit 69b5b7421bc989538689711198510702f129d8f6
    Author: Ben Teese
    Date: Wed Jan 7 14:06:05 2009 +1100

    Made it that transfer service TCP server only binds to IP address provided. Added logging.

    I see that my new branch only goes as far as the previous commit. You could now commit changes to this branch, and they wouldn’t appear in the ‘master’ branch.

  6. We’ll switch back to the ‘master’ branch to continue with this demo:
    bent:remote_maintenance bent$ git checkout master
    Switched to branch “master”

    Synchronizing with Subversion

  1. When I want to synchronize my local git branch with the remote Subversion repository, I run:
    git svn rebase

    It’ll spit out something like this:

    M test/unit/csdb_inventory_content_test.rb
    M test/unit/resource_entity_test.rb
    M test/unit/ground_server_test.rb
    r3743 = 64471395cf084217f7eab91e07abb03297492c83 (git-svn)
    M test/unit/csdb_inventory_content_test.rb
    M test/unit/resource_entity_test.rb
    M test/unit/ground_server_test.rb
    r3744 = 1828baa8e7b91cd8861dfaaecc26eb66b0f9264e (git-svn)
    First, rewinding head to replay your work on top of it…
    Applying: Made it that transfer service TCP server only binds to IP address provided. Added logging.
    Applying: Miscellaneous changes
    /Users/bent/NetBeansProjects/remote_maintenance/.git/rebase-apply/patch:31: trailing whitespace.

    A rebase temporarily winds back the commits that you’ve made on the branch since the last time you rebased, applies the commits from Subversion to the branch, then reapplies your commits to the branch. The great thing about this is that git-svn keeps track of the last rebase you did, so you never have to tell it that you only want to rebase from a particular point. This avoids some of the problems that Subversion has when you repeatedly merge from one branch to another.

  2. But what if somebody has changed a file that I’ve changed and we have a merge conflict? Git will report the problem as it is trying to reapply the local commits:
    Auto-merged test/unit/command/reader_test.rb
    CONFLICT (content): Merge conflict in test/unit/command/reader_test.rb
    Failed to merge in the changes.
    Patch failed at 0002.

    When you have resolved this problem run “git rebase –continue”.
    If you would prefer to skip this patch, instead run “git rebase –skip”.
    To restore the original branch and stop rebasing run “git rebase –abort”.

  3. To resolve the merge conflict, I open up test/unit/command/reader_test.rb, resolve the merge conflicts, then run:

    git add test/unit/command/reader_test.rb
  4. I repeat step the previous step for any other file that reported a conflict during the re-application of that particular commit. When I’m done, I run:
    git rebase –continue
  5. Additional merge conflicts may occur when git reapplies later commits, in which case I repeat steps 3 and 4.
  6. Now I have a look at my log on the current branch:
    bent:remote_maintenance bent$ git log
    commit 21873ad305a06b97504c0c2270549a9a20238596
    Author: Ben Teese
    Date: Wed Jan 7 16:09:34 2009 +1100

    Made it that ground server binds TCP server to provided IP address only, not all network interface

    commit 69b5b7421bc989538689711198510702f129d8f6
    Author: Ben Teese
    Date: Wed Jan 7 14:06:05 2009 +1100

    Made it that transfer service TCP server only binds to IP address provided. Added logging.

    commit 1828baa8e7b91cd8861dfaaecc26eb66b0f9264e
    Author: danielw
    Date: Tue Jan 6 22:13:34 2009 +0000

    converted the first letter of the test names to be lower case

    git-svn-id: svn+ssh://svn.shinetech.com/home/svn/remote_maintenance/trunk@3744 25b05753-7f2e-0410-

    We can see that the changes in my local git repository have been applied on top of the latest change from Subversion.

    Squashing Changes Together

  1. Now I want to squash together the first 2 of the changes I’ve made to my local git respository into a single commit. To do this, I run:
    bent:remote_maintenance bent$ git rebase -i git-svn

    My local terminal editor will appear with the following:

    pick 69b5b74 Made it that transfer service TCP server only binds to IP address provided. Added logging.
    pick 21873ad Made it that ground server binds TCP server to provided IP address only, not all network interfaces.
    pick 76b1ebf Added dvd stub that responds correctly to ProtocolRequest from iPhone.

    # Rebase 1828baa..76b1ebf onto 1828baa
    #
    # Commands:
    # p, pick = use commit
    # e, edit = use commit, but stop for amending
    # s, squash = use commit, but meld into previous commit
    #
    # If you remove a line here THAT COMMIT WILL BE LOST.
    # However, if you remove everything, the rebase will be aborted.
    #

  2. To squash the second commit into the first, I edit the text as follows:
    pick 69b5b74 Made it that transfer service TCP server only binds to IP address provided. Added logging.
    squash 21873ad Made it that ground server binds TCP server to provided IP address only, not all network interfaces.
    pick 76b1ebf Miscellaneous changes

    # Rebase 1828baa..76b1ebf onto 1828baa
    #
    # Commands:
    # p, pick = use commit
    # e, edit = use commit, but stop for amending
    # s, squash = use commit, but meld into previous commit
    #
    # If you remove a line here THAT COMMIT WILL BE LOST.
    # However, if you remove everything, the rebase will be aborted.
    #

    and save and exit the editor.

  3. git immediately pops up another editor that allows me to merge the comments for these two commits that I have said I want to squash together:
    # This is a combination of two commits.
    # The first commit’s message is:

    Made it that transfer service TCP server only binds to IP address provided. Added logging.

    # This is the 2nd commit message:

    Made it that ground server binds TCP server to provided IP address only, not all network interfaces.

    # Please enter the commit message for your changes. Lines starting
    # with ‘#’ will be ignored, and an empty message aborts the commit.
    #
    # Committer: Ben Teese
    #
    # Not currently on any branch.
    # Changes to be committed:
    # (use “git reset HEAD …” to unstage)
    #
    # new file: lib/dvd_stub.rb
    # modified: lib/ground_server.rb
    # modified: lib/rmu_stub.rb
    #

  4. Which I do accordingly:
    Made it that TCP servers only uses IP address provided. This ensures it only binds to the network inte
    rface of that IP address, not all network interfaces. Added logging.
    # Please enter the commit message for your changes. Lines starting
    # with ‘#’ will be ignored, and an empty message aborts the commit.
    #
    # Committer: Ben Teese
    #
    # Not currently on any branch.
    # Changes to be committed:
    # (use “git reset HEAD …” to unstage)
    #
    # new file: lib/dvd_stub.rb
    # modified: lib/ground_server.rb
    # modified: lib/rmu_stub.rb
    #

    and save and exit. Git will then squash the two commits together.

  5. If we do a ‘git log’, we see that git has merged the two commits into one, complete with a new message:
    bent:remote_maintenance bent$ git log
    commit 6a29acd801f280360699ac5278fcb63bb9c8744a
    Author: Ben Teese
    Date: Tue Jan 6 12:04:49 2009 +1100

    Miscellaneous changes

    commit 1fb107af4c765d2220d6674d61edca3fb13f5dc2
    Author: Ben Teese
    Date: Wed Jan 7 14:06:05 2009 +1100

    Made it that TCP servers only uses IP address provided. This ensures it only binds to the network

    commit 1828baa8e7b91cd8861dfaaecc26eb66b0f9264e
    Author: danielw
    Date: Tue Jan 6 22:13:34 2009 +0000

    converted the first letter of the test names to be lower case

    git-svn-id: svn+ssh://svn.shinetech.com/home/svn/remote_maintenance/trunk@3744 25b05753-7f2e-0410-

Commiting to Subversion

Having squashed some of our commits together, commiting to Subversion is relatively straightforward:

bent:remote_maintenance bent$ git svn dcommit
Committing to svn+ssh://svn.shinetech.com/home/svn/remote_maintenance/trunk …
A lib/dvd_stub.rb
M lib/ground_server.rb
M lib/rmu_stub.rb
Committed r3745
M lib/ground_server.rb
M lib/rmu_stub.rb
A lib/dvd_stub.rb
r3745 = fd5fbaf8ad9a71ad997f61e39fc2f3446c47b848 (git-svn)

This will create one commit in Subversion for each git commit.

Keeping Branches Synchronized

So what if you’ve made changes in one branch and you want to get them into another branch? The key piece of advice I can give is to use the Subversion repository as the transport mechanism. Once you’ve finished making changes in one branch, check them into the Subversion repository. Then switch to the other branch and rebase from the Subversion repository.

But what if you want to move code from one branch to another, without commiting to Subversion? Well, I have never done a direct git merge from one branch to another, and the ‘Caveats’ section of the git-svn man page recommends against it if you’re using git-svn. To be perfectly honest, it’s never been an issue for me. I tend to work on distinct features in separate branches so there is little code overlap. If there is some code overlap, I just have to fix the merge conflicts when I rebase from Subversion. However, given that I made both sets of changes, this usually isn’t too difficult.

Conclusion

From this demo you’ll see that my day-to-day usage of git and git-svn essentially boils down to 10 commands. I’ve listed them below, along with a quick summary of what they do:

  • git status :See an overview of the files I’ve changed
  • git diff: See a diff of the changes I’ve made
  • git add: Add new or merged files to the index.
  • git commit -a: Add changed files to the index and commit
  • git log: See the history of commits I’ve made.
  • git branch: See what branch is currently checked out.
  • git checkout -b: Checkout a new branch from a particular point.
  • git rebase -i: Squash together a bunch of git commits.
  • git svn rebase: Get the changes in the Subversion repository.
  • git svn dcommit: Send git commits to the Subversion repository.

Once I figured these out, I never looked back. I hope that you find them as useful as I did when using git for local version control with a remote Subversion repository.

The Problem

A while back we had a Flex client that needed to be able to display search results received from a server. The server was designed RESTfully, returning XML results to the client. The Flex client would display these results nicely to the user, and when the user clicked on a result, their browser would be directed to a HTML page for editing the actual item.

The problem was that, when a client clicked on a result, we were manually constructing the resource URLs in the Flex client from the IDs buried in the search results. The Flex code looked a bit like this:

navigateToURL(new URLRequest(’/item/’ + result.id +”/edit”),”_self”)

Furthermore, we had an impending need to support lots of different types of resources, so our logic for assembling URLs was about to become rather convoluted.

A Solution

Put the URLs into the search results. It’s blindingly simple (when you think about it, we do it all the time with pure HTML sites), but requires a subtle shift in mindset when you’re writing a fat client.

The solution was prompted by an article on REST Anti-Patterns I had read on InfoQ. - in particular, an anti-pattern called ‘Forgetting hypermedia’:

The first indicator of the “Forgetting hypermedia” anti-pattern is the absence of links in representations. There is often a recipe for constructing URIs on the client side, but the client never follows links because the server simply doesn’t send any.

It goes on to suggest that:

a client should have to know a single URI only; everything else…should be communicated via hypermedia, as links within resource representations.

You wouldn’t want to take this to an extreme, but it’s worth aiming for.

This approach helped simplify our code. We tweaked our server to write the resource URL into our XML, then had the Flex client simply navigate to the URL.

navigateToURL(new URLRequest(result.edit_path),”_self”)

Furthermore, this solution was somewhat polymorphic - a link to any sort of resource could be passed back and the client would always be able to navigate to it.

Caveats

The only catch was that we had to tweak the server to manually write the paths into the XML. As our server was a Rails app, we found it easiest to just add a ‘.xml.erb’ file to our views directory:

xml.results do
  @results.each do |result|
    xml.result do
      xml.tag! :name, result.name
      xml.tag! :description, result.description
      xml.tag! :edit_path, edit_polymorphic_path(result)
    end
  end
end

Note the use of edit_polymorphic_path to ensure that the path to any sort of resource can be written out.

My name is Mark. And I like rich clients.

There, I said it. I don’t like web applications. I never got Gmail as an interface. It never quite worked the way I wanted it to. I like eBay as a service, but not as an experience.

Over the last year I have found myself using NetNewsWire, not Google Reader.  I use OmniFocus, not RememberTheMilk.  I like having my data available everywhere, I just don’t want to use a browser to see or manipulate it.

I get that the interweb has allowed us to explore, connect and transact. Awesome. But now that we have the data and services the focus must shift to how we use it. The usability of most web applications is still well behind that of rich clients.  We need to get better.

So, we are faced with two alternatives. Try to make web applications better, or move to web enabled rich applications.

I favour the latter. Here’s why:

Rich clients work faster. Rich clients have tighter integration with the keyboard. You don’t need to be connected to the Internet all the time. Enough?

No! They also have tighter integration with the device they are running on. An iPhone application knows it has GPS and an accelerometer. It can do things you can’t do through a browser.

So let’s use the device well. Let’s optimise the experience for the device we are on. If we are on a mac I want Growl support. If we are on Windows then save data frequently.

But that is expensive to develop I hear you say. Yes. I didn’t say this would be cheap. However, in recent years we have gotten much better at building services faster (Spring: thank you.  Rails: thank you. SOAP: are you still here?).  So now that we have saved all that time on the back end, let’s spend a little more time on the front end.  

Please?!?

The following is a write-up of the highlights during the Sun Developer Day which I just attended. The early day kicked off with the usual registration and light refreshments before moving on to the ballroom for the opening keynote by Sun’s Director of Technology Outreach, Reginald Hutcherson.

The keynote addressed the possibilities of JavaFX in the non-PC arena such as televisions and mobile phones or according to Reginald, “any screen you will ever come across”. While it is a bold claim for a new technology in a world with existing competitors such as Flex, Silverlight, GWT …etc, it would be interesting to see how JavaFX performs in 2009. The keynote wrapped up with the advocacy of using open-source technology which was not surprising.

The demo shootout showcased the more interesting bits of the event. The first demo demonstrated the capabilities of JavaFX such as widget animation, a Flickr demo where click-able images are downloaded on the fly while floating across a canvas and finally, a video puzzle game with the video playing in the background. Performance was great and seamless considering the fact that they were all done on MacBook Pros. The next demo, showcased a compiz/beryl-like desktop for open Solaris and virtualization using VirtualBox which is now owned by Sun. Next up, is a quick 5 minute walkthrough of using NetBeans to produce a JavaFX app. This walkthrough shows off the tools within Netbeans such as drag and drop code generation and on the fly coding and previewing which is really impressive from a usability point of view. A feature which allows importing of Illustrator-created graphics was also mentioned, although it was never demonstrated.

The next bit discussed on the direction Java SE is heading and covered topics such as closure, Java Modules (JAM - JSR 277), and the usage of annotations in Swing, such as event handling…etc. While the morning covered the main highlights, the rest of the day was spent on code demonstrations on various topics such as REST, more JavaFX, SOA, MySQL, Dtrace and xVM (Virtual Box). Also, we got to see many of the features within Netbeans which were used during the demos. Sun is trying to market Netbeans to a wider range of developers (PHP, Ruby…etc.), which may be a challenge where there are many who have already got used to the Eclipse environment.

In general, the demos were well conducted and interesting. However, there were a few that were done in a hurry or needed more time for explanation as they were heavy topics (eg. SOA with OpenESB and Java CAPS). Unfortunately, there was not enough time for a Q&A session. Its understandable Q&As can potentially take up more time, but I’m sure there is always time for 1 or 2.

Personally, my main aim for attending the event was to learn more about JavaFX. I was impressed with what I saw and I appreciate the fact that Sun is stepping up their game in the IDE market. This is important, if they are to compete with the likes of Microsoft’s Visual Studio. However, one itching question remains. Is JavaFX able to compete with other web technologies in terms of performance on older hardware or will it be another slow Swing app?

Time to try Ganymede install again as the current version has got itself very confused! Install from scratch should take no more than 10-15mins (excluding any download times). This should give a good eclipse setup to do GWT and Maven work.

  • Ganymede - Latest Enterprise install eclipse-jee-ganymede-macosx-carbon.tar.gz
  • Sysdeo - I still use the old sysdeo plugin for basic tomcat running, used it for many years and its just easy. Installing 3.2.1 from sysdeo
  • Cypal - For GWT work, get the latest cypal plugin
  • Maven 2 - Update Manager new site, http://m2eclipse.sonatype.org/update/
  • Subclipse - Update Manager new site, http://subclipse.tigris.org/update_1.4.x