A journey to find those pieces of software or technology that facilitate productive and maintainable software development

Wednesday, March 24, 2010

Is this stupid? Drop Last Element of Erlang List

I wanted to drop the last element of a list. I didn't want a queue, I simply wanted to remove the last character of a string. Specifically I wanted to remove the \n from ref: refs/heads/master\n that comes back when reading the .git/HEAD file.

Code listing for trim.erl module:

-module(trim).

-export([string_strip_right/1, reverse_tl_reverse/1, bench/0]).

bench() -> [nbench(N) || N <- [1,1000,1000000]].

nbench(N) -> {N, bench(["a" || _ <- lists:seq(1,N)])}.

bench(String) ->
    {{string_strip_right,
    lists:sum([
        element(1, timer:tc(trim, string_strip_right, [String]))
        || _ <- lists:seq(1,1000)])},
    {reverse_tl_reverse,
    lists:sum([
        element(1, timer:tc(trim, reverse_tl_reverse, [String]))
        || _ <- lists:seq(1,1000)])}}.

string_strip_right(String) -> string:strip(String, right, $\n).

reverse_tl_reverse(String) ->
    lists:reverse(tl(lists:reverse(String))).

Benchmark transcript:

Erlang R13B04 (erts-5.7.5) [source] [64-bit] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.5  (abort with ^G)
1> trim:bench().
[{1,{{string_strip_right,11261},{reverse_tl_reverse,1000}}},
  {1000,
    {{string_strip_right,55131},{reverse_tl_reverse,17915}}},
  {1000000,
    {{string_strip_right,79881856},                                  
     {reverse_tl_reverse,119920353}}}]
2> 

GitX: a great product and one worth repeated donations

GitX is easily the best standalone Git user-interface I have used and I've been hunting around and comparing for over two years. I donated to GitX last year and the year before and I plan to do so again later this year as development continues. Pieter de Bie has built an unparalleled product for Git that truly embraces interaction design.

I don't really have much more to say than that GitX is a joy to use...

Check out GitX, it will be worth your while!

Saturday, October 24, 2009

Kudos to Dojo Campus

When I first got into using The Dojo Toolkit back in early 2007 it was at 0.4. The documentation was thin and tutorials were few and far between. Things have gotten unrecognizably better since then. Dojo Campus is my favorite example of the rapid evolution in serving developers new to The Dojo Toolkit.

With Dojo Campus as my guide I can rapidly learn about and apply dijits to spruce up the user interface. It has equally pragmatic articles for core modules like dojo.query as well. Its concise, example-driven style has made it my primary Dojo resource.

A side benefit for anyone comfortable with crafting their own URLs is that http://docs.dojocampus.org/ supports direct article access based on the fully qualified module name very nicely. For example, the documentation and usage examples for dijit.layout.TabContainer are accessible at http://docs.dojocampus.org/dijit/layout/TabContainer.

From its tutorials and videos to the extensive example-driven documentation Dojo Campus provides a polished user experience. I highly recommend it to anyone who wants to start using Dojo or simply wants to make more effective use of it.

Excellent work guys!

Saturday, October 3, 2009

Git Usability is On Par With Mercurial

In Five Features from Mercurial That Would Make Git Suck Less Geoffrey Grosenbach argues that Git is missing significant usability features that Mercurial has. I disagree on most points.

I must provide a few clarifications. I get that Git has a reputation for being arcane, but IMHO it is undeserved. You have valid points, but many of them are resolved in Git and the Git team is actively improving usability with every release.

An Intelligent Setup Command

How often does the average developer pre-create a repository with no content? I generally find myself creating a repository after I have a basic prototype or at least a basic project structure and directories on disk. I never create it beforehand.

However, this is a legitimate use case and one which – if sufficient demand exists – will be addressed.

In any case this is easily scripted and can even be added to the rails command so that your project gets a Git repository on creation.

Branches Everywhere

The Git example you give for deleting a branch is a valid way of deleting a branch in Git, but you can also do it easily as follows:

git branch -d feature_tweak

Deleting server branches (your demonstration) can be done with the somewhat arcane push nothing syntax git push origin :feature_tweak. I generally dislike the idea of deleting server branches and certainly of granting that privilege to anyone other than an administrator. I am glad the syntax is arcane, and I go even further on my Git servers by disallowing remote branch deletion entirely.

The increase in difficulty of git checkout -b feature_tweak over hg branch feature_tweak seems pretty minor to me. Committing changes is equally easy and pushing changes with git push origin is a minor usability difference and can be configured away.

Quick Local References

Here is where I stand firmly on Git’s side of this divide. I strongly disagree with the use of local revision numbers. Users coming from centralized SCMs will initially enjoy this feature and then become increasingly frustrated by it when they try to collaborate. Saying “Joe, the bug is in r3” is not going to work and providing it is an opening for wasting people’s time. In my experience, developers climatize to Git’s hashes fairly rapidly.

I’m going to go out on a limb and say that local ‘easy’ revision numbers aren’t even really useful to a sole developer. If you are tracking down a bug you are likely using a graphical historical analysis tool like gitk. That same tool lets you diff, checkout and otherwise work with that revision identifier without typing it (which is the only case where numeric revs seem useful to me).

Sensible Defaults

Reverting local changes is trivial with git checkout -f.

The lack of staging is a deal-breaker for me. In Mercurial I manually track the changes I make during a code review whereas Git tracks them for me because I staged the changes under review beforehand.

I agree with you on incremental commit. That strikes me as an extremely unwise feature.

Easy Serving

True on Windows. On any POSIX-compliant OS git daemon --base-path=. --export-all serves up all Git repositories in the directory over the Git protocol. This is a breath of fresh air compared to the infuriating leap I had to take to serve multiple Mercurial repos without resorting to a port per repo.

On Windows it takes about 5 minutes to set up Nginx and a post-update hook to run git update-server-info and serve over HTTP.

A server like Gitosis is a much better long-term solution than git-daemon. It integrates with your SSH server and is stupid simple to configure. I imagine equivalent servers exist for Mercurial now, but they certainly didn’t when I was using it.

Thursday, September 3, 2009

Subversion Hating on poking fun at Git

UPDATE: Ben doesn't hate Git, and his post is pretty damn funny

In iBanjo's Git article, Ben Collins-Sussman makes a funny, but revealing version of the Git documentation. It reveals a lack of understanding fed by dogmatic Git trolls. I love Git, but I certainly hope I don’t come across as a troll.

I am the Subversion administrator at work, but I personally use Git to collaborate with my peers without affecting our quality process or resorting to handing around patches. Surely I should use branches? I do, I simply do not trust Subversion to do merging correctly because it only recently added merge tracking. I’ve been using Subversion since its pre-1.0 days in 2002. Early on, Subversion also fundamentally stated that merge tracking was the user’s responsibility.

Every time we have used Subversion’s branches it has been a complicated ceremony full of fear and risk. I’d just frankly rather use something like Git for my day to day activities because it has treated branching and merging as fundamental use cases from the outset. Subversion does an acceptable job of backing our mainline, but it is beginning to look like more of a liability as our development team grows.

Git works quite nicely with Subversion. It is also significantly faster. Not 20-50% faster, buy tens to hundreds of times faster. While this isn’t a big deal for commits and updates it is a huge deal for forensics during bug fixing. Being able to search the entire history nearly instantaneously for any aspect of a commit is huge and Git provides a GUI for it. Having merges happen in seconds is powerful and changes the way developers work. Simply having working merge tracking is not enough to get developers using it, it needs to be fast and unobtrusive. Subversion does not deliver on speed.

This notion that Git is only for hardcore hackers is antiquated. Do you think GitHub would be anywhere near as successful if Git was actually hard to use?

Last year I scoffed at a new developer’s insistence that Git was an effective SCM. This year I have gained radical productivity advantages from using it. Take the time to read through Scott Chacon’s Pro Git and see whether or not it is a fit before dismissing it.

Monday, August 24, 2009

Concise HOWTO's: Message from Java to Erlang

First create an Erlang module called server that receives messages in the format {Sender,Data} and echoes the Data portion back to the Sender. Then create a Java class called EchoClient that prompts for a node to connect to and prompts in a loop for messages to send. You will need OtpErlang.jar in your build classpath and runtime classpath. I found it in /opt/local/lib/erlang/lib/jinterface-1.5.1/priv/ on Mac OS X. I had to install Erlang from source on Ubuntu since the APT package is missing Jinterface.

Listing of server.erl:

-module(server).
-compile(export_all).

start() -> register(server,spawn(fun loop/0)).
loop() ->
    receive
        {Sender,Data} ->
            Sender ! Data,
            loop();
        shutdown -> ok
    end.

Listing of EchoClient.java

import java.io.BufferedReader;
import java.io.InputStreamReader;

import com.ericsson.otp.erlang.*;

public class EchoClient {
    public static void main(String[] args) throws Exception {
        OtpNode node = new OtpNode("java");
        OtpMbox mbox = node.createMbox("admin_gui");
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String defaultServerNodeName = "erl_node@" + node.host();
        System.out.format("Server Node to contact [%s]> ", defaultServerNodeName);
        String serverNodeName = in.readLine();
        if (serverNodeName == null || "".equals(serverNodeName)) {
            serverNodeName = defaultServerNodeName;
        }
        OtpErlangTuple serverPidTuple = new OtpErlangTuple(new OtpErlangObject[] {
                new OtpErlangAtom("server"), new OtpErlangAtom(serverNodeName)});
        while (true) {
            if (!node.ping(serverNodeName, 1000)) {
                System.out.println("Erlang node is not available: " + serverNodeName);
                System.exit(1);
            }
            System.out.print("Message (Hit Enter to send)> ");
            String message = in.readLine();
            if (message != null) {
                mbox.send("server", serverNodeName, new OtpErlangTuple(
                        new OtpErlangObject[] {
                                mbox.self(), new OtpErlangList(message)}));
                OtpErlangObject serverReply = mbox.receive(1000);
                if (serverReply == null) {
                    System.out.println("WARN: Timeout when receiving reply");
                } else {
                    System.out.format("%s replied : %s%n", serverPidTuple, serverReply);
                }
            }
        }
    }
}

Open an Erlang shell in the directory with server.erl by running erl -sname erl_node. From that shell compile and run the Erlang server module.

Listing of the Erlang shell interaction

$> erl -sname erl_node
Erlang R13B01 (erts-5.7.2) [source] [64-bit] [smp:4:4] [rq:4] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.2  (abort with ^G)
(erl_node@alains_desktop)1> server:start().
true
(erl_node@alains_desktop)2> server ! {self(), hello}.
{<0.84.0>,hello}
(erl_node@alains_desktop)3> f(M), receive M -> {ok, M} after 100 -> {error,timeout} end.
{ok,hello}
(erl_node@alains_desktop)4>

Run the EchoClient Java program and either accept the default node or specify the name of another Erlang node you want to work with. Type messages in and see them echoed back to the EchoClient console.

Listing of the EchoClient Java program console interaction:

Server Node to contact [erl_node@alains_desktop]> [ENTER]
Message (Hit Enter to send)> Hello, Erlang![ENTER]
{server,erl_node@alains_desktop} replied : "Hello, Erlang!"
Message (Hit Enter to send)>

Concise HOWTOS: Install Erlang/OTP R13B01 from Source on Ubuntu 9.04

Generally it is better to use packages, so why have this HOWTO? Ubuntu 9.04's Erlang package is missing Jinterface, but it works when you build Erlang from source. Debian or Ubuntu will address this omission at some point. Until then we can build and install the latest Erlang release fairly easily.

The only real frustration in building from source is making sure all of the necessary build dependencies are installed first. Well, it also takes a significant chunk of time to build...

sudo apt-get install build-essential libncurses-dev \
                     unixodbc-dev libssl-dev \
                     libwxgtk2.8-dev default-jdk
curl http://erlang.org/download/otp_src_R13B01.tar.gz
tar xzvf otp_src_R13B01.tar.gz
cd otp_src_R13B01/
./configure
make
sudo make install

The make step takes a long time. It made me really appreciate the pre-built packages I can get so easily and quickly with APT.

SyntaxHighlighter