Wednesday, December 26, 2007

Launching ASDoc with External Tools

While redoing the player, I have been writing a lot of actionscript lately. And by a lot I mean a ton. After I had everything working properly, the time came to go back through and clean it all up. In that process, I came across ASDoc, the documentation generator for actionscript. Like JavaDoc or PHPDocumentor, you mark up your code with multi-line comments, and after running the tool, you get a nice pretty set of HTML pages that make it understandable.

As usual, I dove right in. Marked up all of my methods and member variables and was ready to go. But, ASDoc has quite a few arguments to customize the output and using the shell to run this every time I made a change got old real fast.

Now enter External Tools from the Eclipse framework. If you haven't used external tools in the past, basically it allows you to configure and run mind numbing tasks click and go style. After digging through the flex mailing lists for a bit, I came across this. Problem solved.

But.... I had several projects I wanted to document and I didn't want a million of these external tool configurations all over the place. Another nice feature of External Tools is variable substitution on workspace and project levels. So, here is how to add the external tool to run asdoc on the currently open project:
  1. Click Run-> External Tools -> Open External Tools Dialog
  2. Click on the New Configuration button
  3. Name it Generate ASDoc
  4. For location, enter the path to asdoc. On windows, the default is C:\Program Files\Adobe\Flex Builder 3\sdks\3.0.0\bin\asdoc.exe
  5. In the working directory, enter ${project_loc}
  6. In the arguments input, -source-path . -doc-sources ./com -window-title "${project_name}" -main-title "${project_name}"
  7. Click Apply
After you run "Generate ASDOC", you will get a new folder in your project called asdoc-oputput that contains the fruit of our labor. If you open up index.html, it will look something like this:




Pretty sexy, no?

About the Arguments


Here is a quick explanation of what the arguments in the above instructions do. You can view all of the available arguments here.

-source-path . Sets the working path for asdoc. Why not use ${project_loc} instead of setting the working directory? For some reason, external tools doesn't like spaces in its substitutions (even with proper escaping). Since the default workspace in flex builder contains spaces, this can be quite a pickle. Setting the working directory gets around this (thanks Jimmy!).

-doc-sources ./com Tells ASDoc to generate docs for everything inside ${project_loc}/com/. If you are documenting a Flex Library Project, you can keep the code as is. Note: If you are trying to document a normal Flex Project (ie your code is in ${project_loc}/src/), change the arguments appropriately.

-window-title "${project_name}" -main-title "${project_name}" Sets the HTML title and any other title references to the name of your project.

Monday, December 17, 2007

fcsh-mode for flex work from (x)emacs

A week or so ago I finally bit the bullet and decided I was going to have to learn some Flex/ActionScript so I could be self-sufficient on my latest project, a music game that integrates a Flash frontend with an Erlang backend. Being a Linux user (at work, at least) I downloaded the Flex SDK and was pleased to find that I could compile my Flex application using mxmlc from the command line. However, it was ridiculously slow -- we're talking 25+ seconds to compile a 500 line mxml file.

It turns out the reason for this is that mxmlc is written in Java and has significant startup cost. The solution is to use fcsh, the Flex Compiler Shell, which runs continuously and can incrementally compile your Flex application as you make changes. Using this from my shell reduced compilation time to 1-2 seconds, which is perfectly acceptable.

However, I quickly noticed that fcsh sucks. Most notably, it has no command history. I was typing "compile 1" every 15 seconds and getting annoyed. So I buckled down and wrote an fcsh-mode for Xemacs, reproduced below.

If you want to try it, paste it into a file like ~/.xemacs/fcsh-mode.el and load it using M-x load-file or adding (load-file "~/.xemacs/fcsh-mode.el") to your emacs init file. Then M-x fcsh will launch an fcsh with command history (even cross-session) in a new buffer. I also added an fcsh-repeat-last command which I bind to C-Enter using M-x local-set-key in my editing buffer. I can then just hit control-enter to recompile my flex app in less than a second.

Hope someone finds this useful!


(require 'comint)

(defvar fcsh-mode-map
(let ((fcsh-mode-map (copy-keymap comint-mode-map)))
(define-key fcsh-mode-map [(up)] 'comint-previous-input)
(define-key fcsh-mode-map [(down)] 'comint-next-input)
fcsh-mode-map
)
"Keymap for fcsh major mode")

(defvar fcsh-mode-hook nil
"Functions to run when fcsh mode is actived.")

(defvar fcsh-input-ring-file-name "~/.fcsh_history"
"*When non-nil, file name used to store Fcsh shell history information.")


(defun fcsh-mode ()
"Major mode for running the fcsh, flex compiler shell"
(interactive)
(comint-mode)
(setq major-mode 'fcsh-mode)
(setq mode-name "FCSH")
(use-local-map fcsh-mode-map)

(setq comint-prompt-regexp "^\\(fcsh\\) ")
(setq comint-eol-on-send t)
(setq comint-input-ignoredups t)
(setq comint-scroll-show-maximum-output t)
(setq comint-scroll-to-bottom-on-output t)

;; Some older versions of comint don't have an input ring.
(if (fboundp 'comint-read-input-ring)
(progn
(setq comint-input-ring-file-name fcsh-input-ring-file-name)
(comint-read-input-ring t)
(make-local-variable 'kill-buffer-hook)
(add-hook 'kill-buffer-hook 'comint-write-input-ring)))

(run-hooks 'fcsh-mode-hook))

(defun fcsh ()
"Run an inferior fcsh, with I/O through buffer *fcsh*.
If buffer exists but fcsh process is not running, make new process.
If buffer exists and fcsh process is running, just switch to *fcsh*.
The buffer is put in fcsh-mode.

\(Type \\[describe-mode] in the fcsh buffer for a list of commands.)"
(interactive)
(cond ((not (comint-check-proc "*fcsh*"))
(set-buffer (make-comint "fcsh" "fcsh"))
(fcsh-mode)))
(pop-to-buffer "*fcsh*"))


(defun fcsh-command (cmd)
"Run a command in the fcsh shell"
(interactive "scommand?")
(let ((old-buffer (current-buffer)))
(cond ((not (comint-check-proc "*fcsh*"))
(set-buffer (make-comint "fcsh" "fcsh"))
(fcsh-mode)))
(set-buffer "*fcsh*")
(goto-char (marker-position (process-mark (get-buffer-process (current-buffer)))))
(insert cmd)
(comint-send-input)
(switch-to-buffer old-buffer)))

(defun fcsh-repeat-last ()
"Repeat last command in fcsh"
(interactive)
(let ((old-buffer (current-buffer)))
(cond ((not (comint-check-proc "*fcsh*"))
(set-buffer (make-comint "fcsh" "fcsh"))
(fcsh-mode)))
(set-buffer "*fcsh*")
(goto-char (marker-position (process-mark (get-buffer-process (current-buffer)))))
(call-interactively 'comint-previous-input)
(comint-send-input)
(switch-to-buffer old-buffer)))

Tuesday, December 11, 2007

Concurrency-Oriented Programming

You may have read Todd's earlier post about Erlang. We like it, in part, because it's designed for concurrency. We can write highly concurrent programs without fighting a continuous uphill battle against races and deadlocks. In fact, we barely worry about these things at all. Does this sound like magic to you? It's real, and it's quite relieving. We don't owe this debt to the presence of some clever language feature. On the contrary... Erlang's strength is in the absence of a particularly detrimental feature.

Mutable data.

Yes, we have essentially declared war on the assignment operator. Does this sound bizarre to you? How do we do without it? Well, a long time ago, delete and free() were pretty important. Language designers got rid of them, programmers had a paradigm shift, and we all moved on. Today's assignment operator is evolving into something new... the single-assignment operator. You instantiate a chunk of data, assign an initial value, and promise never to modify it.

The danger of mutability becomes apparent when we investigate the causes of race conditions. You may have noticed that read-only data structures don't need to be locked. Readers don't race with each other. Put a writer on the scene... and locks have to be introduced. Figuring out your locking is probably the most painful and least forgiving part of coding. So, if we nip the problem in the bud, and make all data read-only... then we obviate the need for locking.

The absence of mutable data makes concurrency a trivial problem.

If we can't change our data, how do we pass information between threads? We use a special language construct to do this... message passing. It takes 3 easy steps. Prepare the message you want to send, aim it at another thread, and fire. It is just like opening a socket and sending data over TCP/IP. As long as the language designers provide a sound implementation, you won't have to worry about race conditions.

The next question is, if we can't change our data... how do we program at all? Namely, how do we maintain state? Well, believe it or not, Erlang has a solution for this as well. It's called concurrency-oriented programming, where processes each maintain private state. By making processes extremely lightweight (quick to spawn, completely user-level, having a memory footprint of a few hundred bytes) we can replace objects with processes.

This is the Java code for a thread-safe counter:

class Counter {

private int value;

public Counter(int value) {
this.value = value;
}

public synchronized int get() {
return value;
}

public synchronized void incr() {
value++;
}
}


This is the Erlang code for a thread-safe counter:

-module(counter).
-export([new/1, get/1, incr/1]).

new(Value) ->
spawn(fun() -> loop(Value) end).

get(Counter) ->
Counter ! {self(), get},
receive
{Counter, Value} -> Value
end.

incr(Counter) ->
Counter ! incr,
ok.

loop(Value) ->
receive
{From, get} -> From ! {self(), Value}, loop(Value);
incr -> loop(Value+1)
end.


There you have it. We've translated a stateful, encapsulated object into a stateful, encapsulated process. Notice we haven't used the assignment operator. It took just a little bit more code (note that Erlang provides nice libraries to abstract away the looping and the message passing). Feel free to instantiate as many as you want; processes are about as cheap as objects.

Inexpensive concurrency makes the absence of mutable data a trivial problem.

The benefits here are numerous. It is automatically race-free, and does not use lock-based synchronization. Work can be done asynchronously (a function can essentially return a value before finishing its computation). The process and caller can transparently live on different machines.

This also fully exploits the power of multi-core processors. An Erlang program might have millions of processes (just like a Java program could have millions of objects). Therefore, you will not exhaust your speedup potential until you're using a million-core processor. Whereas, a Java program with 10 threads maxes out on a 10-core processor, and does not speed up when adding more cores.

I haven't even discussed internals, like garbage collection, which leverage immutability immensely.

While OOP provides proper encapsulation and modularity... COP takes us to the next level and helps us embrace our highly-concurrent world. It's time for another paradigm shift.

Updates for 12/11/07

Mostly bug fixes today.
  • Fixed: existing playlist presets in the player and added a few new ones
  • Fixed: The mystery of being logged in as a ghost user
  • Improved: The Twitter service can now take any username (more on that later today)
  • Improved: The library browser in labs now supports tag browsing and browsing the library of all your amie street friends
  • Fixed: lightboxes are back to fixed position. No more losing the lightbox when you scroll on the page.

Newsletter for December 11th, 2007

This week's Newsletter has finished sending. Check it out here. This week features 8 Albums in: Alternative, Pop, Rock, Country, Rap, Folk, Acoustic, Hard Core, Metal, Indie Rock, and Soundtrack.

Dont like email? Get the newsletter by RSS.

Monday, December 10, 2007

Erlang and "Web 2.0"

At first glance, one might not guess that Erlang, a programming language invented in the 1980s by Ericsson (the Swedish phone equipment company) would be a great tool for Web 2.0 development. One of the most important parts of the included library is the "Open Telecom Platform" and error messages remind me of my Apple IIe:


=ERROR REPORT==== 10-Dec-2007::22:12:48 ===
game terminating for reason: {noproc,{gen_server,
call,
[{global,song_picker},
{pick_song,undefined}]}}
** exited: {noproc,{gen_server,call,
[{global,song_picker},{pick_song,undefined}]}} **


Recently, though, the language has been gaining a lot of buzz online, and for good reason. So, a few weeks ago I picked up the book "Programming Erlang: Software for a Concurrent World." I quickly skimmed it in an evening, and passed it along to Jason who did the same. By the end of the week, we both liked it enough to consider writing some Amie Street backend services in it, and the week after that convinced ourselves it was actually a good idea.

So, why is Erlang a good match for web-based services? Here are a few reasons:


  • Functional programming and dynamic typing - with a dynamically typed language, you can start writing code and have working prototypes within minutes. Good functional code can be much more concise than its procedural equivalents, and less lines of code usually means less bugs and shorter development time.

  • Concurrency-oriented programming - in Erlang, pretty much everything is its own process. If you've got 20 users playing a Flash game, or 100 shopping carts outstanding, just give them each their own process. State machines show up all the time in web programming, and a state machine having its own thread and not having to worry about in-DB storage makes the whole thing a lot easier to think about.

  • Fault tolerance - because everything is its own process, one user running into a bug can't cause the whole system to go down. Processes can monitor each other and recover gracefully when errors do occur. For example, in the 2-player Flash game I'm writing, if a user quits his browser, an AI player will automatically take his place for the remainder of the game, and the code to do this is exceedingly simple.

  • Some great standard libraries - best example: mnesia, a built-in database that supports full ACID transactions, disk/ram storage, replication, hash-based fragmentation, and more.

  • thrift support - the Thrift RPC library from Facebook has Erlang bindings, so you can make calls into an Erlang service from PHP, Perl, Ruby, or whatever your frontend happens to be written in.



Using Erlang, we've implemented a prototype "song labeling" game like the Google "image labeler" in less than 1000 lines of code. It stores tags to an mnesia database, speaks directly to the Flash client using XMLSocket, and is damn near impossible to crash. The first working prototype took about 12-16 man-hours of development time between the client (Flex 3) and the server. I'd love to see someone beat that in any other language.

Tuesday, December 04, 2007

Updates for December 4th, 2007