Unofficial Erlang Planet

November 18, 2008

20bits

Three Myths of Viral Growth

Myth 1: Viral Growth is Exponential Growth

Viral growth isn't exponential growth. Your web product has a maximum audience, for example, but an exponential curve grows forever. Instead viral growth follows a logistic curve.

The logistic curve comes from population biology where the growth of a population has an exponential component, e.g., humans on average have 2.1 children each, but is dampened by competition for resources. If the population is growing too fast eventually it reaches the limit where their environment can no longer support pure exponential growth.

This upper limit is called the carrying capacity.

Seth Godin misses this in his otherwise excellent Elephant Math essay. He equates "perfect viral growth" with exponential growth, but no viral growth is exponential. There are two variables at play: the rate of reproduction and the carrying capacity.

Sometimes the carrying capacity is obvious. If you're building a Facebook app the carrying capacity can't be any larger than the total size of Facebook, for example. Other times you don't know until you start feeling its effects.

This is what happens to every viral product, whether you like it or not. Viral growth slows and you have to worry about retaining users rather than acquiring new ones. If you don't your product runs the risk of jumping the shark.

And here's the kicker: the faster your app is growing the sooner you have to care about retention because you reach the carrying capacity much more quickly.

Myth 2: Viral Growth is a Marketing Buzzword

Viral growth isn't a marketing buzzword, although I won't say marketers don't occasionally misuse the word. It has the potential to happen any time you're in a situation where people can communicate.

In simple terms viral growth happens when a user comes across your product and recommends it to his friends. If the average user recommends the product to more than one person you get viral growth.

What most people don't understand is that viral growth is also a function of the viral substrate, or the underlying communication medium. The easier it is to communicate with other people the more likely something is to go viral.

With modern technologies like email, Facebook, SMS, etc., communication is virtually frictionless. I could send an email to 1,000 people right now if I wanted, or text ten of my best friends simultaneously. What's more, these channels are actually easier to measure than word-of-mouth recommendations.

Instead marketers use vague terms like "word of mouth marketing." But every step in the viral process can and should be measured, and you should use mathematical models (like the logistic growth curve, above) to understand what is really happening.

Myth 3: Viral Growth Can't be Engineered

Viral growth is one of many distribution strategies and that means it can be engineered. Innovation in distribution might be boring, but it makes the difference between a K-Mart and a Wal-Mart.

Innovation in viral distribution means building and optimizing a viral loop.

Here is an example, taken from KISSMetrics' Product Planner:

Invite Loop
View more Hug Me user flows.

Simply put, your viral loop is the series of steps a user goes through before he invites his friends. Each step in the loop costs you users. Perhaps only 10% of users click the "accept invitation" link, for example. The efficiency of the funnel is the percentage of users who make it all the way through the funnel.

One of fundamental equations of viral growth is

k = e\cdot i
where "e" is the efficiency of your loop and "i" is the average number of invites per user. k is the viral coefficient, or the average number of additional users each new user brings in. If k > 1 you get viral growth.

Phrasing it like this makes "getting viral" into an optimization problem, one that you can A/B test.

Measure, Test, Repeat

Viral growth can be measured, tested, and modeled. It's not a fuzzy marketing term. And if you can do it right you'll have yourself a difficult-to-top distribution channel for your next product.

by Jesse at November 18, 2008 10:16 PM

Joel Reymont

Liberate OpenPoker

There's a new widget in the sidebar of my blog. Let OpenPoker be reborn this Christmas!

Here's a follow up post that explains things a bit.

I'm collecting $65,000 to make OpenPoker v2, the latest and most scalable Erlang version, free forever. I will release the source code on Christmas eve if my donation target is reached and will give any money over the target to charity.

Once OpenPoker is liberated, I promise to

  • Not to sell poker software and continue working on the open source version.
  • Write another version in Ruby to show that it can scale just as well as Erlang.
  • Write an iPhone client.

Please donate and use the copy button in the widget to place it on your blog and spread the word! Alternatively, use this.

Update:

I forgot to answer the most important question: why do I need the money? I plan to use it for a startup, one I truly believe in, powered by Ruby, Erlang and Haskell. Follow me on Twitter and stay tuned.

If you have Flash blocked or have problems with the Chipin widget, please consider donating directly to joelr1 at pay pal dot com.

by Joel Reymont at November 18, 2008 01:26 PM

November 17, 2008

Joel Reymont

OpenPoker vs Zynga and PokerCreations: Let 1000 poker sites bloom!

I'm beat by Zynga and PokerCreations, I'm in the corner and on the ropes.

A good poker site needs a scalable server and a Flash client. Once I reach the donations target, I will release the source code to both the server and the Flash client that's currently in development.

There's nothing else to wish for so go ahead and visualize that MySpace or Facebook poker app this Christmas.

Please donate to make it happen and let a thousand poker sites bloom!

If you have Flash blocked or have problems with the Chipin widget, please consider donating directly to joelr1 at pay pal dot com.

by Joel Reymont at November 17, 2008 11:47 PM

Lookery Dev

Erlang Thoughts For Now

Well, we’re close to launching the thing I’ve been writing in Erlang, and I’m thus moving on to doing some work with Hadoop (my job rocks, is what I’m saying here ;-).

Few wrap-up thoughts as I go:

Overall, very happy with the experience.  If you’ve got interesting concurrency, distributed programming and/or high availability problems, I think Erlang is very, very much worth your time.  It makes things which are profoundly difficult in other languages surprisingly clean and easy.

Wondered if I would find the no-mutable-state thing an uncomfortable straitjacket, but I pretty much didn’t.  (I’m probably somewhat atypical, to be fair, since Lisp was a formative early language for me, and functional thinking has always felt pretty natural — but I do use mutable state in python all the time, quite happily).  If you need mutable state, you can get it by writing a little separate gen_server module, which is very easy to do (and then, by magic, you can start to take advantage of multiple cores more easily). Or you can use ets.

In this (and many other, important ways ;-), Erlang is nothing like Haskell, where you seem to need some kind of dispensation from the church to work with mutable state (if you want to hear Dan rant about Haskell, just say the word).

Overall, I think Erlang has two of the most important virtues a programming language can have: it feels simple, and it’s been used heavily in the real world.

Few specific hits and misses:

Hit: eunit.  I can’t say enough good stuff about eunit.  My learning arc was much like my learning arc with python — everything was easy to get started, and then I gradually realized there was tremendous power and flexibility under the hood.  Go ProcessOne guys, go.  And it’s also an excellent example of how you can write DSL-style code.  Just, really great stuff.

Miss: strings. Arg.  Lots of bits of my code have to obsessively check if they’ve been passed a binary or a list (= string), and if I forget to do that, it throws up all over the place.  This did not get less frustrating with time.

Hit: mochiweb.  Although there is, like, no documentation, it’s a very nice set of modules for building your own custom web server applications.  Which is what we were doing.

Minor Miss: the strange mix of line termination/separator syntax.  Thanks to emacs, this wasn’t too much of a pain, but it wasn’t great.  But pretty minor.

Slightly More Major Miss: the fact that you can’t call methods on objects.  As in, to look up a value in a proplist, you’ve got to call proplists:get_value(Key, Proplist).  Instead of, say, Proplist:get(Key).  It ends up being a lot of extra typing, you have to remember the argument order, and it makes it very hard to just swap in a new data structure.

Even More Major Miss: records. Man how they suck. If you could add a built-in functional mapping/dict type, with a literal syntax, it would be such a huge win.

Hit: OTP. Both the fairly comprehensive library (see real-world use above), and also the system for putting together applications.

Miss: lack of documentation on OTP in Joe Armstrong’s otherwise very solid book.  He walks you through setting up a basic OTP app in late chapters, but doesn’t touch on a lot of key facets of the whole powerful but somewhat forbiddingly complex system.  I’ve downloaded the OTP Design Principles docs, but it’s not always easy to figure out how people actually use those design principles.  E.g. do you really need separate boot files?  When?  What’s involved in rolling out a release?  How do I best manage / supervise apps on multiple nodes?  Etc.  Maybe I’ll learn more about all this as we deploy the system I’ve been writing, but I would sure be happier if Joe Armstrong had been able to write 2-4 chapters more on how to use OTP in the real world.

Hit: the Erlang Questions mailing list.  Lots of responsiveness from impressive Erlang guys, both within Ericsson and outside of it.  Feels like an early, small community, if that makes sense.  Love that feel.

Anyways, I’ll leave it there for now.  Had a great time so far, look forward to doing more.  If you have any specific questions, feel free to leave ‘em in the comments…

-Dan M

November 17, 2008 10:52 PM

Barking Iguana

Handling error feedback from Ajax requests to Rails applications

Ajax is frequently used to provide a richer user experience. Why then are important error messages rarely handled properly in Ajax enabled applications? Handling errors gracefully and in a way that helps the visitor to solve them adds a really high quality feel to your application. We've got all the necessary machinery, all it takes is a little care and attention.

class FoosController  ApplicationController
  def update
    @foo = Foo.find(params[:id])
    respond_to do |format|
      if @foo.save
        format.html do
          flash[:info] = "Your foo has been created."
          redirect_to @foo
        end
        format.js { head :ok }
      else
        format.html do
          flash.now[:warning] = "I could not update the foo."
          render :action => :edit
        end
        format.json do
          head :unprocessable_entity, :json => @foo.errors.to_json
        end
      end
    end
  end
end

Using the above code we get a lovely fallback HTML based behaviour and when we work with Ajax we get to use JSON behaviours. When JSON is requested and something goes wrong we get back an array of arrays that takes the following form.

[
  [ "attribute1", "error1", "error2" ],
  [ "attribute2", "error3"]
]

Just think of the awesome things you could do with such rich feedback...

new Ajax.Request('/foo.json', {
  method: 'PUT',
  parameters: {
    authenticity_token: window._token,
    "foo[subject]": $F('foo_subject'),
    "foo[body]"   : $F('foo_body')
  },
  onSuccess: function(transport) {
    // This is Web 2.0: celebrate with a yellow highlight.
  },
  onFailure: function(transport) {
    var errors = transport.responseJSON;
    errors.each(function(error) {
      var attribute = error.shift();
      var messages = error.join(", ");
      var errorMessage = attribute + " " + messages;
      var inputNode = $("foo_" + attribute);
      if(inputNode) {
        // Show that something is wrong with this field.
        inputNode.addClassName("error");
        // Do something better than an alert box. Alert boxes suck.
        alert(errorMessage);
      }
    });
  }
});

by Craig Webster at November 17, 2008 09:10 PM

November 15, 2008

Jan Lehnardt

CouchDBX Revival

couchdb-logo-128-cropped.png

Update 23/08/2008: Version 0.8.1 released[8.4 MB]. This fixes the test suite when using Safari. Beware however, if you are using the Safari 4 Developer Preview, you can run out of memory pretty quickly when running the test suite. This is a problem with Safari, not CouchDB.

All other notes still apply. CouchDBX is still Leopard-only and Intel-only.

Enjoy!

After quite a long hiatus, I released another version of CouchDBX. Do you remember? (Wow, hello dear long-time reader!). CouchDBX is my unofficial binary release of CouchDB for MacOS X that comes with a double-click-and-start wrapper application.

With no further ado:

CouchDB X 0.8-trunk Intel Only.

If you want to play with CouchDB on your Mac and you don’t want to mess with any command line installation business, this is for you. Just download the zipfile above, Safari should uncompress it for you, double click the application icon and you are ready to go.

CouchDBX has super simplistic GUI that lets you start and stop (yay) CouchDB and launch Futon, the admin client in your favourite browser. That’s it. CouchDBX is an independent installation, so you can use it even if you have a CouchDB installation on your system, both versions will not interfere (you just can’t run them in parallel).

cocuhdbx-0.8.0.png

Note that this is an unofficial release of a preview-piece of software. Things might break and not work as expected. Do not blame me. If you run into problems, please report them in the comments below, thanks.

This release only works on MacOS X 10.5 Leopard and on Intel Macs only. We want to have PPC support, and all there is to it is creating universal binaries of all executable files and libraries in the application bundle. If you can help with that, pelase get in touch.

If you want to help with the development, you can find the source at Google Code.

by Jan (jan@apache.org) at November 15, 2008 10:28 AM

Din Björn

Erlang User Conference 2008 in Stockholm

I visited this year's Erlang User Conference in Älvsjö, Stockholm, Sweden and was very impressed by the organizers, sponsors, speakers and the nice Swedish people in general.

Session I:

Francesco Cesarini on ProTest




Melinda Tóth (?) on automated syntax manipulation


Dr. Bjarne Däcker organized the conference and even shot photos


A lot of FUN: Prof. John Hughes uses the computer to come up with algebraic relations for pure functions and to test them




Session II:

Session II chairman Mickaël Rémond


The Erlang crowd


Michal Slaski on the Erlang Web framework


Bob Ippolito talks about his company and its use of Erlang


Garry Bulmer sells DTrace to the crowd


Mickaël Rémond wants to give out this year Erlang User of the Year award to Damien Katz of CouchDB, but Damien could not make it to the conference because of spawn(Fun)


Francesco will hand out the award gift in person to Damien when he visits the United States


Lunch break:

The crowd needs food and drinks


The klokhuset (clock house) of Ericsson in Älvsjö, where the EUC 2008 took place


Session III:
Dr. Kostis Sagonas starts warming up, later he was challenging the crowd to be as nitpicking as the dialyzer tool


Kostis is still answering questions while the next guys want to conquer the place


Hans Nilsson told war stories about parsing SIP and testing that parser


Anders Nygren wrangled with ABNF parsing in general


Session IV:

Vlad Dumitrescu on the ErlIDE, an Erlang IDE based on Eclipse


Jacob Cederlund demoed ErlIDE


(sells 'LISP-flavoured-Erlang 'Robert-Virding 'crowd)


The Erlang logo


Kenneth Lundin on SMP for Erlang


Kenneth on the upcoming Erlang releases


Conference end:
Lennart Öhman reminds the crowd of the helpers and sponsors of the conference


Lennart gives instructions for getting to the ErlLounge after the conference


The conference finished with an ErlLounge (food, drink & conversation), which was a great event - thanks a lot to the sponsors and organizers!

by Dein Bär (noreply@blogger.com) at November 15, 2008 02:35 AM

Joe Armstrong

Itching my programming nerve

Photo: oreillygmtI've just got back from the first ever commercial Erlang conference. Some 40 talks in two days all related in some way or other to Erlang. It was a chance to meet old friends, make new friends and connect people together in the hope that new synergy effects would arise.The most exciting thing was the emergence of what I think might be the first killer applications written in

by Joe Armstrong (noreply@blogger.com) at November 15, 2008 12:49 AM

November 14, 2008

Sudarshan Acharya

Erlang - overhyped or underestimated?

Erlang is like an exotic beautiful woman with no dressing sense. I came across Erlang about a year ago. It is a language of a kind - precise, crafted and powerful. Its been there for about two decades now, and people have been using it for serious real-time applications. But the ...

November 14, 2008 11:30 PM

Hypothetical Labs

Hack Night

We had another successful erlounge RDU Hack Night last night. Not quite as big a turn out as the inaugural Hack Night but still quite healthy with 7 brave souls in attendance.

I think everyone had a good time. There were lots of discussions and Erlang hackery going on. I’m really excited to see the level of interest and enthusiasm for Erlang in the group.

Our next meeting will be on 12/11 at Carrboro Creative Coworking.

by kevin at November 14, 2008 02:35 PM

Chris Anderson

My Couch or Yours? Shareable Apps Are The Future

I don’t have to tell you that in the long run, open source software beats closed source software, in any domain where the software is broadly useful, or in those domains where users are generally technical enough to hack their own gear. Proprietary web-servers and filesystems just can’t keep up with the free competition. As programming gets easier, the open-source advantage is moving up the stack. Microsoft burns out generations of programmers trying to keep up with Rails and Django, and they still don’t have the other advantages of freedom.

I also don’t have to tell you that web development is where all the new developers are cutting their teeth these days. Middle-schoolers the world over are learning to hack by hitting “view source” and having that a-ha moment when they realize those angle brackets correspond to the web apps they use everyday.

The road from kludging together HTML and stolen JavaScript to piloting high-level frameworks like Rails and Django is arduous and fraught with dead ends and distractions, but enough of us make it here to have created this vibrant community of enlightened hackers. We learn from each other’s code, but we still haven’t found a compelling way to share the whole stack. There are a few open-source web application success stories, like WordPress and Trac, but most of us work on applications that will die when the original business case goes away. We certainly haven’t seen an explosion of end-user friendly open-source web apps, to rival the proliferation of free development tools, frameworks, and even end-user software like browsers and media tools.

We Don’t Need No Affero

You only have to Google AGPL to get an idea of the tensions seething under the surface of the Free Software movement. The rub: companies have grown fat and happy using proprietary forks of open-source software to power web services. Because they aren’t distributing the software, just distributing the ability to use the software, they aren’t required to share their code under traditional licenses. It can be discouraging to pour energy in to free software, only to see big companies turn a handsome profit with it, and fail to contribute back to the community.

Some say the solution is to require source distribution to accompany usage distribution. I say the solution is to out-compete the applications that don’t distribute their source. If we build apps that derive a lot of value from the fact that they can run locally or over a network, and we provide an easy way for users to share the applications, I think we can give people a reason to prefer freedom over convenience. Once users expect the benefits that come from taking ownership of their data and their application code, they’ll look at closed-source web apps as dinosaurs.

CouchDB Rocks, Duh

I’m not saying it’s the only way, but I will say that CouchDB is uniquely positioned to open up this new space. The affordances it creates around sharing apps and data make the opportunity cost of not sharing your applications and data higher than the costs of doing so. If you’re interested in my thoughts about the technical ins and outs of shareable apps, I just posted today on the topic of peer-to-peer apps on the CouchDB mailing list.

Let’s Do It!

If you just want to get down and dirty, and have a copy of the latest CouchDB trunk, let’s install my CouchDB Twitter client. Once you’ve got CouchDB installed and running on your local machine, installing it should take about a minute.

Let’s do this step by step – with screenshots!

First, go to your local machine’s CouchDB futon and create a database.


Now go to the Replicator, where we’ll enter the information we need to copy the CouchDB Twitter Client from my public database.


The remote database is http://jchris.mfdz.com:5984/twitter-client-design (I created a special database with just the application code, because in this case the Twitter client tends to accumulate quite a lot of information over time.) There’s a sad bug that was introduced for a few revs of CouchDB’s trunk, having to do with URL escaping. It’s fixed now so if replicating doesn’t work, try running svn up and rebuilding before you retry replication.

Now you have the app! Lets use it. Go back to the “Overview” page (the one you started on) and click into the twitter-client db. Now choose “Design documents” from the drop down menu.


Now click the _design/twitter-client document, and you’ll be happy you did because boy is it awesome! All it takes to enter the application is to click index.html.


And this is what it should look like, only with your friends’ updates instead of mine. If you don’t have a Twitter account, there won’t be anything to see here. There’s also a strange failure mode for some users where it just seems totally broken. This might be due to too many Twitter API accesses, so if you’re gung-ho, try quitting your other Twitter clients and give it an hour or so. If it still doesn’t work, well, you’ve got the source code all in that design document!


Note that you can add standing searches to your timeline by click the star in the lower-left.

Enjoy!

November 14, 2008 01:54 AM

November 13, 2008

Me Dev, You Jane

Adding Erlang library locations

When adding Erlang libraries there are a few possible ways. The easy way is to add the libraries into the directory /usr/local/lib/erlang/lib. All directories there will be added to the library paths by default. The problem with that is that I don't like mixing 3rd party libraries with the core libraries.

Enter the ERL_LIBS environment variable. Set that to a directory and all the subdirectories of it that include code will the added automatically to the code path. To add it open up the file /etc/bashrc and add the following:

ERL_LIBS=/Library/Erlang/lib
if [ -d $HOME/Library/Erlang/lib ]; then
  ERL_LIBS=$HOME/Library/Erlang/lib:$ERL_LIBS
fi
export ERL_LIBS

This way all libraries under /Library/Erlang/lib and /Users/JoeUser/Library/Erlang/lib will be added to Erlangs code paths. The libraries will be in priority before the system libraries but after the -pa code paths. Now you can add things like Mochiweb, Eunit, Nitrogen and more under the /Library/Erlang/lib directory.

You could also put this in the file /usr/local/bin/erl

by Jon Gretar at November 13, 2008 07:36 PM

Hypothetical Labs

Speaking Schedule

I’ve got a few speaking dates coming up in 2009:

CodeMash 2009 Jan 7 - 9 Intro to Erlang
Ruby Rx Feb 19 - 21 Intro to Erlang, Intermediate Erlang
CVREG Mar 10 Introduction to Erlang
Infotec Apr 15 Erlang and Webapps: Oh My!

I’ve got the “Introduction to Erlang” talk down cold and feel pretty comfortable about giving it. I have a pretty good feel for the information most people want to hear when first encountering Erlang.

I’m less certain on what to cover for the “Intermediate Erlang” and “Erlang and Webapps” talks. It’s still early days for Erlang adoption. It’s important the talk is accessible and interesting for the audience even if they have minimal Erlang experience. How to strike the balance between the two is something I’m struggling with.

If anyone reading this has any input — either on topics you’d want to see covered, suggestions on how to keep the talk balanced, or approaches you’ve seen which didn’t work — I’d love to hear about them.

by kevin at November 13, 2008 02:42 PM

Yariv Sadan

Bay Area ACM Talk

Francesco Cesarini and I will be giving a talk about Erlang at the San Francisco Bay Area ACM chapter on Nov 19th. The full description is at sfbayacm.org. Please come by if you’re interested!

by Yariv at November 13, 2008 03:37 AM

Jan Lehnardt

Introducing DevHouseBerlin

I am very proud to announce DevHouseBerlin.

DevHouseBerlin: is a fun-packed weekend of hacking and sharing knowledge. We open the Box119 office for a weekend and invite hackers of all sorts to join us working on projects, sharing code and ideas and just hanging out among fellow geeks.

DevHouseBerlin runs on December 6th & 7th, 2008 and it is a free event. You can sign up on the wiki.

We are highly influenced by the SuperHappyDevHouse:

SuperHappyDevHouse is a non-exclusive event intended for creative and curious people interested in technology. We’re about knowledge sharing, technology exploration, and ad-hoc collaboration. Come to have fun, build things, learn things, and meet new people. It’s called hacker culture, and we’re here to encourage it.

Find out more about DevHouseBerlin.

by Jan (jan@apache.org) at November 13, 2008 12:26 AM

November 12, 2008

Mickaël Rémond

Sponsoring the 14th International Erlang User Conference

ProcessOne sponsors the Erlang User Conference in Stockholm (Sweden) that will take place on the 13th November 2008

For the first time this year, ProcessOne is one of the sponsors of the Erlang User Conference, a major event for the Erlang community.

The program is available from Erlang website: 14th International Erlang/OTP User Conference

I will be covering the conference live from Twitter. If you have a Twitter account, please follow me to get real time update about the conference.

by Mickaël Rémond at November 12, 2008 07:26 PM

Joe's blog

A Simple Concurrent Erlang TCP Server.

The last few days I have been playing with gen_tcp and writing a simple TCP server. I have found a number of resources helpful: gen_tcp, miniserv, 20bits and Programming Erlang. My server will run and display the data sent to it along with the client IP address and a timestamp. The server will also echo back whatever the client sent. It uses {active, once} for flow control as well. I just used telnet as my client. Pretty simple but a good exercise to see how this stuff works.

erl_tcp.erl

-module(erl_tcp).
-export([start_server/0, connect/1, recv_loop/1]).

-define(LISTEN_PORT, 9000).
-define(TCP_OPTS, [binary, {packet, raw}, {nodelay, true}, {reuseaddr, true}, {active, once}]).

start_server() ->
% start up the service and error out if we cannot
case gen_tcp:listen(?LISTEN_PORT, ?TCP_OPTS) of
{ok, Listen} -> spawn(?MODULE, connect, [Listen]),
io:format(”~p Server Started.~n”, [erlang:localtime()]);
Error ->
io:format(”Error: ~p~n”, [Error])
end.

connect(Listen) ->
{ok, Socket} = gen_tcp:accept(Listen),
inet:setopts(Socket, ?TCP_OPTS),
% kick off another process to handle connections concurrently
spawn(fun() -> connect(Listen) end),
recv_loop(Socket),
gen_tcp:close(Socket).

recv_loop(Socket) ->
% reset the socket for flow control
inet:setopts(Socket, [{active, once}]),
receive
% do something with the data you receive
{tcp, Socket, Data} ->
io:format(”~p ~p ~p~n”, [inet:peername(Socket), erlang:localtime(), Data]),
gen_tcp:send(Socket, “I Received ” ++ Data),
recv_loop(Socket);
% exit loop if the client disconnects
{tcp_closed, Socket} ->
io:format(”~p Client Disconnected.~n”, [erlang:localtime()])
end.

Hopefully all of that made some sense. Here is an example of usage, first starting the server and receiving a message.

[zeusfaber@der-dieb ebin]$ erl
Erlang (BEAM) emulator version 5.6.5 [source] [64-bit] [smp:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.6.5 (abort with ^G)
1> erl_tcp:start_server().
{{2008,11,12},{11,20,28}} Server Started.
ok
{ok,{{127,0,0,1},48940}} {{2008,11,12},{11,20,35}} "TEST123\r\n">>
2>

To send the message “TEST123″ I simply used telnet. Of course you could also write a client in Erlang to do the same.

[zeusfaber@der-dieb ~]$ telnet localhost 9000
Trying 127.0.0.1…
Connected to localhost.
Escape character is ‘^]’.
TEST123
I Received TEST123

by joe at November 12, 2008 05:26 PM

Hypothetical Labs

erlounge RDU Hack Night Tomorrow

A reminder that erlounge RDU’s monthly hack night is tomorrow night at Carrboro Creative Coworking starting around 7:00 PM.

A bunch of us are meeting at the Starbuck’s on Creedmoor Road at 5:30 to carpool to Carrboro so if you want to go but don’t want to drive all the way by yourself this might be an option for you.

I’m planning to grab a bite at Carrburritos around 6:00-ish. Anyone who’d like to join is welcome to hang out, enjoy a tasty burrito, and shoot the geekish breeze.

by kevin at November 12, 2008 02:28 PM

Joel Reymont

The OpenPoker scalability challenge

I spent the past few weeks slaving over a new version of OpenPoker and after a few rewrites I can safely say that this is the greatest and most scalable poker server ever!

How scalable? I don't know but you can tell me!

Grab the poker server binaries as well as the data files for the test harness and uncompress them into a directory.

Install Erlang/OTP R12B3 if you haven't already. R12B4 should work as well, although I haven't tested it.

Switch to the directory where you put the binaries and start by running everything on a single Erlang VM like this:

ulimit -n 100000
erl +K true +P 134217727 -sname 1 -s mnesia start -smp disable 

It doesn't matter what the VM is named and you don't have to disable SMP at all.

DO increase the number of available file descriptors A LOT! Every bot uses a socket, every player uses another one. Every running game gets an observer which uses another socket!

Type the following at the Erlang prompt

schema:install().
mb:run().
bb:run().

This will set up the database, run the game launcher and the bot runner. Wave your hands in the air, save a little prayer and type

dmb:test(1000).

This will launch 1000 poker games and start them once all the players have joined their respective games. All of the games will start at the same time!

Your output should look like this

mothership:openpoker_v2 joelr$ /db2/poker
Erlang (BEAM) emulator version 5.6.3 [source] [async-threads:0] [kernel-poll:true]

Eshell V5.6.3  (abort with ^G)
(1@mothership)1> bb:run().
{ok,<0.117.0>}
(1@mothership)2> mb:run().
'1@mothership': game server on port 3001
'1@mothership': port server on 3001...
ok
(1@mothership)3> dmb:test(1000).
gateway:start('1@mothership', 4000, 500000)
Waiting for game servers...
'1@mothership': port server on 4000...
Simulating gameplay with 1000 games...
50 games started, 262 players
...
1000 games started, 5066 players
dmb: 1000 games will be launching simultaneously
dmb: waiting for games to end...

barrier: reached target of 1000
50 games finished
...
1000 games finished
dmb: exited successfully, 207.306785 seconds elapsed
ok
(1@mothership)4> 

Ignore the Mnesia is overloaded warnings but make sure there are no player timeouts and all of the games finish successfully. Now you can get to the fun part and see how many games you can run simultaneously without player timeouts!

There are two ways to accomplish this and the simplest one goes like this

dmb:run(500, 5, 5, 5000). % 500 games, 5 game servers, 5 bot launchers

This will likely not work under Windows as it starts a bunch of Erlang slave nodes, 10 to be precise. Of these 5 will be used to launch games and 5 to run bots. You will also see statistics written to the terminal window every 5 seconds or so. 5000ms is the default so you can just drop this argument while keeping the first three.

Slaves use a RAM copy of the database tables and these arguments

common_args() ->
    "+K true -smp disable".

If everything goes well, your output should look like this

mothership:openpoker_v2 joelr$ /db2/poker
Erlang (BEAM) emulator version 5.6.3 [source] [async-threads:0] [kernel-poll:true]

Eshell V5.6.3  (abort with ^G)
(1@mothership)1> schema:install().

=INFO REPORT==== 30-Oct-2008::02:26:08 ===
    application: mnesia
    exited: stopped
    type: temporary
ok
(1@mothership)2> dmb:run(500, 5, 5).
game5@mothership: game server on port 3001
game5@mothership: port server on 3001...
...
game1@mothership: game server on port 3005
game1@mothership: port server on 3005...
cluster: [bot5@mothership,bot4@mothership,bot3@mothership,
          bot2@mothership,bot1@mothership,game5@mothership,
          game4@mothership,game3@mothership,game2@mothership,
          game1@mothership]
bot launchers  : [<7645.84.0>,<7644.79.0>,<7643.74.0>,<7642.69.0>,
                  <7641.63.0>]
game launchers : [<7640.548.0>,<7639.614.0>,<7638.536.0>,<7637.417.0>,
                  <7636.253.0>]
game servers   : [<7640.385.0>,<7639.451.0>,<7638.373.0>,<7637.254.0>,
                  <7636.90.0>]
gateway:start('1@mothership', 4000, 500000)
Waiting for game servers...
'1@mothership': port server on 4000...
Simulating gameplay with 500 games...
50 games started, 262 players
...
500 games started, 2562 players
dmb: 500 games will be launching simultaneously
dmb: waiting for games to end...

=INFO REPORT==== 30-Oct-2008::02:26:54 ===
    module: stats
    elapsed: 4.999982
    {total_bots_connected,0}: 602
    {bots_connected,0}: 602
    {games_launched,0}: 202
    ...
    {time_to_client,0}: 0.1876190042803583
    {time_to_server,0}: 0.4820268169244182

50 games finished
50 games finished

100 games finished
100 games finished

dmb: exited successfully, 71.21448699999999 seconds elapsed
dmb: exited successfully, 71.214702 seconds elapsed
dmb: exited successfully, 71.214737 seconds elapsed
dmb: exited successfully, 71.21477 seconds elapsed
dmb: exited successfully, 71.214803 seconds elapsed
ok
(1@mothership)3> 

Perhaps you are feeling lucky today, have a bunch of machines in a closet, or just want to run game servers and bot launchers with SMP enabled. Run as many nodes as you like and type

schema:install().

on your master node, then

mb:run(hostname).

on all the game server nodes and

bb:run().

on your bot runner nodes.

Hostname should be the fully qualified domain name and you should be able to connect to it outside of Erlang.

When you are done, come back to the master node and type

stats:start().
dmb:test(1000). % 1000 games, use 5000+ for maximum effect

Game servers and bot runners join their respective global groups and automatically join the cluster so long as you point them to the master node.

I use this shell script to launch my master node

#!/bin/bash

POKER=~/work/openpoker/
erl +K true +P 134217727 -pa $POKER/server/src -sname 1 -s mnesia start -smp disable $*

and this to launch other nodes (add -sname 2, 3, etc.)

#!/bin/bash

POKER=~/work/openpoker/
erl +K true +P 134217727 -pa $POKER/server/src -mnesia extra_db_nodes "['1@mothership']" -s mnesia start $*

That's it folks! Please let me know how far you go.

Feel free to join the OpenPoker Google group if you want to discuss this further.

Update:

The Erlang Questions thread can be found here. Also, it's R12B3 or R12B4, my bad!

I split the download into two parts. This is now part of the download instructions above. Also added link to the OpenPoker Google group.

You can also follow me on Twitter.

Update II:

Here are the results of testing on a 3Gb Joyent Accelerator running Solaris 5.11.

I'm launching 5000 games with 25000 players on 5 game servers and 5 bot nodes, all running on the same physical machine. I'm hitting the 65000 socket maximum so the way to scale out is by adding more physical servers to the cluster.

A starter gun fires when all the players join their respective tables. All games start at the same time and players act in rapid fire, with no delay between bet request and response. Think of it as a 25000 player tournament, running full-speed!

Poker barely consumes any CPU power so the way to scale with OpenPoker is to run a handful of cheap servers with 1-2Gb of memory.

(1@fhm8e4aa)1> schema:install().

=INFO REPORT==== 30-Oct-2008::20:49:19 ===
    application: mnesia
    exited: stopped
    type: temporary
ok
(1@fhm8e4aa)2> dmb:run(5000, 5, 5, 60000).
game5@fhm8e4aa: game server on port 3001
game5@fhm8e4aa: port server on 3001...
game4@fhm8e4aa: game server on port 3002
game4@fhm8e4aa: port server on 3002...
game3@fhm8e4aa: game server on port 3003
game3@fhm8e4aa: port server on 3003...
game2@fhm8e4aa: game server on port 3004
game2@fhm8e4aa: port server on 3004...
game1@fhm8e4aa: game server on port 3005
game1@fhm8e4aa: port server on 3005...
cluster: [bot5@fhm8e4aa,bot4@fhm8e4aa,bot3@fhm8e4aa,bot2@fhm8e4aa,
          bot1@fhm8e4aa,game5@fhm8e4aa,game4@fhm8e4aa,game3@fhm8e4aa,
          game2@fhm8e4aa,game1@fhm8e4aa]
bot launchers  : [<7615.83.0>,<7614.78.0>,<7613.73.0>,<7612.68.0>,<7611.62.0>]
game launchers : [<8822.485.0>,<8820.498.0>,<7610.582.0>,<7609.416.0>,
                  <7608.252.0>]
game servers   : [<8822.322.0>,<8820.335.0>,<7610.419.0>,<7609.253.0>,
                  <7608.89.0>]
gateway:start('1@fhm8e4aa', 4000, 500000)
Waiting for game servers...
'1@fhm8e4aa': port server on 4000...
Simulating gameplay with 5000 games...
50 games started, 262 players
...
5000 games started, 25404 players
dmb: 5000 games will be launching simultaneously
dmb: waiting for games to end...

=INFO REPORT==== 30-Oct-2008::20:50:59 ===
    module: stats
    elapsed: 60.003419
    {total_bots_connected,0}: 8904
    {bots_connected,0}: 8904
    {games_launched,0}: 1820

=INFO REPORT==== 30-Oct-2008::20:51:59 ===
    module: stats
    elapsed: 59.99997
    {total_bots_connected,1}: 17961
    {bots_connected,1}: 9057
    {games_launched,1}: 1811

=INFO REPORT==== 30-Oct-2008::20:52:59 ===
    module: stats
    elapsed: 60.000001
    {total_bots_connected,2}: 24494
    {bots_connected,2}: 6533
    {games_launched,2}: 1198

barrier: reached target of 5000
50 games finished
50 games finished

=INFO REPORT==== 30-Oct-2008::20:53:59 ===
    module: stats
    elapsed: 59.996606
    {total_bots_connected,3}: 25404
    {total_bots_disconnected,3}: 742
    {total_games_ended,3}: 188
    {total_games_started,3}: 5000

50 games finished
...
1000 games finished
dmb: exited successfully, 269.970918 seconds elapsed
dmb: exited successfully, 269.971041 seconds elapsed
dmb: exited successfully, 269.97109 seconds elapsed
dmb: exited successfully, 269.971134 seconds elapsed
dmb: exited successfully, 269.971178 seconds elapsed
ok
(1@fhm8e4aa)3> 
=INFO REPORT==== 30-Oct-2008::20:54:59 ===
    module: stats
    elapsed: 60.000917
    {total_bots_connected,4}: 25404
    {total_bots_disconnected,4}: 30404
    {total_games_ended,4}: 5000
    {total_games_started,4}: 5000

by Joel Reymont at November 12, 2008 05:23 AM

November 11, 2008

Erlang Training and Consulting

Announcing our Training Schedule for 2009!

As a very busy and successful year with lots of scheduled courses draws to a close, we can now confirm our Training Schedule for 2009.

Next year we will be offering courses in Dubai and Singapore in addition to our usual ones in UK, Sweden, Poland, USA and South Africa. For details, please see our Training Schedule.

by Erlang Training and Consulting at November 11, 2008 11:59 PM

November 10, 2008

Hypothetical Labs

EUnit Confusion

One thing I see developers new to Erlang and EUnit perpetually bang their toes on is the different ways one can write unit tests using EUnit. EUnit comes with two styles of macros. I like to think of the styles as immediate and generators. The immediate macros are ones without a leading underscore such as ?assertEqual.

This style of macro expands into code which is immediately executed. For example, the macro ?assertEqual(3, do_something()) translates into code which looks something like this:

case do_something() of
  3 ->
    ok;
  _ ->
    throw(assert_error)
end

I’m pretty sure this isn’t exactly the code the macro expands into but it should be close enough to illustrate my point. Immediate style macros are executed immediately. Put another way, immediate macros are executed at their location within the code.

Generator style macros, on the other hand, generate functions which are executed when the unit test is executed. In functional programming terms, generator macros act as a kind of higher order function.

The generator equivalent of the previous example is ?_assertEqual(3, do_something()). It expands into code which might look like this:

fun() ->
  case do_something() of
    3 ->
      ok;
    _ ->
      throw(assert_error)
  end
end.

Execution of the assertion logic is delayed until the surrounding function is called. You can use the generator macros to build lists of EUnit tests in a few lines of code:

[?_assertEqual(3, do_something()),
 ?_assertEqual(4, do_something_else()),
 ?_assertEqual(0, do_nothing()]

A good rule of thumb to follow is to use the immediate macros when you’re writing your own test functions:

my_test() ->
  ?assertEqual(3, do_something()).

Use the generator macros when you’re generating lists of tests for EUnit to execute. Remember your generator function, if you’re writing one, must end in an underscore. EUnit uses the naming convention to tell the difference between immediate and generator-style tests.

my_test_() ->
  [?_assertEqual(3, do_something()),
   ?_assertEqual(4, do_something_else()),
   ?_assertEqual(0, do_nothing()].

The EUnit docs do a good job of describing how all of this works in some detail. I recommend giving them a good read if you plan on using EUnit.

by kevin at November 10, 2008 02:44 PM

Debasish Ghosh

Design Patterns - The Cult to Blame ?

I always thought GOF Design Patterns book achieved it's objective to make us better C++/Java programmers. It taught us how to design polymorphic class hierarchies alongside encouraging delegation over inheritance. In an object oriented language like Java or C++, which does not offer first class higher order functions or closures, the GOF patterns taught us how to implement patterns like Command, Strategy and State through properly encapsulated class structures that would decouple the theme from the context. As long as we do not link them with the pattern definition and theory as espoused by Christopher Alexander, the GOF book has an invaluable contribution towards today's mainstream OO community.

But that's only the good part. I was wondering what made many people cringe at the patterns movement that seem to deluge the programming community for well over a decade.

One of the drawbacks that the pattern movement in the programming community suffered from, was that, the design patterns as promoted by the GOF book, focused too much on the implementation aspects, the how part of the solution, instead of the what part of problem that they solve. This resulted in the implementation language being the main focus of the entire pattern. People started thinking that C++ is the language of choice since all of the GOF design patterns can be implemented faithfully using the honored constructs of the language. And, of course, in due time, Java, positioned as a better C++, also inherited the same honor. It may not be totally coincidental that during the time we were busy adulating the virtues of GOF design patterns in Java and C++, development of newer programming languages were at a very low ebb.

Developers started thinking that Java and C++ are the be-all and end-all of programming language implementations, since we can implement all GOF patterns in them. Enterprise software loves to follow common practices, rote techniques that can be easily replicated through a set of replacable programmers, and the combination of Java and design patterns made a perfect match. Switching languages was difficult, and even for some mainstream programmers today, switching to more powerful languages like Ruby or Scala, the initial thought processes were limited to the abstraction levels of Java. In reality, the patterns movement created a cult and made us somewhat myopic towards implementing higher order abstractions even in any other more powerful programming language.

Mark Jason Dominus reiterated this way back in 2006 ..

"If the Design Patterns movement had been popular in the 1980's, we wouldn't even have C++ or Java; we would still be implementing Object Oriented Classes in C with structs, and the argument would go that since programmers were forced to use C anyway, we should at least help them as much as possible."

Are Design Patterns useless ?

Absolutely not. Patterns are solutions to problems in context. As long as the problems remain, patterns remain equally relevant. What we need to do is highlight on the intent of the pattern, the problem that it solves, the forces that it resolves and the resultant forces that it generates, instead of just documenting how it solves it in one particular language.

As an example, the Strategy pattern is intended to decouple the implementation of an algorithm from the context of the application. In case of Java, it is implemented through the context class delegating the responsibility to the strategy interface, that can have multiple implementations. Looks and sounds ceremonious, but that is what it is, if you use Java as the implementation language. In languages that support higher order functions, the same pattern is implemented much more succinctly using native language features. Hence the implementation is subsumed into the natural idioms of the language itself. Again, if we highlight on the intent of the pattern, it remains *equally relevant*, irrespective of whether we use Ruby, Groovy, Scala or Lisp for implementation. And the intent is loud and clear - the implementation of the algorithm is a separate concern than the concrete context to which it is being plugged into.

Similarly, the Visitor pattern has often been maligned as an overtly complex structure that should be avoided at any cost. Visitor looks complex in Java or C++, because these languages do not support higher order abstractions like pattern matching or multiple dispatch mechanisms. Languages like Scala that support pattern matching have been known to implement succinct visitors without much ceremony. This paper, presented in OOPSLA 2008, implements the Visitor pattern as a reusable generic type-safe component using the powerful typesystem of Scala.

Irrespective of how you implement, Visitor remains a potent solution to the problem of separating the structure of abstraction hierarchies from the behavior of traversals over that hierarchy. The important part is to add the intent of Visitors to your design vocabulary - it is just the level of abstractions that the language offers that makes the implementation invisible, informal or formal.

Many people also talk about Singleton implementation in Java as being too elaborate, complex and unnecessarily verbose. On the other hand, singleton is available as a library call in Ruby and as a single word language syntax in Scala. That does not make Singleton a simpleton, it is just that Java does not offer a sufficiently higher level of abstraction to express the intent and solution of the pattern. Go, use dependency injection frameworks, they offer Singletons as configurable behaviors ready-to-be-wired with your native objects.

Patterns as a vehicle of communication

.. and not as code snippets that can be copy pasted. The real intrinsic value of design patterns is that they facilitate communication in processes by encouraging a common vocabulary and format that binds the design space. Coplien mentions in his monograph on Software Patterns ..

"Besides, we believe that human communication is the bottleneck in software development. If the pattern literary form can help programmers communicate with their clients, their customers, and with each other, they help fill a crucial need of contemporary software development.

Patterns are not a complete design method; they capture important practices of existing methods and practices uncodified by conventional methods. They are not a CASE tool. They focus more on the human activities of design than on transformations that can blindly be automated. They are not artificial intelligence; they celebrate and encourage the human intelligence that separates people from computers."


People, mostly from the dynamic language community, frown upon design patterns as being too ceremonious, claiming that most of them can be implemented in dynamically typed and functional languages much more easily. Very true, but that does not undermine the core value proposition of design patterns. Maybe most of us became converts to a cult that focused too much on the implementation details of the patterns in a specific family of languages. Ideally we should have been more careful towards documenting beautiful patterns and pattern languages as the core vocabulary of designers.

Some people on the Erlang mailing list recently talked about OTP being the embodiment of Erlang design patterns. OTP is clearly a framework, that helps develop highly concurrent client server applications in Erlang. Patrick Logan correctly points out that OTP is a collection of patterns, only in a very poor sense of the term. The real collection would be a pattern language that documents the problems, identifies the forces at play and suggests solutions through a catalog of literary forms that will help develop concurrent server applications from ground up. In case of Erlang, gen_server, gen_event, gen_fsm etc. collaborate towards implementing the pattern language. Similar efforts have been known to exist for Scala as well. Implementing the same in any other language may be difficult, but that will only point to the deficiencies of that particular language towards implementing a concrete instance of that pattern language.

by Debasish (noreply@blogger.com) at November 10, 2008 01:43 PM

November 09, 2008

Jan Lehnardt

News at Couch – November 2008

couchdb-logo-128-cropped.pngWelcome to another installment of News at Couch, our review of what’s new with, on and around CouchDB.


What’s the most interesting new idea you’ve seen in the field of web development in the past year?

New database architectures: CouchDB and friends.

Tim Bray


Kore Nordmann looks at how to model users, groups and permissions with CouchDB.

Back in August, yours truly presented CouchDB at the BBC. They shot a video.

Chris tries to do Wide Finder in CouchDB.

Amazing Aimee has a seven part series on CouchDB with Rails: One, two, three, four, five, six, seven. Wow. Thanks Aimee!

Domingo looks at couchdb-python’s new attachment support contributed by (again) by yours truly.

Ben Atkin uses CouchDB from FireBug, way cool!

Use CouchDB with ejabberd, by cstar.

Mikeal Rogers releases pouch, a lightweigh CouchDB library for Python, aptly named by Aza Raskin(!).

Scott Leberknight writes about Polyglot Persistence.

Ricky Ho of Adobe takes a closer look at CouchDB’s internals.

Volker got a nice review for his CouchDB talk at BarCampBerlin a few weeks ago. I was there, it was pretty good!

Michael Stillwell of iBuildings reviews my presentation about CouchDB and explains CouchDB and MapReduce in one go!

How to use ActiveCouch with Rails by Arun Thampi

Alex unveils CouchPotato, ActiveCouch’s arch rival with some pretty nifty Rails plugins already built in (acts_as versioned e.g.).

My friend Volker released GeoCouch a Geo Spatial indexer for CouchDB. Woot!

The Book of course :-)

Chris blogs about using CouchDB as an app-server with p2p semantics. Me want!

Chris also did a tech-talk on CouchDB in New York. They taped it!

Ok, this is a big one, Carlos puts a few Wikipedia languages into CouchDB (120 GB in total) and puts a minimalist jQuery-powered interface on top for translations and calls it “Lots of Words”. Neat!

by Jan (jan@apache.org) at November 09, 2008 10:54 PM

Damien Katz

News at Couch

Welcome to another installment of News at Couch, our review of what's new with, on and around CouchDB.
News at Couch - November 2008

by Damien Katz at November 09, 2008 06:19 PM

November 07, 2008

Hypothetical Labs

“Must have 8+ years of Java”

From a recent job posting for a Seattle-based Erlang position:

“We are looking for 2-3 Erlang developers with 3-5 years experience with Erlang development for a short term engagement (4-6 months).

Required Skills: Erlang/OTP, Mnesia,Yaws, MochiWeb, EUnit. Test-Driven Development experience (Unit/Integration/System). Strong verbal and written communication skills. ”

Yeah. Good luck with that. Functional programming, and Erlang in particular, has been mainstream here in the States for a long time so you shouldn’t have any trouble finding candidates with the requisite experience. Yeah, riiiight.

Reminds of me of recruitment ads requiring 6-8 years of Java experience when JDK 1.0 was released.

by kevin at November 07, 2008 03:48 PM

Barking Iguana

Content_for is the new GOTO

I don't like content_for. Your view code jumps around up and down files and makes it hard to work out what's going on. It smells a lot like GOTO. When was the last time you saw someone recommend you use a GOTO?

content_for :javascript and content_for :css

Use of content_for can be easily avoided, at least for including CSS and Javascript files. Include the controller name and action name in the body tag in your layout and properly qualify your CSS declarations.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title><%= page_title %></title>
  <meta http-equiv="Content-Language" content="English" />
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <link rel="stylesheet" type="text/css" href="/stylesheets/simple.css" media="screen" />
</head>
<body id="<%= "#{controller.controller_name.tableize.singularize}_#{controller.action_name}" %> class="<%= "#{controller.controller_name.tableize.singularize} #{controller.action_name}" %>">
  <%= yield %>
</body>
</html>

Say you were looking at the Posts views in your app, you can now style these using something like this.

.post.index .article .title { 
  font-size: 1.25em;
}

.post.show .article .title { 
  font-size: 0.9em;
}

Or, in case you need to support browsers that don't let you specify two classes as a selector for a single element, you can write it like this.

#post_index .article .title { 
  font-size: 1.25em;
}

#post_show .article .title { 
  font-size: 0.9em;
}

Since all your Javascript is unobtrusive anyway (right?), it should be pretty easy to qualify the selectors used there with the same CSS selectors shown above.

As an added bonus, by specifying your Javascript / CSS like the above you can package it all in one Javascript or CSS file on deployment to your production environment and save yourself a bunch of HTTP requests.

by Craig Webster at November 07, 2008 09:44 AM

Joel Reymont

November 06, 2008

Hypothetical Labs

eunit installation bug in R12B-5

If you downloaded R12B-5 yesterday then it’s highly likely you’ve got a bug lurking in the eunit application. The original version of this release had a bug in one of the makefiles which caused eunit to not install eunit.hrl during the make install step. This caused eunit to not work at all since the header file is needed to enable eunit-based tests.

This morning Bjorn Gustavsson posted to erlang-questions that the problem had been fixed for the non-Windows builds in a new version of the release (with the same version number). If you downloaded the release yesterday you’ll need to download and install the new version posted today to correct the problem.

My thanks to the Erlang team for including eunit in the base release and provding a quick fix for the bug!

by kevin at November 06, 2008 02:07 PM

November 05, 2008

Lookery Dev

Hey, Where's That Function Call?

I had a funny moment as I was just looking at an Erlang stacktrace, saying to myself “But, why isn’t it showing the function that called foldl?”, and then realizing that, of course it can’t show that function, Erlang is, y’know, tail recursive, so the function which ended with the call to foldl, was popped right off the stack.

I mean, duh.  But somehow, this was a bit of a “we’re not in Kansas anymore” moment, even though every looping fun I’ve written is tail recursive, so it’s not like I shouldn’t have known this would happen.

I guess what I’m saying is “In Erlang, your stack frame can just go away!  It’s crazy, I tell you! Crazy!”.

-Dan M

November 05, 2008 09:59 PM

Joe's blog

Erlang R12B-5 is out.

Downloads are available here.

The highlights according to the readme:

OTP-7531 Processes spawned using proc_lib (including gen_server and
other library modules that use proc_lib) no longer keep the
entire argument list for the initial call, but only the
arity.

Also, if proc_lib:spawn/1 is used to spawn a fun, the actual
fun is not kept, but only module, function name, and arity of
the function that implements the fun.

The reason for the change is that keeping the initial fun (or
a fun in an argument list), would prevent upgrading the code
for the module. A secondary reason is that keeping the fun
and function arguments could waste a significant amount of
memory.

The drawback with the change is that the crash reports will
provide less precise information about the initial call (only
Module:Function/Arity instead of Module:Function(Arguments)).
The function proc_lib:initial_call/1 still returns a list,
but each argument has been replaced with a dummy atom.

OTP-7586 In user-defined attributes, Name/Arity is now allowed and
will be translated to {Name,Arity}. (An implementation of
EEP-24 by Richard O’Keefe.)

The module_info/{0,1} functions automatically inserted into
each compiled modules are now documented in the Modules
section in the Reference Manual.

OTP-7630 The eunit application (for unit testing of Erlang modules) by
Richard Carlsson is now included in OTP

by joe at November 05, 2008 05:34 PM

Lookery Dev

Testing / Mochiweb / Stacktraces

So, I’m somewhat test-obsessed (because I accept my own prediliction for making dumb mistakes over and over, and I like having the computer keep an eye out for me. Also, it makes programming a lot more fun).

With a mochiweb app, for certain kinds of testing, I want to launch an instance of my mw server, hit it with an http request, and check the responses. Fortunately, Erlang’s lightweight processes make this very easy. Unfortunately, when I kept things simple, I wasn’t seeing any stack traces when the mw server failed—the outer process, which had launched the mw server under test, would just get a crypic connection closed message, and that was it. And, ‘cause I do like to test as I go, I see failures all the time.

I asked on the mw list about this, and someone suggested starting erlang with -boot sasl, which gives it the OTP infrastructure, which does capture stack traces. But it also produces an incredibly verbose output, making the stack trace very hard to find. And, I couldn’t figure out how to get Emacs, which has a fantastic Erlang compile/shell feature, to launch erlang with -boot sasl.

I was beginning to think of really complex solutions involving somehow attaching the shell to the server process, when I suddenly realized there was a simple solution I was missing: I could just wrap my server handler in a catch, use eunit’s debugFmt to print out the stack trace, and I’d be all set. And it worked beautifully. Here’s the code. In my test function, I took:

    RotatorHandler = 
        fun (Req) ->
                handle_rotator(Req, {RuleUrlTmpl, ProfileUrlTmpl})
        end,

And changed it to:

    RotatorHandler = 
        fun (Req) ->
                try 
                    handle_rotator(Req, {RuleUrlTmpl, ProfileUrlTmpl})
                catch Class:Exception -> 
                        ?debugFmt("~p", [[{Class,Exception} |erlang:get_stacktrace()]]),
                        throw({Class,Exception})
                end
        end,

And now it produces a simple stack trace on failure. Woo, woo!

-Dan M

November 05, 2008 04:17 PM

LShift

Simple inter-process locks

I recently faced a very common problem, how to make sure that only one instance of my program is running at a time on the host.

There are a lot of approaches that can be taken to solve this problem, but I needed a portable solution for Python.

My first idea was to use widely known IPC techniques to lock some global resource. In C I would just create a semaphore and lock it. One problem is that a semaphore is not unlocked when a process dies. Another issue is a lack of support of named semaphores for Python.

The best solution on Unix is to gain an exclusive write lock on a file using fcntl(LOCK_EX).

Of course it doesn’t work on Windows. But for this OS the solution is to take advantage of their mutex facilities using pywin32 module. I was surprised to see that this method works quite well.

It’s also possible to use the fact that only one process at a time can bind to specific tcp/ip port (unless you use SO_REUSEPORT). This is the most portable, but also the most obscure method.

Here’s the code for this inter process “locking”. It’s not really locking, because you can’t block and wait for a lock. All you can do is grab a lock or get an exception. But this is enough to make sure that there is only one process that’s using a resource. This is how you can use this module:

import interlocks, time

lock = interlocks.InterProcessLock("my resource name")
try:
    lock.lock()
except interlocks.SingleInstanceError:
    print "Other process has acquired this lock."
else:
    print "Press CTRL+C to release the lock..."
    while True: time.sleep(32767)

Test code for the interlocks module needs to open an external process that blocks the resource. The code is not perfect (race conditions), but should be enough for just a test case:

def execute(cmd):
    ''' spawn a new python process that will execute 'cmd' '''
    cmd = '''import time;''' + cmd + '''time.sleep(10);'''
    pid = os.spawnv(os.P_NOWAIT,'/usr/bin/python', ['/usr/bin/python', '-c', cmd])
    time.sleep(1) # poor man's synchronization
    return pid

lock = interlocks.InterProcessLock('test')

# lock resource from other process
pid = execute("import interlocks; a=interlocks.InterProcessLock('test');a.lock();")
try: # fail to grab a lock
    lock.lock()
except interlocks.SingleInstanceError: print "success: the lock is blocked by spawned process"
else: print "FAILURE: the lock should be blocked by spawned process (pid=%i), but isn't" % (pid,)

os.kill(pid, signal.SIGKILL)
time.sleep(1) # poor man's synchronization

Coding the tests wasn’t so painful, much more problematic was to make tests run on Windows. Obviously we need an os.kill replacement for this platform. The next problem is to make os.spawnv() work on Windows at all: which slashes to use or how to encode spaces in the path. Another issue is that the process pid returned from os.spawnv() can’t be killed. It seems that the return value is not really a proper pid. Don’t waste your time like I did, use subprocess.Popen(). Fixed test code, without os.spawnv is included in the lib.

by marek at November 05, 2008 01:09 PM

November 04, 2008

Mickaël Rémond

CEAN-1.4 R12B released

After nearly one year of no visible activity I'm happy to announce a new release of CEAN.

CEAN-1.4 comes with Erlang R12B-4, and brings up many improvements in the build process. The aim is to reach a production quality level of autogenerated packages for all erlang contributions.

The most valuable improvements in CEAN-1.4 are:

  • Work in cluster environment. It's possible to sync CEAN installation on several hosts using just one command.
  • A better package dependency resolver. Generated dependencies are reliable.
  • Main commands available from bash. No need to join an erlang shell to install packages.
  • Lots of new packages.

CEAN also supports updated packages for R11B-5. The cluster features are backported to the R11B version as well. More information can be found on CEAN website.

by Christophe Romain at November 04, 2008 11:53 AM

November 03, 2008

Erlang Training and Consulting

Releasing the Erlang Web 1.1 Platform as Open Source!

The Erlang Web is an open source framework for the rapid deployment of web based interfaces. By separating the HTML generation, glue and logic while retaining it in the same memory space, we provide a framework which gives the developer better control of content management where reusability is the key. Erlang Training and Consulting has been using the Erlang Web in commercial applications for three years, and in order to increase the user base and available generic components, has decided to release it as open source. For more information and to download the latest version of the code, read documentation and view examples, presentaitons and tutorials, visit the Erlang Web site. You can also meet us at the Erlang User Conference, where we will be presenting the Erlang Web.

by Erlang Training and Consulting at November 03, 2008 11:59 PM

Lookery Dev

Erlang Metaprogramming

Hey, guess what?  If you know what you’re doing, you can rewrite the parse tree of an Erlang file at compile time (!).  You add the following line to your file (or, say, in some header):

-compile(parse_transform, Module).

And Module is handed a parse tree, which it can then rewrite as it desires, and which is then passed on to the rest of the compiler.

It’s not defmacro, but it gives you some very, very interesting opportunities.  For example, I’m about 95% certain this is how the Mnesia db implements Query List Comprehensions, which are list comprehensions which are automagically turned into Mnesia SELECT-type statements.  Almost like you can roll your own LINQ, which is sexy as hell (I’ve wanted to do that in Python, but there’s no way that doesn’t involve some very, very hairy manipulation of bytecode and/or the stack).

Philip Robinson walks one through how to do this sort of thing at:

http://chlorophil.blogspot.com/2007/04/erlang-macro-processor-v2-part-i.html

Oh, and I should finally add that this is probably not something to undertake lightly.  The man page for erl_id_trans, a sample just-plan-identity transform that comes with OTP, has the following priceless line:

Note: Programmers are strongly advised not to engage in parse transformations and no support is offered for problems encountered

-Dan M

November 03, 2008 02:59 PM

In Search of Concise Software

Hello ErlIDE: Installation to Hello World

IDEs Don't Kill Code Bases, People Kill Code Bases

I have just gotten over my mental block for trying ErlIDE. The biggest conflict for me was that my exploration of Erlang was in part a rebellion against Java and IDE-centric programming. ErlIDE is an excellent solution for Erlang development. I now use it in lieu of TextMate and Vim for my desktop automation projects such as erlang_hgsvn which I use daily to merge SVN branches. Vlad Dumitrescu has created an excellent product and I will do my best to contribute in whatever way I can to its success.

Many people have had difficulty installing and using ErlIDE. This step by step guide will show how to install ErlIDE and make effective use of it so that it helps rather than frustrates you.

(Linux only) Allow Large Number of Open Files

When using Erlang it is generally advised to significantly raise the limit on the number of open files per process. Add the following lines to /etc/security/limits.conf (right above # End of file):

* soft nofile 1048576
* hard nofile 1048576

Install Erlang/OTP (if you have not already)

  • Ubuntu Linux: run the following in Terminal:
    sudo apt-get update
    sudo apt-get install erlang
  • Windows: run the Windows Installer for Erlang R12B-4
  • Mac OS X: install MacPorts and then run the following in Terminal:
    sudo port selfupdate
    sudo port install erlang

Install Eclipse and ErlIDE

  1. Download Eclipse IDE for Java Developers
  2. Extract it where you want to run it from (there is no installer, just an archive)
  3. Launch Eclipse by double-clicking eclipse (Linux), eclipse.exe (Windows), or Eclipse (Mac) in the eclipse folder
  4. Select Help (menu) → Software Updates... (a dialog will appear)
  5. Click Add Site...(another dialog will appear)
  6. Enter http://erlide.sourceforge.net/update into the Location field, then click OK (dialog will close)
  7. Select the checkbox by http://erlide.sourceforge.net/update and click Install... (another dialog will appear)
  8. Select Next
  9. Select I accept ... radio button and click Finish (a progress dialog will appear)
  10. (wait for confirmation dialog) Select Yes (Eclipse will restart)

Add Primary Erlang Runtime

Without these steps things like syntax highlighting, code completion and other significant aspects of the ErlIDE UI will not work properly. The IDE will function basically, but it will not work as intended.

  1. Select Window (menu) → Preferences... (Windows/Linux) or Eclipse (menu) → Preferences... (Mac) (a dialog will appear)
  2. Expand Erlang and select Installed runtimes
  3. Click Add... (a dialog will appear) and Enter Erlang in the Runtime name field
  4. Click Browse... and select the root of your Erlang/OTP install (mine is /opt/local/lib/erlang), then click OK (dialog will close)
  5. Click OK (preferences dialog will close)

Create Hello World Project

  1. (wait for Eclipse to restart) Select Window (menu) → Close All Perspectives
  2. Select Window (menu) → Open Perspective → Other... (a dialog will appear)
  3. Select Erlang and click OK (dialog will close and Erlang Perspective will load)
  4. In the Erlang Navigator bring up the context menu (right-click/control-click) and select New Erlang Project (a dialog will appear)
  5. Enter hello_world in the Project Name field and click Finish (dialog will close and hello_world project will appear in Erlang Navigator view)

Start Erlang Node To Run Code

  1. Select hello_world project, bring up the context menu and select Run As → Run Configurations... (a dialog will appear)
  2. Enter hello_world in the Name field
  3. Double-click Erlang application (a new confguration will appear in the right-hand panel)
  4. In the Main tab under Projects click the checkbox beside hello_world
  5. In the Runtimes tab click the checkbox beside Start the Erlang node if not running already and enter hello_world in the Node name field
  6. Click Run (dialog will close and Console will appear with hello_world Erlang node)
  7. Leave the Console running for the next part

Write Hello World Live!

  1. On the hello_world project bring up the context menu (right-click/control-click) and select New Module (dialog will appear)
  2. Enter hello_world in Module name field
  3. To the left of the Apply button, enter say_hello in the first box and 0 in the second box and click Apply
  4. Click Finish (dialog will close and an editor for hello_world.erl will be opened)
  5. In the Console type hello_world:say_hello().
  6. Oops! It displays ok and shows no greeting! Let's fix that
  7. In the hello_world.erl editor replace ok in say_hello with io:format("Hello World!") and save (Ctrl-S/Command-S)
  8. In the Console type hello_world:say_hello().
  9. Great! It displays "Hello World!" for us! Let's get it to say something else
  10. In the hello_world.erl editor replace "Hello World!" in say_hello with "Hello ErlIDE!") and save (Ctrl-S/Command-S)
  11. In the Console type hello_world:say_hello().
  12. Nifty! It displays "Hello ErlIDE!" for us! We can change the code at runtime.

Embrace Convention

When I first tried ErlIDE over a year ago I found the predetermined project structure irritating. I now realize that this project structure is an accepted convention in the Erlang community. It reflects the way that most Erlang/OTP applications are distributed.

Go With The Flow

Buy into ErlIDE's default project structure even though it can now be overridden. It will make it easier for you to work with ErlIDE and easier for other Erlang developers to use what you have created. We have had trouble using Eclipse integration for J2EE at work because of the non-standard layout of our projects. Make the right choice upfront and adopt the conventional Erlang project structure. I wish Joe had mentioned this in his book...

Understated Power Overstated Roughness

ErlIDE is much less rough around the edges than I would expect for a 0.3 release. It is also understating its capabilities and the quality of the Eclipse integration. There is definitely work to be done, but it is an excellent foundation.

ErlIDE is the best tool I have used for Erlang development. It is the clear winner in ease of use for comparable functionality. For anyone already familiar with Eclipse ErlIDE is familiar and comfortable to use. I think ErlIDE will be instrumental in getting more Java developers to use Erlang. I will be actively contributing whatever fixes and features I can to ErlIDE.

by Alain O'Dea (noreply@blogger.com) at November 03, 2008 11:15 AM

Ulf Wiger

erlang.org reaches the 2 million mark

Another graph courtesy of Bjarne Däcker. Interest in Erlang seems to increase at an exciting rate. The monthly hit rate at www.erlang.org now for the first time touches the 2 million mark.

Requests/month at www.erlang.org

Requests/month to www.erlang.org

by Ulf Wiger at November 03, 2008 11:14 AM

EasyErl

CEAN 1.4 is released

Tdoay is a great day, today you can read on the erlang mailling list that "CEAN 1.4 is released" ! ( this time it's R12B4 based release ) There's also a new website, new design and new Cean packages. Go grab it !

by rolphin (noreply@blogger.com) at November 03, 2008 09:08 AM

Sudarshan Acharya

Erlang on Mac OSX

On a fresh install of Leopard, the following is what I did in order to set up Erlang working on my Mackbook Pro: 1. Download Xcode by going to Apple ADC. Xcode is the Apple's developer tool set, and its available for free. At the time of my install, the latest ...

November 03, 2008 12:30 AM

November 01, 2008

Me Dev, You Jane

Contact List using SproutCore, Mochiweb and Mnesia

Here is an example program using a SproutCore frontend talking to an Erlang backend using the ReST protocol.

Sproutcore

Lets start by creating the Sproutcore application. I will not go into detail into the Sproutcore code as JavaScript and Sprutcore are way beyond a single tutorial.

sc-init mochi_contacts
cd mochi_contacts

Inside mochi_contacts we find a nice little framework for our application. Lets start by creating our model with the command. "sc-gen model mochi_contacts/contacts". Then we edit our model at clients/mochi_contacts/model/contacts.js and add the following code.

resourceURL: 'contacts',
properties: ["guid","fullname",'email','mobile'],

commitChanges: function(){
    if(this.get('fullname') == '') this.set('fullname', 'Unnamed');
    this.commit();
}

This is pretty straight forward. resourceURL defines the location of the data source. In this case it would be http://localhost/contacts/. In properties we define the keys we want to read from that resource. The commitChanges function then makes sure we have the fullname property defined and commits the changes to the resource.

Next up is our master controller. The master contoller handles our list view at the side. Create it with the command "sc-gen controller mochi_contacts/master SC.CollectionController", open up the file clients/mochi_contacts/controller/masterController.js and add the following.

allowsEmptySelection: false,
allowsMultipleSelection: false,
canEditCollection: true,

addContact: function(sender){
    var content = this.get('content');
    var contact = MochiContacts.Contacts.newRecord({
        fullname: "Unnamed"
    },MochiContacts.server);

    contact.commitChanges();
    this.set('selection',[contact]);
},

delContact: function(sender){
    if(!confirm('Are you sure?')) return;
    var sel = (this.get('selection') || []).clone() ;
    var idx = sel.get('length') ;
    while(--idx >= 0) {
        var contact = sel.objectAt(idx);
        contact.destroy();
    }
},

Not much to see here. Just basic functions for creating and deleting contacts from the list and 3 properties for defining the behaviour of the list view.

So now we need a second controller that will handle the form itself. Create it with the command "sc-gen controller mochi_contacts/detail SC.ObjectController" and put the following inside clients/mochi_contacts/controller/detailController.js

contentBinding: 'MochiContacts.masterController.selection',
commitChangesImmediately: false

Wow. Even less we do here. We simply bind the content of the controller to the currently selected object of the master controller. We then define that we dont want the changes to be posted automatically because we will add a button to do that.

Now we have to define the view. Open up clients/mochi_contacts/english.lproj/body.rhtml and remove everything. Replace with the following:

<% content_for('body') do %>

<% split_view :workspace, :class => 'sc-app-workspace footer', 
    :direction => :horizontal do %>  
  <% view :sidebar, :outlet => true do %>
    <% scroll_view :master_list, :outlet => true do %>
      <%= list_view :list_view, 
            :outlet => true, 
            :content_value_key => 'fullname', 
            :content_value_editable => false,
            :can_reorder_content => true,
            :bind => { 
              :content => 'MochiContacts.masterController.arrangedObjects', 
              :selection => 'MochiContacts.masterController.selection' 
            }
            %>
    <% end %>
  <% end %>

  <%= split_divider_view :outlet => true, :width => 5 %>

  <% view :detail_view, :outlet => true do %>
    <table class="card-detail">

      <tr>
        <td><label>Full Name:</label></td>
        <td>
          <%= text_field_view :outlet => true, :hint => "Full Name",
            :bind => {
              :value => 'MochiContacts.detailController.fullname'
            } %>
        </td>
      </tr>

      <tr>
        <td><label>Email:</label></td>
        <td>
          <%= text_field_view :outlet => true, :hint => "email@email.com",
            :bind => {
              :value => 'MochiContacts.detailController.email'
            } %>
        </td>
      </tr>

      <tr>
        <td><label>Mobile:</label></td>
        <td>
          <%= text_field_view :outlet => true, :hint => "555-0000",
            :bind => {
              :value => 'MochiContacts.detailController.mobile'
            } %>
        </td>
      </tr>

      <tr>
        <td colspan="2" class="buttons">
          <%= button_view :outlet => true, 
            :title => "Cancel",
            :action => 'MochiContacts.detailController.discardChanges',
            :bind => {
              :enabled => 'MochiContacts.detailController.hasChanges'
            } %>
          <%= button_view :outlet => true, 
            :title => "Save Changes", :default => true,
            :action => 'MochiContacts.detailController.commitChanges',
            :bind => {
              :enabled => "MochiContacts.detailController.hasChanges"
            } %>
        </td>
      </tr>
    </table>

  <% end %>
<% end %>

<% view :footer, :class => 'sc-footer sc-square-theme' do %>
  <div class="left">
    <%= button_view :outlet => true, :label => '+', 
        :action => 'MochiContacts.masterController.addContact' %>
    <%= button_view :outlet => true, :label => '-', 
        :action => 'MochiContacts.masterController.delContact' %>
  </div>

<% end %> <!-- footer -->

<% end %>

In here we have defined the views and bound their properties to the controllers.

Next we connect the contollers to the model. We do that inside clients/mochi_contacts/main.js by replacing the line MochiContacts.server.preload(MochiContacts.FIXTURES);</