<br><div class="gmail_quote">On Sun, Oct 23, 2011 at 6:59 PM, Matthew Evans <span dir="ltr"><<a href="mailto:mattevans123@hotmail.com">mattevans123@hotmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<br>
Hi List,<br>
<br>
I've often wondered what is the correct (as in idiomatic Erlang) way to structure an sufficiently complex service in Erlang?<br>
<br>
Obviously a simple service would be a single application, with a supervisor hierarchy something like:<br>
<br>
app_foo<br>
|<br>
foo_sup<br>
|<br>
gen_servers<br>
<br>
<br>
Let's suppose you have a complex service to deploy (that does related, but functionally separate tasks), what is normal:<br>
<br>
<br>
1) Separating the complexity as multiple apps (i.e. 2 .app files and beam files in separate ebin directories):<br>
<br>
app_foo app_bar<br>
<br>
| |<br>
<br>
foo_sup bar_sup<br>
<br>
| |<br>
<br>
gen_servers gen_servers<br>
<br>
<br>
Or...<br>
<br>
<br>
2) A single app with multiple (hierarchical) supervisors (i.e. 1 .app file, all beam files in the same ebin directory):<br>
<br>
<br>
app_foobar<br>
|<br>
foobar_sup<br>
|<br>
---------------<br>
| |<br>
foo_sup bar_sup<br>
| |<br>
foo's bar's <br>
gen_servers gen_servers<br>
<br>
<br>
Seems like the preference is towards example 2; but to me this means that you can't easily decompose and separate functionality apart. It also means that messaging can jump across supervisors making for somewhat messy interfaces (plus having to cross supervise/link gen_servers that are separated by different supervisors).<br>
<br>
Thanks<br>
<br>
Matt<br><br></blockquote><div><br></div><div>A complex package, in my mind, is made up of a collection of Erlang applications, each of which encapsulates a sub-system of the whole. These sub-systems are either passive (i.e., "just" libraries, in the vein of stdlib and kernel) or active (an Erlang application that has a start function defined in the .app file). For the active components, I tend to go with a simple app-sup-[gen_*] layout. The overall startup is defined through the .rel file and the individual .app files. But for this approach you need to use the release building facilities of Erlang. Those are not hard, but do take a bit of exercise to get a good grip on.</div>
<div><br></div><div>Sometimes, in some of the more complex sub-systems, you can end up with a more complex supervision tree (multiple supervisors, multiple gen_* components, in varying levels of supervision). An example would be a kind of dynamic worker pool, where you could have a top level supervisor in charge of an "organisor" (who brings workers to life to do stuff) and a supervisor, and the latter will look after the workers created by the "organisor".</div>
<div><br></div><div>But your overriding architectural approach needs to use sub-system divisions that make sense when you talk about them using normal language. It is frightfully easy to start dividing your code into "unnatural" divisions, based on overly abstract concepts like "Utility library" or "Framework" or some such. The more you are able to keep the divisions (and naming, which is way harder than it seems) based on the actual real application, the better you will later understand why the architecture looks the way it does.</div>
<div><br></div><div>All a bit abstract, sorry. But hopefully still helpful.</div><div><br></div><div>Robby</div><div><br></div></div>