- it might be easier to start your app with `application:ensure_all_started(erl2048)`. If your dependencies are well set in your app file, this will boot all dependencies for you.<p>- Given you've already compiled, you don't need the `rebar compile skip_deps=true` part to start the app -- that's just to recompile before you boot it, but I guess you knew that already.<p>- Eventually you get to look in releases, but they're a bit more complex. Look at <a href="http://relx.org" rel="nofollow">http://relx.org</a> for an easier way in. Releases will let your system know how to boot apps (so you don't have to `-eval` anything), and lets you pre-configure shell options (`-noshell -detached`) so that you can just boot the server with a `./_rel/bin/my-release` call.<p>- For information on supervisors and what things like `one_on_one` mean, see <a href="http://learnyousomeerlang.com/supervisors" rel="nofollow">http://learnyousomeerlang.com/supervisors</a><p>- The naming convention for Erlang functions is `some_function`, not `someFunction`. This makes it easier to visually parse between variables (`SomeVal`) and functions (`some_function`).<p>- functions like `withinBounds({X, Y})` can be rewritten as `within_bounds({X,Y}) -> (X > 0), (X =< ?SIZE) andalso (Y > 0), (Y =< ?SIZE).` -- no need to pattern match there past the initial tuple. Remove the `_` matching, and just let it crash if something doesn't fit. You'll see it in logs (somewhere) and can fix it later.<p>- Functions like `getVector(up) -> {-1,0}` could easily be made declarative by using `vector(up) -> {-1,0}` or just `up() -> {-1,0}`.<p>- Break out large functions more. There's often no reason to have a 100+ lines function in Erlang. If you end up nesting `case` constructs more than two level deeps, start thinking about splitting the functions up and deferring stuff to other function calls. Your code will also be more testable that way, easier to reason about when something goes wrong, and easier to delete and refactor without breaking anything.
Very good write up!<p>Good overview of how to get started with Erlang. Sometimes those that give it a first try are the best ones at writing a getting started guide.<p>> I'm not exactly sure what one_to_one is, but it works. It makes sense to look through Erlang documentation and find out the definition.<p>one_for_one just means that if one child of the supervisor dies, it will be restarted. There other choice is all_for_one, which means that if one child crashes, supervisor will restart all its children.<p>You can nest supervisors and create hierarchies of supervisors and workers and restart them as you need. Each process has an isolated heap (just like OS processes) and it will be neatly cleaned up by the garbage collector.
The *app.src file is used to store metadata about the application, and compilation will munge it a bit and copy it into your ebin directory (without the app.src bit I believe).<p>Essentially, it's what allows application:start(erl2048) to work. The {mod, {erl2048_app, []}} param is what indicates you want to run the code in erl2048_app.erl (though obviously the compiled beam file equivalent) as an application; the application behavior says that starting an application calls the equivalent start/# function.<p>So basically the order of startup when you call application:start(erl2048) is<p>Erlang looks for the munged erl2048.app.src, and loads that metadata.<p>The mod argument specifies a module to start.<p>The start function in that module is called (as it is expected to adhere to the application behavior). That function should start up the top level supervisor, which in turn is in charge of starting your entire supervisor heirarchy, and by extension, your actual worker processes.
That was a very helpful tutorial. I plan on messin around with the code later tonight. I really am starting to like kukuruku, haven't been able to find content like this lately...